1 /*
2 	Copyright 2006-2019 The QElectroTech Team
3 	This file is part of QElectroTech.
4 
5 	QElectroTech is free software: you can redistribute it and/or modify
6 	it under the terms of the GNU General Public License as published by
7 	the Free Software Foundation, either version 2 of the License, or
8 	(at your option) any later version.
9 
10 	QElectroTech is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 	GNU General Public License for more details.
14 
15 	You should have received a copy of the GNU General Public License
16 	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "polygoneditor.h"
19 #include "partpolygon.h"
20 #include "elementscene.h"
21 #include "qetmessagebox.h"
22 #include "styleeditor.h"
23 #include "QPropertyUndoCommand/qpropertyundocommand.h"
24 
25 /**
26 	Constructeur
27 	@param editor L'editeur d'element concerne
28 	@param p Le polygone a editer
29 	@param parent le Widget parent
30 */
PolygonEditor(QETElementEditor * editor,PartPolygon * p,QWidget * parent)31 PolygonEditor::PolygonEditor(QETElementEditor *editor, PartPolygon *p, QWidget *parent) :
32 	ElementItemEditor(editor, parent),
33 	part(p),
34 	points_list(this),
35 	close_polygon(tr("Polygone fermé"), this)
36 {
37 	style_ = new StyleEditor(editor);
38 
39 	// prepare la liste de points
40 	points_list.setColumnCount(2);
41 	QStringList headers;
42 	headers << tr("x") << tr("y");
43 	points_list.setHeaderLabels(headers);
44 	points_list.setRootIsDecorated(false);
45 	updateForm();
46 
47 	// layout
48 	QVBoxLayout *layout = new QVBoxLayout(this);
49 	layout -> addWidget(style_);
50 	layout -> addWidget(new QLabel(tr("Points du polygone :")));
51 	layout -> addWidget(&points_list);
52 	layout -> addWidget(&close_polygon);
53 	layout->addStretch();
54 
55 	updateForm();
56 }
57 
58 /// Destructeur
~PolygonEditor()59 PolygonEditor::~PolygonEditor() {
60 }
61 
62 /**
63 	Met a jour les points du polygone et cree un objet d'annulation
64 */
updatePolygonPoints()65 void PolygonEditor::updatePolygonPoints()
66 {
67 	if (!part) return;
68 	QPolygonF points = getPointsFromTree();
69 	if (points.count() < 2)
70 	{
71 		QET::QetMessageBox::warning(this, tr("Erreur", "message box title"), tr("Le polygone doit comporter au moins deux points.", "message box content"));
72 		return;
73 	}
74 
75 	if (points != part->polygon())
76 	{
77 		QPropertyUndoCommand *undo = new QPropertyUndoCommand(part, "polygon", part->property("polygon"), points);
78 		undo->setText(tr("Modifier un polygone"));
79 		undoStack().push(undo);
80 	}
81 }
82 
83 /**
84 	Met a jour l'etat ferme ou non du polygone
85 */
updatePolygonClosedState()86 void PolygonEditor::updatePolygonClosedState()
87 {
88 	if (!part) return;
89 	bool close = close_polygon.isChecked();
90 	if (close != part->isClosed())
91 	{
92 		QPropertyUndoCommand *undo = new QPropertyUndoCommand(part, "closed", part->property("closed"), close);
93 		undo->setText(tr("Modifier un polygone"));
94 		undoStack().push(undo);
95 	}
96 }
97 
98 /**
99 	Met a jour le formulaire d'edition
100 */
updateForm()101 void PolygonEditor::updateForm() {
102 	if (!part) return;
103 	activeConnections(false);
104 	while(points_list.takeTopLevelItem(0)) {}
105 	foreach(QPointF point, part -> polygon()) {
106 		point = part -> mapToScene(point);
107 		QStringList qsl;
108 		qsl << QString("%1").arg(point.x()) << QString("%1").arg(point.y());
109 		QTreeWidgetItem *qtwi = new QTreeWidgetItem(qsl);
110 		qtwi -> setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
111 		points_list.addTopLevelItem(qtwi);
112 	}
113 	close_polygon.setChecked(part -> isClosed());
114 	activeConnections(true);
115 }
116 
117 /**
118 	Permet de specifier a cet editeur quelle primitive il doit editer. A noter
119 	qu'un editeur peut accepter ou refuser d'editer une primitive.
120 	L'editeur de polygone acceptera d'editer la primitive new_part s'il s'agit
121 	d'un objet de la classe PartPolygon.
122 	@param new_part Nouvelle primitive a editer
123 	@return true si l'editeur a accepter d'editer la primitive, false sinon
124 */
setPart(CustomElementPart * new_part)125 bool PolygonEditor::setPart(CustomElementPart *new_part)
126 {
127 	if (!new_part)
128 	{
129 		if (part)
130 		{
131 			disconnect(part, &PartPolygon::polygonChanged, this, &PolygonEditor::updateForm);
132 			disconnect(part, &PartPolygon::closedChange, this, &PolygonEditor::updateForm);
133 		}
134 		part = nullptr;
135 		style_ -> setPart(nullptr);
136 		return(true);
137 	}
138 	if (PartPolygon *part_polygon = dynamic_cast<PartPolygon *>(new_part))
139 	{
140 		if (part == part_polygon) return true;
141 		if (part)
142 		{
143 			disconnect(part, &PartPolygon::polygonChanged, this, &PolygonEditor::updateForm);
144 			disconnect(part, &PartPolygon::closedChange, this, &PolygonEditor::updateForm);
145 		}
146 		part = part_polygon;
147 		style_ -> setPart(part);
148 		updateForm();
149 		connect(part, &PartPolygon::polygonChanged, this, &PolygonEditor::updateForm);
150 		connect(part, &PartPolygon::closedChange, this, &PolygonEditor::updateForm);
151 		return(true);
152 	}
153 	return(false);
154 }
155 
156 /**
157 	@return la primitive actuellement editee, ou 0 si ce widget n'en edite pas
158 */
currentPart() const159 CustomElementPart *PolygonEditor::currentPart() const {
160 	return(part);
161 }
162 
163 /**
164 	@return Un vecteur contenant les points composant le polygone a partir du
165 	formulaire d'edition
166 */
getPointsFromTree()167 QVector<QPointF> PolygonEditor::getPointsFromTree() {
168 	if (!part) return(QVector<QPointF>());
169 	QVector<QPointF> points;
170 	for(int i = 0 ; i < points_list.topLevelItemCount() ; ++ i) {
171 		QTreeWidgetItem *qtwi = points_list.topLevelItem(i);
172 		bool x_convert_ok, y_convert_ok;
173 		qreal x = qtwi -> text(0).toDouble(&x_convert_ok);
174 		qreal y = qtwi -> text(1).toDouble(&y_convert_ok);
175 		if (!x_convert_ok || !y_convert_ok) continue;
176 		points << part -> mapFromScene(QPointF(x, y));
177 	}
178 	return(points);
179 }
180 
181 /**
182 	@param qtwi QTreeWidgetItem a valider
183 	@param column Colonne exacte du QTreeWidgetItem a valider
184 */
validColumn(QTreeWidgetItem * qtwi,int column)185 void PolygonEditor::validColumn(QTreeWidgetItem *qtwi, int column) {
186 	bool convert_ok;
187 	qtwi -> text(column).toDouble(&convert_ok);
188 	if (convert_ok) {
189 		points_list.closePersistentEditor(qtwi, column);
190 		updatePolygonPoints();
191 	} else points_list.openPersistentEditor(qtwi, column);
192 }
193 
194 /**
195 	Active ou desactive les connexionx signaux/slots entre les widgets internes.
196 	@param active true pour activer les connexions, false pour les desactiver
197 */
activeConnections(bool active)198 void PolygonEditor::activeConnections(bool active) {
199 	if (active) {
200 		connect(&close_polygon, SIGNAL(stateChanged(int)),                   this, SLOT(updatePolygonClosedState()));
201 		connect(&points_list,   SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(validColumn(QTreeWidgetItem *, int)));
202 	} else {
203 		disconnect(&close_polygon, SIGNAL(stateChanged(int)),                   this, SLOT(updatePolygonClosedState()));
204 		disconnect(&points_list,   SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(validColumn(QTreeWidgetItem *, int)));
205 	}
206 }
207