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