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 "qetdiagrameditor.h"
19 #include "qetapp.h"
20 #include "diagramcontent.h"
21 #include "diagramview.h"
22 #include "diagram.h"
23 #include "qetgraphicsitem/element.h"
24 #include "elementspanelwidget.h"
25 #include "conductorpropertieswidget.h"
26 #include "qetproject.h"
27 #include "projectview.h"
28 #include "recentfiles.h"
29 #include "qeticons.h"
30 #include "qetelementeditor.h"
31 #include "qetmessagebox.h"
32 #include "qetresult.h"
33 #include "genericpanel.h"
34 #include "nomenclature.h"
35 #include "diagramfoliolist.h"
36 #include "qetshapeitem.h"
37 #include "reportproperties.h"
38 #include "diagrampropertieseditordockwidget.h"
39 #include "diagrameventaddshape.h"
40 #include "diagrameventaddimage.h"
41 #include "diagrameventaddtext.h"
42 #include "elementscollectionwidget.h"
43 #include "autonumberingdockwidget.h"
44 #include "dynamicelementtextitem.h"
45 #include "conductortextitem.h"
46 #include "undocommand/rotateselectioncommand.h"
47 #include "rotatetextscommand.h"
48 #include "diagramcommands.h"
49 #include "dialogwaiting.h"
50 #include "addelementtextcommand.h"
51 
52 #include <QMessageBox>
53 #include <QStandardPaths>
54 #include <KAutoSaveFile>
55 
56 #include "elementscollectionmodel.h"
57 
58 
59 /**
60  * @brief QETDiagramEditor::QETDiagramEditor
61  * Constructor
62  * @param files, list of files to open
63  * @param parent, parent widget
64  */
QETDiagramEditor(const QStringList & files,QWidget * parent)65 QETDiagramEditor::QETDiagramEditor(const QStringList &files, QWidget *parent) :
66 	QETMainWindow(parent),
67 	m_row_column_actions_group (this),
68 	m_selection_actions_group  (this),
69 	m_add_item_actions_group   (this),
70 	m_zoom_actions_group       (this),
71 	m_select_actions_group     (this),
72 	m_file_actions_group       (this),
73 	open_dialog_dir            (QStandardPaths::writableLocation(QStandardPaths::DesktopLocation))
74 {
75 	activeSubWindowIndex = 0;
76 
77 	QSplitter *splitter_ = new QSplitter(this);
78 	splitter_->setChildrenCollapsible(false);
79 	splitter_->setOrientation(Qt::Vertical);
80 	splitter_->addWidget(&m_workspace);
81 	splitter_->addWidget(&m_search_and_replace_widget);
82 	m_search_and_replace_widget.setHidden(true);
83 	m_search_and_replace_widget.setEditor(this);
84 	setCentralWidget(splitter_);
85 
86 		//Set object name to be retrieved by the stylesheets
87 	m_workspace.setBackground(QBrush(Qt::NoBrush));
88 	m_workspace.setObjectName("mdiarea");
89 	m_workspace.setTabsClosable(true);
90 
91 		//Set the signal mapper
92 	connect(&windowMapper, SIGNAL(mapped(QWidget *)), this, SLOT(activateWidget(QWidget *)));
93 
94 	setWindowTitle(tr("QElectroTech", "window title"));
95 	setWindowIcon(QET::Icons::QETLogo);
96 	statusBar() -> showMessage(tr("QElectroTech", "status bar message"));
97 
98 	setUpElementsPanel();
99 	setUpElementsCollectionWidget();
100 	setUpUndoStack();
101 	setUpSelectionPropertiesEditor();
102 	setUpAutonumberingWidget();
103 
104 	setUpActions();
105 	setUpToolBar();
106 	setUpMenu();
107 
108 	tabifyDockWidget(qdw_undo, qdw_pa);
109 
110 		//By default the windows is maximised
111 	setMinimumSize(QSize(500, 350));
112 	setWindowState(Qt::WindowMaximized);
113 
114 	connect (&m_workspace,                SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(subWindowActivated(QMdiSubWindow*)));
115 	connect (QApplication::clipboard(), SIGNAL(dataChanged()),                       this, SLOT(slot_updatePasteAction()));
116 
117 	readSettings();
118 	show();
119 
120 		//If valid file path is given as arguments
121 	uint opened_projects = 0;
122 	if (files.count())
123 	{
124 			//So we open this files
125 		foreach(QString file, files)
126 			if (openAndAddProject(file))
127 				++ opened_projects;
128 	}
129 
130 	slot_updateActions();
131 }
132 
133 /**
134 	Destructeur
135 */
~QETDiagramEditor()136 QETDiagramEditor::~QETDiagramEditor() {
137 }
138 
139 /**
140  * @brief QETDiagramEditor::setUpElementsPanel
141  * Setup the element panel and element panel widget
142  */
setUpElementsPanel()143 void QETDiagramEditor::setUpElementsPanel() {
144 	//Add the element panel as a QDockWidget
145 	qdw_pa = new QDockWidget(tr("Projets", "dock title"), this);
146 
147 	qdw_pa -> setObjectName   ("projects panel");
148 	qdw_pa -> setAllowedAreas (Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
149 	qdw_pa -> setFeatures     (QDockWidget::AllDockWidgetFeatures);
150 	qdw_pa -> setMinimumWidth (160);
151 	qdw_pa -> setWidget       (pa = new ElementsPanelWidget(qdw_pa));
152 
153 	addDockWidget(Qt::LeftDockWidgetArea, qdw_pa);
154 
155 	connect(pa, SIGNAL(requestForProject                  (QETProject *)), this, SLOT(activateProject(QETProject *)));
156 	connect(pa, SIGNAL(requestForProjectClosing           (QETProject *)), this, SLOT(closeProject(QETProject *)));
157 	connect(pa, SIGNAL(requestForProjectPropertiesEdition (QETProject *)), this, SLOT(editProjectProperties(QETProject *)));
158 	connect(pa, SIGNAL(requestForNewDiagram               (QETProject *)), this, SLOT(addDiagramToProject(QETProject *)));
159 
160 	connect(pa, SIGNAL(requestForDiagram                  (Diagram *)), this, SLOT(activateDiagram(Diagram *)));
161 	connect(pa, SIGNAL(requestForDiagramPropertiesEdition (Diagram *)), this, SLOT(editDiagramProperties(Diagram *)));
162 	connect(pa, SIGNAL(requestForDiagramDeletion          (Diagram *)), this, SLOT(removeDiagram(Diagram *)));
163 	connect(pa, SIGNAL(requestForDiagramMoveUp            (Diagram *)), this, SLOT(moveDiagramUp(Diagram *)));
164 	connect(pa, SIGNAL(requestForDiagramMoveDown          (Diagram *)), this, SLOT(moveDiagramDown(Diagram *)));
165 	connect(pa, SIGNAL(requestForDiagramMoveUpTop         (Diagram *)), this, SLOT(moveDiagramUpTop(Diagram *)));
166 	connect(pa, SIGNAL(requestForDiagramMoveUpx10         (Diagram *)), this, SLOT(moveDiagramUpx10(Diagram *)));
167 	connect(pa, SIGNAL(requestForDiagramMoveDownx10       (Diagram *)), this, SLOT(moveDiagramDownx10(Diagram *)));
168 }
169 
170 /**
171  * @brief QETDiagramEditor::setUpElementsCollectionWidget
172  * Set up the dock widget of element collection
173  */
setUpElementsCollectionWidget()174 void QETDiagramEditor::setUpElementsCollectionWidget()
175 {
176 	m_qdw_elmt_collection = new QDockWidget(tr("Collections"), this);
177 	m_qdw_elmt_collection->setObjectName("elements_collection_widget");
178 	m_qdw_elmt_collection->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
179 	m_qdw_elmt_collection->setFeatures(QDockWidget::AllDockWidgetFeatures);
180 
181 	m_element_collection_widget = new ElementsCollectionWidget(m_qdw_elmt_collection);
182 	m_qdw_elmt_collection->setWidget(m_element_collection_widget);
183 	m_element_collection_widget->expandFirstItems();
184 
185 	addDockWidget(Qt::RightDockWidgetArea, m_qdw_elmt_collection);
186 }
187 
188 /**
189  * @brief QETDiagramEditor::setUpUndoStack
190  * Setup the undostack and undo stack widget
191  */
setUpUndoStack()192 void QETDiagramEditor::setUpUndoStack() {
193 
194 	QUndoView *undo_view = new QUndoView(&undo_group, this);
195 
196 	undo_view -> setEmptyLabel (tr("Aucune modification"));
197 	undo_view -> setStatusTip  (tr("Cliquez sur une action pour revenir en arrière dans l'édition de votre schéma", "Status tip"));
198 	undo_view -> setWhatsThis  (tr("Ce panneau liste les différentes actions effectuées sur le folio courant. Cliquer sur une action permet de revenir à l'état du schéma juste après son application.", "\"What's this\" tip"));
199 
200 	qdw_undo  = new QDockWidget(tr("Annulations", "dock title"), this);
201 	qdw_undo -> setObjectName("diagram_undo");
202 
203 	qdw_undo -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
204 	qdw_undo -> setFeatures(QDockWidget::AllDockWidgetFeatures);
205 	qdw_undo -> setMinimumWidth(160);
206 	qdw_undo -> setWidget(undo_view);
207 
208 	addDockWidget(Qt::LeftDockWidgetArea, qdw_undo);
209 }
210 
211 /**
212  * @brief QETDiagramEditor::setUpSelectionPropertiesEditor
213  * Setup the dock for edit the current selection
214  */
setUpSelectionPropertiesEditor()215 void QETDiagramEditor::setUpSelectionPropertiesEditor()
216 {
217 	m_selection_properties_editor = new DiagramPropertiesEditorDockWidget(this);
218 	m_selection_properties_editor -> setObjectName("diagram_properties_editor_dock_widget");
219 	addDockWidget(Qt::RightDockWidgetArea, m_selection_properties_editor);
220 }
221 
222 /**
223  * @brief QETDiagramEditor::setUpAutonumberingWidget
224  * Setup the dock for AutoNumbering Selection
225  */
setUpAutonumberingWidget()226 void QETDiagramEditor::setUpAutonumberingWidget()
227 {
228 	m_autonumbering_dock = new AutoNumberingDockWidget(this);
229 	m_autonumbering_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
230 	m_autonumbering_dock -> setFeatures(QDockWidget::AllDockWidgetFeatures);
231 	addDockWidget(Qt::RightDockWidgetArea, m_autonumbering_dock);
232 }
233 
234 /**
235  * @brief QETDiagramEditor::setUpActions
236  * Set up all Qaction
237  */
setUpActions()238 void QETDiagramEditor::setUpActions()
239 {
240 		//Export to another file type (jpeg, dxf etc...)
241 	m_export_diagram = new QAction(QET::Icons::DocumentExport,  tr("E&xporter"), this);
242 	m_export_diagram->setShortcut(QKeySequence(tr("Ctrl+Shift+X")));
243 	m_export_diagram->setStatusTip(tr("Exporte le folio courant dans un autre format", "status bar tip"));
244 	connect(m_export_diagram, &QAction::triggered, [this]() {
245 		ProjectView *current_project = currentProjectView();
246 		if (current_project) {
247 			current_project -> exportProject();
248 		}
249 	});
250 
251 		//Print
252 	m_print = new QAction(QET::Icons::DocumentPrint,   tr("Imprimer"),  this);
253 	m_print->setShortcut(QKeySequence(QKeySequence::Print));
254 	m_print->setStatusTip(tr("Imprime un ou plusieurs folios du projet courant", "status bar tip"));
255 	connect(m_print, &QAction::triggered, [this]() {
256 		ProjectView *current_project = currentProjectView();
257 		if (current_project) {
258 			current_project -> printProject();
259 		}
260 	});
261 
262 		//Quit editor
263 	m_quit_editor = new QAction(QET::Icons::ApplicationExit, tr("&Quitter"),  this);
264 	m_quit_editor->setShortcut(QKeySequence(tr("Ctrl+Q")));
265 	m_quit_editor->setStatusTip(tr("Ferme l'application QElectroTech", "status bar tip"));
266 	connect(m_quit_editor, &QAction::triggered, this, &QETDiagramEditor::close);
267 
268 		//Undo
269 	undo = undo_group.createUndoAction(this, tr("Annuler"));
270 	undo->setIcon(QET::Icons::EditUndo);
271 	undo->setShortcut(QKeySequence::Undo);
272 	undo->setStatusTip(tr("Annule l'action précédente", "status bar tip"));
273 		//Redo
274 	redo = undo_group.createRedoAction(this, tr("Refaire"));
275 	redo->setIcon(QET::Icons::EditRedo);
276 	redo->setShortcut(QKeySequence::Redo);
277 	redo->setStatusTip(tr("Restaure l'action annulée", "status bar tip"));
278 
279 		//cut copy past
280 	m_cut   = new QAction(QET::Icons::EditCut,   tr("Co&uper"), this);
281 	m_copy  = new QAction(QET::Icons::EditCopy,  tr("Cop&ier"), this);
282 	m_paste = new QAction(QET::Icons::EditPaste, tr("C&oller"), this);
283 
284 	m_cut   -> setShortcut(QKeySequence::Cut);
285 	m_copy  -> setShortcut(QKeySequence::Copy);
286 	m_paste -> setShortcut(QKeySequence::Paste);
287 
288 	m_cut   -> setStatusTip(tr("Transfère les éléments sélectionnés dans le presse-papier", "status bar tip"));
289 	m_copy  -> setStatusTip(tr("Copie les éléments sélectionnés dans le presse-papier", "status bar tip"));
290 	m_paste -> setStatusTip(tr("Place les éléments du presse-papier sur le folio", "status bar tip"));
291 
292 	connect(m_cut, &QAction::triggered, [this]() {
293 		if (currentDiagramView())
294 			currentDiagramView()->cut();
295 	});
296 	connect(m_copy, &QAction::triggered, [this]() {
297 		if (currentDiagramView())
298 			currentDiagramView()->copy();
299 	});
300 	connect(m_paste, &QAction::triggered, [this]() {
301 		if(currentDiagramView())
302 			currentDiagramView()->paste();
303 	});
304 
305 		//Reset conductor path
306 	m_conductor_reset = new QAction(QET::Icons::ConductorSettings,     tr("Réinitialiser les conducteurs"),        this);
307 	m_conductor_reset->setShortcut( QKeySequence( tr("Ctrl+K")		) );
308 	m_conductor_reset->setStatusTip(tr("Recalcule les chemins des conducteurs sans tenir compte des modifications", "status bar tip"));
309 	connect(m_conductor_reset, &QAction::triggered, [this]() {
310 		if (DiagramView *dv = currentDiagramView())
311 			dv->resetConductors();
312 	});
313 
314 		//AutoConductor
315 	m_auto_conductor = new QAction   (QET::Icons::Autoconnect, tr("Création automatique de conducteur(s)","Tool tip of auto conductor"), this);
316 	m_auto_conductor->setStatusTip (tr("Utiliser la création automatique de conducteur(s) quand cela est possible", "Status tip of auto conductor"));
317 	m_auto_conductor->setCheckable (true);
318 	connect(m_auto_conductor, &QAction::triggered, [this](bool ac) {
319 		if (ProjectView *pv = currentProjectView())
320 			pv->project()->setAutoConductor(ac);
321 	});
322 
323 		//Switch background color
324 	m_grey_background = new QAction   (QET::Icons::DiagramBg, tr("Couleur de fond blanc/gris","Tool tip of white/grey background button"), this);
325 	m_grey_background -> setStatusTip (tr("Affiche la couleur de fond du folio en blanc ou en gris", "Status tip of white/grey background button"));
326 	m_grey_background -> setCheckable (true);
327 	connect (m_grey_background, &QAction::triggered, [this](bool checked) {
328 		Diagram::background_color = checked ? Qt::darkGray : Qt::white;
329 		if (this->currentDiagramView() &&  this->currentDiagramView()->diagram())
330 			this->currentDiagramView()->diagram()->update();
331 	});
332 
333 		//Draw or not the background grid
334 	m_draw_grid = new QAction ( QET::Icons::Grid, tr("Afficher la grille"), this);
335 	m_draw_grid->setStatusTip(tr("Affiche ou masque la grille des folios"));
336 	m_draw_grid->setCheckable(true);
337 	m_draw_grid->setChecked(true);
338 	connect(m_draw_grid, &QAction::triggered, [this](bool checked) {
339 		foreach (ProjectView *prjv, this->openedProjects())
340 			foreach (Diagram *d, prjv->project()->diagrams()) {
341 				d->setDisplayGrid(checked);
342 				d->update();
343 			}
344 	});
345 
346 		//Edit current diagram properties
347 	m_edit_diagram_properties = new QAction(QET::Icons::DialogInformation, tr("Propriétés du folio"), this);
348 	m_edit_diagram_properties->setShortcut( QKeySequence( tr("Ctrl+L")));
349 	m_edit_diagram_properties     -> setStatusTip(tr("Édite les propriétés du folio (dimensions, informations du cartouche, propriétés des conducteurs...)", "status bar tip"));
350 	connect(m_edit_diagram_properties, &QAction::triggered, [this]() {
351 		if (ProjectView *project_view = currentProjectView())
352 		{
353 			activateProject(project_view);
354 			project_view->editCurrentDiagramProperties();
355 		}
356 	});
357 
358 		//Edit current project properties
359 	m_project_edit_properties = new QAction(QET::Icons::ProjectProperties, tr("Propriétés du projet"), this);
360 	connect(m_project_edit_properties, &QAction::triggered, [this]() {
361 		editProjectProperties(currentProjectView());
362 	});
363 
364 		//Add new folio to current project
365 	m_project_add_diagram = new QAction(QET::Icons::DiagramAdd, tr("Ajouter un folio"), this);
366 	m_project_add_diagram->setShortcut(QKeySequence(tr("Ctrl+T")));
367 	connect(m_project_add_diagram, &QAction::triggered, [this]() {
368 		if (ProjectView *current_project = currentProjectView()) {
369 			current_project->addNewDiagram();
370 		}
371 	});
372 
373 		//Remove current folio from current project
374 	m_remove_diagram_from_project = new QAction(QET::Icons::DiagramDelete, tr("Supprimer le folio"), this);
375 	connect(m_remove_diagram_from_project, &QAction::triggered, this, &QETDiagramEditor::removeDiagramFromProject);
376 
377 		//Clean the current project
378 	m_clean_project         = new QAction(QET::Icons::EditClear,             tr("Nettoyer le projet"),                   this);
379 	connect(m_clean_project, &QAction::triggered, [this]() {
380 		if (ProjectView *current_project = currentProjectView()) {
381 			if (current_project->cleanProject()) {
382 				pa -> reloadAndFilter();
383 			}
384 		}
385 	});
386 
387 		//Add folio list to current project
388 	m_project_folio_list = new QAction(QET::Icons::TableOfContent, tr("Ajouter un sommaire"), this);
389 	connect(m_project_folio_list, &QAction::triggered, [this]() {
390 		if (ProjectView *current_project = currentProjectView()) {
391 			current_project->addNewDiagramFolioList();
392 		}
393 	});
394 
395 		//Export nomenclature to CSV
396 	m_project_nomenclature = new QAction(QET::Icons::DocumentSpreadsheet, tr("Exporter une nomenclature"), this);
397 	connect(m_project_nomenclature, &QAction::triggered, [this]() {
398 		nomenclature nomencl(currentProjectView()->project(), this);
399 		nomencl.saveToCSVFile();
400 	});
401 
402 		//Lauch the plugin of terminal generator
403 	m_project_terminalBloc = new QAction(QET::Icons::TerminalStrip, tr("Lancer le plugin de création de borniers"), this);
404 	connect(m_project_terminalBloc, &QAction::triggered, this, &QETDiagramEditor::generateTerminalBlock);
405 
406 		//MDI view style
407 	m_tabbed_view_mode = new QAction(tr("en utilisant des onglets"), this);
408 	m_tabbed_view_mode->setStatusTip(tr("Présente les différents projets ouverts des onglets", "status bar tip"));
409 	m_tabbed_view_mode->setCheckable(true);
410 	connect(m_tabbed_view_mode, &QAction::triggered, this, &QETDiagramEditor::setTabbedMode);
411 
412 	m_windowed_view_mode = new QAction(tr("en utilisant des fenêtres"), this);
413 	m_windowed_view_mode->setStatusTip(tr("Présente les différents projets ouverts dans des sous-fenêtres", "status bar tip"));
414 	m_windowed_view_mode->setCheckable(true);
415 	connect(m_windowed_view_mode, &QAction::triggered, this, &QETDiagramEditor::setWindowedMode);
416 
417 	m_group_view_mode = new QActionGroup(this);
418 	m_group_view_mode -> addAction(m_windowed_view_mode);
419 	m_group_view_mode -> addAction(m_tabbed_view_mode);
420 	m_group_view_mode -> setExclusive(true);
421 
422 	m_tile_window = new QAction(tr("&Mosaïque"), this);
423 	m_tile_window->setStatusTip(tr("Dispose les fenêtres en mosaïque", "status bar tip"));
424 	connect(m_tile_window, &QAction::triggered, &m_workspace, &QMdiArea::tileSubWindows);
425 
426 	m_cascade_window = new QAction(tr("&Cascade"), this);
427 	m_cascade_window->setStatusTip(tr("Dispose les fenêtres en cascade", "status bar tip"));
428 	connect(m_cascade_window, &QAction::triggered, &m_workspace, &QMdiArea::cascadeSubWindows);
429 
430 		//Switch selection/view mode
431 	m_mode_selection = new QAction(QET::Icons::PartSelect, tr("Mode Selection"), this);
432 	m_mode_selection->setStatusTip(tr("Permet de sélectionner les éléments", "status bar tip"));
433 	m_mode_selection->setCheckable(true);
434 	m_mode_selection->setChecked(true);
435 	connect(m_mode_selection, &QAction::triggered, [this]() {
436 		if (ProjectView *pv = currentProjectView()) {
437 			for (DiagramView *dv : pv->diagram_views()) {
438 				dv->setSelectionMode();
439 			}
440 		}
441 	});
442 
443 	m_mode_visualise = new QAction(QET::Icons::ViewMove, tr("Mode Visualisation"), this);
444 	m_mode_visualise->setStatusTip(tr("Permet de visualiser le folio sans pouvoir le modifier", "status bar tip"));
445 	m_mode_visualise->setCheckable(true);
446 	connect(m_mode_visualise, &QAction::triggered, [this]() {
447 		if (ProjectView *pv = currentProjectView()) {
448 			for(DiagramView *dv : pv->diagram_views()) {
449 				dv->setVisualisationMode();
450 			}
451 		}
452 	});
453 
454 	grp_visu_sel = new QActionGroup(this);
455 	grp_visu_sel->addAction(m_mode_selection);
456 	grp_visu_sel->addAction(m_mode_visualise);
457 	grp_visu_sel->setExclusive(true);
458 
459 		//Navigate next/previous project
460 	m_next_window = new QAction(tr("Projet suivant"), this);
461 	m_next_window->setShortcut(QKeySequence::NextChild);
462 	m_next_window->setStatusTip(tr("Active le projet suivant", "status bar tip"));
463 	connect(m_next_window, &QAction::triggered, &m_workspace, &QMdiArea::activateNextSubWindow);
464 
465 	m_previous_window = new QAction(tr("Projet précédent"), this);
466 	m_previous_window->setShortcut(QKeySequence::PreviousChild);
467 	m_previous_window->setStatusTip(tr("Active le projet précédent", "status bar tip"));
468 	connect(m_previous_window, &QAction::triggered, &m_workspace, &QMdiArea::activatePreviousSubWindow);
469 
470 		//Files action
471 	QAction *new_file  = m_file_actions_group.addAction(QET::Icons::ProjectNew,     tr("&Nouveau"));
472 	QAction *open_file = m_file_actions_group.addAction(QET::Icons::DocumentOpen,   tr("&Ouvrir"));
473 	m_save_file          = m_file_actions_group.addAction(QET::Icons::DocumentSave,   tr("&Enregistrer"));
474 	m_save_file_as       = m_file_actions_group.addAction(QET::Icons::DocumentSaveAs, tr("Enregistrer sous"));
475 	m_close_file       = m_file_actions_group.addAction(QET::Icons::ProjectClose,   tr("&Fermer"));
476 
477 	new_file     ->setShortcut(QKeySequence::New);
478 	open_file    ->setShortcut(QKeySequence::Open);
479 	m_close_file ->setShortcut(QKeySequence::Close);
480 	m_save_file    ->setShortcut(QKeySequence::Save);
481 
482 	new_file     ->setStatusTip( tr("Crée un nouveau projet", "status bar tip")								 );
483 	open_file    ->setStatusTip( tr("Ouvre un projet existant", "status bar tip")								 );
484 	m_close_file ->setStatusTip( tr("Ferme le projet courant", "status bar tip")								 );
485 	m_save_file    ->setStatusTip( tr("Enregistre le projet courant et tous ses folios", "status bar tip")		 );
486 	m_save_file_as ->setStatusTip( tr("Enregistre le projet courant avec un autre nom de fichier", "status bar tip") );
487 
488 	connect(m_save_file_as, &QAction::triggered, this, &QETDiagramEditor::saveAs);
489 	connect(m_save_file,    &QAction::triggered, this, &QETDiagramEditor::save);
490 	connect(new_file,       &QAction::triggered, this, &QETDiagramEditor::newProject);
491 	connect(open_file,      &QAction::triggered, this, &QETDiagramEditor::openProject);
492 	connect(m_close_file,   &QAction::triggered, [this]() {
493 		if (ProjectView *project_view = currentProjectView()) {
494 			closeProject(project_view);
495 		}
496 	});
497 
498 		//Rows and Columns
499 	QAction *add_column    = m_row_column_actions_group.addAction( QET::Icons::EditTableInsertColumnRight, tr("Ajouter une colonne") );
500 	QAction *remove_column = m_row_column_actions_group.addAction( QET::Icons::EditTableDeleteColumn,      tr("Enlever une colonne") );
501 	QAction *add_row       = m_row_column_actions_group.addAction( QET::Icons::EditTableInsertRowUnder,    tr("Ajouter une ligne", "Add row") );
502 	QAction *remove_row    = m_row_column_actions_group.addAction( QET::Icons::EditTableDeleteRow,         tr("Enlever une ligne","Remove row") );
503 
504 	add_column    -> setStatusTip( tr("Ajoute une colonne au folio", "status bar tip"));
505 	remove_column -> setStatusTip( tr("Enlève une colonne au folio", "status bar tip"));
506 	add_row       -> setStatusTip( tr("Agrandit le folio en hauteur", "status bar tip"));
507 	remove_row    -> setStatusTip( tr("Rétrécit le folio en hauteur", "status bar tip"));
508 
509 	add_column   ->setData("add_column");
510 	remove_column->setData("remove_column");
511 	add_row      ->setData("add_row");
512 	remove_row   ->setData("remove_row");
513 
514 	connect(&m_row_column_actions_group, &QActionGroup::triggered, this, &QETDiagramEditor::rowColumnGroupTriggered);
515 
516 		//Selections Actions (related to a selected item)
517 	m_delete_selection    = m_selection_actions_group.addAction( QET::Icons::EditDelete,        tr("Supprimer")                 );
518 	m_rotate_selection     = m_selection_actions_group.addAction( QET::Icons::TransformRotate,   tr("Pivoter")                   );
519 	m_rotate_texts         = m_selection_actions_group.addAction( QET::Icons::ObjectRotateRight, tr("Orienter les textes")       );
520 	m_find_element         = m_selection_actions_group.addAction( QET::Icons::ZoomDraw,          tr("Retrouver dans le panel")   );
521 	m_edit_selection       = m_selection_actions_group.addAction( QET::Icons::ElementEdit,       tr("Éditer l'item sélectionné") );
522 	m_group_selected_texts = m_selection_actions_group.addAction(QET::Icons::textGroup,       tr("Grouper les textes sélectionnés"));
523 
524 	m_delete_selection->setShortcut(QKeySequence::Delete);
525 	m_rotate_selection->setShortcut(QKeySequence( tr("Space")));
526 	m_rotate_texts    ->setShortcut(QKeySequence( tr("Ctrl+Space")));
527 	m_edit_selection  ->setShortcut(QKeySequence( tr("Ctrl+E")));
528 
529 	m_delete_selection->setStatusTip( tr("Enlève les éléments sélectionnés du folio", "status bar tip"));
530 	m_rotate_selection->setStatusTip( tr("Pivote les éléments et textes sélectionnés", "status bar tip"));
531 	m_rotate_texts    ->setStatusTip( tr("Pivote les textes sélectionnés à un angle précis", "status bar tip"));
532 	m_find_element    ->setStatusTip( tr("Retrouve l'élément sélectionné dans le panel", "status bar tip"));
533 
534 	m_delete_selection    ->setData("delete_selection");
535 	m_rotate_selection    ->setData("rotate_selection");
536 	m_rotate_texts        ->setData("rotate_selected_text");
537 	m_find_element        ->setData("find_selected_element");
538 	m_edit_selection      ->setData("edit_selected_element");
539 	m_group_selected_texts->setData("group_selected_texts");
540 
541 	connect(&m_selection_actions_group, &QActionGroup::triggered, this, &QETDiagramEditor::selectionGroupTriggered);
542 
543 		//Select Action
544 	QAction *select_all     = m_select_actions_group.addAction( QET::Icons::EditSelectAll,      tr("Tout sélectionner") );
545 	QAction *select_nothing = m_select_actions_group.addAction( QET::Icons::EditSelectNone,     tr("Désélectionner tout") );
546 	QAction *select_invert  = m_select_actions_group.addAction( QET::Icons::EditSelectInvert,   tr("Inverser la sélection") );
547 
548 	select_all    ->setShortcut(QKeySequence::SelectAll);
549 	select_nothing->setShortcut(QKeySequence::Deselect);
550 	select_invert ->setShortcut(QKeySequence( tr("Ctrl+I")));
551 
552 	select_all    ->setStatusTip( tr("Sélectionne tous les éléments du folio", "status bar tip")																	  );
553 	select_nothing->setStatusTip( tr("Désélectionne tous les éléments du folio", "status bar tip")															  );
554 	select_invert ->setStatusTip( tr("Désélectionne les éléments sélectionnés et sélectionne les éléments non sélectionnés", "status bar tip") );
555 
556 	select_all    ->setData("select_all");
557 	select_nothing->setData("deselect");
558 	select_invert ->setData("invert_selection");
559 
560 	connect(&m_select_actions_group, &QActionGroup::triggered, this, &QETDiagramEditor::selectGroupTriggered);
561 
562 		//Zoom actions
563 	QAction *zoom_in      = m_zoom_actions_group.addAction( QET::Icons::ZoomIn,       tr("Zoom avant"));
564 	QAction *zoom_out     = m_zoom_actions_group.addAction( QET::Icons::ZoomOut,      tr("Zoom arrière"));
565 	QAction *zoom_content = m_zoom_actions_group.addAction( QET::Icons::ZoomDraw,     tr("Zoom sur le contenu"));
566 	QAction *zoom_fit     = m_zoom_actions_group.addAction( QET::Icons::ZoomFitBest,  tr("Zoom adapté"));
567 	QAction *zoom_reset   = m_zoom_actions_group.addAction( QET::Icons::ZoomOriginal, tr("Pas de zoom"));
568 	m_zoom_action_toolBar << zoom_content << zoom_fit << zoom_reset;
569 
570 	zoom_in     ->setShortcut(QKeySequence::ZoomIn);
571 	zoom_out    ->setShortcut(QKeySequence::ZoomOut);
572 	zoom_content->setShortcut(QKeySequence( tr("Ctrl+8")));
573 	zoom_fit    ->setShortcut(QKeySequence( tr("Ctrl+9")));
574 	zoom_reset  ->setShortcut(QKeySequence( tr("Ctrl+0")));
575 
576 	zoom_in     ->setStatusTip(tr("Agrandit le folio", "status bar tip"));
577 	zoom_out    ->setStatusTip(tr("Rétrécit le folio", "status bar tip"));
578 	zoom_content->setStatusTip(tr("Adapte le zoom de façon à afficher tout le contenu du folio indépendamment du cadre"));
579 	zoom_fit    ->setStatusTip(tr("Adapte le zoom exactement sur le cadre du folio", "status bar tip"));
580 	zoom_reset  ->setStatusTip(tr("Restaure le zoom par défaut", "status bar tip"));
581 
582 	zoom_in     ->setData("zoom_in");
583 	zoom_out    ->setData("zoom_out");
584 	zoom_content->setData("zoom_content");
585 	zoom_fit    ->setData("zoom_fit");
586 	zoom_reset  ->setData("zoom_reset");
587 
588 	connect(&m_zoom_actions_group, &QActionGroup::triggered, this, &QETDiagramEditor::zoomGroupTriggered);
589 
590 		//Adding action (add text, image, shape...)
591 	QAction *add_text      = m_add_item_actions_group.addAction(QET::Icons::PartTextField, tr("Ajouter un champ de texte"));
592 	QAction *add_image	   = m_add_item_actions_group.addAction(QET::Icons::adding_image,  tr("Ajouter une image"));
593 	QAction *add_line	   = m_add_item_actions_group.addAction(QET::Icons::PartLine,      tr("Ajouter une ligne", "Draw line"));
594 	QAction *add_rectangle = m_add_item_actions_group.addAction(QET::Icons::PartRectangle, tr("Ajouter un rectangle"));
595 	QAction *add_ellipse   = m_add_item_actions_group.addAction(QET::Icons::PartEllipse,   tr("Ajouter une ellipse"));
596 	QAction *add_polyline  = m_add_item_actions_group.addAction(QET::Icons::PartPolygon,   tr("Ajouter une polyligne"));
597 
598 	add_text     ->setStatusTip(tr("Ajoute un champ de texte sur le folio actuel"));
599 	add_image    ->setStatusTip(tr("Ajoute une image sur le folio actuel"));
600 	add_line     ->setStatusTip(tr("Ajoute une ligne sur le folio actuel"));
601 	add_rectangle->setStatusTip(tr("Ajoute un rectangle sur le folio actuel"));
602 	add_ellipse  ->setStatusTip(tr("Ajoute une ellipse sur le folio actuel"));
603 	add_polyline ->setStatusTip(tr("Ajoute une polyligne sur le folio actuel"));
604 
605 	add_text     ->setData("text");
606 	add_image    ->setData("image");
607 	add_line     ->setData("line");
608 	add_rectangle->setData("rectangle");
609 	add_ellipse  ->setData("ellipse");
610 	add_polyline ->setData("polyline");
611 
612 	for(QAction *action : m_add_item_actions_group.actions()) {
613 		action->setCheckable(true);
614 	}
615 	connect(&m_add_item_actions_group, &QActionGroup::triggered, this, &QETDiagramEditor::addItemGroupTriggered);
616 
617 		//Depth action
618 	m_depth_action_group = QET::depthActionGroup(this);
619 	m_depth_action_group->setDisabled(true);
620 
621 	connect(m_depth_action_group, &QActionGroup::triggered, [this](QAction *action) {
622 		this->currentDiagramView()->diagram()->changeZValue(action->data().value<QET::DepthOption>());
623 	});
624 
625 	m_find = new QAction(tr("Chercher/remplacer"), this);
626 	m_find->setShortcut(QKeySequence::Find);
627 	connect(m_find, &QAction::triggered, [this]() {
628 		this->m_search_and_replace_widget.setHidden(!m_search_and_replace_widget.isHidden());
629 	});
630 }
631 
632 /**
633  * @brief QETDiagramEditor::setUpToolBar
634  */
setUpToolBar()635 void QETDiagramEditor::setUpToolBar()
636 {
637 	main_tool_bar = new QToolBar(tr("Outils"), this);
638 	main_tool_bar -> setObjectName("toolbar");
639 
640 	view_tool_bar = new QToolBar(tr("Affichage"), this);
641 	view_tool_bar -> setObjectName("display");
642 
643 	diagram_tool_bar = new QToolBar(tr("Schéma"), this);
644 	diagram_tool_bar -> setObjectName("diagram");
645 
646 	main_tool_bar -> addActions(m_file_actions_group.actions());
647 	main_tool_bar -> addAction(m_print);
648 	main_tool_bar -> addSeparator();
649 	main_tool_bar -> addAction(undo);
650 	main_tool_bar -> addAction(redo);
651 	main_tool_bar -> addSeparator();
652 	main_tool_bar -> addAction(m_cut);
653 	main_tool_bar -> addAction(m_copy);
654 	main_tool_bar -> addAction(m_paste);
655 	main_tool_bar -> addSeparator();
656 	main_tool_bar -> addAction(m_delete_selection);
657 	main_tool_bar -> addAction(m_rotate_selection);
658 
659 	// Modes selection / visualisation et zoom
660 	view_tool_bar -> addAction(m_mode_selection);
661 	view_tool_bar -> addAction(m_mode_visualise);
662 	view_tool_bar -> addSeparator();
663 	view_tool_bar -> addAction(m_draw_grid);
664 	view_tool_bar -> addAction (m_grey_background);
665 	view_tool_bar -> addSeparator();
666 	view_tool_bar -> addActions(m_zoom_action_toolBar);
667 
668 	diagram_tool_bar -> addAction (m_edit_diagram_properties);
669 	diagram_tool_bar -> addAction (m_conductor_reset);
670 	diagram_tool_bar -> addAction (m_auto_conductor);
671 
672 	m_add_item_tool_bar = new QToolBar(tr("Ajouter"), this);
673 	m_add_item_tool_bar->setObjectName("adding");
674 	m_add_item_tool_bar->addActions(m_add_item_actions_group.actions());
675 
676 	m_depth_tool_bar = new QToolBar(tr("Profondeur", "toolbar title"));
677 	m_depth_tool_bar->setObjectName("diagram_depth_toolbar");
678 	m_depth_tool_bar->addActions(m_depth_action_group->actions());
679 
680 	addToolBar(Qt::TopToolBarArea, main_tool_bar);
681 	addToolBar(Qt::TopToolBarArea, view_tool_bar);
682 	addToolBar(Qt::TopToolBarArea, diagram_tool_bar);
683 	addToolBar(Qt::TopToolBarArea, m_add_item_tool_bar);
684 	addToolBar(Qt::TopToolBarArea, m_depth_tool_bar);
685 }
686 
687 /**
688  * @brief QETDiagramEditor::setUpMenu
689  */
setUpMenu()690 void QETDiagramEditor::setUpMenu() {
691 
692 	QMenu *menu_fichier   = new QMenu(tr("&Fichier"));
693 	QMenu *menu_edition   = new QMenu(tr("&Édition"));
694 	QMenu *menu_project   = new QMenu(tr("&Projet"));
695 	QMenu *menu_affichage = new QMenu(tr("Afficha&ge"));
696 	//QMenu *menu_outils    = new QMenu(tr("O&utils"));
697 	windows_menu          = new QMenu(tr("Fe&nêtres"));
698 
699 	insertMenu(settings_menu_, menu_fichier);
700 	insertMenu(settings_menu_, menu_edition);
701 	insertMenu(settings_menu_, menu_project);
702 	insertMenu(settings_menu_, menu_affichage);
703 	insertMenu(help_menu_, windows_menu);
704 
705 	// File menu
706 	QMenu *recentfile = menu_fichier -> addMenu(QET::Icons::DocumentOpenRecent, tr("&Récemment ouverts"));
707 	recentfile->addActions(QETApp::projectsRecentFiles()->menu()->actions());
708 	connect(QETApp::projectsRecentFiles(), SIGNAL(fileOpeningRequested(const QString &)), this, SLOT(openRecentFile(const QString &)));
709 	menu_fichier -> addActions(m_file_actions_group.actions());
710 	menu_fichier -> addSeparator();
711 	//menu_fichier -> addAction(import_diagram);
712 	menu_fichier -> addAction(m_export_diagram);
713 	//menu_fichier -> addSeparator();
714 	menu_fichier -> addAction(m_print);
715 	menu_fichier -> addSeparator();
716 	menu_fichier -> addAction(m_quit_editor);
717 
718 	// menu Edition
719 	menu_edition -> addAction(undo);
720 	menu_edition -> addAction(redo);
721 	menu_edition -> addSeparator();
722 	menu_edition -> addAction(m_cut);
723 	menu_edition -> addAction(m_copy);
724 	menu_edition -> addAction(m_paste);
725 	menu_edition -> addSeparator();
726 	menu_edition -> addActions(m_select_actions_group.actions());
727 	menu_edition -> addSeparator();
728 	menu_edition -> addActions(m_selection_actions_group.actions());
729 	menu_edition -> addSeparator();
730 	menu_edition -> addAction(m_conductor_reset);
731 	menu_edition -> addSeparator();
732 	menu_edition -> addAction(m_edit_diagram_properties);
733 	menu_edition -> addActions(m_row_column_actions_group.actions());
734 	menu_edition -> addSeparator();
735 	menu_edition -> addActions(m_depth_action_group->actions());
736 	menu_edition -> addSeparator();
737 	menu_edition -> addAction(m_find);
738 
739 	// menu Projet
740 	menu_project -> addAction(m_project_edit_properties);
741 	menu_project -> addAction(m_project_add_diagram);
742 	menu_project -> addAction(m_remove_diagram_from_project);
743 	menu_project -> addAction(m_clean_project);
744 	menu_project -> addSeparator();
745 	menu_project -> addAction(m_project_folio_list);
746 	menu_project -> addAction(m_project_nomenclature);
747 	menu_project -> addAction(m_project_terminalBloc);
748 
749 	main_tool_bar         -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la barre d'outils principale"));
750 	view_tool_bar         -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la barre d'outils Affichage"));
751 	diagram_tool_bar      -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la barre d'outils Schéma"));
752 	qdw_pa           -> toggleViewAction() -> setStatusTip(tr("Affiche ou non le panel d'appareils"));
753 	qdw_undo         -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la liste des modifications"));
754 
755 
756 	// menu Affichage
757 	QMenu *projects_view_mode = menu_affichage -> addMenu(QET::Icons::ConfigureToolbars, tr("Afficher les projets"));
758 	projects_view_mode -> setTearOffEnabled(true);
759 	projects_view_mode -> addAction(m_windowed_view_mode);
760 	projects_view_mode -> addAction(m_tabbed_view_mode);
761 
762 	menu_affichage -> addSeparator();
763 	menu_affichage -> addAction(m_mode_selection);
764 	menu_affichage -> addAction(m_mode_visualise);
765 	menu_affichage -> addSeparator();
766 	menu_affichage -> addAction(m_draw_grid);
767 	menu_affichage -> addAction(m_grey_background);
768 	menu_affichage -> addSeparator();
769 	menu_affichage -> addActions(m_zoom_actions_group.actions());
770 
771 	// menu Fenetres
772 	slot_updateWindowsMenu();
773 }
774 
775 /**
776 	Permet de quitter l'application lors de la fermeture de la fenetre principale
777 	@param qce Le QCloseEvent correspondant a l'evenement de fermeture
778 */
closeEvent(QCloseEvent * qce)779 void QETDiagramEditor::closeEvent(QCloseEvent *qce) {
780 	// quitte directement s'il n'y a aucun projet ouvert
781 	bool can_quit = true;
782 	if (openedProjects().count()) {
783 		// s'assure que la fenetre soit visible s'il y a des projets a fermer
784 		if (!isVisible() || isMinimized()) {
785 			if (isMaximized()) showMaximized();
786 			else showNormal();
787 		}
788 		// sinon demande la permission de fermer chaque projet
789 		foreach(ProjectView *project, openedProjects()) {
790 			if (!closeProject(project)) {
791 				can_quit = false;
792 				qce -> ignore();
793 				break;
794 			}
795 		}
796 	}
797 	if (can_quit) {
798 		writeSettings();
799 		setAttribute(Qt::WA_DeleteOnClose);
800 		qce -> accept();
801 	}
802 }
803 
804 /**
805  * @brief QETDiagramEditor::event
806  * Reimplemented to :
807  * -Load elements collection when WindowActivate.
808  * @param e
809  * @return
810  */
event(QEvent * e)811 bool QETDiagramEditor::event(QEvent *e)
812 {
813 	if (m_first_show && e->type() == QEvent::WindowActivate)
814 	{
815 		m_first_show = false;
816 		QTimer::singleShot(250, m_element_collection_widget, SLOT(reload()));
817 	}
818 	return(QETMainWindow::event(e));
819 }
820 
821 /**
822  * @brief QETDiagramEditor::save
823  * Ask the current active project to save
824  */
save()825 void QETDiagramEditor::save() {
826 	if (ProjectView *project_view = currentProjectView()) {
827 		QETResult saved = project_view -> save();
828 
829 		if (saved.isOk()) {
830 			//save_file -> setDisabled(true);
831 			QETApp::projectsRecentFiles() -> fileWasOpened(project_view -> project() -> filePath());
832 
833 			QString title = (project_view -> project() -> title ());
834 			if (title.isEmpty()) title = "QElectroTech ";
835 			QString filePath = (project_view -> project() -> filePath ());
836 			statusBar()-> showMessage(tr("Projet %1 enregistré dans le repertoire: %2.").arg(title).arg (filePath), 2000);
837 			m_element_collection_widget->highlightUnusedElement();
838 		}
839 		else {
840 			showError(saved);
841 		}
842 	}
843 }
844 
845 /**
846  * @brief QETDiagramEditor::saveAs
847  * Ask the current active project to save as
848  */
saveAs()849 void QETDiagramEditor::saveAs() {
850 	if (ProjectView *project_view = currentProjectView()) {
851 		QETResult save_file = project_view -> saveAs();
852 		if (save_file.isOk()) {
853 			QETApp::projectsRecentFiles() -> fileWasOpened(project_view -> project() -> filePath());
854 
855 			QString title = (project_view -> project() -> title ());
856 			if (title.isEmpty()) title = "QElectroTech ";
857 			QString filePath = (project_view -> project() -> filePath ());
858 			statusBar()->showMessage(tr("Projet %1 enregistré dans le repertoire: %2.").arg(title).arg (filePath), 2000);
859 			m_element_collection_widget->highlightUnusedElement();
860 		}
861 		else {
862 			showError(save_file);
863 		}
864 	}
865 }
866 
867 /**
868  * @brief QETDiagramEditor::newProject
869  * Create an empty project
870  * @return
871  */
newProject()872 bool QETDiagramEditor::newProject() {
873 	// create new project without diagram
874 	QETProject *new_project = new QETProject(this);
875 
876 	// Set default properties for new diagram
877 	new_project -> setDefaultBorderProperties	  (BorderProperties::    defaultProperties());
878 	new_project -> setDefaultConductorProperties  (ConductorProperties:: defaultProperties());
879 	new_project -> setDefaultTitleBlockProperties (TitleBlockProperties::defaultProperties());
880 	new_project -> setDefaultReportProperties	  (ReportProperties::    defaultProperties());
881 	new_project -> setDefaultXRefProperties		  (XRefProperties::      defaultProperties());
882 
883 	// add new diagram
884 	new_project -> addNewDiagram();
885 
886 	return(addProject(new_project));
887 }
888 
889 /**
890 	Slot utilise pour ouvrir un fichier recent.
891 	Transfere filepath au slot openAndAddDiagram seulement si cet editeur est
892 	actif
893 	@param filepath Fichier a ouvrir
894 	@see openAndAddDiagram
895 */
openRecentFile(const QString & filepath)896 bool QETDiagramEditor::openRecentFile(const QString &filepath) {
897 	// small hack to prevent all diagram editors from trying to topen the required
898 	// recent file at the same time
899 	if (qApp -> activeWindow() != this) return(false);
900 	return(openAndAddProject(filepath));
901 }
902 
903 /**
904 	Cette fonction demande un nom de fichier a ouvrir a l'utilisateur
905 	@return true si l'ouverture a reussi, false sinon
906 */
openProject()907 bool QETDiagramEditor::openProject() {
908 	// demande un chemin de fichier a ouvrir a l'utilisateur
909 	QString filepath = QFileDialog::getOpenFileName(
910 		this,
911 		tr("Ouvrir un fichier"),
912 		open_dialog_dir.absolutePath(),
913 		tr("Projets QElectroTech (*.qet);;Fichiers XML (*.xml);;Tous les fichiers (*)")
914 	);
915 	if (filepath.isEmpty()) return(false);
916 
917 	// retient le dossier contenant le dernier projet ouvert
918 	open_dialog_dir = QDir(filepath);
919 
920 	// ouvre le fichier
921 	return(openAndAddProject(filepath));
922 }
923 
924 /**
925 	Ferme un projet
926 	@param project_view Projet a fermer
927 	@return true si la fermeture du projet a reussi, false sinon
928 	Note : cette methode renvoie true si project est nul
929 */
closeProject(ProjectView * project_view)930 bool QETDiagramEditor::closeProject(ProjectView *project_view) {
931 	if (project_view) {
932 		activateProject(project_view);
933 		if (QMdiSubWindow *sub_window = subWindowForWidget(project_view)){
934 			return(sub_window -> close());
935 		}
936 	}
937 	return(true);
938 }
939 
940 /**
941 	Ferme un projet
942 	@param project projet a fermer
943 	@return true si la fermeture du fichier a reussi, false sinon
944 	Note : cette methode renvoie true si project est nul
945 */
closeProject(QETProject * project)946 bool QETDiagramEditor::closeProject(QETProject *project) {
947 	if (ProjectView *project_view = findProject(project)) {
948 		return(closeProject(project_view));
949 	}
950 	return(true);
951 }
952 
953 /**
954 	Ouvre un projet depuis un fichier et l'ajoute a cet editeur
955 	@param filepath Chemin du projet a ouvrir
956 	@param interactive true pour afficher des messages a l'utilisateur, false sinon
957 	@return true si l'ouverture a reussi, false sinon
958 */
openAndAddProject(const QString & filepath,bool interactive)959 bool QETDiagramEditor::openAndAddProject(const QString &filepath, bool interactive)
960 {
961 	if (filepath.isEmpty()) return(false);
962 
963 	QFileInfo filepath_info(filepath);
964 
965 		//Check if project is not open in another editor
966 	if (QETDiagramEditor *diagram_editor = QETApp::diagramEditorForFile(filepath))
967 	{
968 		if (diagram_editor == this)
969 		{
970 			if (ProjectView *project_view = viewForFile(filepath))
971 			{
972 				activateWidget(project_view);
973 				show();
974 				activateWindow();
975 			}
976 			return(false);
977 		}
978 		else
979 		{
980 				//Ask to the other editor to display the file
981 			return(diagram_editor -> openAndAddProject(filepath));
982 		}
983 	}
984 
985 		// check the file exists
986 	if (!filepath_info.exists())
987 	{
988 		if (interactive)
989 		{
990 			QET::QetMessageBox::critical(
991 				this,
992 				tr("Impossible d'ouvrir le fichier", "message box title"),
993 				QString(
994 					tr("Il semblerait que le fichier %1 que vous essayez d'ouvrir"
995 					" n'existe pas ou plus.")
996 				).arg(filepath)
997 			);
998 		}
999 		return(false);
1000 	}
1001 
1002 		//Check if file readable
1003 	if (!filepath_info.isReadable())
1004 	{
1005 		if (interactive) {
1006 			QET::QetMessageBox::critical(
1007 				this,
1008 				tr("Impossible d'ouvrir le fichier", "message box title"),
1009 				tr("Il semblerait que le fichier que vous essayez d'ouvrir ne "
1010 				"soit pas accessible en lecture. Il est donc impossible de "
1011 				"l'ouvrir. Veuillez vérifier les permissions du fichier.")
1012 			);
1013 		}
1014 		return(false);
1015 	}
1016 
1017 		//Check if file is read only
1018 	if (!filepath_info.isWritable())
1019 	{
1020 		if (interactive) {
1021 			QET::QetMessageBox::warning(
1022 				this,
1023 				tr("Ouverture du projet en lecture seule", "message box title"),
1024 				tr("Il semblerait que le projet que vous essayez d'ouvrir ne "
1025 				"soit pas accessible en écriture. Il sera donc ouvert en "
1026 				"lecture seule.")
1027 			);
1028 		}
1029 	}
1030 
1031 		//Create the project
1032 	DialogWaiting::instance(this);
1033 
1034 	QETProject *project = new QETProject(filepath);
1035 	if (project -> state() != QETProject::Ok)
1036 	{
1037 		if (interactive && project -> state() != QETProject::FileOpenDiscard)
1038 		{
1039 			QET::QetMessageBox::warning(
1040 				this,
1041 				tr("Échec de l'ouverture du projet", "message box title"),
1042 				QString(
1043 					tr(
1044 						"Il semblerait que le fichier %1 ne soit pas un fichier"
1045 						" projet QElectroTech. Il ne peut donc être ouvert.",
1046 						"message box content"
1047 					)
1048 				).arg(filepath)
1049 			);
1050 		}
1051 		delete project;
1052 		DialogWaiting::dropInstance();
1053 		return(false);
1054 	}
1055 
1056 	QETApp::projectsRecentFiles() -> fileWasOpened(filepath);
1057 	addProject(project);
1058 	DialogWaiting::dropInstance();
1059 	return true;
1060 }
1061 
1062 /**
1063 	Ajoute un projetmoveDiagramUp(
1064 	@param project projet a ajouter
1065 	@param update_panel Whether the elements panel should be warned this
1066 	project has been added. Defaults to true.
1067 */
addProject(QETProject * project,bool update_panel)1068 bool QETDiagramEditor::addProject(QETProject *project, bool update_panel) {
1069 	// enregistre le projet
1070 	QETApp::registerProject(project);
1071 
1072 	// cree un ProjectView pour visualiser le projet
1073 	ProjectView *project_view = new ProjectView(project);
1074 	addProjectView(project_view);
1075 
1076 	undo_group.addStack(project -> undoStack());
1077 
1078 	m_element_collection_widget->addProject(project);
1079 
1080 	// met a jour le panel d'elements
1081 	if (update_panel) {
1082 		pa -> elementsPanel().projectWasOpened(project);
1083 		if (currentDiagramView() != nullptr)
1084 		m_autonumbering_dock->setProject(project, project_view);
1085 	}
1086 
1087 	return(true);
1088 }
1089 
1090 /**
1091 	@return la liste des projets ouverts dans cette fenetre
1092 */
openedProjects() const1093 QList<ProjectView *> QETDiagramEditor::openedProjects() const {
1094 	QList<ProjectView *> result;
1095 	QList<QMdiSubWindow *> window_list(m_workspace.subWindowList());
1096 	foreach(QMdiSubWindow *window, window_list) {
1097 		if (ProjectView *project_view = qobject_cast<ProjectView *>(window -> widget())) {
1098 			result << project_view;
1099 		}
1100 	}
1101 	return(result);
1102 }
1103 
1104 /**
1105 	@return Le projet actuellement edite (= qui a le focus dans l'interface
1106 	MDI) ou 0 s'il n'y en a pas
1107 */
currentProjectView() const1108 ProjectView *QETDiagramEditor::currentProjectView() const {
1109 	QMdiSubWindow *current_window = m_workspace.activeSubWindow();
1110 	if (!current_window) return(nullptr);
1111 
1112 	QWidget *current_widget = current_window -> widget();
1113 	if (!current_widget) return(nullptr);
1114 
1115 	if (ProjectView *project_view = qobject_cast<ProjectView *>(current_widget)) {
1116 		return(project_view);
1117 	}
1118 	return(nullptr);
1119 }
1120 
1121 /**
1122  * @brief QETDiagramEditor::currentProject
1123  * @return the current edited project.
1124  * This function can return nullptr.
1125  */
currentProject() const1126 QETProject *QETDiagramEditor::currentProject() const
1127 {
1128 	ProjectView *view = currentProjectView();
1129 	if (view) {
1130 		return view->project();
1131 	}
1132 	else {
1133 		return nullptr;
1134 	}
1135 }
1136 
1137 /**
1138 	@return Le schema actuellement edite (= l'onglet ouvert dans le projet
1139 	courant) ou 0 s'il n'y en a pas
1140 */
currentDiagramView() const1141 DiagramView *QETDiagramEditor::currentDiagramView() const {
1142 	if (ProjectView *project_view = currentProjectView()) {
1143 		return(project_view -> currentDiagram());
1144 	}
1145 	return(nullptr);
1146 }
1147 
1148 /**
1149 	@return the selected element in the current diagram view, or 0 if:
1150 	  * no diagram is being viewed in this editor.
1151 	  * no element is selected
1152 	  * more than one element is selected
1153 */
currentElement() const1154 Element *QETDiagramEditor::currentElement() const
1155 {
1156 	DiagramView *dv = currentDiagramView();
1157 	if (!dv)
1158 		return(nullptr);
1159 
1160 	QList<Element *> selected_elements = DiagramContent(dv->diagram()).m_elements;
1161 	if (selected_elements.count() != 1)
1162 		return(nullptr);
1163 
1164 	return(selected_elements.first());
1165 }
1166 
1167 /**
1168 	Cette methode permet de retrouver le projet contenant un schema donne.
1169 	@param diagram_view Schema dont il faut retrouver
1170 	@return la vue sur le projet contenant ce schema ou 0 s'il n'y en a pas
1171 */
findProject(DiagramView * diagram_view) const1172 ProjectView *QETDiagramEditor::findProject(DiagramView *diagram_view) const {
1173 	foreach(ProjectView *project_view, openedProjects()) {
1174 		if (project_view -> diagram_views().contains(diagram_view)) {
1175 			return(project_view);
1176 		}
1177 	}
1178 	return(nullptr);
1179 }
1180 
1181 /**
1182 	Cette methode permet de retrouver le projet contenant un schema donne.
1183 	@param diagram Schema dont il faut retrouver
1184 	@return la vue sur le projet contenant ce schema ou 0 s'il n'y en a pas
1185 */
findProject(Diagram * diagram) const1186 ProjectView *QETDiagramEditor::findProject(Diagram *diagram) const {
1187 	foreach(ProjectView *project_view, openedProjects()) {
1188 		foreach(DiagramView *diagram_view, project_view -> diagram_views()) {
1189 			if (diagram_view -> diagram() == diagram) {
1190 				return(project_view);
1191 			}
1192 		}
1193 	}
1194 	return(nullptr);
1195 }
1196 
1197 /**
1198 	@param project Projet dont il faut trouver la vue
1199 	@return la vue du projet passe en parametre
1200 */
findProject(QETProject * project) const1201 ProjectView *QETDiagramEditor::findProject(QETProject *project) const {
1202 	foreach(ProjectView *opened_project, openedProjects()) {
1203 		if (opened_project -> project() == project) {
1204 			return(opened_project);
1205 		}
1206 	}
1207 	return(nullptr);
1208 }
1209 
1210 /**
1211 	@param filepath Chemin de fichier d'un projet
1212 	@return le ProjectView correspondant au chemin passe en parametre, ou 0 si
1213 	celui-ci n'a pas ete trouve
1214 */
findProject(const QString & filepath) const1215 ProjectView *QETDiagramEditor::findProject(const QString &filepath) const {
1216 	foreach(ProjectView *opened_project, openedProjects()) {
1217 		if (QETProject *project = opened_project -> project()) {
1218 			if (project -> filePath() == filepath) {
1219 				return(opened_project);
1220 			}
1221 		}
1222 	}
1223 	return(nullptr);
1224 }
1225 
1226 /**
1227 	@param widget Widget a rechercher dans la zone MDI
1228 	@return La sous-fenetre accueillant le widget passe en parametre, ou 0 si
1229 	celui-ci n'a pas ete trouve.
1230 */
subWindowForWidget(QWidget * widget) const1231 QMdiSubWindow *QETDiagramEditor::subWindowForWidget(QWidget *widget) const {
1232 	foreach(QMdiSubWindow *sub_window, m_workspace.subWindowList()) {
1233 		if (sub_window -> widget() == widget) {
1234 			return(sub_window);
1235 		}
1236 	}
1237 	return(nullptr);
1238 }
1239 
1240 /**
1241 	@param widget Widget a activer
1242 */
activateWidget(QWidget * widget)1243 void QETDiagramEditor::activateWidget(QWidget *widget) {
1244 	QMdiSubWindow *sub_window = subWindowForWidget(widget);
1245 	if (sub_window) {
1246 		m_workspace.setActiveSubWindow(sub_window);
1247 	}
1248 }
1249 
zoomGroupTriggered(QAction * action)1250 void QETDiagramEditor::zoomGroupTriggered(QAction *action)
1251 {
1252 	QString value = action->data().toString();
1253 	DiagramView *dv = currentDiagramView();
1254 
1255 	if (!dv || value.isEmpty()) return;
1256 
1257 	if (value == "zoom_in")
1258 		dv->zoom(1.15);
1259 	else if (value == "zoom_out")
1260 		dv->zoom(0.85);
1261 	else if (value == "zoom_content")
1262 		dv->zoomContent();
1263 	else if (value == "zoom_fit")
1264 		dv->zoomFit();
1265 	else if (value == "zoom_reset")
1266 		dv->zoomReset();
1267 }
1268 
1269 /**
1270  * @brief QETDiagramEditor::selectGroupTriggered
1271  * This slot is called when selection need to change.
1272  * @param action : Action that describes what to do.
1273  */
selectGroupTriggered(QAction * action)1274 void QETDiagramEditor::selectGroupTriggered(QAction *action)
1275 {
1276 	QString value = action->data().toString();
1277 	DiagramView *dv = currentDiagramView();
1278 
1279 	if (!dv || value.isEmpty()) return;
1280 
1281 	if (value == "select_all")
1282 		dv->selectAll();
1283 	else if (value == "deselect")
1284 		dv->selectNothing();
1285 	else if (value == "invert_selection")
1286 		dv->selectInvert();
1287 }
1288 
1289 /**
1290  * @brief QETDiagramEditor::addItemGroupTriggered
1291  * This slot is called when an item must be added to the curent diagram,
1292  * this slot use the DVEventInterface to add item
1293  * @param action : Action that describe the item to add.
1294  */
addItemGroupTriggered(QAction * action)1295 void QETDiagramEditor::addItemGroupTriggered(QAction *action)
1296 {
1297 	QString value = action->data().toString();
1298 
1299 	if (Q_UNLIKELY (!currentDiagramView() || !currentDiagramView()->diagram() || value.isEmpty())) return;
1300 
1301 	Diagram *d = currentDiagramView()->diagram();
1302 	DiagramEventInterface *diagram_event = nullptr;
1303 
1304 	if (value == "line")
1305 		diagram_event = new DiagramEventAddShape (d, QetShapeItem::Line);
1306 	else if (value == "rectangle")
1307 		diagram_event = new DiagramEventAddShape (d, QetShapeItem::Rectangle);
1308 	else if (value == "ellipse")
1309 		diagram_event = new DiagramEventAddShape (d, QetShapeItem::Ellipse);
1310 	else if (value == "polyline")
1311 	{
1312 		diagram_event = new DiagramEventAddShape (d, QetShapeItem::Polygon);
1313 		statusBar()-> showMessage(tr("Double-click pour terminer la forme, Click droit pour annuler le dernier point"));
1314 		connect(diagram_event, &DiagramEventInterface::destroyed, [this]() {
1315 		statusBar()->clearMessage();
1316 		});
1317 	}
1318 	else if (value == "image")
1319 	{
1320 		DiagramEventAddImage *deai = new DiagramEventAddImage(d);
1321 		if (deai->isNull())
1322 		{
1323 			delete deai;
1324 			action->setChecked(false);
1325 			return;
1326 		}
1327 		else
1328 			diagram_event = deai;
1329 	}
1330 	else if (value == "text")
1331 		diagram_event = new DiagramEventAddText(d);
1332 
1333 	if (diagram_event)
1334 	{
1335 		d->setEventInterface(diagram_event);
1336 		connect(diagram_event, &DiagramEventInterface::destroyed, [action]() {action->setChecked(false);});
1337 	}
1338 }
1339 
1340 /**
1341  * @brief QETDiagramEditor::selectionGroupTriggered
1342  * This slot is called when an action should be made on the current selection
1343  * @param action : Action that describe the action to do.
1344  */
selectionGroupTriggered(QAction * action)1345 void QETDiagramEditor::selectionGroupTriggered(QAction *action)
1346 {
1347 	QString value = action->data().toString();
1348 	DiagramView *dv = currentDiagramView();
1349 	Diagram *diagram = dv->diagram();
1350 	DiagramContent dc(diagram);
1351 
1352 	if (!dv || value.isEmpty()) return;
1353 
1354 	if (value == "delete_selection")
1355 	{
1356 		diagram->clearSelection();
1357 		diagram->undoStack().push(new DeleteQGraphicsItemCommand(diagram, dc));
1358 		dv->adjustSceneRect();
1359 	}
1360 	else if (value == "rotate_selection")
1361 	{
1362 		RotateSelectionCommand *c = new RotateSelectionCommand(diagram);
1363 		if(c->isValid())
1364 			diagram->undoStack().push(c);
1365 	}
1366 	else if (value == "rotate_selected_text")
1367 		diagram->undoStack().push(new RotateTextsCommand(diagram));
1368 	else if (value == "find_selected_element" && currentElement())
1369 		findElementInPanel(currentElement()->location());
1370 	else if (value == "edit_selected_element")
1371 		dv->editSelection();
1372 	else if (value == "group_selected_texts")
1373 	{
1374 		QList<DynamicElementTextItem *> deti_list = dc.m_element_texts.toList();
1375 		if(deti_list.size() <= 1)
1376 			return;
1377 
1378 		diagram->undoStack().push(new AddTextsGroupCommand(deti_list.first()->parentElement(), tr("Groupe"), deti_list));
1379 	}
1380 }
1381 
rowColumnGroupTriggered(QAction * action)1382 void QETDiagramEditor::rowColumnGroupTriggered(QAction *action)
1383 {
1384 	QString value = action->data().toString();
1385 	DiagramView *dv = currentDiagramView();
1386 
1387 	if (!dv || value.isEmpty() || dv->diagram()->isReadOnly()) return;
1388 
1389 	Diagram *d = dv->diagram();
1390 	BorderProperties old_bp = d->border_and_titleblock.exportBorder();
1391 	BorderProperties new_bp = d->border_and_titleblock.exportBorder();
1392 
1393 	if (value == "add_column")
1394 		new_bp.columns_count += 1;
1395 	else if (value == "remove_column")
1396 		new_bp.columns_count -= 1;
1397 	else if (value == "add_row")
1398 		new_bp.rows_count += 1;
1399 	else if (value == "remove_row")
1400 		new_bp.rows_count -= 1;
1401 
1402 	d->undoStack().push(new ChangeBorderCommand(d, old_bp, new_bp));
1403 }
1404 
1405 /**
1406  * @brief QETDiagramEditor::slot_updateActions
1407  * Manage actions
1408  */
slot_updateActions()1409 void QETDiagramEditor::slot_updateActions()
1410 {
1411 	DiagramView *dv = currentDiagramView();
1412 	ProjectView *pv = currentProjectView();
1413 
1414 	bool opened_project = pv;
1415 	bool opened_diagram = dv;
1416 	bool editable_project = (pv && !pv -> project() -> isReadOnly());
1417 
1418 	m_close_file       -> setEnabled(opened_project);
1419 	m_save_file        -> setEnabled(opened_project);
1420 	m_save_file_as     -> setEnabled(opened_project);
1421 	m_project_edit_properties    -> setEnabled(opened_project);
1422 	//prj_terminalBloc -> setEnabled(opened_project);
1423 	m_rotate_texts -> setEnabled(editable_project);
1424 	m_project_add_diagram  -> setEnabled(editable_project);
1425 	m_remove_diagram_from_project  -> setEnabled(editable_project);
1426 	m_clean_project        -> setEnabled(editable_project);
1427 	m_project_folio_list  -> setEnabled(opened_project);
1428 	m_project_nomenclature -> setEnabled(editable_project);
1429 	m_export_diagram   -> setEnabled(opened_diagram);
1430 	m_print            -> setEnabled(opened_diagram);
1431 	m_edit_diagram_properties    -> setEnabled(opened_diagram);
1432 	m_project_nomenclature -> setEnabled(editable_project);
1433 	m_zoom_actions_group.      setEnabled(opened_diagram);
1434 	m_select_actions_group.    setEnabled(opened_diagram);
1435 	m_add_item_actions_group.  setEnabled(editable_project);
1436 	m_row_column_actions_group.setEnabled(editable_project);
1437 	m_grey_background->setEnabled(opened_diagram);
1438 
1439 
1440 	slot_updateUndoStack();
1441 	slot_updateModeActions();
1442 	slot_updatePasteAction();
1443 	slot_updateComplexActions();
1444 	slot_updateAutoNumDock();
1445 }
1446 
1447 /**
1448  * @brief QETDiagramEditor::slot_updateAutoNumDock
1449  * Update Auto Num Dock Widget when changing Project
1450  */
slot_updateAutoNumDock()1451 void QETDiagramEditor::slot_updateAutoNumDock() {
1452 	if ( m_workspace.subWindowList().indexOf(m_workspace.activeSubWindow()) != activeSubWindowIndex) {
1453 			activeSubWindowIndex = m_workspace.subWindowList().indexOf(m_workspace.activeSubWindow());
1454 			if (currentProjectView() != nullptr && currentDiagramView() != nullptr) {
1455 				m_autonumbering_dock->setProject(currentProjectView()->project(),currentProjectView());
1456 			}
1457 	}
1458 }
1459 
1460 /**
1461  * @brief QETDiagramEditor::slot_updateUndoStack
1462  * Update the undo stack view
1463  */
slot_updateUndoStack()1464 void QETDiagramEditor::slot_updateUndoStack()
1465 {
1466 	if(currentProjectView())
1467 		undo_group.setActiveStack(currentProjectView()->project()->undoStack());
1468 }
1469 
1470 /**
1471  * @brief QETDiagramEditor::slot_updateComplexActions
1472  * Manage the actions who need some conditions to be enable or not.
1473  * This method does nothing if there is no project opened
1474  */
slot_updateComplexActions()1475 void QETDiagramEditor::slot_updateComplexActions()
1476 {
1477 	DiagramView *dv = currentDiagramView();
1478 	if(!dv)
1479 	{
1480 		QList <QAction *> action_list;
1481 		action_list << m_conductor_reset << m_find_element << m_cut << m_copy << m_delete_selection << m_rotate_selection << m_edit_selection << m_group_selected_texts;
1482 		for(QAction *action : action_list)
1483 			action->setEnabled(false);
1484 
1485 		return;
1486 	}
1487 
1488 	Diagram *diagram_ = dv->diagram();
1489 	DiagramContent dc(diagram_);
1490 	bool ro = diagram_->isReadOnly();
1491 
1492 
1493 		//Number of selected conductors
1494 	int selected_conductors_count = diagram_->selectedConductors().count();
1495 	m_conductor_reset->setEnabled(!ro && selected_conductors_count);
1496 
1497 		// number of selected elements
1498 	int selected_elements_count = dc.count(DiagramContent::Elements);
1499 	m_find_element->setEnabled(selected_elements_count == 1);
1500 
1501 		//Action that need items (elements, conductors, texts...) selected, to be enabled
1502 	bool copiable_items  = dc.hasCopiableItems();
1503 	bool deletable_items = dc.hasDeletableItems();
1504 	m_cut              -> setEnabled(!ro && copiable_items);
1505 	m_copy             -> setEnabled(copiable_items);
1506 	m_delete_selection -> setEnabled(!ro && deletable_items);
1507 	m_rotate_selection -> setEnabled(!ro && diagram_->canRotateSelection());
1508 
1509 		//Action that need selected texts or texts group
1510 	QList<DiagramTextItem *> texts = DiagramContent(diagram_).selectedTexts();
1511 	QList<ElementTextItemGroup *> groups = DiagramContent(diagram_).selectedTextsGroup();
1512 	int selected_texts = texts.count();
1513 	int selected_conductor_texts   = 0; for(DiagramTextItem *dti : texts) {if(dti->type() == ConductorTextItem::Type) selected_conductor_texts++;}
1514 	int selected_dynamic_elmt_text = 0; for(DiagramTextItem *dti : texts) {if(dti->type() == DynamicElementTextItem::Type) selected_dynamic_elmt_text++;}
1515 	m_rotate_texts->setEnabled(!ro && (selected_texts || groups.size()));
1516 
1517 		//Action that need only element text selected
1518 	QList<DynamicElementTextItem *> deti_list = dc.m_element_texts.toList();
1519 	if(deti_list.size() > 1 && dc.count() == deti_list.count())
1520 	{
1521 		Element *elmt = deti_list.first()->parentElement();
1522 		bool ok = true;
1523 		for(DynamicElementTextItem *deti : deti_list)
1524 		{
1525 			if(elmt != deti->parentElement())
1526 				ok = false;
1527 		}
1528 		m_group_selected_texts->setEnabled(!ro && ok);
1529 	}
1530 	else
1531 		m_group_selected_texts->setDisabled(true);
1532 
1533 		// actions need only one editable item
1534 	int selected_image = dc.count(DiagramContent::Images);
1535 
1536 	int selected_shape = dc.count(DiagramContent::Shapes);
1537 	int selected_editable = selected_elements_count +
1538 							(selected_texts - selected_conductor_texts - selected_dynamic_elmt_text) +
1539 							selected_image +
1540 							selected_shape +
1541 							selected_conductors_count;
1542 
1543 	if (selected_editable == 1)
1544 	{
1545 		m_edit_selection -> setEnabled(true);
1546 			//edit element
1547 		if (selected_elements_count)
1548 		{
1549 			m_edit_selection -> setText(tr("Éditer l'élement", "edit element"));
1550 			m_edit_selection -> setIcon(QET::Icons::ElementEdit);
1551 		}
1552 			//edit text field
1553 		else if (selected_texts)
1554 		{
1555 			m_edit_selection -> setText(tr("Éditer le champ de texte", "edit text field"));
1556 			m_edit_selection -> setIcon(QET::Icons::EditText);
1557 		}
1558 			//edit image
1559 		else if (selected_image)
1560 		{
1561 			m_edit_selection -> setText(tr("Éditer l'image", "edit image"));
1562 			m_edit_selection -> setIcon(QET::Icons::resize_image);
1563 		}
1564 			//edit conductor
1565 		else if (selected_conductors_count)
1566 		{
1567 			m_edit_selection -> setText(tr("Éditer le conducteur", "edit conductor"));
1568             m_edit_selection -> setIcon(QET::Icons::ConductorEdit);
1569 		}
1570 	}
1571 		//not an editable item
1572 	else
1573 	{
1574 		m_edit_selection -> setText(tr("Éditer l'objet sélectionné", "edit selected item"));
1575 		m_edit_selection -> setIcon(QET::Icons::ElementEdit);
1576 		m_edit_selection -> setEnabled(false);
1577 	}
1578 
1579 		//Actions for edit Z value
1580 	QList<QGraphicsItem *> list = dc.items(DiagramContent::SelectedOnly | \
1581 											 DiagramContent::Elements | \
1582 											 DiagramContent::Shapes | \
1583 											 DiagramContent::Images);
1584 	m_depth_action_group->setEnabled(list.isEmpty()? false : true);
1585 }
1586 
1587 /**
1588  * @brief QETDiagramEditor::slot_updateModeActions
1589  * Manage action who need an opened diagram or project to be updated
1590  */
slot_updateModeActions()1591 void QETDiagramEditor::slot_updateModeActions()
1592 {
1593 	DiagramView *dv = currentDiagramView();
1594 
1595 	if (!dv)
1596 		grp_visu_sel -> setEnabled(false);
1597 	else
1598 	{
1599 		switch((int)(dv -> dragMode()))
1600 		{
1601 			case QGraphicsView::NoDrag:
1602 				grp_visu_sel -> setEnabled(false);
1603 				break;
1604 			case QGraphicsView::ScrollHandDrag:
1605 				grp_visu_sel -> setEnabled(true);
1606 				m_mode_visualise -> setChecked(true);
1607 				break;
1608 			case QGraphicsView::RubberBandDrag:
1609 				grp_visu_sel -> setEnabled(true);
1610 				m_mode_selection -> setChecked(true);
1611 				break;
1612 		}
1613 	}
1614 
1615 	if (ProjectView *pv = currentProjectView())
1616 	{
1617 		m_auto_conductor -> setEnabled (true);
1618 		m_auto_conductor -> setChecked (pv -> project() -> autoConductor());
1619 	}
1620 	else
1621 		m_auto_conductor -> setDisabled(true);
1622 }
1623 
1624 /**
1625 	Gere les actions ayant besoin du presse-papier
1626 */
slot_updatePasteAction()1627 void QETDiagramEditor::slot_updatePasteAction() {
1628 	DiagramView *dv = currentDiagramView();
1629 	bool editable_diagram = (dv && !dv -> diagram() -> isReadOnly());
1630 
1631 	// pour coller, il faut un schema ouvert et un schema dans le presse-papier
1632 	m_paste -> setEnabled(editable_diagram && Diagram::clipboardMayContainDiagram());
1633 }
1634 
1635 /**
1636  * @brief QETDiagramEditor::addProjectView
1637  * Add a new project view to workspace and
1638  * build the connection between the projectview / project and this QETDiagramEditor.
1639  * @param project_view, project view to add
1640  */
addProjectView(ProjectView * project_view)1641 void QETDiagramEditor::addProjectView(ProjectView *project_view)
1642 {
1643 	if (!project_view) return;
1644 
1645 	foreach(DiagramView *dv, project_view -> diagram_views())
1646 		diagramWasAdded(dv);
1647 
1648 		//Manage the close event of project
1649 	connect(project_view, SIGNAL(projectClosed(ProjectView*)), this, SLOT(projectWasClosed(ProjectView *)));
1650 		//Manage the adding  of diagram
1651 	connect(project_view, SIGNAL(diagramAdded(DiagramView *)), this, SLOT(diagramWasAdded(DiagramView *)));
1652 
1653 	if (QETProject *project = project_view -> project())
1654 		connect(project, SIGNAL(readOnlyChanged(QETProject *, bool)), this, SLOT(slot_updateActions()));
1655 
1656 		//Manage request for edit or find element and titleblock
1657 	connect (project_view, &ProjectView::findElementRequired, this, &QETDiagramEditor::findElementInPanel);
1658 	connect (project_view, &ProjectView::editElementRequired, this, &QETDiagramEditor::editElementInEditor);
1659 
1660 		// display error messages sent by the project view
1661 	connect(project_view, SIGNAL(errorEncountered(QString)), this, SLOT(showError(const QString &)));
1662 
1663 		//We maximise the new window if the current window is inexistent or maximized
1664 	QWidget *current_window = m_workspace.activeSubWindow();
1665 	bool     maximise       = ((!current_window) || (current_window -> windowState() & Qt::WindowMaximized));
1666 
1667 		//Add the new window
1668 	QMdiSubWindow *sub_window = m_workspace.addSubWindow(project_view);
1669 	sub_window -> setWindowIcon(project_view -> windowIcon());
1670 	sub_window -> systemMenu() -> clear();
1671 
1672 		//By defaut QMdiSubWindow have a QAction "close" with shortcut QKeySequence::Close
1673 		//But the QAction m_close_file of this class have the same shortcut too.
1674 		//We remove the shortcut of the QAction of QMdiSubWindow for avoid conflic
1675 	for(QAction *act : sub_window->actions())
1676 	{
1677 		if(act->shortcut() == QKeySequence::Close)
1678 			act->setShortcut(QKeySequence());
1679 	}
1680 
1681 		//Display the new window
1682 	if (maximise) project_view -> showMaximized();
1683 	else          project_view -> show();
1684 }
1685 
1686 /**
1687 	@return la liste des fichiers edites par cet editeur de schemas
1688 */
editedFiles() const1689 QList<QString> QETDiagramEditor::editedFiles() const {
1690 	QList<QString> edited_files_list;
1691 	foreach (ProjectView *project_view, openedProjects()) {
1692 		QString diagram_file(project_view -> project() -> filePath());
1693 		if (!diagram_file.isEmpty()) {
1694 			edited_files_list << QFileInfo(diagram_file).canonicalFilePath();
1695 		}
1696 	}
1697 	return(edited_files_list);
1698 }
1699 
1700 /**
1701 	@param filepath Un chemin de fichier
1702 	Note : si filepath est une chaine vide, cette methode retourne 0.
1703 	@return le ProjectView editant le fichier filepath, ou 0 si ce fichier n'est
1704 	pas edite par cet editeur de schemas.
1705 */
viewForFile(const QString & filepath) const1706 ProjectView *QETDiagramEditor::viewForFile(const QString &filepath) const {
1707 	if (filepath.isEmpty()) return(nullptr);
1708 
1709 	QString searched_can_file_path = QFileInfo(filepath).canonicalFilePath();
1710 	if (searched_can_file_path.isEmpty()) {
1711 		// QFileInfo returns an empty path for non-existent files
1712 		return(nullptr);
1713 	}
1714 	foreach (ProjectView *project_view, openedProjects()) {
1715 		QString project_can_file_path = QFileInfo(project_view -> project() -> filePath()).canonicalFilePath();
1716 		if (project_can_file_path == searched_can_file_path) {
1717 			return(project_view);
1718 		}
1719 	}
1720 	return(nullptr);
1721 }
1722 
1723 /**
1724  * @brief QETDiagramEditor::drawGrid
1725  * @return true if the grid of folio must be displayed
1726  */
drawGrid() const1727 bool QETDiagramEditor::drawGrid() const {
1728 	return m_draw_grid->isChecked();
1729 }
1730 
1731 /**
1732  * @brief QETDiagramEditor::openBackupFiles
1733  * @param backup_files
1734  */
openBackupFiles(QList<KAutoSaveFile * > backup_files)1735 void QETDiagramEditor::openBackupFiles(QList<KAutoSaveFile *> backup_files)
1736 {
1737 	for (KAutoSaveFile *file : backup_files)
1738 	{
1739 			//Create the project
1740 		DialogWaiting::instance(this);
1741 
1742 		QETProject *project = new QETProject(file, this);
1743 		if (project->state() != QETProject::Ok)
1744 		{
1745 			if (project -> state() != QETProject::FileOpenDiscard)
1746 			{
1747 				QET::QetMessageBox::warning(this, tr("Échec de l'ouverture du projet", "message box title"),
1748 											QString(tr("Une erreur est survenue lors de l'ouverture du fichier %1.",
1749 													   "message box content")).arg(file->managedFile().fileName()));
1750 			}
1751 			delete project;
1752 			DialogWaiting::dropInstance();
1753 		}
1754 		addProject(project);
1755 		DialogWaiting::dropInstance();
1756 	}
1757 }
1758 
1759 /**
1760 	met a jour le menu "Fenetres"
1761 */
slot_updateWindowsMenu()1762 void QETDiagramEditor::slot_updateWindowsMenu() {
1763 	// nettoyage du menu
1764 	foreach(QAction *a, windows_menu -> actions()) windows_menu -> removeAction(a);
1765 
1766 	// actions de fermeture
1767 	windows_menu -> addAction(m_close_file);
1768 	//windows_menu -> addAction(closeAllAct);
1769 
1770 	// actions de reorganisation des fenetres
1771 	windows_menu -> addSeparator();
1772 	windows_menu -> addAction(m_tile_window);
1773 	windows_menu -> addAction(m_cascade_window);
1774 
1775 	// actions de deplacement entre les fenetres
1776 	windows_menu -> addSeparator();
1777 	windows_menu -> addAction(m_next_window);
1778 	windows_menu -> addAction(m_previous_window);
1779 
1780 	// liste des fenetres
1781 	QList<ProjectView *> windows = openedProjects();
1782 
1783 	m_tile_window    -> setEnabled(!windows.isEmpty() && m_workspace.viewMode() == QMdiArea::SubWindowView);
1784 	m_cascade_window -> setEnabled(!windows.isEmpty() && m_workspace.viewMode() == QMdiArea::SubWindowView);
1785 	m_next_window    -> setEnabled(windows.count() > 1);
1786 	m_previous_window    -> setEnabled(windows.count() > 1);
1787 
1788 	if (!windows.isEmpty()) windows_menu -> addSeparator();
1789 	QActionGroup *windows_actions = new QActionGroup(this);
1790 	foreach(ProjectView *project_view, windows) {
1791 		QString pv_title = project_view -> windowTitle();
1792 		QAction *action  = windows_menu -> addAction(pv_title);
1793 		windows_actions -> addAction(action);
1794 		action -> setStatusTip(QString(tr("Active le projet « %1 »")).arg(pv_title));
1795 		action -> setCheckable(true);
1796 		action -> setChecked(project_view == currentProjectView());
1797 		connect(action, SIGNAL(triggered()), &windowMapper, SLOT(map()));
1798 		windowMapper.setMapping(action, project_view);
1799 	}
1800 }
1801 
1802 /**
1803 	Edite les proprietes du schema diagram
1804 	@param diagram_view schema dont il faut editer les proprietes
1805 */
editDiagramProperties(DiagramView * diagram_view)1806 void QETDiagramEditor::editDiagramProperties(DiagramView *diagram_view) {
1807 	if (ProjectView *project_view = findProject(diagram_view)) {
1808 		activateProject(project_view);
1809 		project_view -> editDiagramProperties(diagram_view);
1810 	}
1811 }
1812 
1813 /**
1814 	Edite les proprietes du schema diagram
1815 	@param diagram schema dont il faut editer les proprietes
1816 */
editDiagramProperties(Diagram * diagram)1817 void QETDiagramEditor::editDiagramProperties(Diagram *diagram) {
1818 	if (ProjectView *project_view = findProject(diagram)) {
1819 		activateProject(project_view);
1820 		project_view -> editDiagramProperties(diagram);
1821 	}
1822 }
1823 
1824 /**
1825 	Affiche les projets dans des fenetres.
1826 */
setWindowedMode()1827 void QETDiagramEditor::setWindowedMode() {
1828 	m_workspace.setViewMode(QMdiArea::SubWindowView);
1829 	m_windowed_view_mode -> setChecked(true);
1830 	slot_updateWindowsMenu();
1831 }
1832 
1833 /**
1834 	Affiche les projets dans des onglets.
1835 */
setTabbedMode()1836 void QETDiagramEditor::setTabbedMode() {
1837 	m_workspace.setViewMode(QMdiArea::TabbedView);
1838 	m_tabbed_view_mode -> setChecked(true);
1839 	slot_updateWindowsMenu();
1840 }
1841 
1842 /**
1843  * @brief QETDiagramEditor::readSettings
1844  * Read the settings
1845  */
readSettings()1846 void QETDiagramEditor::readSettings()
1847 {
1848 	QSettings settings;
1849 
1850 	// dimensions et position de la fenetre
1851 	QVariant geometry = settings.value("diagrameditor/geometry");
1852 	if (geometry.isValid()) restoreGeometry(geometry.toByteArray());
1853 
1854 	// etat de la fenetre (barres d'outils, docks...)
1855 	QVariant state = settings.value("diagrameditor/state");
1856 	if (state.isValid()) restoreState(state.toByteArray());
1857 
1858 	// gestion des projets (onglets ou fenetres)
1859 	bool tabbed = settings.value("diagrameditor/viewmode", "tabbed") == "tabbed";
1860 	if (tabbed) {
1861 		setTabbedMode();
1862 	} else {
1863 		setWindowedMode();
1864 	}
1865 }
1866 
1867 /**
1868  * @brief QETDiagramEditor::writeSettings
1869  * Write the settings
1870  */
writeSettings()1871 void QETDiagramEditor::writeSettings()
1872 {
1873 	QSettings settings;
1874 	settings.setValue("diagrameditor/geometry", saveGeometry());
1875 	settings.setValue("diagrameditor/state", saveState());
1876 }
1877 
1878 /**
1879 	Active le schema passe en parametre
1880 	@param diagram Schema a activer
1881 */
activateDiagram(Diagram * diagram)1882 void QETDiagramEditor::activateDiagram(Diagram *diagram) {
1883 	if (QETProject *project = diagram -> project()) {
1884 		if (ProjectView *project_view = findProject(project)) {
1885 			activateWidget(project_view);
1886 			project_view -> showDiagram(diagram);
1887 		}
1888 	} else {
1889 		/// @todo gerer ce cas
1890 	}
1891 }
1892 
1893 /**
1894 	Active le projet passe en parametre
1895 	@param project Projet a activer
1896 */
activateProject(QETProject * project)1897 void QETDiagramEditor::activateProject(QETProject *project) {
1898 	activateProject(findProject(project));
1899 }
1900 
1901 /**
1902 	Active le projet passe en parametre
1903 	@param project_view Projet a activer
1904 */
activateProject(ProjectView * project_view)1905 void QETDiagramEditor::activateProject(ProjectView *project_view) {
1906 	if (!project_view) return;
1907 	activateWidget(project_view);
1908 }
1909 
1910 /**
1911 	Gere la fermeture d'une ProjectView
1912 	@param project_view ProjectView fermee
1913 */
projectWasClosed(ProjectView * project_view)1914 void QETDiagramEditor::projectWasClosed(ProjectView *project_view) {
1915 	QETProject *project = project_view -> project();
1916 	if (project) {
1917 		pa -> elementsPanel().projectWasClosed(project);
1918 		m_element_collection_widget->removeProject(project);
1919 		undo_group.removeStack(project -> undoStack());
1920 		QETApp::unregisterProject(project);
1921 	}
1922 	project_view -> deleteLater();
1923 	project -> deleteLater();
1924 }
1925 
1926 /**
1927 	Edite les proprietes du projet project_view.
1928 	@param project_view Vue sur le projet dont il faut editer les proprietes
1929 */
editProjectProperties(ProjectView * project_view)1930 void QETDiagramEditor::editProjectProperties(ProjectView *project_view) {
1931 	if (!project_view) return;
1932 	activateProject(project_view);
1933 	project_view -> editProjectProperties();
1934 }
1935 
1936 /**
1937 	Edite les proprietes du projet project.
1938 	@param project Projet dont il faut editer les proprietes
1939 */
editProjectProperties(QETProject * project)1940 void QETDiagramEditor::editProjectProperties(QETProject *project) {
1941 	editProjectProperties(findProject(project));
1942 }
1943 
1944 /**
1945 	Ajoute un nouveau schema a un projet
1946 	@param project Projet auquel il faut ajouter un schema
1947 */
addDiagramToProject(QETProject * project)1948 void QETDiagramEditor::addDiagramToProject(QETProject *project) {
1949 	if (!project) return;
1950 
1951 	// recupere le ProjectView visualisant ce projet
1952 	if (ProjectView *project_view = findProject(project)) {
1953 
1954 		// affiche le projet en question
1955 		activateProject(project);
1956 
1957 		// ajoute un schema au projet
1958 		project_view -> addNewDiagram();
1959 	}
1960 }
1961 
1962 /**
1963 	Supprime un schema de son projet
1964 	@param diagram Schema a supprimer
1965 */
removeDiagram(Diagram * diagram)1966 void QETDiagramEditor::removeDiagram(Diagram *diagram) {
1967 	if (!diagram) return;
1968 
1969 	// recupere le projet contenant le schema
1970 	if (QETProject *diagram_project = diagram -> project()) {
1971 		// recupere la vue sur ce projet
1972 		if (ProjectView *project_view = findProject(diagram_project)) {
1973 
1974 			// affiche le schema en question
1975 			project_view -> showDiagram(diagram);
1976 
1977 			// supprime le schema
1978 			project_view -> removeDiagram(diagram);
1979 		}
1980 	}
1981 }
1982 
1983 /**
1984 	Change l'ordre des schemas d'un projet, en decalant le schema vers le haut /
1985 	la gauche
1986 	@param diagram Schema a decaler vers le haut / la gauche
1987 */
moveDiagramUp(Diagram * diagram)1988 void QETDiagramEditor::moveDiagramUp(Diagram *diagram) {
1989 	if (!diagram) return;
1990 
1991 	// recupere le projet contenant le schema
1992 	if (QETProject *diagram_project = diagram -> project()) {
1993 		if (diagram_project -> isReadOnly()) return;
1994 
1995 		// recupere la vue sur ce projet
1996 		if (ProjectView *project_view = findProject(diagram_project)) {
1997 			project_view -> moveDiagramUp(diagram);
1998 		}
1999 	}
2000 }
2001 
2002 /**
2003 	Change l'ordre des schemas d'un projet, en decalant le schema vers le bas /
2004 	la droite
2005 	@param diagram Schema a decaler vers le bas / la droite
2006 */
moveDiagramDown(Diagram * diagram)2007 void QETDiagramEditor::moveDiagramDown(Diagram *diagram) {
2008 	if (!diagram) return;
2009 
2010 	// recupere le projet contenant le schema
2011 	if (QETProject *diagram_project = diagram -> project()) {
2012 		if (diagram_project -> isReadOnly()) return;
2013 
2014 		// recupere la vue sur ce projet
2015 		if (ProjectView *project_view = findProject(diagram_project)) {
2016 			project_view -> moveDiagramDown(diagram);
2017 		}
2018 	}
2019 }
2020 
2021 /**
2022 	Change l'ordre des schemas d'un projet, en decalant le schema vers le haut /
2023 	la gauche en position 0
2024 	@param diagram Schema a decaler vers le haut / la gauche en position 0
2025  */
moveDiagramUpTop(Diagram * diagram)2026 void QETDiagramEditor::moveDiagramUpTop(Diagram *diagram) {
2027 	if (!diagram) return;
2028 
2029 	// recupere le projet contenant le schema
2030 	if (QETProject *diagram_project = diagram -> project()) {
2031 		if (diagram_project -> isReadOnly()) return;
2032 
2033 		// recupere la vue sur ce projet
2034 		if (ProjectView *project_view = findProject(diagram_project)) {
2035 			project_view -> moveDiagramUpTop(diagram);
2036 		}
2037 	}
2038 }
2039 
2040 
2041 /**
2042 	Change l'ordre des schemas d'un projet, en decalant le schema vers le haut /
2043 	la gauche x10
2044 	@param diagram Schema a decaler vers le haut / la gauche x10
2045 */
moveDiagramUpx10(Diagram * diagram)2046 void QETDiagramEditor::moveDiagramUpx10(Diagram *diagram) {
2047 	if (!diagram) return;
2048 
2049 	// recupere le projet contenant le schema
2050 	if (QETProject *diagram_project = diagram -> project()) {
2051 		if (diagram_project -> isReadOnly()) return;
2052 
2053 		// recupere la vue sur ce projet
2054 		if (ProjectView *project_view = findProject(diagram_project)) {
2055 			project_view -> moveDiagramUpx10(diagram);
2056 		}
2057 	}
2058 }
2059 
2060 /**
2061 	Change l'ordre des schemas d'un projet, en decalant le schema vers le bas /
2062 	la droite x10
2063 	@param diagram Schema a decaler vers le bas / la droite x10
2064 */
moveDiagramDownx10(Diagram * diagram)2065 void QETDiagramEditor::moveDiagramDownx10(Diagram *diagram) {
2066 	if (!diagram) return;
2067 
2068 	// recupere le projet contenant le schema
2069 	if (QETProject *diagram_project = diagram -> project()) {
2070 		if (diagram_project -> isReadOnly()) return;
2071 
2072 		// recupere la vue sur ce projet
2073 		if (ProjectView *project_view = findProject(diagram_project)) {
2074 			project_view -> moveDiagramDownx10(diagram);
2075 		}
2076 	}
2077 }
2078 
reloadOldElementPanel()2079 void QETDiagramEditor::reloadOldElementPanel() {
2080 	pa->reloadAndFilter();
2081 }
2082 
2083 /**
2084 	Supprime le schema courant du projet courant
2085 */
removeDiagramFromProject()2086 void QETDiagramEditor::removeDiagramFromProject() {
2087 	if (ProjectView *current_project = currentProjectView()) {
2088 		if (DiagramView *current_diagram = current_project -> currentDiagram()) {
2089 			bool isFolioList = false;
2090 
2091 			// if diagram to remove is a "folio list sheet", then set a flag.
2092 			if (dynamic_cast<DiagramFolioList *>(current_diagram -> diagram()))
2093 				isFolioList = true;
2094 
2095 			current_project -> removeDiagram(current_diagram);
2096 
2097 			// if the removed diagram was a folio sheet, then delete all the remaining folio sheets also.
2098 			if (isFolioList) {
2099 				foreach (DiagramView *diag, current_project -> diagram_views()) {
2100 					if (dynamic_cast<DiagramFolioList *>(diag -> diagram())) {
2101 						current_project -> removeDiagram(diag);
2102 					}
2103 				}
2104 
2105 			  // else if after diagram removal, the total diagram quantity becomes a factor of 58, then
2106 			  // remove one (last) folio sheet.
2107 			} else if (current_project -> diagram_views().size() % 58 == 0) {
2108 				foreach (DiagramView *diag, current_project -> diagram_views()) {
2109 					DiagramFolioList *ptr = dynamic_cast<DiagramFolioList *>(diag -> diagram());
2110 					if (ptr && ptr -> getId() == current_project -> project() -> getFolioSheetsQuantity() - 1) {
2111 						current_project -> removeDiagram(diag);
2112 					}
2113 				}
2114 			}
2115 		}
2116 	}
2117 }
2118 
2119 /**
2120  * @brief QETDiagramEditor::diagramWasAdded
2121  * Manage the adding of diagram view in a project
2122  * @param dv, added diagram view
2123  */
diagramWasAdded(DiagramView * dv)2124 void QETDiagramEditor::diagramWasAdded(DiagramView *dv)
2125 {
2126 	connect(dv, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
2127 	connect(dv, SIGNAL(modeChanged()),      this, SLOT(slot_updateModeActions()));
2128 }
2129 
2130 /**
2131  * @brief QETDiagramEditor::findElementInPanel
2132  * Find the item for @location in the element panel
2133  * @param location
2134  */
findElementInPanel(const ElementsLocation & location)2135 void QETDiagramEditor::findElementInPanel(const ElementsLocation &location)
2136 {
2137 	m_element_collection_widget->setCurrentLocation(location);
2138 }
2139 
2140 /**
2141 	Lance l'editeur d'element pour l'element filename
2142 	@param location Emplacement de l'element a editer
2143 */
editElementInEditor(const ElementsLocation & location)2144 void QETDiagramEditor::editElementInEditor(const ElementsLocation &location) {
2145 	QETApp::instance() -> openElementLocations(QList<ElementsLocation>() << location);
2146 }
2147 
2148 /**
2149 	Launch an element editor to edit the selected element in the current
2150 	diagram view.
2151 */
editSelectedElementInEditor()2152 void QETDiagramEditor::editSelectedElementInEditor() {
2153 	if (Element *selected_element = currentElement()) {
2154 		editElementInEditor(selected_element -> location());
2155 	}
2156 }
2157 
2158 /**
2159 	Show the error message contained in \a result.
2160 */
showError(const QETResult & result)2161 void QETDiagramEditor::showError(const QETResult &result) {
2162 	if (result.isOk()) return;
2163 	showError(result.errorMessage());
2164 }
2165 
2166 /**
2167 	Show the \a error message.
2168 */
showError(const QString & error)2169 void QETDiagramEditor::showError(const QString &error) {
2170 	if (error.isEmpty()) return;
2171 	QET::QetMessageBox::critical(this, tr("Erreur", "message box title"), error);
2172 }
2173 
2174 /**
2175  * @brief QETDiagramEditor::subWindowActivated
2176  * Slot used to update menu and undo stack when subwindows of MDIarea was activated
2177  * @param subWindows
2178  */
subWindowActivated(QMdiSubWindow * subWindows)2179 void QETDiagramEditor::subWindowActivated(QMdiSubWindow *subWindows)
2180 {
2181 	Q_UNUSED(subWindows);
2182 
2183 	slot_updateActions();
2184 	slot_updateWindowsMenu();
2185 }
2186 
2187 /**
2188  * @brief QETDiagramEditor::selectionChanged
2189  * This slot is called when a diagram selection was changed.
2190  */
selectionChanged()2191 void QETDiagramEditor::selectionChanged()
2192 {
2193 	slot_updateComplexActions();
2194 
2195 	DiagramView *dv = currentDiagramView();
2196 	if (dv && dv->diagram())
2197 		m_selection_properties_editor->setDiagram(dv->diagram());
2198 }
2199 
2200 
2201 /**
2202  * @brief QETDiagramEditor::generateTerminalBlock
2203  */
generateTerminalBlock()2204 void QETDiagramEditor::generateTerminalBlock()
2205 {
2206 	bool success;
2207 	QProcess *process = new QProcess(qApp);
2208 
2209 		// If launched under control:
2210 		//connect(process, SIGNAL(errorOcurred(int error)), this, SLOT(slot_generateTerminalBlock_error()));
2211 		//process->start("qet_tb_generator");
2212 
2213 #ifdef Q_OS_MAC
2214 	if (openedProjects().count()){
2215 		success = process->startDetached("/Library/Frameworks/Python.framework/Versions/3.5/bin/qet_tb_generator", {(QETDiagramEditor::currentProjectView()->project()->filePath())});
2216 	}
2217 	else  {
2218 		success = process->startDetached("/Library/Frameworks/Python.framework/Versions/3.5/bin/qet_tb_generator");
2219 	}
2220 #else
2221 	if (openedProjects().count()){
2222 		success = process->startDetached("qet_tb_generator", {(QETDiagramEditor::currentProjectView()->project()->filePath())});
2223 	}
2224 	else  {
2225 		success = process->startDetached("qet_tb_generator");
2226 	}
2227 
2228 #endif
2229 	if ( !success ) {
2230 	#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64)
2231 		QMessageBox::warning(nullptr,
2232 							 tr("Error launching qet_tb_generator plugin"),
2233 							 QObject::tr("To install the plugin qet_tb_generator"
2234 								 "<br>"
2235 								 "Visit :"
2236 								 "<br>"
2237 								 "<a href='https://pypi.python.org/pypi/qet-tb-generator'>qet-tb-generator</a>"
2238 								 "<br>"
2239 								"Requires python 3.5 or above."
2240 								"<br>"
2241 								"<B>""<U>"
2242 								" First install on Windows"
2243 								"</B>""</U>"
2244 								 "<br>"
2245 								"1. Install, if required, python 3.5 or above"
2246 								 "<br>"
2247 								" Visit :"
2248 								 "<br>"
2249 								"<a href='https://www.python.org/downloads/'>python.org</a>"
2250 								 "<br>"
2251 								"2. pip install qet_tb_generator"
2252 								 "<br>"
2253 								 "<B>""<U>"
2254 								" Update on Windows"
2255 								"</B>""</U>"
2256 								 "<br>"
2257 								"python -m pip install --upgrade qet_tb_generator"
2258 								 "<br>"
2259 								">>user could launch in a terminal this script in this directory"
2260 								 "<br>"
2261 								" C:\\users\\XXXX\\AppData\\Local\\Programs\\Python\\Python36-32\\Scripts   "
2262 								 "<br>"
2263 								));
2264 	}
2265 }
2266 #elif defined(Q_OS_MAC)
2267 		QMessageBox::warning(nullptr,
2268 							 tr("Error launching qet_tb_generator plugin"),
2269 							 QObject::tr("To install the plugin qet_tb_generator"
2270 							 "<br>"
2271 							 "Visit  :"
2272 							 "<br>"
2273 							 "<a href='https://pypi.python.org/pypi/qet-tb-generator'>qet-tb-generator</a>"
2274 							 "<br>"
2275 							 "<B>""<U>"
2276 								" First install on macOSX"
2277 							 "</B>""</U>"
2278 								"<br>"
2279 								"1. Install, if required, python 3.5 "
2280 								"<br>"
2281 								" Visit :"
2282 								"<br>"
2283 								"<a href='https://qelectrotech.org/forum/viewtopic.php?pid=5674#p5674'>howto</a>"
2284 								"<br>"
2285 								"2. pip3 install qet_tb_generator"
2286 								"<br>"
2287 								"<B>""<U>"
2288 								" Update on macOSX"
2289 								"</B>""</U>"
2290 								"<br>"
2291 								" pip3 install --upgrade qet_tb_generator"
2292 								"<br>"
2293 								));
2294 	}
2295 }
2296 
2297 #else
2298 		QMessageBox::warning(nullptr,
2299 							 tr("Error launching qet_tb_generator plugin"),
2300 							 QObject::tr("To install the plugin qet_tb_generator"
2301 								 "<br>"
2302 								 "Visit : "
2303 								 "<br>"
2304 								 "<a href='https://pypi.python.org/pypi/qet-tb-generator'>qet-tb-generator</a>"
2305 								 "<br>"
2306 								 "<br>"
2307 								 "Requires python 3.5 or above."
2308 								 "<br>"
2309 								"<br>"
2310 								"<B>""<U>"
2311 								" First install on Linux"
2312 								"</B>""</U>"
2313 								"<br>"
2314 								"1. check you have pip3 installed: pip3 --version"
2315 								"<br>"
2316 								"If not install with: sudo apt-get install python3-pip"
2317 								"<br>"
2318 								"2. Install the program: sudo pip3 install qet_tb_generator"
2319 								"<br>"
2320 								"3. Run the program: qet_tb_generator"
2321 								"<br>"
2322 								"<br>"
2323 								"<B>""<U>"
2324 								" Update on Linux"
2325 								"</B>""</U>"
2326 								"<br>"
2327 								"sudo pip3 install --upgrade qet_tb_generator"
2328 								"<br>"
2329 								));
2330 	}
2331 }
2332 
2333 #endif
2334 
2335