Here is the new version.
How can I protect the new CLAM::Network methods from other calls than from ClamNetworkCanvas?

If you think it's going well, I can add a new bool attribute of "isCutMode", to erase the processings once are copied.

Regards,
Natanael.

El 06/05/2008 12:04 PM, Pau Arumí Albó escribió:
El dj 05 de 06 de 2008 a les 12:37 +0200, en/na David García Garzón va
escriure:
On Dijous 05 Juny 2008, Pau Arumí Albó wrote:
El dj 05 de 06 de 2008 a les 06:15 -0300, en/na Natanael Olaiz va

escriure:
El 06/04/2008 06:17 AM, Pau Arumí Albó escribió:
El dc 04 de 06 de 2008 a les 03:58 -0300, en/na Natanael Olaiz va

escriure:
El 06/03/2008 03:16 PM, Pau Arumí escribió:
After some chat with David about this, I think it would be good to
start with 1) reuse the network loading/saving code, before starting
2) adding positions to the xml. This is because having 2) will make
the load/save more difficult, as needs transferring data from
canvas/procboxes to the network, and should be better approached as a
posterior refactoring.

Don't hesitate to ask if find problems
Should I store the positions & sizes within the Network root path, or
on a separate one (let's call it "NetworkCanvas", for instance)? In
the second case I will need to make two calls to dump/restore methods
(one within the network -as right now-, and the other within the
canvas), but that keeps the data separated and doesn't need to
transfer any new data to the network.

Is my question clear enough? What do you prefer?
It makes sense to me but I'm not sure about the details -- specially
who and how to close the xml doc if we have two dump calls?
One possible solution that comes to my mind is adding a new string
argument to the Dump mothod (or function, don't remember) containing an
"extra root" with the positions and sizes.

However, this is 2) and, IMO, 1) should be done before.
Sorry to insist.... but thinking about it, I'm wondering how to reuse
the code to save selections without get the same problem of positions.
The selections are attributes of ProcessingBoxes, just like positions!
So, I can pass the list of selected processings to the Network, but I
think doing that is maybe more weired than just start doing the
integration in a higher level, in ClamNetworkCanvas, deriving it from
Components, redefining StoreOn and LoadFrom, and make the
ProcessingBoxes correspondents definition adaptions...
Well yes I see it's not an easy problem.
The main problem I see implementing Store and Load methods in
NetworkCanvas is that will duplicate the code in Network::StoreOn.
And we need this functinality in Network for the NE-less use cases.
What about adding optional decorations (in the design pattern sense) in
the Processing in the network containing the Canvas data: position,
size, isSelected (so that you can store only the selected processings in
a given string).
I think that the decorator already exists: it is the ProcessingDefinitionAdapter it is a matter of adding the position information besides the name.

Then when the Canvas store would consist on first pushing the
canvas-related data into the network and then call the normal Store (or
Dump). And similarly for Loading.

However at this point I'd like to have David's input, he is the expert
on NE user-interface.
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.

I agree with the approach.
Now let's see if Natanel can defeat the evil details :-)
As David says, let's first address the selections part, since this will
define the  PBox-Canvas-Network communication while maintaining the
changeset small.

P




_______________________________________________
Clam-devel mailing list
[email protected]
https://llistes.projectes.lafarga.org/cgi-bin/mailman/listinfo/clam-devel


Index: NetworkEditor/src/NetworkCanvas.hxx
===================================================================
--- NetworkEditor/src/NetworkCanvas.hxx	(revision 11453)
+++ 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
 {
@@ -93,6 +94,17 @@
 		_clearSelectionAction->setShortcut(QKeySequence(tr("Ctrl+Shift+A")));
 		addAction(_clearSelectionAction);
 		connect(_clearSelectionAction, SIGNAL(triggered()), this, SLOT(onClearSelections()));
+
+		_copySelectionAction = new QAction("Copy Selection", this);
+		_copySelectionAction->setShortcut(QKeySequence(tr("Ctrl+C")));
+		addAction(_copySelectionAction);
+		connect(_copySelectionAction, SIGNAL(triggered()), this, SLOT (onCopyProcessingsToClipboard()));
+
+		_pasteSelectionAction = new QAction("Paste Selection", this);
+		_pasteSelectionAction->setShortcut(QKeySequence(tr("Ctrl+V")));
+		addAction(_pasteSelectionAction);
+		connect(_pasteSelectionAction, SIGNAL(triggered()), this, SLOT (onPasteProcessingsFromClipboard()));
+
 	}
 	void raise(ProcessingBox * toRaise)
 	{
@@ -735,6 +747,8 @@
 	QAction * _deleteSelectedAction;
 	QAction * _selectAllAction;
 	QAction * _clearSelectionAction;
+	QAction * _copySelectionAction;
+	QAction * _pasteSelectionAction;
 	QColor _colorBoxFrameText;
 	QColor _colorBoxFrameOutline;
 	QColor _colorBoxFrame;
@@ -1115,6 +1129,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();
@@ -1244,6 +1274,53 @@
 			return;
 		}
 	}
+
+	void onCopyProcessingsToClipboard()
+	{
+		std::ostringstream streamXMLBuffer;
+		QPoint point = ((QAction*)sender())->data().toPoint();
+
+		CLAM::Network::NamesList processingsNamesList;
+		// Copy selected (/active) processings on networkToCopy
+		for (unsigned i=0; i<_processings.size();i++)
+		{
+			ProcessingBox::Region region = _processings[i]->getRegion(point);
+			if ( (region==ProcessingBox::noRegion) && (!_processings[i]->isSelected()) )
+				continue;
+			const std::string name=(_processings[i]->getName()).toStdString();
+			processingsNamesList.push_back(name);
+		}
+		_network->UpdateSelections(processingsNamesList);
+		CLAM::XmlStorage::Dump(*_network,"network",streamXMLBuffer);
+		_network->ClearSelections();
+		QApplication::clipboard()->setText(QString(streamXMLBuffer.str().c_str()));
+	}
+
+	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);
+			_network->unSetPasteMode();
+		}
+		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();
+	}
+
+
 	void onAddSlider()
 	{
 		QPoint point = ((QAction*)sender())->data().toPoint();
@@ -1587,11 +1664,13 @@
 					this, SLOT(onRename()))->setData(translatedPos);
 				menu->addAction(QIcon(":/icons/images/editdelete.png"), "Remove",
 				this, SLOT(onDeleteProcessing()))->setData(translatedPos);
+				menu->addAction("Copy processing(s)", this, SLOT(onCopyProcessingsToClipboard()))->setData(translatedPos);
 				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:
Index: CLAM/src/Flow/Networks/Network.cxx
===================================================================
--- CLAM/src/Flow/Networks/Network.cxx	(revision 11453)
+++ 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,11 @@
 		for(it=BeginProcessings();it!=EndProcessings();it++)
 		{
 			Processing * proc = it->second;
-			ProcessingDefinitionAdapter procDefinition(proc, it->first);
+			const std::string & name = it->first;
+			ProcessingsSet::const_iterator itFindSelected = _selectedProcessings.find(name);
+			if (!_selectedProcessings.empty() && itFindSelected==_selectedProcessings.end())
+				continue; // if there are selected processings and the actual isn't, skip
+			ProcessingDefinitionAdapter procDefinition(proc, name);
 			XMLComponentAdapter xmlAdapter(procDefinition, "processing", true);
 			storage.Store(xmlAdapter);
 		}
@@ -70,6 +75,11 @@
 		{
 			const std::string & name = it->first;
 			Processing * proc = it->second;
+
+			ProcessingsSet::const_iterator itFindSelected = _selectedProcessings.find(name);
+			if (!_selectedProcessings.empty() && itFindSelected==_selectedProcessings.end())
+				continue; // if there are selected processings and the actual isn't, skip
+
 			OutPortRegistry::Iterator itOutPort;
 			for (itOutPort=proc->GetOutPorts().Begin(); 
 			     itOutPort!=proc->GetOutPorts().End(); 
@@ -85,6 +95,9 @@
 				    namesIterator!=namesInPorts.end();
 				    namesIterator++)
 				{
+					ProcessingsSet::const_iterator itFindSelected = _selectedProcessings.find(GetProcessingIdentifier(*namesIterator));
+					if (!_selectedProcessings.empty() && itFindSelected==_selectedProcessings.end())
+						continue; // if there are selected processings and the actual isn't, skip
 					ConnectionDefinitionAdapter connectionDefinition( outPortName, *namesIterator );
 					XMLComponentAdapter xmlAdapter(connectionDefinition, "port_connection", true);
 					storage.Store(xmlAdapter);
@@ -96,6 +109,11 @@
 		{
 			const std::string & name = it->first;
 			Processing * proc = it->second;
+
+			ProcessingsSet::const_iterator itFindSelected = _selectedProcessings.find(name);
+			if (!_selectedProcessings.empty() && itFindSelected==_selectedProcessings.end())
+				continue; // if there are selected processings and the actual isn't, skip
+
 			OutControlRegistry::Iterator itOutControl;
 			for (itOutControl=proc->GetOutControls().Begin(); 
 			     itOutControl!=proc->GetOutControls().End(); 
@@ -108,6 +126,9 @@
 				    namesIterator!=namesInControls.end();
 				    namesIterator++)
 				{
+					ProcessingsSet::const_iterator itFindSelected = _selectedProcessings.find(GetProcessingIdentifier(*namesIterator));
+					if (!_selectedProcessings.empty() && itFindSelected==_selectedProcessings.end())
+						continue; // if there are selected processings and the actual isn't, skip		
 					ConnectionDefinitionAdapter connectionDefinition( outControlName, *namesIterator );
 					XMLComponentAdapter xmlAdapter(connectionDefinition, "control_connection", true);
 					storage.Store(xmlAdapter);
@@ -118,7 +139,9 @@
 
 	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);
 
@@ -128,7 +151,18 @@
 			XMLComponentAdapter xmlAdapter(procDefinition, "processing", true);
 			if(storage.Load(xmlAdapter) == false) break;
 			
-			AddProcessing(procDefinition.GetName(), procDefinition.GetProcessing()); 
+			if (!_setPasteMode)
+				AddProcessing(procDefinition.GetName(), procDefinition.GetProcessing()); 
+			else
+			{
+				const std::string & name = procDefinition.GetName();
+				CLAM::Processing * processing =procDefinition.GetProcessing();
+				std::string key=processing->GetClassName();
+				std::string newname= AddProcessing(key);
+				//CLAM::Processing * procnew = &GetProcessing(newname);
+				//procnew->Configure(processing->GetConfig());
+				newProcNames.insert(changeProcNames::value_type(name,newname));
+			}
 		}
 
 		while(1)
@@ -140,7 +174,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 +196,42 @@
 			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()); }
 		}
 
 	}
 
+	bool Network::UpdateSelections (const NamesList & processingsNamesList)
+	{
+		NamesList::const_iterator namesIterator;
+		if (!_selectedProcessings.empty() || processingsNamesList.empty())
+			return 1;
+		for (namesIterator=processingsNamesList.begin();namesIterator!=processingsNamesList.end();namesIterator++)
+		{
+			_selectedProcessings.insert(*namesIterator);
+		}
+		return 0;
+		
+	}
+	void Network::ClearSelections ()
+	{
+		_selectedProcessings.clear();
+	}
+
+
 	void Network::AddFlowControl(FlowControl* flowControl)
 	{
 		if (_flowControl) delete _flowControl;
Index: CLAM/src/Flow/Networks/Network.hxx
===================================================================
--- CLAM/src/Flow/Networks/Network.hxx	(revision 11453)
+++ 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"
@@ -75,6 +76,13 @@
 	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 ClearSelections ();
+	void setPasteMode() { _setPasteMode=true; }
+	void unSetPasteMode() { _setPasteMode=false; }
+	bool getPasteMode() { return _setPasteMode; }
+
 	// methods related to connect/disconnect interface
 	bool ConnectPorts( const std::string &, const std::string & );
 	bool ConnectControls( const std::string &, const std::string & );
@@ -158,6 +166,12 @@
 	static char NamesIdentifiersSeparator();
 	FlowControl* _flowControl;
 	NetworkPlayer* _player;
+	
+	// attributes for canvas copy & paste
+	typedef std::set<std::string> ProcessingsSet;
+	ProcessingsSet _selectedProcessings;
+	bool _setPasteMode;
+
 };
 
 }// namespace

_______________________________________________
Clam-devel mailing list
[email protected]
https://llistes.projectes.lafarga.org/cgi-bin/mailman/listinfo/clam-devel

Reply via email to