[qet] [4001] Revamp the class link and unlink element command

[ Thread Index | Date Index | More lists.tuxfamily.org/qet Archives ]


Revision: 4001
Author:   blacksun
Date:     2015-06-08 20:18:35 +0200 (Mon, 08 Jun 2015)
Log Message:
-----------
Revamp the class link and unlink element command

Modified Paths:
--------------
    trunk/dev_doc/ID_of_QUndoCommand.txt
    trunk/sources/diagramcommands.cpp
    trunk/sources/diagramcommands.h
    trunk/sources/ui/linksingleelementwidget.cpp
    trunk/sources/ui/linksingleelementwidget.ui
    trunk/sources/ui/masterpropertieswidget.cpp

Added Paths:
-----------
    trunk/sources/undocommand/linkelementcommand.cpp
    trunk/sources/undocommand/linkelementcommand.h

Modified: trunk/dev_doc/ID_of_QUndoCommand.txt
===================================================================
--- trunk/dev_doc/ID_of_QUndoCommand.txt	2015-06-08 15:23:05 UTC (rev 4000)
+++ trunk/dev_doc/ID_of_QUndoCommand.txt	2015-06-08 18:18:35 UTC (rev 4001)
@@ -1 +1,2 @@
 ChangeElementInformationCommand  = 1
+LinkElementCommand = 2

Modified: trunk/sources/diagramcommands.cpp
===================================================================
--- trunk/sources/diagramcommands.cpp	2015-06-08 15:23:05 UTC (rev 4000)
+++ trunk/sources/diagramcommands.cpp	2015-06-08 18:18:35 UTC (rev 4001)
@@ -1137,142 +1137,3 @@
 	diagram -> showMe();
 	QUndoCommand::redo();
 }
-
-/**
- * @brief LinkElementsCommand::LinkElementsCommand
- *Constructor
- * @param elmt1 element to Link
- * @param elmt2 element to link
- * @param parent parent undo command
- */
-LinkElementsCommand::LinkElementsCommand(Element *elmt1, Element *elmt2, QUndoCommand *parent) :
-	QUndoCommand(parent),
-	diagram_(elmt1->diagram()),
-	element_(elmt1),
-	first_redo(true)
-{
-	elmt_list << elmt2;
-	if (elmt1->linkType() & Element::AllReport &&
-		elmt2->linkType() & Element::AllReport) {
-		setText(QObject::tr("Lier deux reports de folio",
-							"title for undo LinkElementsCommand if two elements are folio report"));
-	}
-	else if (element_->linkType() & (Element::Master|Element::Slave))
-			setText(QObject::tr("Editer les référence croisé", "edite the cross reference"));
-	else	setText(QObject::tr("Lier deux éléments"));
-
-	previous_linked = elmt1->linkedElements();
-}
-
-LinkElementsCommand::LinkElementsCommand(Element *elmt1, QList<Element *> &elmtList, QUndoCommand *parent) :
-	QUndoCommand(parent),
-	diagram_(elmt1->diagram()),
-	element_(elmt1),
-	elmt_list(elmtList),
-	first_redo(true)
-{
-	if (element_->linkType() & (Element::Master|Element::Slave))
-				 setText(QObject::tr("Editer les référence croisé"));
-	else setText(QObject::tr("Lier deux éléments"));
-	previous_linked = elmt1->linkedElements();
-}
-
-/**
- * @brief LinkElementsCommand::~LinkElementsCommand
- *destructor
- */
-LinkElementsCommand::~LinkElementsCommand(){}
-
-/**
- * @brief LinkElementsCommand::undo
- *Undo command
- */
-void LinkElementsCommand::undo() {
-	diagram_->showMe();
-
-	foreach (Element *elmt, elmt_list)
-		element_->unlinkElement(elmt);
-
-	foreach (Element *elmt, previous_linked)
-		element_->linkToElement(elmt);
-
-	QUndoCommand::undo();
-}
-
-/**
- * @brief LinkElementsCommand::redo
- *redo command
- */
-void LinkElementsCommand::redo() {
-	diagram_->showMe();
-
-	foreach (Element *elmt, elmt_list)
-		element_->linkToElement(elmt);
-
-	//If element are report, check if text of this potential is identical.
-	if ((element_->linkType() &Element::AllReport) && first_redo) {
-		if(element_->conductors().count() && elmt_list.first()->conductors().count()) {
-			ConductorAutoNumerotation::checkPotential(element_->conductors().first());
-		}
-		first_redo = false;
-	}
-	QUndoCommand::redo();
-}
-
-/**
- * @brief unlinkElementsCommand::unlinkElementsCommand
- * Constructor, unlink elmt2 or all elements if elmt2 isn't specified
- * @param elmt1 element to set undo command
- * @param elmt2 element to be unlinked
- * @param parent undo parent
- */
-unlinkElementsCommand::unlinkElementsCommand(Element *elmt1, Element *elmt2, QUndoCommand *parent):
-	QUndoCommand(parent),
-	diagram_(elmt1->diagram()),
-	element_(elmt1)
-{
-	if (elmt2) elmt_list << elmt2;
-	else elmt_list << elmt1->linkedElements();
-	setText(QObject::tr("Délier %n élément(s)", "", elmt_list.size()));
-}
-
-/**
- * @brief unlinkElementsCommand::unlinkElementsCommand
- * @param elmt1 Element to set the link
- * @param elmtList list of all element to be linked to elmt1
- * @param parent undo command
- */
-unlinkElementsCommand::unlinkElementsCommand(Element *elmt1, QList<Element *> &elmtList, QUndoCommand *parent):
-	QUndoCommand(parent),
-	diagram_(elmt1->diagram()),
-	element_(elmt1),
-	elmt_list(elmtList)
-{
-	setText(QObject::tr("Délier %n élément(s)", "", elmt_list.size()));
-}
-
-/**
- * @brief unlinkElementsCommand::~unlinkElementsCommand
- * destructor
- */
-unlinkElementsCommand::~unlinkElementsCommand(){}
-
-/**
- * @brief unlinkElementsCommand::undo
- *undo command
- */
-void unlinkElementsCommand::undo() {
-	foreach (Element *elmt, elmt_list)
-		element_->linkToElement(elmt);
-	QUndoCommand::undo();
-}
-
-/**
- * @brief unlinkElementsCommand::redo
- *redo command
- */
-void unlinkElementsCommand::redo() {
-	foreach (Element *elmt, elmt_list)
-		element_->unlinkElement(elmt);
-	QUndoCommand::redo();
-}

Modified: trunk/sources/diagramcommands.h
===================================================================
--- trunk/sources/diagramcommands.h	2015-06-08 15:23:05 UTC (rev 4000)
+++ trunk/sources/diagramcommands.h	2015-06-08 18:18:35 UTC (rev 4001)
@@ -547,41 +547,4 @@
 	Qt::PenStyle old_style, new_style;
 	Diagram *diagram;
 };
-
-class LinkElementsCommand : public QUndoCommand {
-	public:
-	// constructor destructor
-	LinkElementsCommand (Element *elmt1, Element *elmt2, QUndoCommand *parent = 0);
-	LinkElementsCommand (Element *elmt1, QList <Element *> &elmtList, QUndoCommand *parent = 0);
-	virtual ~LinkElementsCommand();
-	//methods
-	virtual void undo();
-	virtual void redo();
-
-	private:
-	//attributes
-	Diagram *diagram_;
-	Element *element_;
-	QList <Element *> elmt_list;
-	QList <Element *> previous_linked;
-	bool first_redo;
-};
-
-class unlinkElementsCommand : public QUndoCommand {
-	public:
-	//constructor destructor
-	unlinkElementsCommand (Element *elmt1, Element *elmt2 = 0, QUndoCommand *parent = 0);
-	unlinkElementsCommand (Element *elmt1, QList <Element *> &elmtList, QUndoCommand *parent = 0);
-	virtual ~unlinkElementsCommand();
-	//methods
-	virtual void undo();
-	virtual void redo();
-
-	private:
-	//attributes
-	Diagram *diagram_;
-	Element *element_;
-	QList <Element *> elmt_list;
-};
-
 #endif

Modified: trunk/sources/ui/linksingleelementwidget.cpp
===================================================================
--- trunk/sources/ui/linksingleelementwidget.cpp	2015-06-08 15:23:05 UTC (rev 4000)
+++ trunk/sources/ui/linksingleelementwidget.cpp	2015-06-08 18:18:35 UTC (rev 4001)
@@ -19,8 +19,8 @@
 #include "ui_linksingleelementwidget.h"
 #include "diagram.h"
 #include "elementprovider.h"
-#include "diagramcommands.h"
 #include "elementselectorwidget.h"
+#include "linkelementcommand.h"
 
 /**
  * @brief LinkSingleElementWidget::LinkSingleElementWidget
@@ -104,11 +104,18 @@
  */
 QUndoCommand *LinkSingleElementWidget::associatedUndo() const
 {
-	if (esw_->selectedElement())
-		return new LinkElementsCommand(m_element, esw_->selectedElement());
-	else if (unlink_)
-		return new unlinkElementsCommand(m_element);
+	if (esw_->selectedElement() || unlink_)
+	{
+		LinkElementCommand *undo = new LinkElementCommand(m_element);
 
+		if (esw_->selectedElement())
+			undo->setLink(esw_->selectedElement());
+		else if (unlink_)
+			undo->unlinkAll();
+
+		return undo;
+	}
+
 	return nullptr;
 }
 

Modified: trunk/sources/ui/linksingleelementwidget.ui
===================================================================
--- trunk/sources/ui/linksingleelementwidget.ui	2015-06-08 15:23:05 UTC (rev 4000)
+++ trunk/sources/ui/linksingleelementwidget.ui	2015-06-08 18:18:35 UTC (rev 4001)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>300</width>
-    <height>400</height>
+    <width>265</width>
+    <height>182</height>
    </rect>
   </property>
   <property name="windowTitle">

Modified: trunk/sources/ui/masterpropertieswidget.cpp
===================================================================
--- trunk/sources/ui/masterpropertieswidget.cpp	2015-06-08 15:23:05 UTC (rev 4000)
+++ trunk/sources/ui/masterpropertieswidget.cpp	2015-06-08 18:18:35 UTC (rev 4001)
@@ -20,9 +20,9 @@
 #include <QListWidgetItem>
 #include <diagramposition.h>
 #include <elementprovider.h>
-#include <diagramcommands.h>
 #include <diagram.h>
 #include <element.h>
+#include <linkelementcommand.h>
 
 /**
  * @brief MasterPropertiesWidget::MasterPropertiesWidget
@@ -109,43 +109,35 @@
  * If no change return nullptr.
  * @return
  */
-QUndoCommand* MasterPropertiesWidget::associatedUndo() const {
+QUndoCommand* MasterPropertiesWidget::associatedUndo() const
+{
 	QList <Element *> to_link;
 	QList <Element *> linked_ = m_element->linkedElements();
 
-	for (int i=0; i<ui->linked_list->count(); i++) {
+	for (int i=0; i<ui->linked_list->count(); i++)
 		to_link << lwi_hash[ui->linked_list->item(i)];
-	}
 
-		//If same element are find in to_link and linked, that means
-		// element are already linked, so we remove element on the two list
-		//if linked_ contains element at the end of the operation,
-		//that means this element must be unlinked from @m_element
-	foreach (Element *elmt, to_link) {
-		if(linked_.contains(elmt)) {
-			to_link.removeAll(elmt);
-			linked_.removeAll(elmt);
-		}
-	}
+		//The two list contain the same element, there is no change
+	if (to_link.size() == linked_.size())
+	{
+		bool equal = true;
 
-		// if two list, contain element, we link and unlink @m_element with corresponding
-		//undo command, and add first command for parent of the second, user see only one
-		//undo command
-	if (linked_.count() && to_link.count()) {
-		LinkElementsCommand *lec = new LinkElementsCommand(m_element, to_link);
-		new unlinkElementsCommand(m_element, linked_, lec);
-		return lec;
+		foreach(Element *elmt, to_link)
+			if (!linked_.contains(elmt))
+				equal = false;
+
+		if(equal)
+			return nullptr;
 	}
-		//Else do the single undo command corresponding to the link.
-	else if (to_link.count()) {
-		return (new LinkElementsCommand(m_element, to_link));
-	}
-	else if (linked_.count()) {
-		return (new unlinkElementsCommand(m_element, linked_));
-	}
-	else {
-		return nullptr;
-	}
+
+	LinkElementCommand *undo = new LinkElementCommand(m_element);
+
+	if (to_link.isEmpty())
+		undo->unlinkAll();
+	else
+		undo->setLink(to_link);
+
+	return undo;
 }
 
 /**

Added: trunk/sources/undocommand/linkelementcommand.cpp
===================================================================
--- trunk/sources/undocommand/linkelementcommand.cpp	                        (rev 0)
+++ trunk/sources/undocommand/linkelementcommand.cpp	2015-06-08 18:18:35 UTC (rev 4001)
@@ -0,0 +1,270 @@
+/*
+	Copyright 2006-2015 The QElectroTech Team
+	This file is part of QElectroTech.
+
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "linkelementcommand.h"
+#include "element.h"
+#include "diagram.h"
+
+/**
+ * @brief LinkElementCommand::LinkElementCommand
+ * Constructor
+ * @param element_ : element where we work the link / unlink
+ * @param parent : parent undo
+ */
+LinkElementCommand::LinkElementCommand(Element *element_, QUndoCommand *parent):
+	QUndoCommand(parent),
+	m_element(element_)
+{
+	m_linked_before = m_linked_after = m_element->linkedElements();
+	setText(QObject::tr("Éditer les référence croisé", "edite the cross reference"));
+}
+
+/**
+ * @brief LinkElementCommand::mergeWith
+ * @param other try to merge this command with other
+ * @return true if merge with success else false
+ */
+bool LinkElementCommand::mergeWith(const QUndoCommand *other)
+{
+	if (id() != other->id()) return false;
+	LinkElementCommand const *undo = static_cast<const LinkElementCommand *> (other);
+	if (m_element != undo->m_element) return false;
+	m_linked_after = undo->m_linked_after;
+	return true;
+}
+
+/**
+ * @brief LinkElementCommand::isLinkable
+ * @param element_a
+ * @param element_b
+ * @param already_linked
+ * @return true if element_a and element_b can be linked between them.
+ * There is few condition to be linked :
+ * 1- element_a and element_b must be linkable type. (Ex : A is master and B is slave 'OK', A and B is master 'KO')
+ * 2- For element type slave and report (no matter if element is 'A' or 'B'), the element must be free (not connected to an element)
+ * 3- we can override the section 2 by set already_linked to true. In this case, if slave or report is already
+ * linked to the other element ('A' or 'B') return true, but if linked to another element (not 'A' or 'B') return false
+ */
+bool LinkElementCommand::isLinkable(Element *element_a, Element *element_b, bool already_linked)
+{
+	switch(element_a->linkType())
+	{
+		case Element::Simple: return false;
+
+		case Element::NextReport:
+		{
+				//Type isn't good
+			if (element_b->linkType() != Element::PreviousReport) return false;
+				//two report is free
+			if (element_a->isFree() && element_b->isFree()) return true;
+				//Reports aren't free but are already linked between them and and already_linked is true
+			if (element_a->linkedElements().contains(element_b) && already_linked) return true;
+
+			return false;
+		}
+
+		case Element::PreviousReport:
+		{
+			//Type isn't good
+		if (element_b->linkType() != Element::NextReport) return false;
+			//two report is free
+		if (element_a->isFree() && element_b->isFree()) return true;
+			//Reports aren't free but are already linked between them and and already_linked is true
+		if (element_a->linkedElements().contains(element_b) && already_linked) return true;
+
+		return false;
+		}
+
+		case Element::Master:
+		{
+			//Type isn't good
+		if (element_b->linkType() != Element::Slave) return false;
+			//element_b is free
+		if (element_b->isFree()) return true;
+			//element_b isn't free but already linked to element_a and already_linked is true
+		if (element_a->linkedElements().contains(element_b) && already_linked) return true;
+
+		return false;
+		}
+
+		case Element::Slave:
+		{
+				//Type isn't good
+			if (element_b->linkType() != Element::Master) return false;
+				//Element_a is free
+			if (element_a->isFree()) return true;
+				//element_a isn't free but already linked to element_b and already_linked is true;
+			if (element_b->linkedElements().contains(element_a) && already_linked) return true;
+
+			return false;
+		}
+
+		case Element::Terminale: return false;
+
+		default: return false;
+	}
+}
+
+/**
+ * @brief LinkElementCommand::addLink
+ * Add elements from the list to the linked element of edited element
+ * This method do several check to know if element can be linked or not.
+ * @param element_list
+ */
+void LinkElementCommand::addLink(QList<Element *> element_list)
+{
+	setUpNewLink(element_list, false);
+}
+
+/**
+ * @brief LinkElementCommand::addLink
+ * This is an overloaded function
+ * @param element_
+ */
+void LinkElementCommand::addLink(Element *element_)
+{
+	QList<Element *> list;
+	list << element_;
+	addLink(list);
+}
+
+/**
+ * @brief LinkElementCommand::setLink
+ * Replace all linked elements of edited element by elements stored in @element_list
+ * This method do several check to know if element can be linked or not.
+ * @param element_list
+ */
+void LinkElementCommand::setLink(QList<Element *> element_list)
+{
+	m_linked_after.clear();
+	setUpNewLink(element_list, true);
+}
+
+/**
+ * @brief LinkElementCommand::setLink
+ * This is an overloaded function.
+ * @param element_
+ */
+void LinkElementCommand::setLink(Element *element_)
+{
+	QList<Element *> list;
+	list << element_;
+	setLink(list);
+}
+
+/**
+ * @brief LinkElementCommand::unlink
+ * Unlink all elements of element_list from the edited element.
+ * @param element_list
+ */
+void LinkElementCommand::unlink(QList<Element *> element_list)
+{
+	foreach(Element *elmt, element_list)
+		m_linked_after.removeAll(elmt);
+}
+
+/**
+ * @brief LinkElementCommand::unlinkAll
+ * Unlink all element of the edited element
+ */
+void LinkElementCommand::unlinkAll() {
+	m_linked_after.clear();
+}
+
+/**
+ * @brief LinkElementCommand::undo
+ * Undo this command
+ */
+void LinkElementCommand::undo()
+{
+	if(m_element->diagram()) m_element->diagram()->showMe();
+	makeLink(m_linked_before);
+	QUndoCommand::undo();
+}
+
+/**
+ * @brief LinkElementCommand::redo
+ * Redo this command
+ */
+void LinkElementCommand::redo()
+{
+	if(m_element->diagram()) m_element->diagram()->showMe();
+	makeLink(m_linked_after);
+	QUndoCommand::redo();
+}
+
+/**
+ * @brief LinkElementCommand::setUpNewLink
+ * Update the content of m_link_after with the content of @element_list.
+ * Each linkable element (know via the static method isLinkable) is added to m_linked_after
+ * @already_link is used for the static method isLinkable.
+ * @param element_list
+ * @param already_link
+ */
+void LinkElementCommand::setUpNewLink(const QList<Element *> &element_list, bool already_link)
+{
+		//m_element is a master we can connect several element to it
+		//if m_element isn't master (may be a report or slave) we can connect only one element
+	if (m_element->linkType() == Element::Master || element_list.size() == 1)
+	{
+		foreach(Element *elmt, element_list)
+			if (isLinkable(m_element, elmt, already_link))
+				m_linked_after << elmt;
+	}
+	else
+	{
+		qDebug() << "LinkElementCommand::setUpNewLink : try to link several elements to a report element or slave element,"
+					" only the first element of the list will be taken to be linked";
+		foreach(Element *elmt, element_list)
+			if (isLinkable(m_element, elmt, already_link))
+			{
+				m_linked_after << elmt;
+				return;
+			}
+	}
+}
+
+/**
+ * @brief LinkElementCommand::makeLink
+ * Make the link between m_element and element_list;
+ * This method unlink elements if needed.
+ * @param element_list
+ */
+void LinkElementCommand::makeLink(const QList<Element *> &element_list)
+{
+		//List is empty, that mean m_element must be free, so we unlink all elements
+	if (element_list.isEmpty())
+	{
+		m_element->unlinkAllElements();
+		return;
+	}
+
+		//We link all element from element_list
+	foreach(Element *elmt, element_list)
+		m_element->linkToElement(elmt);
+
+		//At this point may be there are unwanted linked elements to m_element. We must to unlink it.
+		//Elements from @element_list are wanted so we compare @element_list to current linked element of @m_element
+	QList<Element *> to_unlink = m_element->linkedElements();
+	foreach(Element *elmt, element_list)
+		to_unlink.removeAll(elmt);
+
+		//All elements stored in to_unlink is unwanted we unlink it from m_element
+	if (!to_unlink.isEmpty())
+		foreach(Element *elmt, to_unlink)
+			m_element->unlinkElement(elmt);
+}

Added: trunk/sources/undocommand/linkelementcommand.h
===================================================================
--- trunk/sources/undocommand/linkelementcommand.h	                        (rev 0)
+++ trunk/sources/undocommand/linkelementcommand.h	2015-06-08 18:18:35 UTC (rev 4001)
@@ -0,0 +1,61 @@
+/*
+	Copyright 2006-2015 The QElectroTech Team
+	This file is part of QElectroTech.
+
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef LINKELEMENTCOMMAND_H
+#define LINKELEMENTCOMMAND_H
+
+#include <QUndoCommand>
+
+class Element;
+
+/**
+ * @brief The LinkElementCommand class
+ * This undo class manage link between elements.
+ * In the same instance of this class, we can link and unlink elements from an edited element
+ * This undo class support the merge.
+ */
+class LinkElementCommand : public QUndoCommand
+{
+	public:
+		LinkElementCommand(Element *element_, QUndoCommand *parent = 0);
+
+		virtual int id() const {return 2;}
+		virtual bool mergeWith(const QUndoCommand *other);
+
+		static bool isLinkable (Element *element_a, Element *element_b, bool already_linked = false);
+
+		void addLink (QList<Element *> element_list);
+		void addLink (Element *element_);
+		void setLink (QList<Element *> element_list);
+		void setLink (Element *element_);
+		void unlink  (QList<Element *> element_list);
+		void unlinkAll ();
+
+		void undo();
+		void redo();
+
+	private:
+		void setUpNewLink (const QList<Element *> &element_list, bool already_link);
+		void makeLink (const QList <Element *> &element_list);
+
+	private:
+		Element *m_element;
+		QList<Element *> m_linked_before; //<Linked elements before this command, or when we call "undo"
+		QList<Element *> m_linked_after;  //<Linked elements after this command, or when we recall "redo"
+};
+
+#endif // LINKELEMENTCOMMAND_H


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/