Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/fxcommand.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/txsheet.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnfx.h"
Toshihiro Shimizu 890ddd
#include "toonz/fxdag.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnfxset.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshzeraryfxcolumn.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobjecttree.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelcolumn.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshpalettecolumn.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzscene.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheethandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tfxhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tscenehandle.h"
Toshihiro Shimizu 890ddd
#include "historytypes.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzBase includes
Toshihiro Shimizu 890ddd
#include "tparamcontainer.h"
Toshihiro Shimizu 890ddd
#include "tparamset.h"
Toshihiro Shimizu 890ddd
#include "tfxattributes.h"
Toshihiro Shimizu 890ddd
#include "tmacrofx.h"
Toshihiro Shimizu 890ddd
#include "tpassivecachemanager.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tundo.h"
Toshihiro Shimizu 890ddd
#include "tconst.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Toshihiro Shimizu 890ddd
#include <qmap></qmap>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "tcg/tcg_macros.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_base.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_function_types.h"
Toshihiro Shimizu 890ddd
Campbell Barton 40cabe
#include <memory></memory>
Campbell Barton 40cabe
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  Toonz currently has THREE different APIs to deal with scene objects commands:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    1. From the xsheet, see columncommand.cpp
Toshihiro Shimizu 890ddd
    2. From the stage schematic
Toshihiro Shimizu 890ddd
    3. From the fx schematic
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  *This* is the one version that should 'rule them all' - we still have to
Toshihiro Shimizu 890ddd
  unify them, though.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TODO:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  - Associated Stage Object copies when copying columns
Toshihiro Shimizu 890ddd
  - Stage schematic currently ignored (eg delete columns undo)
Toshihiro Shimizu 890ddd
  - Double-check macro fxs behavior
Toshihiro Shimizu 890ddd
  - Double-check group behavior
Toshihiro Shimizu 890ddd
  - Enforce dynamic link groups consistency
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Local Namespace  stuff
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline TFx *getActualIn(TFx *fx) {
Shinya Kitaoka 120a6e
  TZeraryColumnFx *zcfx = dynamic_cast<tzerarycolumnfx *="">(fx);</tzerarycolumnfx>
Shinya Kitaoka 120a6e
  return zcfx ? (assert(zcfx->getZeraryFx()), zcfx->getZeraryFx()) : fx;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline TFx *getActualOut(TFx *fx) {
Shinya Kitaoka 120a6e
  TZeraryFx *zfx = dynamic_cast<tzeraryfx *="">(fx);</tzeraryfx>
Shinya Kitaoka 120a6e
  return (zfx && zfx->getColumnFx()) ? zfx->getColumnFx() : fx;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline int inputPortIndex(TFx *fx, TFxPort *port) {
Shinya Kitaoka 120a6e
  int p, pCount = fx->getInputPortCount();
Shinya Kitaoka 120a6e
  for (p = 0; p != pCount; ++p)
Shinya Kitaoka 120a6e
    if (fx->getInputPort(p) == port) break;
Shinya Kitaoka 120a6e
  return p;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Toshihiro Shimizu 890ddd
  Returns whether the specified fx is internal to a macro fx. Fxs
Toshihiro Shimizu 890ddd
  inside a macro should not be affected by most editing commands - the
Toshihiro Shimizu 890ddd
  macro is required to be exploded first.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
bool isInsideAMacroFx(TFx *fx, TXsheet *xsh) {
Shinya Kitaoka 120a6e
  if (!fx) return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TColumnFx *cfx = dynamic_cast<tcolumnfx *="">(fx);</tcolumnfx>
Shinya Kitaoka 120a6e
  TXsheetFx *xfx = dynamic_cast<txsheetfx *="">(fx);</txsheetfx>
Shinya Kitaoka 120a6e
  TOutputFx *ofx = dynamic_cast<toutputfx *="">(fx);</toutputfx>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return !cfx && !xfx && !ofx &&
Shinya Kitaoka 120a6e
         !(xsh->getFxDag()->getInternalFxs()->containsFx(fx));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename paramcont=""></typename>
Shinya Kitaoka 120a6e
void setParamsToCurrentScene(TXsheet *xsh, const ParamCont *cont) {
Shinya Kitaoka 120a6e
  for (int p = 0; p != cont->getParamCount(); ++p) {
Shinya Kitaoka 120a6e
    TParam ¶m = *cont->getParam(p);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (TDoubleParam *dp = dynamic_cast<tdoubleparam *="">(¶m))</tdoubleparam>
Shinya Kitaoka 120a6e
      xsh->getStageObjectTree()->setGrammar(dp);
Shinya Kitaoka 120a6e
    else if (TParamSet *paramSet = dynamic_cast<tparamset *="">(¶m))</tparamset>
Shinya Kitaoka 120a6e
      setParamsToCurrentScene(xsh, paramSet);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void setFxParamToCurrentScene(TFx *fx, TXsheet *xsh) {
Shinya Kitaoka 120a6e
  setParamsToCurrentScene(xsh, fx->getParams());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void initializeFx(TXsheet *xsh, TFx *fx) {
Shinya Kitaoka 120a6e
  if (TZeraryColumnFx *zcfx = dynamic_cast<tzerarycolumnfx *="">(fx))</tzerarycolumnfx>
Shinya Kitaoka 120a6e
    fx = zcfx->getZeraryFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  xsh->getFxDag()->assignUniqueId(fx);
Shinya Kitaoka 120a6e
  setFxParamToCurrentScene(fx, xsh);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void showFx(TXsheet *xsh, TFx *fx) {
Shinya Kitaoka 120a6e
  fx->getAttributes()->setIsOpened(xsh->getFxDag()->getDagGridDimension() == 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (TZeraryColumnFx *zcfx = dynamic_cast<tzerarycolumnfx *="">(fx))</tzerarycolumnfx>
Shinya Kitaoka 120a6e
    fx                                       = zcfx->getZeraryFx();
Shinya Kitaoka 120a6e
  fx->getAttributes()->passiveCacheDataIdx() = -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void hideFx(TXsheet *xsh, TFx *fx) {
Shinya Kitaoka 120a6e
  if (TZeraryColumnFx *zcfx = dynamic_cast<tzerarycolumnfx *="">(fx))</tzerarycolumnfx>
Shinya Kitaoka 120a6e
    fx = zcfx->getZeraryFx();
Shinya Kitaoka 120a6e
  TPassiveCacheManager::instance()->disableCache(fx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void addFxToCurrentScene(TFx *fx, TXsheet *xsh, bool isNewFx = true) {
Shinya Kitaoka 120a6e
  if (isNewFx) initializeFx(xsh, fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  xsh->getFxDag()->getInternalFxs()->addFx(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  showFx(xsh, fx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void removeFxFromCurrentScene(TFx *fx, TXsheet *xsh) {
Shinya Kitaoka 120a6e
  xsh->getFxDag()->getInternalFxs()->removeFx(fx);
Shinya Kitaoka 120a6e
  xsh->getFxDag()->getTerminalFxs()->removeFx(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  hideFx(xsh, fx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Filter Functors  definition
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct FilterInsideAMacro {
Shinya Kitaoka 120a6e
  TXsheet *m_xsh;
Shinya Kitaoka 120a6e
  inline bool operator()(const TFxP &fx) {
Shinya Kitaoka 120a6e
    return ::isInsideAMacroFx(fx.getPointer(), m_xsh);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  inline bool operator()(const TFxCommand::Link &link) {
Shinya Kitaoka 120a6e
    return ::isInsideAMacroFx(link.m_inputFx.getPointer(), m_xsh) ||
Shinya Kitaoka 120a6e
           ::isInsideAMacroFx(link.m_outputFx.getPointer(), m_xsh);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct FilterNonTerminalFxs {
Shinya Kitaoka 120a6e
  TXsheet *xsh;
Shinya Kitaoka 120a6e
  inline bool operator()(const TFxP &fx) {
Shinya Kitaoka 120a6e
    return !xsh->getFxDag()->getTerminalFxs()->containsFx(fx.getPointer());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct FilterTerminalFxs {
Shinya Kitaoka 120a6e
  TXsheet *xsh;
Shinya Kitaoka 120a6e
  inline bool operator()(const TFxP &fx) {
Shinya Kitaoka 120a6e
    return xsh->getFxDag()->getTerminalFxs()->containsFx(fx.getPointer());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct FilterColumnFxs {
Shinya Kitaoka 120a6e
  inline bool operator()(const TFxP &fx) {
Shinya Kitaoka 120a6e
    return dynamic_cast<tlevelcolumnfx *="">(fx.getPointer());</tlevelcolumnfx>
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    CloneFxFunctor  definition
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct CloneFxFunctor {
Shinya Kitaoka 120a6e
  TFxP m_src;
Shinya Kitaoka 120a6e
  bool m_ownsSrc;
Shinya Kitaoka 120a6e
  TFx *operator()() {
Shinya Kitaoka 120a6e
    if (m_ownsSrc)
Shinya Kitaoka 120a6e
      m_ownsSrc = false;  // Transfer m_src and ownership if it
Shinya Kitaoka 120a6e
    else                  // was surrendered
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      assert(m_src->getRefCount() >
Shinya Kitaoka 120a6e
             1);  // We'll be linking params to the cloned
Shinya Kitaoka 120a6e
                  // fx - so it MUST NOT be destroyed on release
Shinya Kitaoka 120a6e
      TFx *src = m_src.getPointer();
Shinya Kitaoka 120a6e
      m_src    = m_src->clone(false);  // Duplicate and link parameters all
Shinya Kitaoka 120a6e
      m_src->linkParams(src);          // the following times
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    return m_src.getPointer();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    FxCommandUndo  definition
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class FxCommandUndo : public TUndo {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  virtual ~FxCommandUndo() {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  virtual bool isConsistent() const = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  template <typename pred=""></typename>
Shinya Kitaoka 120a6e
  static TFx *leftmostConnectedFx(TFx *fx, Pred pred);
Shinya Kitaoka 120a6e
  template <typename pred=""></typename>
Shinya Kitaoka 120a6e
  static TFx *rightmostConnectedFx(TFx *fx, Pred pred);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  static TFx *leftmostConnectedFx(TFx *fx);
Shinya Kitaoka 120a6e
  static TFx *rightmostConnectedFx(TFx *fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  static std::vector<tfxcommand::link> inputLinks(TXsheet *xsh, TFx *fx);</tfxcommand::link>
Shinya Kitaoka 120a6e
  static std::vector<tfxcommand::link> outputLinks(TXsheet *xsh, TFx *fx);</tfxcommand::link>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getHistoryType() override { return HistoryType::Schematic; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  static TXshZeraryFxColumn *createZeraryFxColumn(TXsheet *xsh, TFx *zfx,
Shinya Kitaoka 120a6e
                                                  int row = 0);
Shinya Kitaoka 120a6e
  static void cloneGroupStack(const QStack<int> &groupIds,</int>
Shinya Kitaoka 120a6e
                              const QStack<std::wstring> &groupNames,</std::wstring>
Shinya Kitaoka 120a6e
                              TFx *toFx);
Shinya Kitaoka 120a6e
  static void cloneGroupStack(TFx *fromFx, TFx *toFx);
Shinya Kitaoka 120a6e
  static void copyGroupEditLevel(int editGroupId, TFx *toFx);
Shinya Kitaoka 120a6e
  static void copyGroupEditLevel(TFx *fromFx, TFx *toFx);
Shinya Kitaoka 120a6e
  static void copyDagPosition(TFx *fromFx, TFx *toFx);
Shinya Kitaoka 120a6e
  static void attach(TXsheet *xsh, TFx *inputFx, TFx *outputFx, int port,
Shinya Kitaoka 120a6e
                     bool copyGroupData);
Shinya Kitaoka 120a6e
  static void attach(TXsheet *xsh, const TFxCommand::Link &link,
Shinya Kitaoka 120a6e
                     bool copyGroupData);
Shinya Kitaoka 120a6e
  static void attachOutputs(TXsheet *xsh, TFx *insertedFx, TFx *inputFx);
Shinya Kitaoka 120a6e
  static void detachFxs(TXsheet *xsh, TFx *fxLeft, TFx *fxRight,
Shinya Kitaoka 120a6e
                        bool detachLeft = true);
Shinya Kitaoka 120a6e
  static void insertFxs(TXsheet *xsh, const TFxCommand::Link &link, TFx *fxLeft,
Shinya Kitaoka 120a6e
                        TFx *fxRight);
Shinya Kitaoka 120a6e
  static void insertColumn(TXsheet *xsh, TXshColumn *column, int colIdx,
Shinya Kitaoka 120a6e
                           bool removeHole = false, bool autoTerminal = false);
Shinya Kitaoka 120a6e
  static void removeFxOrColumn(TXsheet *xsh, TFx *fx, int colIdx,
Shinya Kitaoka 120a6e
                               bool insertHole   = false,
Shinya Kitaoka 120a6e
                               bool unlinkParams = true);
Shinya Kitaoka 120a6e
  static void linkParams(TFx *fx, TFx *linkedFx);
Shinya Kitaoka 120a6e
  static void unlinkParams(TFx *fx);
Shinya Kitaoka 120a6e
  static void makeNotCurrent(TFxHandle *fxHandle, TFx *fx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  static void removeColumn(TXsheet *xsh, int colIdx, bool insertHole);
Shinya Kitaoka 120a6e
  static void removeNormalFx(TXsheet *xsh, TFx *fx);
Shinya Kitaoka 120a6e
  static void removeOutputFx(TXsheet *xsh, TOutputFx *outputFx);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TXshZeraryFxColumn *FxCommandUndo::createZeraryFxColumn(TXsheet *xsh, TFx *zfx,
Shinya Kitaoka 120a6e
                                                        int row) {
Shinya Kitaoka 120a6e
  int frameCount = xsh->getScene()->getFrameCount() - row;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXshZeraryFxColumn *column =
Shinya Kitaoka 120a6e
      new TXshZeraryFxColumn(frameCount > 0 ? frameCount : 100);
Shinya Kitaoka 120a6e
  column->getZeraryColumnFx()->setZeraryFx(zfx);
Shinya Kitaoka 120a6e
  column->insertEmptyCells(0, row);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return column;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::cloneGroupStack(const QStack<int> &groupIds,</int>
Shinya Kitaoka 120a6e
                                    const QStack<std::wstring> &groupNames,</std::wstring>
Shinya Kitaoka 120a6e
                                    TFx *toFx) {
Shinya Kitaoka 120a6e
  toFx->getAttributes()->removeFromAllGroup();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int i = 0; i < groupIds.size(); ++i) {
Shinya Kitaoka 120a6e
    toFx->getAttributes()->setGroupId(groupIds[i]);
Shinya Kitaoka 120a6e
    toFx->getAttributes()->setGroupName(groupNames[i]);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::cloneGroupStack(TFx *fromFx, TFx *toFx) {
Shinya Kitaoka 120a6e
  if (fromFx->getAttributes()->isGrouped()) {
Shinya Kitaoka 120a6e
    cloneGroupStack(fromFx->getAttributes()->getGroupIdStack(),
Shinya Kitaoka 120a6e
                    fromFx->getAttributes()->getGroupNameStack(), toFx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::copyGroupEditLevel(int editGroupId, TFx *toFx) {
Shinya Kitaoka 120a6e
  toFx->getAttributes()->closeAllGroups();
Shinya Kitaoka 120a6e
  while (editGroupId != toFx->getAttributes()->getEditingGroupId() &&
Shinya Kitaoka 120a6e
         toFx->getAttributes()->editGroup())
Shinya Kitaoka 120a6e
    ;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(editGroupId == toFx->getAttributes()->getEditingGroupId());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::copyGroupEditLevel(TFx *fromFx, TFx *toFx) {
Shinya Kitaoka 120a6e
  assert(toFx);
Shinya Kitaoka 120a6e
  if (fromFx && fromFx->getAttributes()->isGrouped())
Shinya Kitaoka 120a6e
    copyGroupEditLevel(fromFx->getAttributes()->getEditingGroupId(), toFx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::copyDagPosition(TFx *fromFx, TFx *toFx) {
Shinya Kitaoka 120a6e
  assert(toFx);
Shinya Kitaoka 120a6e
  if (fromFx)
Shinya Kitaoka 120a6e
    toFx->getAttributes()->setDagNodePos(
Shinya Kitaoka 120a6e
        fromFx->getAttributes()->getDagNodePos());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void FxCommandUndo::attach(TXsheet *xsh, TFx *inputFx, TFx *outputFx, int link,
Shinya Kitaoka 120a6e
                           bool copyGroupData) {
Shinya Kitaoka 120a6e
  if (outputFx) {
Shinya Kitaoka 120a6e
    FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    inputFx  = ::getActualOut(inputFx);
Shinya Kitaoka 120a6e
    outputFx = ::getActualIn(outputFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (inputFx && link < 0) {
Shinya Kitaoka 120a6e
      assert(dynamic_cast<txsheetfx *="">(outputFx));</txsheetfx>
Shinya Kitaoka 120a6e
      fxDag->addToXsheet(inputFx);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      int ipCount = outputFx->getInputPortCount();
Shinya Kitaoka 120a6e
      if (ipCount > 0 && link < ipCount)
Shinya Kitaoka 120a6e
        outputFx->getInputPort(link)->setFx(inputFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      if (copyGroupData) copyGroupEditLevel(inputFx, outputFx);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::attach(TXsheet *xsh, const TFxCommand::Link &link,
Shinya Kitaoka 120a6e
                           bool copyGroupData) {
Shinya Kitaoka 120a6e
  attach(xsh, link.m_inputFx.getPointer(), link.m_outputFx.getPointer(),
Shinya Kitaoka 120a6e
         link.m_index, copyGroupData);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::attachOutputs(TXsheet *xsh, TFx *insertedFx, TFx *inputFx) {
Shinya Kitaoka 120a6e
  TCG_ASSERT(inputFx, return );
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  insertedFx = ::getActualOut(insertedFx);
Shinya Kitaoka 120a6e
  inputFx    = ::getActualOut(inputFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int p, pCount = inputFx->getOutputConnectionCount();
Shinya Kitaoka 120a6e
  for (p = pCount - 1; p >= 0;
Shinya Kitaoka 120a6e
       --p)  // Backward iteration on output connections -
Shinya Kitaoka 120a6e
  {          // it's necessary since TFxPort::setFx() REMOVES
Shinya Kitaoka 120a6e
    TFxPort *port = inputFx->getOutputConnection(
Shinya Kitaoka 120a6e
        p);  // the corresponding port int the output connections
Shinya Kitaoka 120a6e
    port->setFx(
Shinya Kitaoka 120a6e
        insertedFx);  // container - thus, it's better to start from the end
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (fxDag->getTerminalFxs()->containsFx(inputFx)) {
Shinya Kitaoka 120a6e
    fxDag->removeFromXsheet(inputFx);
Shinya Kitaoka 120a6e
    fxDag->addToXsheet(insertedFx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::detachFxs(TXsheet *xsh, TFx *fxLeft, TFx *fxRight,
Shinya Kitaoka 120a6e
                              bool detachLeft) {
Shinya Kitaoka 120a6e
  assert(fxLeft && fxRight);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  fxLeft  = ::getActualIn(fxLeft);
Shinya Kitaoka 120a6e
  fxRight = ::getActualOut(fxRight);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int ipCount = fxLeft->getInputPortCount();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Redirect input/output ports
Shinya Kitaoka 120a6e
  TFx *inputFx0 = (ipCount > 0) ? fxLeft->getInputPort(0)->getFx() : 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int p, opCount = fxRight->getOutputConnectionCount();
Shinya Kitaoka 120a6e
  for (p = opCount - 1; p >= 0;
Shinya Kitaoka 120a6e
       --p)  // Backward iteration due to TFxPort::setFx()
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    TFxPort *outPort = fxRight->getOutputConnection(p);
Shinya Kitaoka 120a6e
    assert(outPort && outPort->getFx() == fxRight);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    outPort->setFx(inputFx0);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Xsheet links redirection
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Shinya Kitaoka 120a6e
  if (fxDag->getTerminalFxs()->containsFx(fxRight)) {
Shinya Kitaoka 120a6e
    fxDag->removeFromXsheet(fxRight);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    for (int p = 0; p != ipCount; ++p)
Shinya Kitaoka 120a6e
      if (TFx *inputFx = fxLeft->getInputPort(p)->getFx())
Shinya Kitaoka 120a6e
        fxDag->addToXsheet(inputFx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (detachLeft) fxLeft->disconnectAll();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void FxCommandUndo::insertFxs(TXsheet *xsh, const TFxCommand::Link &link,
Shinya Kitaoka 120a6e
                              TFx *fxLeft, TFx *fxRight) {
Shinya Kitaoka 120a6e
  assert(fxLeft && fxRight);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (link.m_inputFx && link.m_outputFx) {
Shinya Kitaoka 120a6e
    FxCommandUndo::attach(xsh, link.m_inputFx.getPointer(), fxLeft, 0, false);
Shinya Kitaoka 120a6e
    FxCommandUndo::attach(xsh, fxRight, link.m_outputFx.getPointer(),
Shinya Kitaoka 120a6e
                          link.m_index, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (link.m_index < 0)
Shinya Kitaoka 120a6e
      xsh->getFxDag()->removeFromXsheet(
Shinya Kitaoka 120a6e
          ::getActualOut(link.m_inputFx.getPointer()));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void FxCommandUndo::insertColumn(TXsheet *xsh, TXshColumn *column, int col,
Shinya Kitaoka 120a6e
                                 bool removeHole, bool autoTerminal) {
Shinya Kitaoka 120a6e
  FxDag *fxDag  = xsh->getFxDag();
Shinya Kitaoka 120a6e
  TFx *fx       = column->getFx();
Shinya Kitaoka 120a6e
  bool terminal = false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (fx) {
Shinya Kitaoka 120a6e
    ::showFx(xsh, fx);
Shinya Kitaoka 120a6e
    terminal = fxDag->getTerminalFxs()->containsFx(fx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (removeHole) xsh->removeColumn(col);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  xsh->insertColumn(col, column);  // Attaches the fx to the xsheet, too -
Shinya Kitaoka 120a6e
                                   // but not if the column is a palette one.
Shinya Kitaoka 120a6e
  if (!autoTerminal) {
Shinya Kitaoka 120a6e
    // Preserve the initial terminal state.
Shinya Kitaoka 120a6e
    // This lets fxs to be linked to the xsheet while still hidden.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    fxDag->removeFromXsheet(fx);
Shinya Kitaoka 120a6e
    if (terminal) fxDag->addToXsheet(fx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  xsh->updateFrameCount();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::removeColumn(TXsheet *xsh, int col, bool insertHole) {
Shinya Kitaoka 120a6e
  if (TFx *colFx = xsh->getColumn(col)->getFx()) {
Shinya Kitaoka 120a6e
    detachFxs(xsh, colFx, colFx);
Shinya Kitaoka 120a6e
    ::hideFx(xsh, colFx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  xsh->removeColumn(col);    // Already detaches any fx in output,
Shinya Kitaoka 120a6e
  if (insertHole)            // including the terminal case
Shinya Kitaoka 120a6e
    xsh->insertColumn(col);  // Note that fxs in output are not
Shinya Kitaoka 120a6e
                             // removed - just detached.
Shinya Kitaoka 120a6e
  xsh->updateFrameCount();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::removeNormalFx(TXsheet *xsh, TFx *fx) {
Shinya Kitaoka 120a6e
  detachFxs(xsh, fx, fx);
Shinya Kitaoka 120a6e
  ::removeFxFromCurrentScene(fx, xsh);  // Already hideFx()s
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::removeOutputFx(TXsheet *xsh, TOutputFx *outputFx) {
Shinya Kitaoka 120a6e
  detachFxs(xsh, outputFx, outputFx);
Shinya Kitaoka 120a6e
  xsh->getFxDag()->removeOutputFx(outputFx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::linkParams(TFx *fx, TFx *linkedFx) {
Shinya Kitaoka 120a6e
  if (linkedFx) ::getActualIn(fx)->linkParams(::getActualIn(linkedFx));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::unlinkParams(TFx *fx) {
Shinya Kitaoka 120a6e
  if (fx = ::getActualIn(fx), fx->getLinkedFx()) fx->unlinkParams();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FxCommandUndo::makeNotCurrent(TFxHandle *fxHandle, TFx *fx) {
Shinya Kitaoka 120a6e
  if (fx = ::getActualOut(fx), fx == fxHandle->getFx()) fxHandle->setFx(0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void FxCommandUndo::removeFxOrColumn(TXsheet *xsh, TFx *fx, int colIdx,
Shinya Kitaoka 120a6e
                                     bool insertHole, bool unlinkParams) {
Shinya Kitaoka 120a6e
  assert(fx || colIdx >= 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!fx)
Shinya Kitaoka 120a6e
    fx = xsh->getColumn(colIdx)->getFx();
Shinya Kitaoka 120a6e
  else if (TColumnFx *colFx = dynamic_cast<tcolumnfx *="">(fx))</tcolumnfx>
Shinya Kitaoka 120a6e
    colIdx = colFx->getColumnIndex();
Shinya Kitaoka 120a6e
  else if (TZeraryFx *zfx = dynamic_cast<tzeraryfx *="">(fx)) {</tzeraryfx>
Shinya Kitaoka 120a6e
    if (zfx->getColumnFx())
Shinya Kitaoka 120a6e
      fx     = zfx->getColumnFx(),
Shinya Kitaoka 120a6e
      colIdx = static_cast<tcolumnfx *="">(fx)->getColumnIndex();</tcolumnfx>
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (fx) {
Shinya Kitaoka 120a6e
    // Discriminate special fx types
Shinya Kitaoka 120a6e
    if (TZeraryColumnFx *zcfx = dynamic_cast<tzerarycolumnfx *="">(fx)) {</tzerarycolumnfx>
Shinya Kitaoka 120a6e
      // Removed as a column
Shinya Kitaoka 120a6e
      fx = zcfx->getZeraryFx();
Shinya Kitaoka 120a6e
    } else if (TOutputFx *outputFx = dynamic_cast<toutputfx *="">(fx)) {</toutputfx>
Shinya Kitaoka 120a6e
      assert(xsh->getFxDag()->getOutputFxCount() > 1);
Shinya Kitaoka 120a6e
      FxCommandUndo::removeOutputFx(xsh, outputFx);
Shinya Kitaoka 120a6e
    } else if (colIdx < 0)
Shinya Kitaoka 120a6e
      FxCommandUndo::removeNormalFx(xsh, fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (unlinkParams) FxCommandUndo::unlinkParams(fx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (colIdx >= 0) FxCommandUndo::removeColumn(xsh, colIdx, insertHole);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pred=""></typename>
Shinya Kitaoka 120a6e
TFx *FxCommandUndo::leftmostConnectedFx(TFx *fx, Pred pred) {
Shinya Kitaoka 120a6e
  assert(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  fx = rightmostConnectedFx(
Shinya Kitaoka 120a6e
      fx, pred);  // The rightmost fx should be discovered first,
Shinya Kitaoka 120a6e
                  // then, we'll descend from that
Shinya Kitaoka 120a6e
  do {
Shinya Kitaoka 120a6e
    fx = ::getActualIn(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (!((fx->getInputPortCount() > 0) && fx->getInputPort(0)->isConnected() &&
Shinya Kitaoka 120a6e
          pred(fx->getInputPort(0)->getFx())))
Shinya Kitaoka 120a6e
      break;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    fx = fx->getInputPort(0)->getFx();
Shinya Kitaoka 120a6e
  } while (true);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return fx;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pred=""></typename>
Shinya Kitaoka 120a6e
TFx *FxCommandUndo::rightmostConnectedFx(TFx *fx, Pred pred) {
Shinya Kitaoka 120a6e
  assert(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  do {
Shinya Kitaoka 120a6e
    fx = ::getActualOut(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (!(fx->getOutputConnectionCount() > 0 &&
Shinya Kitaoka 120a6e
          pred(fx->getOutputConnection(0)->getOwnerFx())))
Shinya Kitaoka 120a6e
      break;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    fx = fx->getOutputConnection(0)->getOwnerFx();
Shinya Kitaoka 120a6e
  } while (true);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return fx;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
struct True_pred {
Shinya Kitaoka 120a6e
  bool operator()(TFx *fx) { return true; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFx *FxCommandUndo::leftmostConnectedFx(TFx *fx) {
Shinya Kitaoka 120a6e
  return leftmostConnectedFx(fx, ::True_pred());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFx *FxCommandUndo::rightmostConnectedFx(TFx *fx) {
Shinya Kitaoka 120a6e
  return rightmostConnectedFx(fx, ::True_pred());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::vector<tfxcommand::link> FxCommandUndo::inputLinks(TXsheet *xsh, TFx *fx) {</tfxcommand::link>
Shinya Kitaoka 120a6e
  std::vector<tfxcommand::link> result;</tfxcommand::link>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  fx = ::getActualIn(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int il, ilCount = fx->getInputPortCount();
Shinya Kitaoka 120a6e
  for (il = 0; il != ilCount; ++il) {
Shinya Kitaoka 120a6e
    TFxPort *port = fx->getInputPort(il);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    assert(port);
Shinya Kitaoka 120a6e
    if (port->isConnected())
Shinya Kitaoka 120a6e
      result.push_back(TFxCommand::Link(port->getFx(), fx, il));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::vector<tfxcommand::link> FxCommandUndo::outputLinks(TXsheet *xsh,</tfxcommand::link>
Shinya Kitaoka 120a6e
                                                         TFx *fx) {
Shinya Kitaoka 120a6e
  std::vector<tfxcommand::link> result;</tfxcommand::link>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  fx = ::getActualOut(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int ol, olCount = fx->getOutputConnectionCount();
Shinya Kitaoka 120a6e
  for (ol = 0; ol != olCount; ++ol) {
Shinya Kitaoka 120a6e
    TFxPort *port = fx->getOutputConnection(ol);
Shinya Kitaoka 120a6e
    TFx *ownerFx  = port->getOwnerFx();
Shinya Kitaoka 120a6e
    int portIndex = ::inputPortIndex(ownerFx, port);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    result.push_back(TFxCommand::Link(fx, ownerFx, portIndex));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Shinya Kitaoka 120a6e
  if (fxDag->getTerminalFxs()->containsFx(fx))
Shinya Kitaoka 120a6e
    result.push_back(TFxCommand::Link(fx, fxDag->getXsheetFx(), -1));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Insert Fx  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class InsertFxUndo final : public FxCommandUndo {
Shinya Kitaoka 120a6e
  QList<tfxp> m_selectedFxs;</tfxp>
Shinya Kitaoka 120a6e
  QList<tfxcommand::link> m_selectedLinks;</tfxcommand::link>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TApplication *m_app;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QList<tfxp> m_insertedFxs;</tfxp>
Shinya Kitaoka 120a6e
  TXshZeraryFxColumnP m_insertedColumn;
Shinya Kitaoka 120a6e
  int m_colIdx;
Shinya Kitaoka 120a6e
  bool m_columnReplacesHole;
Shinya Kitaoka 120a6e
  bool m_attachOutputs;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  InsertFxUndo(const TFxP &fx, int row, int col, const QList<tfxp> &selectedFxs,</tfxp>
Shinya Kitaoka 120a6e
               QList<tfxcommand::link> selectedLinks, TApplication *app,</tfxcommand::link>
Shinya Kitaoka 120a6e
               bool attachOutputs = true)
Shinya Kitaoka 120a6e
      : m_selectedFxs(selectedFxs)
Shinya Kitaoka 120a6e
      , m_selectedLinks(selectedLinks)
Shinya Kitaoka 120a6e
      , m_insertedColumn(0)
Shinya Kitaoka 120a6e
      , m_app(app)
Shinya Kitaoka 120a6e
      , m_colIdx(col)
Shinya Kitaoka 120a6e
      , m_columnReplacesHole(false)
Shinya Kitaoka 120a6e
      , m_attachOutputs(attachOutputs) {
Shinya Kitaoka 120a6e
    initialize(fx, row, col);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool isConsistent() const override { return !m_insertedFxs.isEmpty(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize(const TFxP &newFx, int row, int col);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline bool has_fx_column(TFx *fx) {
Shinya Kitaoka 120a6e
  if (TPluginInterface *plgif = dynamic_cast<tplugininterface *="">(fx))</tplugininterface>
Shinya Kitaoka 120a6e
    return plgif->isPluginZerary();
Shinya Kitaoka 120a6e
  else if (TZeraryFx *zfx = dynamic_cast<tzeraryfx *="">(fx))</tzeraryfx>
Shinya Kitaoka 120a6e
    return zfx->isZerary();
Shinya Kitaoka 120a6e
  return false;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
bool containsInputFx(const QList<tfxp> &fxs, const TFxCommand::Link &link) {</tfxp>
Shinya Kitaoka 120a6e
  return fxs.contains(link.m_inputFx);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
typedef tcg::function<bool (*)(const="" qlist<tfxp=""> &, const TFxCommand::Link &),</bool>
Shinya Kitaoka 120a6e
                      containsInputFx>
Shinya Kitaoka 120a6e
    ContainsInputFx_fun;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
}  // namespace
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void InsertFxUndo::initialize(const TFxP &newFx, int row, int col) {
Shinya Kitaoka 120a6e
  struct Locals {
Shinya Kitaoka 120a6e
    InsertFxUndo *m_this;
Shinya Kitaoka 120a6e
    inline void storeFx(TXsheet *xsh, TFx *fx) {
Shinya Kitaoka 120a6e
      ::initializeFx(xsh, fx);
Shinya Kitaoka 120a6e
      m_this->m_insertedFxs.push_back(fx);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  } locals = {this};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_app->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  TFx *fx      = newFx.getPointer();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(!dynamic_cast<tzerarycolumnfx *="">(fx));</tzerarycolumnfx>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TZeraryFx *zfx = dynamic_cast<tzeraryfx *="">(fx);</tzeraryfx>
Shinya Kitaoka 120a6e
  if (has_fx_column(fx)) {
Shinya Kitaoka 120a6e
    m_insertedColumn = InsertFxUndo::createZeraryFxColumn(xsh, fx, row);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    locals.storeFx(xsh, fx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (xsh->getColumn(col) && xsh->getColumn(col)->isEmpty())
Shinya Kitaoka 120a6e
      m_columnReplacesHole = true;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    if (m_selectedFxs.isEmpty() && m_selectedLinks.isEmpty()) {
Shinya Kitaoka 120a6e
      // Attempt retrieval of current Fx from the fxHandle
Shinya Kitaoka 120a6e
      if (TFx *currentFx = m_app->getCurrentFx()->getFx())
Shinya Kitaoka 120a6e
        m_selectedFxs.push_back(currentFx);
Shinya Kitaoka 120a6e
      else {
Shinya Kitaoka 120a6e
        // Isolated case
Shinya Kitaoka 120a6e
        locals.storeFx(xsh, fx);
Shinya Kitaoka 120a6e
        return;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Remove all unacceptable input fxs
Shinya Kitaoka 120a6e
    ::FilterInsideAMacro filterInMacroFxs = {xsh};
Shinya Kitaoka 120a6e
    m_selectedFxs.erase(std::remove_if(m_selectedFxs.begin(),
Shinya Kitaoka 120a6e
                                       m_selectedFxs.end(), filterInMacroFxs),
Shinya Kitaoka 120a6e
                        m_selectedFxs.end());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Remove all unacceptable links or links whose input fx was already
Shinya Kitaoka 120a6e
    // selected
Shinya Kitaoka 120a6e
    m_selectedLinks.erase(
Shinya Kitaoka 120a6e
        std::remove_if(m_selectedLinks.begin(), m_selectedLinks.end(),
Shinya Kitaoka 120a6e
                       filterInMacroFxs),
Shinya Kitaoka 120a6e
        m_selectedLinks.end());
Shinya Kitaoka 120a6e
    m_selectedLinks.erase(
Shinya Kitaoka 120a6e
        std::remove_if(m_selectedLinks.begin(), m_selectedLinks.end(),
Shinya Kitaoka 120a6e
                       tcg::bind1st(::ContainsInputFx_fun(), m_selectedFxs)),
Shinya Kitaoka 120a6e
        m_selectedLinks.end());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Build an fx for each of the specified inputs
Shinya Kitaoka 120a6e
    ::CloneFxFunctor cloneFx = {fx, true};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int f, fCount = m_selectedFxs.size();
Shinya Kitaoka 120a6e
    for (f = 0; f != fCount; ++f) {
Shinya Kitaoka 120a6e
      TFx *fx = cloneFx();
Shinya Kitaoka 120a6e
      FxCommandUndo::cloneGroupStack(m_selectedFxs[f].getPointer(), fx);
Shinya Kitaoka 120a6e
      locals.storeFx(xsh, fx);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    fCount = m_selectedLinks.size();
Shinya Kitaoka 120a6e
    for (f = 0; f != fCount; ++f) {
Shinya Kitaoka 120a6e
      TFx *fx = cloneFx();
Shinya Kitaoka 120a6e
      FxCommandUndo::cloneGroupStack(m_selectedLinks[f].m_inputFx.getPointer(),
Shinya Kitaoka 120a6e
                                     fx);
Shinya Kitaoka 120a6e
      locals.storeFx(xsh, fx);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void InsertFxUndo::redo() const {
Shinya Kitaoka 120a6e
  struct OnExit {
Shinya Kitaoka 120a6e
    const InsertFxUndo *m_this;
Shinya Kitaoka 120a6e
    ~OnExit() {
Shinya Kitaoka 120a6e
      m_this->m_app->getCurrentFx()->setFx(
Shinya Kitaoka 120a6e
          m_this->m_insertedFxs.back().getPointer());
Shinya Kitaoka 120a6e
      m_this->m_app->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
      m_this->m_app->getCurrentScene()->setDirtyFlag(true);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } onExit = {this};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_app->getCurrentXsheet()->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Zerary case
Shinya Kitaoka 120a6e
  if (m_insertedColumn) {
Shinya Kitaoka 120a6e
    FxCommandUndo::insertColumn(xsh, m_insertedColumn.getPointer(), m_colIdx,
Shinya Kitaoka 120a6e
                                m_columnReplacesHole, true);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Isolated Fx case
Shinya Kitaoka 120a6e
  if (m_selectedLinks.isEmpty() && m_selectedFxs.isEmpty()) {
Shinya Kitaoka 120a6e
    assert(m_insertedFxs.size() == 1);
Shinya Kitaoka 120a6e
    ::addFxToCurrentScene(m_insertedFxs.back().getPointer(), xsh,
Shinya Kitaoka 120a6e
                          false);  // Already showFx()s
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // Selected links
Shinya Kitaoka 120a6e
    int i;
Shinya Kitaoka 120a6e
    for (i = 0; i < m_selectedLinks.size(); ++i) {
Shinya Kitaoka 120a6e
      const TFxCommand::Link &link = m_selectedLinks[i];
Shinya Kitaoka 120a6e
      TFx *insertedFx              = m_insertedFxs[i].getPointer();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      ::addFxToCurrentScene(insertedFx, xsh, false);
Shinya Kitaoka 120a6e
      FxCommandUndo::insertFxs(xsh, link, insertedFx, insertedFx);
Shinya Kitaoka 120a6e
      FxCommandUndo::copyGroupEditLevel(link.m_inputFx.getPointer(),
Shinya Kitaoka 120a6e
                                        insertedFx);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Selected fxs
Shinya Kitaoka 120a6e
    int j, t;
Shinya Kitaoka 120a6e
    for (j = 0, t = 0; j < m_selectedFxs.size(); j++) {
Shinya Kitaoka 120a6e
      TFx *fx = m_selectedFxs[j].getPointer();
Shinya Kitaoka 120a6e
      assert(fx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TFx *insertedFx = m_insertedFxs[i + t].getPointer();
Shinya Kitaoka 120a6e
      t++;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      assert(insertedFx);
Shinya Kitaoka 120a6e
      ::addFxToCurrentScene(insertedFx, xsh, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (m_attachOutputs) FxCommandUndo::attachOutputs(xsh, insertedFx, fx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      FxCommandUndo::attach(xsh, fx, insertedFx, 0, true);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void InsertFxUndo::undo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_app->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i, iCount = m_insertedFxs.size();
Shinya Kitaoka 120a6e
  for (i = 0; i != iCount; ++i) {
Shinya Kitaoka 120a6e
    TFx *insertedFx = m_insertedFxs[i].getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    FxCommandUndo::removeFxOrColumn(xsh, insertedFx, -1, m_columnReplacesHole,
Shinya Kitaoka 120a6e
                                    false);  // Skip parameter links removal
Shinya Kitaoka 120a6e
    FxCommandUndo::makeNotCurrent(m_app->getCurrentFx(), insertedFx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_app->getCurrentFx()->setFx(0);
Shinya Kitaoka 120a6e
  m_app->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
  m_app->getCurrentScene()->setDirtyFlag(true);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString InsertFxUndo::getHistoryString() {
Shinya Kitaoka 120a6e
  QString str = (m_selectedLinks.isEmpty()) ? QObject::tr("Add Fx  : ")
Shinya Kitaoka 120a6e
                                            : QObject::tr("Insert Fx  : ");
Shinya Kitaoka 120a6e
  QList<tfxp>::iterator it;</tfxp>
Shinya Kitaoka 120a6e
  for (it = m_insertedFxs.begin(); it != m_insertedFxs.end(); it++) {
Shinya Kitaoka 120a6e
    if (it != m_insertedFxs.begin()) str += QString(", ");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    str += QString::fromStdWString((*it)->getFxId());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return str;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::insertFx(TFx *newFx, const QList<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                          const QList<link> &links, TApplication *app, int col,
Shinya Kitaoka 120a6e
                          int row) {
Shinya Kitaoka 120a6e
  if (!newFx) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(</fxcommandundo>
Shinya Kitaoka 120a6e
      new InsertFxUndo(newFx, row, col, fxs, links, app));
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Add Fx  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::addFx(TFx *newFx, const QList<tfxp> &fxs, TApplication *app,</tfxp>
Shinya Kitaoka 120a6e
                       int col, int row) {
Shinya Kitaoka 120a6e
  if (!newFx) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(</fxcommandundo>
Shinya Kitaoka 120a6e
      new InsertFxUndo(newFx, row, col, fxs, QList<link>(), app, false));
Shinya Kitaoka 120a6e
  if (!undo->isConsistent()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  undo->redo();
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(undo.release());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Duplicate Fx  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class DuplicateFxUndo final : public FxCommandUndo {
Shinya Kitaoka 120a6e
  TFxP m_fx, m_dupFx;
Shinya Kitaoka 120a6e
  TXshColumnP m_column;
Shinya Kitaoka 120a6e
  int m_colIdx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Shinya Kitaoka 120a6e
  TFxHandle *m_fxHandle;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  DuplicateFxUndo(const TFxP &originalFx, TXsheetHandle *xshHandle,
Shinya Kitaoka 120a6e
                  TFxHandle *fxHandle)
Shinya Kitaoka 120a6e
      : m_fx(originalFx)
Shinya Kitaoka 120a6e
      , m_colIdx(-1)
Shinya Kitaoka 120a6e
      , m_xshHandle(xshHandle)
Shinya Kitaoka 120a6e
      , m_fxHandle(fxHandle) {
Shinya Kitaoka 120a6e
    initialize();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool isConsistent() const override { return bool(m_dupFx); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DuplicateFxUndo::initialize() {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  TFx *fx      = m_fx.getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  fx = ::getActualOut(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (isInsideAMacroFx(fx, xsh) || dynamic_cast<txsheetfx *="">(fx) ||</txsheetfx>
Shinya Kitaoka 120a6e
      dynamic_cast<toutputfx *="">(fx) ||</toutputfx>
Shinya Kitaoka 120a6e
      (dynamic_cast<tcolumnfx *="">(fx) && !dynamic_cast<tzerarycolumnfx *="">(fx)))</tzerarycolumnfx></tcolumnfx>
Shinya Kitaoka 120a6e
    return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (TZeraryColumnFx *zcfx = dynamic_cast<tzerarycolumnfx *="">(fx)) {</tzerarycolumnfx>
Shinya Kitaoka 120a6e
    m_column = new TXshZeraryFxColumn(*zcfx->getColumn());
Shinya Kitaoka 120a6e
    m_colIdx = xsh->getFirstFreeColumnIndex();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TZeraryColumnFx *dupZcfx =
Shinya Kitaoka 120a6e
        static_cast<tzerarycolumnfx *="">(m_column->getFx());</tzerarycolumnfx>
Shinya Kitaoka 120a6e
    ::initializeFx(xsh, dupZcfx->getZeraryFx());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    FxCommandUndo::cloneGroupStack(zcfx, dupZcfx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_dupFx = dupZcfx;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    fx = fx->clone(false);
Shinya Kitaoka 120a6e
    ::initializeFx(xsh, fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    FxCommandUndo::cloneGroupStack(m_fx.getPointer(), fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_dupFx = fx;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DuplicateFxUndo::redo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_column) {
Shinya Kitaoka 120a6e
    // Zerary Fx case
Shinya Kitaoka 120a6e
    TZeraryColumnFx *zcfx = static_cast<tzerarycolumnfx *="">(m_fx.getPointer());</tzerarycolumnfx>
Shinya Kitaoka 120a6e
    TZeraryColumnFx *dupZcfx =
Shinya Kitaoka 120a6e
        static_cast<tzerarycolumnfx *="">(m_dupFx.getPointer());</tzerarycolumnfx>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    FxCommandUndo::insertColumn(xsh, m_column.getPointer(), m_colIdx, true,
Shinya Kitaoka 120a6e
                                true);
Shinya Kitaoka 120a6e
    FxCommandUndo::copyGroupEditLevel(zcfx, dupZcfx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    dupZcfx->getZeraryFx()->linkParams(zcfx->getZeraryFx());
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // Normal Fx case
Shinya Kitaoka 120a6e
    addFxToCurrentScene(m_dupFx.getPointer(), m_xshHandle->getXsheet(), false);
Shinya Kitaoka 120a6e
    FxCommandUndo::copyGroupEditLevel(m_fx.getPointer(), m_dupFx.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_dupFx->linkParams(m_fx.getPointer());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_fxHandle->setFx(m_dupFx.getPointer());
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DuplicateFxUndo::undo() const {
Shinya Kitaoka 120a6e
  FxCommandUndo::removeFxOrColumn(m_xshHandle->getXsheet(),
Shinya Kitaoka 120a6e
                                  m_dupFx.getPointer(), -1, true, true);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_fxHandle->setFx(0);
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString DuplicateFxUndo::getHistoryString() {
Shinya Kitaoka 120a6e
  if (TZeraryColumnFx *zDup =
Shinya Kitaoka 120a6e
          dynamic_cast<tzerarycolumnfx *="">(m_dupFx.getPointer()))</tzerarycolumnfx>
Shinya Kitaoka 120a6e
    return QObject::tr("Create Linked Fx  : %1")
Shinya Kitaoka 120a6e
        .arg(QString::fromStdWString(zDup->getZeraryFx()->getFxId()));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return QObject::tr("Create Linked Fx  : %1")
Shinya Kitaoka 120a6e
      .arg(QString::fromStdWString(m_dupFx->getFxId()));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::duplicateFx(TFx *src, TXsheetHandle *xshHandle,
Shinya Kitaoka 120a6e
                             TFxHandle *fxHandle) {
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(</fxcommandundo>
Shinya Kitaoka 120a6e
      new DuplicateFxUndo(src, xshHandle, fxHandle));
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Replace Fx  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class ReplaceFxUndo final : public FxCommandUndo {
Shinya Kitaoka 120a6e
  TFxP m_fx, m_repFx, m_linkedFx;
Shinya Kitaoka 120a6e
  TXshColumnP m_column, m_repColumn;
Shinya Kitaoka 120a6e
  int m_colIdx, m_repColIdx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<std::pair<int, *="" tfx="">> m_inputLinks;</std::pair<int,>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Shinya Kitaoka 120a6e
  TFxHandle *m_fxHandle;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  ReplaceFxUndo(const TFxP &replacementFx, const TFxP &replacedFx,
Shinya Kitaoka 120a6e
                TXsheetHandle *xshHandle, TFxHandle *fxHandle)
Shinya Kitaoka 120a6e
      : m_fx(replacedFx)
Shinya Kitaoka 120a6e
      , m_repFx(replacementFx)
Shinya Kitaoka 120a6e
      , m_xshHandle(xshHandle)
Shinya Kitaoka 120a6e
      , m_fxHandle(fxHandle)
Shinya Kitaoka 120a6e
      , m_colIdx(-1)
Shinya Kitaoka 120a6e
      , m_repColIdx(-1) {
Shinya Kitaoka 120a6e
    initialize();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool isConsistent() const override { return bool(m_repFx); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize();
Shinya Kitaoka 120a6e
  static void replace(TXsheet *xsh, TFx *fx, TFx *repFx, TXshColumn *column,
Shinya Kitaoka 120a6e
                      TXshColumn *repColumn, int colIdx, int repColIdx);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ReplaceFxUndo::initialize() {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFx *fx    = m_fx.getPointer();
Shinya Kitaoka 120a6e
  TFx *repFx = m_repFx.getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  fx = ::getActualOut(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (isInsideAMacroFx(fx, xsh) || dynamic_cast<txsheetfx *="">(fx) ||</txsheetfx>
Shinya Kitaoka 120a6e
      dynamic_cast<toutputfx *="">(fx) ||</toutputfx>
Shinya Kitaoka 120a6e
      (dynamic_cast<tcolumnfx *="">(fx) && !dynamic_cast<tzerarycolumnfx *="">(fx))) {</tzerarycolumnfx></tcolumnfx>
Shinya Kitaoka 120a6e
    m_repFx = TFxP();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (dynamic_cast<txsheetfx *="">(repFx) || dynamic_cast<toutputfx *="">(repFx) ||</toutputfx></txsheetfx>
Shinya Kitaoka 120a6e
      dynamic_cast<tcolumnfx *="">(repFx)) {</tcolumnfx>
Shinya Kitaoka 120a6e
    m_repFx = TFxP();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ::initializeFx(xsh, repFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TZeraryColumnFx *zcfx = dynamic_cast<tzerarycolumnfx *="">(fx);</tzerarycolumnfx>
Shinya Kitaoka 120a6e
  if (zcfx) {
Shinya Kitaoka 120a6e
    TXshZeraryFxColumn *zfColumn = zcfx->getColumn();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_column = zfColumn;
Shinya Kitaoka 120a6e
    m_colIdx = zfColumn->getIndex();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    fx = zcfx->getZeraryFx();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
manongjohn ffd27d
  TZeraryColumnFx *zcrepfx = dynamic_cast<tzerarycolumnfx *="">(repFx);</tzerarycolumnfx>
manongjohn ffd27d
  if (zcrepfx) repFx       = zcrepfx->getZeraryFx();
manongjohn ffd27d
manongjohn ffd27d
  bool fxHasCol    = has_fx_column(fx);
manongjohn ffd27d
  bool repfxHasCol = has_fx_column(repFx);
manongjohn ffd27d
manongjohn ffd27d
  if (fxHasCol && repfxHasCol) {
Shinya Kitaoka 120a6e
    if (zcfx) {
Shinya Kitaoka 120a6e
      // Build a column with the same source cells pattern
Shinya Kitaoka 120a6e
      m_repColumn = new TXshZeraryFxColumn(*zcfx->getColumn());
Shinya Kitaoka 120a6e
      m_repColIdx = m_colIdx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      // Substitute the column's zerary fx with the subsitute one
Shinya Kitaoka 120a6e
      TZeraryColumnFx *repZcfx =
Shinya Kitaoka 120a6e
          static_cast<tzerarycolumnfx *="">(m_repColumn->getFx());</tzerarycolumnfx>
Shinya Kitaoka 120a6e
      repZcfx->setZeraryFx(repFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      FxCommandUndo::cloneGroupStack(zcfx, repZcfx);
Shinya Kitaoka 120a6e
      m_repFx = repZcfx;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      m_repColumn = FxCommandUndo::createZeraryFxColumn(xsh, repFx);
Shinya Kitaoka 120a6e
      m_repColIdx = xsh->getFirstFreeColumnIndex();
Shinya Kitaoka 120a6e
      m_repFx     = static_cast<tzerarycolumnfx *="">(m_repColumn->getFx());</tzerarycolumnfx>
Shinya Kitaoka 120a6e
    }
manongjohn ffd27d
  } else if (!fxHasCol && repfxHasCol) {
manongjohn ffd27d
    m_repColumn = FxCommandUndo::createZeraryFxColumn(xsh, repFx);
manongjohn ffd27d
    m_repColIdx = xsh->getFirstFreeColumnIndex();
manongjohn ffd27d
    m_repFx     = static_cast<tzerarycolumnfx *="">(m_repColumn->getFx());</tzerarycolumnfx>
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  FxCommandUndo::cloneGroupStack(fx, m_repFx.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Store fx's input links (depending on m_repFx, they could be not matched
Shinya Kitaoka 120a6e
  // in the replacement)
Shinya Kitaoka 120a6e
  int p, ipCount = fx->getInputPortCount();
Shinya Kitaoka 120a6e
  for (p = 0; p != ipCount; ++p) {
Shinya Kitaoka 120a6e
    TFxPort *port = fx->getInputPort(p);
Shinya Kitaoka 120a6e
    if (TFx *inputFx = port->getFx())
Shinya Kitaoka 120a6e
      m_inputLinks.push_back(std::make_pair(p, inputFx));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Store the fx's linked fx
Shinya Kitaoka 120a6e
  m_linkedFx = fx->getLinkedFx();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ReplaceFxUndo::replace(TXsheet *xsh, TFx *fx, TFx *repFx,
Shinya Kitaoka 120a6e
                            TXshColumn *column, TXshColumn *repColumn,
Shinya Kitaoka 120a6e
                            int colIdx, int repColIdx) {
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TZeraryColumnFx *zcfx = column ? static_cast<tzerarycolumnfx *="">(fx) : 0;</tzerarycolumnfx>
Shinya Kitaoka 120a6e
  TZeraryColumnFx *repZcfx =
Shinya Kitaoka 120a6e
      repColumn ? static_cast<tzerarycolumnfx *="">(repFx) : 0;</tzerarycolumnfx>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFx *ifx    = zcfx ? zcfx->getZeraryFx() : fx;
Shinya Kitaoka 120a6e
  TFx *irepFx = repZcfx ? repZcfx->getZeraryFx() : repFx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Copy links first
Shinya Kitaoka 120a6e
  int p, ipCount = ifx->getInputPortCount(),
Shinya Kitaoka 120a6e
         ripCount = irepFx->getInputPortCount();
Shinya Kitaoka 120a6e
  for (p = 0; p != ipCount && p != ripCount; ++p) {
Shinya Kitaoka 120a6e
    TFxPort *ifxPort    = ifx->getInputPort(p);
Shinya Kitaoka 120a6e
    TFxPort *irepFxPort = irepFx->getInputPort(p);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    FxCommandUndo::attach(xsh, ifxPort->getFx(), irepFx, p, true);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int opCount = fx->getOutputConnectionCount();
Shinya Kitaoka 120a6e
  for (p = opCount - 1; p >= 0; --p) {
Shinya Kitaoka 120a6e
    TFxPort *port = fx->getOutputConnection(p);
Shinya Kitaoka 120a6e
    port->setFx(repFx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (fxDag->getTerminalFxs()->containsFx(fx)) {
Shinya Kitaoka 120a6e
    fxDag->removeFromXsheet(fx);
Shinya Kitaoka 120a6e
    fxDag->addToXsheet(repFx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Remove fx/column
Shinya Kitaoka 120a6e
  FxCommandUndo::removeFxOrColumn(xsh, fx, colIdx, bool(repColumn), false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Insert the new fx/column
Shinya Kitaoka 120a6e
  if (repColumn)
Shinya Kitaoka 120a6e
    FxCommandUndo::insertColumn(xsh, repColumn, repColIdx,
Shinya Kitaoka 120a6e
                                column);  // Not attached to the xsheet
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    ::addFxToCurrentScene(repFx, xsh, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  FxCommandUndo::copyGroupEditLevel(fx, repFx);
Shinya Kitaoka 120a6e
  FxCommandUndo::copyDagPosition(fx, repFx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ReplaceFxUndo::redo() const {
Shinya Kitaoka 120a6e
  ReplaceFxUndo::replace(m_xshHandle->getXsheet(), m_fx.getPointer(),
Shinya Kitaoka 120a6e
                         m_repFx.getPointer(), m_column.getPointer(),
Shinya Kitaoka 120a6e
                         m_repColumn.getPointer(), m_colIdx, m_repColIdx);
Shinya Kitaoka 120a6e
  FxCommandUndo::unlinkParams(m_fx.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_fxHandle->setFx(0);
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ReplaceFxUndo::undo() const {
Shinya Kitaoka 120a6e
  ReplaceFxUndo::replace(m_xshHandle->getXsheet(), m_repFx.getPointer(),
Shinya Kitaoka 120a6e
                         m_fx.getPointer(), m_repColumn.getPointer(),
Shinya Kitaoka 120a6e
                         m_column.getPointer(), m_repColIdx, m_colIdx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Repair original input links for m_fx
Shinya Kitaoka 120a6e
  m_fx->disconnectAll();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  size_t l, lCount = m_inputLinks.size();
Shinya Kitaoka 120a6e
  for (l = 0; l != lCount; ++l)
Shinya Kitaoka 120a6e
    m_fx->getInputPort(m_inputLinks[l].first)->setFx(m_inputLinks[l].second);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Repair parameter links
Shinya Kitaoka 120a6e
  FxCommandUndo::linkParams(m_fx.getPointer(), m_linkedFx.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_fxHandle->setFx(0);
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString ReplaceFxUndo::getHistoryString() {
Shinya Kitaoka 120a6e
  QString str = QObject::tr("Replace Fx  : ");
Shinya Kitaoka 120a6e
  str += QString("%1 > %2")
Shinya Kitaoka 120a6e
             .arg(QString::fromStdWString(m_fx->getFxId()))
Shinya Kitaoka 120a6e
             .arg(QString::fromStdWString(m_repFx->getFxId()));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return str;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::replaceFx(TFx *newFx, const QList<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                           TXsheetHandle *xshHandle, TFxHandle *fxHandle) {
Shinya Kitaoka 120a6e
  if (!newFx) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TUndoManager *undoManager = TUndoManager::manager();
Shinya Kitaoka 120a6e
  ::CloneFxFunctor cloneFx  = {newFx, true};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  undoManager->beginBlock();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFxP clonedFx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int f, fCount = fxs.size();
Shinya Kitaoka 120a6e
  for (f = 0; f != fCount; ++f) {
Shinya Kitaoka 120a6e
    if (!clonedFx) clonedFx = cloneFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2a7129
    std::unique_ptr<fxcommandundo> undo(</fxcommandundo>
Shinya Kitaoka 120a6e
        new ReplaceFxUndo(clonedFx, fxs[f], xshHandle, fxHandle));
Shinya Kitaoka 120a6e
    if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
      undo->redo();
Shinya Kitaoka 120a6e
      undoManager->add(undo.release());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      clonedFx = TFxP();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  undoManager->endBlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Unlink Fx  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class UnlinkFxUndo final : public FxCommandUndo {
Shinya Kitaoka 120a6e
  TFxP m_fx, m_linkedFx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UnlinkFxUndo(const TFxP &fx, TXsheetHandle *xshHandle)
Shinya Kitaoka 120a6e
      : m_fx(fx), m_linkedFx(fx->getLinkedFx()), m_xshHandle(xshHandle) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  bool isConsistent() const override { return bool(m_linkedFx); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    FxCommandUndo::linkParams(m_fx.getPointer(), m_linkedFx.getPointer());
Shinya Kitaoka 120a6e
    m_xshHandle->notifyXsheetChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    FxCommandUndo::unlinkParams(m_fx.getPointer());
Shinya Kitaoka 120a6e
    m_xshHandle->notifyXsheetChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  QString getHistoryString() override {
Shinya Kitaoka 120a6e
    return QObject::tr("Unlink Fx  : %1 - - %2")
Shinya Kitaoka 120a6e
        .arg(QString::fromStdWString(m_fx->getFxId()))
Shinya Kitaoka 120a6e
        .arg(QString::fromStdWString(m_linkedFx->getFxId()));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::unlinkFx(TFx *fx, TFxHandle *fxHandle,
Shinya Kitaoka 120a6e
                          TXsheetHandle *xshHandle) {
Shinya Kitaoka 120a6e
  if (!fx) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(new UnlinkFxUndo(fx, xshHandle));</fxcommandundo>
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Make Macro Fx  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class MakeMacroUndo : public FxCommandUndo {
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  TFxP m_macroFx;
Shinya Kitaoka 120a6e
  TApplication *m_app;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  MakeMacroUndo(const std::vector<tfxp> &fxs, TApplication *app) : m_app(app) {</tfxp>
Shinya Kitaoka 120a6e
    initialize(fxs);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool isConsistent() const override { return bool(m_macroFx); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override {
Shinya Kitaoka 120a6e
    return QObject::tr("Make Macro Fx  : %1")
Shinya Kitaoka 120a6e
        .arg(QString::fromStdWString(m_macroFx->getFxId()));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize(const std::vector<tfxp> &fxs);</tfxp>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  MakeMacroUndo(TMacroFx *macroFx, TApplication *app)
Shinya Kitaoka 120a6e
      : m_macroFx(macroFx), m_app(app) {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void MakeMacroUndo::initialize(const std::vector<tfxp> &fxs) {</tfxp>
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_app->getCurrentXsheet()->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  size_t f, fCount = fxs.size();
Shinya Kitaoka 120a6e
  for (f = 0; f != fCount; ++f) {
Shinya Kitaoka 120a6e
    // Only normal Fxs can be added in a macro
Shinya Kitaoka 120a6e
    TFx *fx = fxs[f].getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (isInsideAMacroFx(fx, xsh) || fx->isZerary() ||
Shinya Kitaoka 120a6e
        dynamic_cast<tzerarycolumnfx *="">(fx) || dynamic_cast<tmacrofx *="">(fx) ||</tmacrofx></tzerarycolumnfx>
Shinya Kitaoka 120a6e
        dynamic_cast<tlevelcolumnfx *="">(fx) ||</tlevelcolumnfx>
Shinya Kitaoka 120a6e
        dynamic_cast<tpalettecolumnfx *="">(fx) || dynamic_cast<txsheetfx *="">(fx) ||</txsheetfx></tpalettecolumnfx>
Shinya Kitaoka 120a6e
        dynamic_cast<toutputfx *="">(fx))</toutputfx>
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TMacroFx *macroFx = TMacroFx::create(fxs);
Shinya Kitaoka 120a6e
  if (!macroFx) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ::initializeFx(xsh, macroFx);
Shinya Kitaoka 120a6e
  m_macroFx = TFxP(macroFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // An old comment suggested there may be trouble in case the fx editor popup
Shinya Kitaoka 120a6e
  // is opened.
Shinya Kitaoka 120a6e
  // In any case, the new macro fx will be selected at the end - so, let's
Shinya Kitaoka 120a6e
  // disable it right now
Shinya Kitaoka 120a6e
  m_app->getCurrentFx()->setFx(0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void MakeMacroUndo::redo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh        = m_app->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  FxDag *fxDag        = xsh->getFxDag();
Shinya Kitaoka 120a6e
  TFxSet *terminalFxs = fxDag->getTerminalFxs();
Shinya Kitaoka 120a6e
  TMacroFx *macroFx   = static_cast<tmacrofx *="">(m_macroFx.getPointer());</tmacrofx>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ::addFxToCurrentScene(macroFx, xsh, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Replace the macro's root and deal with output links
Shinya Kitaoka 120a6e
  TFx *rootFx = macroFx->getRoot();
Shinya Kitaoka 120a6e
  if (terminalFxs->containsFx(rootFx)) fxDag->addToXsheet(macroFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int p, opCount = rootFx->getOutputConnectionCount();
Shinya Kitaoka 120a6e
  for (p = opCount - 1; p >= 0; --p)
Shinya Kitaoka 120a6e
    rootFx->getOutputConnection(p)->setFx(macroFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Remove the macro's internal fxs from the scene
Shinya Kitaoka 120a6e
  const std::vector<tfxp> &fxs = macroFx->getFxs();</tfxp>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  size_t f, fCount = fxs.size();
Shinya Kitaoka 120a6e
  for (f = 0; f != fCount; ++f)
Shinya Kitaoka 120a6e
    ::removeFxFromCurrentScene(fxs[f].getPointer(), xsh);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Hijack their ports (no actual redirection) - resetting the port ownership.
Shinya Kitaoka 120a6e
  // NOTE: Is this even legal? Not gonna touch it, but...   o_o!
Shinya Kitaoka 120a6e
  int ipCount = macroFx->getInputPortCount();
Shinya Kitaoka 120a6e
  for (p = 0; p != ipCount; ++p) macroFx->getInputPort(p)->setOwnerFx(macroFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_app->getCurrentFx()->setFx(macroFx);
Shinya Kitaoka 120a6e
  m_app->getCurrentXsheet()->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void MakeMacroUndo::undo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh        = m_app->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  FxDag *fxDag        = xsh->getFxDag();
Shinya Kitaoka 120a6e
  TFxSet *terminalFxs = fxDag->getTerminalFxs();
Shinya Kitaoka 120a6e
  TMacroFx *macroFx   = static_cast<tmacrofx *="">(m_macroFx.getPointer());</tmacrofx>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Reattach the macro's root to the xsheet if necessary
Shinya Kitaoka 120a6e
  TFx *rootFx = macroFx->getRoot();
Shinya Kitaoka 120a6e
  if (terminalFxs->containsFx(macroFx)) fxDag->addToXsheet(rootFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Restore the root's output connections
Shinya Kitaoka 120a6e
  int p, opCount = macroFx->getOutputConnectionCount();
Shinya Kitaoka 120a6e
  for (p = opCount - 1; p >= 0; --p)
Shinya Kitaoka 120a6e
    macroFx->getOutputConnection(p)->setFx(rootFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Remove the macro
Shinya Kitaoka 120a6e
  ::removeFxFromCurrentScene(macroFx, xsh);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Re-insert the macro's internal fxs and restore ports ownership
Shinya Kitaoka 120a6e
  const std::vector<tfxp> &fxs = macroFx->getFxs();</tfxp>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  size_t f, fCount = fxs.size();
Shinya Kitaoka 120a6e
  for (f = 0; f != fCount; ++f) {
Shinya Kitaoka 120a6e
    TFx *fx = fxs[f].getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    ::addFxToCurrentScene(fx, xsh, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int p, ipCount = fx->getInputPortCount();
Shinya Kitaoka 120a6e
    for (p = 0; p != ipCount; ++p) fx->getInputPort(p)->setOwnerFx(fx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_app->getCurrentFx()->setFx(0);
Shinya Kitaoka 120a6e
  m_app->getCurrentXsheet()->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::makeMacroFx(const std::vector<tfxp> &fxs, TApplication *app) {</tfxp>
Shinya Kitaoka 120a6e
  if (fxs.empty()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(new MakeMacroUndo(fxs, app));</fxcommandundo>
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Explode Macro Fx  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class ExplodeMacroUndo final : public MakeMacroUndo {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  ExplodeMacroUndo(TMacroFx *macro, TApplication *app)
Shinya Kitaoka 120a6e
      : MakeMacroUndo(macro, app) {
Shinya Kitaoka 120a6e
    initialize();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override { MakeMacroUndo::undo(); }
Shinya Kitaoka 473e70
  void undo() const override { MakeMacroUndo::redo(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override {
Shinya Kitaoka 120a6e
    return QObject::tr("Explode Macro Fx  : %1")
Shinya Kitaoka 120a6e
        .arg(QString::fromStdWString(m_macroFx->getFxId()));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ExplodeMacroUndo::initialize() {
Shinya Kitaoka 120a6e
  if (!static_cast<tmacrofx *="">(m_macroFx.getPointer())->getRoot())</tmacrofx>
Shinya Kitaoka 120a6e
    m_macroFx = TFxP();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::explodeMacroFx(TMacroFx *macroFx, TApplication *app) {
Shinya Kitaoka 120a6e
  if (!macroFx) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(new ExplodeMacroUndo(macroFx, app));</fxcommandundo>
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Create Output Fx  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class CreateOutputFxUndo final : public FxCommandUndo {
Shinya Kitaoka 120a6e
  TFxP m_outputFx;
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  CreateOutputFxUndo(TFx *fx, TXsheetHandle *xshHandle)
Shinya Kitaoka 120a6e
      : m_outputFx(new TOutputFx), m_xshHandle(xshHandle) {
Shinya Kitaoka 120a6e
    initialize(fx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool isConsistent() const override { return true; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    FxDag *fxDag        = m_xshHandle->getXsheet()->getFxDag();
Shinya Kitaoka 120a6e
    TOutputFx *outputFx = static_cast<toutputfx *="">(m_outputFx.getPointer());</toutputfx>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    fxDag->addOutputFx(outputFx);
Shinya Kitaoka 120a6e
    fxDag->setCurrentOutputFx(outputFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_xshHandle->notifyXsheetChanged();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    TOutputFx *outputFx = static_cast<toutputfx *="">(m_outputFx.getPointer());</toutputfx>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_xshHandle->getXsheet()->getFxDag()->removeOutputFx(outputFx);
Shinya Kitaoka 120a6e
    m_xshHandle->notifyXsheetChanged();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 38fd86
  QString getHistoryString() override {
Shinya Kitaoka 38fd86
    return QObject::tr("Create Output Fx");
Shinya Kitaoka 38fd86
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize(TFx *fx) {
Shinya Kitaoka 120a6e
    TXsheet *xsh        = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
    TOutputFx *outputFx = static_cast<toutputfx *="">(m_outputFx.getPointer());</toutputfx>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (fx && !dynamic_cast<toutputfx *="">(fx))</toutputfx>
Shinya Kitaoka 120a6e
      outputFx->getInputPort(0)->setFx(fx);
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      TOutputFx *currentOutputFx = xsh->getFxDag()->getCurrentOutputFx();
Shinya Kitaoka 120a6e
      const TPointD &pos = currentOutputFx->getAttributes()->getDagNodePos();
manongjohn f37f4a
      if (pos != TConst::nowhere)
manongjohn f37f4a
        outputFx->getAttributes()->setDagNodePos(pos + TPointD(20, 20));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::createOutputFx(TXsheetHandle *xshHandle, TFx *currentFx) {
Shinya Kitaoka 120a6e
  TUndo *undo = new CreateOutputFxUndo(currentFx, xshHandle);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  undo->redo();
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(undo);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Make Output Fx Current  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::makeOutputFxCurrent(TFx *fx, TXsheetHandle *xshHandle) {
Shinya Kitaoka 120a6e
  TOutputFx *outputFx = dynamic_cast<toutputfx *="">(fx);</toutputfx>
Shinya Kitaoka 120a6e
  if (!outputFx) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheet *xsh = xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  if (xsh->getFxDag()->getCurrentOutputFx() == outputFx) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  xsh->getFxDag()->setCurrentOutputFx(outputFx);
Shinya Kitaoka 120a6e
  xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Connect Nodes To Xsheet  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class ConnectNodesToXsheetUndo : public FxCommandUndo {
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  std::vector<tfxp> m_fxs;</tfxp>
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  ConnectNodesToXsheetUndo(const std::list<tfxp> &fxs, TXsheetHandle *xshHandle)</tfxp>
Shinya Kitaoka 120a6e
      : m_fxs(fxs.begin(), fxs.end()), m_xshHandle(xshHandle) {
Shinya Kitaoka 120a6e
    initialize();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  bool isConsistent() const override { return !m_fxs.empty(); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    /*
Shinya Kitaoka 120a6e
Due to compatibility issues from *schematicnode.cpp files, the "do" operation
Shinya Kitaoka 120a6e
must be
Shinya Kitaoka 120a6e
accessible without scene change notifications (see TFxCommand::setParent())
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    redo_();
Shinya Kitaoka 120a6e
    m_xshHandle->notifyXsheetChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void redo_() const {
Shinya Kitaoka 120a6e
    FxDag *fxDag = m_xshHandle->getXsheet()->getFxDag();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    size_t f, fCount = m_fxs.size();
Shinya Kitaoka 120a6e
    for (f = 0; f != fCount; ++f) fxDag->addToXsheet(m_fxs[f].getPointer());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    FxDag *fxDag = m_xshHandle->getXsheet()->getFxDag();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    size_t f, fCount = m_fxs.size();
Shinya Kitaoka 120a6e
    for (f = 0; f != fCount; ++f)
Shinya Kitaoka 120a6e
      fxDag->removeFromXsheet(m_fxs[f].getPointer());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_xshHandle->notifyXsheetChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  QString getHistoryString() override {
Shinya Kitaoka 120a6e
    QString str = QObject::tr("Connect to Xsheet  : ");
Shinya Kitaoka 120a6e
    std::vector<tfxp>::iterator it;</tfxp>
Shinya Kitaoka 120a6e
    for (it = m_fxs.begin(); it != m_fxs.end(); it++) {
Shinya Kitaoka 120a6e
      if (it != m_fxs.begin()) str += QString(", ");
Shinya Kitaoka 120a6e
      str += QString::fromStdWString((*it)->getFxId());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return str;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  ConnectNodesToXsheetUndo(const std::list<tfxp> &fxs, TXsheetHandle *xshHandle,</tfxp>
Shinya Kitaoka 120a6e
                           bool)
Shinya Kitaoka 120a6e
      : m_fxs(fxs.begin(), fxs.end()), m_xshHandle(xshHandle) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ConnectNodesToXsheetUndo::initialize() {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ::FilterInsideAMacro filterInMacro = {xsh};
Shinya Kitaoka 120a6e
  m_fxs.erase(std::remove_if(m_fxs.begin(), m_fxs.end(), filterInMacro),
Shinya Kitaoka 120a6e
              m_fxs.end());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ::FilterTerminalFxs filterTerminalFxs = {xsh};
Shinya Kitaoka 120a6e
  m_fxs.erase(std::remove_if(m_fxs.begin(), m_fxs.end(), filterTerminalFxs),
Shinya Kitaoka 120a6e
              m_fxs.end());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::connectNodesToXsheet(const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                                      TXsheetHandle *xshHandle) {
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(</fxcommandundo>
Shinya Kitaoka 120a6e
      new ConnectNodesToXsheetUndo(fxs, xshHandle));
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Disconnect Nodes From Xsheet  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class DisconnectNodesFromXsheetUndo final : public ConnectNodesToXsheetUndo {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  DisconnectNodesFromXsheetUndo(const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                                TXsheetHandle *xshHandle)
Shinya Kitaoka 120a6e
      : ConnectNodesToXsheetUndo(fxs, xshHandle, true) {
Shinya Kitaoka 120a6e
    initialize();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void redo() const override { ConnectNodesToXsheetUndo::undo(); }
Shinya Kitaoka 473e70
  void undo() const override { ConnectNodesToXsheetUndo::redo(); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  QString getHistoryString() override {
Shinya Kitaoka 120a6e
    QString str = QObject::tr("Disconnect from Xsheet  : ");
Shinya Kitaoka 120a6e
    std::vector<tfxp>::iterator it;</tfxp>
Shinya Kitaoka 120a6e
    for (it = m_fxs.begin(); it != m_fxs.end(); it++) {
Shinya Kitaoka 120a6e
      if (it != m_fxs.begin()) str += QString(", ");
Shinya Kitaoka 120a6e
      str += QString::fromStdWString((*it)->getFxId());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return str;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DisconnectNodesFromXsheetUndo::initialize() {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ::FilterInsideAMacro filterInMacro = {xsh};
Shinya Kitaoka 120a6e
  m_fxs.erase(std::remove_if(m_fxs.begin(), m_fxs.end(), filterInMacro),
Shinya Kitaoka 120a6e
              m_fxs.end());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ::FilterNonTerminalFxs filterNonTerminalFxs = {xsh};
Shinya Kitaoka 120a6e
  m_fxs.erase(std::remove_if(m_fxs.begin(), m_fxs.end(), filterNonTerminalFxs),
Shinya Kitaoka 120a6e
              m_fxs.end());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::disconnectNodesFromXsheet(const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                                           TXsheetHandle *xshHandle) {
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(</fxcommandundo>
Shinya Kitaoka 120a6e
      new DisconnectNodesFromXsheetUndo(fxs, xshHandle));
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Delete Link  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class DeleteLinksUndo : public FxCommandUndo {
Shinya Kitaoka 120a6e
  struct DynamicLink {
Shinya Kitaoka 120a6e
    int m_groupIndex;
Shinya Kitaoka 120a6e
    std::string m_portName;
Shinya Kitaoka 120a6e
    TFx *m_inputFx;
Shinya Kitaoka 120a6e
  };
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  typedef std::vector<dynamiclink> DynamicLinksVector;</dynamiclink>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  std::list<tfxcommand::link> m_links;  //!< The input links to remove</tfxcommand::link>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  std::list<tfxcommand::link></tfxcommand::link>
Shinya Kitaoka 120a6e
      m_normalLinks;               //!< Actual *common* links from m_links
Shinya Kitaoka 120a6e
  std::list<tfx *=""> m_terminalFxs;  //!< Fxs connected to the xsheet (represents</tfx>
Shinya Kitaoka 38fd86
                                   //! xsheet input links)
Shinya Kitaoka 120a6e
  //   Why SMART pointers? No fx is deleted with this command... hmm...
Shinya Kitaoka 120a6e
  std::map<tfx *,="" dynamiclinksvector=""></tfx>
Shinya Kitaoka 120a6e
      m_dynamicLinks;  //!< Complete dynamic links configuration, per fx.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  DeleteLinksUndo(const std::list<tfxcommand::link> &links,</tfxcommand::link>
Shinya Kitaoka 120a6e
                  TXsheetHandle *xshHandle)
Shinya Kitaoka 120a6e
      : m_links(links), m_xshHandle(xshHandle) {
Shinya Kitaoka 120a6e
    initialize();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool isConsistent() const override { return !m_links.empty(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return 10 << 10; }  // Say, around 10 kB
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  DeleteLinksUndo(TXsheetHandle *xshHandle) : m_xshHandle(xshHandle) {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void initialize();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DeleteLinksUndo::initialize() {
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    static bool isInvalid(FxDag *fxDag, const TFxCommand::Link &link) {
Shinya Kitaoka 120a6e
      if (link.m_index < 0)
Shinya Kitaoka 120a6e
        return !fxDag->getTerminalFxs()->containsFx(
Shinya Kitaoka 120a6e
            link.m_inputFx.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      TFx *inFx  = ::getActualOut(link.m_inputFx.getPointer());
Shinya Kitaoka 120a6e
      TFx *outFx = ::getActualIn(link.m_outputFx.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      return (link.m_index >= outFx->getInputPortCount())
Shinya Kitaoka 120a6e
                 ? true
Shinya Kitaoka 120a6e
                 : (outFx->getInputPort(link.m_index)->getFx() != inFx);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Forget links dealing with an open macro Fx. Note that this INCLUDES
Shinya Kitaoka 120a6e
  // inside/outside links.
Shinya Kitaoka 120a6e
  ::FilterInsideAMacro filterInMacro = {xsh};
Shinya Kitaoka 120a6e
  m_links.erase(std::remove_if(m_links.begin(), m_links.end(), filterInMacro),
Shinya Kitaoka 120a6e
                m_links.end());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Remove invalid links
Shinya Kitaoka 120a6e
  m_links.erase(std::remove_if(m_links.begin(), m_links.end(),
Shinya Kitaoka 120a6e
                               tcg::bind1st(&locals::isInvalid, fxDag)),
Shinya Kitaoka 120a6e
                m_links.end());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::list<tfxcommand::link>::iterator lt, lEnd(m_links.end());</tfxcommand::link>
Shinya Kitaoka 120a6e
  for (lt = m_links.begin(); lt != lEnd; ++lt) {
Shinya Kitaoka 120a6e
    const TFxCommand::Link &link = *lt;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (TXsheetFx *xsheetFx =
Shinya Kitaoka 120a6e
            dynamic_cast<txsheetfx *="">(link.m_outputFx.getPointer())) {</txsheetfx>
Shinya Kitaoka 120a6e
      // The input fx is connected to an xsheet node - ie it's terminal
Shinya Kitaoka 120a6e
      m_terminalFxs.push_back(link.m_inputFx.getPointer());
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TFx *outputFx = link.m_outputFx.getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Zerary columns wrap the actual zerary fx - that is the fx holding input
Shinya Kitaoka 120a6e
    // ports
Shinya Kitaoka 120a6e
    if (TZeraryColumnFx *zfx = dynamic_cast<tzerarycolumnfx *="">(outputFx))</tzerarycolumnfx>
Shinya Kitaoka 120a6e
      outputFx = zfx->getZeraryFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TFxPort *port = outputFx->getInputPort(link.m_index);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int portGroup = port->getGroupIndex();
Shinya Kitaoka 120a6e
    if (portGroup < 0) m_normalLinks.push_back(link);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (outputFx->hasDynamicPortGroups())
Shinya Kitaoka 120a6e
      m_dynamicLinks.insert(std::make_pair(outputFx, DynamicLinksVector()));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_normalLinks.sort();  // Really necessary?
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Store the complete configuration of dynamic groups - not just the ones
Shinya Kitaoka 120a6e
  // touched by
Shinya Kitaoka 120a6e
  // link editing, ALL of them.
Shinya Kitaoka 120a6e
  std::map<tfx *,="" dynamiclinksvector="">::iterator dlt,</tfx>
Shinya Kitaoka 120a6e
      dlEnd(m_dynamicLinks.end());
Shinya Kitaoka 120a6e
  for (dlt = m_dynamicLinks.begin(); dlt != dlEnd; ++dlt) {
Shinya Kitaoka 120a6e
    TFx *outputFx                = dlt->first;
Shinya Kitaoka 120a6e
    DynamicLinksVector &dynLinks = dlt->second;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int p, pCount = outputFx->getInputPortCount();
Shinya Kitaoka 120a6e
    for (p = 0; p != pCount; ++p) {
Shinya Kitaoka 120a6e
      TFxPort *port = outputFx->getInputPort(p);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      int g = port->getGroupIndex();
Shinya Kitaoka 120a6e
      if (g >= 0) {
Shinya Kitaoka 120a6e
        DynamicLink dLink = {g, outputFx->getInputPortName(p), port->getFx()};
Shinya Kitaoka 120a6e
        dynLinks.push_back(dLink);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DeleteLinksUndo::redo() const {
Shinya Kitaoka 120a6e
  FxDag *fxDag = m_xshHandle->getXsheet()->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Perform unlinking
Shinya Kitaoka 120a6e
  std::list<tfxcommand::link>::const_iterator lt, lEnd(m_links.end());</tfxcommand::link>
Shinya Kitaoka 120a6e
  for (lt = m_links.begin(); lt != lEnd; ++lt) {
Shinya Kitaoka 120a6e
    const TFxCommand::Link &link = *lt;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TFx *outputFx = lt->m_outputFx.getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (TXsheetFx *xsheetFx = dynamic_cast<txsheetfx *="">(outputFx)) {</txsheetfx>
Shinya Kitaoka 120a6e
      // Terminal fx link case
Shinya Kitaoka 120a6e
      fxDag->removeFromXsheet(link.m_inputFx.getPointer());
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Actual link case
Shinya Kitaoka 120a6e
    if (TZeraryColumnFx *zcfx = dynamic_cast<tzerarycolumnfx *="">(outputFx))</tzerarycolumnfx>
Shinya Kitaoka 120a6e
      outputFx = zcfx->getZeraryFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int index = lt->m_index;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    assert(index < outputFx->getInputPortCount());
Shinya Kitaoka 120a6e
    if (index < outputFx->getInputPortCount())
Shinya Kitaoka 120a6e
      outputFx->getInputPort(index)->setFx(0);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DeleteLinksUndo::undo() const {
Shinya Kitaoka 120a6e
  FxDag *fxDag = m_xshHandle->getXsheet()->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Re-attach terminal fxs
Shinya Kitaoka 120a6e
  std::list<tfx *="">::const_iterator ft;</tfx>
Shinya Kitaoka 120a6e
  for (ft = m_terminalFxs.begin(); ft != m_terminalFxs.end(); ++ft) {
Shinya Kitaoka 120a6e
    if (fxDag->checkLoop(*ft, fxDag->getXsheetFx())) {
Shinya Kitaoka 120a6e
      assert(fxDag->checkLoop(*ft, fxDag->getXsheetFx()));
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    fxDag->addToXsheet(*ft);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Restore common links
Shinya Kitaoka 120a6e
  std::list<tfxcommand::link>::const_iterator lt, lEnd(m_normalLinks.end());</tfxcommand::link>
Shinya Kitaoka 120a6e
  for (lt = m_normalLinks.begin(); lt != lEnd; ++lt) {
Shinya Kitaoka 120a6e
    const TFxCommand::Link &link = *lt;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int index     = link.m_index;
Shinya Kitaoka 120a6e
    TFx *inputFx  = link.m_inputFx.getPointer();
Shinya Kitaoka 120a6e
    TFx *outputFx = link.m_outputFx.getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (TZeraryColumnFx *zcfx = dynamic_cast<tzerarycolumnfx *="">(outputFx))</tzerarycolumnfx>
Shinya Kitaoka 120a6e
      outputFx = zcfx->getZeraryFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (fxDag->checkLoop(inputFx, outputFx)) {
Shinya Kitaoka 120a6e
      assert(fxDag->checkLoop(inputFx, outputFx));
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    assert(index < outputFx->getInputPortCount());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (index < outputFx->getInputPortCount())
Shinya Kitaoka 120a6e
      outputFx->getInputPort(index)->setFx(inputFx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Restore complete dynamic port groups configuration
Shinya Kitaoka 120a6e
  std::map<tfx *,="" dynamiclinksvector="">::const_iterator dlt,</tfx>
Shinya Kitaoka 120a6e
      dlEnd(m_dynamicLinks.end());
Shinya Kitaoka 120a6e
  for (dlt = m_dynamicLinks.begin(); dlt != dlEnd; ++dlt) {
Shinya Kitaoka 120a6e
    TFx *outputFx                      = dlt->first;
Shinya Kitaoka 120a6e
    const DynamicLinksVector &dynLinks = dlt->second;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      int g, gCount = outputFx->dynamicPortGroupsCount();
Shinya Kitaoka 120a6e
      for (g = 0; g != gCount; ++g) outputFx->clearDynamicPortGroup(g);
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    size_t d, dCount = dynLinks.size();
Shinya Kitaoka 120a6e
    for (d = 0; d != dCount; ++d) {
Shinya Kitaoka 120a6e
      const DynamicLink &link = dynLinks[d];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      TFxPort *port = new TRasterFxPort;  // isAControlPort... semi-obsolete
Shinya Kitaoka 120a6e
      port->setFx(link.m_inputFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      outputFx->addInputPort(link.m_portName, port, link.m_groupIndex);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString DeleteLinksUndo::getHistoryString() {
Shinya Kitaoka 120a6e
  QString str = QObject::tr("Delete Link");
Shinya Kitaoka 120a6e
  if (!m_normalLinks.empty()) {
Shinya Kitaoka 120a6e
    str += QString("  :  ");
Shinya Kitaoka 120a6e
    std::list<tfxcommand::link>::const_iterator it;</tfxcommand::link>
Shinya Kitaoka 120a6e
    for (it = m_normalLinks.begin(); it != m_normalLinks.end(); it++) {
Shinya Kitaoka 120a6e
      if (it != m_normalLinks.begin()) str += QString(",  ");
Shinya Kitaoka 120a6e
      TFxCommand::Link boundingFxs = *it;
Shinya Kitaoka 120a6e
      str +=
Shinya Kitaoka 120a6e
          QString("%1- -%2")
Shinya Kitaoka 120a6e
              .arg(QString::fromStdWString(boundingFxs.m_inputFx->getName()))
Shinya Kitaoka 120a6e
              .arg(QString::fromStdWString(boundingFxs.m_outputFx->getName()));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!m_terminalFxs.empty()) {
Shinya Kitaoka 120a6e
    str += QString("  :  ");
Shinya Kitaoka 120a6e
    std::list<tfx *="">::const_iterator ft;</tfx>
Shinya Kitaoka 120a6e
    for (ft = m_terminalFxs.begin(); ft != m_terminalFxs.end(); ++ft) {
Shinya Kitaoka 120a6e
      if (ft != m_terminalFxs.begin()) str += QString(",  ");
jabarrera 15baed
      str +=
jabarrera 15baed
          QString("%1- -Xsheet").arg(QString::fromStdWString((*ft)->getName()));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return str;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Campbell Barton b3bd84
static void deleteLinks(const std::list<tfxcommand::link> &links,</tfxcommand::link>
shun-iwasawa 27b0cf
                        TXsheetHandle *xshHandle) {
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(new DeleteLinksUndo(links, xshHandle));</fxcommandundo>
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************
Toshihiro Shimizu 890ddd
//    Delete Fx  command
Toshihiro Shimizu 890ddd
//******************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class DeleteFxOrColumnUndo final : public DeleteLinksUndo {
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  TFxP m_fx;
Shinya Kitaoka 120a6e
  TXshColumnP m_column;
Shinya Kitaoka 120a6e
  int m_colIdx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFxP m_linkedFx;
Shinya Kitaoka 120a6e
  std::vector<tfx *=""> m_nonTerminalInputs;</tfx>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2a7129
  mutable std::unique_ptr<tstageobjectparams> m_columnData;</tstageobjectparams>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Shinya Kitaoka 120a6e
  TFxHandle *m_fxHandle;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  using DeleteLinksUndo::m_links;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  DeleteFxOrColumnUndo(const TFxP &fx, TXsheetHandle *xshHandle,
Shinya Kitaoka 120a6e
                       TFxHandle *fxHandle);
Shinya Kitaoka 120a6e
  DeleteFxOrColumnUndo(int colIdx, TXsheetHandle *xshHandle,
Shinya Kitaoka 120a6e
                       TFxHandle *fxHandle);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool isConsistent() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DeleteFxOrColumnUndo::DeleteFxOrColumnUndo(const TFxP &fx,
Shinya Kitaoka 120a6e
                                           TXsheetHandle *xshHandle,
Shinya Kitaoka 120a6e
                                           TFxHandle *fxHandle)
Shinya Kitaoka 120a6e
    : DeleteLinksUndo(xshHandle)
Shinya Kitaoka 120a6e
    , m_fx(fx)
Shinya Kitaoka 120a6e
    , m_colIdx(-1)
Shinya Kitaoka 120a6e
    , m_xshHandle(xshHandle)
Shinya Kitaoka 120a6e
    , m_fxHandle(fxHandle) {
Shinya Kitaoka 120a6e
  initialize();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DeleteFxOrColumnUndo::DeleteFxOrColumnUndo(int colIdx, TXsheetHandle *xshHandle,
Shinya Kitaoka 120a6e
                                           TFxHandle *fxHandle)
Shinya Kitaoka 120a6e
    : DeleteLinksUndo(xshHandle)
Shinya Kitaoka 120a6e
    , m_colIdx(colIdx)
Shinya Kitaoka 120a6e
    , m_xshHandle(xshHandle)
Shinya Kitaoka 120a6e
    , m_fxHandle(fxHandle) {
Shinya Kitaoka 120a6e
  initialize();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DeleteFxOrColumnUndo::initialize() {
Shinya Kitaoka 120a6e
  struct {
Shinya Kitaoka 120a6e
    DeleteFxOrColumnUndo *m_this;
Shinya Kitaoka 120a6e
    inline void getActualData(TXsheet *xsh, TFx *&ifx, TFx *&ofx) {
Shinya Kitaoka 120a6e
      TFx *fx = m_this->m_fx.getPointer();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (!fx) fx = xsh->getColumn(m_this->m_colIdx)->getFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (fx) {
Shinya Kitaoka 120a6e
        ifx = ::getActualIn(fx);
Shinya Kitaoka 120a6e
        ofx = ::getActualOut(fx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (TColumnFx *colFx = dynamic_cast<tcolumnfx *="">(ofx))</tcolumnfx>
Shinya Kitaoka 120a6e
          m_this->m_colIdx = colFx->getColumnIndex();
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_this->m_fx = ofx;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } locals = {this};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(m_fx || m_colIdx >= 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  TFx *ifx = 0, *ofx = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  locals.getActualData(xsh, ifx, ofx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ofx && isInsideAMacroFx(ofx, xsh))  // Macros must be exploded first
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    m_fx = TFxP(), m_colIdx = -1;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Assume shared ownership of the associated column, if any
Shinya Kitaoka 120a6e
  if (m_colIdx >= 0) {
Shinya Kitaoka 120a6e
    m_column = xsh->getColumn(m_colIdx);
Shinya Kitaoka 120a6e
    assert(m_column);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Currently disputed, but in the previous implementation there was code
Shinya Kitaoka 120a6e
    // suggesting
Shinya Kitaoka 120a6e
    // that the column could have already been removed from the xsheet.
Shinya Kitaoka 120a6e
    // Preventing that case...
Shinya Kitaoka 120a6e
    if (!m_column->inColumnsSet()) {
Shinya Kitaoka 120a6e
      m_fx = TFxP(), m_colIdx = -1;  // Bail out as inconsistent op
Shinya Kitaoka 120a6e
      return;                        //
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (TOutputFx *outputFx = dynamic_cast<toutputfx *="">(ofx)) {</toutputfx>
Shinya Kitaoka 120a6e
    if (xsh->getFxDag()->getOutputFxCount() <= 1) {
Shinya Kitaoka 120a6e
      // Cannot delete the last output fx
Shinya Kitaoka 120a6e
      m_fx = TFxP();
Shinya Kitaoka 120a6e
      assert(m_colIdx < 0);
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Store links to be re-established in the undo
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ofx) {
Shinya Kitaoka 120a6e
    // Store the terminal output link, if any
Shinya Kitaoka 120a6e
    if (fxDag->getTerminalFxs()->containsFx(ofx))
Shinya Kitaoka 120a6e
      m_links.push_back(TFxCommand::Link(ofx, fxDag->getXsheetFx(), -1));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Store output links
Shinya Kitaoka 120a6e
    int p, opCount = ofx->getOutputConnectionCount();
Shinya Kitaoka 120a6e
    for (p = 0; p != opCount; ++p) {
Shinya Kitaoka 120a6e
      if (TFx *outFx = ofx->getOutputConnection(p)->getOwnerFx()) {
Shinya Kitaoka 120a6e
        int ip, ipCount = outFx->getInputPortCount();
Shinya Kitaoka 120a6e
        for (ip = 0; ip != ipCount; ++ip)
Shinya Kitaoka 120a6e
          if (outFx->getInputPort(ip)->getFx() == ofx) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        assert(ip < ipCount);
Shinya Kitaoka 120a6e
        if (ip < ipCount) m_links.push_back(TFxCommand::Link(m_fx, outFx, ip));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ifx) {
Shinya Kitaoka 120a6e
    m_linkedFx = ifx->getLinkedFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Store input links
Shinya Kitaoka 120a6e
    int p, ipCount = ifx->getInputPortCount();
Shinya Kitaoka 120a6e
    for (p = 0; p != ipCount; ++p) {
Shinya Kitaoka 120a6e
      if (TFx *inputFx = ifx->getInputPort(p)->getFx()) {
Shinya Kitaoka 120a6e
        m_links.push_back(TFxCommand::Link(inputFx, m_fx, p));
Shinya Kitaoka 120a6e
        if (!fxDag->getTerminalFxs()->containsFx(
Shinya Kitaoka 120a6e
                inputFx))  // Store input fxs which DID NOT have an
Shinya Kitaoka 120a6e
          m_nonTerminalInputs.push_back(
Shinya Kitaoka 120a6e
              inputFx);  // xsheet link before the deletion
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  DeleteLinksUndo::initialize();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool DeleteFxOrColumnUndo::isConsistent() const {
Shinya Kitaoka 120a6e
  return (bool(m_fx) || (m_colIdx >= 0));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // NOTE: DeleteLinksUndo::isConsistent() is not checked.
Shinya Kitaoka 120a6e
  //       This is because there could be no link to remove, and yet
Shinya Kitaoka 120a6e
  //       the operation IS consistent.
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DeleteFxOrColumnUndo::redo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Store data to be restored in the undo
Shinya Kitaoka 120a6e
  if (m_colIdx >= 0) {
Shinya Kitaoka 120a6e
    assert(!m_columnData.get());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_columnData.reset(
Shinya Kitaoka 120a6e
        xsh->getStageObject(TStageObjectId::ColumnId(
Shinya Kitaoka 120a6e
                                m_colIdx))  // Cloned, ownership acquired
Shinya Kitaoka 120a6e
            ->getParams());  // However, params stored there are NOT cloned.
Shinya Kitaoka 120a6e
  }                          // This is fine since we're deleting the column...
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Peform operation
Shinya Kitaoka 120a6e
  FxCommandUndo::removeFxOrColumn(xsh, m_fx.getPointer(), m_colIdx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();  // Add the rest...
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DeleteFxOrColumnUndo::undo() const {
Shinya Kitaoka 120a6e
  struct Locals {
Shinya Kitaoka 120a6e
    const DeleteFxOrColumnUndo *m_this;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    void insertColumnIn(TXsheet *xsh) {
Shinya Kitaoka 120a6e
      m_this->insertColumn(xsh, m_this->m_column.getPointer(),
Shinya Kitaoka 120a6e
                           m_this->m_colIdx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      // Restore column data
Shinya Kitaoka 120a6e
      TStageObject *sObj =
Shinya Kitaoka 120a6e
          xsh->getStageObject(TStageObjectId::ColumnId(m_this->m_colIdx));
Shinya Kitaoka 120a6e
      assert(sObj);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      sObj->assignParams(m_this->m_columnData.get(), false);
Shinya Kitaoka 120a6e
      m_this->m_columnData.reset();
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  } locals = {this};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Re-add the fx/column to the xsheet
Shinya Kitaoka 120a6e
  TFx *fx = m_fx.getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_column)
Shinya Kitaoka 120a6e
    locals.insertColumnIn(xsh);
Shinya Kitaoka 120a6e
  else if (TOutputFx *outFx = dynamic_cast<toutputfx *="">(fx))</toutputfx>
Shinya Kitaoka 120a6e
    xsh->getFxDag()->addOutputFx(outFx);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    addFxToCurrentScene(fx, xsh, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (fx) {
Shinya Kitaoka 120a6e
    // Remove xsheet connections that became terminal due to the fx
Shinya Kitaoka 120a6e
    // removal
Shinya Kitaoka 120a6e
    size_t ti, tiCount = m_nonTerminalInputs.size();
Shinya Kitaoka 120a6e
    for (ti = 0; ti != tiCount; ++ti)
Shinya Kitaoka 120a6e
      fxDag->removeFromXsheet(m_nonTerminalInputs[ti]);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Re-link parameters if necessary
Shinya Kitaoka 120a6e
    TFx *ifx = ::getActualIn(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (m_linkedFx) ifx->linkParams(m_linkedFx.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Re-establish fx links
Shinya Kitaoka 120a6e
    DeleteLinksUndo::undo();
Shinya Kitaoka 120a6e
  } else  // Already covered by DeleteLinksUndo::undo()
Shinya Kitaoka 120a6e
    m_xshHandle->notifyXsheetChanged();  // in the other branch
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString DeleteFxOrColumnUndo::getHistoryString() {
Shinya Kitaoka 120a6e
  return QObject::tr("Delete Fx Node : %1")
Shinya Kitaoka 120a6e
      .arg(QString::fromStdWString(m_fx->getFxId()));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Campbell Barton b3bd84
static void deleteFxs(const std::list<tfxp> &fxs, TXsheetHandle *xshHandle,</tfxp>
shun-iwasawa 27b0cf
                      TFxHandle *fxHandle) {
Shinya Kitaoka 120a6e
  TUndoManager *undoManager = TUndoManager::manager();
Shinya Kitaoka 120a6e
  TXsheet *xsh              = xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  undoManager->beginBlock();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::list<tfxp>::const_iterator ft, fEnd = fxs.end();</tfxp>
Shinya Kitaoka 120a6e
  for (ft = fxs.begin(); ft != fEnd; ++ft) {
Shinya Kitaoka 120a6e
    // Skip levels, as they are effectively supplied in here, AND in the
Shinya Kitaoka 120a6e
    // deleteColumns() branch.
Shinya Kitaoka 120a6e
    // This should NOT be performed here, though. TO BE MOVED TO deleteSelection
Shinya Kitaoka 120a6e
    // or ABOVE, if any.
Shinya Kitaoka 120a6e
    if (dynamic_cast<tlevelcolumnfx *="">(ft->getPointer())) continue;</tlevelcolumnfx>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2a7129
    std::unique_ptr<fxcommandundo> undo(</fxcommandundo>
Shinya Kitaoka 120a6e
        new DeleteFxOrColumnUndo(*ft, xshHandle, fxHandle));
Shinya Kitaoka 120a6e
    if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
      undo->redo();
Shinya Kitaoka 120a6e
      TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  undoManager->endBlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Remove Output Fx  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::removeOutputFx(TFx *fx, TXsheetHandle *xshHandle,
Shinya Kitaoka 120a6e
                                TFxHandle *fxHandle) {
Shinya Kitaoka 120a6e
  TOutputFx *outputFx = dynamic_cast<toutputfx *="">(fx);</toutputfx>
Shinya Kitaoka 120a6e
  if (!outputFx) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(</fxcommandundo>
Shinya Kitaoka 120a6e
      new DeleteFxOrColumnUndo(fx, xshHandle, fxHandle));
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Delete Columns  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
shun-iwasawa 27b0cf
static void deleteColumns(const std::list<int> &columns,</int>
shun-iwasawa 27b0cf
                          TXsheetHandle *xshHandle, TFxHandle *fxHandle) {
Shinya Kitaoka 120a6e
  TUndoManager *undoManager = TUndoManager::manager();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  undoManager->beginBlock();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // As columns are deleted, their index changes. So, the easiest workaround is
Shinya Kitaoka 120a6e
  // to address the
Shinya Kitaoka 120a6e
  // columns directly, and then their (updated) column index.
Shinya Kitaoka 120a6e
  TXsheet *xsh = xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
otakuto e347ad
  std::vector<txshcolumn *=""> cols;</txshcolumn>
otakuto e347ad
  for (auto const &c : columns) {
otakuto e347ad
    cols.push_back(xsh->getColumn(c));
otakuto e347ad
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  size_t c, cCount = cols.size();
Shinya Kitaoka 120a6e
  for (c = 0; c != cCount; ++c) {
Shinya Kitaoka 2a7129
    std::unique_ptr<fxcommandundo> undo(</fxcommandundo>
Shinya Kitaoka 120a6e
        new DeleteFxOrColumnUndo(cols[c]->getIndex(), xshHandle, fxHandle));
Shinya Kitaoka 120a6e
    if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
      undo->redo();
Shinya Kitaoka 120a6e
      undoManager->add(undo.release());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  undoManager->endBlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Delete Selection  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TFxCommand::deleteSelection(const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                                 const std::list<link> &links,
Shinya Kitaoka 120a6e
                                 const std::list<int> &columns,</int>
Shinya Kitaoka 120a6e
                                 TXsheetHandle *xshHandle,
Shinya Kitaoka 120a6e
                                 TFxHandle *fxHandle) {
Shinya Kitaoka 120a6e
  // Prepare selected fxs - column fxs would be done twice if the corresponding
Shinya Kitaoka 120a6e
  // columns have
Shinya Kitaoka 120a6e
  // been supplied for deletion too
Shinya Kitaoka 120a6e
  ::FilterColumnFxs filterColumnFxs;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::list<tfxp> filteredFxs(fxs);</tfxp>
Shinya Kitaoka 120a6e
  filteredFxs.erase(
Shinya Kitaoka 120a6e
      std::remove_if(filteredFxs.begin(), filteredFxs.end(), filterColumnFxs),
Shinya Kitaoka 120a6e
      filteredFxs.end());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Perform deletions
Shinya Kitaoka 120a6e
  TUndoManager::manager()->beginBlock();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  deleteColumns(columns, xshHandle, fxHandle);
Shinya Kitaoka 120a6e
  deleteFxs(filteredFxs, xshHandle, fxHandle);
Shinya Kitaoka 120a6e
  deleteLinks(links, xshHandle);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TUndoManager::manager()->endBlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Paste Fxs  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Shinya Kitaoka 120a6e
  NOTE: Zerary fxs should not be in the fxs list - but rather in the columns
Shinya Kitaoka 120a6e
  list.
Toshihiro Shimizu 890ddd
  This would allow us to forget about the zeraryColumnSize map.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  This requires changing the *selection*, though. To be done, in a later step.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class UndoPasteFxs : public FxCommandUndo {
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  std::list<tfxp> m_fxs;             //!< Fxs to be pasted</tfxp>
Shinya Kitaoka 120a6e
  std::list<txshcolumnp> m_columns;  //!< Columns to be pasted</txshcolumnp>
Shinya Kitaoka 120a6e
  std::vector<tfxcommand::link></tfxcommand::link>
Shinya Kitaoka 120a6e
      m_links;  //!< Links to be re-established at the redo
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Shinya Kitaoka 120a6e
  TFxHandle *m_fxHandle;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoPasteFxs(const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
               const std::map<tfx *,="" int=""> &zeraryFxColumnSize,</tfx>
Shinya Kitaoka 120a6e
               const std::list<txshcolumnp> &columns, const TPointD &pos,</txshcolumnp>
Shinya Kitaoka 120a6e
               TXsheetHandle *xshHandle, TFxHandle *fxHandle,
Shinya Kitaoka 120a6e
               bool addOffset = true)
Shinya Kitaoka 120a6e
      : m_fxs(fxs)
Shinya Kitaoka 120a6e
      , m_columns(columns)
Shinya Kitaoka 120a6e
      , m_xshHandle(xshHandle)
Shinya Kitaoka 120a6e
      , m_fxHandle(fxHandle) {
Shinya Kitaoka 120a6e
    initialize(zeraryFxColumnSize, pos, addOffset);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 38fd86
  bool isConsistent() const override {
Shinya Kitaoka 38fd86
    return !(m_fxs.empty() && m_columns.empty());
Shinya Kitaoka 38fd86
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  template <typename func=""></typename>
Shinya Kitaoka 120a6e
  void for_each_fx(Func func) const;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize(const std::map<tfx *,="" int=""> &zeraryFxColumnSize,</tfx>
Shinya Kitaoka 120a6e
                  const TPointD &pos, bool addOffset);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void UndoPasteFxs::initialize(const std::map<tfx *,="" int=""> &zeraryFxColumnSize,</tfx>
Shinya Kitaoka 120a6e
                              const TPointD &pos, bool addOffset) {
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    static void buildDagPos(TFx *fromFx, TFx *toFx, bool copyPos,
Shinya Kitaoka 120a6e
                            bool addOffset) {
Shinya Kitaoka 120a6e
      TPointD dagPos = TConst::nowhere;
Shinya Kitaoka 120a6e
      if (copyPos) {
Shinya Kitaoka 120a6e
        static const TPointD offset(30, 30);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        dagPos = fromFx->getAttributes()->getDagNodePos();
Shinya Kitaoka 120a6e
        if (addOffset &&
Shinya Kitaoka 120a6e
            (dagPos != TConst::nowhere))  // Shift may only happen if the copied
Shinya Kitaoka 120a6e
          dagPos += offset;               // position is well-formed.
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      toFx->getAttributes()->setDagNodePos(dagPos);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    static void renamePort(TFx *fx, int p, const std::wstring &oldId,
Shinya Kitaoka 120a6e
                           const std::wstring &newId) {
Shinya Kitaoka 120a6e
      const QString &qOldId = QString::fromStdWString(oldId);
Shinya Kitaoka 120a6e
      const QString &qNewId = QString::fromStdWString(newId);
Shinya Kitaoka 120a6e
      const QString &qPortName =
Shinya Kitaoka 120a6e
          QString::fromStdString(fx->getInputPortName(p));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (qPortName.endsWith(qOldId)) {
Shinya Kitaoka 120a6e
        QString qNewPortName = qPortName;
Shinya Kitaoka 120a6e
        qNewPortName.replace(qOldId, qNewId);
Shinya Kitaoka 120a6e
        fx->renamePort(qPortName.toStdString(), qNewPortName.toStdString());
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    static bool circularSubxsheet(TXsheet *xsh, const TXshColumnP &col) {
Shinya Kitaoka 120a6e
      return xsh->checkCircularReferences(col.getPointer());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    static void push_back(std::vector<tfx *=""> &fxs, TFx *fx) {</tfx>
Shinya Kitaoka 120a6e
      fxs.push_back(fx);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXsheet *xsh    = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  bool copyDagPos = (pos != TConst::nowhere);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Initialize fxs
Shinya Kitaoka 120a6e
  std::list<tfxp>::iterator ft, fEnd = m_fxs.end();</tfxp>
Shinya Kitaoka 120a6e
  for (ft = m_fxs.begin(); ft != fEnd;) {
Shinya Kitaoka 120a6e
    TFx *fx = ft->getPointer();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(!dynamic_cast<tzerarycolumnfx *="">(fx));</tzerarycolumnfx>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (has_fx_column(fx)) {
Shinya Kitaoka 120a6e
      // Zerary case
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Since we have no column available (WHICH IS WRONG), we'll build up a
Shinya Kitaoka 120a6e
      // column with
Shinya Kitaoka 120a6e
      // the specified column size
Shinya Kitaoka 120a6e
      std::map<tfx *,="" int="">::const_iterator it = zeraryFxColumnSize.find(fx);</tfx>
Shinya Kitaoka 120a6e
      int rows = (it == zeraryFxColumnSize.end()) ? 100 : it->second;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TXshZeraryFxColumn *column = new TXshZeraryFxColumn(rows);
Shinya Kitaoka 120a6e
      TZeraryColumnFx *zcfx      = column->getZeraryColumnFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      zcfx->setZeraryFx(fx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      int op, opCount = fx->getOutputConnectionCount();
Shinya Kitaoka 120a6e
      for (op = opCount - 1; op >= 0;
Shinya Kitaoka 120a6e
           --op)  // Output links in the zerary case were
Shinya Kitaoka 120a6e
      {           // assigned to the *actual* zerary
Shinya Kitaoka 120a6e
        TFxPort *outPort =
Shinya Kitaoka 120a6e
            fx->getOutputConnection(op);  // and not to a related zerary column.
Shinya Kitaoka 120a6e
        outPort->setFx(zcfx);  // This is an FxsData fault... BUGFIX REQUEST!
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      zcfx->getAttributes()->setDagNodePos(
Shinya Kitaoka 120a6e
          fx->getAttributes()->getDagNodePos());
Shinya Kitaoka 120a6e
      m_columns.push_front(column);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      ft = m_fxs.erase(ft);
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Macro case
Shinya Kitaoka 120a6e
    if (TMacroFx *macroFx = dynamic_cast<tmacrofx *="">(fx)) {</tmacrofx>
Shinya Kitaoka 120a6e
      const std::vector<tfxp> &inMacroFxs = macroFx->getFxs();</tfxp>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      size_t f, fCount = inMacroFxs.size();
Shinya Kitaoka 120a6e
      for (f = 0; f != fCount; ++f) {
Shinya Kitaoka 120a6e
        TFx *inFx                   = inMacroFxs[f].getPointer();
Shinya Kitaoka 120a6e
        const std::wstring &oldFxId = inFx->getFxId();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // Since we're pasting a macro, we're actually pasting all of its inner
Shinya Kitaoka 120a6e
        // fxs,
Shinya Kitaoka 120a6e
        // which must have a different name (id) from the originals. However,
Shinya Kitaoka 120a6e
        // such ids
Shinya Kitaoka 120a6e
        // are actually copied in the macro's *port names* - which must
Shinya Kitaoka 120a6e
        // therefore be
Shinya Kitaoka 120a6e
        // redirected to the new names.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        ::initializeFx(xsh, inFx);
Shinya Kitaoka 120a6e
        const std::wstring &newFxId = inFx->getFxId();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        int ip, ipCount = macroFx->getInputPortCount();
Shinya Kitaoka 120a6e
        for (ip = 0; ip != ipCount; ++ip)
Shinya Kitaoka 120a6e
          locals::renamePort(macroFx, ip, oldFxId, newFxId);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ::initializeFx(xsh, fx);
Shinya Kitaoka 120a6e
    locals::buildDagPos(fx, fx, copyDagPos, addOffset);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ++ft;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Filter columns
Shinya Kitaoka 120a6e
  m_columns.erase(std::remove_if(m_columns.begin(), m_columns.end(),
Shinya Kitaoka 120a6e
                                 tcg::bind1st(&locals::circularSubxsheet, xsh)),
Shinya Kitaoka 120a6e
                  m_columns.end());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Initialize columns
Shinya Kitaoka 120a6e
  std::list<txshcolumnp>::const_iterator ct, cEnd(m_columns.end());</txshcolumnp>
Shinya Kitaoka 120a6e
  for (ct = m_columns.begin(); ct != cEnd; ++ct) {
Shinya Kitaoka 120a6e
    if (TFx *cfx = (*ct)->getFx()) {
Shinya Kitaoka 120a6e
      ::initializeFx(xsh, cfx);
Shinya Kitaoka 120a6e
      locals::buildDagPos(cfx, cfx, copyDagPos, addOffset);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Now, let's make a temporary container of all the stored fxs, both
Shinya Kitaoka 120a6e
  // normal and column-based
Shinya Kitaoka 120a6e
  std::vector<tfx *=""> fxs;</tfx>
Shinya Kitaoka 120a6e
  fxs.reserve(m_fxs.size() + m_columns.size());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for_each_fx(tcg::bind1st(&locals::push_back, fxs));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // We need to store input links for these fxs
Shinya Kitaoka 120a6e
  size_t f, fCount = fxs.size();
Shinya Kitaoka 120a6e
  for (f = 0; f != fCount; ++f) {
Shinya Kitaoka 120a6e
    TFx *fx = fxs[f];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TFx *ofx = ::getActualIn(fx);
Shinya Kitaoka 120a6e
    fx       = ::getActualOut(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int il, ilCount = ofx->getInputPortCount();
Shinya Kitaoka 120a6e
    for (il = 0; il != ilCount; ++il) {
Shinya Kitaoka 120a6e
      if (TFx *ifx = ofx->getInputPort(il)->getFx())
Shinya Kitaoka 120a6e
        m_links.push_back(TFxCommand::Link(ifx, ofx, il));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Apply the required position, if any
Shinya Kitaoka 120a6e
  if (pos != TConst::nowhere) {
Shinya Kitaoka 120a6e
    // Then, we'll take the mean difference from pos and add it to
Shinya Kitaoka 120a6e
    // each fx
Shinya Kitaoka 120a6e
    TPointD middlePos;
Shinya Kitaoka 120a6e
    int fxsCount = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    std::vector<tfx *="">::const_iterator ft, fEnd = fxs.end();</tfx>
Shinya Kitaoka 120a6e
    for (ft = fxs.begin(); ft != fEnd; ++ft) {
Shinya Kitaoka 120a6e
      TFx *fx = *ft;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      const TPointD &fxPos = fx->getAttributes()->getDagNodePos();
Shinya Kitaoka 120a6e
      if (fxPos != TConst::nowhere) {
Shinya Kitaoka 120a6e
        middlePos += fxPos;
Shinya Kitaoka 120a6e
        ++fxsCount;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (fxsCount > 0) {
Shinya Kitaoka 120a6e
      middlePos = TPointD(middlePos.x / fxsCount, middlePos.y / fxsCount);
Shinya Kitaoka 120a6e
      const TPointD &offset = pos - middlePos;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      for (ft = fxs.begin(); ft != fEnd; ++ft) {
Shinya Kitaoka 120a6e
        TFx *fx = *ft;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        const TPointD &fxPos = fx->getAttributes()->getDagNodePos();
manongjohn f37f4a
        if (fxPos != TConst::nowhere)
manongjohn f37f4a
          fx->getAttributes()->setDagNodePos(fxPos + offset);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoPasteFxs::redo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Iterate all normal fxs
Shinya Kitaoka 120a6e
  std::list<tfxp>::const_iterator ft, fEnd = m_fxs.end();</tfxp>
Shinya Kitaoka 120a6e
  for (ft = m_fxs.begin(); ft != fEnd; ++ft) {
Shinya Kitaoka 120a6e
    // Re-insert them in the scene
Shinya Kitaoka 120a6e
    addFxToCurrentScene(ft->getPointer(), xsh, false);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Iterate columns
Shinya Kitaoka 120a6e
  std::list<txshcolumnp>::const_iterator ct, cEnd = m_columns.end();</txshcolumnp>
Shinya Kitaoka 120a6e
  for (ct = m_columns.begin(); ct != cEnd; ++ct) {
Shinya Kitaoka 120a6e
    // Insert them
Shinya Kitaoka 120a6e
    FxCommandUndo::insertColumn(xsh, ct->getPointer(),
Shinya Kitaoka 120a6e
                                xsh->getFirstFreeColumnIndex(), true, false);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Restore links
Shinya Kitaoka 120a6e
  size_t l, lCount = m_links.size();
Shinya Kitaoka 120a6e
  for (l = 0; l != lCount; ++l) FxCommandUndo::attach(xsh, m_links[l], false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoPasteFxs::undo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::list<tfxp>::const_iterator ft, fEnd = m_fxs.end();</tfxp>
Shinya Kitaoka 120a6e
  for (ft = m_fxs.begin(); ft != fEnd; ++ft) {
Shinya Kitaoka 120a6e
    TFx *fx = ft->getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    FxCommandUndo::removeFxOrColumn(xsh, fx, -1, true,
Shinya Kitaoka 120a6e
                                    false);  // Skip parameter links removal
Shinya Kitaoka 120a6e
    FxCommandUndo::makeNotCurrent(m_fxHandle, fx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::list<txshcolumnp>::const_iterator ct, cEnd = m_columns.end();</txshcolumnp>
Shinya Kitaoka 120a6e
  for (ct = m_columns.begin(); ct != cEnd; ++ct) {
Shinya Kitaoka 120a6e
    FxCommandUndo::removeFxOrColumn(xsh, 0, (*ct)->getIndex(), true,
Shinya Kitaoka 120a6e
                                    false);  // Skip parameter links removal
Shinya Kitaoka 120a6e
    FxCommandUndo::makeNotCurrent(m_fxHandle, (*ct)->getFx());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename func=""></typename>
Shinya Kitaoka 120a6e
void UndoPasteFxs::for_each_fx(Func func) const {
Shinya Kitaoka 120a6e
  std::list<tfxp>::const_iterator ft, fEnd = m_fxs.end();</tfxp>
Shinya Kitaoka 120a6e
  for (ft = m_fxs.begin(); ft != fEnd; ++ft) func(ft->getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::list<txshcolumnp>::const_iterator ct, cEnd = m_columns.end();</txshcolumnp>
Shinya Kitaoka 120a6e
  for (ct = m_columns.begin(); ct != cEnd; ++ct)
Shinya Kitaoka 120a6e
    if (TFx *cfx = (*ct)->getFx()) func(cfx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString UndoPasteFxs::getHistoryString() {
Shinya Kitaoka 120a6e
  QString str = QObject::tr("Paste Fx  :  ");
Shinya Kitaoka 120a6e
  std::list<tfxp>::const_iterator it;</tfxp>
Shinya Kitaoka 120a6e
  for (it = m_fxs.begin(); it != m_fxs.end(); it++) {
Shinya Kitaoka 120a6e
    if (it != m_fxs.begin()) str += QString(",  ");
Shinya Kitaoka 120a6e
    str += QString("%1").arg(QString::fromStdWString((*it)->getName()));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return str;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::pasteFxs(const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                          const std::map<tfx *,="" int=""> &zeraryFxColumnSize,</tfx>
Shinya Kitaoka 120a6e
                          const std::list<txshcolumnp> &columns,</txshcolumnp>
Shinya Kitaoka 120a6e
                          const TPointD &pos, TXsheetHandle *xshHandle,
Shinya Kitaoka 120a6e
                          TFxHandle *fxHandle) {
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(new UndoPasteFxs(</fxcommandundo>
Shinya Kitaoka 120a6e
      fxs, zeraryFxColumnSize, columns, pos, xshHandle, fxHandle));
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Add Paste Fxs  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class UndoAddPasteFxs : public UndoPasteFxs {
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  TFxCommand::Link m_linkIn;  //!< Input link to be re-established on redo
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoAddPasteFxs(TFx *inFx, const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                  const std::map<tfx *,="" int=""> &zeraryFxColumnSize,</tfx>
Shinya Kitaoka 120a6e
                  const std::list<txshcolumnp> &columns,</txshcolumnp>
Shinya Kitaoka 120a6e
                  TXsheetHandle *xshHandle, TFxHandle *fxHandle)
Shinya Kitaoka 120a6e
      : UndoPasteFxs(fxs, zeraryFxColumnSize, columns, TConst::nowhere,
Shinya Kitaoka 120a6e
                     xshHandle, fxHandle) {
Shinya Kitaoka 120a6e
    initialize(inFx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize(TFx *inFx);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoAddPasteFxs::initialize(TFx *inFx) {
Shinya Kitaoka 120a6e
  if (!(inFx && UndoPasteFxs::isConsistent())) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // NOTE: Any zerary (shouldn't be there anyway) has already been
Shinya Kitaoka 120a6e
  //       moved to columns at this point
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Ensure that inFx and outFx are not in a macro Fx
Shinya Kitaoka 120a6e
  if (::isInsideAMacroFx(inFx, xsh)) {
Shinya Kitaoka 120a6e
    m_fxs.clear(), m_columns.clear();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Get the first fx to be inserted, and follow links down
Shinya Kitaoka 120a6e
  // (until an empty input port at index 0 is found)
Shinya Kitaoka 120a6e
  TFx *ifx = FxCommandUndo::leftmostConnectedFx(m_fxs.front().getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Then, we have the link to be established
Shinya Kitaoka 120a6e
  m_linkIn = TFxCommand::Link(inFx, ifx, 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Furthermore, clone the group stack from inFx into each inserted fx
Shinya Kitaoka 120a6e
  typedef tcg::function<void (*)(tfx="" *),="" *,="" fxcommandundo::clonegroupstack="" tfx=""></void>
Shinya Kitaoka 120a6e
      clone_fun;
Shinya Kitaoka 120a6e
  for_each_fx(tcg::bind1st(clone_fun(), inFx));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoAddPasteFxs::redo() const {
Shinya Kitaoka 120a6e
  if (m_linkIn.m_inputFx) {
Shinya Kitaoka 120a6e
    TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Further apply the stored link
Shinya Kitaoka 120a6e
    FxCommandUndo::attach(xsh, m_linkIn, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Copiare l'indice di gruppo dell'fx di input
Shinya Kitaoka 120a6e
    typedef tcg::function
Shinya Kitaoka 120a6e
                          FxCommandUndo::copyGroupEditLevel>
Shinya Kitaoka 120a6e
        copy_fun;
Shinya Kitaoka 120a6e
    for_each_fx(
Shinya Kitaoka 120a6e
        tcg::binder1st<copy_fun>(copy_fun(), m_linkIn.m_inputFx.getPointer()));</copy_fun>
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UndoPasteFxs::redo();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::addPasteFxs(TFx *inFx, const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                             const std::map<tfx *,="" int=""> &zeraryFxColumnSize,</tfx>
Shinya Kitaoka 120a6e
                             const std::list<txshcolumnp> &columns,</txshcolumnp>
Shinya Kitaoka 120a6e
                             TXsheetHandle *xshHandle, TFxHandle *fxHandle) {
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(new UndoAddPasteFxs(</fxcommandundo>
Shinya Kitaoka 120a6e
      inFx, fxs, zeraryFxColumnSize, columns, xshHandle, fxHandle));
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    // NOTE: (inFx == 0) is considered consistent, as long as
Shinya Kitaoka 120a6e
    // UndoPasteFxs::isConsistent()
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Insert Paste Fxs  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class UndoInsertPasteFxs final : public UndoAddPasteFxs {
Shinya Kitaoka 120a6e
  TFxCommand::Link m_linkOut;  //!< Output link to be re-established
Shinya Kitaoka 120a6e
                               //!< on redo
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoInsertPasteFxs(const TFxCommand::Link &link, const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                     const std::map<tfx *,="" int=""> &zeraryFxColumnSize,</tfx>
Shinya Kitaoka 120a6e
                     const std::list<txshcolumnp> &columns,</txshcolumnp>
Shinya Kitaoka 120a6e
                     TXsheetHandle *xshHandle, TFxHandle *fxHandle)
Shinya Kitaoka 120a6e
      : UndoAddPasteFxs(link.m_inputFx.getPointer(), fxs, zeraryFxColumnSize,
Shinya Kitaoka 120a6e
                        columns, xshHandle, fxHandle) {
Shinya Kitaoka 120a6e
    initialize(link);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize(const TFxCommand::Link &link);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoInsertPasteFxs::initialize(const TFxCommand::Link &link) {
Shinya Kitaoka 120a6e
  if (!UndoPasteFxs::isConsistent()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  TFx *inFx    = link.m_inputFx.getPointer();
Shinya Kitaoka 120a6e
  TFx *outFx   = link.m_outputFx.getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Ensure consistency
Shinya Kitaoka 120a6e
  if (!(inFx && outFx) || ::isInsideAMacroFx(outFx, xsh)) {
Shinya Kitaoka 120a6e
    m_fxs.clear(), m_columns.clear();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Get the first fx to be inserted, and follow links up
Shinya Kitaoka 120a6e
  // (to a no output fx)
Shinya Kitaoka 120a6e
  TFx *ofx = FxCommandUndo::rightmostConnectedFx(m_fxs.front().getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Now, store the appropriate output link
Shinya Kitaoka 120a6e
  m_linkOut = TFxCommand::Link(ofx, outFx, link.m_index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoInsertPasteFxs::redo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Further apply the stored link pair
Shinya Kitaoka 120a6e
  FxCommandUndo::attach(xsh, m_linkOut, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_linkOut.m_index < 0)
Shinya Kitaoka 120a6e
    xsh->getFxDag()->removeFromXsheet(m_linkIn.m_inputFx.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UndoAddPasteFxs::redo();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoInsertPasteFxs::undo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Reattach the original configuration
Shinya Kitaoka 120a6e
  TFxCommand::Link orig(m_linkIn.m_inputFx, m_linkOut.m_outputFx,
Shinya Kitaoka 120a6e
                        m_linkOut.m_index);
Shinya Kitaoka 120a6e
  FxCommandUndo::attach(xsh, orig, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UndoAddPasteFxs::undo();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::insertPasteFxs(const Link &link, const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                                const std::map<tfx *,="" int=""> &zeraryFxColumnSize,</tfx>
Shinya Kitaoka 120a6e
                                const std::list<txshcolumnp> &columns,</txshcolumnp>
Shinya Kitaoka 120a6e
                                TXsheetHandle *xshHandle, TFxHandle *fxHandle) {
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(new UndoInsertPasteFxs(</fxcommandundo>
Shinya Kitaoka 120a6e
      link, fxs, zeraryFxColumnSize, columns, xshHandle, fxHandle));
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Replace Paste Fxs  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class UndoReplacePasteFxs final : public UndoAddPasteFxs {
Shinya Kitaoka 2a7129
  std::unique_ptr<deletefxorcolumnundo> m_deleteFxUndo;</deletefxorcolumnundo>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFx *m_fx, *m_rightmostFx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoReplacePasteFxs(TFx *fx, const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                      const std::map<tfx *,="" int=""> &zeraryFxColumnSize,</tfx>
Shinya Kitaoka 120a6e
                      const std::list<txshcolumnp> &columns,</txshcolumnp>
Shinya Kitaoka 120a6e
                      TXsheetHandle *xshHandle, TFxHandle *fxHandle)
Shinya Kitaoka 120a6e
      : UndoAddPasteFxs(inFx(fx), fxs, zeraryFxColumnSize, columns, xshHandle,
Shinya Kitaoka 120a6e
                        fxHandle)
Shinya Kitaoka 120a6e
      , m_deleteFxUndo(new DeleteFxOrColumnUndo(fx, xshHandle, fxHandle))
Shinya Kitaoka 120a6e
      , m_fx(fx)
Shinya Kitaoka 120a6e
      , m_rightmostFx() {
Shinya Kitaoka 120a6e
    initialize();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  bool isConsistent() const override {
Shinya Kitaoka 120a6e
    return UndoAddPasteFxs::isConsistent() && m_deleteFxUndo->isConsistent();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  static TFx *inFx(const TFx *fx) {
Shinya Kitaoka 120a6e
    return (fx && fx->getInputPortCount() > 0) ? fx->getInputPort(0)->getFx()
Shinya Kitaoka 120a6e
                                               : 0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void initialize();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoReplacePasteFxs::initialize() {
Shinya Kitaoka 120a6e
  if (m_fxs.empty()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Get the first fx to be inserted, and follow links up
Shinya Kitaoka 120a6e
  // (to a no output fx)
Shinya Kitaoka 120a6e
  m_rightmostFx =
Shinya Kitaoka 120a6e
      FxCommandUndo::rightmostConnectedFx(this->m_fxs.front().getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Then, add to the list of links to be inserted upon redo
Shinya Kitaoka 120a6e
  int ol, olCount = m_fx->getOutputConnectionCount();
Shinya Kitaoka 120a6e
  for (ol = 0; ol != olCount; ++ol) {
Shinya Kitaoka 120a6e
    TFxPort *port = m_fx->getOutputConnection(ol);
Shinya Kitaoka 120a6e
    TFx *ownerFx  = port->getOwnerFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TCG_ASSERT(port && ownerFx, continue);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int p = ::inputPortIndex(ownerFx, port);
Shinya Kitaoka 120a6e
    TCG_ASSERT(p < ownerFx->getInputPortCount(), continue);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    this->m_links.push_back(TFxCommand::Link(m_rightmostFx, ownerFx, p));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (fxDag->getTerminalFxs()->containsFx(m_fx))
Shinya Kitaoka 120a6e
    this->m_links.push_back(
Shinya Kitaoka 120a6e
        TFxCommand::Link(m_rightmostFx, fxDag->getXsheetFx(), -1));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoReplacePasteFxs::redo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Deleting m_fx would attach its input to the xsheet, if m_fx is terminal.
Shinya Kitaoka 120a6e
  // In our case, however, it needs to be attached to the replacement fx - so,
Shinya Kitaoka 120a6e
  // let's detach m_fx from the xsheet
Shinya Kitaoka 120a6e
  fxDag->removeFromXsheet(m_fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Then, delete the fx and insert the replacement. Note that this order is
Shinya Kitaoka 120a6e
  // required to ensure the correct dag positions
Shinya Kitaoka 120a6e
  m_deleteFxUndo->redo();
Shinya Kitaoka 120a6e
  UndoAddPasteFxs::redo();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoReplacePasteFxs::undo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Remove m_lastFx's output connections - UndoAddPasteFxs would try to
Shinya Kitaoka 120a6e
  // redirect them to the replaced fx's input (due to the 'blind' detach
Shinya Kitaoka 120a6e
  // command)
Shinya Kitaoka 120a6e
  int ol, olCount = m_rightmostFx->getOutputConnectionCount();
Shinya Kitaoka 120a6e
  for (ol = olCount - 1; ol >= 0; --ol)
Shinya Kitaoka 120a6e
    if (TFxPort *port = m_rightmostFx->getOutputConnection(ol)) port->setFx(0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  fxDag->removeFromXsheet(m_rightmostFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Reverse the applied commands. Again, the order prevents 'bumped' dag
Shinya Kitaoka 120a6e
  // positions
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UndoAddPasteFxs::undo();  // This would bridge the inserted fxs' inputs with
Shinya Kitaoka 120a6e
                            // their outputs
Shinya Kitaoka 120a6e
  m_deleteFxUndo->undo();  // This also re-establishes the original output links
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::replacePasteFxs(TFx *inFx, const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                                 const std::map<tfx *,="" int=""> &zeraryFxColumnSize,</tfx>
Shinya Kitaoka 120a6e
                                 const std::list<txshcolumnp> &columns,</txshcolumnp>
Shinya Kitaoka 120a6e
                                 TXsheetHandle *xshHandle,
Shinya Kitaoka 120a6e
                                 TFxHandle *fxHandle) {
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(new UndoReplacePasteFxs(</fxcommandundo>
Shinya Kitaoka 120a6e
      inFx, fxs, zeraryFxColumnSize, columns, xshHandle, fxHandle));
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Disconnect Fxs  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class UndoDisconnectFxs : public FxCommandUndo {
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  std::list<tfxp> m_fxs;</tfxp>
Shinya Kitaoka 120a6e
  TFx *m_leftFx, *m_rightFx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // NOTE: Although we'll detach only 1 input link, fxs with dynamic ports still
Shinya Kitaoka 120a6e
  // require us
Shinya Kitaoka 120a6e
  // to store the whole ports configuration
Shinya Kitaoka 120a6e
  std::vector<tfxcommand::link> m_undoLinksIn, m_undoLinksOut,</tfxcommand::link>
Shinya Kitaoka 120a6e
      m_undoTerminalLinks;
Shinya Kitaoka 120a6e
  std::vector<qpair<tfxp, tpointd="">> m_undoDagPos, m_redoDagPos;</qpair<tfxp,>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoDisconnectFxs(const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                    const QList<qpair<tfxp, tpointd="">> &oldFxPos,</qpair<tfxp,>
Shinya Kitaoka 120a6e
                    TXsheetHandle *xshHandle)
Shinya Kitaoka 120a6e
      : m_fxs(fxs)
Shinya Kitaoka 120a6e
      , m_xshHandle(xshHandle)
Shinya Kitaoka 120a6e
      , m_undoDagPos(oldFxPos.begin(), oldFxPos.end()) {
Shinya Kitaoka 120a6e
    initialize();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool isConsistent() const override { return !m_fxs.empty(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override { return QObject::tr("Disconnect Fx"); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  static void applyPos(const QPair<tfxp, tpointd=""> &pair) {</tfxp,>
Shinya Kitaoka 120a6e
    pair.first->getAttributes()->setDagNodePos(pair.second);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  static void attach(TXsheet *xsh, const TFxCommand::Link &link) {
Shinya Kitaoka 120a6e
    FxCommandUndo::attach(xsh, link, false);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  static void detachXsh(TXsheet *xsh, const TFxCommand::Link &link) {
Shinya Kitaoka 120a6e
    xsh->getFxDag()->removeFromXsheet(link.m_inputFx.getPointer());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoDisconnectFxs::initialize() {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Don't deal with fxs inside a macro fx
Shinya Kitaoka 120a6e
  ::FilterInsideAMacro insideAMacro_fun = {xsh};
Shinya Kitaoka 120a6e
  if (std::find_if(m_fxs.begin(), m_fxs.end(), insideAMacro_fun) != m_fxs.end())
Shinya Kitaoka 120a6e
    m_fxs.clear();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_fxs.empty()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build fxs data
otakuto e347ad
  auto const contains = [this](TFx const *fx) -> bool {
otakuto e347ad
    return std::count_if(this->m_fxs.begin(), this->m_fxs.end(),
otakuto e347ad
                         [fx](TFxP &f) { return f.getPointer() == fx; }) > 0;
otakuto e347ad
  };
Toshihiro Shimizu 890ddd
otakuto e347ad
  m_leftFx =
otakuto e347ad
      FxCommandUndo::leftmostConnectedFx(m_fxs.front().getPointer(), contains);
otakuto e347ad
  m_rightFx =
otakuto e347ad
      FxCommandUndo::rightmostConnectedFx(m_fxs.front().getPointer(), contains);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Store sensible original data for the undo
Shinya Kitaoka 120a6e
  m_undoLinksIn  = FxCommandUndo::inputLinks(xsh, m_leftFx);
Shinya Kitaoka 120a6e
  m_undoLinksOut = FxCommandUndo::outputLinks(xsh, m_rightFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<tfxcommand::link>::const_iterator lt, lEnd = m_undoLinksIn.end();</tfxcommand::link>
Shinya Kitaoka 120a6e
  for (lt = m_undoLinksIn.begin(); lt != lEnd; ++lt)
Shinya Kitaoka 120a6e
    if (fxDag->getTerminalFxs()->containsFx(lt->m_inputFx.getPointer()))
Shinya Kitaoka 120a6e
      m_undoTerminalLinks.push_back(TFxCommand::Link(lt->m_inputFx.getPointer(),
Shinya Kitaoka 120a6e
                                                     fxDag->getXsheetFx(), -1));
Toshihiro Shimizu 890ddd
otakuto e347ad
  std::vector<qpair<tfxp, tpointd="">> v;</qpair<tfxp,>
otakuto e347ad
  for (auto const &e : m_undoDagPos) {
otakuto e347ad
    v.emplace_back(e.first, e.first->getAttributes()->getDagNodePos());
otakuto e347ad
  }
otakuto e347ad
  m_redoDagPos = std::move(v);
otakuto e347ad
  m_redoDagPos.shrink_to_fit();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoDisconnectFxs::redo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Detach the first port only - I'm not sure it should really be like this,
Shinya Kitaoka 120a6e
  // but it's
Shinya Kitaoka 120a6e
  // legacy, and altering it would require to revise the 'simulation' procedures
Shinya Kitaoka 120a6e
  // in fxschematicscene.cpp...  (any command simulation should be done here,
Shinya Kitaoka 120a6e
  // btw)
Shinya Kitaoka 120a6e
  FxCommandUndo::detachFxs(xsh, m_leftFx, m_rightFx, false);
Shinya Kitaoka 120a6e
  if (m_leftFx->getInputPortCount() > 0) m_leftFx->getInputPort(0)->setFx(0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // This is also convenient, since fxs with dynamic groups will maintain all
Shinya Kitaoka 120a6e
  // BUT 1
Shinya Kitaoka 120a6e
  // port - thus preventing us from dealing with that, since 1 port is always
Shinya Kitaoka 120a6e
  // available
Shinya Kitaoka 120a6e
  // on fxs with dynamic ports...
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::for_each(m_redoDagPos.begin(), m_redoDagPos.end(), applyPos);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoDisconnectFxs::undo() const {
Shinya Kitaoka 120a6e
  typedef void (*LinkFun)(TXsheet * xsh, const TFxCommand::Link &);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Restore the old links
Shinya Kitaoka 120a6e
  tcg::binder1st<linkfun> attacher(&UndoDisconnectFxs::attach, xsh);</linkfun>
Shinya Kitaoka 120a6e
  tcg::binder1st<linkfun> xshDetacher(&UndoDisconnectFxs::detachXsh, xsh);</linkfun>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::for_each(m_undoLinksIn.begin(), m_undoLinksIn.end(), attacher);
Shinya Kitaoka 120a6e
  std::for_each(m_undoLinksOut.begin(), m_undoLinksOut.end(), attacher);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::for_each(m_undoLinksIn.begin(), m_undoLinksIn.end(), xshDetacher);
Shinya Kitaoka 120a6e
  std::for_each(m_undoTerminalLinks.begin(), m_undoTerminalLinks.end(),
Shinya Kitaoka 120a6e
                attacher);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Restore old positions
Shinya Kitaoka 120a6e
  std::for_each(m_undoDagPos.begin(), m_undoDagPos.end(), applyPos);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::disconnectFxs(const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                               TXsheetHandle *xshHandle,
Shinya Kitaoka 120a6e
                               const QList<qpair<tfxp, tpointd="">> &fxPos) {</qpair<tfxp,>
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(</fxcommandundo>
Shinya Kitaoka 120a6e
      new UndoDisconnectFxs(fxs, fxPos, xshHandle));
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Connect Fxs  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class UndoConnectFxs final : public UndoDisconnectFxs {
Shinya Kitaoka 120a6e
  struct GroupData;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  TFxCommand::Link m_link;
Shinya Kitaoka 120a6e
  std::vector<groupdata> m_undoGroupDatas;</groupdata>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoConnectFxs(const TFxCommand::Link &link, const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                 const QList<qpair<tfxp, tpointd="">> &fxPos,</qpair<tfxp,>
Shinya Kitaoka 120a6e
                 TXsheetHandle *xshHandle)
Shinya Kitaoka 120a6e
      : UndoDisconnectFxs(fxs, fxPos, xshHandle), m_link(link) {
Shinya Kitaoka 120a6e
    initialize();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool isConsistent() const override { return !m_fxs.empty(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  static void applyPos(const QPair<tfxp, tpointd=""> &pair) {</tfxp,>
Shinya Kitaoka 120a6e
    pair.first->getAttributes()->setDagNodePos(pair.second);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct UndoConnectFxs::GroupData {
Shinya Kitaoka 120a6e
  TFx *m_fx;
Shinya Kitaoka 120a6e
  QStack<int> m_groupIds;</int>
Shinya Kitaoka 120a6e
  QStack<std::wstring> m_groupNames;</std::wstring>
Shinya Kitaoka 120a6e
  int m_editingGroup;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  GroupData(TFx *fx);
Shinya Kitaoka 120a6e
  void restore() const;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
UndoConnectFxs::GroupData::GroupData(TFx *fx)
Shinya Kitaoka 120a6e
    : m_fx(fx)
Shinya Kitaoka 120a6e
    , m_groupIds(fx->getAttributes()->getGroupIdStack())
Shinya Kitaoka 120a6e
    , m_groupNames(fx->getAttributes()->getGroupNameStack())
Shinya Kitaoka 120a6e
    , m_editingGroup(fx->getAttributes()->getEditingGroupId()) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoConnectFxs::GroupData::restore() const {
Shinya Kitaoka 120a6e
  assert(!m_groupIds.empty());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  FxCommandUndo::cloneGroupStack(m_groupIds, m_groupNames, m_fx);
Shinya Kitaoka 120a6e
  FxCommandUndo::copyGroupEditLevel(m_editingGroup, m_fx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoConnectFxs::initialize() {
Shinya Kitaoka 120a6e
  if (!UndoDisconnectFxs::isConsistent()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TCG_ASSERT(m_link.m_inputFx && m_link.m_outputFx, m_fxs.clear(); return );
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Store sensible original data for the undo
Shinya Kitaoka 120a6e
  m_undoGroupDatas.reserve(m_fxs.size());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::list<tfxp>::const_iterator ft, fEnd = m_fxs.end();</tfxp>
Shinya Kitaoka 120a6e
  for (ft = m_fxs.begin(); ft != fEnd; ++ft) {
Shinya Kitaoka 120a6e
    if ((*ft)->getAttributes()->isGrouped())
Shinya Kitaoka 120a6e
      m_undoGroupDatas.push_back(GroupData((*ft).getPointer()));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoConnectFxs::redo() const {
Shinya Kitaoka 120a6e
  UndoDisconnectFxs::redo();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Apply the new links
Shinya Kitaoka 120a6e
  FxCommandUndo::insertFxs(xsh, m_link, m_leftFx, m_rightFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Copy the input fx's group data
Shinya Kitaoka 120a6e
  TFx *inFx = m_link.m_inputFx.getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::list<tfxp>::const_iterator ft, fEnd = m_fxs.end();</tfxp>
Shinya Kitaoka 120a6e
  for (ft = m_fxs.begin(); ft != fEnd; ++ft) {
Shinya Kitaoka 120a6e
    TFx *fx = (*ft).getPointer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    FxCommandUndo::cloneGroupStack(inFx, fx);
Shinya Kitaoka 120a6e
    FxCommandUndo::copyGroupEditLevel(inFx, fx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoConnectFxs::undo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Undo the insert
Shinya Kitaoka 120a6e
  FxCommandUndo::detachFxs(xsh, m_leftFx, m_rightFx);
Shinya Kitaoka 120a6e
  FxCommandUndo::attach(xsh, m_link, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Restore the old fxs' group data
Shinya Kitaoka 120a6e
  tcg::function<void &groupdata::restore="" (groupdata::*)()="" const,=""> restore_fun;</void>
Shinya Kitaoka 120a6e
  std::for_each(m_undoGroupDatas.begin(), m_undoGroupDatas.end(), restore_fun);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UndoDisconnectFxs::undo();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString UndoConnectFxs::getHistoryString() {
Shinya Kitaoka 120a6e
  return QObject::tr("Connect Fx : %1 - %2")
Shinya Kitaoka 120a6e
      .arg(QString::fromStdWString(m_leftFx->getName()))
Shinya Kitaoka 120a6e
      .arg(QString::fromStdWString(m_rightFx->getName()));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::connectFxs(const Link &link, const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                            TXsheetHandle *xshHandle,
Shinya Kitaoka 120a6e
                            const QList<qpair<tfxp, tpointd="">> &fxPos) {</qpair<tfxp,>
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(</fxcommandundo>
Shinya Kitaoka 120a6e
      new UndoConnectFxs(link, fxs, fxPos, xshHandle));
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Set Parent  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class SetParentUndo final : public FxCommandUndo {
Shinya Kitaoka 120a6e
  TFxP m_oldFx, m_newFx, m_parentFx;
Shinya Kitaoka 120a6e
  int m_parentPort;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool m_removeFromXsheet;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  SetParentUndo(TFx *fx, TFx *parentFx, int parentFxPort,
Shinya Kitaoka 120a6e
                TXsheetHandle *xshHandle)
Shinya Kitaoka 120a6e
      : m_newFx(fx)
Shinya Kitaoka 120a6e
      , m_parentFx(parentFx)
Shinya Kitaoka 120a6e
      , m_parentPort(parentFxPort)
Shinya Kitaoka 120a6e
      , m_xshHandle(xshHandle) {
Shinya Kitaoka 120a6e
    initialize();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool isConsistent() const override { return m_parentFx; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 120a6e
  void redo_() const;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SetParentUndo::initialize() {
Shinya Kitaoka 120a6e
  if (!m_parentFx) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // NOTE: We cannot store this directly, since it's the actual out that owns
Shinya Kitaoka 120a6e
  // the actual in, not viceversa
Shinya Kitaoka 120a6e
  TFx *parentFx = ::getActualIn(m_parentFx.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(m_parentPort < parentFx->getInputPortCount());
Shinya Kitaoka 120a6e
  assert(m_parentPort >= 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_oldFx = parentFx->getInputPort(m_parentPort)->getFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_removeFromXsheet =  // This is a bit odd. The legacy behavior of the
Shinya Kitaoka 120a6e
      (m_newFx &&       // setParent() (ie connect 2 fxs with a link, I know
Shinya Kitaoka 120a6e
       (m_newFx->getOutputConnectionCount() ==
Shinya Kitaoka 120a6e
        0) &&  // the name is bad) command is that of *removing terminal
Shinya Kitaoka 120a6e
       fxDag->getTerminalFxs()->containsFx(
Shinya Kitaoka 120a6e
           m_newFx.getPointer()) &&  // links* on the input fx (m_newFx in our
Shinya Kitaoka 120a6e
                                     // case).
Shinya Kitaoka 120a6e
       m_parentFx != fxDag->getXsheetFx());  // I've retained this behavior
Shinya Kitaoka 120a6e
                                             // since it can be handy
Shinya Kitaoka 120a6e
  // for users, but only if the xsheet link is the SOLE output
Shinya Kitaoka 120a6e
  if (::isInsideAMacroFx(m_parentFx.getPointer(), xsh) ||  // link.
Shinya Kitaoka 120a6e
      ::isInsideAMacroFx(m_oldFx.getPointer(), xsh) ||
Shinya Kitaoka 120a6e
      ::isInsideAMacroFx(m_newFx.getPointer(), xsh))
Shinya Kitaoka 120a6e
    m_parentFx = TFxP();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SetParentUndo::redo() const {
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
Due to compatibility issues from *schematicnode.cpp files, the "do" operation
Shinya Kitaoka 120a6e
cannot
Shinya Kitaoka 120a6e
signal changes to the scene/xsheet... but the *re*do must.
Shinya Kitaoka 120a6e
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  redo_();
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SetParentUndo::redo_() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFx *parentFx = ::getActualIn(m_parentFx.getPointer());
Shinya Kitaoka 120a6e
  FxCommandUndo::attach(xsh, m_newFx.getPointer(), parentFx, m_parentPort,
Shinya Kitaoka 120a6e
                        false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_removeFromXsheet)
Shinya Kitaoka 120a6e
    xsh->getFxDag()->removeFromXsheet(m_newFx.getPointer());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SetParentUndo::undo() const {
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFx *parentFx = ::getActualIn(m_parentFx.getPointer());
Shinya Kitaoka 120a6e
  FxCommandUndo::attach(xsh, m_oldFx.getPointer(), parentFx, m_parentPort,
Shinya Kitaoka 120a6e
                        false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_removeFromXsheet) xsh->getFxDag()->addToXsheet(m_newFx.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::setParent(TFx *fx, TFx *parentFx, int parentFxPort,
Shinya Kitaoka 120a6e
                           TXsheetHandle *xshHandle) {
Shinya Kitaoka 120a6e
  if (dynamic_cast<txsheetfx *="">(parentFx) || parentFxPort < 0) {</txsheetfx>
Shinya Kitaoka 2a7129
    std::unique_ptr<connectnodestoxsheetundo> undo(</connectnodestoxsheetundo>
Shinya Kitaoka 120a6e
        new ConnectNodesToXsheetUndo(std::list<tfxp>(1, fx), xshHandle));</tfxp>
Shinya Kitaoka 120a6e
    if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
      undo->redo_();
Shinya Kitaoka 120a6e
      TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 2a7129
    std::unique_ptr<setparentundo> undo(</setparentundo>
Shinya Kitaoka 120a6e
        new SetParentUndo(fx, parentFx, parentFxPort, xshHandle));
Shinya Kitaoka 120a6e
    if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
      undo->redo_();
Shinya Kitaoka 120a6e
      TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Rename Fx  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class UndoRenameFx final : public FxCommandUndo {
Shinya Kitaoka 120a6e
  TFxP m_fx;
Shinya Kitaoka 120a6e
  std::wstring m_newName, m_oldName;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoRenameFx(TFx *fx, const std::wstring &newName, TXsheetHandle *xshHandle)
Shinya Kitaoka 120a6e
      : m_fx(fx)
Shinya Kitaoka 120a6e
      , m_newName(newName)
Shinya Kitaoka 120a6e
      , m_oldName(::getActualIn(fx)->getName())
Shinya Kitaoka 120a6e
      , m_xshHandle(xshHandle) {
Shinya Kitaoka 120a6e
    assert(fx);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  bool isConsistent() const override { return true; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    redo_();
Shinya Kitaoka 120a6e
    m_xshHandle->notifyXsheetChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void redo_() const { ::getActualIn(m_fx.getPointer())->setName(m_newName); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    ::getActualIn(m_fx.getPointer())->setName(m_oldName);
Shinya Kitaoka 120a6e
    m_xshHandle->notifyXsheetChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  QString getHistoryString() override {
Shinya Kitaoka 120a6e
    return QObject::tr("Rename Fx : %1 > %2")
Shinya Kitaoka 120a6e
        .arg(QString::fromStdWString(m_oldName))
Shinya Kitaoka 120a6e
        .arg(QString::fromStdWString(m_newName));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::renameFx(TFx *fx, const std::wstring &newName,
Shinya Kitaoka 120a6e
                          TXsheetHandle *xshHandle) {
Shinya Kitaoka 120a6e
  if (!fx) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2a7129
  std::unique_ptr<undorenamefx> undo(new UndoRenameFx(fx, newName, xshHandle));</undorenamefx>
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo_();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Group Fxs  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class UndoGroupFxs : public FxCommandUndo {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  struct GroupData {
Shinya Kitaoka 120a6e
    TFxP m_fx;
Shinya Kitaoka 120a6e
    mutable int m_groupIndex;  //! AKA group \a position (not \a id).
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    GroupData(const TFxP &fx, int groupIdx = -1)
Shinya Kitaoka 120a6e
        : m_fx(fx), m_groupIndex(groupIdx) {}
Shinya Kitaoka 120a6e
  };
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  std::vector<groupdata> m_groupData;</groupdata>
Shinya Kitaoka 120a6e
  int m_groupId;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoGroupFxs(const std::list<tfxp> &fxs, TXsheetHandle *xshHandle)</tfxp>
Shinya Kitaoka 120a6e
      : m_groupData(fxs.begin(), fxs.end()), m_xshHandle(xshHandle) {
Shinya Kitaoka 120a6e
    initialize();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool isConsistent() const override { return !m_groupData.empty(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override { return QObject::tr("Group Fx"); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
protected:
Shinya Kitaoka 120a6e
  UndoGroupFxs(int groupId, TXsheetHandle *xshHandle)
Shinya Kitaoka 120a6e
      : m_groupId(groupId), m_xshHandle(xshHandle) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoGroupFxs::initialize() {
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    inline static bool isXsheetFx(const GroupData &gd) {
Shinya Kitaoka 120a6e
      return dynamic_cast<txsheet *="">(gd.m_fx.getPointer());</txsheet>
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build a group id for the new group
Shinya Kitaoka 120a6e
  m_groupId = fxDag->getNewGroupId();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // The xsheet fx must never be grouped
Shinya Kitaoka 120a6e
  m_groupData.erase(std::remove_if(m_groupData.begin(), m_groupData.end(),
Shinya Kitaoka 120a6e
                                   &locals::isXsheetFx),
Shinya Kitaoka 120a6e
                    m_groupData.end());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Scan for macro fxs. A macro's internal fxs must be added to the group data,
Shinya Kitaoka 120a6e
  // too
Shinya Kitaoka 120a6e
  // Yep, this is one of the few fx commands that do not require macro
Shinya Kitaoka 120a6e
  // explosion.
Shinya Kitaoka 120a6e
  size_t g, gCount = m_groupData.size();
Shinya Kitaoka 120a6e
  for (g = 0; g != gCount; ++g) {
Shinya Kitaoka 120a6e
    if (TMacroFx *macro =
Shinya Kitaoka 120a6e
            dynamic_cast<tmacrofx *="">(m_groupData[g].m_fx.getPointer())) {</tmacrofx>
Shinya Kitaoka 120a6e
      const std::vector<tfxp> &internalFxs = macro->getFxs();</tfxp>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      std::vector<tfxp>::const_iterator ft, fEnd = internalFxs.end();</tfxp>
Shinya Kitaoka 120a6e
      for (ft = internalFxs.begin(); ft != fEnd; ++ft)
Shinya Kitaoka 120a6e
        m_groupData.push_back(*ft);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoGroupFxs::redo() const {
Shinya Kitaoka 120a6e
  const std::wstring groupName = L"Group " + std::to_wstring(m_groupId);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<groupdata>::const_iterator gt, gEnd = m_groupData.end();</groupdata>
Shinya Kitaoka 120a6e
  for (gt = m_groupData.begin(); gt != gEnd; ++gt) {
Shinya Kitaoka 120a6e
    // Insert the group id in the fx
Shinya Kitaoka 120a6e
    gt->m_groupIndex = gt->m_fx->getAttributes()->setGroupId(m_groupId);
Shinya Kitaoka 120a6e
    gt->m_fx->getAttributes()->setGroupName(groupName);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoGroupFxs::undo() const {
Shinya Kitaoka 120a6e
  std::vector<groupdata>::const_iterator gt, gEnd = m_groupData.end();</groupdata>
Shinya Kitaoka 120a6e
  for (gt = m_groupData.begin(); gt != gEnd; ++gt) {
Shinya Kitaoka 120a6e
    TCG_ASSERT(gt->m_groupIndex >= 0, continue);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Insert the group id in the fx
Shinya Kitaoka 120a6e
    gt->m_fx->getAttributes()->removeGroupId(gt->m_groupIndex);
Shinya Kitaoka 120a6e
    gt->m_fx->getAttributes()->removeGroupName(gt->m_groupIndex);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    gt->m_groupIndex = -1;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::groupFxs(const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                          TXsheetHandle *xshHandle) {
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(new UndoGroupFxs(fxs, xshHandle));</fxcommandundo>
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Ungroup Fxs  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class UndoUngroupFxs final : public UndoGroupFxs {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoUngroupFxs(int groupId, TXsheetHandle *xshHandle)
Shinya Kitaoka 120a6e
      : UndoGroupFxs(groupId, xshHandle) {
Shinya Kitaoka 120a6e
    initialize();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override { UndoGroupFxs::undo(); }
Shinya Kitaoka 473e70
  void undo() const override { UndoGroupFxs::redo(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override { return QObject::tr("Ungroup Fx"); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoUngroupFxs::initialize() {
Shinya Kitaoka 120a6e
  struct {
Shinya Kitaoka 120a6e
    UndoUngroupFxs *m_this;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    void scanFxForGroup(TFx *fx) {
Shinya Kitaoka 120a6e
      if (fx) {
Shinya Kitaoka 120a6e
        const QStack<int> &groupStack = fx->getAttributes()->getGroupIdStack();</int>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        int groupIdx =
Shinya Kitaoka 120a6e
            groupStack.indexOf(m_this->m_groupId);  // Returns -1 if not found
Shinya Kitaoka 120a6e
        if (groupIdx >= 0)
Shinya Kitaoka 120a6e
          m_this->m_groupData.push_back(GroupData(fx, groupIdx));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  } locals = {this};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheet *xsh = m_xshHandle->getXsheet();
Shinya Kitaoka 120a6e
  FxDag *fxDag = xsh->getFxDag();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // We must iterate the xsheet's fxs pool and look for fxs with the specified
Shinya Kitaoka 120a6e
  // group id
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Search column fxs
Shinya Kitaoka 120a6e
  int c, cCount = xsh->getColumnCount();
Shinya Kitaoka 120a6e
  for (c = 0; c != cCount; ++c) {
Shinya Kitaoka 120a6e
    TXshColumn *column = xsh->getColumn(c);
Shinya Kitaoka 120a6e
    assert(column);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    locals.scanFxForGroup(column->getFx());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Search normal fxs (not column ones)
Shinya Kitaoka 120a6e
  TFxSet *internalFxs = fxDag->getInternalFxs();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int f, fCount = internalFxs->getFxCount();
Shinya Kitaoka 120a6e
  for (f = 0; f != fCount; ++f) {
Shinya Kitaoka 120a6e
    TFx *fx = internalFxs->getFx(f);
Shinya Kitaoka 120a6e
    locals.scanFxForGroup(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (TMacroFx *macroFx = dynamic_cast<tmacrofx *="">(fx)) {</tmacrofx>
Shinya Kitaoka 120a6e
      // Search internal macro fxs
Shinya Kitaoka 120a6e
      const std::vector<tfxp> &fxs = macroFx->getFxs();</tfxp>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      std::vector<tfxp>::const_iterator ft, fEnd = fxs.end();</tfxp>
Shinya Kitaoka 120a6e
      for (ft = fxs.begin(); ft != fEnd; ++ft)
Shinya Kitaoka 120a6e
        locals.scanFxForGroup(ft->getPointer());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Search output fxs
Shinya Kitaoka 120a6e
  int o, oCount = fxDag->getOutputFxCount();
Shinya Kitaoka 120a6e
  for (o = 0; o != oCount; ++o) locals.scanFxForGroup(fxDag->getOutputFx(o));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::ungroupFxs(int groupId, TXsheetHandle *xshHandle) {
Shinya Kitaoka 2a7129
  std::unique_ptr<fxcommandundo> undo(new UndoUngroupFxs(groupId, xshHandle));</fxcommandundo>
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo();
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
//    Rename Group  command
Toshihiro Shimizu 890ddd
//**********************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class UndoRenameGroup final : public FxCommandUndo {
Shinya Kitaoka 120a6e
  std::vector<undogroupfxs::groupdata> m_groupData;</undogroupfxs::groupdata>
Shinya Kitaoka 120a6e
  std::wstring m_oldGroupName, m_newGroupName;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXsheetHandle *m_xshHandle;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoRenameGroup(const std::list<tfxp> &fxs, const std::wstring &newGroupName,</tfxp>
Shinya Kitaoka 120a6e
                  bool fromEditor, TXsheetHandle *xshHandle)
Shinya Kitaoka 120a6e
      : m_groupData(fxs.begin(), fxs.end())
Shinya Kitaoka 120a6e
      , m_newGroupName(newGroupName)
Shinya Kitaoka 120a6e
      , m_xshHandle(xshHandle) {
Shinya Kitaoka 120a6e
    initialize(fromEditor);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool isConsistent() const override { return !m_groupData.empty(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override;
Shinya Kitaoka 473e70
  void undo() const override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void redo_() const;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  QString getHistoryString() override {
Shinya Kitaoka 120a6e
    return QObject::tr("Rename Group  : %1 > %2")
Shinya Kitaoka 120a6e
        .arg(QString::fromStdWString(m_oldGroupName))
Shinya Kitaoka 120a6e
        .arg(QString::fromStdWString(m_newGroupName));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void initialize(bool fromEditor);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoRenameGroup::initialize(bool fromEditor) {
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    inline static bool isInvalid(const UndoGroupFxs::GroupData &gd) {
Shinya Kitaoka 120a6e
      return (gd.m_groupIndex < 0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!m_groupData.empty()) {
Shinya Kitaoka 120a6e
    m_oldGroupName =
Shinya Kitaoka 120a6e
        m_groupData.front().m_fx->getAttributes()->getGroupName(fromEditor);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Extract group indices
Shinya Kitaoka 120a6e
    std::vector<undogroupfxs::groupdata>::const_iterator gt,</undogroupfxs::groupdata>
Shinya Kitaoka 120a6e
        gEnd = m_groupData.end();
Shinya Kitaoka 120a6e
    for (gt = m_groupData.begin(); gt != gEnd; ++gt) {
Shinya Kitaoka 120a6e
      const QStack<std::wstring> &groupNamesStack =</std::wstring>
Shinya Kitaoka 120a6e
          gt->m_fx->getAttributes()->getGroupNameStack();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      gt->m_groupIndex =
Shinya Kitaoka 120a6e
          groupNamesStack.indexOf(m_oldGroupName);  // Returns -1 if not found
Shinya Kitaoka 120a6e
      assert(gt->m_groupIndex >= 0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_groupData.erase(std::remove_if(m_groupData.begin(), m_groupData.end(),
Shinya Kitaoka 120a6e
                                   &locals::isInvalid),
Shinya Kitaoka 120a6e
                    m_groupData.end());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoRenameGroup::redo() const {
Shinya Kitaoka 120a6e
  redo_();
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoRenameGroup::redo_() const {
Shinya Kitaoka 120a6e
  std::vector<undogroupfxs::groupdata>::const_iterator gt,</undogroupfxs::groupdata>
Shinya Kitaoka 120a6e
      gEnd = m_groupData.end();
Shinya Kitaoka 120a6e
  for (gt = m_groupData.begin(); gt != gEnd; ++gt) {
Shinya Kitaoka 120a6e
    gt->m_fx->getAttributes()->removeGroupName(gt->m_groupIndex);
Shinya Kitaoka 120a6e
    gt->m_fx->getAttributes()->setGroupName(m_newGroupName, gt->m_groupIndex);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void UndoRenameGroup::undo() const {
Shinya Kitaoka 120a6e
  std::vector<undogroupfxs::groupdata>::const_iterator gt,</undogroupfxs::groupdata>
Shinya Kitaoka 120a6e
      gEnd = m_groupData.end();
Shinya Kitaoka 120a6e
  for (gt = m_groupData.begin(); gt != gEnd; ++gt) {
Shinya Kitaoka 120a6e
    gt->m_fx->getAttributes()->removeGroupName(gt->m_groupIndex);
Shinya Kitaoka 120a6e
    gt->m_fx->getAttributes()->setGroupName(m_oldGroupName, gt->m_groupIndex);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_xshHandle->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFxCommand::renameGroup(const std::list<tfxp> &fxs,</tfxp>
Shinya Kitaoka 120a6e
                             const std::wstring &name, bool fromEditor,
Shinya Kitaoka 120a6e
                             TXsheetHandle *xshHandle) {
Shinya Kitaoka 2a7129
  std::unique_ptr<undorenamegroup> undo(</undorenamegroup>
Shinya Kitaoka 120a6e
      new UndoRenameGroup(fxs, name, fromEditor, xshHandle));
Shinya Kitaoka 120a6e
  if (undo->isConsistent()) {
Shinya Kitaoka 120a6e
    undo->redo_();  // Same schematic nodes problem as above...   :(
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo.release());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}