The same with little improvements in the code (deleted some unuseful loops).
El 06/08/2008 01:43 AM, Natanael Olaiz escribió:
El 06/05/2008 07:37 AM, David García Garzón escribió:
Well i think it is very important to keep the network, canvas
agnostic, as well as keeping the NetworkCanvas clam agnostic. But as
we are introducing the positions and the selections as part of the
network itself i propose to add such an information to the network
itself, not as part of the processings but as network optional
attributes. That is duplicating the information but just during
loading and storing. The key to eliminate a duplication hell is
declaring such information in the Network is not reliable, is the
canvas who set it before loading and recovers it after saving but
clears it afterwards. So there is no temptation on using it in a
different place than load/store.
So how to implement that? For selections adding the network a
std::set attribute of selected processing names. It has just effect
on storing and only if it is not empty. If it is not empty the
network should check if the name is in the set before storin it. On
storing a selection and just on storing a selection call
Network::UpdateSelections(list or other container), do the store and
then clear them Network::ClearSelections.
The Network::StoreOn will only store the processing whose name is in
the set, or all of them if the set is empty. I think that this one
would be the easier one and the first to be addressed.
About the positions and sizes, i would use the same strategy. On
load/store push or extract such information into the network being
reliable just on load and store time, clearing it afterwards to be
sure we don't rely on it after load/store. Such information should be
transfered if present to the ProcessingDefinitionAdapter to xml them.
Not that clear about the structure to store size and position but
let's address first selections and then, let's see what about sizes
and positions.
This is a first attempt to store & restore positions and sizes too. I
make it in two steps, but I think it's not necessary...
What do you think?
BTW, I don't like that boxPos and boxSize goes first... can you
imagine names which begins with a latter letter than "t" (of type)? :-)
Regards,
Natanael.
Index: NetworkEditor/src/NetworkCanvas.hxx
===================================================================
--- NetworkEditor/src/NetworkCanvas.hxx (revision 11454)
+++ NetworkEditor/src/NetworkCanvas.hxx (working copy)
@@ -25,6 +25,7 @@
#include <vector>
#include <algorithm>
#include <CLAM/Assert.hxx>
+#include <CLAM/XMLStorage.hxx>
class NetworkCanvas : public QWidget
{
@@ -794,6 +795,21 @@
_newProcessingAction->setShortcut(QKeySequence(tr("Ctrl+Space")));
addAction(_newProcessingAction);
connect(_newProcessingAction, SIGNAL(triggered()), this, SLOT(onNewProcessing()));
+
+ _copySelectionAction = new QAction("Copy Selection", this);
+ _copySelectionAction->setShortcut(QKeySequence(tr("Ctrl+C")));
+ addAction(_copySelectionAction);
+ connect(_copySelectionAction, SIGNAL(triggered()), this, SLOT (onCopyProcessingsToClipboard()));
+
+ _cutSelectionAction = new QAction("Cut Selection", this);
+ _cutSelectionAction->setShortcut(QKeySequence(tr("Ctrl+X")));
+ addAction(_cutSelectionAction);
+ connect(_cutSelectionAction, SIGNAL(triggered()), this, SLOT (onCutProcessingsToClipboard()));
+
+ _pasteSelectionAction = new QAction("Paste Selection", this);
+ _pasteSelectionAction->setShortcut(QKeySequence(tr("Ctrl+V")));
+ addAction(_pasteSelectionAction);
+ connect(_pasteSelectionAction, SIGNAL(triggered()), this, SLOT (onPasteProcessingsFromClipboard()));
}
CLAM::Network & network()
{
@@ -1115,6 +1131,22 @@
refreshWires();
}
+
+ void reloadNetwork()
+ {
+ if (networkIsDummy()) return;
+ CLAM::Network::ProcessingsMap::const_iterator it;
+ for (it=_network->BeginProcessings(); it!=_network->EndProcessings(); it++)
+ {
+ const std::string & name = it->first;
+ if (getBox(QString(name.c_str())))
+ continue; // if the processing exists in canvas, skip it
+ CLAM::Processing * processing = it->second;
+ addProcessingBox( name.c_str(), processing );
+ }
+ refreshWires();
+ }
+
void refreshWires()
{
clearWires();
@@ -1214,6 +1246,48 @@
box->resize(size);
}
}
+
+ bool updatePositionsOnXML()
+ {
+ CLAM::Network::StringsMap positionsMap;
+ CLAM::Network::StringsMap sizesMap;
+ for (unsigned i=0; i<_processings.size(); i++)
+ {
+ QPoint posProcessing = _processings[i]->pos();
+ QSize sizeProcessing = _processings[i]->size();
+ const std::string name=_processings[i]->getName().toStdString();
+ const std::string pos=(tr("%1,%2").arg(posProcessing.x()).arg(posProcessing.y())).toStdString();
+ const std::string size=(tr("%1,%2").arg(sizeProcessing.width()).arg(sizeProcessing.height())).toStdString();
+ positionsMap.insert(CLAM::Network::StringsMap::value_type(name,pos));
+ sizesMap.insert(CLAM::Network::StringsMap::value_type(name,size));
+ }
+ return (_network->UpdateProcBoxesPos(positionsMap) || _network->UpdateProcBoxesSizes(sizesMap));
+ }
+
+ void loadPositionsFromXML(QPoint offsetPoint = QPoint(0,0))
+ {
+ const CLAM::Network::StringsMap & ProcPosMap=_network->getProcBoxesPos();
+ CLAM::Network::StringsMap::const_iterator it;
+ for(it=ProcPosMap.begin();it!=ProcPosMap.end();it++)
+ {
+ QString name=QString(it->first.c_str());
+ QStringList stringsPos=QString(it->second.c_str()).split(",");
+ QPoint pos=offsetPoint+QPoint(stringsPos[0].toInt(),stringsPos[1].toInt());
+ ProcessingBox * box=getBox(name);
+ box->move(pos);
+ }
+
+ const CLAM::Network::StringsMap & ProcSizesMap=_network->getProcBoxesSizes();
+ for(it=ProcSizesMap.begin();it!=ProcSizesMap.end();it++)
+ {
+ QString name=QString(it->first.c_str());
+ QStringList stringsSize=QString(it->second.c_str()).split(",");
+ QSize size=QSize(stringsSize[0].toInt(),stringsSize[1].toInt());
+ ProcessingBox * box=getBox(name);
+ box->resize(size);
+ }
+ }
+
private slots:
void onCopyConnection()
{
@@ -1244,6 +1318,66 @@
return;
}
}
+
+ void onCopyProcessingsToClipboard(bool cut=false)
+ {
+ std::ostringstream streamXMLBuffer;
+ CLAM::Network::NamesList processingsNamesList;
+ // Copy selected processings on networkToCopy
+ for (unsigned i=0; i<_processings.size();i++)
+ {
+ if (!_processings[i]->isSelected())
+ continue;
+ const std::string name=(_processings[i]->getName()).toStdString();
+ processingsNamesList.push_back(name);
+ }
+ if (_network->UpdateSelections(processingsNamesList))
+ return;
+ updatePositionsOnXML();
+ CLAM::XmlStorage::Dump(*_network,"network",streamXMLBuffer);
+
+ QApplication::clipboard()->setText(QString(streamXMLBuffer.str().c_str()));
+ if (!cut) return;
+
+ CLAM::Network::NamesList::iterator cuttedNamesIterator;
+ for(cuttedNamesIterator=processingsNamesList.begin();
+ cuttedNamesIterator!=processingsNamesList.end();
+ cuttedNamesIterator++)
+ {
+ removeProcessing(getBox(QString((*cuttedNamesIterator).c_str())));
+ }
+ }
+
+ void onCutProcessingsToClipboard()
+ {
+ onCopyProcessingsToClipboard(true);
+ }
+
+ void onPasteProcessingsFromClipboard()
+ {
+ QPoint point = ((QAction*)sender())->data().toPoint();
+ QString text=QApplication::clipboard()->text();
+ std::stringstream streamXMLBuffer;
+ streamXMLBuffer << text.toStdString();
+ CLAM::Network networkToPaste;
+
+ try
+ {
+ _network->setPasteMode();
+ CLAM::XMLStorage::Restore(*_network, streamXMLBuffer);
+ }
+ catch(CLAM::XmlStorageErr &e)
+ {
+ QMessageBox::critical(this, tr("Error trying to paste from clipboard"),
+ tr("<p>An occurred while loading clipboard.<p>"
+ "<p><b>%1</b></p>").arg(e.what()));
+ return;
+ }
+ reloadNetwork();
+ loadPositionsFromXML(point);
+ }
+
+
void onAddSlider()
{
QPoint point = ((QAction*)sender())->data().toPoint();
@@ -1587,15 +1721,23 @@
this, SLOT(onRename()))->setData(translatedPos);
menu->addAction(QIcon(":/icons/images/editdelete.png"), "Remove",
this, SLOT(onDeleteProcessing()))->setData(translatedPos);
+ menu->addSeparator();
+ menu->addAction("Copy processing(s)", this, SLOT(onCopyProcessingsToClipboard()));
+ menu->addAction("Cut processing(s)", this, SLOT(onCutProcessingsToClipboard()));
return;
}
}
menu->addAction(QIcon(":/icons/images/newprocessing.png"), "Add processing",
this, SLOT(onNewProcessing()))->setData(translatedPos);
+ menu->addAction("Paste processing(s)",
+ this,SLOT(onPasteProcessingsFromClipboard()))->setData(translatedPos);
}
protected:
QAction * _newProcessingAction;
+ QAction * _copySelectionAction;
+ QAction * _cutSelectionAction;
+ QAction * _pasteSelectionAction;
private:
CLAM::Network * _network;
};
Index: CLAM/src/Flow/Networks/ProcessingDefinitionAdapter.cxx
===================================================================
--- CLAM/src/Flow/Networks/ProcessingDefinitionAdapter.cxx (revision 11454)
+++ CLAM/src/Flow/Networks/ProcessingDefinitionAdapter.cxx (working copy)
@@ -30,8 +30,8 @@
namespace CLAM
{
- ProcessingDefinitionAdapter::ProcessingDefinitionAdapter( Processing * adaptee, const std::string & name )
- : mAdaptee(adaptee), mName(name)
+ ProcessingDefinitionAdapter::ProcessingDefinitionAdapter( Processing * adaptee, const std::string & name, const std::string & pos, const std::string & size )
+ : mAdaptee(adaptee), mName(name), mPos(pos), mSize(size)
{
}
@@ -47,7 +47,18 @@
XMLAdapter<Text> classNameAdapter( className, "type");
store.Store(nameAdapter);
store.Store(classNameAdapter);
-
+ if (mPos!="")
+ {
+ Text posCopy(mPos);
+ XMLAdapter<Text> posAdapter (posCopy, "boxPos");
+ store.Store(posAdapter);
+ }
+ if (mSize!="")
+ {
+ Text sizeCopy(mSize);
+ XMLAdapter<Text> sizeAdapter (sizeCopy, "boxSize");
+ store.Store(sizeAdapter);
+ }
XMLComponentAdapter configAdapter((ProcessingConfig&)mAdaptee->GetConfig());
store.Store(configAdapter);
}
@@ -60,6 +71,11 @@
XMLAdapter<Text> classNameAdapter( className, "type");
store.Load(classNameAdapter);
+ XMLAdapter<Text> posAdapter (mPos, "boxPos");
+ store.Load(posAdapter);
+ XMLAdapter<Text> sizeAdapter (mSize, "boxSize");
+ store.Load(sizeAdapter);
+
try
{
mAdaptee = ProcessingFactory::GetInstance().CreateSafe(className);
Index: CLAM/src/Flow/Networks/Network.cxx
===================================================================
--- CLAM/src/Flow/Networks/Network.cxx (revision 11454)
+++ CLAM/src/Flow/Networks/Network.cxx (working copy)
@@ -37,7 +37,8 @@
Network::Network() :
_name("Unnamed Network"),
_flowControl(new NaiveFlowControl),
- _player(0)
+ _player(0),
+ _setPasteMode(false)
{}
Network::~Network()
@@ -57,7 +58,17 @@
for(it=BeginProcessings();it!=EndProcessings();it++)
{
Processing * proc = it->second;
- ProcessingDefinitionAdapter procDefinition(proc, it->first);
+ const std::string & name = it->first;
+ if (!ifHasSelectionAndContains(name))
+ continue;
+
+ std::string procPos="";
+ if (!_processingsBoxesPositions.empty())
+ procPos=_processingsBoxesPositions.find(name)->second;
+ std::string procSize="";
+ if(!_processingsBoxesSizes.empty())
+ procSize=_processingsBoxesSizes.find(name)->second;
+ ProcessingDefinitionAdapter procDefinition(proc, name, procPos, procSize);
XMLComponentAdapter xmlAdapter(procDefinition, "processing", true);
storage.Store(xmlAdapter);
}
@@ -70,6 +81,10 @@
{
const std::string & name = it->first;
Processing * proc = it->second;
+
+ if (!ifHasSelectionAndContains(name))
+ continue;
+
OutPortRegistry::Iterator itOutPort;
for (itOutPort=proc->GetOutPorts().Begin();
itOutPort!=proc->GetOutPorts().End();
@@ -85,6 +100,8 @@
namesIterator!=namesInPorts.end();
namesIterator++)
{
+ if (!ifHasSelectionAndContains(GetProcessingIdentifier(*namesIterator)))
+ continue;
ConnectionDefinitionAdapter connectionDefinition( outPortName, *namesIterator );
XMLComponentAdapter xmlAdapter(connectionDefinition, "port_connection", true);
storage.Store(xmlAdapter);
@@ -96,6 +113,10 @@
{
const std::string & name = it->first;
Processing * proc = it->second;
+
+ if (!ifHasSelectionAndContains(name))
+ continue;
+
OutControlRegistry::Iterator itOutControl;
for (itOutControl=proc->GetOutControls().Begin();
itOutControl!=proc->GetOutControls().End();
@@ -108,17 +129,24 @@
namesIterator!=namesInControls.end();
namesIterator++)
{
+ if (!ifHasSelectionAndContains(GetProcessingIdentifier(*namesIterator)))
+ continue;
ConnectionDefinitionAdapter connectionDefinition( outControlName, *namesIterator );
XMLComponentAdapter xmlAdapter(connectionDefinition, "control_connection", true);
storage.Store(xmlAdapter);
}
}
}
+ _selectedProcessings.clear();
+ _processingsBoxesPositions.clear();
+ _processingsBoxesSizes.clear();
}
void Network::LoadFrom( Storage & storage)
{
- Clear();
+ typedef std::map <std::string, std::string> changeProcNames;
+ changeProcNames newProcNames;
+ if (!_setPasteMode) Clear();
XMLAdapter<std::string> strAdapter( _name, "id");
storage.Load(strAdapter);
@@ -127,8 +155,26 @@
ProcessingDefinitionAdapter procDefinition;
XMLComponentAdapter xmlAdapter(procDefinition, "processing", true);
if(storage.Load(xmlAdapter) == false) break;
-
- AddProcessing(procDefinition.GetName(), procDefinition.GetProcessing());
+
+ std::string name=procDefinition.GetName();
+
+ if (!_setPasteMode)
+ AddProcessing(name, procDefinition.GetProcessing());
+ else
+ {
+ CLAM::Processing * processing =procDefinition.GetProcessing();
+ std::string key=processing->GetClassName();
+ std::string newName= AddProcessing(key);
+ CLAM::Processing & newProcessing = GetProcessing(newName);
+ newProcessing.Configure(processing->GetConfig());
+ newProcNames.insert(changeProcNames::value_type(name,newName));
+ name=newName;
+ }
+ // if exists restore canvas processings boxes related attributes
+ if (procDefinition.GetPos()!="")
+ _processingsBoxesPositions.insert(StringsMap::value_type(name,procDefinition.GetPos()));
+ if (procDefinition.GetSize()!="")
+ _processingsBoxesSizes.insert(StringsMap::value_type(name,procDefinition.GetSize()));
}
while(1)
@@ -140,7 +186,17 @@
const std::string & fullIn = connectionDefinition.GetInName();
try
{
- ConnectPorts( fullOut, fullIn );
+ if (!_setPasteMode)
+ ConnectPorts( fullOut, fullIn );
+ else
+ {
+ const std::string newNameOut = newProcNames.find(GetProcessingIdentifier(fullOut))->second
+ +"."+GetConnectorIdentifier(fullOut);
+ const std::string newNameIn = newProcNames.find(GetProcessingIdentifier(fullIn))->second
+ +"."+GetConnectorIdentifier(fullIn);
+ ConnectPorts( newNameOut, newNameIn );
+ }
+
}
catch (Err & e) { throw XmlStorageErr(e.what()); }
}
@@ -152,15 +208,76 @@
if (!storage.Load(xmlAdapter)) break;
const std::string & fullOut = connectionDefinition.GetOutName();
const std::string & fullIn = connectionDefinition.GetInName();
- try
+ try
{
- ConnectControls( fullOut, fullIn );
+ if (!_setPasteMode)
+ ConnectControls( fullOut, fullIn );
+ else
+ {
+ const std::string newNameOut = newProcNames.find(GetProcessingIdentifier(fullOut))->second
+ +"."+GetConnectorIdentifier(fullOut);
+ const std::string newNameIn = newProcNames.find(GetProcessingIdentifier(fullIn))->second
+ +"."+GetConnectorIdentifier(fullIn);
+ ConnectControls( newNameOut, newNameIn );
+ }
}
catch (Err & e) { throw XmlStorageErr(e.what()); }
}
+ _setPasteMode=false;
+ }
+ bool Network::UpdateSelections (const NamesList & processingsNamesList)
+ {
+ _selectedProcessings.clear();
+ if (processingsNamesList.empty())
+ return 1;
+ NamesList::const_iterator namesIterator;
+ for (namesIterator=processingsNamesList.begin();namesIterator!=processingsNamesList.end();namesIterator++)
+ _selectedProcessings.insert(*namesIterator);
+ return 0;
+
}
+ bool Network::ifHasSelectionAndContains(const std::string & name) const
+ {
+ NamesSet::const_iterator itFindSelected = _selectedProcessings.find(name);
+ if (!_selectedProcessings.empty() && itFindSelected==_selectedProcessings.end())
+ return 0;
+ return 1;
+ }
+
+ bool Network::UpdateProcBoxesPos (const StringsMap & processingsBoxesPositions)
+ {
+ _processingsBoxesPositions.clear();
+ if (processingsBoxesPositions.empty())
+ return 1;
+ _processingsBoxesPositions=processingsBoxesPositions;
+ return 0;
+ }
+
+ bool Network::UpdateProcBoxesSizes (const StringsMap & processingsBoxesSizes)
+ {
+ _processingsBoxesSizes.clear();
+ if (processingsBoxesSizes.empty())
+ return 1;
+ _processingsBoxesSizes=processingsBoxesSizes;
+ return 0;
+ }
+
+ const Network::StringsMap Network::getProcBoxesPos()
+ {
+ const StringsMap copyProcBoxesPos(_processingsBoxesPositions);
+ _processingsBoxesPositions.clear();
+ return copyProcBoxesPos;
+ }
+
+ const Network::StringsMap Network::getProcBoxesSizes()
+ {
+ const StringsMap copyProcBoxesSizes(_processingsBoxesSizes);
+ _processingsBoxesSizes.clear();
+ return copyProcBoxesSizes;
+ }
+
void Network::AddFlowControl(FlowControl* flowControl)
{
if (_flowControl) delete _flowControl;
Index: CLAM/src/Flow/Networks/ProcessingDefinitionAdapter.hxx
===================================================================
--- CLAM/src/Flow/Networks/ProcessingDefinitionAdapter.hxx (revision 11454)
+++ CLAM/src/Flow/Networks/ProcessingDefinitionAdapter.hxx (working copy)
@@ -36,12 +36,16 @@
private:
Processing * mAdaptee;
Text mName;
+ Text mPos;
+ Text mSize;
public:
- ProcessingDefinitionAdapter( Processing * adaptee = 0, const std::string & name = "");
+ ProcessingDefinitionAdapter( Processing * adaptee = 0, const std::string & name = "", const std::string & pos = "" , const std::string & size = "");
virtual ~ProcessingDefinitionAdapter();
Processing * GetProcessing(){return mAdaptee;}
const std::string & GetName(){return mName;}
+ const std::string & GetPos(){return mPos;}
+ const std::string & GetSize(){return mSize;}
public:
//* Returns the class name
Index: CLAM/src/Flow/Networks/Network.hxx
===================================================================
--- CLAM/src/Flow/Networks/Network.hxx (revision 11454)
+++ CLAM/src/Flow/Networks/Network.hxx (working copy)
@@ -32,6 +32,7 @@
#include <string>
#include <list>
#include <map>
+#include <set>
#include "Component.hxx"
#include "Storage.hxx"
@@ -48,6 +49,7 @@
typedef std::map< std::string, Processing* > ProcessingsMap;
typedef std::list<std::string> NamesList;
typedef std::list<InPortBase *> InPortsList;
+ typedef std::map<std::string, std::string> StringsMap;
// constructor / destructor
Network();
@@ -75,6 +77,15 @@
virtual void StoreOn( Storage & storage) const;
virtual void LoadFrom( Storage & storage);
+ // methods related to copy&paste processings from canvas
+ bool UpdateSelections (const NamesList & processingsNamesList);
+ void setPasteMode() { _setPasteMode=true; }
+
+ bool UpdateProcBoxesPos (const StringsMap & processingsBoxesPositions);
+ bool UpdateProcBoxesSizes (const StringsMap & processingsBoxesSizes);
+ const StringsMap getProcBoxesPos();
+ const StringsMap getProcBoxesSizes();
+
// methods related to connect/disconnect interface
bool ConnectPorts( const std::string &, const std::string & );
bool ConnectControls( const std::string &, const std::string & );
@@ -158,6 +169,18 @@
static char NamesIdentifiersSeparator();
FlowControl* _flowControl;
NetworkPlayer* _player;
+
+ // attributes for canvas copy & paste
+ typedef std::set<std::string> NamesSet;
+ mutable NamesSet _selectedProcessings;
+ bool _setPasteMode;
+
+ bool ifHasSelectionAndContains(const std::string & name) const;
+
+ // attributes for canvas procesisngs boxes positions and sizes
+ mutable StringsMap _processingsBoxesPositions;
+ mutable StringsMap _processingsBoxesSizes;
+
};
}// namespace
_______________________________________________
Clam-devel mailing list
[email protected]
https://llistes.projectes.lafarga.org/cgi-bin/mailman/listinfo/clam-devel