diff --git a/sources/ElementsCollection/elementscollectionwidget.cpp b/sources/ElementsCollection/elementscollectionwidget.cpp index 249fc40c9..6b4c62555 100644 --- a/sources/ElementsCollection/elementscollectionwidget.cpp +++ b/sources/ElementsCollection/elementscollectionwidget.cpp @@ -17,7 +17,7 @@ */ #include "elementscollectionwidget.h" -#include "../editor/qetelementeditor.h" +#include "../editor/ui/qetelementeditor.h" #include "../elementscategoryeditor.h" #include "../newelementwizard.h" #include "../qetapp.h" @@ -38,6 +38,9 @@ #include #include #include +#include +#include +#include /** @brief ElementsCollectionWidget::ElementsCollectionWidget diff --git a/sources/editor/elementitemeditor.cpp b/sources/editor/elementitemeditor.cpp index 3f2169aa3..540e57f7a 100644 --- a/sources/editor/elementitemeditor.cpp +++ b/sources/editor/elementitemeditor.cpp @@ -16,7 +16,7 @@ along with QElectroTech. If not, see . */ #include "elementitemeditor.h" -#include "qetelementeditor.h" +#include "ui/qetelementeditor.h" #include "editorcommands.h" /** diff --git a/sources/editor/elementscene.cpp b/sources/editor/elementscene.cpp index e0120dd90..0388799b6 100644 --- a/sources/editor/elementscene.cpp +++ b/sources/editor/elementscene.cpp @@ -33,7 +33,7 @@ #include "graphicspart/partrectangle.h" #include "graphicspart/partterminal.h" #include "graphicspart/parttext.h" -#include "qetelementeditor.h" +#include "ui/qetelementeditor.h" #include "ui/elementpropertieseditorwidget.h" #include diff --git a/sources/editor/elementview.cpp b/sources/editor/elementview.cpp index 3a0c72c48..39cf5e63c 100644 --- a/sources/editor/elementview.cpp +++ b/sources/editor/elementview.cpp @@ -19,7 +19,7 @@ #include "../qetapp.h" #include "UndoCommand/pastepartscommand.h" -#include "qetelementeditor.h" +#include "ui/qetelementeditor.h" /** Constructeur @param scene ElementScene visualisee par cette ElementView diff --git a/sources/editor/esevent/eseventaddline.cpp b/sources/editor/esevent/eseventaddline.cpp index 27eb36f87..93f83a320 100644 --- a/sources/editor/esevent/eseventaddline.cpp +++ b/sources/editor/esevent/eseventaddline.cpp @@ -20,7 +20,7 @@ #include "../editorcommands.h" #include "../elementscene.h" #include "../graphicspart/partline.h" -#include "../qetelementeditor.h" +#include "../ui/qetelementeditor.h" #include #include diff --git a/sources/editor/esevent/eseventinterface.cpp b/sources/editor/esevent/eseventinterface.cpp index 818786e51..23e20ee05 100644 --- a/sources/editor/esevent/eseventinterface.cpp +++ b/sources/editor/esevent/eseventinterface.cpp @@ -18,7 +18,8 @@ #include "eseventinterface.h" #include "../elementscene.h" -#include "../qetelementeditor.h" +#include "../ui/qetelementeditor.h" +#include "../elementview.h" #include @@ -40,7 +41,7 @@ ESEventInterface::ESEventInterface(ElementScene *scene) : void ESEventInterface::init() { m_scene->setBehavior(ElementScene::Behavior::AddPart); - m_editor->slot_setNoDragToView(); + m_editor->elementView()->setDragMode(QGraphicsView::NoDrag); } /** @@ -53,31 +54,31 @@ ESEventInterface::~ESEventInterface() delete m_help_verti; m_scene->setBehavior(ElementScene::Behavior::Normal); - m_editor->slot_setRubberBandToView(); + m_editor->elementView()->setDragMode(QGraphicsView::RubberBandDrag); } bool ESEventInterface::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { - Q_UNUSED (event); + Q_UNUSED (event) return false; } bool ESEventInterface::mousePressEvent(QGraphicsSceneMouseEvent *event) { - Q_UNUSED (event); + Q_UNUSED (event) return false; } bool ESEventInterface::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { - Q_UNUSED (event); + Q_UNUSED (event) return false; } bool ESEventInterface::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { - Q_UNUSED (event); + Q_UNUSED (event) return false; } bool ESEventInterface::wheelEvent(QGraphicsSceneWheelEvent *event) { - Q_UNUSED (event); + Q_UNUSED (event) return false; } @@ -97,7 +98,7 @@ bool ESEventInterface::keyPressEvent(QKeyEvent *event) { } bool ESEventInterface::KeyReleaseEvent(QKeyEvent *event) { - Q_UNUSED (event); + Q_UNUSED (event) return false; } diff --git a/sources/editor/graphicspart/customelementpart.cpp b/sources/editor/graphicspart/customelementpart.cpp index bd60846de..2ecaf817c 100644 --- a/sources/editor/graphicspart/customelementpart.cpp +++ b/sources/editor/graphicspart/customelementpart.cpp @@ -17,7 +17,8 @@ */ #include "customelementpart.h" -#include "../qetelementeditor.h" +#include "../ui/qetelementeditor.h" +#include "../elementscene.h" /// @return le QETElementEditor auquel cet editeur appartient QETElementEditor *CustomElementPart::elementEditor() const diff --git a/sources/editor/graphicspart/partpolygon.cpp b/sources/editor/graphicspart/partpolygon.cpp index 43dd8fde8..5e142b374 100644 --- a/sources/editor/graphicspart/partpolygon.cpp +++ b/sources/editor/graphicspart/partpolygon.cpp @@ -22,7 +22,7 @@ #include "../../QetGraphicsItemModeler/qetgraphicshandlerutility.h" #include "../../qeticons.h" #include "../elementscene.h" -#include "../qetelementeditor.h" +#include "../ui/qetelementeditor.h" /** @brief PartPolygon::PartPolygon diff --git a/sources/editor/qetelementeditor.cpp b/sources/editor/qetelementeditor.cpp deleted file mode 100644 index e1586e175..000000000 --- a/sources/editor/qetelementeditor.cpp +++ /dev/null @@ -1,1734 +0,0 @@ -/* - Copyright 2006-2021 The QElectroTech Team - This file is part of QElectroTech. - - QElectroTech is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - QElectroTech is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with QElectroTech. If not, see . -*/ -#include "qetelementeditor.h" - -#include "../editor/graphicspart/customelementpart.h" -#include "../elementdialog.h" -#include "../newelementwizard.h" -#include "../qet.h" -#include "../qetapp.h" -#include "../qeticons.h" -#include "../qetmessagebox.h" -#include "../recentfiles.h" -#include "arceditor.h" -#include "editorcommands.h" -#include "elementitemeditor.h" -#include "elementscene.h" -#include "elementview.h" -#include "esevent/eseventaddarc.h" -#include "esevent/eseventadddynamictextfield.h" -#include "esevent/eseventaddellipse.h" -#include "esevent/eseventaddline.h" -#include "esevent/eseventaddpolygon.h" -#include "esevent/eseventaddrect.h" -#include "esevent/eseventaddterminal.h" -#include "esevent/eseventaddtext.h" -#include "graphicspart/partterminal.h" -#include "styleeditor.h" -#include "terminaleditor.h" -#include "ui/dynamictextfieldeditor.h" -#include "ui/ellipseeditor.h" -#include "ui/lineeditor.h" -#include "ui/polygoneditor.h" -#include "ui/rectangleeditor.h" -#include "ui/texteditor.h" - -#include -#include -#include -#include -#include -#include - -/* - Nombre maximum de primitives affichees par la "liste des parties" - Au-dela, un petit message est affiche, indiquant que ce nombre a ete depasse - et que la liste ne sera donc pas mise a jour. -*/ -#define QET_MAX_PARTS_IN_ELEMENT_EDITOR_LIST 200 - -/** - Constructeur - @param parent QWidget parent -*/ -QETElementEditor::QETElementEditor(QWidget *parent) : - QETMainWindow(parent), - read_only(false), - min_title(tr("QElectroTech - Éditeur d'élément", "window title")), - opened_from_file(false) { - setWindowTitle(min_title); - setWindowIcon(QET::Icons::QETLogo); - - setupInterface(); - setupActions(); - setupMenus(); - - // la fenetre est maximisee par defaut - setMinimumSize(QSize(500, 350)); - setWindowState(Qt::WindowMaximized); - - // lecture des parametres - readSettings(); - slot_updateMenus(); - - // affichage - show(); -} - -/// Destructeur -QETElementEditor::~QETElementEditor() -{ - /* - retire le widget d'edition de primitives affiche par le dock - cela evite qu'il ne soit supprime par son widget parent - */ - clearToolsDock(); - - // supprime les editeurs de primitives - qDeleteAll(m_editors.begin(), m_editors.end()); - m_editors.clear(); -} - -/** - @brief QETElementEditor::setLocation - The new location to edit - @param el -*/ -void QETElementEditor::setLocation(const ElementsLocation &el) { - location_ = el; - opened_from_file = false; - setReadOnly(!location_.isWritable()); - slot_updateTitle(); -} - -/** - @param fn Le nouveau nom de fichier de l'element edite -*/ -void QETElementEditor::setFileName(const QString &fn) { - filename_ = fn; - opened_from_file = true; - // modifie le mode lecture seule si besoin - bool must_be_read_only = !QFileInfo(filename_).isWritable(); - if (isReadOnly() != must_be_read_only) { - setReadOnly(must_be_read_only); - } - slot_updateTitle(); -} - -/** - @brief QETElementEditor::setupActions - Create action used in Element editor -*/ -void QETElementEditor::setupActions() -{ - new_element = new QAction(QET::Icons::DocumentNew, tr("&Nouveau"), this); - open = new QAction(QET::Icons::FolderOpen, tr("&Ouvrir"), this); - open_file = new QAction(QET::Icons::FolderOpen, tr("&Ouvrir depuis un fichier"), this); - open_dxf = new QAction(QET::Icons::RunDxf, tr("&Lancer le plugin convertisseur DXF"), this); - save = new QAction(QET::Icons::DocumentSave, tr("&Enregistrer"), this); - save_as = new QAction(QET::Icons::DocumentSaveAs, tr("Enregistrer sous"), this); - save_as_file = new QAction(QET::Icons::DocumentSaveAs, tr("Enregistrer dans un fichier"), this); - reload = new QAction(QET::Icons::ViewRefresh, tr("Recharger"), this); - quit = new QAction(QET::Icons::ApplicationExit, tr("&Quitter"), this); - selectall = new QAction(QET::Icons::EditSelectAll, tr("Tout sélectionner"), this); - deselectall = new QAction(QET::Icons::EditSelectNone, tr("Désélectionner tout"), this); - cut = new QAction(QET::Icons::EditCut, tr("Co&uper"), this); - copy = new QAction(QET::Icons::EditCopy, tr("Cop&ier"), this); - paste = new QAction(QET::Icons::EditPaste, tr("C&oller"), this); - paste_in_area = new QAction(QET::Icons::EditPaste, tr("C&oller dans la zone..."), this); - paste_from_file = new QAction(QET::Icons::XmlTextFile, tr("un fichier"), this); - paste_from_elmt = new QAction(QET::Icons::Element, tr("un élément"), this); - inv_select = new QAction(QET::Icons::EditSelectInvert, tr("Inverser la sélection"), this); - edit_delete = new QAction(QET::Icons::EditDelete, tr("&Supprimer"), this); - edit_names = new QAction(QET::Icons::Names, tr("Éditer le nom et les traductions de l'élément"), this); - edit_author = new QAction(QET::Icons::UserInformations, tr("Éditer les informations sur l'auteur"), this); - m_edit_properties = new QAction(QET::Icons::ElementEdit, tr("Éditer les propriétés de l'élément"), this); - -#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) - open_dxf -> setStatusTip(tr("To install the plugin DXFtoQET\nVisit https://download.tuxfamily.org/qet/builds/dxf_to_elmt/\n" - "\n" - ">> Install on Windows\n" - "Put DXFtoQET.exe binary on C:\\Users\\user_name\\AppData\\Roaming\\qet\\ directory \n" - )); -#elif defined(Q_OS_MAC) - open_dxf -> setStatusTip(tr("To install the plugin DXFtoQET\nVisit https://download.tuxfamily.org/qet/builds/dxf_to_elmt/\n" - "\n" - ">> Install on macOSX\n" - "Put DXFtoQET.app binary on /Users/user_name/.qet/ directory \n" - )); -#else - open_dxf -> setStatusTip(tr("To install the plugin DXFtoQET\nVisit https://download.tuxfamily.org/qet/builds/dxf_to_elmt/\n" - "\n" - ">> Install on Linux\n" - "Put DXFtoQET binary on your /home/user_name/.qet/ directory\n" - "make it executable : chmod +x ./DXFtoQET\n" - )); -#endif - - open_dxf -> setWhatsThis (tr("To install the plugin DXFtoQET\nVisit https://download.tuxfamily.org/qet/builds/dxf_to_elmt/\n" - "\n" - ">> Install on Linux\n" - "Put DXFtoQET binary on your /home/user_name/.qet/ directory\n" - "make it executable : chmod +x ./DXFtoQET\n" - ">> Install on Windows\n" - "Put DXFtoQET.exe binary on C:\\Users\\user_name\\AppData\\Roaming\\qet\\ directory \n" - "\n" - ">> Install on macOSX\n" - "Put DXFtoQET.app binary on /Users/user_name/.qet/ directory \n" - )); - - undo = m_elmt_scene -> undoStack().createUndoAction(this, tr("Annuler")); - redo = m_elmt_scene -> undoStack().createRedoAction(this, tr("Refaire")); - undo -> setIcon(QET::Icons::EditUndo); - redo -> setIcon(QET::Icons::EditRedo); - undo -> setShortcuts(QKeySequence::Undo); - redo -> setShortcuts(QKeySequence::Redo); - - new_element -> setShortcut(QKeySequence::New); - open -> setShortcut(QKeySequence::Open); - open_file -> setShortcut(tr("Ctrl+Shift+O")); - save -> setShortcut(QKeySequence::Save); - save_as_file -> setShortcut(tr("Ctrl+Shift+S")); - quit -> setShortcut(QKeySequence(tr("Ctrl+Q"))); - selectall -> setShortcut(QKeySequence::SelectAll); - deselectall -> setShortcut(QKeySequence(tr("Ctrl+Shift+A"))); - inv_select -> setShortcut(QKeySequence(tr("Ctrl+I"))); - cut -> setShortcut(QKeySequence::Cut); - copy -> setShortcut(QKeySequence::Copy); - paste -> setShortcut(QKeySequence::Paste); - paste_in_area -> setShortcut(tr("Ctrl+Shift+V")); - -#ifndef Q_OS_MAC - edit_delete -> setShortcut(QKeySequence(Qt::Key_Delete)); -#else - edit_delete -> setShortcut(QKeySequence(tr("Backspace"))); -#endif - - edit_names -> setShortcut(QKeySequence(tr("Ctrl+E"))); - edit_author -> setShortcut(tr("Ctrl+Y")); - - connect(new_element, SIGNAL(triggered()), this, SLOT(slot_new())); - connect(open, SIGNAL(triggered()), this, SLOT(slot_open())); - connect(open_dxf, SIGNAL(triggered()), this, SLOT(slot_openDxf())); - connect(open_file, SIGNAL(triggered()), this, SLOT(slot_openFile())); - connect(save, SIGNAL(triggered()), this, SLOT(slot_save())); - connect(save_as, SIGNAL(triggered()), this, SLOT(slot_saveAs())); - connect(save_as_file, SIGNAL(triggered()), this, SLOT(slot_saveAsFile())); - connect(reload, SIGNAL(triggered()), this, SLOT(slot_reload())); - connect(quit, SIGNAL(triggered()), this, SLOT(close())); - connect(selectall, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_selectAll())); - connect(deselectall, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_deselectAll())); - connect(inv_select, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_invertSelection())); - connect(cut, SIGNAL(triggered()), m_view, SLOT(cut())); - connect(copy, SIGNAL(triggered()), m_view, SLOT(copy())); - connect(paste, SIGNAL(triggered()), m_view, SLOT(paste())); - connect(paste_in_area, SIGNAL(triggered()), m_view, SLOT(pasteInArea())); - connect(paste_from_file, SIGNAL(triggered()), this, SLOT(pasteFromFile())); - connect(paste_from_elmt, SIGNAL(triggered()), this, SLOT(pasteFromElement())); - connect(edit_delete, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_delete())); - connect(edit_names, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_editNames())); - connect(edit_author, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_editAuthorInformations())); - connect(m_edit_properties, SIGNAL(triggered()), m_elmt_scene, SLOT(slot_editProperties())); - - //Action related to change depth of primitive - m_depth_action_group = QET::depthActionGroup(this); - - connect(m_depth_action_group, &QActionGroup::triggered, [this](QAction *action) { - this -> elementScene() -> undoStack().push( - new ChangeZValueCommand(this -> elementScene(), action -> data().value())); - emit(this -> elementScene() -> partsZValueChanged()); - }); - - depth_toolbar = addToolBar(tr("Profondeur", "toolbar title")); - depth_toolbar -> setObjectName("depth_toolbar"); - depth_toolbar -> addActions(m_depth_action_group -> actions()); - addToolBar(Qt::TopToolBarArea, depth_toolbar); - - /* - Action related to zoom - */ - m_zoom_ag = new QActionGroup(this); - - QAction *zoom_in = new QAction(QET::Icons::ZoomIn, tr("Zoom avant"), m_zoom_ag); - QAction *zoom_out = new QAction(QET::Icons::ZoomOut, tr("Zoom arrière"), m_zoom_ag); - QAction *zoom_fit = new QAction(QET::Icons::ZoomFitBest, tr("Zoom adapté"), m_zoom_ag); - QAction *zoom_reset = new QAction(QET::Icons::ZoomOriginal, tr("Pas de zoom"), m_zoom_ag); - - zoom_in -> setShortcut(QKeySequence::ZoomIn); - zoom_out -> setShortcut(QKeySequence::ZoomOut); - zoom_fit -> setShortcut(QKeySequence(tr("Ctrl+9"))); - zoom_reset -> setShortcut(QKeySequence(tr("Ctrl+0"))); - - connect(zoom_in, SIGNAL(triggered()), m_view, SLOT(zoomIn() )); - connect(zoom_out, SIGNAL(triggered()), m_view, SLOT(zoomOut() )); - connect(zoom_fit, SIGNAL(triggered()), m_view, SLOT(zoomFit() )); - connect(zoom_reset, SIGNAL(triggered()), m_view, SLOT(zoomReset() )); - - /* - Action related to primitive creation - */ - connect (m_elmt_scene, SIGNAL(partsAdded()), this, SLOT(UncheckAddPrimitive())); - parts = new QActionGroup(this); - - QAction *add_line = new QAction(QET::Icons::PartLine, tr("Ajouter une ligne"), parts); - QAction *add_rectangle = new QAction(QET::Icons::PartRectangle, tr("Ajouter un rectangle"), parts); - QAction *add_ellipse = new QAction(QET::Icons::PartEllipse, tr("Ajouter une ellipse"), parts); - QAction *add_polygon = new QAction(QET::Icons::PartPolygon, tr("Ajouter un polygone"), parts); - QAction *add_text = new QAction(QET::Icons::PartText, tr("Ajouter du texte"), parts); - QAction *add_arc = new QAction(QET::Icons::PartArc, tr("Ajouter un arc de cercle"), parts); - QAction *add_terminal = new QAction(QET::Icons::Terminal, tr("Ajouter une borne"), parts); - QAction *add_dynamic_text_field = new QAction(QET::Icons::PartTextField, tr("Ajouter un champ texte dynamique"), parts); - - foreach (QAction *action, parts -> actions()) action -> setCheckable(true); - - connect(add_line, SIGNAL(triggered()), this, SLOT(addLine() )); - connect(add_rectangle, SIGNAL(triggered()), this, SLOT(addRect() )); - connect(add_ellipse, SIGNAL(triggered()), this, SLOT(addEllipse() )); - connect(add_polygon, SIGNAL(triggered()), this, SLOT(addPolygon() )); - connect(add_text, SIGNAL(triggered()), this, SLOT(addText() )); - connect(add_arc, SIGNAL(triggered()), this, SLOT(addArc() )); - connect(add_terminal, SIGNAL(triggered()), this, SLOT(addTerminal() )); - connect(add_dynamic_text_field, &QAction::triggered, this, &QETElementEditor::addDynamicTextField); - - add_polygon -> setStatusTip(tr("Double-click pour terminer la forme, Click droit pour annuler le dernier point")); - add_text -> setStatusTip(tr("Ajouter un texte d'élément non éditable dans les schémas")); - add_dynamic_text_field -> setStatusTip(tr("Ajouter un texte d'élément pouvant être édité dans les schémas")); - - parts_toolbar = addToolBar(tr("Parties", "toolbar title")); - parts_toolbar -> setAllowedAreas(Qt::AllToolBarAreas); - parts_toolbar -> setObjectName("parts"); - parts_toolbar -> addActions(parts -> actions()); - addToolBar(Qt::LeftToolBarArea, parts_toolbar); - - main_toolbar = new QToolBar(tr("Outils", "toolbar title"), this); - main_toolbar -> setObjectName("main_toolbar"); - view_toolbar = new QToolBar(tr("Affichage", "toolbar title"), this); - view_toolbar -> setObjectName("display"); - element_toolbar = new QToolBar(tr("Élément", "toolbar title"), this); - element_toolbar -> setObjectName("element_toolbar"); - - main_toolbar -> addAction(new_element); - main_toolbar -> addAction(open); - main_toolbar -> addAction(save); - main_toolbar -> addAction(save_as); - main_toolbar -> addAction(reload); - main_toolbar -> addSeparator(); - main_toolbar -> addAction(undo); - main_toolbar -> addAction(redo); - main_toolbar -> addSeparator(); - main_toolbar -> addAction(edit_delete); - - view_toolbar -> addAction(zoom_fit); - view_toolbar -> addAction(zoom_reset); - - element_toolbar -> addAction(edit_names); - element_toolbar -> addAction(m_edit_properties); - - addToolBar(Qt::TopToolBarArea, main_toolbar); - addToolBar(Qt::TopToolBarArea, view_toolbar); - addToolBar(Qt::TopToolBarArea, element_toolbar); - - connect(m_elmt_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updateInformations()), Qt::QueuedConnection); - connect(m_elmt_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updateMenus())); - connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slot_updateMenus())); - connect(&(m_elmt_scene -> undoStack()), SIGNAL(cleanChanged(bool)), this, SLOT(slot_updateMenus())); - connect(&(m_elmt_scene -> undoStack()), SIGNAL(cleanChanged(bool)), this, SLOT(slot_updateTitle())); - - // Annuler ou refaire une action met a jour la liste des primitives ; cela sert notamment pour les - // ajouts et suppressions de primitives ainsi que pour les actions entrainant un change - connect(&(m_elmt_scene -> undoStack()), SIGNAL(indexChanged(int)), this, SLOT(slot_updatePartsList())); - - // Annuler ou refaire une action met a jour les informations affichees sur les primitives selectionnees, - // celles-ci etant potentiellement impactees - connect(&(m_elmt_scene -> undoStack()), SIGNAL(indexChanged(int)), this, SLOT(slot_updateInformations())); -} - -/** - @brief QETElementEditor::setupMenus -*/ -void QETElementEditor::setupMenus() -{ - file_menu = new QMenu(tr("&Fichier"), this); - edit_menu = new QMenu(tr("&Édition"), this); - display_menu = new QMenu(tr("Afficha&ge"), this); - tools_menu = new QMenu(tr("O&utils"), this); - - file_menu -> setTearOffEnabled(true); - edit_menu -> setTearOffEnabled(true); - display_menu -> setTearOffEnabled(true); - tools_menu -> setTearOffEnabled(true); - - file_menu -> addAction(new_element); - file_menu -> addAction(open); - file_menu -> addAction(open_file); - file_menu -> addAction(open_dxf); - QMenu *recentfile = file_menu -> addMenu(QET::Icons::DocumentOpenRecent, tr("&Récemment ouverts")); - recentfile -> addActions(QETApp::elementsRecentFiles() -> menu() -> actions()); - connect(QETApp::elementsRecentFiles(), SIGNAL( - fileOpeningRequested(const QString &)), this, SLOT(openRecentFile(const QString &))); - file_menu -> addAction(save); - file_menu -> addAction(save_as); - file_menu -> addAction(save_as_file); - file_menu -> addSeparator(); - file_menu -> addAction(reload); - file_menu -> addSeparator(); - file_menu -> addAction(quit); - - paste_from_menu = new QMenu(tr("Coller depuis...")); - paste_from_menu -> setIcon(QET::Icons::EditPaste); - paste_from_menu -> addAction(paste_from_file); - paste_from_menu -> addAction(paste_from_elmt); - - edit_menu -> addAction(undo); - edit_menu -> addAction(redo); - edit_menu -> addSeparator(); - edit_menu -> addAction(selectall); - edit_menu -> addAction(deselectall); - edit_menu -> addAction(inv_select); - edit_menu -> addSeparator(); - edit_menu -> addAction(cut); - edit_menu -> addAction(copy); - edit_menu -> addAction(paste); - edit_menu -> addAction(paste_in_area); - edit_menu -> addMenu(paste_from_menu); - edit_menu -> addSeparator(); - edit_menu -> addAction(edit_delete); - edit_menu -> addSeparator(); - edit_menu -> addAction(edit_names); - edit_menu -> addAction(edit_author); - edit_menu -> addAction(m_edit_properties); - edit_menu -> addSeparator(); - edit_menu -> addActions(m_depth_action_group -> actions()); - - display_menu -> addActions(m_zoom_ag -> actions()); - - insertMenu(settings_menu_, file_menu); - insertMenu(settings_menu_, edit_menu); - insertMenu(settings_menu_, display_menu); -} - -/** - @brief QETElementEditor::contextMenu - Display a context menu, with all available action. - @param p : the pos of the menu, in screen coordinate - @param actions : - a list of actions who can be prepended to the context menu. -*/ -void QETElementEditor::contextMenu(QPoint p, QList actions) { - QMenu menu(this); - menu.addActions(std::move(actions)); - menu.addSeparator(); - menu.addAction(undo); - menu.addAction(redo); - menu.addAction(selectall); - menu.addAction(deselectall); - menu.addAction(inv_select); - menu.addSeparator(); - menu.addAction(edit_delete); - menu.addAction(cut); - menu.addAction(copy); - menu.addSeparator(); - menu.addAction(paste); - menu.addAction(paste_in_area); - menu.addMenu(paste_from_menu); - menu.addSeparator(); - menu.addActions(m_depth_action_group -> actions()); - - //Remove from the context menu the actions which are disabled. - const QListmenu_actions = menu.actions(); - for(QAction *action : menu_actions) { - if(!action -> isEnabled()) { - menu.removeAction(action); - } - } - menu.exec(p); -} - -/** - Met a jour les menus -*/ -void QETElementEditor::slot_updateMenus() -{ - bool selected_items = !read_only && !m_elmt_scene -> selectedItems().isEmpty(); - bool clipboard_elmt = !read_only && ElementScene::clipboardMayContainElement(); - - // actions dependant seulement de l'etat "lecture seule" de l'editeur - foreach (QAction *action, parts -> actions()) { - action -> setEnabled(!read_only); - } - selectall -> setEnabled(!read_only); - inv_select -> setEnabled(!read_only); - paste_from_file -> setEnabled(!read_only); - paste_from_elmt -> setEnabled(!read_only); - m_parts_list -> setEnabled(!read_only); - - // Action enabled if primitive selected - deselectall -> setEnabled(selected_items); - cut -> setEnabled(selected_items); - copy -> setEnabled(selected_items); - edit_delete -> setEnabled(selected_items); - foreach (QAction *action, m_depth_action_group -> actions()) { - action -> setEnabled(selected_items); - } - - // actions dependant du contenu du presse-papiers - paste -> setEnabled(clipboard_elmt); - paste_in_area -> setEnabled(clipboard_elmt); - - // actions dependant de l'etat de la pile d'annulation - save -> setEnabled(!read_only && !m_elmt_scene -> undoStack().isClean()); - undo -> setEnabled(!read_only && m_elmt_scene -> undoStack().canUndo()); - redo -> setEnabled(!read_only && m_elmt_scene -> undoStack().canRedo()); -} - -/** - Met a jour le titre de la fenetre -*/ -void QETElementEditor::slot_updateTitle() -{ - QString title = min_title; - title += " - " + m_elmt_scene -> names().name() + " "; - if (!filename_.isEmpty() || !location_.isNull()) { - if (!m_elmt_scene -> undoStack().isClean()) { - title += tr("[Modifié]", "window title tag"); - } - } - if (isReadOnly()) { - title += tr(" [lecture seule]", "window title tag"); - } - setWindowTitle(title); -} - -/** - @brief QETElementEditor::setupInterface -*/ -void QETElementEditor::setupInterface() -{ - // editeur - m_elmt_scene = new ElementScene(this, this); - m_view = new ElementView(m_elmt_scene, this); - slot_setRubberBandToView(); - setCentralWidget(m_view); - - // widget par defaut dans le QDockWidget - m_default_informations = new QLabel(); - - // ScrollArea pour accueillir un widget d'edition (change a la volee) -// m_tools_dock_scroll_area = new QScrollArea(); -// m_tools_dock_scroll_area -> setFrameStyle(QFrame::NoFrame); -// m_tools_dock_scroll_area -> setAlignment(Qt::AlignHCenter|Qt::AlignTop); - - // Pile de widgets pour accueillir les deux widgets precedents - m_tools_dock_stack = new QStackedWidget(); - m_tools_dock_stack -> insertWidget(0, m_default_informations); -// m_tools_dock_stack -> insertWidget(1, m_tools_dock_scroll_area); - - // widgets d'editions pour les parties - m_editors["arc"] = new ArcEditor(this); - m_editors["ellipse"] = new EllipseEditor(this); - m_editors["line"] = new LineEditor(this); - m_editors["polygon"] = new PolygonEditor(this); - m_editors["rect"] = new RectangleEditor(this); - m_editors["terminal"] = new TerminalEditor(this); - m_editors["text"] = new TextEditor(this); - m_editors["style"] = new StyleEditor(this); - m_editors["dynamic_text"] = new DynamicTextFieldEditor(this); - - // panel sur le cote pour editer les parties - m_tools_dock = new QDockWidget(tr("Informations", "dock title"), this); - m_tools_dock -> setObjectName("informations"); - m_tools_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - m_tools_dock -> setFeatures( - QDockWidget::DockWidgetClosable - |QDockWidget::DockWidgetMovable - |QDockWidget::DockWidgetFloatable); - //m_tools_dock -> setMinimumWidth(380); - addDockWidget(Qt::RightDockWidgetArea, m_tools_dock); - m_tools_dock -> setWidget(m_tools_dock_stack); - - // panel sur le cote pour les annulations - m_undo_dock = new QDockWidget(tr("Annulations", "dock title"), this); - m_undo_dock -> setObjectName("undo"); - m_undo_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - m_undo_dock -> setFeatures( - QDockWidget::DockWidgetClosable - |QDockWidget::DockWidgetMovable - |QDockWidget::DockWidgetFloatable); - m_undo_dock -> setMinimumWidth(290); - addDockWidget(Qt::RightDockWidgetArea, m_undo_dock); - QUndoView* undo_view = new QUndoView(&(m_elmt_scene -> undoStack()), this); - undo_view -> setEmptyLabel(tr("Aucune modification")); - m_undo_dock -> setWidget(undo_view); - - // panel sur le cote pour la liste des parties - m_parts_list = new QListWidget(this); - m_parts_list -> setSelectionMode(QAbstractItemView::ExtendedSelection); - connect(m_elmt_scene, SIGNAL(partsAdded()), this, SLOT(slot_createPartsList())); - connect(m_elmt_scene, SIGNAL(partsRemoved()), this, SLOT(slot_createPartsList())); - connect(m_elmt_scene, SIGNAL(partsZValueChanged()), this, SLOT(slot_createPartsList())); - connect(m_elmt_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updatePartsList())); - connect(m_parts_list, SIGNAL(itemSelectionChanged()), this, SLOT(slot_updateSelectionFromPartsList())); - m_parts_dock = new QDockWidget(tr("Parties", "dock title"), this); - m_parts_dock -> setObjectName("parts_list"); - m_parts_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - m_parts_dock -> setFeatures( - QDockWidget::DockWidgetClosable - |QDockWidget::DockWidgetMovable - |QDockWidget::DockWidgetFloatable); - m_parts_dock -> setMinimumWidth(290); - tabifyDockWidget(m_undo_dock, m_parts_dock); - m_parts_dock -> setWidget(m_parts_list); - - slot_updateInformations(); - slot_createPartsList(); - - // barre d'etat - statusBar() -> showMessage(tr("Éditeur d'éléments", "status bar message")); -} - -/** - Passe l'editeur d'element en mode selection : le pointeur deplace les - elements selectionnes et il est possible d'utiliser un rectangle de selection. -*/ -void QETElementEditor::slot_setRubberBandToView() -{ - m_view -> setDragMode(QGraphicsView::RubberBandDrag); -} - -/** - Passe l'editeur d'element en mode immobile (utilise pour la lecture seule) -*/ -void QETElementEditor::slot_setNoDragToView() -{ - m_view -> setDragMode(QGraphicsView::NoDrag); -} - -/** - Met a jour la zone d'information et d'edition des primitives. - Si plusieurs primitives sont selectionnees, seule leur quantite est - affichee. Sinon, un widget d'edition approprie est mis en place. -*/ -void QETElementEditor::slot_updateInformations() -{ - QList selected_qgis = m_elmt_scene -> selectedItems(); - if (selected_qgis.isEmpty()) { - clearToolsDock(); - m_default_informations -> setText(tr("%n partie(s) sélectionnée(s).", - "", - selected_qgis.size())); - m_default_informations -> setAlignment(Qt::AlignHCenter | Qt::AlignTop); - m_tools_dock_stack -> setCurrentIndex(0); - return; - } - - QList cep_list; - - CustomElementPart* part = dynamic_cast(selected_qgis.first()); - QString selection_xml_name = part -> xmlName(); - bool same_xml_name = true; - bool style_editable = true; - for (QGraphicsItem *qgi: selected_qgis) { - if (CustomElementPart *cep = dynamic_cast(qgi)) { - cep_list << cep; - if (cep -> xmlName() != selection_xml_name) { - same_xml_name = false; - } - } - else { - style_editable = false; - same_xml_name = false; - } - } - if (style_editable) { - style_editable = StyleEditor::isStyleEditable(cep_list); - } - - if (same_xml_name) { - if (selection_xml_name == "terminal" || - selection_xml_name == "text" || - selection_xml_name == "dynamic_text" || - selection_xml_name == "line" || - selection_xml_name == "rect" || - selection_xml_name == "ellipse" || - selection_xml_name == "arc") { - clearToolsDock(); - //We add the editor widget - ElementItemEditor *editor = static_cast(m_editors[selection_xml_name]); - -#if TODO_LIST -#pragma message("@TODO Check if it takes longer than setting the parts again to the editor.") -#endif - // TODO: Check if it takes longer than setting the parts again to the editor. - bool equal = true; - QList parts = editor -> currentParts(); - if (parts.length() == cep_list.length()) { - for (auto cep: cep_list) { - bool part_found = false; - for (auto part: parts) { - if (part == cep) { - part_found = true; - break; - } - } - if (!part_found) { - equal = false; - break; - } - } - } - else { - equal = false; - } - - if (editor) { - bool success = true; - if (equal == false) { - success = editor -> setParts(cep_list); - } - if (success) { - m_tools_dock_stack -> insertWidget(1, editor); - m_tools_dock_stack -> setCurrentIndex(1); - } - else { - qDebug() << "Editor refused part."; - } - } - return; - } - else if (selection_xml_name == "polygon" && cep_list.length() == 1) { -#if TODO_LIST -#pragma message("@TODO maybe allowing multipart edit when number of points is the same?") -#endif - // multi edit for polygons makes no sense - // TODO: maybe allowing multipart edit when number of points is the same? - //We add the editor widget - clearToolsDock(); - ElementItemEditor *editor = static_cast(m_editors[selection_xml_name]); - CustomElementPart* part = editor -> currentPart(); - bool equal = part == cep_list.first(); - - if (editor) { - bool success = true; - if (equal == false) { - success = editor -> setPart(cep_list.first()); - } - if (success) { - m_tools_dock_stack -> insertWidget(1, editor); - m_tools_dock_stack -> setCurrentIndex(1); - } - else { - qDebug() << "Editor refused part."; - } - } - return; - - } - else { - qDebug() << "Multiedit not supported for: " << cep_list.first() -> xmlName(); - } - - } - - //There's several parts selecteds and all can be edited by style editor. - if (style_editable) { - clearToolsDock(); - ElementItemEditor *selection_editor = m_editors["style"]; - if (selection_editor) { - if (selection_editor -> setParts(cep_list)) { - m_tools_dock_stack -> insertWidget(1, selection_editor); - m_tools_dock_stack -> setCurrentIndex(1); - } - else { - qDebug() << "Editor refused part."; - } - } - } - //Else we only display the number of selected items - else { - clearToolsDock(); - m_default_informations -> setText(tr("%n partie(s) sélectionnée(s).", - "", - selected_qgis.size())); - m_default_informations -> setAlignment(Qt::AlignHCenter | Qt::AlignTop); - m_tools_dock_stack -> setCurrentIndex(0); - } -} - -/** - @brief QETElementEditor::checkElement - Do several check about element. - If error is occurred return false -*/ -bool QETElementEditor::checkElement() -{ - //List of warning and error - typedef QPair QETWarning; - QList warnings; - QList errors; - - /// Warning #1: Element haven't got terminal - /// (except for report, because report must have one terminal and this checking is do below) - if (!m_elmt_scene -> containsTerminals() && !m_elmt_scene -> elementType().contains("report")) { - warnings << qMakePair( - tr("Absence de borne", "warning title"), - tr( - "
En l'absence de borne, l'élément ne pourra être" - " relié à d'autres éléments par l'intermédiaire de conducteurs.", - "warning description" - ) - ); - } - - /// Check folio report element - if (m_elmt_scene -> elementType().contains("report")) { - int terminal =0; - - foreach(QGraphicsItem *qgi, m_elmt_scene -> items()) { - if (qgraphicsitem_cast(qgi)) { - terminal ++; - } - } - - ///Error folio report must have only one terminal - if (terminal != 1) { - errors << qMakePair (tr("Absence de borne"), - tr("
Erreur :" - "
Les reports de folio doivent posséder une seul borne." - "
Solution :" - "
Verifier que l'élément ne possède qu'une seul borne")); - } - } - - if (!errors.count() && !warnings.count()) { - return(true); - } - - // Display warnings - QString dialog_message = tr("La vérification de cet élément a généré", "message box content"); - - if (errors.size()) { - dialog_message += QString(tr(" %n erreur(s)", "errors", errors.size())); - } - - if (warnings.size()) { - if (errors.size()) { - dialog_message += QString (tr(" et")); - } - dialog_message += QString (tr(" %n avertissement(s)", "warnings", warnings.size())); - } - dialog_message += " :"; - - dialog_message += "
    "; - QList total = warnings << errors; - foreach(QETWarning warning, total) { - dialog_message += "
  1. "; - dialog_message += QString( - tr("%1 : %2", "warning title: warning description") - ).arg(warning.first).arg(warning.second); - dialog_message += "
  2. "; - } - dialog_message += "
"; - - if (errors.size()) { - QMessageBox::critical(this, tr("Erreurs"), dialog_message); - } - else { - QMessageBox::warning(this, tr("Avertissements"), dialog_message); - } - - //if error == 0 that means they are only warning, we return true. - if (errors.count() == 0) { - return(true); - } - return false; -} - -/** - Charge un fichier - @param filepath Chemin du fichier a charger -*/ -void QETElementEditor::fromFile(const QString &filepath) { - bool state = true; - QString error_message; - - // le fichier doit exister - QFileInfo infos_file(filepath); - if (!infos_file.exists() || !infos_file.isFile()) { - state = false; - error_message = QString(tr("Le fichier %1 n'existe pas.", "message box content")).arg(filepath); - } - - // le fichier doit etre lisible - QFile file(filepath); - if (state) { - if (!file.open(QIODevice::ReadOnly)) { - state = false; - error_message = QString(tr("Impossible d'ouvrir le fichier %1.", "message box content")).arg(filepath); - } - } - - // le fichier doit etre un document XML - QDomDocument document_xml; - if (state) { - if (!document_xml.setContent(&file)) { - state = false; - error_message = tr("Ce fichier n'est pas un document XML valide", "message box content"); - } - file.close(); - } - - if (!state) { - QET::QetMessageBox::critical(this, tr("Erreur", "toolbar title"), error_message); - return; - } - - // chargement de l'element - m_elmt_scene -> fromXml(document_xml); - slot_createPartsList(); - - // gestion de la lecture seule - if (!infos_file.isWritable()) { - QET::QetMessageBox::warning( - this, - tr("Édition en lecture seule", "message box title"), - tr("Vous n'avez pas les privilèges nécessaires pour modifier cet élement. Il sera donc ouvert en lecture seule.", "message box content") - ); - setReadOnly(true); - } - else { - setReadOnly(false); - } - - // memorise le fichier - setFileName(filepath); - QETApp::elementsRecentFiles() -> fileWasOpened(filepath); - slot_updateMenus(); -} - -/** - @brief QETElementEditor::toFile - Save to file the drawed element. - @param fn : path of the file - @return : true if succesfully save. -*/ -bool QETElementEditor::toFile(const QString &fn) { - m_elmt_scene -> clearEventInterface(); - m_elmt_scene -> clearSelection(); - UncheckAddPrimitive(); - - QDomDocument element_xml = m_elmt_scene -> toXml(); - bool writing = QET::writeXmlFile(element_xml, fn); - if (!writing) { - QET::QetMessageBox::warning( - this, - tr("Erreur", "message box title"), - tr("Impossible d'écrire dans ce fichier", "message box content") - ); - } - return(writing); -} - -/** - @brief QETElementEditor::toLocation - Save the element to Location - @param location : location where we must save the current element - @return true if succesfully saved -*/ -bool QETElementEditor::toLocation(const ElementsLocation &location) { - m_elmt_scene -> clearEventInterface(); - m_elmt_scene -> clearSelection(); - UncheckAddPrimitive(); - - if (!location.setXml(m_elmt_scene -> toXml())) { - QET::QetMessageBox::critical(this, - tr("Erreur", "message box title"), - tr("Impossible d'enregistrer l'élément", "message box content")); - return(false); - } - return(true); -} - -/** - @param provided_location Emplacement d'un element - @return true si cet editeur est en train d'editer l'element dont - l'emplacement est location, false sinon -*/ -bool QETElementEditor::isEditing(const ElementsLocation &provided_location) { - if (opened_from_file) { - return( - QET::compareCanonicalFilePaths( - filename_, - QETApp::realPath(provided_location.toString()) - ) - ); - } - else { - return(provided_location == location_); - } -} - -/** - @param provided_filepath Chemin d'un element sur un filesystem - @return true si cet editeur est en train d'editer l'element dont - le chemin est filepath, false sinon -*/ -bool QETElementEditor::isEditing(const QString &provided_filepath) { - // determine le chemin canonique de l'element actuelle edite, si applicable - QString current_filepath; - if (opened_from_file) { - current_filepath = filename_; - } - else { - current_filepath = QETApp::realPath(location_.toString()); - } - - return( - QET::compareCanonicalFilePaths( - current_filepath, - provided_filepath - ) - ); -} - -/** - specifie si l'editeur d'element doit etre en mode lecture seule - @param ro true pour activer le mode lecture seule, false pour le desactiver -*/ -void QETElementEditor::setReadOnly(bool ro) { - read_only = ro; - - // active / desactive les interactions avec la scene - m_view -> setInteractive(!ro); - - slot_updateMenus(); -} - -/** - @return true si l'editeur d'element est en mode lecture seule -*/ -bool QETElementEditor::isReadOnly() const -{ - return(read_only); -} - -/** - @brief QETElementEditor::addLine - Set line creation interface to scene -*/ -void QETElementEditor::addLine() -{ - m_elmt_scene -> setEventInterface(new ESEventAddLine(m_elmt_scene)); -} - -/** - @brief QETElementEditor::addRect - Set rectangle creation interface to scene -*/ -void QETElementEditor::addRect() -{ - m_elmt_scene -> setEventInterface(new ESEventAddRect(m_elmt_scene)); -} - -/** - @brief QETElementEditor::addEllipse - Set ellipse creation interface to scene -*/ -void QETElementEditor::addEllipse() -{ - m_elmt_scene -> setEventInterface(new ESEventAddEllipse(m_elmt_scene)); -} - -/** - @brief QETElementEditor::addPolygon - Set polygon creation interface to scene -*/ -void QETElementEditor::addPolygon() -{ - m_elmt_scene -> setEventInterface(new ESEventAddPolygon(m_elmt_scene)); -} - -/** - @brief QETElementEditor::addArc - Set arc creation interface to scene -*/ -void QETElementEditor::addArc() -{ - m_elmt_scene -> setEventInterface(new ESEventAddArc(m_elmt_scene)); -} - -/** - @brief QETElementEditor::addText - Set text creation interface to scene -*/ -void QETElementEditor::addText() -{ - m_elmt_scene -> setEventInterface(new ESEventAddText(m_elmt_scene)); -} - -/** - @brief QETElementEditor::addTerminal - Set terminal creation interface to scene -*/ -void QETElementEditor::addTerminal() -{ - m_elmt_scene -> setEventInterface(new ESEventAddTerminal(m_elmt_scene)); -} - -/** - @brief QETElementEditor::addDynamicTextField - Set dynamic text field creation interface to scene -*/ -void QETElementEditor::addDynamicTextField() -{ - m_elmt_scene -> setEventInterface(new ESEventAddDynamicTextField(m_elmt_scene)); -} - -/** - @brief QETElementEditor::UncheckAddPrimitive - Uncheck all action related to primitive -*/ -void QETElementEditor::UncheckAddPrimitive() -{ - foreach(QAction *action, parts -> actions()) { - action -> setChecked(false); - } -} - -/** - Lance l'assistant de creation d'un nouvel element. -*/ -void QETElementEditor::slot_new() -{ - NewElementWizard new_element_wizard(this); - new_element_wizard.exec(); -} - -/** - Ouvre un element -*/ -void QETElementEditor::slot_open() -{ - // demande le chemin virtuel de l'element a ouvrir a l'utilisateur - ElementsLocation location = ElementDialog::getOpenElementLocation(this); - if (location.isNull()) { - return; - } - QETApp::instance() -> openElementLocations(QList() << location); -} - -/** - Ouvre un fichier - Demande un fichier a l'utilisateur et ouvre ce fichier -*/ -void QETElementEditor::slot_openFile() -{ - // repertoire a afficher initialement dans le dialogue - QString open_dir = filename_.isEmpty() ? QETApp::customElementsDir() : QDir(filename_).absolutePath(); - - // demande un nom de fichier a ouvrir a l'utilisateur - QString user_filename = QETElementEditor::getOpenElementFileName(this, open_dir); - - // ouvre l'element - openElement(user_filename); -} - -/** - Slot utilise pour ouvrir un fichier recent. - Transfere filepath au slot openElement seulement si cet editeur est actif - @param filepath Fichier a ouvrir - @see openElement -*/ -void QETElementEditor::openRecentFile(const QString &filepath) { - // small hack to prevent all element editors from trying to topen the required - // recent file at the same time - if (qApp -> activeWindow() != this) { - return; - } - openElement(filepath); -} - -/** - @brief QETElementEditor::slot_openDxf -*/ -void QETElementEditor::slot_openDxf () -{ -#ifdef TODO_LIST -# pragma message("@TODO Merge 'DXF to GET-2020' code in to Qet") -# pragma message("https://github.com/qelectrotech/DXFtoQET-2020") -#endif -#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) -QString program = (QDir::homePath() + "/Application Data/qet/DXFtoQET.exe"); -#elif defined(Q_OS_MAC) -QString program = (QDir::homePath() + "/.qet/DXFtoQET.app"); -#else -QString program = (QDir::homePath() + "/.qet/DXFtoQET"); -#endif -QStringList arguments; -QProcess *DXF = new QProcess(qApp); -DXF -> start(program,arguments); - -} - -/** - Ouvre un fichier element dans un nouvel editeur - Cette methode ne controle pas si le fichier est deja ouvert - @param filepath Fichier a ouvrir - @see fromFile - @see QETApp::openElementFiles -*/ -void QETElementEditor::openElement(const QString &filepath) { - if (filepath.isEmpty()) { - return; - } - // we have to test the file existence here because QETApp::openElementFiles() - // will discard non-existent files through QFileInfo::canonicalFilePath() - if (!QFile::exists(filepath)) { - QET::QetMessageBox::critical( - this, - tr("Impossible d'ouvrir le fichier", "message box title"), - QString( - tr("Il semblerait que le fichier %1 que vous essayez d'ouvrir" - " n'existe pas ou plus.") - ).arg(filepath) - ); - } - QETApp::instance() -> openElementFiles(QStringList() << filepath); -} - -/** - @brief QETElementEditor::slot_reload - Reload the element from the file or location -*/ -void QETElementEditor::slot_reload() -{ - //If user already edit the element, ask confirmation to reload - if (!m_elmt_scene -> undoStack().isClean()) { - QMessageBox::StandardButton answer = QET::QetMessageBox::question(this, - tr("Recharger l'élément", "dialog title"), - 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"), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::Cancel); - if (answer != QMessageBox::Yes){ - return; - } - } - - //Reload the element - m_elmt_scene -> reset(); - if (opened_from_file) { - fromFile(filename_); - } - else { - fromLocation(location_); - } -} - -/** - @brief QETElementEditor::slot_save - Save the current editing element. - If the filepath or location is unknown, use save_as instead - @return true if save with success -*/ -bool QETElementEditor::slot_save() -{ - // Check element befor writing - if (checkElement()) { - //If we don't know the name of the current file, use save as instead - if (opened_from_file) { - if (filename_.isEmpty()) { - return(slot_saveAsFile()); - } - - //Else wa save to the file at filename_ path - bool result_save = toFile(filename_); - if (result_save) m_elmt_scene -> undoStack().setClean(); - return(result_save); - } - else { - if (location_.isNull()) { - return(slot_saveAs()); - } - - //Else save to the known location - bool result_save = toLocation(location_); - if (result_save) { - m_elmt_scene -> undoStack().setClean(); - emit saveToLocation(location_); - } - return(result_save); - } - } - - QMessageBox::critical(this, tr("Echec de l'enregistrement"), tr("L'enregistrement à échoué,\nles conditions requises ne sont pas valides")); - return false; -} - -/** - @brief QETElementEditor::slot_saveAs - Ask a location to user and save the current edited element - to this location - @return true if save with success -*/ -bool QETElementEditor::slot_saveAs() -{ - // Check element befor writing - if (checkElement()) { - //Ask a location to user - ElementsLocation location = ElementDialog::getSaveElementLocation(this); - if (location.isNull()) { - return(false); - } - - bool result_save = toLocation(location); - if (result_save) { - setLocation(location); - m_elmt_scene -> undoStack().setClean(); - emit saveToLocation(location); - } - - return(result_save); - } - QMessageBox::critical(this, tr("Echec de l'enregistrement"), tr("L'enregistrement à échoué,\nles conditions requises ne sont pas valides")); - return (false); -} - -/** - @brief QETElementEditor::slot_saveAsFile - Ask a file to user and save the current edited element to this file - @return true if save with success -*/ -bool QETElementEditor::slot_saveAsFile() -{ - // Check element befor writing - if (checkElement()) { - //Ask a filename to user, for save the element - QString fn = QFileDialog::getSaveFileName( - this, - tr("Enregistrer sous", "dialog title"), - filename_.isEmpty() ? QETApp::customElementsDir() : QDir(filename_).absolutePath(), - tr( - "Éléments QElectroTech (*.elmt)", - "filetypes allowed when saving an element file" - ) - ); - - if (fn.isEmpty()) { - return(false); - } - - //If the name doesn't end by .elmt, we add it - if (!fn.endsWith(".elmt", Qt::CaseInsensitive)) { - fn += ".elmt"; - } - - bool result_save = toFile(fn); - //If the save success, the filename is keep - if (result_save) { - setFileName(fn); - QETApp::elementsRecentFiles() -> fileWasOpened(fn); - m_elmt_scene -> undoStack().setClean(); - } - - return(result_save); - } - QMessageBox::critical(this, tr("Echec de l'enregistrement"), tr("L'enregistrement à échoué,\nles conditions requises ne sont pas valides")); - return false; -} - -/** - @return true si l'element peut etre ferme. - Un element peut etre ferme s'il ne comporte aucune modification. - Si l'element comporte des modifications, la question est posee a - l'utilisateur. -*/ -bool QETElementEditor::canClose() -{ - if (m_elmt_scene -> undoStack().isClean()) { - return(true); - } - // demande d'abord a l'utilisateur s'il veut enregistrer l'element en cours - QMessageBox::StandardButton answer = QET::QetMessageBox::question( - this, - tr("Enregistrer l'élément en cours ?", "dialog title"), - QString( - tr( - "Voulez-vous enregistrer l'élément %1 ?", - "dialog content - %1 is an element name" - ) - ).arg(m_elmt_scene -> names().name()), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::Cancel - ); - bool result; - switch(answer) { - case QMessageBox::Cancel: { - result = false; - break; // l'utilisateur annule : echec de la fermeture - } - case QMessageBox::Yes: { - result = slot_save(); - break; // l'utilisateur dit oui : la reussite depend de l'enregistrement - } - default: { - result = true; // l'utilisateur dit non ou ferme le dialogue: c'est reussi - } - } - return(result); -} - -/** - Enleve et cache le widget affiche par le dock permettant d'editer les - parties. - @return le widget enleve, ou 0 s'il n'y avait pas de widget a enlever -*/ -QWidget *QETElementEditor::clearToolsDock() -{ - if (QWidget *previous_widget = m_tools_dock_stack -> widget(1)) { - m_tools_dock_stack -> removeWidget(previous_widget); - previous_widget -> setParent(nullptr); - previous_widget -> hide(); - return(previous_widget); - } - return(nullptr); -} - -/** - Exporte le document XML xml_document vers le presse-papier puis declenche - son collage dans l'editeur courant, avec selection de la zone de collage - @param xml_document Document XML a copier/coller - @see ElementView::pasteInArea -*/ -void QETElementEditor::copyAndPasteXml(const QDomDocument &xml_document) { - // accede au presse-papier - QClipboard *clipboard = QApplication::clipboard(); - - // genere la description XML de la selection - QString clipboard_content = xml_document.toString(4); - - // met la description XML dans le presse-papier - if (clipboard -> supportsSelection()) { - clipboard -> setText(clipboard_content, QClipboard::Selection); - } - clipboard -> setText(clipboard_content); - - m_view -> pasteInArea(); -} - -/** - Permet de quitter l'editeur lors de la fermeture de la fenetre principale - @param qce Le QCloseEvent correspondant a l'evenement de fermeture -*/ -void QETElementEditor::closeEvent(QCloseEvent *qce) { - if (canClose()) { - writeSettings(); - setAttribute(Qt::WA_DeleteOnClose); - m_elmt_scene -> reset(); - qce -> accept(); - } - else { - qce -> ignore(); - } -} - -/** - Executed the first time the window editor is displayed. -*/ -void QETElementEditor::firstActivation(QEvent *event) { - Q_UNUSED(event) - QTimer::singleShot(250, m_view, SLOT(zoomFit())); -} - -/** - Remplit la liste des parties -*/ -void QETElementEditor::slot_createPartsList() -{ - m_parts_list -> blockSignals(true); - m_parts_list -> clear(); - QList qgis = m_elmt_scene -> zItems(); - - // on ne construit plus la liste a partir de 200 primitives - // c'est ingerable : la maj de la liste prend trop de temps et le resultat - // est inexploitable - if (qgis.count() <= QET_MAX_PARTS_IN_ELEMENT_EDITOR_LIST) { - for (int j = qgis.count() - 1 ; j >= 0 ; -- j) { - QGraphicsItem *qgi = qgis[j]; - if (CustomElementPart *cep = dynamic_cast(qgi)) { - QString part_desc = cep -> name(); - QListWidgetItem *qlwi = new QListWidgetItem(part_desc); - QVariant v; -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove - v.setValue(qgi); -#else -#if TODO_LIST -#pragma message("@TODO remove code for QT 6 or later") -#endif - qDebug()<<"Help code for QT 6 or later"; -#endif - qlwi -> setData(42, v); - m_parts_list -> addItem(qlwi); - qlwi -> setSelected(qgi -> isSelected()); - } - } - } - else { - m_parts_list -> addItem(new QListWidgetItem(tr("Trop de primitives, liste non générée."))); - } - m_parts_list -> blockSignals(false); -} - -/** - Met a jour la selection dans la liste des parties -*/ -void QETElementEditor::slot_updatePartsList() -{ - int items_count = m_elmt_scene -> items().count(); - if (m_parts_list -> count() != items_count) { - slot_createPartsList(); - } - else if (items_count <= QET_MAX_PARTS_IN_ELEMENT_EDITOR_LIST) { - m_parts_list -> blockSignals(true); - int i = 0; - QList items = m_elmt_scene -> zItems(); - for (int j = items.count() - 1 ; j >= 0 ; -- j) { - QGraphicsItem *qgi = items[j]; - QListWidgetItem *qlwi = m_parts_list -> item(i); - if (qlwi) qlwi -> setSelected(qgi -> isSelected()); - ++ i; - } - m_parts_list -> blockSignals(false); - } -} - -/** - Met a jour la selection des parties de l'element a partir de la liste des - parties -*/ -void QETElementEditor::slot_updateSelectionFromPartsList() -{ - m_elmt_scene -> blockSignals(true); - m_parts_list -> blockSignals(true); - for (int i = 0 ; i < m_parts_list -> count() ; ++ i) { - QListWidgetItem *qlwi = m_parts_list -> item(i); - QGraphicsItem *qgi = qlwi -> data(42).value(); - if (qgi) { - qgi -> setSelected(qlwi -> isSelected()); - } - } - m_parts_list -> blockSignals(false); - m_elmt_scene -> blockSignals(false); - slot_updateInformations(); - slot_updateMenus(); -} - -/** - @brief QETElementEditor::readSettings - Read settings -*/ -void QETElementEditor::readSettings() -{ - QSettings settings; - - // dimensions et position de la fenetre - QVariant geometry = settings.value("elementeditor/geometry"); - if (geometry.isValid()) { - restoreGeometry(geometry.toByteArray()); - } - - // etat de la fenetre (barres d'outils, docks...) - QVariant state = settings.value("elementeditor/state"); - if (state.isValid()) { - restoreState(state.toByteArray()); - } - - // informations complementaires de l'element : valeur par defaut - m_elmt_scene -> setInformations(settings.value("elementeditor/default-informations", "").toString()); -} - -/** - @brief QETElementEditor::writeSettings - Write the settings -*/ -void QETElementEditor::writeSettings() -{ - QSettings settings; - settings.setValue("elementeditor/geometry", saveGeometry()); - settings.setValue("elementeditor/state", saveState()); -} - -/** - @return les decalages horizontaux et verticaux (sous la forme d'un point) a - utiliser lors d'un copier/coller avec decalage. -*/ -QPointF QETElementEditor::pasteOffset() -{ - QPointF paste_offset(5.0, 0.0); - return(paste_offset); -} - -/** - Demande a l'utilisateur d'ouvrir un fichier sense etre un element. - @param parent QWidget parent du dialogue d'ouverture de fichier - @param initial_dir Repertoire a afficher initialement - si une chaine vide - est fournie, QETApp::customElementsDir() sera utilise. - @return Le chemin du fichier choisi ou une chaine vide si l'utilisateur a - clique sur le bouton "Annuler". - @see QETApp::customElementsDir() -*/ -QString QETElementEditor::getOpenElementFileName(QWidget *parent, const QString &initial_dir) { - // demande un nom de fichier a ouvrir a l'utilisateur - QString user_filename = QFileDialog::getOpenFileName( - parent, - tr("Ouvrir un fichier", "dialog title"), - initial_dir.isEmpty() ? QETApp::customElementsDir() : initial_dir, - tr( - "Éléments QElectroTech (*.elmt);;" - "Fichiers XML (*.xml);;" - "Tous les fichiers (*)", - "filetypes allowed when opening an element file" - ) - ); - return(user_filename); -} - -/** - @brief QETElementEditor::fromLocation - Location of the element to edit - @param location -*/ -void QETElementEditor::fromLocation(const ElementsLocation &location) { - if (!location.isElement()) { - QET::QetMessageBox::critical(this, - tr("Élément inexistant.", "message box title"), - tr("Le chemin virtuel choisi ne correspond pas à un élément.", "message box content")); - return; - } - if (!location.exist()) { - QET::QetMessageBox::critical(this, - tr("Élément inexistant.", "message box title"), - tr("L'élément n'existe pas.", "message box content")); - return; - } - - //The file must be an xml document - QDomDocument document_xml; - QDomNode node = document_xml.importNode(location.xml(), true); - document_xml.appendChild(node); - - //Load the element - m_elmt_scene -> fromXml(document_xml); - slot_createPartsList(); - - //location is read only - if (!location.isWritable()) { - QET::QetMessageBox::warning(this, - tr("Édition en lecture seule", "message box title"), - tr("Vous n'avez pas les privilèges nécessaires pour modifier cet élement. Il sera donc ouvert en lecture seule.", "message box content")); - setReadOnly(true); - } - else { - setReadOnly(false); - } - - setLocation(location); - slot_updateMenus(); -} - -/** - Demande un fichier a l'utilisateur, l'ouvre en tant que fichier element, - met son contenu dans le presse-papiers, et appelle ElementView::PasteInArea -*/ -void QETElementEditor::pasteFromFile() -{ - // demande le chemin du fichier a ouvrir a l'utilisateur - QString element_file_path = getOpenElementFileName(this); - if (element_file_path.isEmpty()) { - return; - } - - QString error_message; - QDomDocument xml_document; - QFile element_file(element_file_path); - // le fichier doit etre lisible - if (!element_file.open(QIODevice::ReadOnly)) { - error_message = QString(tr("Impossible d'ouvrir le fichier %1.", "message box content")).arg(element_file_path); - } - else { - // le fichier doit etre un document XML - if (!xml_document.setContent(&element_file)) { - error_message = tr("Ce fichier n'est pas un document XML valide", "message box content"); - } - element_file.close(); - } - - if (!error_message.isEmpty()) { - QET::QetMessageBox::critical(this, tr("Erreur", "toolbar title"), error_message); - } - copyAndPasteXml(xml_document); -} - -/** - @brief QETElementEditor::pasteFromElement - Ask an element to user, copy the xml definition of the element - to the clipboard and call ElementView::PasteInArea -*/ -void QETElementEditor::pasteFromElement() -{ - //Ask for a location - ElementsLocation location = ElementDialog::getOpenElementLocation(this); - if (location.isNull()) { - return; - } - - if (!location.isElement()) { - QET::QetMessageBox::critical(this, - tr("Élément inexistant.", "message box title"), - tr("Le chemin virtuel choisi ne correspond pas à un élément.", "message box content")); - return; - } - if (!location.exist()) { - QET::QetMessageBox::critical(this, - tr("Élément inexistant.", "message box title"), - tr("L'élément n'existe pas.", "message box content")); - return; - } - - //Create an xml document from the location xml - QDomDocument document_xml; - QDomNode node = document_xml.importNode(location.xml(), true); - document_xml.appendChild(node); - - copyAndPasteXml(document_xml); -} - -/** - Met a jour l'editeur de primitive actuellement visible. - Si aucun editeur de primitive n'est visible, ce slot ne fait rien. -*/ -void QETElementEditor::updateCurrentPartEditor() -{ - // si aucun widget d'edition n'est affiche, on ne fait rien - if (!m_tools_dock_stack -> currentIndex()) { - return; - } - - // s'il y a un widget d'edition affiche, on le met a jour - if (ElementItemEditor *current_editor = dynamic_cast(m_tools_dock_stack -> widget(1))) { - current_editor -> updateForm(); - } -} diff --git a/sources/editor/qetelementeditor.h b/sources/editor/qetelementeditor.h deleted file mode 100644 index c08061da1..000000000 --- a/sources/editor/qetelementeditor.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - Copyright 2006-2021 The QElectroTech Team - This file is part of QElectroTech. - - QElectroTech is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - QElectroTech is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with QElectroTech. If not, see . -*/ -#ifndef CUSTOM_ELEMENT_EDITOR_H -#define CUSTOM_ELEMENT_EDITOR_H -#include "../ElementsCollection/elementslocation.h" -#include "../qet.h" -#include "../qetmainwindow.h" -#include "elementscene.h" - -class ElementItemEditor; -class ElementView; - -/** - This class represents an element editor, allowing users to draw, change and - configure a particular electrical element. -*/ -class QETElementEditor : public QETMainWindow { - Q_OBJECT - - // constructor, destructor - public: - QETElementEditor(QWidget * = nullptr); - ~QETElementEditor() override; - private: - QETElementEditor(const QETElementEditor &); - void setupActions(); - void setupMenus(); - void setupInterface(); - - // attributes - private: - /// whether the editor is "read-only" - bool read_only; - /// menus - QMenu *file_menu, *edit_menu, *paste_from_menu, *display_menu, *tools_menu; - /// view widget for the editing scene - ElementView *m_view; - /// editing scene - ElementScene *m_elmt_scene; - /// container for widgets dedicated to primitive edition - QDockWidget *m_tools_dock; - /// Stack of widgets for tools_dock - QStackedWidget *m_tools_dock_stack; - /// label displayed when several primitives are selected - QLabel *m_default_informations; - /// Hash associating primitive names with their matching edition widget - QHash m_editors; - /// container for the undo list - QDockWidget *m_undo_dock; - /// Container for the list of existing primitives - QDockWidget *m_parts_dock; - /// List of primitives - QListWidget *m_parts_list; - /// actions for the "file" menu - QAction *new_element, *open, *open_dxf, *open_file, *save, *save_as, *save_as_file, *reload, *quit; - /// actions for the "edit" menu - QAction *selectall, *deselectall, *inv_select; - QAction *cut, *copy, *paste, *paste_in_area, *paste_from_file, *paste_from_elmt; - QAction *undo, *redo; - QAction *edit_delete, *edit_size_hs, *edit_names, *edit_author, *m_edit_properties; - /// toolbars - QToolBar *parts_toolbar, *main_toolbar, *view_toolbar, *depth_toolbar, *element_toolbar; - /// Action group - QActionGroup *parts, *m_zoom_ag, *m_depth_action_group; - /// minimum window title - QString min_title; - /// filename of the currently edited element - QString filename_; - /// location of the currently edited element - ElementsLocation location_; - /// whether the currently edited element comes from a file or a location - bool opened_from_file; - - // methods - public: - void setNames(const NamesList &); - void setLocation(const ElementsLocation &); - ElementsLocation location() const; - void setFileName(const QString &); - QString fileName() const; - void setReadOnly(bool); - bool isReadOnly() const; - void fromFile(const QString &); - void fromLocation(const ElementsLocation &); - bool toFile(const QString &); - bool toLocation(const ElementsLocation &location); - bool isEditing(const ElementsLocation &); - bool isEditing(const QString &); - ElementScene *elementScene() const; - void readSettings(); - void writeSettings(); - static QPointF pasteOffset(); - static QString getOpenElementFileName(QWidget * = nullptr, const QString & = QString()); - void contextMenu(QPoint p, QList actions = QList()); - - signals: - void saveToLocation(ElementsLocation loc); - - protected: - void closeEvent(QCloseEvent *) override; - void firstActivation(QEvent *) override; - - private: - bool canClose(); - QWidget *clearToolsDock(); - void copyAndPasteXml(const QDomDocument &); - - public slots: - void addLine(); - void addRect(); - void addEllipse(); - void addPolygon(); - void addArc(); - void addText(); - void addTerminal(); - void addDynamicTextField(); - void UncheckAddPrimitive(); - - void slot_new(); - void slot_open(); - void slot_openDxf(); - void slot_openFile(); - void openRecentFile(const QString &); - void openElement(const QString &); - void slot_reload(); - bool slot_save(); - bool slot_saveAs(); - bool slot_saveAsFile(); - void slot_setRubberBandToView(); - void slot_setNoDragToView(); - void slot_updateInformations(); - void slot_updateMenus(); - void slot_updateTitle(); - void slot_createPartsList(); - void slot_updatePartsList(); - void slot_updateSelectionFromPartsList(); - bool checkElement(); - void pasteFromFile(); - void pasteFromElement(); - void updateCurrentPartEditor(); -}; - -/** - @param nameslist the new list of names for the currently edited element -*/ -inline void QETElementEditor::setNames(const NamesList &nameslist) { - m_elmt_scene -> setNames(nameslist); -} - -/** - @return the location of the currently edited element -*/ -inline ElementsLocation QETElementEditor::location() const -{ - return(location_); -} - -/** - @return the filename of the currently edited element -*/ -inline QString QETElementEditor::fileName() const -{ - return(filename_); -} - -/** - @return the editing scene -*/ -inline ElementScene *QETElementEditor::elementScene() const -{ - return(m_elmt_scene); -} - -#endif diff --git a/sources/editor/ui/dynamictextfieldeditor.cpp b/sources/editor/ui/dynamictextfieldeditor.cpp index 658ab3319..ca6011401 100644 --- a/sources/editor/ui/dynamictextfieldeditor.cpp +++ b/sources/editor/ui/dynamictextfieldeditor.cpp @@ -24,7 +24,8 @@ #include "../../qetinformation.h" #include "../../ui/alignmenttextdialog.h" #include "../../ui/compositetexteditdialog.h" -#include "../qetelementeditor.h" +#include "../ui/qetelementeditor.h" +#include "../elementscene.h" #include "ui_dynamictextfieldeditor.h" #include diff --git a/sources/editor/ui/qetelementeditor.cpp b/sources/editor/ui/qetelementeditor.cpp new file mode 100644 index 000000000..ec79a0739 --- /dev/null +++ b/sources/editor/ui/qetelementeditor.cpp @@ -0,0 +1,1480 @@ +/* + Copyright 2006-2021 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#include "qetelementeditor.h" +#include "ui_qetelementeditor.h" +#include "../elementscene.h" +#include "../../qeticons.h" +#include "../elementview.h" +#include "../../qetmessagebox.h" +#include "../../qetapp.h" +#include "../../recentfiles.h" +#include "../graphicspart/customelementpart.h" +#include "../elementitemeditor.h" +#include "../styleeditor.h" +#include "../esevent/eseventaddline.h" +#include "../esevent/eseventaddrect.h" +#include "../esevent/eseventaddellipse.h" +#include "../esevent/eseventaddpolygon.h" +#include "../esevent/eseventaddarc.h" +#include "../esevent/eseventaddtext.h" +#include "../esevent/eseventaddterminal.h" +#include "../esevent/eseventadddynamictextfield.h" +#include "../../elementdialog.h" +#include "../graphicspart/partterminal.h" +#include "../arceditor.h" +#include "ellipseeditor.h" +#include "lineeditor.h" +#include "polygoneditor.h" +#include "rectangleeditor.h" +#include "../terminaleditor.h" +#include "texteditor.h" +#include "dynamictextfieldeditor.h" +#include "../../newelementwizard.h" +#include "../editorcommands.h" + +#include +#include + +/** + Number max of primitive displayed by the parts list widget + */ +#define QET_MAX_PARTS_IN_ELEMENT_EDITOR_LIST 200 + +/** + * @brief QETElementEditor::QETElementEditor + * @param parent + */ +QETElementEditor::QETElementEditor(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::QETElementEditor) +{ + ui->setupUi(this); + initGui(); + setupActions(); + setupConnection(); + + auto menu = createPopupMenu(); + menu->setTearOffEnabled(true); + menu->setTitle(tr("Afficher", "menu entry")); + menu->setIcon(QET::Icons::ConfigureToolbars); + ui->m_display_menu->addMenu(menu); + //ui->m_display_menu->insertMenu(ui->m_zoom_in_action, menu); + + setWindowState(Qt::WindowMaximized); + readSettings(); + show(); +} + +/** + * @brief QETElementEditor::~QETElementEditor + */ +QETElementEditor::~QETElementEditor() +{ + delete ui; + qDeleteAll(m_editors.begin(), m_editors.end()); +} + +/** + * @brief QETElementEditor::contextMenu + * Display a context menu, with all available action. + * @param p : the pos of the menu, in screen coordinate + * @param actions : a list of actions who can be prepended to the context menu. + */ +void QETElementEditor::contextMenu(QPoint p, QList actions) +{ + QMenu menu(this); + menu.addActions(std::move(actions)); + menu.addSeparator(); + menu.addAction(m_undo_action); + menu.addAction(m_redo_action); + menu.addAction(ui->m_select_all_act); + menu.addAction(ui->m_deselect_all_action); + menu.addAction(ui->m_revert_selection_action); + menu.addSeparator(); + menu.addAction(ui->m_delete_action); + menu.addAction(ui->m_cut_action); + menu.addAction(ui->m_copy_action); + menu.addSeparator(); + menu.addAction(ui->m_paste_action); + menu.addAction(ui->m_paste_in_area_action); + menu.addMenu(ui->m_paste_from_menu); + menu.addSeparator(); + menu.addActions(m_depth_action_group -> actions()); + + //Remove from the context menu the actions which are disabled. + const QListmenu_actions = menu.actions(); + for(QAction *action : menu_actions) { + if(!action -> isEnabled()) { + menu.removeAction(action); + } + } + menu.exec(p); +} + +/** + * @brief QETElementEditor::setNames + * Set the names list of the edited element + * @param name_list + */ +void QETElementEditor::setNames(const NamesList &name_list) +{ + m_elmt_scene->setNames(name_list); +} + +/** + * @brief QETElementEditor::setLocation + * Set the location to edit + * @param location + */ +void QETElementEditor::setLocation(const ElementsLocation &location) +{ + m_location = location; + m_opened_from_file = false; + setReadOnly(!location.isWritable()); + updateTitle(); + +} + +/** + * @brief QETElementEditor::location + * @return The location of the edited element + */ +ElementsLocation QETElementEditor::location() const { + return m_location; +} + +/** + * @brief QETElementEditor::setFileName + * Set the file name of the edited element + * @param file_name + */ +void QETElementEditor::setFileName(const QString &file_name) +{ + m_file_name = file_name; + m_opened_from_file = true; + bool must_be_read_only = !QFileInfo(file_name).isWritable(); + if (isReadOnly() != must_be_read_only) { + setReadOnly(must_be_read_only); + } + updateTitle(); +} + +/** + * @brief QETElementEditor::fileName + * @return the file name of this element + */ +QString QETElementEditor::fileName() const { + return m_file_name; +} + +void QETElementEditor::setReadOnly(bool ro) +{ + m_read_only = ro; + m_view->setInteractive(!ro); + updateAction(); +} + +bool QETElementEditor::isReadOnly() const { + return m_read_only; +} + +/** + * @brief QETElementEditor::fromFile + * Open an element from @filepath + * @param filepath + */ +void QETElementEditor::fromFile(const QString &filepath) +{ + bool state_ = true; + QString error_message; + + + QFileInfo infos_file(filepath); + if (!infos_file.exists() || !infos_file.isFile()) + { + state_ = false; + error_message = QString(tr("Le fichier %1 n'existe pas.", "message box content")).arg(filepath); + } + + QFile file(filepath); + if (state_ && !file.open(QIODevice::ReadOnly)) { + state_ = false; + error_message = QString(tr("Impossible d'ouvrir le fichier %1.", "message box content")).arg(filepath); + } + + QDomDocument document_xml; + if (state_) { + if (!document_xml.setContent(&file)) { + state_ = false; + error_message = tr("Ce fichier n'est pas un document XML valide", "message box content"); + } + file.close(); + } + + if (!state_) { + QET::QetMessageBox::critical(this, tr("Erreur", "toolbar title"), error_message); + return; + } + + m_elmt_scene -> fromXml(document_xml); + fillPartsList(); + + if (!infos_file.isWritable()) + { + QET::QetMessageBox::warning( + this, + tr("Édition en lecture seule", "message box title"), + tr("Vous n'avez pas les privilèges nécessaires pour modifier cet élement. Il sera donc ouvert en lecture seule.", "message box content") + ); + setReadOnly(true); + } + else { + setReadOnly(false); + } + + // memorise le fichier + setFileName(filepath); + QETApp::elementsRecentFiles() -> fileWasOpened(filepath); + updateAction(); +} + +/** + * @brief QETElementEditor::toFile + * Save to a file the current edited element + * @param filepath : path of the file + * @return true if success + */ +bool QETElementEditor::toFile(const QString &filepath) +{ + m_elmt_scene -> clearEventInterface(); + m_elmt_scene -> clearSelection(); + UncheckAddPrimitive(); + + QDomDocument element_xml = m_elmt_scene -> toXml(); + bool writing = QET::writeXmlFile(element_xml, filepath); + if (!writing) { + QET::QetMessageBox::warning( + this, + tr("Erreur", "message box title"), + tr("Impossible d'écrire dans ce fichier", "message box content") + ); + } + return(writing); +} + +/** + * @brief QETElementEditor::fromLocation + * Location of an element to edit. + */ +void QETElementEditor::fromLocation(const ElementsLocation &location) +{ + if (!location.isElement()) { + QET::QetMessageBox::critical(this, + tr("Élément inexistant.", "message box title"), + tr("Le chemin virtuel choisi ne correspond pas à un élément.", "message box content")); + return; + } + if (!location.exist()) { + QET::QetMessageBox::critical(this, + tr("Élément inexistant.", "message box title"), + tr("L'élément n'existe pas.", "message box content")); + return; + } + + //The file must be an xml document + QDomDocument document_xml; + QDomNode node = document_xml.importNode(location.xml(), true); + document_xml.appendChild(node); + + //Load the element + m_elmt_scene -> fromXml(document_xml); + fillPartsList(); + + //location is read only + if (!location.isWritable()) { + QET::QetMessageBox::warning(this, + tr("Édition en lecture seule", "message box title"), + tr("Vous n'avez pas les privilèges nécessaires pour modifier cet élement. Il sera donc ouvert en lecture seule.", "message box content")); + setReadOnly(true); + } + else { + setReadOnly(false); + } + + setLocation(location); + updateAction(); +} + +/** + * @brief QETElementEditor::toLocation + * Save the edited element into @location + * @param location + * @return true if succesfully saved + */ +bool QETElementEditor::toLocation(const ElementsLocation &location) +{ + m_elmt_scene -> clearEventInterface(); + m_elmt_scene -> clearSelection(); + UncheckAddPrimitive(); + + if (!location.setXml(m_elmt_scene -> toXml())) { + QET::QetMessageBox::critical(this, + tr("Erreur", "message box title"), + tr("Impossible d'enregistrer l'élément", "message box content")); + return(false); + } + return(true); +} + +/** + * @brief QETElementEditor::isEditing + * @param location + * @return true if this editor is currently + * editing element of location + */ +bool QETElementEditor::isEditing(const ElementsLocation &location) +{ + if (m_opened_from_file) + { + auto r = QET::compareCanonicalFilePaths( + m_file_name, + QETApp::realPath(location.toString())); + return r; + } + else { + return(location == m_location); + } +} + +/** + * @brief QETElementEditor::isEditing + * @param filepath + * @return true if this editor is currently + * editing element at filepath. + */ +bool QETElementEditor::isEditing(const QString &filepath) +{ + QString current_filepath; + if (m_opened_from_file) { + current_filepath = m_file_name; + } else { + current_filepath = QETApp::realPath(m_location.toString()); + } + + auto r = QET::compareCanonicalFilePaths( + current_filepath, + filepath); + return r; +} + +/** + * @brief QETElementEditor::elementScene + * @return + */ +ElementScene *QETElementEditor::elementScene() const { + return m_elmt_scene; +} + +/** + * @brief QETElementEditor::elementView + * @return + */ +ElementView *QETElementEditor::elementView() const { + return m_view; +} + +/** + * @brief QETElementEditor::pasteOffset + * @return the vertical and horizontal paste offset + */ +QPointF QETElementEditor::pasteOffset() +{ + QPointF paste_offset(5.0, 0.0); + return(paste_offset); +} + +/** + * @brief QETElementEditor::getOpenElementFileName + * Ask user to open a file who must be an element. + * @param parent + * @param dir + * @return + */ +QString QETElementEditor::getOpenElementFileName(QWidget *parent, const QString &dir) +{ + QString user_filename = QFileDialog::getOpenFileName( + parent, + tr("Ouvrir un fichier", "dialog title"), + dir.isEmpty() ? QETApp::customElementsDir() : dir, + tr( + "Éléments QElectroTech (*.elmt);;" + "Fichiers XML (*.xml);;" + "Tous les fichiers (*)", + "filetypes allowed when opening an element file" + ) + ); + return(user_filename); +} + +/** + * @brief QETElementEditor::updateTitle + * Update the title of the windows + */ +void QETElementEditor::updateTitle() +{ + QString title = m_min_title; + title += " - " + m_elmt_scene -> names().name() + " "; + if (!m_file_name.isEmpty() || !m_location.isNull()) { + if (!m_elmt_scene -> undoStack().isClean()) { + title += tr("[Modifié]", "window title tag"); + } + } + if (isReadOnly()) { + title += tr(" [lecture seule]", "window title tag"); + } + setWindowTitle(title); +} + +/** + * @brief QETElementEditor::fillPartsList + */ +void QETElementEditor::fillPartsList() +{ + m_parts_list -> blockSignals(true); + m_parts_list -> clear(); + QList qgis = m_elmt_scene -> zItems(); + + if (qgis.count() <= QET_MAX_PARTS_IN_ELEMENT_EDITOR_LIST) + { + for (int j = qgis.count() - 1 ; j >= 0 ; -- j) + { + QGraphicsItem *qgi = qgis[j]; + if (CustomElementPart *cep = dynamic_cast(qgi)) + { + QString part_desc = cep -> name(); + QListWidgetItem *qlwi = new QListWidgetItem(part_desc); + QVariant v; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove + v.setValue(qgi); +#else +#if TODO_LIST +#pragma message("@TODO remove code for QT 6 or later") +#endif + qDebug()<<"Help code for QT 6 or later"; +#endif + qlwi -> setData(42, v); + m_parts_list -> addItem(qlwi); + qlwi -> setSelected(qgi -> isSelected()); + } + } + } + else { + m_parts_list -> addItem(new QListWidgetItem(tr("Trop de primitives, liste non générée."))); + } + m_parts_list -> blockSignals(false); +} + +/** + * @brief QETElementEditor::UncheckAddPrimitive + */ +void QETElementEditor::UncheckAddPrimitive() { + for (auto action : m_add_part_action_grp->actions()) { + action->setChecked(false); + } +} + +/** + * @brief QETElementEditor::updateCurrentPartEditor + */ +void QETElementEditor::updateCurrentPartEditor() +{ + if (!m_tools_dock_stack -> currentIndex()) { + return; + } + + if (ElementItemEditor *current_editor = dynamic_cast(m_tools_dock_stack -> widget(1))) { + current_editor -> updateForm(); + } +} + +/** + * @brief QETElementEditor::updateInformations + * Update the information and editor dock. + */ +void QETElementEditor::updateInformations() +{ + QList selected_qgis = m_elmt_scene -> selectedItems(); + if (selected_qgis.isEmpty()) + { + clearToolsDock(); + m_default_informations -> setText(tr("%n partie(s) sélectionnée(s).", + "", + selected_qgis.size())); + m_default_informations -> setAlignment(Qt::AlignHCenter | Qt::AlignTop); + m_tools_dock_stack -> setCurrentIndex(0); + return; + } + + QList cep_list; + + CustomElementPart* part = dynamic_cast(selected_qgis.first()); + QString selection_xml_name = part -> xmlName(); + bool same_xml_name = true; + bool style_editable = true; + for (QGraphicsItem *qgi: selected_qgis) + { + if (CustomElementPart *cep = dynamic_cast(qgi)) { + cep_list << cep; + if (cep -> xmlName() != selection_xml_name) { + same_xml_name = false; + } + } + else { + style_editable = false; + same_xml_name = false; + } + } + if (style_editable) { + style_editable = StyleEditor::isStyleEditable(cep_list); + } + + if (same_xml_name) { + if (selection_xml_name == "terminal" || + selection_xml_name == "text" || + selection_xml_name == "dynamic_text" || + selection_xml_name == "line" || + selection_xml_name == "rect" || + selection_xml_name == "ellipse" || + selection_xml_name == "arc") { + clearToolsDock(); + //We add the editor widget + ElementItemEditor *editor = static_cast(m_editors[selection_xml_name]); + +#if TODO_LIST +#pragma message("@TODO Check if it takes longer than setting the parts again to the editor.") +#endif + // TODO: Check if it takes longer than setting the parts again to the editor. + bool equal = true; + QList parts = editor -> currentParts(); + if (parts.length() == cep_list.length()) { + for (auto cep: cep_list) { + bool part_found = false; + for (auto part: parts) { + if (part == cep) { + part_found = true; + break; + } + } + if (!part_found) { + equal = false; + break; + } + } + } + else { + equal = false; + } + + if (editor) { + bool success = true; + if (equal == false) { + success = editor -> setParts(cep_list); + } + if (success) { + m_tools_dock_stack -> insertWidget(1, editor); + m_tools_dock_stack -> setCurrentIndex(1); + } + else { + qDebug() << "Editor refused part."; + } + } + return; + } + else if (selection_xml_name == "polygon" && cep_list.length() == 1) { +#if TODO_LIST +#pragma message("@TODO maybe allowing multipart edit when number of points is the same?") +#endif + // multi edit for polygons makes no sense + // TODO: maybe allowing multipart edit when number of points is the same? + //We add the editor widget + clearToolsDock(); + ElementItemEditor *editor = static_cast(m_editors[selection_xml_name]); + CustomElementPart* part = editor -> currentPart(); + bool equal = part == cep_list.first(); + + if (editor) { + bool success = true; + if (equal == false) { + success = editor -> setPart(cep_list.first()); + } + if (success) { + m_tools_dock_stack -> insertWidget(1, editor); + m_tools_dock_stack -> setCurrentIndex(1); + } + else { + qDebug() << "Editor refused part."; + } + } + return; + + } + else { + qDebug() << "Multiedit not supported for: " << cep_list.first() -> xmlName(); + } + + } + + //There's several parts selecteds and all can be edited by style editor. + if (style_editable) { + clearToolsDock(); + ElementItemEditor *selection_editor = m_editors["style"]; + if (selection_editor) { + if (selection_editor -> setParts(cep_list)) { + m_tools_dock_stack -> insertWidget(1, selection_editor); + m_tools_dock_stack -> setCurrentIndex(1); + } + else { + qDebug() << "Editor refused part."; + } + } + } + //Else we only display the number of selected items + else { + clearToolsDock(); + m_default_informations -> setText(tr("%n partie(s) sélectionnée(s).", + "", + selected_qgis.size())); + m_default_informations -> setAlignment(Qt::AlignHCenter | Qt::AlignTop); + m_tools_dock_stack -> setCurrentIndex(0); + } +} + +/** + * @brief QETElementEditor::updatePartsList + */ +void QETElementEditor::updatePartsList() +{ + int items_count = m_elmt_scene -> items().count(); + if (m_parts_list -> count() != items_count) { + fillPartsList(); + } + else if (items_count <= QET_MAX_PARTS_IN_ELEMENT_EDITOR_LIST) { + m_parts_list -> blockSignals(true); + int i = 0; + QList items = m_elmt_scene -> zItems(); + for (int j = items.count() - 1 ; j >= 0 ; -- j) { + QGraphicsItem *qgi = items[j]; + QListWidgetItem *qlwi = m_parts_list -> item(i); + if (qlwi) qlwi -> setSelected(qgi -> isSelected()); + ++ i; + } + m_parts_list -> blockSignals(false); + } +} + +/** + * @brief QETElementEditor::updateSelectionFromPartsList + */ +void QETElementEditor::updateSelectionFromPartsList() +{ + m_elmt_scene -> blockSignals(true); + m_parts_list -> blockSignals(true); + for (int i = 0 ; i < m_parts_list -> count() ; ++ i) { + QListWidgetItem *qlwi = m_parts_list -> item(i); + QGraphicsItem *qgi = qlwi -> data(42).value(); + if (qgi) { + qgi -> setSelected(qlwi -> isSelected()); + } + } + m_parts_list -> blockSignals(false); + m_elmt_scene -> blockSignals(false); + updateInformations(); + updateAction(); +} + +/** + * @brief QETElementEditor::checkElement + * Do several check about element + * @return true if there is no error + */ +bool QETElementEditor::checkElement() +{ + //List of warning and error + typedef QPair QETWarning; + QList warnings; + QList errors; + + // Warning #1: Element haven't got terminal + // (except for report, because report must have one terminal and this checking is do below) + if (!m_elmt_scene -> containsTerminals() && !m_elmt_scene -> elementType().contains("report")) { + warnings << qMakePair( + tr("Absence de borne", "warning title"), + tr( + "
En l'absence de borne, l'élément ne pourra être" + " relié à d'autres éléments par l'intermédiaire de conducteurs.", + "warning description" + ) + ); + } + + // Check folio report element + if (m_elmt_scene -> elementType().contains("report")) + { + int terminal =0; + + for(auto qgi : m_elmt_scene -> items()) { + if (qgraphicsitem_cast(qgi)) { + terminal ++; + } + } + + //Error folio report must have only one terminal + if (terminal != 1) { + errors << qMakePair (tr("Absence de borne"), + tr("
Erreur :" + "
Les reports de folio doivent posséder une seul borne." + "
Solution :" + "
Verifier que l'élément ne possède qu'une seul borne")); + } + } + + if (!errors.count() && !warnings.count()) { + return(true); + } + + // Display warnings + QString dialog_message = tr("La vérification de cet élément a généré", "message box content"); + + if (errors.size()) { + dialog_message += QString(tr(" %n erreur(s)", "errors", errors.size())); + } + + if (warnings.size()) { + if (errors.size()) { + dialog_message += QString (tr(" et")); + } + dialog_message += QString (tr(" %n avertissement(s)", "warnings", warnings.size())); + } + dialog_message += " :"; + + dialog_message += "
    "; + QList total = warnings << errors; + for(QETWarning warning : total) + { + dialog_message += "
  1. "; + dialog_message += QString( + tr("%1 : %2", "warning title: warning description") + ).arg(warning.first).arg(warning.second); + dialog_message += "
  2. "; + } + dialog_message += "
"; + + if (errors.size()) { + QMessageBox::critical(this, tr("Erreurs"), dialog_message); + } + else { + QMessageBox::warning(this, tr("Avertissements"), dialog_message); + } + + //if error == 0 that means they are only warning, we return true. + if (errors.count() == 0) { + return(true); + } + return false; +} + +/** + * @brief QETElementEditor::event + * @param event + * @return + */ +bool QETElementEditor::event(QEvent *event) +{ + if (m_first_activation && event->type() == QEvent::WindowActivate) { + m_first_activation = false; + QTimer::singleShot(250, m_view, SLOT(zoomFit())); + } + + return QMainWindow::event(event); +} + +/** + * @brief QETElementEditor::openElement + * OPen an element from @filepath + * @param filepath + */ +void QETElementEditor::openElement(const QString &filepath) +{ + if (filepath.isEmpty()) { + return; + } + // we have to test the file existence here because QETApp::openElementFiles() + // will discard non-existent files through QFileInfo::canonicalFilePath() + if (!QFile::exists(filepath)) { + QET::QetMessageBox::critical( + this, + tr("Impossible d'ouvrir le fichier", "message box title"), + QString( + tr("Il semblerait que le fichier %1 que vous essayez d'ouvrir" + " n'existe pas ou plus.") + ).arg(filepath) + ); + } + QETApp::instance() -> openElementFiles(QStringList() << filepath); +} + +/** + * @brief QETElementEditor::closeEvent + * @param qce + */ +void QETElementEditor::closeEvent(QCloseEvent *qce) +{ + if (canClose()) { + writeSettings(); + setAttribute(Qt::WA_DeleteOnClose); + m_elmt_scene -> reset(); + qce -> accept(); + } + else { + qce -> ignore(); + } +} + +/** + * @brief QETElementEditor::canClose + * @return + */ +bool QETElementEditor::canClose() +{ + if (m_elmt_scene -> undoStack().isClean()) { + return(true); + } + //First ask user to save + QMessageBox::StandardButton answer = QET::QetMessageBox::question( + this, + tr("Enregistrer l'élément en cours ?", "dialog title"), + QString( + tr( + "Voulez-vous enregistrer l'élément %1 ?", + "dialog content - %1 is an element name" + ) + ).arg(m_elmt_scene -> names().name()), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, + QMessageBox::Cancel + ); + + bool result; + switch(answer) { + case QMessageBox::Cancel: { + result = false; + break; + } + case QMessageBox::Yes: { + result = on_m_save_action_triggered(); + break; + } + default: { + result = true; + } + } + return(result); +} + +/** + * @brief QETElementEditor::readSettings + * Read some setting about this widget in the QSetting + * of qelectrotech + */ +void QETElementEditor::readSettings() +{ + QSettings settings; + + QVariant geometry = settings.value("elementeditor/geometry"); + if (geometry.isValid()) { + restoreGeometry(geometry.toByteArray()); + } + + QVariant state = settings.value("elementeditor/state"); + if (state.isValid()) { + restoreState(state.toByteArray()); + } + + m_elmt_scene->setInformations(settings.value("elementeditor/default-informations", "").toString()); +} + +/** + * @brief QETElementEditor::writeSettings + * Write some setting of this widget in the + * QSetting of qelectrotech + */ +void QETElementEditor::writeSettings() const +{ + QSettings settings; + settings.setValue("elementeditor/geometry", saveGeometry()); + settings.setValue("elementeditor/state", saveState()); +} + +/** + * @brief QETElementEditor::setupActions + */ +void QETElementEditor::setupActions() +{ +#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) + ui->m_open_dxf_action -> setStatusTip(tr("To install the plugin DXFtoQET\nVisit https://download.tuxfamily.org/qet/builds/dxf_to_elmt/\n" + "\n" + ">> Install on Windows\n" + "Put DXFtoQET.exe binary on C:\\Users\\user_name\\AppData\\Roaming\\qet\\ directory \n" + )); +#elif defined(Q_OS_MAC) + ui->m_open_dxf_action -> setStatusTip(tr("To install the plugin DXFtoQET\nVisit https://download.tuxfamily.org/qet/builds/dxf_to_elmt/\n" + "\n" + ">> Install on macOSX\n" + "Put DXFtoQET.app binary on /Users/user_name/.qet/ directory \n" + )); +#else + ui->m_open_dxf_action -> setStatusTip(tr("To install the plugin DXFtoQET\nVisit https://download.tuxfamily.org/qet/builds/dxf_to_elmt/\n" + "\n" + ">> Install on Linux\n" + "Put DXFtoQET binary on your /home/user_name/.qet/ directory\n" + "make it executable : chmod +x ./DXFtoQET\n" + )); +#endif + + ui->m_open_dxf_action -> setWhatsThis (tr("To install the plugin DXFtoQET\nVisit https://download.tuxfamily.org/qet/builds/dxf_to_elmt/\n" + "\n" + ">> Install on Linux\n" + "Put DXFtoQET binary on your /home/user_name/.qet/ directory\n" + "make it executable : chmod +x ./DXFtoQET\n" + ">> Install on Windows\n" + "Put DXFtoQET.exe binary on C:\\Users\\user_name\\AppData\\Roaming\\qet\\ directory \n" + "\n" + ">> Install on macOSX\n" + "Put DXFtoQET.app binary on /Users/user_name/.qet/ directory \n" + )); + + m_undo_action = m_elmt_scene -> undoStack().createUndoAction(this, tr("Annuler")); + m_redo_action = m_elmt_scene -> undoStack().createRedoAction(this, tr("Refaire")); + m_undo_action -> setIcon(QET::Icons::EditUndo); + m_redo_action -> setIcon(QET::Icons::EditRedo); + m_undo_action -> setShortcuts(QKeySequence::Undo); + m_redo_action -> setShortcuts(QKeySequence::Redo); + ui->m_undo_toolbar->addAction(m_undo_action); + ui->m_undo_toolbar->addAction(m_redo_action); + + ui->m_new_action -> setShortcut(QKeySequence::New); + ui->m_open_action -> setShortcut(QKeySequence::Open); + ui->m_open_from_file_action -> setShortcut(tr("Ctrl+Shift+O")); + ui->m_save_action -> setShortcut(QKeySequence::Save); + ui->m_save_as_file_action -> setShortcut(tr("Ctrl+Shift+S")); + ui->m_quit_action -> setShortcut(QKeySequence(tr("Ctrl+Q"))); + ui->m_select_all_act -> setShortcut(QKeySequence::SelectAll); + ui->m_deselect_all_action -> setShortcut(QKeySequence(tr("Ctrl+Shift+A"))); + ui->m_revert_selection_action -> setShortcut(QKeySequence(tr("Ctrl+I"))); + ui->m_cut_action -> setShortcut(QKeySequence::Cut); + ui->m_copy_action -> setShortcut(QKeySequence::Copy); + ui->m_paste_action -> setShortcut(QKeySequence::Paste); + ui->m_paste_in_area_action -> setShortcut(tr("Ctrl+Shift+V")); + ui->m_edit_names_action -> setShortcut(QKeySequence(tr("Ctrl+E"))); + ui->m_edit_author_action -> setShortcut(tr("Ctrl+Y")); + +#ifndef Q_OS_MAC + ui->m_delete_action -> setShortcut(QKeySequence(Qt::Key_Delete)); +#else + ui->m_delete_action -> setShortcut(QKeySequence(tr("Backspace"))); +#endif + + //Depth action + m_depth_action_group = QET::depthActionGroup(this); + connect(m_depth_action_group, &QActionGroup::triggered, [this](QAction *action) { + this -> elementScene() -> undoStack().push( + new ChangeZValueCommand(this -> elementScene(), action -> data().value())); + emit(this -> elementScene() -> partsZValueChanged()); + }); + auto depth_toolbar = addToolBar(tr("Profondeur", "toolbar title")); + depth_toolbar -> setObjectName("depth_toolbar"); + depth_toolbar -> addActions(m_depth_action_group -> actions()); + addToolBar(Qt::TopToolBarArea, depth_toolbar); + + //Zoom action + ui->m_zoom_in_action -> setShortcut(QKeySequence::ZoomIn); + ui->m_zoom_out_action -> setShortcut(QKeySequence::ZoomOut); + ui->m_zoom_fit_best_action -> setShortcut(QKeySequence(tr("Ctrl+9"))); + ui->m_zoom_original_action -> setShortcut(QKeySequence(tr("Ctrl+0"))); + + //Add primitive actions + m_add_part_action_grp = new QActionGroup(this); + + auto *add_line = new QAction(QET::Icons::PartLine, tr("Ajouter une ligne"), m_add_part_action_grp); + auto *add_rectangle = new QAction(QET::Icons::PartRectangle, tr("Ajouter un rectangle"), m_add_part_action_grp); + auto *add_ellipse = new QAction(QET::Icons::PartEllipse, tr("Ajouter une ellipse"), m_add_part_action_grp); + auto *add_polygon = new QAction(QET::Icons::PartPolygon, tr("Ajouter un polygone"), m_add_part_action_grp); + auto *add_text = new QAction(QET::Icons::PartText, tr("Ajouter du texte"), m_add_part_action_grp); + auto *add_arc = new QAction(QET::Icons::PartArc, tr("Ajouter un arc de cercle"), m_add_part_action_grp); + auto *add_terminal = new QAction(QET::Icons::Terminal, tr("Ajouter une borne"), m_add_part_action_grp); + auto *add_dynamic_text_field = new QAction(QET::Icons::PartTextField, tr("Ajouter un champ texte dynamique"), m_add_part_action_grp); + + for (auto action : m_add_part_action_grp->actions()) { + action -> setCheckable(true); + } + + connect(add_line, &QAction::triggered, [this]() {m_elmt_scene->setEventInterface(new ESEventAddLine(m_elmt_scene));}); + connect(add_rectangle, &QAction::triggered, [this]() {m_elmt_scene->setEventInterface(new ESEventAddRect(m_elmt_scene));}); + connect(add_ellipse, &QAction::triggered, [this]() {m_elmt_scene->setEventInterface(new ESEventAddEllipse(m_elmt_scene));}); + connect(add_polygon, &QAction::triggered, [this]() {m_elmt_scene->setEventInterface(new ESEventAddPolygon(m_elmt_scene));}); + connect(add_text, &QAction::triggered, [this]() {m_elmt_scene->setEventInterface(new ESEventAddText(m_elmt_scene));}); + connect(add_arc, &QAction::triggered, [this]() {m_elmt_scene->setEventInterface(new ESEventAddArc(m_elmt_scene));}); + connect(add_terminal, &QAction::triggered, [this]() {m_elmt_scene->setEventInterface(new ESEventAddTerminal(m_elmt_scene));}); + connect(add_dynamic_text_field, &QAction::triggered, [this]() {m_elmt_scene->setEventInterface(new ESEventAddDynamicTextField(m_elmt_scene));}); + + add_polygon -> setStatusTip(tr("Double-click pour terminer la forme, Click droit pour annuler le dernier point")); + add_text -> setStatusTip(tr("Ajouter un texte d'élément non éditable dans les schémas")); + add_dynamic_text_field -> setStatusTip(tr("Ajouter un texte d'élément pouvant être édité dans les schémas")); + + auto parts_toolbar = addToolBar(tr("Parties", "toolbar title")); + parts_toolbar -> setAllowedAreas(Qt::AllToolBarAreas); + parts_toolbar -> setObjectName("parts"); + parts_toolbar -> addActions(m_add_part_action_grp -> actions()); + addToolBar(Qt::LeftToolBarArea, parts_toolbar); +} + +/** + * @brief QETElementEditor::updateAction + * Update actions + */ +void QETElementEditor::updateAction() +{ + //Action disabled if read only + auto ro_list = m_add_part_action_grp->actions(); + ro_list << ui->m_select_all_act + << ui->m_revert_selection_action + << ui->m_paste_from_file_action + << ui->m_paste_from_element_action; + for (auto action : qAsConst(ro_list)) { + action->setDisabled(m_read_only); + } + + //Action enabled if a primitive is selected + auto select_list = m_depth_action_group->actions(); + select_list << ui->m_deselect_all_action + << ui->m_cut_action + << ui->m_copy_action + << ui->m_delete_action; + auto items_selected = !m_read_only && m_elmt_scene->selectedItems().count(); + for (auto action : qAsConst(select_list)) { + action->setEnabled(items_selected); + } + + //Action about clipboard + auto clipboard_contain_elmt = !m_read_only && ElementScene::clipboardMayContainElement(); + ui->m_paste_action->setEnabled(clipboard_contain_elmt); + ui->m_paste_in_area_action->setEnabled(clipboard_contain_elmt); + + //Action about undo stack status + ui->m_save_action-> setEnabled(!m_read_only && !m_elmt_scene->undoStack().isClean()); + m_undo_action -> setEnabled(!m_read_only && m_elmt_scene -> undoStack().canUndo()); + m_redo_action -> setEnabled(!m_read_only && m_elmt_scene -> undoStack().canRedo()); + +} + +/** + * @brief QETElementEditor::setupConnection + */ +void QETElementEditor::setupConnection() +{ + connect(m_elmt_scene, &ElementScene::partsAdded, this, &QETElementEditor::UncheckAddPrimitive); + connect(m_elmt_scene, &ElementScene::partsAdded, this, &QETElementEditor::fillPartsList); + connect(m_elmt_scene, &ElementScene::partsRemoved, this, &QETElementEditor::fillPartsList); + connect(m_elmt_scene, &ElementScene::partsZValueChanged, this, &QETElementEditor::fillPartsList); + connect(m_parts_list, &QListWidget::itemSelectionChanged, this, &QETElementEditor::updateSelectionFromPartsList); + connect(QApplication::clipboard(), &QClipboard::dataChanged, this, &QETElementEditor::updateAction); + + connect(m_elmt_scene, &ElementScene::selectionChanged, [this]() { + this->updateInformations(); + this->updateAction(); + this->updatePartsList(); + }); + + connect(&(m_elmt_scene -> undoStack()), &QUndoStack::cleanChanged, [this]() { + this->updateAction(); + this->updateTitle(); + }); + + connect(&(m_elmt_scene -> undoStack()), &QUndoStack::indexChanged, [this]() { + this->updatePartsList(); + this->updateInformations(); + }); +} + +/** + * @brief QETElementEditor::initGui + */ +void QETElementEditor::initGui() +{ + m_editors["arc"] = new ArcEditor(this); + m_editors["ellipse"] = new EllipseEditor(this); + m_editors["line"] = new LineEditor(this); + m_editors["polygon"] = new PolygonEditor(this); + m_editors["rect"] = new RectangleEditor(this); + m_editors["terminal"] = new TerminalEditor(this); + m_editors["text"] = new TextEditor(this); + m_editors["style"] = new StyleEditor(this); + m_editors["dynamic_text"] = new DynamicTextFieldEditor(this); + + m_elmt_scene = new ElementScene(this, this); + m_view = new ElementView(m_elmt_scene, this); + m_view->setDragMode(QGraphicsView::RubberBandDrag); + setCentralWidget(m_view); + + //Part dock editor + m_default_informations = new QLabel(this); + m_tools_dock_stack = new QStackedWidget(this); + m_tools_dock_stack->insertWidget(0, m_default_informations); + ui->m_tools_dock->setWidget(m_tools_dock_stack); + + //Undo dock + auto undo_view = new QUndoView(&(m_elmt_scene->undoStack()), this); + undo_view->setEmptyLabel(tr("Aucune modification")); + ui->m_undo_dock->setWidget(undo_view); + + //parts list dock + m_parts_list = new QListWidget(this); + m_parts_list->setSelectionMode(QAbstractItemView::ExtendedSelection); + tabifyDockWidget(ui->m_undo_dock, ui->m_parts_dock); + ui->m_parts_dock->setWidget(m_parts_list); + + updateInformations(); + fillPartsList(); + + statusBar()->showMessage(tr("Éditeur d'éléments", "status bar message")); +} + +/** + * @brief QETElementEditor::clearToolsDock + * Remove and hide the widget displayed by + * the dock used to edit primitives + * @return Return the removed widget or nullptr if there is no widget to remove. + */ +QWidget *QETElementEditor::clearToolsDock() +{ + if (QWidget *previous_widget = m_tools_dock_stack -> widget(1)) { + m_tools_dock_stack -> removeWidget(previous_widget); + previous_widget -> setParent(nullptr); + previous_widget -> hide(); + return(previous_widget); + } + return(nullptr); +} + +/** + * @brief QETElementEditor::copyAndPasteXml + * Copy the content of @xml_document to the clipboard + * and call pasteInArea method of elementView. + * @param xml_document + */ +void QETElementEditor::copyAndPasteXml(const QDomDocument &xml_document) +{ + QClipboard *clipboard = QApplication::clipboard(); + QString clipboard_content = xml_document.toString(4); + + if (clipboard -> supportsSelection()) { + clipboard -> setText(clipboard_content, QClipboard::Selection); + } + clipboard -> setText(clipboard_content); + + m_view -> pasteInArea(); +} + +/** + * @brief QETElementEditor::on_m_save_action_triggered + * @return + */ +bool QETElementEditor::on_m_save_action_triggered() +{ + if (checkElement()) + { + if (m_opened_from_file) + { + if (m_file_name.isEmpty()) { + return(on_m_save_as_action_triggered()); + } + + //Else wa save to the file at filename_ path + bool result_save = toFile(m_file_name); + if (result_save) m_elmt_scene -> undoStack().setClean(); + return(result_save); + } + else + { + if (m_location.isNull()) { + return(on_m_save_as_action_triggered()); + } + + //Else save to the known location + bool result_save = toLocation(m_location); + if (result_save) { + m_elmt_scene -> undoStack().setClean(); + emit saveToLocation(m_location); + } + return(result_save); + } + } + + QMessageBox::critical(this, tr("Echec de l'enregistrement"), tr("L'enregistrement à échoué,\nles conditions requises ne sont pas valides")); + return false; +} + +/** + * @brief QETElementEditor::on_m_save_as_action_triggered + * Ask a location to user and save the current edited element + * to this location + * @return true is success + */ +bool QETElementEditor::on_m_save_as_action_triggered() +{ + // Check element befor writing + if (checkElement()) { + //Ask a location to user + ElementsLocation location = ElementDialog::getSaveElementLocation(this); + if (location.isNull()) { + return(false); + } + + bool result_save = toLocation(location); + if (result_save) { + setLocation(location); + m_elmt_scene -> undoStack().setClean(); + emit saveToLocation(location); + } + + return(result_save); + } + QMessageBox::critical(this, tr("Echec de l'enregistrement"), tr("L'enregistrement à échoué,\nles conditions requises ne sont pas valides")); + return (false); +} + +void QETElementEditor::on_m_select_all_act_triggered() { + m_elmt_scene->slot_selectAll(); +} + +void QETElementEditor::on_m_edit_element_properties_action_triggered() { m_elmt_scene->slot_editProperties(); } + +void QETElementEditor::on_m_new_action_triggered() +{ + NewElementWizard new_element_wizard(this); + new_element_wizard.exec(); +} + +void QETElementEditor::on_m_open_action_triggered() +{ + ElementsLocation location = ElementDialog::getOpenElementLocation(this); + if (location.isNull()) { + return; + } + QETApp::instance() -> openElementLocations(QList() << location); +} + +void QETElementEditor::on_m_open_from_file_action_triggered() +{ + QString open_dir = m_file_name.isEmpty() ? QETApp::customElementsDir() : QDir(m_file_name).absolutePath(); + QString user_filename = QETElementEditor::getOpenElementFileName(this, open_dir); + openElement(user_filename); +} + +void QETElementEditor::on_m_open_dxf_action_triggered() +{ +#ifdef TODO_LIST +# pragma message("@TODO Merge 'DXF to GET-2020' code in to Qet") +# pragma message("https://github.com/qelectrotech/DXFtoQET-2020") +#endif +#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) + QString program = (QDir::homePath() + "/Application Data/qet/DXFtoQET.exe"); +#elif defined(Q_OS_MAC) + QString program = (QDir::homePath() + "/.qet/DXFtoQET.app"); +#else + QString program = (QDir::homePath() + "/.qet/DXFtoQET"); +#endif + QStringList arguments; + QProcess *DXF = new QProcess(qApp); + DXF -> start(program,arguments); +} + +bool QETElementEditor::on_m_save_as_file_action_triggered() +{ + // Check element befor writing + if (checkElement()) { + //Ask a filename to user, for save the element + QString fn = QFileDialog::getSaveFileName( + this, + tr("Enregistrer sous", "dialog title"), + m_file_name.isEmpty() ? QETApp::customElementsDir() : QDir(m_file_name).absolutePath(), + tr( + "Éléments QElectroTech (*.elmt)", + "filetypes allowed when saving an element file" + ) + ); + + if (fn.isEmpty()) { + return(false); + } + + //If the name doesn't end by .elmt, we add it + if (!fn.endsWith(".elmt", Qt::CaseInsensitive)) { + fn += ".elmt"; + } + + bool result_save = toFile(fn); + //If the save success, the filename is keep + if (result_save) { + setFileName(fn); + QETApp::elementsRecentFiles() -> fileWasOpened(fn); + m_elmt_scene -> undoStack().setClean(); + } + + return(result_save); + } + QMessageBox::critical(this, tr("Echec de l'enregistrement"), tr("L'enregistrement à échoué,\nles conditions requises ne sont pas valides")); + return false; +} + +void QETElementEditor::on_m_reload_action_triggered() +{ + //If user already edit the element, ask confirmation to reload + if (!m_elmt_scene -> undoStack().isClean()) { + QMessageBox::StandardButton answer = QET::QetMessageBox::question(this, + tr("Recharger l'élément", "dialog title"), + 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"), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, + QMessageBox::Cancel); + if (answer != QMessageBox::Yes){ + return; + } + } + + //Reload the element + m_elmt_scene -> reset(); + if (m_opened_from_file) { + fromFile(m_file_name); + } + else { + fromLocation(m_location); + } +} + +void QETElementEditor::on_m_quit_action_triggered() { close(); } + +void QETElementEditor::on_m_deselect_all_action_triggered() { m_elmt_scene->slot_deselectAll(); } + +void QETElementEditor::on_m_cut_action_triggered() { m_view->cut(); } + +void QETElementEditor::on_m_copy_action_triggered() { m_view->copy(); } + +void QETElementEditor::on_m_paste_action_triggered() { m_view->paste(); } + +void QETElementEditor::on_m_paste_in_area_action_triggered() { m_view->pasteInArea(); } + +void QETElementEditor::on_m_paste_from_file_action_triggered() +{ + QString element_file_path = getOpenElementFileName(this); + if (element_file_path.isEmpty()) { + return; + } + + QString error_message; + QDomDocument xml_document; + QFile element_file(element_file_path); + // le fichier doit etre lisible + if (!element_file.open(QIODevice::ReadOnly)) { + error_message = QString(tr("Impossible d'ouvrir le fichier %1.", "message box content")).arg(element_file_path); + } + else { + // le fichier doit etre un document XML + if (!xml_document.setContent(&element_file)) { + error_message = tr("Ce fichier n'est pas un document XML valide", "message box content"); + } + element_file.close(); + } + + if (!error_message.isEmpty()) { + QET::QetMessageBox::critical(this, tr("Erreur", "toolbar title"), error_message); + } + copyAndPasteXml(xml_document); +} + +void QETElementEditor::on_m_paste_from_element_action_triggered() +{ + //Ask for a location + ElementsLocation location = ElementDialog::getOpenElementLocation(this); + if (location.isNull()) { + return; + } + + if (!location.isElement()) { + QET::QetMessageBox::critical(this, + tr("Élément inexistant.", "message box title"), + tr("Le chemin virtuel choisi ne correspond pas à un élément.", "message box content")); + return; + } + if (!location.exist()) { + QET::QetMessageBox::critical(this, + tr("Élément inexistant.", "message box title"), + tr("L'élément n'existe pas.", "message box content")); + return; + } + + //Create an xml document from the location xml + QDomDocument document_xml; + QDomNode node = document_xml.importNode(location.xml(), true); + document_xml.appendChild(node); + + copyAndPasteXml(document_xml); +} + +void QETElementEditor::on_m_revert_selection_action_triggered() { m_elmt_scene->slot_invertSelection(); } + +void QETElementEditor::on_m_delete_action_triggered() { m_elmt_scene->slot_delete(); } + +void QETElementEditor::on_m_edit_names_action_triggered() { m_elmt_scene->slot_editNames(); } + +void QETElementEditor::on_m_edit_author_action_triggered() { m_elmt_scene->slot_editAuthorInformations(); } + +void QETElementEditor::on_m_zoom_in_action_triggered() { m_view->zoomIn(); } + +void QETElementEditor::on_m_zoom_out_action_triggered() { m_view->zoomOut(); } + +void QETElementEditor::on_m_zoom_fit_best_action_triggered() { m_view->zoomFit(); } + +void QETElementEditor::on_m_zoom_original_action_triggered() { m_view->zoomReset(); } + +void QETElementEditor::on_m_about_qet_action_triggered() { QETApp::instance()->aboutQET(); } + +void QETElementEditor::on_m_online_manual_triggered() { + QString link = "https://download.tuxfamily.org/qet/manual_0.7/build/index.html"; + QDesktopServices::openUrl(QUrl(link)); +} + +void QETElementEditor::on_m_youtube_action_triggered() { + QString link = "https://www.youtube.com/user/scorpio8101/videos"; + QDesktopServices::openUrl(QUrl(link)); +} + +void QETElementEditor::on_m_donate_action_triggered() { + QString link = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ZZHC9D7C3MDPC"; + QDesktopServices::openUrl(QUrl(link)); +} + +void QETElementEditor::on_m_about_qt_action_triggered() { qApp->aboutQt(); } diff --git a/sources/editor/ui/qetelementeditor.h b/sources/editor/ui/qetelementeditor.h new file mode 100644 index 000000000..ee0b5a221 --- /dev/null +++ b/sources/editor/ui/qetelementeditor.h @@ -0,0 +1,163 @@ +/* + Copyright 2006-2021 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#ifndef QETELEMENTEDITOR_H +#define QETELEMENTEDITOR_H + +#include +#include "../../ElementsCollection/elementslocation.h" + +class ElementScene; +class QActionGroup; +class ElementItemEditor; +class ElementView; +class QListWidget; +class QStackedWidget; +class QLabel; + +namespace Ui { + class QETElementEditor; +} + +class QETElementEditor : public QMainWindow +{ + Q_OBJECT + signals: + void saveToLocation(ElementsLocation loc); + + public: + explicit QETElementEditor(QWidget *parent = nullptr); + ~QETElementEditor() override; + + void contextMenu(QPoint p, QList actions = QList()); + void setNames(const NamesList &name_list); + void setLocation(const ElementsLocation &location); + ElementsLocation location() const; + void setFileName(const QString &file_name); + QString fileName() const; + void setReadOnly(bool ro); + bool isReadOnly() const; + void fromFile(const QString &filepath); + bool toFile(const QString &filepath); + void fromLocation(const ElementsLocation &location); + bool toLocation(const ElementsLocation &location); + bool isEditing(const ElementsLocation &location); + bool isEditing(const QString &filepath); + ElementScene *elementScene() const; + ElementView *elementView() const; + static QPointF pasteOffset(); + static QString getOpenElementFileName(QWidget *parent = nullptr, const QString &dir = QString()); + void updateTitle(); + void fillPartsList(); + void UncheckAddPrimitive(); + void updateCurrentPartEditor(); + void updateInformations(); + void updatePartsList(); + void updateSelectionFromPartsList(); + void openElement(const QString &filepath); + bool checkElement(); + + protected: + bool event(QEvent *event) override; + void closeEvent(QCloseEvent *) override; + + + private slots: + bool on_m_save_action_triggered(); + bool on_m_save_as_action_triggered(); + void on_m_select_all_act_triggered(); + void on_m_edit_element_properties_action_triggered(); + void on_m_new_action_triggered(); + void on_m_open_action_triggered(); + void on_m_open_from_file_action_triggered(); + void on_m_open_dxf_action_triggered(); + bool on_m_save_as_file_action_triggered(); + void on_m_reload_action_triggered(); + void on_m_quit_action_triggered(); + void on_m_deselect_all_action_triggered(); + void on_m_cut_action_triggered(); + void on_m_copy_action_triggered(); + void on_m_paste_action_triggered(); + void on_m_paste_in_area_action_triggered(); + void on_m_paste_from_file_action_triggered(); + void on_m_paste_from_element_action_triggered(); + void on_m_revert_selection_action_triggered(); + void on_m_delete_action_triggered(); + void on_m_edit_names_action_triggered(); + void on_m_edit_author_action_triggered(); + void on_m_zoom_in_action_triggered(); + void on_m_zoom_out_action_triggered(); + void on_m_zoom_fit_best_action_triggered(); + void on_m_zoom_original_action_triggered(); + void on_m_about_qet_action_triggered(); + void on_m_online_manual_triggered(); + void on_m_youtube_action_triggered(); + void on_m_donate_action_triggered(); + void on_m_about_qt_action_triggered(); + + private: + bool canClose(); + void readSettings(); + void writeSettings() const; + void setupActions(); + void updateAction(); + void setupConnection(); + void initGui(); + QWidget *clearToolsDock(); + void copyAndPasteXml(const QDomDocument &xml_document); + + private: + Ui::QETElementEditor *ui; + + bool + m_read_only = false, + m_opened_from_file = false, + m_first_activation = true; + + ElementScene *m_elmt_scene = nullptr; + + QActionGroup + *m_add_part_action_grp = nullptr, + *m_depth_action_group = nullptr; + + QList m_context_menu_action_list; + + QAction + *m_undo_action = nullptr, + *m_redo_action = nullptr; + + + /// Hash associating primitive names with their matching edition widget + QHash m_editors; + + ElementsLocation m_location; + + QString + m_file_name, + m_min_title; + + ElementView *m_view = nullptr; + + QListWidget *m_parts_list = nullptr; + + QStackedWidget *m_tools_dock_stack = nullptr; + + QLabel *m_default_informations = nullptr; + +}; + +#endif // QETELEMENTEDITOR_H diff --git a/sources/editor/ui/qetelementeditor.ui b/sources/editor/ui/qetelementeditor.ui new file mode 100644 index 000000000..d63959565 --- /dev/null +++ b/sources/editor/ui/qetelementeditor.ui @@ -0,0 +1,496 @@ + + + QETElementEditor + + + + 0 + 0 + 800 + 600 + + + + QElectroTech - Éditeur d'élément + + + + :/ico/16x16/qet.png:/ico/16x16/qet.png + + + + + + + 0 + 0 + 800 + 21 + + + + + &Fichier + + + + + + + + + + + + + + + + &Édition + + + + Coller depuis... + + + + :/ico/16x16/edit-paste.png:/ico/16x16/edit-paste.png + + + + + + + + + + + + + + + + + + + + + + + + Afficha&ge + + + + + + + + + + &Aide + + + + + + + + + + + + + + + + Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea + + + Annulations + + + 1 + + + + + + Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea + + + Parties + + + 2 + + + + + + Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea + + + Informations + + + 1 + + + + + + Outils + + + TopToolBarArea + + + false + + + + + + + + + + + Affichage + + + TopToolBarArea + + + false + + + + + + + + + Élément + + + TopToolBarArea + + + false + + + + + + + Annulation + + + TopToolBarArea + + + false + + + + + + :/ico/16x16/edit-select-all.png:/ico/16x16/edit-select-all.png + + + Tout sélectionner + + + + + + :/ico/22x22/document-new.png:/ico/22x22/document-new.png + + + &Nouveau + + + + + + :/ico/22x22/folder-open.png:/ico/22x22/folder-open.png + + + &Ouvrir + + + + + + :/ico/22x22/folder-open.png:/ico/22x22/folder-open.png + + + &Ouvrir depuis un fichier + + + + + + :/ico/16x16/run-dxf.png:/ico/16x16/run-dxf.png + + + &Lancer le plugin convertisseur DXF + + + + + + :/ico/22x22/document-save.png:/ico/22x22/document-save.png + + + &Enregistrer + + + + + + :/ico/22x22/document-save-as.png:/ico/22x22/document-save-as.png + + + Enregistrer sous + + + + + + :/ico/22x22/document-save.png:/ico/22x22/document-save.png + + + Enregistrer dans un fichier + + + + + + :/ico/22x22/view-refresh.png:/ico/22x22/view-refresh.png + + + Recharger + + + + + + :/ico/16x16/application-exit.png:/ico/16x16/application-exit.png + + + &Quitter + + + + + + :/ico/16x16/edit-select-none.png:/ico/16x16/edit-select-none.png + + + Désélectionner tout + + + + + + :/ico/16x16/edit-cut.png:/ico/16x16/edit-cut.png + + + Co&uper + + + + + + :/ico/16x16/edit-copy.png:/ico/16x16/edit-copy.png + + + Cop&ier + + + + + + :/ico/16x16/edit-paste.png:/ico/16x16/edit-paste.png + + + C&oller + + + + + + :/ico/16x16/edit-paste.png:/ico/16x16/edit-paste.png + + + C&oller dans la zone + + + + + + :/ico/16x16/text-xml.png:/ico/16x16/text-xml.png + + + Un fichier + + + + + + :/ico/16x16/element.png:/ico/16x16/element.png + + + Un élément + + + + + + :/ico/16x16/edit-select-invert.png:/ico/16x16/edit-select-invert.png + + + Inverser la sélection + + + + + + :/ico/22x22/edit-delete.png:/ico/22x22/edit-delete.png + + + &Supprimer + + + + + + :/ico/22x22/names.png:/ico/22x22/names.png + + + Éditer le nom et les traductions de l'élément + + + + + + :/ico/16x16/preferences-desktop-user.png:/ico/16x16/preferences-desktop-user.png + + + Éditer les informations sur l'auteur + + + + + + :/ico/22x22/element-edit.png:/ico/22x22/element-edit.png + + + Éditer les propriétés de l'élément + + + + + + :/ico/22x22/zoom-in.png:/ico/22x22/zoom-in.png + + + Zoom avant + + + + + + :/ico/22x22/zoom-out.png:/ico/22x22/zoom-out.png + + + Zoom arrière + + + + + + :/ico/22x22/zoom-fit-best.png:/ico/22x22/zoom-fit-best.png + + + Zoom adapté + + + + + + :/ico/22x22/zoom-original.png:/ico/22x22/zoom-original.png + + + Pas de zoom + + + + + + :/ico/16x16/qet.png:/ico/16x16/qet.png + + + À &propos de QElectroTech + + + Affiche des informations sur QElectroTech + + + + + + :/ico/16x16/help-contents.png:/ico/16x16/help-contents.png + + + Manuel en ligne + + + Lance le navigateur par défaut vers le manuel en ligne de QElectroTech + + + + + + :/ico/16x16/kdenlive-show-video.png:/ico/16x16/kdenlive-show-video.png + + + Chaine Youtube + + + Lance le navigateur par défaut vers la chaine Youtube de QElectroTech + + + + + + :/ico/16x16/help-donate.png:/ico/16x16/help-donate.png + + + Soutenir le projet par un don + + + Soutenir le projet QElectroTech par un don + + + + + + :/ico/16x16/qt.png:/ico/16x16/qt.png + + + À propos de &Qt + + + Affiche des informations sur la bibliothèque Qt + + + + + + + + diff --git a/sources/elementspanelwidget.cpp b/sources/elementspanelwidget.cpp index faeaf1c77..b1ff1b5d8 100644 --- a/sources/elementspanelwidget.cpp +++ b/sources/elementspanelwidget.cpp @@ -18,7 +18,7 @@ #include "elementspanelwidget.h" #include "diagram.h" -#include "editor/qetelementeditor.h" +#include "editor/ui/qetelementeditor.h" #include "elementscategoryeditor.h" #include "qetapp.h" #include "qeticons.h" diff --git a/sources/newelementwizard.cpp b/sources/newelementwizard.cpp index 05363b5b1..ebda78bb3 100644 --- a/sources/newelementwizard.cpp +++ b/sources/newelementwizard.cpp @@ -20,10 +20,14 @@ #include "ElementsCollection/elementcollectionitem.h" #include "ElementsCollection/elementscollectionmodel.h" #include "NameList/ui/namelistwidget.h" -#include "editor/qetelementeditor.h" +#include "editor/ui/qetelementeditor.h" #include "qetmessagebox.h" #include "qfilenameedit.h" +#include +#include +#include + /** Constructeur @param parent QWidget parent de ce dialogue diff --git a/sources/projectview.cpp b/sources/projectview.cpp index db0afb383..f5420dbfa 100644 --- a/sources/projectview.cpp +++ b/sources/projectview.cpp @@ -21,7 +21,7 @@ #include "autoNum/assignvariables.h" #include "diagram.h" #include "diagramview.h" -#include "editor/qetelementeditor.h" +#include "editor/ui/qetelementeditor.h" #include "exportdialog.h" #include "qetapp.h" #include "qeticons.h" diff --git a/sources/qetapp.cpp b/sources/qetapp.cpp index 143b35fac..0e825346b 100644 --- a/sources/qetapp.cpp +++ b/sources/qetapp.cpp @@ -19,7 +19,7 @@ #include "configdialog.h" #include "configpages.h" -#include "editor/qetelementeditor.h" +#include "editor/ui/qetelementeditor.h" #include "elementscollectioncache.h" #include "factory/elementfactory.h" #include "factory/elementpicturefactory.h"