QElectroTech  0.70
qetelementeditor.cpp
Go to the documentation of this file.
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 "qetelementeditor.h"
19 #include "qet.h"
20 #include "qetapp.h"
21 #include "elementscene.h"
22 #include "elementview.h"
23 #include "customelementpart.h"
24 #include "newelementwizard.h"
25 #include "elementitemeditor.h"
26 #include "elementdialog.h"
27 #include "recentfiles.h"
28 #include "qeticons.h"
29 #include "qetmessagebox.h"
30 #include "editorcommands.h"
31 
32 // editeurs de primitives
33 #include "arceditor.h"
34 #include "ellipseeditor.h"
35 #include "lineeditor.h"
36 #include "polygoneditor.h"
37 #include "rectangleeditor.h"
38 #include "terminaleditor.h"
39 #include "texteditor.h"
40 #include "partterminal.h"
41 #include "styleeditor.h"
42 #include "dynamictextfieldeditor.h"
43 
44 #include "eseventaddline.h"
45 #include "eseventaddrect.h"
46 #include "eseventaddellipse.h"
47 #include "eseventaddpolygon.h"
48 #include "eseventaddarc.h"
49 #include "eseventaddtext.h"
50 #include "eseventaddterminal.h"
52 
53 #include <QMessageBox>
54 #include <QTextStream>
55 #include <QFileDialog>
56 #include <QFile>
57 #include <QModelIndex>
58 #include <utility>
59 
60 /*
61  Nombre maximum de primitives affichees par la "liste des parties"
62  Au-dela, un petit message est affiche, indiquant que ce nombre a ete depasse
63  et que la liste ne sera donc pas mise a jour.
64 */
65 #define QET_MAX_PARTS_IN_ELEMENT_EDITOR_LIST 200
66 
72  QETMainWindow(parent),
73  read_only(false),
74  min_title(tr("QElectroTech - Éditeur d'élément", "window title")),
75  opened_from_file(false)
76 {
77  setWindowTitle(min_title);
78  setWindowIcon(QET::Icons::QETLogo);
79 
81  setupActions();
82  setupMenus();
83 
84  // la fenetre est maximisee par defaut
85  setMinimumSize(QSize(500, 350));
86  setWindowState(Qt::WindowMaximized);
87 
88  // lecture des parametres
89  readSettings();
91 
92  // affichage
93  show();
94 }
95 
98  /*
99  retire le widget d'edition de primitives affiche par le dock
100  cela evite qu'il ne soit supprime par son widget parent
101  */
102  clearToolsDock();
103 
104  // supprime les editeurs de primitives
105  qDeleteAll(m_editors.begin(), m_editors.end());
106  m_editors.clear();
107 }
108 
115 {
116  location_ = el;
117  opened_from_file = false;
120 }
121 
125 void QETElementEditor::setFileName(const QString &fn) {
126  filename_ = fn;
127  opened_from_file = true;
128  // modifie le mode lecture seule si besoin
129  bool must_be_read_only = !QFileInfo(filename_).isWritable();
130  if (isReadOnly() != must_be_read_only) {
131  setReadOnly(must_be_read_only);
132  }
134 }
135 
141  new_element = new QAction(QET::Icons::DocumentNew, tr("&Nouveau"), this);
142  open = new QAction(QET::Icons::FolderOpen, tr("&Ouvrir"), this);
143  open_file = new QAction(QET::Icons::FolderOpen, tr("&Ouvrir depuis un fichier"), this);
144  open_dxf = new QAction(QET::Icons::RunDxf, tr("&Lancer le plugin convertisseur DXF"), this);
145  save = new QAction(QET::Icons::DocumentSave, tr("&Enregistrer"), this);
146  save_as = new QAction(QET::Icons::DocumentSaveAs, tr("Enregistrer sous"), this);
147  save_as_file = new QAction(QET::Icons::DocumentSaveAs, tr("Enregistrer dans un fichier"), this);
148  reload = new QAction(QET::Icons::ViewRefresh, tr("Recharger"), this);
149  quit = new QAction(QET::Icons::ApplicationExit, tr("&Quitter"), this);
150  selectall = new QAction(QET::Icons::EditSelectAll, tr("Tout sélectionner"), this);
151  deselectall = new QAction(QET::Icons::EditSelectNone, tr("Désélectionner tout"), this);
152  cut = new QAction(QET::Icons::EditCut, tr("Co&uper"), this);
153  copy = new QAction(QET::Icons::EditCopy, tr("Cop&ier"), this);
154  paste = new QAction(QET::Icons::EditPaste, tr("C&oller"), this);
155  paste_in_area = new QAction(QET::Icons::EditPaste, tr("C&oller dans la zone..."), this);
156  paste_from_file = new QAction(QET::Icons::XmlTextFile, tr("un fichier"), this);
157  paste_from_elmt = new QAction(QET::Icons::Element, tr("un élément"), this);
158  inv_select = new QAction(QET::Icons::EditSelectInvert, tr("Inverser la sélection"), this);
159  edit_delete = new QAction(QET::Icons::EditDelete, tr("&Supprimer"), this);
160  edit_names = new QAction(QET::Icons::Names, tr("Éditer le nom et les traductions de l'élément"), this);
161  edit_author = new QAction(QET::Icons::UserInformations, tr("Éditer les informations sur l'auteur"), this);
162  m_edit_properties = new QAction(QET::Icons::ElementEdit, tr("Éditer les propriétés de l'élément"), this);
163 
164 #if defined(Q_OS_WIN32) || defined(Q_OS_WIN64)
165  open_dxf -> setStatusTip(tr("To install the plugin DXFtoQET\nVisit https://download.tuxfamily.org/qet/builds/dxf_to_elmt/\n"
166  "\n"
167  ">> Install on Windows\n"
168  "Put DXFtoQET.exe binary on C:\\Users\\user_name\\AppData\\Roaming\\qet\\ directory \n"
169  ));
170 #elif defined(Q_OS_MAC)
171  open_dxf -> setStatusTip(tr("To install the plugin DXFtoQET\nVisit https://download.tuxfamily.org/qet/builds/dxf_to_elmt/\n"
172  "\n"
173  ">> Install on macOSX\n"
174  "Put DXFtoQET.app binary on /Users/user_name/.qet/ directory \n"
175  ));
176 #else
177  open_dxf -> setStatusTip(tr("To install the plugin DXFtoQET\nVisit https://download.tuxfamily.org/qet/builds/dxf_to_elmt/\n"
178  "\n"
179  ">> Install on Linux\n"
180  "Put DXFtoQET binary on your /home/user_name/.qet/ directory\n"
181  "make it executable : chmod +x ./DXFtoQET\n"
182  ));
183 #endif
184 
185  open_dxf -> setWhatsThis (tr("To install the plugin DXFtoQET\nVisit https://download.tuxfamily.org/qet/builds/dxf_to_elmt/\n"
186  "\n"
187  ">> Install on Linux\n"
188  "Put DXFtoQET binary on your /home/user_name/.qet/ directory\n"
189  "make it executable : chmod +x ./DXFtoQET\n"
190  ">> Install on Windows\n"
191  "Put DXFtoQET.exe binary on C:\\Users\\user_name\\AppData\\Roaming\\qet\\ directory \n"
192  "\n"
193  ">> Install on macOSX\n"
194  "Put DXFtoQET.app binary on /Users/user_name/.qet/ directory \n"
195  ));
196 
197  undo = m_elmt_scene -> undoStack().createUndoAction(this, tr("Annuler"));
198  redo = m_elmt_scene -> undoStack().createRedoAction(this, tr("Refaire"));
199  undo -> setIcon(QET::Icons::EditUndo);
200  redo -> setIcon(QET::Icons::EditRedo);
201  undo -> setShortcuts(QKeySequence::Undo);
202  redo -> setShortcuts(QKeySequence::Redo);
203 
204  new_element -> setShortcut(QKeySequence::New);
205  open -> setShortcut(QKeySequence::Open);
206  open_file -> setShortcut(tr("Ctrl+Shift+O"));
207  save -> setShortcut(QKeySequence::Save);
208  save_as_file -> setShortcut(tr("Ctrl+Shift+S"));
209  quit -> setShortcut(QKeySequence(tr("Ctrl+Q")));
210  selectall -> setShortcut(QKeySequence::SelectAll);
211  deselectall -> setShortcut(QKeySequence(tr("Ctrl+Shift+A")));
212  inv_select -> setShortcut(QKeySequence(tr("Ctrl+I")));
213  cut -> setShortcut(QKeySequence::Cut);
214  copy -> setShortcut(QKeySequence::Copy);
215  paste -> setShortcut(QKeySequence::Paste);
216  paste_in_area -> setShortcut(tr("Ctrl+Shift+V"));
217 #ifndef Q_OS_MAC
218  edit_delete -> setShortcut(QKeySequence(Qt::Key_Delete));
219 #else
220  edit_delete -> setShortcut(QKeySequence(tr("Backspace")));
221 #endif
222 
223  edit_names -> setShortcut(QKeySequence(tr("Ctrl+E")));
224  edit_author -> setShortcut(tr("Ctrl+Y"));
225 
226  connect(new_element, SIGNAL(triggered()), this, SLOT(slot_new()));
227  connect(open, SIGNAL(triggered()), this, SLOT(slot_open()));
228  connect(open_dxf, SIGNAL(triggered()), this, SLOT(slot_openDxf()));
229  connect(open_file, SIGNAL(triggered()), this, SLOT(slot_openFile()));
230  connect(save, SIGNAL(triggered()), this, SLOT(slot_save()));
231  connect(save_as, SIGNAL(triggered()), this, SLOT(slot_saveAs()));
232  connect(save_as_file, SIGNAL(triggered()), this, SLOT(slot_saveAsFile()));
233  connect(reload, SIGNAL(triggered()), this, SLOT(slot_reload()));
234  connect(quit, SIGNAL(triggered()), this, SLOT(close()));
235  connect(selectall, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_selectAll()));
236  connect(deselectall, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_deselectAll()));
237  connect(inv_select, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_invertSelection()));
238  connect(cut, SIGNAL(triggered()), m_view, SLOT(cut()));
239  connect(copy, SIGNAL(triggered()), m_view, SLOT(copy()));
240  connect(paste, SIGNAL(triggered()), m_view, SLOT(paste()));
241  connect(paste_in_area, SIGNAL(triggered()), m_view, SLOT(pasteInArea()));
242  connect(paste_from_file, SIGNAL(triggered()), this, SLOT(pasteFromFile()));
243  connect(paste_from_elmt, SIGNAL(triggered()), this, SLOT(pasteFromElement()));
244  connect(edit_delete, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_delete()));
245  connect(edit_names, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_editNames()));
246  connect(edit_author, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_editAuthorInformations()));
247  connect(m_edit_properties, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_editProperties()));
248 
249  //Action related to change depth of primitive
251 
252  connect(m_depth_action_group, &QActionGroup::triggered, [this](QAction *action) {
253  this->elementScene()->undoStack().push(new ChangeZValueCommand(this->elementScene(), action->data().value<QET::DepthOption>()));
254  emit(this->elementScene()->partsZValueChanged());
255  });
256 
257  depth_toolbar = addToolBar(tr("Profondeur", "toolbar title"));
258  depth_toolbar -> setObjectName("depth_toolbar");
259  depth_toolbar -> addActions(m_depth_action_group -> actions());
260  addToolBar(Qt::TopToolBarArea, depth_toolbar);
261 
262 
263  /*
264  * Action related to zoom
265  */
266  m_zoom_ag = new QActionGroup(this);
267 
268  QAction *zoom_in = new QAction(QET::Icons::ZoomIn, tr("Zoom avant"), m_zoom_ag);
269  QAction *zoom_out = new QAction(QET::Icons::ZoomOut, tr("Zoom arrière"), m_zoom_ag);
270  QAction *zoom_fit = new QAction(QET::Icons::ZoomFitBest, tr("Zoom adapté"), m_zoom_ag);
271  QAction *zoom_reset = new QAction(QET::Icons::ZoomOriginal, tr("Pas de zoom"), m_zoom_ag);
272 
273  zoom_in -> setShortcut(QKeySequence::ZoomIn);
274  zoom_out -> setShortcut(QKeySequence::ZoomOut);
275  zoom_fit -> setShortcut(QKeySequence(tr("Ctrl+9")));
276  zoom_reset -> setShortcut(QKeySequence(tr("Ctrl+0")));
277 
278  connect(zoom_in, SIGNAL(triggered()), m_view, SLOT(zoomIn() ));
279  connect(zoom_out, SIGNAL(triggered()), m_view, SLOT(zoomOut() ));
280  connect(zoom_fit, SIGNAL(triggered()), m_view, SLOT(zoomFit() ));
281  connect(zoom_reset, SIGNAL(triggered()), m_view, SLOT(zoomReset() ));
282 
283 
284  /*
285  * Action related to primitive creation
286  */
287  connect (m_elmt_scene, SIGNAL(partsAdded()), this, SLOT(UncheckAddPrimitive()));
288  parts = new QActionGroup(this);
289 
290  QAction *add_line = new QAction(QET::Icons::PartLine, tr("Ajouter une ligne"), parts);
291  QAction *add_rectangle = new QAction(QET::Icons::PartRectangle, tr("Ajouter un rectangle"), parts);
292  QAction *add_ellipse = new QAction(QET::Icons::PartEllipse, tr("Ajouter une ellipse"), parts);
293  QAction *add_polygon = new QAction(QET::Icons::PartPolygon, tr("Ajouter un polygone"), parts);
294  QAction *add_text = new QAction(QET::Icons::PartText, tr("Ajouter du texte"), parts);
295  QAction *add_arc = new QAction(QET::Icons::PartArc, tr("Ajouter un arc de cercle"), parts);
296  QAction *add_terminal = new QAction(QET::Icons::Terminal, tr("Ajouter une borne"), parts);
297  QAction *add_dynamic_text_field = new QAction(QET::Icons::PartTextField, tr("Ajouter un champ texte dynamique"), parts);
298 
299  foreach (QAction *action, parts -> actions()) action -> setCheckable(true);
300 
301  connect(add_line, SIGNAL(triggered()), this, SLOT(addLine() ));
302  connect(add_rectangle, SIGNAL(triggered()), this, SLOT(addRect() ));
303  connect(add_ellipse, SIGNAL(triggered()), this, SLOT(addEllipse() ));
304  connect(add_polygon, SIGNAL(triggered()), this, SLOT(addPolygon() ));
305  connect(add_text, SIGNAL(triggered()), this, SLOT(addText() ));
306  connect(add_arc, SIGNAL(triggered()), this, SLOT(addArc() ));
307  connect(add_terminal, SIGNAL(triggered()), this, SLOT(addTerminal() ));
308  connect(add_dynamic_text_field, &QAction::triggered, this, &QETElementEditor::addDynamicTextField);
309 
310  add_polygon ->setStatusTip(tr("Double-click pour terminer la forme, Click droit pour annuler le dernier point"));
311  add_text ->setStatusTip(tr("Ajouter un texte d'élément non éditable dans les schémas"));
312  add_dynamic_text_field ->setStatusTip(tr("Ajouter un texte d'élément pouvant être édité dans les schémas"));
313 
314  parts_toolbar = addToolBar(tr("Parties", "toolbar title"));
315  parts_toolbar -> setAllowedAreas(Qt::AllToolBarAreas);
316  parts_toolbar -> setObjectName("parts");
317  parts_toolbar -> addActions(parts -> actions());
318  addToolBar(Qt::LeftToolBarArea, parts_toolbar);
319 
320 
321  main_toolbar = new QToolBar(tr("Outils", "toolbar title"), this);
322  main_toolbar -> setObjectName("main_toolbar");
323  view_toolbar = new QToolBar(tr("Affichage", "toolbar title"), this);
324  view_toolbar -> setObjectName("display");
325  element_toolbar = new QToolBar(tr("Élément", "toolbar title"), this);
326  element_toolbar -> setObjectName("element_toolbar");
327 
328  main_toolbar -> addAction(new_element);
329  main_toolbar -> addAction(open);
330  main_toolbar -> addAction(save);
331  main_toolbar -> addAction(save_as);
332  main_toolbar -> addAction(reload);
333  main_toolbar -> addSeparator();
334  main_toolbar -> addAction(undo);
335  main_toolbar -> addAction(redo);
336  main_toolbar -> addSeparator();
337  main_toolbar -> addAction(edit_delete);
338 
339  view_toolbar -> addAction(zoom_fit);
340  view_toolbar -> addAction(zoom_reset);
341 
342  element_toolbar -> addAction(edit_names);
343  element_toolbar -> addAction(m_edit_properties);
344 
345  addToolBar(Qt::TopToolBarArea, main_toolbar);
346  addToolBar(Qt::TopToolBarArea, view_toolbar);
347  addToolBar(Qt::TopToolBarArea, element_toolbar);
348 
349  connect(m_elmt_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updateInformations()), Qt::QueuedConnection);
350  connect(m_elmt_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updateMenus()));
351  connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slot_updateMenus()));
352  connect(&(m_elmt_scene -> undoStack()), SIGNAL(cleanChanged(bool)), this, SLOT(slot_updateMenus()));
353  connect(&(m_elmt_scene -> undoStack()), SIGNAL(cleanChanged(bool)), this, SLOT(slot_updateTitle()));
354 
355  // Annuler ou refaire une action met a jour la liste des primitives ; cela sert notamment pour les
356  // ajouts et suppressions de primitives ainsi que pour les actions entrainant un change
357  connect(&(m_elmt_scene -> undoStack()), SIGNAL(indexChanged(int)), this, SLOT(slot_updatePartsList()));
358 
359  // Annuler ou refaire une action met a jour les informations affichees sur les primitives selectionnees,
360  // celles-ci etant potentiellement impactees
361  connect(&(m_elmt_scene -> undoStack()), SIGNAL(indexChanged(int)), this, SLOT(slot_updateInformations()));
362 }
363 
368  file_menu = new QMenu(tr("&Fichier"), this);
369  edit_menu = new QMenu(tr("&Édition"), this);
370  display_menu = new QMenu(tr("Afficha&ge"), this);
371  tools_menu = new QMenu(tr("O&utils"), this);
372 
373  file_menu -> setTearOffEnabled(true);
374  edit_menu -> setTearOffEnabled(true);
375  display_menu -> setTearOffEnabled(true);
376  tools_menu -> setTearOffEnabled(true);
377 
378  file_menu -> addAction(new_element);
379  file_menu -> addAction(open);
380  file_menu -> addAction(open_file);
381  file_menu -> addAction(open_dxf);
382  QMenu *recentfile = file_menu -> addMenu(QET::Icons::DocumentOpenRecent, tr("&Récemment ouverts"));
383  recentfile->addActions(QETApp::elementsRecentFiles()->menu()->actions());
384  connect(QETApp::elementsRecentFiles(), SIGNAL(fileOpeningRequested(const QString &)), this, SLOT(openRecentFile(const QString &)));
385  file_menu -> addAction(save);
386  file_menu -> addAction(save_as);
387  file_menu -> addAction(save_as_file);
388  file_menu -> addSeparator();
389  file_menu -> addAction(reload);
390  file_menu -> addSeparator();
391  file_menu -> addAction(quit);
392 
393  paste_from_menu = new QMenu(tr("Coller depuis..."));
395  paste_from_menu -> addAction(paste_from_file);
396  paste_from_menu -> addAction(paste_from_elmt);
397 
398  edit_menu -> addAction(undo);
399  edit_menu -> addAction(redo);
400  edit_menu -> addSeparator();
401  edit_menu -> addAction(selectall);
402  edit_menu -> addAction(deselectall);
403  edit_menu -> addAction(inv_select);
404  edit_menu -> addSeparator();
405  edit_menu -> addAction(cut);
406  edit_menu -> addAction(copy);
407  edit_menu -> addAction(paste);
408  edit_menu -> addAction(paste_in_area);
409  edit_menu -> addMenu(paste_from_menu);
410  edit_menu -> addSeparator();
411  edit_menu -> addAction(edit_delete);
412  edit_menu -> addSeparator();
413  edit_menu -> addAction(edit_names);
414  edit_menu -> addAction(edit_author);
415  edit_menu -> addAction(m_edit_properties);
416  edit_menu -> addSeparator();
417  edit_menu -> addActions(m_depth_action_group -> actions());
418 
419  display_menu -> addActions(m_zoom_ag -> actions());
420 
424 }
425 
432 void QETElementEditor::contextMenu(QPoint p, QList<QAction *> actions)
433 {
434  QMenu menu(this);
435  menu.addActions(std::move(actions));
436  menu.addSeparator();
437  menu.addAction(undo);
438  menu.addAction(redo);
439  menu.addAction(selectall);
440  menu.addAction(deselectall);
441  menu.addAction(inv_select);
442  menu.addSeparator();
443  menu.addAction(edit_delete);
444  menu.addAction(cut);
445  menu.addAction(copy);
446  menu.addSeparator();
447  menu.addAction(paste);
448  menu.addAction(paste_in_area);
449  menu.addMenu(paste_from_menu);
450  menu.addSeparator();
451  menu.addActions(m_depth_action_group -> actions());
452 
453  //Remove from the context menu the actions which are disabled.
454  const QList<QAction *>menu_actions = menu.actions();
455  for(QAction *action : menu_actions)
456  {
457  if(!action->isEnabled())
458  menu.removeAction(action);
459  }
460  menu.exec(p);
461 }
462 
463 
468  bool selected_items = !read_only && !m_elmt_scene -> selectedItems().isEmpty();
469  bool clipboard_elmt = !read_only && ElementScene::clipboardMayContainElement();
470 
471  // actions dependant seulement de l'etat "lecture seule" de l'editeur
472  foreach (QAction *action, parts -> actions()) {
473  action -> setEnabled(!read_only);
474  }
475  selectall -> setEnabled(!read_only);
476  inv_select -> setEnabled(!read_only);
477  paste_from_file -> setEnabled(!read_only);
478  paste_from_elmt -> setEnabled(!read_only);
479  m_parts_list -> setEnabled(!read_only);
480 
481  // Action enabled if primitive selected
482  deselectall -> setEnabled(selected_items);
483  cut -> setEnabled(selected_items);
484  copy -> setEnabled(selected_items);
485  edit_delete -> setEnabled(selected_items);
486  foreach (QAction *action, m_depth_action_group -> actions())
487  action->setEnabled(selected_items);
488 
489  // actions dependant du contenu du presse-papiers
490  paste -> setEnabled(clipboard_elmt);
491  paste_in_area -> setEnabled(clipboard_elmt);
492 
493  // actions dependant de l'etat de la pile d'annulation
494  save -> setEnabled(!read_only && !m_elmt_scene -> undoStack().isClean());
495  undo -> setEnabled(!read_only && m_elmt_scene -> undoStack().canUndo());
496  redo -> setEnabled(!read_only && m_elmt_scene -> undoStack().canRedo());
497 }
498 
503  QString title = min_title;
504  title += " - " + m_elmt_scene -> names().name() + " ";
505  if (!filename_.isEmpty() || !location_.isNull()) {
506  if (!m_elmt_scene -> undoStack().isClean()) title += tr("[Modifié]", "window title tag");
507  }
508  if (isReadOnly()) title += tr(" [lecture seule]", "window title tag");
509  setWindowTitle(title);
510 }
511 
516 {
517  // editeur
518  m_elmt_scene = new ElementScene(this, this);
519  m_view = new ElementView(m_elmt_scene, this);
521  setCentralWidget(m_view);
522 
523  // widget par defaut dans le QDockWidget
524  m_default_informations = new QLabel();
525 
526  // ScrollArea pour accueillir un widget d'edition (change a la volee)
527 // m_tools_dock_scroll_area = new QScrollArea();
528 // m_tools_dock_scroll_area -> setFrameStyle(QFrame::NoFrame);
529 // m_tools_dock_scroll_area -> setAlignment(Qt::AlignHCenter|Qt::AlignTop);
530 
531  // Pile de widgets pour accueillir les deux widgets precedents
532  m_tools_dock_stack = new QStackedWidget();
533  m_tools_dock_stack -> insertWidget(0, m_default_informations);
534 // m_tools_dock_stack -> insertWidget(1, m_tools_dock_scroll_area);
535 
536  // widgets d'editions pour les parties
537  m_editors["arc"] = new ArcEditor(this);
538  m_editors["ellipse"] = new EllipseEditor(this);
539  m_editors["line"] = new LineEditor(this);
540  m_editors["polygon"] = new PolygonEditor(this);
541  m_editors["rect"] = new RectangleEditor(this);
542  m_editors["terminal"] = new TerminalEditor(this);
543  m_editors["text"] = new TextEditor(this);
544  m_editors["style"] = new StyleEditor(this);
545  m_editors["dynamic_text"] = new DynamicTextFieldEditor(this);
546 
547  // panel sur le cote pour editer les parties
548  m_tools_dock = new QDockWidget(tr("Informations", "dock title"), this);
549  m_tools_dock -> setObjectName("informations");
550  m_tools_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
551  m_tools_dock -> setFeatures(QDockWidget::AllDockWidgetFeatures);
552  //m_tools_dock -> setMinimumWidth(380);
553  addDockWidget(Qt::RightDockWidgetArea, m_tools_dock);
554  m_tools_dock -> setWidget(m_tools_dock_stack);
555 
556  // panel sur le cote pour les annulations
557  m_undo_dock = new QDockWidget(tr("Annulations", "dock title"), this);
558  m_undo_dock -> setObjectName("undo");
559  m_undo_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
560  m_undo_dock -> setFeatures(QDockWidget::AllDockWidgetFeatures);
561  m_undo_dock -> setMinimumWidth(290);
562  addDockWidget(Qt::RightDockWidgetArea, m_undo_dock);
563  QUndoView* undo_view = new QUndoView(&(m_elmt_scene -> undoStack()), this);
564  undo_view -> setEmptyLabel(tr("Aucune modification"));
565  m_undo_dock -> setWidget(undo_view);
566 
567  // panel sur le cote pour la liste des parties
568  m_parts_list = new QListWidget(this);
569  m_parts_list -> setSelectionMode(QAbstractItemView::ExtendedSelection);
570  connect(m_elmt_scene, SIGNAL(partsAdded()), this, SLOT(slot_createPartsList()));
571  connect(m_elmt_scene, SIGNAL(partsRemoved()), this, SLOT(slot_createPartsList()));
572  connect(m_elmt_scene, SIGNAL(partsZValueChanged()), this, SLOT(slot_createPartsList()));
573  connect(m_elmt_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updatePartsList()));
574  connect(m_parts_list, SIGNAL(itemSelectionChanged()), this, SLOT(slot_updateSelectionFromPartsList()));
575  m_parts_dock = new QDockWidget(tr("Parties", "dock title"), this);
576  m_parts_dock -> setObjectName("parts_list");
577  m_parts_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
578  m_parts_dock -> setFeatures(QDockWidget::AllDockWidgetFeatures);
579  m_parts_dock -> setMinimumWidth(290);
580  tabifyDockWidget(m_undo_dock, m_parts_dock);
581  m_parts_dock -> setWidget(m_parts_list);
582 
585 
586  // barre d'etat
587  statusBar() -> showMessage(tr("Éditeur d'éléments", "status bar message"));
588 }
589 
595  m_view -> setDragMode(QGraphicsView::RubberBandDrag);
596 }
597 
602  m_view -> setDragMode(QGraphicsView::NoDrag);
603 }
604 
611 {
612  QList<QGraphicsItem *> selected_qgis = m_elmt_scene -> selectedItems();
613  QList<CustomElementPart *> cep_list;
614  bool style_editable = false;
615 
616  //Test if part are editable by style editor
617  if (selected_qgis.size() >= 2)
618  {
619  style_editable = true;
620  foreach (QGraphicsItem *qgi, selected_qgis)
621  {
622  if (CustomElementPart *cep = dynamic_cast<CustomElementPart *>(qgi))
623  cep_list << cep;
624  else
625  style_editable = false;
626  }
627  if (style_editable)
628  style_editable = StyleEditor::isStyleEditable(cep_list);
629 
630  }
631 
632  if(selected_qgis.size() == 1)
633  {
634  QGraphicsItem *qgi = selected_qgis.first();
635  if (CustomElementPart *selection = dynamic_cast<CustomElementPart *>(qgi))
636  {
637  if (QWidget *widget = m_tools_dock_stack->widget(1))
638  {
639  if (ElementItemEditor *editor = dynamic_cast<ElementItemEditor *>(widget))
640  {
641  if(editor->currentPart() == selection)
642  return;
643  }
644  }
645  }
646  }
647 
648  //There's one selected item
649  if (selected_qgis.size() == 1)
650  {
651  QGraphicsItem *qgi = selected_qgis.first();
652  if (CustomElementPart *selection = dynamic_cast<CustomElementPart *>(qgi))
653  {
654  //The current editor already edit the selected part
655  if (QWidget *widget = m_tools_dock_stack->widget(1))
656  if (ElementItemEditor *editor = dynamic_cast<ElementItemEditor *>(widget))
657  if(editor->currentPart() == selection)
658  return;
659 
660  clearToolsDock();
661  //We add the editor widget
662  QString selection_xml_name = selection -> xmlName();
663  ElementItemEditor *selection_editor = m_editors[selection_xml_name];
664  if (selection_editor)
665  {
666  if (selection_editor->setPart(selection))
667  {
668  m_tools_dock_stack->insertWidget(1, selection_editor);
669  m_tools_dock_stack -> setCurrentIndex(1);
670  }
671  else
672  {
673  qDebug() << "Editor refused part.";
674  }
675  }
676  }
677  }
678  //There's several parts selecteds and all can be edited by style editor.
679  else if (style_editable)
680  {
681  clearToolsDock();
682  ElementItemEditor *selection_editor = m_editors["style"];
683  if (selection_editor)
684  {
685  if (selection_editor -> setParts(cep_list))
686  {
687  m_tools_dock_stack->insertWidget(1, selection_editor);
688  m_tools_dock_stack -> setCurrentIndex(1);
689  }
690  else
691  {
692  qDebug() << "Editor refused part.";
693  }
694  }
695  }
696  //Else we only display the number of selected items
697  else
698  {
699  clearToolsDock();
700  m_default_informations -> setText(tr("%n partie(s) sélectionnée(s).",
701  "",
702  selected_qgis.size()));
703  m_default_informations -> setAlignment(Qt::AlignHCenter | Qt::AlignTop);
704  m_tools_dock_stack -> setCurrentIndex(0);
705  }
706 }
707 
714 {
715  //List of warning and error
716  typedef QPair<QString, QString> QETWarning;
717  QList<QETWarning> warnings;
718  QList<QETWarning> errors;
719 
722  if (!m_elmt_scene -> containsTerminals() && !m_elmt_scene -> elementType().contains("report"))
723  {
724  warnings << qMakePair(
725  tr("Absence de borne", "warning title"),
726  tr(
727  "<br>En l'absence de borne, l'élément ne pourra être"
728  " relié à d'autres éléments par l'intermédiaire de conducteurs.",
729  "warning description"
730  )
731  );
732  }
733 
735  if (m_elmt_scene -> elementType().contains("report"))
736  {
737  int terminal =0;
738 
739  foreach(QGraphicsItem *qgi, m_elmt_scene->items())
740  if (qgraphicsitem_cast<PartTerminal *>(qgi))
741  terminal ++;
742 
744  if (terminal != 1)
745  {
746  errors << qMakePair (tr("Absence de borne"),
747  tr("<br><b>Erreur</b> :"
748  "<br>Les reports de folio doivent posséder une seul borne."
749  "<br><b>Solution</b> :"
750  "<br>Verifier que l'élément ne possède qu'une seul borne"));
751  }
752  }
753 
754  if (!errors.count() && !warnings.count()) return(true);
755 
756  // Display warnings
757  QString dialog_message = tr("La vérification de cet élément a généré", "message box content");
758 
759  if (errors.size())
760  dialog_message += QString(tr(" %n erreur(s)", "errors", errors.size()));
761 
762  if (warnings.size())
763  {
764  if (errors.size())
765  dialog_message += QString (tr(" et"));
766 
767  dialog_message += QString (tr(" %n avertissement(s)", "warnings", warnings.size()));
768  }
769  dialog_message += " :";
770 
771  dialog_message += "<ol>";
772  QList<QETWarning> total = warnings << errors;
773  foreach(QETWarning warning, total) {
774  dialog_message += "<li>";
775  dialog_message += QString(
776  tr("<b>%1</b> : %2", "warning title: warning description")
777  ).arg(warning.first).arg(warning.second);
778  dialog_message += "</li>";
779  }
780  dialog_message += "</ol>";
781 
782  if (errors.size())
783  QMessageBox::critical(this, tr("Erreurs"), dialog_message);
784  else
785  QMessageBox::warning(this, tr("Avertissements"), dialog_message);
786 
787  //if error == 0 that means they are only warning, we return true.
788  if (errors.count() == 0) return(true);
789  return false;
790 }
791 
796 void QETElementEditor::fromFile(const QString &filepath) {
797  bool state = true;
798  QString error_message;
799 
800  // le fichier doit exister
801  QFileInfo infos_file(filepath);
802  if (!infos_file.exists() || !infos_file.isFile()) {
803  state = false;
804  error_message = QString(tr("Le fichier %1 n'existe pas.", "message box content")).arg(filepath);
805  }
806 
807  // le fichier doit etre lisible
808  QFile file(filepath);
809  if (state) {
810  if (!file.open(QIODevice::ReadOnly)) {
811  state = false;
812  error_message = QString(tr("Impossible d'ouvrir le fichier %1.", "message box content")).arg(filepath);
813  }
814  }
815 
816  // le fichier doit etre un document XML
817  QDomDocument document_xml;
818  if (state) {
819  if (!document_xml.setContent(&file)) {
820  state = false;
821  error_message = tr("Ce fichier n'est pas un document XML valide", "message box content");
822  }
823  file.close();
824  }
825 
826  if (!state) {
827  QET::QetMessageBox::critical(this, tr("Erreur", "toolbar title"), error_message);
828  return;
829  }
830 
831  // chargement de l'element
832  m_elmt_scene -> fromXml(document_xml);
834 
835  // gestion de la lecture seule
836  if (!infos_file.isWritable()) {
838  this,
839  tr("Édition en lecture seule", "message box title"),
840  tr("Vous n'avez pas les privilèges nécessaires pour modifier cet élement. Il sera donc ouvert en lecture seule.", "message box content")
841  );
842  setReadOnly(true);
843  } else {
844  setReadOnly(false);
845  }
846 
847  // memorise le fichier
848  setFileName(filepath);
849  QETApp::elementsRecentFiles() -> fileWasOpened(filepath);
851 }
852 
859 bool QETElementEditor::toFile(const QString &fn)
860 {
862  m_elmt_scene->clearSelection();
864 
865  QDomDocument element_xml = m_elmt_scene->toXml();
866  bool writing = QET::writeXmlFile(element_xml, fn);
867  if (!writing) {
869  this,
870  tr("Erreur", "message box title"),
871  tr("Impossible d'écrire dans ce fichier", "message box content")
872  );
873  }
874  return(writing);
875 }
876 
877 
885 {
887  m_elmt_scene->clearSelection();
889 
891  {
893  tr("Erreur", "message box title"),
894  tr("Impossible d'enregistrer l'élément", "message box content"));
895  return(false);
896  }
897  return(true);
898 }
899 
905 bool QETElementEditor::isEditing(const ElementsLocation &provided_location) {
906  if (opened_from_file) {
907  return(
909  filename_,
910  QETApp::realPath(provided_location.toString())
911  )
912  );
913  } else {
914  return(provided_location == location_);
915  }
916 }
917 
923 bool QETElementEditor::isEditing(const QString &provided_filepath) {
924  // determine le chemin canonique de l'element actuelle edite, si applicable
925  QString current_filepath;
926  if (opened_from_file) {
927  current_filepath = filename_;
928  } else {
929  current_filepath = QETApp::realPath(location_.toString());
930  }
931 
932  return(
934  current_filepath,
935  provided_filepath
936  )
937  );
938 }
939 
945  read_only = ro;
946 
947  // active / desactive les interactions avec la scene
948  m_view -> setInteractive(!ro);
949 
951 }
952 
957  return(read_only);
958 }
959 
965  m_elmt_scene -> setEventInterface(new ESEventAddLine(m_elmt_scene));
966 }
967 
973  m_elmt_scene -> setEventInterface(new ESEventAddRect(m_elmt_scene));
974 }
975 
981  m_elmt_scene -> setEventInterface(new ESEventAddEllipse(m_elmt_scene));
982 }
983 
989  m_elmt_scene -> setEventInterface(new ESEventAddPolygon(m_elmt_scene));
990 }
991 
997  m_elmt_scene -> setEventInterface(new ESEventAddArc(m_elmt_scene));
998 }
999 
1005  m_elmt_scene -> setEventInterface(new ESEventAddText(m_elmt_scene));
1006 }
1007 
1013  m_elmt_scene -> setEventInterface(new ESEventAddTerminal(m_elmt_scene));
1014 }
1015 
1022 }
1023 
1029  foreach(QAction *action, parts->actions()) action -> setChecked(false);
1030 }
1031 
1036  NewElementWizard new_element_wizard(this);
1037  new_element_wizard.exec();
1038 }
1039 
1044  // demande le chemin virtuel de l'element a ouvrir a l'utilisateur
1046  if (location.isNull()) return;
1047  QETApp::instance() -> openElementLocations(QList<ElementsLocation>() << location);
1048 }
1049 
1055  // repertoire a afficher initialement dans le dialogue
1056  QString open_dir = filename_.isEmpty() ? QETApp::customElementsDir() : QDir(filename_).absolutePath();
1057 
1058  // demande un nom de fichier a ouvrir a l'utilisateur
1059  QString user_filename = QETElementEditor::getOpenElementFileName(this, open_dir);
1060 
1061  // ouvre l'element
1062  openElement(user_filename);
1063 }
1064 
1071 void QETElementEditor::openRecentFile(const QString &filepath) {
1072  // small hack to prevent all element editors from trying to topen the required
1073  // recent file at the same time
1074  if (qApp -> activeWindow() != this) return;
1075  openElement(filepath);
1076 }
1077 
1082 
1083 #if defined(Q_OS_WIN32) || defined(Q_OS_WIN64)
1084 QString program = (QDir::homePath() + "/Application Data/qet/DXFtoQET.exe");
1085 #elif defined(Q_OS_MAC)
1086 QString program = (QDir::homePath() + "/.qet/DXFtoQET.app");
1087 #else
1088 QString program = (QDir::homePath() + "/.qet/DXFtoQET");
1089 #endif
1090 QStringList arguments;
1091 QProcess *DXF = new QProcess(qApp);
1092 DXF->start(program,arguments);
1093 
1094 }
1095 
1103 void QETElementEditor::openElement(const QString &filepath) {
1104  if (filepath.isEmpty()) return;
1105  // we have to test the file existence here because QETApp::openElementFiles()
1106  // will discard non-existent files through QFileInfo::canonicalFilePath()
1107  if (!QFile::exists(filepath)) {
1109  this,
1110  tr("Impossible d'ouvrir le fichier", "message box title"),
1111  QString(
1112  tr("Il semblerait que le fichier %1 que vous essayez d'ouvrir"
1113  " n'existe pas ou plus.")
1114  ).arg(filepath)
1115  );
1116  }
1117  QETApp::instance() -> openElementFiles(QStringList() << filepath);
1118 }
1119 
1125 {
1126  //If user already edit the element, ask confirmation to reload
1127  if (!m_elmt_scene -> undoStack().isClean())
1128  {
1129  QMessageBox::StandardButton answer = QET::QetMessageBox::question(this,
1130  tr("Recharger l'élément", "dialog title"),
1131  tr("Vous avez efffectué des modifications sur cet élément. Si vous le rechargez, ces modifications seront perdues. Voulez-vous vraiment recharger l'élément ?", "dialog content"),
1132  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
1134  if (answer != QMessageBox::Yes) return;
1135  }
1136 
1137  //Reload the element
1138  m_elmt_scene -> reset();
1139  if (opened_from_file)
1141  else
1143 }
1144 
1152 {
1153  // Check element befor writing
1154  if (checkElement())
1155  {
1156  //If we don't know the name of the current file, use save as instead
1157  if (opened_from_file)
1158  {
1159  if (filename_.isEmpty())
1160  return(slot_saveAsFile());
1161 
1162  //Else wa save to the file at filename_ path
1163  bool result_save = toFile(filename_);
1164  if (result_save) m_elmt_scene -> undoStack().setClean();
1165  return(result_save);
1166  }
1167  else
1168  {
1169  if (location_.isNull())
1170  return(slot_saveAs());
1171 
1172  //Else save to the known location
1173  bool result_save = toLocation(location_);
1174  if (result_save) {
1175  m_elmt_scene -> undoStack().setClean();
1176  emit saveToLocation(location_);
1177  }
1178  return(result_save);
1179  }
1180  }
1181 
1182  QMessageBox::critical(this, tr("Echec de l'enregistrement"), tr("L'enregistrement à échoué,\nles conditions requises ne sont pas valides"));
1183  return false;
1184 }
1185 
1193 {
1194  // Check element befor writing
1195  if (checkElement())
1196  {
1197  //Ask a location to user
1199  if (location.isNull())
1200  return(false);
1201 
1202  bool result_save = toLocation(location);
1203  if (result_save)
1204  {
1206  m_elmt_scene->undoStack().setClean();
1207  emit saveToLocation(location);
1208  }
1209 
1210  return(result_save);
1211  }
1212  QMessageBox::critical(this, tr("Echec de l'enregistrement"), tr("L'enregistrement à échoué,\nles conditions requises ne sont pas valides"));
1213  return (false);
1214 }
1215 
1222 {
1223  // Check element befor writing
1224  if (checkElement())
1225  {
1226  //Ask a filename to user, for save the element
1227  QString fn = QFileDialog::getSaveFileName(
1228  this,
1229  tr("Enregistrer sous", "dialog title"),
1230  filename_.isEmpty() ? QETApp::customElementsDir() : QDir(filename_).absolutePath(),
1231  tr(
1232  "Éléments QElectroTech (*.elmt)",
1233  "filetypes allowed when saving an element file"
1234  )
1235  );
1236 
1237  if (fn.isEmpty())
1238  return(false);
1239 
1240  //If the name doesn't end by .elmt, we add it
1241  if (!fn.endsWith(".elmt", Qt::CaseInsensitive))
1242  fn += ".elmt";
1243 
1244  bool result_save = toFile(fn);
1245  //If the save success, the filename is keep
1246  if (result_save)
1247  {
1248  setFileName(fn);
1249  QETApp::elementsRecentFiles() -> fileWasOpened(fn);
1250  m_elmt_scene -> undoStack().setClean();
1251  }
1252 
1253  return(result_save);
1254  }
1255  QMessageBox::critical(this, tr("Echec de l'enregistrement"), tr("L'enregistrement à échoué,\nles conditions requises ne sont pas valides"));
1256  return false;
1257 }
1258 
1266  if (m_elmt_scene -> undoStack().isClean()) return(true);
1267  // demande d'abord a l'utilisateur s'il veut enregistrer l'element en cours
1268  QMessageBox::StandardButton answer = QET::QetMessageBox::question(
1269  this,
1270  tr("Enregistrer l'élément en cours ?", "dialog title"),
1271  QString(
1272  tr(
1273  "Voulez-vous enregistrer l'élément %1 ?",
1274  "dialog content - %1 is an element name"
1275  )
1276  ).arg(m_elmt_scene -> names().name()),
1277  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
1279  );
1280  bool result;
1281  switch(answer) {
1282  case QMessageBox::Cancel: result = false; break; // l'utilisateur annule : echec de la fermeture
1283  case QMessageBox::Yes: result = slot_save(); break; // l'utilisateur dit oui : la reussite depend de l'enregistrement
1284  default: result = true; // l'utilisateur dit non ou ferme le dialogue: c'est reussi
1285  }
1286  return(result);
1287 }
1288 
1295  if (QWidget *previous_widget = m_tools_dock_stack->widget(1))
1296  {
1297  m_tools_dock_stack->removeWidget(previous_widget);
1298  previous_widget -> setParent(nullptr);
1299  previous_widget -> hide();
1300  return(previous_widget);
1301  }
1302  return(nullptr);
1303 }
1304 
1311 void QETElementEditor::copyAndPasteXml(const QDomDocument &xml_document) {
1312  // accede au presse-papier
1313  QClipboard *clipboard = QApplication::clipboard();
1314 
1315  // genere la description XML de la selection
1316  QString clipboard_content = xml_document.toString(4);
1317 
1318  // met la description XML dans le presse-papier
1319  if (clipboard -> supportsSelection()) {
1320  clipboard -> setText(clipboard_content, QClipboard::Selection);
1321  }
1322  clipboard -> setText(clipboard_content);
1323 
1324  m_view -> pasteInArea();
1325 }
1326 
1331 void QETElementEditor::closeEvent(QCloseEvent *qce) {
1332  if (canClose()) {
1333  writeSettings();
1334  setAttribute(Qt::WA_DeleteOnClose);
1335  m_elmt_scene -> reset();
1336  qce -> accept();
1337  } else qce -> ignore();
1338 }
1339 
1344  Q_UNUSED(event)
1345  QTimer::singleShot(250, m_view, SLOT(zoomFit()));
1346 }
1347 
1352  m_parts_list -> blockSignals(true);
1353  m_parts_list -> clear();
1354  QList<QGraphicsItem *> qgis = m_elmt_scene -> zItems();
1355 
1356  // on ne construit plus la liste a partir de 200 primitives
1357  // c'est ingerable : la maj de la liste prend trop de temps et le resultat
1358  // est inexploitable
1359  if (qgis.count() <= QET_MAX_PARTS_IN_ELEMENT_EDITOR_LIST) {
1360  for (int j = qgis.count() - 1 ; j >= 0 ; -- j) {
1361  QGraphicsItem *qgi = qgis[j];
1362  if (CustomElementPart *cep = dynamic_cast<CustomElementPart *>(qgi)) {
1363  QString part_desc = cep -> name();
1364  QListWidgetItem *qlwi = new QListWidgetItem(part_desc);
1365  QVariant v;
1366  v.setValue<QGraphicsItem *>(qgi);
1367  qlwi -> setData(42, v);
1368  m_parts_list -> addItem(qlwi);
1369  qlwi -> setSelected(qgi -> isSelected());
1370  }
1371  }
1372  } else {
1373  m_parts_list -> addItem(new QListWidgetItem(tr("Trop de primitives, liste non générée.")));
1374  }
1375  m_parts_list -> blockSignals(false);
1376 }
1377 
1382  int items_count = m_elmt_scene -> items().count();
1383  if (m_parts_list -> count() != items_count) {
1385  } else if (items_count <= QET_MAX_PARTS_IN_ELEMENT_EDITOR_LIST) {
1386  m_parts_list -> blockSignals(true);
1387  int i = 0;
1388  QList<QGraphicsItem *> items = m_elmt_scene -> zItems();
1389  for (int j = items.count() - 1 ; j >= 0 ; -- j) {
1390  QGraphicsItem *qgi = items[j];
1391  QListWidgetItem *qlwi = m_parts_list -> item(i);
1392  if (qlwi) qlwi -> setSelected(qgi -> isSelected());
1393  ++ i;
1394  }
1395  m_parts_list -> blockSignals(false);
1396  }
1397 }
1398 
1404  m_elmt_scene -> blockSignals(true);
1405  m_parts_list -> blockSignals(true);
1406  for (int i = 0 ; i < m_parts_list -> count() ; ++ i) {
1407  QListWidgetItem *qlwi = m_parts_list -> item(i);
1408  QGraphicsItem *qgi = qlwi -> data(42).value<QGraphicsItem *>();
1409  if (qgi) {
1410  qgi -> setSelected(qlwi -> isSelected());
1411  }
1412  }
1413  m_parts_list -> blockSignals(false);
1414  m_elmt_scene -> blockSignals(false);
1416  slot_updateMenus();
1417 }
1418 
1424 {
1425  QSettings settings;
1426 
1427  // dimensions et position de la fenetre
1428  QVariant geometry = settings.value("elementeditor/geometry");
1429  if (geometry.isValid()) restoreGeometry(geometry.toByteArray());
1430 
1431  // etat de la fenetre (barres d'outils, docks...)
1432  QVariant state = settings.value("elementeditor/state");
1433  if (state.isValid()) restoreState(state.toByteArray());
1434 
1435  // informations complementaires de l'element : valeur par defaut
1436  m_elmt_scene -> setInformations(settings.value("elementeditor/default-informations", "").toString());
1437 }
1438 
1444 {
1445  QSettings settings;
1446  settings.setValue("elementeditor/geometry", saveGeometry());
1447  settings.setValue("elementeditor/state", saveState());
1448 }
1449 
1455  QPointF paste_offset(5.0, 0.0);
1456  return(paste_offset);
1457 }
1458 
1468 QString QETElementEditor::getOpenElementFileName(QWidget *parent, const QString &initial_dir) {
1469  // demande un nom de fichier a ouvrir a l'utilisateur
1470  QString user_filename = QFileDialog::getOpenFileName(
1471  parent,
1472  tr("Ouvrir un fichier", "dialog title"),
1473  initial_dir.isEmpty() ? QETApp::customElementsDir() : initial_dir,
1474  tr(
1475  "Éléments QElectroTech (*.elmt);;"
1476  "Fichiers XML (*.xml);;"
1477  "Tous les fichiers (*)",
1478  "filetypes allowed when opening an element file"
1479  )
1480  );
1481  return(user_filename);
1482 }
1483 
1490 {
1491  if (!location.isElement())
1492  {
1494  tr("Élément inexistant.", "message box title"),
1495  tr("Le chemin virtuel choisi ne correspond pas à un élément.", "message box content"));
1496  return;
1497  }
1498  if (!location.exist())
1499  {
1501  tr("Élément inexistant.", "message box title"),
1502  tr("L'élément n'existe pas.", "message box content"));
1503  return;
1504  }
1505 
1506  //The file must be an xml document
1507  QDomDocument document_xml;
1508  QDomNode node = document_xml.importNode(location.xml(), true);
1509  document_xml.appendChild(node);
1510 
1511  //Load the element
1512  m_elmt_scene -> fromXml(document_xml);
1514 
1515  //location is read only
1516  if (!location.isWritable())
1517  {
1519  tr("Édition en lecture seule", "message box title"),
1520  tr("Vous n'avez pas les privilèges nécessaires pour modifier cet élement. Il sera donc ouvert en lecture seule.", "message box content"));
1521  setReadOnly(true);
1522  }
1523  else {
1524  setReadOnly(false);
1525  }
1526 
1528  slot_updateMenus();
1529 }
1530 
1536  // demande le chemin du fichier a ouvrir a l'utilisateur
1537  QString element_file_path = getOpenElementFileName(this);
1538  if (element_file_path.isEmpty()) return;
1539 
1540  QString error_message;
1541  QDomDocument xml_document;
1542  QFile element_file(element_file_path);
1543  // le fichier doit etre lisible
1544  if (!element_file.open(QIODevice::ReadOnly)) {
1545  error_message = QString(tr("Impossible d'ouvrir le fichier %1.", "message box content")).arg(element_file_path);
1546  } else {
1547  // le fichier doit etre un document XML
1548  if (!xml_document.setContent(&element_file)) {
1549  error_message = tr("Ce fichier n'est pas un document XML valide", "message box content");
1550  }
1551  element_file.close();
1552  }
1553 
1554  if (!error_message.isEmpty()) {
1555  QET::QetMessageBox::critical(this, tr("Erreur", "toolbar title"), error_message);
1556  }
1557  copyAndPasteXml(xml_document);
1558 }
1559 
1566 {
1567  //Ask for a location
1569  if (location.isNull())
1570  return;
1571 
1572  if (!location.isElement())
1573  {
1575  tr("Élément inexistant.", "message box title"),
1576  tr("Le chemin virtuel choisi ne correspond pas à un élément.", "message box content"));
1577  return;
1578  }
1579  if (!location.exist())
1580  {
1582  tr("Élément inexistant.", "message box title"),
1583  tr("L'élément n'existe pas.", "message box content"));
1584  return;
1585  }
1586 
1587  //Create an xml document from the location xml
1588  QDomDocument document_xml;
1589  QDomNode node = document_xml.importNode(location.xml(), true);
1590  document_xml.appendChild(node);
1591 
1592  copyAndPasteXml(document_xml);
1593 }
1594 
1600  // si aucun widget d'edition n'est affiche, on ne fait rien
1601  if (!m_tools_dock_stack -> currentIndex()) return;
1602 
1603  // s'il y a un widget d'edition affiche, on le met a jour
1604  if (ElementItemEditor *current_editor = dynamic_cast<ElementItemEditor *>(m_tools_dock_stack->widget(1))) {
1605  current_editor -> updateForm();
1606  }
1607 }
~QETElementEditor() override
Destructeur.
QToolBar * depth_toolbar
QIcon PartEllipse
Definition: qeticons.cpp:129
void setEventInterface(ESEventInterface *event_interface)
ElementScene::setEventInterface Set a new event interface.
The ESEventAddEllipse class This ESEvent manage creation of ellpise in an ElementScene.
QHash< QString, ElementItemEditor * > m_editors
Hash associating primitive names with their matching edition widget.
QToolBar * element_toolbar
QIcon Element
Definition: qeticons.cpp:83
void saveToLocation(ElementsLocation loc)
QString filename_
filename of the currently edited element
The RectangleEditor class This class provides a widget to edit rectangles within the element editor...
void addArc()
QETElementEditor::addArc Set arc creation interface to scene.
bool toLocation(const ElementsLocation &location)
QETElementEditor::toLocation Save the element to Location.
QMenu * file_menu
menus
static QString customElementsDir()
QETApp::customElementsDir.
Definition: qetapp.cpp:555
QString toString() const
QIcon EditRedo
Definition: qeticons.cpp:68
ElementsLocation location_
location of the currently edited element
void addEllipse()
QETElementEditor::addEllipse Set ellipse creation interface to scene.
QIcon DocumentNew
Definition: qeticons.cpp:53
ElementView * m_view
view widget for the editing scene
QIcon QETLogo
Definition: qeticons.cpp:151
QIcon Terminal
Definition: qeticons.cpp:164
QActionGroup * m_depth_action_group
QIcon ZoomOut
Definition: qeticons.cpp:181
QIcon PartRectangle
Definition: qeticons.cpp:132
bool opened_from_file
whether the currently edited element comes from a file or a location
bool compareCanonicalFilePaths(const QString &, const QString &)
Definition: qet.cpp:519
QIcon EditUndo
Definition: qeticons.cpp:82
The ESEventAddPolygon class This ESEvent manage creation of polygon in an ElementScene.
QDockWidget * m_tools_dock
container for widgets dedicated to primitive edition
The DynamicTextFieldEditor class This class provide a widget used to edit the property of a dynamic t...
QMenu * settings_menu_
Settings menu.
Definition: qetmainwindow.h:65
ElementScene * m_elmt_scene
editing scene
void copyAndPasteXml(const QDomDocument &)
virtual const QDomDocument toXml(bool=true)
ElementScene::toXml Export this element as a xml file.
QIcon PartText
Definition: qeticons.cpp:134
bool event(QEvent *) override
QIcon ViewRefresh
Definition: qeticons.cpp:173
static bool isStyleEditable(QList< CustomElementPart *> cep_list)
StyleEditor::isStyleEditable.
QIcon EditSelectNone
Definition: qeticons.cpp:72
void slot_updateSelectionFromPartsList()
ElementScene * elementScene() const
The ESEventAddDynamicTextField class This ESEvent manage creation of dynamic text field in an Element...
void UncheckAddPrimitive()
QETElementEditor::UncheckAddPrimitive Uncheck all action related to primitive.
bool read_only
whether the editor is "read-only"
QIcon EditSelectInvert
Definition: qeticons.cpp:71
void addLine()
QETElementEditor::addLine Set line creation interface to scene.
QIcon RunDxf
Definition: qeticons.cpp:157
QIcon ZoomIn
Definition: qeticons.cpp:179
QIcon EditCopy
Definition: qeticons.cpp:64
QIcon DocumentSave
Definition: qeticons.cpp:58
virtual bool setPart(CustomElementPart *)=0
QUndoStack & undoStack()
QToolBar * view_toolbar
QToolBar * main_toolbar
QIcon Names
Definition: qeticons.cpp:119
void addTerminal()
QETElementEditor::addTerminal Set terminal creation interface to scene.
The ESEventAddLine class This ESEvent manage creation of line in a ElementScene.
QIcon XmlTextFile
Definition: qeticons.cpp:176
bool slot_saveAsFile()
QETElementEditor::slot_saveAsFile Ask a file to user and save the current edited element to this file...
QIcon PartPolygon
Definition: qeticons.cpp:131
void slot_openDxf()
QETElementEditor::slot_openDxf.
QIcon PartTextField
Definition: qeticons.cpp:135
bool setXml(const QDomDocument &xml_document) const
ElementsLocation::setXml Replace the current xml description by ; The document element of must have ...
void setupMenus()
QETElementEditor::setupMenus.
QAction * new_element
actions for the "file" menu
QIcon UserInformations
Definition: qeticons.cpp:169
bool checkElement()
QETElementEditor::checkElement Do several check about element. If error is occurred return false...
bool slot_saveAs()
QETElementEditor::slot_saveAs Ask a location to user and save the current edited element to this loca...
void addRect()
QETElementEditor::addRect Set rectangle creation interface to scene.
QETElementEditor(QWidget *=nullptr)
static bool clipboardMayContainElement()
#define QET_MAX_PARTS_IN_ELEMENT_EDITOR_LIST
QIcon tr
Definition: qeticons.cpp:204
QIcon EditSelectAll
Definition: qeticons.cpp:70
The ESEventAddTerminal class This ESEvent manage creation of terminal in an ElementScene.
bool writeXmlFile(QDomDocument &xml_doc, const QString &filepath, QString *error_message=nullptr)
Definition: qet.cpp:544
QIcon EditPaste
Definition: qeticons.cpp:67
The ESEventAddArc class This ESEvent manage creation of arc in an ElementScene.
Definition: eseventaddarc.h:31
static QPointF pasteOffset()
DepthOption
List the various kind of changes for the zValue.
Definition: qet.h:43
QDomElement xml() const
ElementsLocation::xml.
QActionGroup * parts
Action group.
The ESEventAddText class This ESEvent manage creation of text in an ElementScene. ...
void fromLocation(const ElementsLocation &)
QETElementEditor::fromLocation Location of the element to edit.
void clearEventInterface()
ElementScene::clearEventInterface Clear the current event interface.
void openElement(const QString &)
bool slot_save()
QETElementEditor::slot_save Save the current editing element. If the filepath or location is unknow...
void setLocation(const ElementsLocation &)
QETElementEditor::setLocation The new location to edit.
QIcon DocumentSaveAs
Definition: qeticons.cpp:60
QIcon PartArc
Definition: qeticons.cpp:127
bool exist() const
ElementsLocation::exist.
QDockWidget * m_parts_dock
Container for the list of existing primitives.
QAction * selectall
actions for the "edit" menu
void openRecentFile(const QString &)
QDockWidget * m_undo_dock
container for the undo list
QIcon ZoomOriginal
Definition: qeticons.cpp:180
QAction * paste_from_elmt
void readSettings()
QETElementEditor::readSettings Read settings.
void closeEvent(QCloseEvent *) override
QIcon EditCut
Definition: qeticons.cpp:65
static QString getOpenElementFileName(QWidget *=nullptr, const QString &=QString())
QString min_title
minimum window title
QLabel * m_default_informations
label displayed when several primitives are selected
void fromFile(const QString &)
QActionGroup * m_zoom_ag
QAction * m_edit_properties
QIcon PartLine
Definition: qeticons.cpp:130
void addDynamicTextField()
QETElementEditor::addDynamicTextField Set dynamic text field creation interface to scene...
QListWidget * m_parts_list
List of primitives.
QIcon ro
Definition: qeticons.cpp:199
void firstActivation(QEvent *) override
void addText()
QETElementEditor::addText Set text creation interface to scene.
void contextMenu(QPoint p, QList< QAction *> actions=QList< QAction *>())
QETElementEditor::contextMenu Display a context menu, with all available action.
QIcon Cancel
Definition: qeticons.cpp:34
void pasteFromElement()
QETElementEditor::pasteFromElement Ask an element to user, copy the xml definition of the element to ...
void addPolygon()
QETElementEditor::addPolygon Set polygon creation interface to scene.
QIcon ApplicationExit
Definition: qeticons.cpp:27
bool toFile(const QString &)
QETElementEditor::toFile Save to file the drawed element.
void setupActions()
QETElementEditor::setupActions Create action used in Element editor.
QMessageBox::StandardButton question(QWidget *, const QString &, const QString &, QMessageBox::StandardButtons=QMessageBox::Ok, QMessageBox::StandardButton=QMessageBox::NoButton)
QIcon ElementEdit
Definition: qeticons.cpp:85
bool isReadOnly() const
QAction * save_as_file
void insertMenu(QMenu *, QMenu *, bool=true)
QToolBar * parts_toolbar
toolbars
QIcon ZoomFitBest
Definition: qeticons.cpp:178
void slot_reload()
QETElementEditor::slot_reload Reload the element from the file or location.
QAction * paste_in_area
bool isEditing(const ElementsLocation &)
bool isElement() const
ElementsLocation::isElement.
void setFileName(const QString &)
void writeSettings()
QETElementEditor::writeSettings Write the settings.
static RecentFiles * elementsRecentFiles()
Definition: qetapp.cpp:1173
QAction * paste_from_file
QIcon DocumentOpenRecent
Definition: qeticons.cpp:55
QMessageBox::StandardButton critical(QWidget *, const QString &, const QString &, QMessageBox::StandardButtons=QMessageBox::Ok, QMessageBox::StandardButton=QMessageBox::NoButton)
static ElementsLocation getOpenElementLocation(QWidget *parent=nullptr)
ElementDialog::getOpenElementLocation Display a dialog for open an element through her location...
QActionGroup * depthActionGroup(QObject *parent=nullptr)
QET::depthActionGroup.
Definition: qet.cpp:636
QWidget * clearToolsDock()
ElementsLocation location() const
bool isWritable() const
ElementsLocation::isWritable.
static QETApp * instance()
Definition: qetapp.cpp:143
void setupInterface()
QETElementEditor::setupInterface.
QIcon EditDelete
Definition: qeticons.cpp:66
QIcon FolderOpen
Definition: qeticons.cpp:99
QMessageBox::StandardButton warning(QWidget *, const QString &, const QString &, QMessageBox::StandardButtons=QMessageBox::Ok, QMessageBox::StandardButton=QMessageBox::NoButton)
static ElementsLocation getSaveElementLocation(QWidget *parent=nullptr)
ElementDialog::getSaveElementLocation Display a dialog that allow to user to select an element (exist...
QStackedWidget * m_tools_dock_stack
Stack of widgets for tools_dock.
static QString realPath(const QString &)
Definition: qetapp.cpp:704