mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2025-09-13 20:23:04 +02:00
Optimisation de l'editeur d'element. L'organisation interne de l'editeur d'element a ete completement revue. Auparavant, chaque primitive instanciait son propre widget d'edition et le gardait durant toute sa duree de vie, entrainant ainsi une consommation memoire et un temps de chargement importants. Desormais, l'editeur instancie des son demarrage 9 widgets d'edition qu'il conserve durant toute sa duree de vie. Il choisit alors lequel afficher en fonction des primitives selectionnees. git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/branches/0.3@856 bfdf4180-ca20-0410-9c96-a3a8aa849046
1379 lines
52 KiB
C++
1379 lines
52 KiB
C++
/*
|
|
Copyright 2006-2010 Xavier Guerrin
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "qetelementeditor.h"
|
|
#include "qetapp.h"
|
|
#include "elementscene.h"
|
|
#include "elementview.h"
|
|
#include "customelementpart.h"
|
|
#include "newelementwizard.h"
|
|
#include "elementitemeditor.h"
|
|
#include "elementdefinition.h"
|
|
#include "elementdialog.h"
|
|
#include "recentfiles.h"
|
|
#include "qeticons.h"
|
|
#include "qetmessagebox.h"
|
|
|
|
// editeurs de primitives
|
|
#include "arceditor.h"
|
|
#include "circleeditor.h"
|
|
#include "ellipseeditor.h"
|
|
#include "lineeditor.h"
|
|
#include "polygoneditor.h"
|
|
#include "rectangleeditor.h"
|
|
#include "terminaleditor.h"
|
|
#include "texteditor.h"
|
|
#include "textfieldeditor.h"
|
|
|
|
/**
|
|
Constructeur
|
|
@param parent QWidget parent
|
|
*/
|
|
QETElementEditor::QETElementEditor(QWidget *parent) :
|
|
QMainWindow(parent),
|
|
read_only(false),
|
|
min_title(tr("QElectroTech - \311diteur d'\351l\351ment", "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(editors_.begin(), editors_.end());
|
|
editors_.clear();
|
|
}
|
|
|
|
/**
|
|
Met en place les actions
|
|
*/
|
|
void QETElementEditor::setupActions() {
|
|
new_element = new QAction(QET::Icons::DocumentNew, tr("&Nouveau"), this);
|
|
open = new QAction(QET::Icons::DocumentOpen, tr("&Ouvrir"), this);
|
|
open_file = new QAction(QET::Icons::DocumentOpen, tr("&Ouvrir depuis un fichier"), 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\351lectionner"), this);
|
|
deselectall = new QAction( tr("D\351s\351lectionner 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 \351l\351ment"), this);
|
|
inv_select = new QAction( tr("Inverser la s\351lection"), this);
|
|
edit_delete = new QAction(QET::Icons::EditDelete, tr("&Supprimer"), this);
|
|
zoom_in = new QAction(QET::Icons::ZoomIn, tr("Zoom avant"), this);
|
|
zoom_out = new QAction(QET::Icons::ZoomOut, tr("Zoom arri\350re"), this);
|
|
zoom_fit = new QAction(QET::Icons::ZoomFitBest, tr("Zoom adapt\351"), this);
|
|
zoom_reset = new QAction(QET::Icons::ZoomOriginal, tr("Pas de zoom"), this);
|
|
edit_size_hs = new QAction(QET::Icons::HotSpot, tr("\311diter la taille et le point de saisie"), this);
|
|
edit_names = new QAction(QET::Icons::Names, tr("\311diter les noms"), this);
|
|
edit_ori = new QAction(QET::Icons::Orientations, tr("\311diter les orientations"), this);
|
|
edit_author = new QAction(QET::Icons::UserInformations, tr("\311diter les informations sur l'auteur"), this);
|
|
edit_raise = new QAction(QET::Icons::Raise, tr("Rapprocher"), this);
|
|
edit_lower = new QAction(QET::Icons::Lower, tr("\311loigner"), this);
|
|
edit_backward = new QAction(QET::Icons::SendBackward, tr("Envoyer au fond"), this);
|
|
edit_forward = new QAction(QET::Icons::BringForward, tr("Amener au premier plan"), this);
|
|
move = new QAction(QET::Icons::PartSelect, tr("D\351placer un objet"), this);
|
|
add_line = new QAction(QET::Icons::PartLine, tr("Ajouter une ligne"), this);
|
|
add_rectangle = new QAction(QET::Icons::PartRectangle, tr("Ajouter un rectangle"), this);
|
|
add_ellipse = new QAction(QET::Icons::PartEllipse, tr("Ajouter une ellipse"), this);
|
|
add_circle = new QAction(QET::Icons::PartCircle, tr("Ajouter un cercle"), this);
|
|
add_polygon = new QAction(QET::Icons::PartPolygon, tr("Ajouter un polygone"), this);
|
|
add_text = new QAction(QET::Icons::PartText, tr("Ajouter du texte"), this);
|
|
add_arc = new QAction(QET::Icons::PartArc, tr("Ajouter un arc de cercle"), this);
|
|
add_terminal = new QAction(QET::Icons::Terminal, tr("Ajouter une borne"), this);
|
|
add_textfield = new QAction(QET::Icons::PartTextField, tr("Ajouter un champ de texte"), this);
|
|
fullscreen = new QAction(this);
|
|
slot_updateFullScreenAction();
|
|
configure = new QAction(QET::Icons::Configure, tr("&Configurer QElectroTech"), this);
|
|
about_qet = new QAction(QET::Icons::QETLogo, tr("\300 &propos de QElectroTech"), this);
|
|
about_qt = new QAction(QET::Icons::QtLogo, tr("\300 propos de &Qt"), this);
|
|
|
|
QString add_status_tip = tr("Maintenez la touche Shift enfonc\351e pour effectuer plusieurs ajouts d'affil\351e");
|
|
add_line -> setStatusTip(add_status_tip);
|
|
add_rectangle -> setStatusTip(add_status_tip);
|
|
add_ellipse -> setStatusTip(add_status_tip);
|
|
add_circle -> setStatusTip(add_status_tip);
|
|
add_text -> setStatusTip(add_status_tip);
|
|
add_arc -> setStatusTip(add_status_tip);
|
|
add_terminal -> setStatusTip(add_status_tip);
|
|
add_textfield -> setStatusTip(add_status_tip);
|
|
add_polygon -> setStatusTip(tr("Utilisez le bouton droit de la souris pour poser le dernier point du polygone"));
|
|
configure -> setStatusTip(tr("Permet de r\351gler diff\351rents param\350tres de QElectroTech", "status bar tip"));
|
|
about_qet -> setStatusTip(tr("Affiche des informations sur QElectroTech", "status bar tip"));
|
|
about_qt -> setStatusTip(tr("Affiche des informations sur la biblioth\350que Qt", "status bar tip"));
|
|
|
|
undo = ce_scene -> undoStack().createUndoAction(this, tr("Annuler"));
|
|
redo = ce_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"));
|
|
reload -> setShortcut(Qt::Key_F5);
|
|
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_WS_MAC
|
|
edit_delete -> setShortcut(QKeySequence(Qt::Key_Delete));
|
|
#else
|
|
edit_delete -> setShortcut(QKeySequence(tr("Backspace")));
|
|
#endif
|
|
|
|
zoom_in -> setShortcut(QKeySequence::ZoomIn);
|
|
zoom_out -> setShortcut(QKeySequence::ZoomOut);
|
|
zoom_fit -> setShortcut(QKeySequence(tr("Ctrl+9")));
|
|
zoom_reset -> setShortcut(QKeySequence(tr("Ctrl+0")));
|
|
|
|
fullscreen -> setShortcut(QKeySequence(tr("Ctrl+Shift+F")));
|
|
|
|
edit_names -> setShortcut(QKeySequence(tr("Ctrl+E")));
|
|
edit_size_hs -> setShortcut(QKeySequence(tr("Ctrl+R")));
|
|
edit_ori -> setShortcut(QKeySequence(tr("Ctrl+T")));
|
|
edit_author -> setShortcut(tr("Ctrl+Y"));
|
|
|
|
edit_raise -> setShortcut(QKeySequence(tr("Ctrl+Shift+Up")));
|
|
edit_lower -> setShortcut(QKeySequence(tr("Ctrl+Shift+Down")));
|
|
edit_backward -> setShortcut(QKeySequence(tr("Ctrl+Shift+End")));
|
|
edit_forward -> setShortcut(QKeySequence(tr("Ctrl+Shift+Home")));
|
|
|
|
QETApp *qet_app = QETApp::instance();
|
|
|
|
connect(new_element, SIGNAL(triggered()), this, SLOT(slot_new()));
|
|
connect(open, SIGNAL(triggered()), this, SLOT(slot_open()));
|
|
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()), ce_scene, SLOT(slot_selectAll()));
|
|
connect(deselectall, SIGNAL(triggered()), ce_scene, SLOT(slot_deselectAll()));
|
|
connect(inv_select, SIGNAL(triggered()), ce_scene, SLOT(slot_invertSelection()));
|
|
connect(cut, SIGNAL(triggered()), ce_view, SLOT(cut()));
|
|
connect(copy, SIGNAL(triggered()), ce_view, SLOT(copy()));
|
|
connect(paste, SIGNAL(triggered()), ce_view, SLOT(paste()));
|
|
connect(paste_in_area, SIGNAL(triggered()), ce_view, SLOT(pasteInArea()));
|
|
connect(paste_from_file, SIGNAL(triggered()), this, SLOT(pasteFromFile()));
|
|
connect(paste_from_elmt, SIGNAL(triggered()), this, SLOT(pasteFromElement()));
|
|
connect(zoom_in, SIGNAL(triggered()), ce_view, SLOT(zoomIn()));
|
|
connect(zoom_out, SIGNAL(triggered()), ce_view, SLOT(zoomOut()));
|
|
connect(zoom_fit, SIGNAL(triggered()), ce_view, SLOT(zoomFit()));
|
|
connect(zoom_reset, SIGNAL(triggered()), ce_view, SLOT(zoomReset()));
|
|
connect(edit_delete, SIGNAL(triggered()), ce_scene, SLOT(slot_delete()));
|
|
connect(edit_size_hs, SIGNAL(triggered()), ce_scene, SLOT(slot_editSizeHotSpot()));
|
|
connect(edit_names, SIGNAL(triggered()), ce_scene, SLOT(slot_editNames()));
|
|
connect(fullscreen, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
|
|
connect(configure, SIGNAL(triggered()), qet_app, SLOT(configureQET()));
|
|
connect(edit_ori, SIGNAL(triggered()), ce_scene, SLOT(slot_editOrientations()));
|
|
connect(edit_author, SIGNAL(triggered()), ce_scene, SLOT(slot_editAuthorInformations()));
|
|
connect(edit_forward, SIGNAL(triggered()), ce_scene, SLOT(slot_bringForward()));
|
|
connect(edit_raise, SIGNAL(triggered()), ce_scene, SLOT(slot_raise()));
|
|
connect(edit_lower, SIGNAL(triggered()), ce_scene, SLOT(slot_lower()));
|
|
connect(edit_backward, SIGNAL(triggered()), ce_scene, SLOT(slot_sendBackward()));
|
|
connect(move, SIGNAL(triggered()), ce_scene, SLOT(slot_move()));
|
|
connect(add_line, SIGNAL(triggered()), ce_scene, SLOT(slot_addLine()));
|
|
connect(add_rectangle, SIGNAL(triggered()), ce_scene, SLOT(slot_addRectangle()));
|
|
connect(add_ellipse, SIGNAL(triggered()), ce_scene, SLOT(slot_addEllipse()));
|
|
connect(add_circle, SIGNAL(triggered()), ce_scene, SLOT(slot_addCircle()));
|
|
connect(add_polygon, SIGNAL(triggered()), ce_scene, SLOT(slot_addPolygon()));
|
|
connect(add_text, SIGNAL(triggered()), ce_scene, SLOT(slot_addText()));
|
|
connect(add_arc, SIGNAL(triggered()), ce_scene, SLOT(slot_addArc()));
|
|
connect(add_terminal, SIGNAL(triggered()), ce_scene, SLOT(slot_addTerminal()));
|
|
connect(add_textfield, SIGNAL(triggered()), ce_scene, SLOT(slot_addTextField()));
|
|
|
|
connect(move, SIGNAL(triggered()), this, SLOT(slot_setRubberBandToView()));
|
|
connect(add_line, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
|
|
connect(add_rectangle, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
|
|
connect(add_ellipse, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
|
|
connect(add_circle, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
|
|
connect(add_polygon, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
|
|
connect(add_text, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
|
|
connect(add_arc, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
|
|
connect(add_terminal, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
|
|
connect(add_textfield, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
|
|
|
|
connect(about_qet, SIGNAL(triggered()), qet_app, SLOT(aboutQET()));
|
|
connect(about_qt, SIGNAL(triggered()), qet_app, SLOT(aboutQt()));
|
|
|
|
connect(ce_scene, SIGNAL(needNormalMode()), this, SLOT(slot_setNormalMode()));
|
|
|
|
move -> setCheckable(true);
|
|
add_line -> setCheckable(true);
|
|
add_rectangle -> setCheckable(true);
|
|
add_ellipse -> setCheckable(true);
|
|
add_circle -> setCheckable(true);
|
|
add_polygon -> setCheckable(true);
|
|
add_text -> setCheckable(true);
|
|
add_arc -> setCheckable(true);
|
|
add_terminal -> setCheckable(true);
|
|
add_textfield -> setCheckable(true);
|
|
|
|
parts = new QActionGroup(this);
|
|
parts -> addAction(move);
|
|
parts -> addAction(add_line);
|
|
parts -> addAction(add_rectangle);
|
|
parts -> addAction(add_ellipse);
|
|
parts -> addAction(add_circle);
|
|
parts -> addAction(add_polygon);
|
|
parts -> addAction(add_arc);
|
|
parts -> addAction(add_text);
|
|
parts -> addAction(add_textfield);
|
|
parts -> addAction(add_terminal);
|
|
parts -> setExclusive(true);
|
|
|
|
parts_toolbar = new QToolBar(tr("Parties", "toolbar title"), this);
|
|
parts_toolbar -> setObjectName("parts");
|
|
foreach (QAction *action, parts -> actions()) parts_toolbar -> addAction(action);
|
|
move -> setChecked(true);
|
|
parts_toolbar -> setAllowedAreas(Qt::AllToolBarAreas);
|
|
|
|
/*
|
|
QAction *xml_preview = new QAction(QET::Icons::DialogInformation, tr("XML"), this);
|
|
connect(xml_preview, SIGNAL(triggered()), this, SLOT(xmlPreview()));
|
|
parts_toolbar -> addAction(xml_preview);
|
|
*/
|
|
|
|
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("\311l\351ment", "toolbar title"), this);
|
|
element_toolbar -> setObjectName("element_toolbar");
|
|
depth_toolbar = new QToolBar(tr("Profondeur", "toolbar title"), this);
|
|
depth_toolbar -> setObjectName("depth_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_in);
|
|
view_toolbar -> addAction(zoom_out);
|
|
view_toolbar -> addAction(zoom_fit);
|
|
view_toolbar -> addAction(zoom_reset);
|
|
element_toolbar -> addAction(edit_size_hs);
|
|
element_toolbar -> addAction(edit_names);
|
|
element_toolbar -> addAction(edit_ori);
|
|
depth_toolbar -> addAction(edit_forward);
|
|
depth_toolbar -> addAction(edit_raise);
|
|
depth_toolbar -> addAction(edit_lower);
|
|
depth_toolbar -> addAction(edit_backward);
|
|
|
|
addToolBar(Qt::TopToolBarArea, main_toolbar);
|
|
addToolBar(Qt::TopToolBarArea, view_toolbar);
|
|
addToolBar(Qt::TopToolBarArea, element_toolbar);
|
|
addToolBar(Qt::TopToolBarArea, depth_toolbar);
|
|
addToolBar(Qt::LeftToolBarArea, parts_toolbar);
|
|
|
|
connect(ce_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updateInformations()));
|
|
connect(ce_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updateMenus()));
|
|
connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slot_updateMenus()));
|
|
connect(&(ce_scene -> undoStack()), SIGNAL(cleanChanged(bool)), this, SLOT(slot_updateMenus()));
|
|
connect(&(ce_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(&(ce_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(&(ce_scene -> undoStack()), SIGNAL(indexChanged(int)), this, SLOT(slot_updateInformations()));
|
|
}
|
|
|
|
/**
|
|
Met en place les menus.
|
|
*/
|
|
void QETElementEditor::setupMenus() {
|
|
file_menu = new QMenu(tr("Fichier"), this);
|
|
edit_menu = new QMenu(tr("\311dition"), this);
|
|
display_menu = new QMenu(tr("Affichage"), this);
|
|
tools_menu = new QMenu(tr("Outils"), this);
|
|
config_menu = new QMenu(tr("&Configuration"), this);
|
|
help_menu = new QMenu(tr("Aide"), this);
|
|
|
|
file_menu -> setTearOffEnabled(true);
|
|
edit_menu -> setTearOffEnabled(true);
|
|
display_menu -> setTearOffEnabled(true);
|
|
tools_menu -> setTearOffEnabled(true);
|
|
config_menu -> setTearOffEnabled(true);
|
|
help_menu -> setTearOffEnabled(true);
|
|
|
|
file_menu -> addAction(new_element);
|
|
file_menu -> addAction(open);
|
|
file_menu -> addAction(open_file);
|
|
file_menu -> addMenu(QETApp::elementsRecentFiles() -> menu());
|
|
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_size_hs);
|
|
edit_menu -> addAction(edit_ori);
|
|
edit_menu -> addAction(edit_author);
|
|
edit_menu -> addSeparator();
|
|
edit_menu -> addAction(edit_forward);
|
|
edit_menu -> addAction(edit_raise);
|
|
edit_menu -> addAction(edit_lower);
|
|
edit_menu -> addAction(edit_backward);
|
|
|
|
display_menu -> addAction(zoom_in);
|
|
display_menu -> addAction(zoom_out);
|
|
display_menu -> addAction(zoom_fit);
|
|
display_menu -> addAction(zoom_reset);
|
|
|
|
// menu Configurer > Afficher
|
|
QMenu *display_toolbars = createPopupMenu();
|
|
display_toolbars -> setTearOffEnabled(true);
|
|
display_toolbars -> setTitle(tr("Afficher"));
|
|
|
|
config_menu -> addMenu(display_toolbars);
|
|
config_menu -> addAction(fullscreen);
|
|
config_menu -> addAction(configure);
|
|
|
|
help_menu -> addAction(about_qet);
|
|
help_menu -> addAction(about_qt);
|
|
|
|
menuBar() -> addMenu(file_menu);
|
|
menuBar() -> addMenu(edit_menu);
|
|
menuBar() -> addMenu(display_menu);
|
|
//menuBar() -> addMenu(tools_menu);
|
|
menuBar() -> addMenu(config_menu);
|
|
menuBar() -> addMenu(help_menu);
|
|
}
|
|
|
|
/**
|
|
Met a jour les menus
|
|
*/
|
|
void QETElementEditor::slot_updateMenus() {
|
|
bool selected_items = !read_only && !ce_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);
|
|
edit_size_hs -> setEnabled(!read_only);
|
|
edit_names -> setEnabled(!read_only);
|
|
edit_ori -> setEnabled(!read_only);
|
|
edit_author -> setEnabled(!read_only);
|
|
parts_list -> setEnabled(!read_only);
|
|
|
|
// actions dependant de la presence de parties selectionnees
|
|
deselectall -> setEnabled(selected_items);
|
|
cut -> setEnabled(selected_items);
|
|
copy -> setEnabled(selected_items);
|
|
edit_delete -> setEnabled(selected_items);
|
|
edit_forward -> setEnabled(selected_items);
|
|
edit_raise -> setEnabled(selected_items);
|
|
edit_lower -> setEnabled(selected_items);
|
|
edit_backward -> 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 && !ce_scene -> undoStack().isClean());
|
|
undo -> setEnabled(!read_only && ce_scene -> undoStack().canUndo());
|
|
redo -> setEnabled(!read_only && ce_scene -> undoStack().canRedo());
|
|
|
|
slot_updateFullScreenAction();
|
|
}
|
|
|
|
/**
|
|
Gere l'action permettant de passer en plein ecran ou d'en sortir
|
|
*/
|
|
void QETElementEditor::slot_updateFullScreenAction() {
|
|
if (windowState() & Qt::WindowFullScreen) {
|
|
fullscreen -> setText(tr("Sortir du &mode plein \351cran"));
|
|
fullscreen -> setIcon(QET::Icons::FullScreenExit);
|
|
fullscreen -> setStatusTip(tr("Affiche QElectroTech en mode fen\352tr\351", "status bar tip"));
|
|
} else {
|
|
fullscreen -> setText(tr("Passer en &mode plein \351cran"));
|
|
fullscreen -> setIcon(QET::Icons::FullScreenEnter);
|
|
fullscreen -> setStatusTip(tr("Affiche QElectroTech en mode plein \351cran", "status bar tip"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
Met a jour le titre de la fenetre
|
|
*/
|
|
void QETElementEditor::slot_updateTitle() {
|
|
QString title = min_title;
|
|
title += " - " + ce_scene -> names().name() + " ";
|
|
if (!filename_.isEmpty() || !location_.isNull()) {
|
|
if (!ce_scene -> undoStack().isClean()) title += tr("[Modifi\351]", "window title tag");
|
|
}
|
|
if (isReadOnly()) title += tr(" [lecture seule]", "window title tag");
|
|
setWindowTitle(title);
|
|
}
|
|
|
|
/**
|
|
Met en place l'interface
|
|
*/
|
|
void QETElementEditor::setupInterface() {
|
|
// editeur
|
|
ce_scene = new ElementScene(this, this);
|
|
ce_scene -> slot_move();
|
|
ce_view = new ElementView(ce_scene, this);
|
|
slot_setRubberBandToView();
|
|
setCentralWidget(ce_view);
|
|
|
|
// widget par defaut dans le QDockWidget
|
|
default_informations = new QLabel();
|
|
|
|
// ScrollArea pour accueillir un widget d'edition (change a la volee)
|
|
tools_dock_scroll_area_ = new QScrollArea();
|
|
|
|
// Pile de widgets pour accueillir les deux widgets precedents
|
|
tools_dock_stack_ = new QStackedWidget();
|
|
tools_dock_stack_ -> insertWidget(0, default_informations);
|
|
tools_dock_stack_ -> insertWidget(1, tools_dock_scroll_area_);
|
|
|
|
// widgets d'editions pour les parties
|
|
editors_["arc"] = new ArcEditor(this);
|
|
editors_["circle"] = new CircleEditor(this);
|
|
editors_["ellipse"] = new EllipseEditor(this);
|
|
editors_["line"] = new LineEditor(this);
|
|
editors_["polygon"] = new PolygonEditor(this);
|
|
editors_["rect"] = new RectangleEditor(this);
|
|
editors_["terminal"] = new TerminalEditor(this);
|
|
editors_["text"] = new TextEditor(this);
|
|
editors_["input"] = new TextFieldEditor(this);
|
|
|
|
// panel sur le cote pour editer les parties
|
|
tools_dock = new QDockWidget(tr("Informations", "dock title"), this);
|
|
tools_dock -> setObjectName("informations");
|
|
tools_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
|
tools_dock -> setFeatures(QDockWidget::AllDockWidgetFeatures);
|
|
tools_dock -> setMinimumWidth(380);
|
|
addDockWidget(Qt::RightDockWidgetArea, tools_dock);
|
|
tools_dock -> setWidget(tools_dock_stack_);
|
|
|
|
// panel sur le cote pour les annulations
|
|
undo_dock = new QDockWidget(tr("Annulations", "dock title"), this);
|
|
undo_dock -> setObjectName("undo");
|
|
undo_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
|
undo_dock -> setFeatures(QDockWidget::AllDockWidgetFeatures);
|
|
undo_dock -> setMinimumWidth(290);
|
|
addDockWidget(Qt::RightDockWidgetArea, undo_dock);
|
|
QUndoView* undo_view = new QUndoView(&(ce_scene -> undoStack()), this);
|
|
undo_view -> setEmptyLabel(tr("Aucune modification"));
|
|
undo_dock -> setWidget(undo_view);
|
|
|
|
// panel sur le cote pour la liste des parties
|
|
parts_list = new QListWidget(this);
|
|
parts_list -> setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
connect(ce_scene, SIGNAL(partsAdded()), this, SLOT(slot_createPartsList()));
|
|
connect(ce_scene, SIGNAL(partsRemoved()), this, SLOT(slot_createPartsList()));
|
|
connect(ce_scene, SIGNAL(partsZValueChanged()), this, SLOT(slot_createPartsList()));
|
|
connect(ce_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updatePartsList()));
|
|
connect(parts_list, SIGNAL(itemSelectionChanged()), this, SLOT(slot_updateSelectionFromPartsList()));
|
|
parts_dock = new QDockWidget(tr("Parties", "dock title"), this);
|
|
parts_dock -> setObjectName("parts_list");
|
|
parts_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
|
parts_dock -> setFeatures(QDockWidget::AllDockWidgetFeatures);
|
|
parts_dock -> setMinimumWidth(290);
|
|
tabifyDockWidget(undo_dock, parts_dock);
|
|
parts_dock -> setWidget(parts_list);
|
|
|
|
slot_updateInformations();
|
|
slot_createPartsList();
|
|
|
|
// barre d'etat
|
|
statusBar() -> showMessage(tr("\311diteur d'\351l\351ments", "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() {
|
|
ce_view -> setDragMode(QGraphicsView::RubberBandDrag);
|
|
}
|
|
|
|
/**
|
|
Passe l'editeur d'element en mode immobile (utilise pour la lecture seule)
|
|
*/
|
|
void QETElementEditor::slot_setNoDragToView() {
|
|
ce_view -> setDragMode(QGraphicsView::NoDrag);
|
|
}
|
|
|
|
/**
|
|
Passe l'editeur en mode normal
|
|
*/
|
|
void QETElementEditor::slot_setNormalMode() {
|
|
if (!move -> isChecked()) move -> setChecked(true);
|
|
ce_view -> setDragMode(QGraphicsView::RubberBandDrag);
|
|
ce_scene -> slot_move();
|
|
}
|
|
|
|
/**
|
|
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<QGraphicsItem *> selected_qgis = ce_scene -> selectedItems();
|
|
|
|
clearToolsDock();
|
|
|
|
// s'il n'y a qu'une seule primitive selectionnee
|
|
if (selected_qgis.size() == 1) {
|
|
QGraphicsItem *qgi = selected_qgis.first();
|
|
if (CustomElementPart *selection = dynamic_cast<CustomElementPart *>(qgi)) {
|
|
// on en ajoute le widget d'edition
|
|
QString selection_xml_name = selection -> xmlName();
|
|
ElementItemEditor *selection_editor = editors_[selection_xml_name];
|
|
if (selection_editor) {
|
|
if (selection_editor -> setPart(selection)) {
|
|
tools_dock_scroll_area_ -> setWidget(selection_editor);
|
|
tools_dock_stack_ -> setCurrentIndex(1);
|
|
} else {
|
|
qDebug() << "Editor refused part.";
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
default_informations -> setText(
|
|
tr(
|
|
"%n partie(s) s\351lectionn\351e(s).",
|
|
"",
|
|
selected_qgis.size()
|
|
)
|
|
);
|
|
default_informations -> setAlignment(Qt::AlignHCenter | Qt::AlignTop);
|
|
tools_dock_stack_ -> setCurrentIndex(0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Affiche le code XML correspondant a l'element dans son etat actuel dans
|
|
une boite de dialogue.
|
|
*/
|
|
void QETElementEditor::xmlPreview() {
|
|
QET::MessageBox::information(
|
|
this,
|
|
"Export XML",
|
|
ce_scene -> toXml().toString(4)
|
|
);
|
|
}
|
|
|
|
/**
|
|
Effectue diverses verifications sur l'element et en informe l'utilisateur.
|
|
@return true si la situation est ok, false sinon
|
|
*/
|
|
bool QETElementEditor::checkElement() {
|
|
// liste les avertissements applicables
|
|
typedef QPair<QString, QString> QETWarning;
|
|
QList<QETWarning> warnings;
|
|
|
|
/// Avertissement #1 : si les parties semblent deborder du cadre de l'element
|
|
if (!ce_scene -> borderContainsEveryParts()) {
|
|
warnings << qMakePair(
|
|
tr("Dimensions de l'\351l\351ment", "warning title"),
|
|
tr(
|
|
"Certaines parties graphiques (textes, cercles, lignes...) "
|
|
"semblent d\351border du cadre de l'\351l\351ment. Cela "
|
|
"risque de g\351n\351rer des bugs graphiques lors de leur "
|
|
"manipulation sur un sch\351ma. Vous pouvez corriger cela soit "
|
|
"en d\351pla\347ant ces parties, soit en vous rendant dans "
|
|
"\311dition > \311diter la taille et le point de saisie.",
|
|
"warning description"
|
|
)
|
|
);
|
|
}
|
|
|
|
/// Avertissement #2 : si l'element ne comporte aucune borne
|
|
if (!ce_scene -> containsTerminals()) {
|
|
warnings << qMakePair(
|
|
tr("Absence de borne", "warning title"),
|
|
tr(
|
|
"L'\351l\351ment ne comporte aucune borne. Un \351l\351ment "
|
|
"doit comporter des bornes afin de pouvoir \351tre reli\351 "
|
|
"\340 d'autres \351l\351ments par l'interm\351diaire de "
|
|
"conducteurs.",
|
|
"warning description"
|
|
)
|
|
);
|
|
}
|
|
|
|
if (!warnings.count()) return(true);
|
|
|
|
// affiche les avertissements
|
|
QString warning_message = tr(
|
|
"La v\351rification de cet \351l\351ment a g\351n\351r\351 %n avertissement(s)\240:",
|
|
"message box content",
|
|
warnings.count()
|
|
);
|
|
|
|
warning_message += "<ol>";
|
|
foreach(QETWarning warning, warnings) {
|
|
warning_message += "<li>";
|
|
warning_message += QString(
|
|
tr("<b>%1</b>\240: %2", "warning title: warning description")
|
|
).arg(warning.first).arg(warning.second);
|
|
warning_message += "</li>";
|
|
}
|
|
warning_message += "</ol>";
|
|
|
|
QMessageBox warnings_message_box(this);
|
|
warnings_message_box.setWindowModality(Qt::WindowModal);
|
|
warnings_message_box.setWindowFlags(warnings_message_box.windowFlags() | Qt::Sheet);
|
|
warnings_message_box.setTextFormat(Qt::RichText);
|
|
warnings_message_box.setWindowTitle(tr("Avertissements", "messagebox title"));
|
|
warnings_message_box.setText(warning_message);
|
|
warnings_message_box.exec();
|
|
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::MessageBox::critical(this, tr("Erreur", "toolbar title"), error_message);
|
|
return;
|
|
}
|
|
|
|
// chargement de l'element
|
|
ce_scene -> fromXml(document_xml);
|
|
slot_createPartsList();
|
|
|
|
// gestion de la lecture seule
|
|
if (!infos_file.isWritable()) {
|
|
QET::MessageBox::warning(
|
|
this,
|
|
tr("\311dition en lecture seule", "message box title"),
|
|
tr("Vous n'avez pas les privil\350ges n\351cessaires pour modifier cet \351lement. 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();
|
|
}
|
|
|
|
/**
|
|
Enregistre l'element vers un fichier
|
|
@param fn Chemin du fichier a enregistrer
|
|
@return true en cas de reussite, false sinon
|
|
*/
|
|
bool QETElementEditor::toFile(const QString &fn) {
|
|
QFile file(fn);
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
|
QET::MessageBox::warning(this, tr("Erreur", "message box title"), tr("Impossible d'\351crire dans ce fichier", "message box content"));
|
|
return(false);
|
|
}
|
|
QTextStream out(&file);
|
|
out.setCodec("UTF-8");
|
|
out << ce_scene -> toXml().toString(4);
|
|
file.close();
|
|
return(true);
|
|
}
|
|
|
|
/**
|
|
Enregistre l'element vers un emplacement
|
|
@param location Emplacement de l'element a enregistrer
|
|
@return true en cas de reussite, false sinon
|
|
*/
|
|
bool QETElementEditor::toLocation(const ElementsLocation &location) {
|
|
ElementsCollectionItem *item = QETApp::collectionItem(location);
|
|
ElementDefinition *element;
|
|
if (item) {
|
|
// l'element existe deja
|
|
element = qobject_cast<ElementDefinition *>(item);
|
|
} else {
|
|
// l'element n'existe pas encore, on demande sa creation
|
|
element = QETApp::createElement(location);
|
|
}
|
|
|
|
if (!element) {
|
|
QET::MessageBox::critical(
|
|
this,
|
|
tr("Erreur", "message box title"),
|
|
tr("Impossible d'atteindre l'\351l\351ment", "message box content")
|
|
);
|
|
return(false);
|
|
}
|
|
|
|
// enregistre l'element
|
|
element -> setXml(ce_scene -> toXml().documentElement());
|
|
if (!element -> write()) {
|
|
QET::MessageBox::critical(
|
|
this,
|
|
tr("Erreur", "message box title"),
|
|
tr("Impossible d'enregistrer l'\351l\351ment", "message box content")
|
|
);
|
|
return(false);
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
/**
|
|
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
|
|
ce_view -> setInteractive(!ro);
|
|
|
|
slot_updateMenus();
|
|
}
|
|
|
|
/**
|
|
@return true si l'editeur d'element est en mode lecture seule
|
|
*/
|
|
bool QETElementEditor::isReadOnly() const {
|
|
return(read_only);
|
|
}
|
|
|
|
/**
|
|
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;
|
|
QETElementEditor *cee = new QETElementEditor();
|
|
cee -> fromLocation(location);
|
|
cee -> show();
|
|
}
|
|
|
|
/**
|
|
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) {
|
|
if (qApp -> activeWindow() != this) return;
|
|
openElement(filepath);
|
|
}
|
|
|
|
/**
|
|
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
|
|
*/
|
|
void QETElementEditor::openElement(const QString &filepath) {
|
|
if (filepath.isEmpty()) return;
|
|
QETElementEditor *cee = new QETElementEditor();
|
|
cee -> fromFile(filepath);
|
|
cee -> show();
|
|
}
|
|
|
|
/**
|
|
Recharge l'element edite
|
|
*/
|
|
void QETElementEditor::slot_reload() {
|
|
// s'il ya des modifications, on demande a l'utilisateur s'il est certain
|
|
// de vouloir recharger
|
|
if (!ce_scene -> undoStack().isClean()) {
|
|
QMessageBox::StandardButton answer = QET::MessageBox::question(
|
|
this,
|
|
tr("Recharger l'\351l\351ment", "dialog title"),
|
|
tr("Vous avez efffectu\351 des modifications sur cet \351l\351ment. Si vous le rechargez, ces modifications seront perdues. Voulez-vous vraiment recharger l'\351l\351ment ?", "dialog content"),
|
|
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
|
|
QMessageBox::Cancel
|
|
);
|
|
if (answer != QMessageBox::Yes) return;
|
|
}
|
|
|
|
// recharge l'element
|
|
if (opened_from_file) {
|
|
// l'element a ete ouvert a partir d'un chemin de fichier
|
|
ce_scene -> reset();
|
|
fromFile(filename_);
|
|
} else {
|
|
// l'element a ete ouvert a partir d'un emplacement (ElementsLocation)
|
|
// il peut s'agir aussi bien d'un fichier que d'un element XML
|
|
if (ElementsCollectionItem *item = QETApp::collectionItem(location_)) {
|
|
item -> reload();
|
|
ce_scene -> reset();
|
|
fromLocation(location_);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Enregistre l'element en cours d'edition.
|
|
Si le nom du fichier en cours n'est pas connu, cette methode equivaut a
|
|
l'action "Enregistrer sous"
|
|
@see slot_saveAs()
|
|
*/
|
|
bool QETElementEditor::slot_save() {
|
|
// verification avant d'enregistrer le fichier
|
|
checkElement();
|
|
|
|
// si on ne connait pas le nom du fichier en cours, enregistrer revient a enregistrer sous
|
|
if (opened_from_file) {
|
|
if (filename_.isEmpty()) return(slot_saveAsFile());
|
|
// sinon on enregistre dans le nom de fichier connu
|
|
bool result_save = toFile(filename_);
|
|
if (result_save) ce_scene -> undoStack().setClean();
|
|
return(result_save);
|
|
} else {
|
|
if (location_.isNull()) return(slot_saveAs());
|
|
// sinon on enregistre a l'emplacement connu
|
|
bool result_save = toLocation(location_);
|
|
if (result_save) ce_scene -> undoStack().setClean();
|
|
return(result_save);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Demande une localisation a l'utilisateur et enregistre l'element
|
|
*/
|
|
bool QETElementEditor::slot_saveAs() {
|
|
// demande une localisation a l'utilisateur
|
|
ElementsLocation location = ElementDialog::getSaveElementLocation(this);
|
|
if (location.isNull()) return(false);
|
|
|
|
// tente l'enregistrement
|
|
bool result_save = toLocation(location);
|
|
if (result_save) {
|
|
setLocation(location);
|
|
ce_scene -> undoStack().setClean();
|
|
}
|
|
|
|
// retourne un booleen representatif de la reussite de l'enregistrement
|
|
return(result_save);
|
|
}
|
|
|
|
/**
|
|
Demande un nom de fichier a l'utilisateur et enregistre l'element
|
|
*/
|
|
bool QETElementEditor::slot_saveAsFile() {
|
|
// demande un nom de fichier a l'utilisateur pour enregistrer l'element
|
|
QString fn = QFileDialog::getSaveFileName(
|
|
this,
|
|
tr("Enregistrer sous", "dialog title"),
|
|
filename_.isEmpty() ? QETApp::customElementsDir() : QDir(filename_).absolutePath(),
|
|
tr(
|
|
"\311l\351ments QElectroTech (*.elmt)",
|
|
"filetypes allowed when saving an element file"
|
|
)
|
|
);
|
|
// si aucun nom n'est entre, renvoie faux.
|
|
if (fn.isEmpty()) return(false);
|
|
// si le nom ne se termine pas par l'extension .elmt, celle-ci est ajoutee
|
|
if (!fn.endsWith(".elmt", Qt::CaseInsensitive)) fn += ".elmt";
|
|
// tente d'enregistrer le fichier
|
|
bool result_save = toFile(fn);
|
|
// si l'enregistrement reussit, le nom du fichier est conserve
|
|
if (result_save) {
|
|
setFileName(fn);
|
|
QETApp::elementsRecentFiles() -> fileWasOpened(fn);
|
|
ce_scene -> undoStack().setClean();
|
|
}
|
|
// retourne un booleen representatif de la reussite de l'enregistrement
|
|
return(result_save);
|
|
}
|
|
|
|
/**
|
|
@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 (ce_scene -> undoStack().isClean()) return(true);
|
|
// demande d'abord a l'utilisateur s'il veut enregistrer l'element en cours
|
|
QMessageBox::StandardButton answer = QET::MessageBox::question(
|
|
this,
|
|
tr("Enregistrer l'\351l\351ment en cours ?", "dialog title"),
|
|
QString(
|
|
tr(
|
|
"Voulez-vous enregistrer l'\351l\351ment %1 ?",
|
|
"dialog content - %1 is an element name"
|
|
)
|
|
).arg(ce_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 = tools_dock_scroll_area_ -> takeWidget()) {
|
|
previous_widget -> setParent(0);
|
|
previous_widget -> hide();
|
|
return(previous_widget);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
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);
|
|
|
|
ce_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);
|
|
qce -> accept();
|
|
} else qce -> ignore();
|
|
}
|
|
|
|
/**
|
|
Gere les evenements du l'editeur d'element
|
|
Reimplemente ici pour :
|
|
* mettre a jour l'action permettant d'entrer en mode plein ecran ou d'en sortir
|
|
@param e Evenement
|
|
*/
|
|
bool QETElementEditor::event(QEvent *e) {
|
|
if (e -> type() == QEvent::WindowStateChange) {
|
|
slot_updateFullScreenAction();
|
|
}
|
|
return(QMainWindow::event(e));
|
|
}
|
|
|
|
/**
|
|
Remplit la liste des parties
|
|
*/
|
|
void QETElementEditor::slot_createPartsList() {
|
|
parts_list -> blockSignals(true);
|
|
parts_list -> clear();
|
|
QList<QGraphicsItem *> qgis = ce_scene -> zItems(true);
|
|
for (int j = qgis.count() - 1 ; j >= 0 ; -- j) {
|
|
QGraphicsItem *qgi = qgis[j];
|
|
if (CustomElementPart *cep = dynamic_cast<CustomElementPart *>(qgi)) {
|
|
QString part_desc = cep -> name();
|
|
QListWidgetItem *qlwi = new QListWidgetItem(part_desc);
|
|
QVariant v;
|
|
v.setValue<QGraphicsItem *>(qgi);
|
|
qlwi -> setData(42, v);
|
|
parts_list -> addItem(qlwi);
|
|
qlwi -> setSelected(qgi -> isSelected());
|
|
}
|
|
}
|
|
parts_list -> blockSignals(false);
|
|
}
|
|
|
|
/**
|
|
Met a jour la selection dans la liste des parties
|
|
*/
|
|
void QETElementEditor::slot_updatePartsList() {
|
|
if (parts_list -> count() != ce_scene -> items().count()) {
|
|
slot_createPartsList();
|
|
} else {
|
|
parts_list -> blockSignals(true);
|
|
int i = 0;
|
|
QList<QGraphicsItem *> items = ce_scene -> zItems(true);
|
|
for (int j = items.count() - 1 ; j >= 0 ; -- j) {
|
|
QGraphicsItem *qgi = items[j];
|
|
QListWidgetItem *qlwi = parts_list -> item(i);
|
|
if (qlwi) qlwi -> setSelected(qgi -> isSelected());
|
|
++ i;
|
|
}
|
|
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() {
|
|
ce_scene -> blockSignals(true);
|
|
parts_list -> blockSignals(true);
|
|
for (int i = 0 ; i < parts_list -> count() ; ++ i) {
|
|
QListWidgetItem *qlwi = parts_list -> item(i);
|
|
QGraphicsItem *qgi = qlwi -> data(42).value<QGraphicsItem *>();
|
|
if (qgi) {
|
|
qgi -> setSelected(qlwi -> isSelected());
|
|
}
|
|
}
|
|
parts_list -> blockSignals(false);
|
|
ce_scene -> blockSignals(false);
|
|
slot_updateInformations();
|
|
slot_updateMenus();
|
|
}
|
|
|
|
/**
|
|
Fait passer la fenetre du mode plein ecran au mode normal et vice-versa
|
|
*/
|
|
void QETElementEditor::toggleFullScreen() {
|
|
setWindowState(windowState() ^ Qt::WindowFullScreen);
|
|
}
|
|
|
|
/// Lit les parametres de l'editeur d'element
|
|
void QETElementEditor::readSettings() {
|
|
QSettings &settings = QETApp::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
|
|
ce_scene -> setInformations(settings.value("elementeditor/default-informations", "").toString());
|
|
}
|
|
|
|
/// Enregistre les parametres de l'editeur d'element
|
|
void QETElementEditor::writeSettings() {
|
|
QSettings &settings = QETApp::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);
|
|
}
|
|
|
|
/**
|
|
@return Le type de mouvement a effectuer lors d'un copier/coller avec
|
|
decalage.
|
|
*/
|
|
QET::OrientedMovement QETElementEditor::pasteMovement() {
|
|
return(QET::ToEast);
|
|
}
|
|
|
|
/**
|
|
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(
|
|
"\311l\351ments QElectroTech (*.elmt);;"
|
|
"Fichiers XML (*.xml);;"
|
|
"Tous les fichiers (*)",
|
|
"filetypes allowed when opening an element file"
|
|
)
|
|
);
|
|
return(user_filename);
|
|
}
|
|
|
|
/**
|
|
@param location Emplacement de l'element a editer
|
|
*/
|
|
void QETElementEditor::fromLocation(const ElementsLocation &location) {
|
|
|
|
// l'element doit exister
|
|
ElementsCollectionItem *item = QETApp::collectionItem(location);
|
|
ElementDefinition *element = 0;
|
|
if (!item) {
|
|
QET::MessageBox::critical(
|
|
this,
|
|
tr("\311l\351ment inexistant.", "message box title"),
|
|
tr("L'\351l\351ment n'existe pas.", "message box content")
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (!item -> isElement() || !(element = qobject_cast<ElementDefinition *>(item)) || element -> isNull()) {
|
|
QET::MessageBox::critical(
|
|
this,
|
|
tr("\311l\351ment inexistant.", "message box title"),
|
|
tr("Le chemin virtuel choisi ne correspond pas \340 un \351l\351ment.", "message box content")
|
|
);
|
|
return;
|
|
}
|
|
|
|
// le fichier doit etre un document XML
|
|
QDomDocument document_xml;
|
|
QDomNode node = document_xml.importNode(element -> xml(), true);
|
|
document_xml.appendChild(node);
|
|
|
|
// chargement de l'element
|
|
ce_scene -> fromXml(document_xml);
|
|
slot_createPartsList();
|
|
|
|
// gestion de la lecture seule
|
|
if (!element -> isWritable()) {
|
|
QET::MessageBox::warning(
|
|
this,
|
|
tr("\311dition en lecture seule", "message box title"),
|
|
tr("Vous n'avez pas les privil\350ges n\351cessaires pour modifier cet \351lement. Il sera donc ouvert en lecture seule.", "message box content")
|
|
);
|
|
setReadOnly(true);
|
|
} else {
|
|
setReadOnly(false);
|
|
}
|
|
|
|
// memorise le fichier
|
|
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::MessageBox::critical(this, tr("Erreur", "toolbar title"), error_message);
|
|
}
|
|
copyAndPasteXml(xml_document);
|
|
}
|
|
|
|
/**
|
|
Denande un element a l'utilisateur, met son contenu dans le presse-papiers,
|
|
et appelle ElementView::PasteInArea
|
|
*/
|
|
void QETElementEditor::pasteFromElement() {
|
|
// demande le chemin virtuel de l'element a ouvrir a l'utilisateur
|
|
ElementsLocation location = ElementDialog::getOpenElementLocation(this);
|
|
if (location.isNull()) return;
|
|
|
|
// verifie l'existence de l'element choisi
|
|
ElementsCollectionItem *item = QETApp::collectionItem(location);
|
|
ElementDefinition *element = 0;
|
|
if (!item) {
|
|
QET::MessageBox::critical(
|
|
this,
|
|
tr("\311l\351ment inexistant.", "message box title"),
|
|
tr("L'\351l\351ment n'existe pas.", "message box content")
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (!item -> isElement() || !(element = qobject_cast<ElementDefinition *>(item)) || element -> isNull()) {
|
|
QET::MessageBox::critical(
|
|
this,
|
|
tr("\311l\351ment inexistant.", "message box title"),
|
|
tr("Le chemin virtuel choisi ne correspond pas \340 un \351l\351ment.", "message box content")
|
|
);
|
|
return;
|
|
}
|
|
|
|
// creation d'un document XML a partir de la description XML de l'element
|
|
QDomDocument document_xml;
|
|
QDomNode node = document_xml.importNode(element -> 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 (!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<ElementItemEditor *>(tools_dock_scroll_area_ -> widget())) {
|
|
current_editor -> updateForm();
|
|
}
|
|
}
|