diff --git a/ico/titleblock.png b/ico/titleblock.png new file mode 100644 index 000000000..c0585d411 Binary files /dev/null and b/ico/titleblock.png differ diff --git a/qelectrotech.qrc b/qelectrotech.qrc index dc74de6b5..bf21bb49b 100644 --- a/qelectrotech.qrc +++ b/qelectrotech.qrc @@ -180,6 +180,7 @@ ico/oxygen-icons/48x48/apps/qelectrotech.png ico/oxygen-icons/64x64/apps/qelectrotech.png ico/splash.png + ico/titleblock.png titleblocks/default.titleblock LICENSE diff --git a/sources/bordertitleblock.cpp b/sources/bordertitleblock.cpp index 95b9a30b6..48e0b19b1 100644 --- a/sources/bordertitleblock.cpp +++ b/sources/bordertitleblock.cpp @@ -161,6 +161,35 @@ void BorderTitleBlock::setTitleBlockTemplate(const TitleBlockTemplate *titlebloc titleblock_template_renderer -> setTitleBlockTemplate(titleblock_template); } +/** + This slot may be used to inform this class that the given title block + template has changed. The title block-dedicated rendering cache will thus be + flushed. + @param template_name Name of the title block template that has changed +*/ +void BorderTitleBlock::titleBlockTemplateChanged(const QString &template_name) { + Q_UNUSED(template_name); // this class does not store the name of its template + titleblock_template_renderer -> invalidateRenderedTemplate(); +} + +/** + This slot has to be used to inform this class that the given title block + template is about to be removed and is no longer accessible. This class + will either use the provided optional TitleBlockTemplate or the default + title block provided by QETApp::defaultTitleBlockTemplate() + @param template_name Name of the title block template that has changed + @param new_template (Optional) title block template to use instead +*/ +void BorderTitleBlock::titleBlockTemplateRemoved(const QString &removed_template_name, const TitleBlockTemplate *new_template) { + Q_UNUSED(removed_template_name); // this class does not store the name of its template + + if (new_template) { + setTitleBlockTemplate(new_template); + } else { + setTitleBlockTemplate(QETApp::defaultTitleBlockTemplate()); + } +} + /** @param di true pour afficher le cartouche, false sinon */ diff --git a/sources/bordertitleblock.h b/sources/bordertitleblock.h index dfe395dcb..a9502580d 100644 --- a/sources/bordertitleblock.h +++ b/sources/bordertitleblock.h @@ -153,6 +153,10 @@ class BorderTitleBlock : public QObject { const TitleBlockTemplate *titleBlockTemplate(); void setTitleBlockTemplate(const TitleBlockTemplate *); + public slots: + void titleBlockTemplateChanged(const QString &); + void titleBlockTemplateRemoved(const QString &, const TitleBlockTemplate * = 0); + // methodes d'acces en ecriture aux options void displayTitleBlock(bool); void displayColumns(bool); diff --git a/sources/diagram.cpp b/sources/diagram.cpp index 006d27230..ae59d956f 100644 --- a/sources/diagram.cpp +++ b/sources/diagram.cpp @@ -765,6 +765,36 @@ void Diagram::diagramTextChanged(DiagramTextItem *text_item, const QString &old_ undo_stack -> push(new ChangeDiagramTextCommand(text_item, old_text, new_text)); } +/** + This slot may be used to inform the diagram object that the given title + block template has changed. The diagram will thus flush its title + block-dedicated rendering cache. + @param template_name Name of the title block template that has changed +*/ +void Diagram::titleBlockTemplateChanged(const QString &template_name) { + if (titleblock_template_name_ == template_name) { + border_and_titleblock.titleBlockTemplateChanged(template_name); + } + update(); +} + +/** + This slot has to be be used to inform this class that the given title block + template is about to be removed and is no longer accessible. This class + will either use the provided optional TitleBlockTemplate or the default + title block provided by QETApp::defaultTitleBlockTemplate() + @param template_name Name of the title block template that has changed + @param new_template (Optional) Name of the title block template to use instead +*/ +void Diagram::titleBlockTemplateRemoved(const QString &template_name, const QString &new_template) { + if (titleblock_template_name_ == template_name) { + const TitleBlockTemplate *final_template = project_ -> getTemplateByName(new_template); + titleblock_template_name_ = final_template ? new_template : QString(); + border_and_titleblock.titleBlockTemplateRemoved(template_name, final_template); + update(); + } +} + /** Selectionne tous les objets du schema */ diff --git a/sources/diagram.h b/sources/diagram.h index 8a51ab044..efdbd0e93 100644 --- a/sources/diagram.h +++ b/sources/diagram.h @@ -169,6 +169,8 @@ class Diagram : public QGraphicsScene { public slots: void diagramTextChanged(DiagramTextItem *, const QString &, const QString &); + void titleBlockTemplateChanged(const QString &); + void titleBlockTemplateRemoved(const QString &, const QString & = QString()); // fonctions relative a la selection sur le schema void selectAll(); diff --git a/sources/elementspanel.cpp b/sources/elementspanel.cpp index 3e42ae4e6..3bbfababd 100644 --- a/sources/elementspanel.cpp +++ b/sources/elementspanel.cpp @@ -170,6 +170,24 @@ bool ElementsPanel::itemIsWritable(QTreeWidgetItem *qtwi) const { return(false); } +/** + @param qtwi A QTreeWidgetItem + @return true if the given QTreeWidgetItem represents a block templates directory +*/ +bool ElementsPanel::itemIsATitleBlockTemplatesDirectory(QTreeWidgetItem *qtwi) const { + return(title_blocks_directories_.contains(qtwi)); +} + +/** + @param qtwi A QTreeWidgetItem + @return true if the given QTreeWidgetItem represents a block template +*/ +bool ElementsPanel::itemIsATitleBlockTemplate(QTreeWidgetItem *qtwi) const { + // does this QTreeWidgetItem have a parent? + if (!qtwi -> parent()) return(false); + return(itemIsATitleBlockTemplatesDirectory(qtwi -> parent())); +} + /** @param qtwi Un QTreeWidgetItem @return L'ElementsCollectionItem represente par qtwi, ou 0 si qtwi ne @@ -279,6 +297,23 @@ bool ElementsPanel::selectedItemIsWritable() const { return(false); } +/** + @return true if the currently selected item represents a title block + templates directory +*/ +bool ElementsPanel::selectedItemIsATitleBlockTemplatesDirectory() const { + return(itemIsATitleBlockTemplatesDirectory(currentItem())); +} + +/** + @return true if the currently selected item represents a title block + template +*/ +bool ElementsPanel::selectedItemIsATitleBlockTemplate() const { + if (!currentItem()) return(false); + return(itemIsATitleBlockTemplate(currentItem())); +} + /** @return la collection, la categorie ou l'element selectionne(e) */ @@ -507,6 +542,13 @@ QTreeWidgetItem *ElementsPanel::addProject(QTreeWidgetItem *qtwi_parent, QETProj addDiagram(qtwi_project, diagram); } + // add the title blocks templates embedded within the project + updateProjectTemplates(project); + connect( + project, SIGNAL(projectTemplatesChanged(QETProject *)), + this, SLOT (projectTemplatesChanged(QETProject *)) + ); + // ajoute la collection du projet addCollection(qtwi_project, project -> embeddedCollection(), tr("Collection projet")); @@ -673,6 +715,7 @@ void ElementsPanel::reload(bool reload_collections) { locations_.clear(); projects_.clear(); diagrams_.clear(); + title_blocks_directories_.clear(); common_collection_item_ = 0; custom_collection_item_ = 0; @@ -769,6 +812,8 @@ void ElementsPanel::deleteItem(QTreeWidgetItem *removed_item) { diagrams_.remove(removed_item); } else if (projects_.contains(removed_item)) { projects_.remove(removed_item); + } else if (title_blocks_directories_.contains(removed_item)) { + title_blocks_directories_.remove(removed_item); } delete removed_item; } @@ -789,6 +834,41 @@ ElementsCategory *ElementsPanel::categoryForPos(const QPoint &pos) { return(categoryForItem(pos_qtwi)); } +/** + @param qtwi A QTreeWidgetItem, supposed to represent a templates directory + @return the project that embeds the given templates directory, if + applicable, 0 otherwise +*/ +QETProject *ElementsPanel::projectForTitleBlockTemplatesDirectory(QTreeWidgetItem *qtwi) { + if (title_blocks_directories_.contains(qtwi)) { + return(title_blocks_directories_[qtwi]); + } + return(0); +} + +/** + @param qtwi A QTreeWidgetItem, supposed to represent a title block template + @return the project that embeds the given template, if applicable, 0 + otherwise +*/ +QETProject *ElementsPanel::projectForTitleBlockTemplate(QTreeWidgetItem *qtwi) { + if (qtwi->parent()) { + return(projectForTitleBlockTemplatesDirectory(qtwi->parent())); + } + return(0); +} + +/** + @param qtwi A QTreeWidgetItem, supposed to represent a title block template + @return the name of the given template, if applicable, 0 otherwise +*/ +QString ElementsPanel::nameOfTitleBlockTemplate(QTreeWidgetItem *qtwi) { + if (itemIsATitleBlockTemplate(qtwi)) { + return(qtwi -> data(0, 42).toString()); + } + return(QString()); +} + /** Cette methode permet d'acceder a la categorie correspondant a un item donne. Si cet item represente une collection, c'est sa categorie racine qui est renvoyee. @@ -860,6 +940,14 @@ void ElementsPanel::projectInformationsChanged(QETProject *project) { updateProjectItemInformations(project); } +/** + Handles the fact that the title block templates of a project changed. + @param project the modified project +*/ +void ElementsPanel::projectTemplatesChanged(QETProject *project) { + updateProjectTemplates(project); +} + /** Gere l'ajout d'un schema dans un projet @param project Projet auquel a ete ajouter le schema @@ -965,6 +1053,39 @@ void ElementsPanel::updateProjectItemInformations(QETProject *project) { qtwi_project -> setIcon(0, QET::Icons::Project); } +/** + (Re)generates the templates list of a given project. + @param project the project we want to update the templates +*/ +void ElementsPanel::updateProjectTemplates(QETProject *project) { + // determine the QTWI for the templates directory of the given project + QTreeWidgetItem *qtwi_project = projects_.key(project); + if (!qtwi_project) return; + + // determine the templates directory for the given project, if any + QTreeWidgetItem *titleblock_templates_qtwi = title_blocks_directories_.key(project); + if (!titleblock_templates_qtwi) { + // the poor thing does not exist... let's create it. + titleblock_templates_qtwi = new QTreeWidgetItem(qtwi_project, QStringList() << tr("Mod\350les de cartouche")); + titleblock_templates_qtwi -> setIcon(0, QET::Icons::Folder); + titleblock_templates_qtwi -> setExpanded(true); + title_blocks_directories_.insert(titleblock_templates_qtwi, project); + } else { + // oh, what a shiny templates directory... let's clear it. + foreach(QTreeWidgetItem *titleblock_template_qtwi, titleblock_templates_qtwi -> takeChildren()) { + deleteItem(titleblock_template_qtwi); + } + } + + // we can now populate the templates directory + foreach (QString titleblock_name, project -> embeddedTitleBlockTemplates()) { + QString final_name = QString(tr("Mod\350le \"%1\"")).arg(titleblock_name); + QTreeWidgetItem *titleblock_template_qtwi = new QTreeWidgetItem(titleblock_templates_qtwi, QStringList() << final_name); + titleblock_template_qtwi -> setIcon(0, QET::Icons::TitleBlock); + titleblock_template_qtwi -> setData(0, 42, titleblock_name); // we store the original title block template name here, since the displayed one could be modified + } +} + /** @param diagram Schema dont on souhaite affiche le titre @return Un titre affichable, tenant compte du fait que le titre du schema diff --git a/sources/elementspanel.h b/sources/elementspanel.h index 668bcba10..a1af64ff0 100644 --- a/sources/elementspanel.h +++ b/sources/elementspanel.h @@ -51,6 +51,8 @@ class ElementsPanel : public QTreeWidget { bool itemIsADiagram(QTreeWidgetItem *) const; bool itemHasLocation(QTreeWidgetItem *) const; bool itemIsWritable(QTreeWidgetItem *) const; + bool itemIsATitleBlockTemplatesDirectory(QTreeWidgetItem *) const; + bool itemIsATitleBlockTemplate(QTreeWidgetItem *) const; // methodes pour obtenir ce que represente un item donne ElementsCollectionItem *collectionItemForItem(QTreeWidgetItem *) const; @@ -59,6 +61,9 @@ class ElementsPanel : public QTreeWidget { ElementsLocation locationForItem(QTreeWidgetItem *) const; ElementsCategory *categoryForItem(QTreeWidgetItem *); ElementsCategory *categoryForPos(const QPoint &); + QETProject *projectForTitleBlockTemplatesDirectory(QTreeWidgetItem *); + QETProject *projectForTitleBlockTemplate(QTreeWidgetItem *); + QString nameOfTitleBlockTemplate(QTreeWidgetItem *); // methodes pour determiner ce que represente l'item selectionne bool selectedItemIsACollection() const; @@ -68,6 +73,8 @@ class ElementsPanel : public QTreeWidget { bool selectedItemIsADiagram() const; bool selectedItemHasLocation() const; bool selectedItemIsWritable() const; + bool selectedItemIsATitleBlockTemplatesDirectory() const; + bool selectedItemIsATitleBlockTemplate() const; // methodes pour obtenir ce que represente l'item selectionne ElementsCollectionItem *selectedItem() const; @@ -88,6 +95,7 @@ class ElementsPanel : public QTreeWidget { void projectWasOpened(QETProject *); void projectWasClosed(QETProject *); void projectInformationsChanged(QETProject *); + void projectTemplatesChanged(QETProject *); void diagramWasAdded(QETProject *, Diagram *); void diagramWasRemoved(QETProject *, Diagram *); void diagramTitleChanged(QETProject *, Diagram *); @@ -111,6 +119,7 @@ class ElementsPanel : public QTreeWidget { QTreeWidgetItem *findLocation(const QString &) const; void deleteItem(QTreeWidgetItem *); void updateProjectItemInformations(QETProject *); + void updateProjectTemplates(QETProject *); QString diagramTitleToDisplay(Diagram *) const; void ensureHierarchyIsVisible(QList); @@ -122,6 +131,7 @@ class ElementsPanel : public QTreeWidget { QSet projects_to_display_; QHash projects_; QHash diagrams_; + QHash title_blocks_directories_; QTreeWidgetItem *common_collection_item_; QTreeWidgetItem *custom_collection_item_; }; diff --git a/sources/elementspanelwidget.cpp b/sources/elementspanelwidget.cpp index 1ec5cb432..1a58142a8 100644 --- a/sources/elementspanelwidget.cpp +++ b/sources/elementspanelwidget.cpp @@ -64,6 +64,9 @@ ElementsPanelWidget::ElementsPanelWidget(QWidget *parent) : QWidget(parent) { prj_del_diagram = new QAction(QET::Icons::DiagramDelete, tr("Supprimer ce sch\351ma"), this); prj_move_diagram_up = new QAction(QET::Icons::GoUp, tr("Remonter ce sch\351ma"), this); prj_move_diagram_down = new QAction(QET::Icons::GoDown, tr("Abaisser ce sch\351ma"), this); + tbt_add = new QAction(QET::Icons::TitleBlock, tr("Importer un nouveau mod\350le"), this); + tbt_edit = new QAction(QET::Icons::TitleBlock, tr("\311diter ce mod\350le"), this); + tbt_remove = new QAction(QET::Icons::TitleBlock, tr("Supprimer ce mod\350le"), this); move_elements_ = new QAction(QET::Icons::MoveFile, tr("D\351placer dans cette cat\351gorie"), this); copy_elements_ = new QAction(QET::Icons::CopyFile, tr("Copier dans cette cat\351gorie"), this); cancel_elements_ = new QAction(QET::Icons::Cancel, tr("Annuler"), this); @@ -102,6 +105,9 @@ ElementsPanelWidget::ElementsPanelWidget(QWidget *parent) : QWidget(parent) { connect(prj_del_diagram, SIGNAL(triggered()), this, SLOT(deleteDiagram())); connect(prj_move_diagram_up, SIGNAL(triggered()), this, SLOT(moveDiagramUp())); connect(prj_move_diagram_down, SIGNAL(triggered()), this, SLOT(moveDiagramDown())); + connect(tbt_add, SIGNAL(triggered()), this, SLOT(addTitleBlockTemplate())); + connect(tbt_edit, SIGNAL(triggered()), this, SLOT(editTitleBlockTemplate())); + connect(tbt_remove, SIGNAL(triggered()), this, SLOT(removeTitleBlockTemplate())); connect(move_elements_, SIGNAL(triggered()), this, SLOT(moveElements())); connect(copy_elements_, SIGNAL(triggered()), this, SLOT(copyElements())); @@ -234,6 +240,49 @@ void ElementsPanelWidget::moveDiagramDown() { } } +/** + Opens a template editor to create a new title block template. +*/ +void ElementsPanelWidget::addTitleBlockTemplate() { + QTreeWidgetItem *current_item = elements_panel -> currentItem(); + if (!current_item) return; + + QETProject *parent_project = 0; + if (elements_panel -> itemIsATitleBlockTemplate(current_item)) { + parent_project = elements_panel -> projectForTitleBlockTemplate(current_item); + } else if (elements_panel -> itemIsATitleBlockTemplatesDirectory(current_item)) { + parent_project = elements_panel -> projectForTitleBlockTemplatesDirectory(current_item); + } + + if (parent_project) { + QETApp::instance() -> openTitleBlockTemplate(parent_project); + } +} + +/** + Opens an editor to edit the currently selected title block template, if any. +*/ +void ElementsPanelWidget::editTitleBlockTemplate() { + QTreeWidgetItem *current_item = elements_panel -> currentItem(); + if (current_item && elements_panel -> itemIsATitleBlockTemplate(current_item)) { + QETProject *parent_project = elements_panel -> projectForTitleBlockTemplate(current_item); + QString template_name = elements_panel -> nameOfTitleBlockTemplate(current_item); + QETApp::instance() -> openTitleBlockTemplate(parent_project, template_name); + } +} + +/** + Delete the currently selected title block template, if any. +*/ +void ElementsPanelWidget::removeTitleBlockTemplate() { + QTreeWidgetItem *current_item = elements_panel -> currentItem(); + if (current_item && elements_panel -> itemIsATitleBlockTemplate(current_item)) { + QETProject *parent_project = elements_panel -> projectForTitleBlockTemplate(current_item); + QString template_name = elements_panel -> nameOfTitleBlockTemplate(current_item); + parent_project -> removeTemplateByName(template_name); + } +} + /** Appelle l'assistant de creation de nouvel element */ @@ -311,6 +360,14 @@ void ElementsPanelWidget::updateButtons() { prj_del_diagram -> setEnabled(is_writable); prj_move_diagram_up -> setEnabled(is_writable && diagram_position > 0); prj_move_diagram_down -> setEnabled(is_writable && diagram_position < project_diagrams_count - 1); + } else if (elements_panel -> selectedItemIsATitleBlockTemplatesDirectory()) { + bool is_writable = !(elements_panel -> projectForTitleBlockTemplatesDirectory(elements_panel -> currentItem()) -> isReadOnly()); + tbt_add -> setEnabled(is_writable); + } else if (elements_panel -> selectedItemIsATitleBlockTemplate()) { + bool is_writable = !(elements_panel -> projectForTitleBlockTemplate(elements_panel -> currentItem()) -> isReadOnly()); + tbt_add -> setEnabled(is_writable); + tbt_edit -> setEnabled(is_writable); + tbt_remove -> setEnabled(is_writable); } } @@ -381,6 +438,12 @@ void ElementsPanelWidget::handleContextMenu(const QPoint &pos) { context_menu -> addAction(prj_del_diagram); context_menu -> addAction(prj_move_diagram_up); context_menu -> addAction(prj_move_diagram_down); + } else if (elements_panel -> itemIsATitleBlockTemplatesDirectory(item)) { + context_menu -> addAction(tbt_add); + } else if (elements_panel -> itemIsATitleBlockTemplate(item)) { + context_menu -> addAction(tbt_add); + context_menu -> addAction(tbt_edit); + context_menu -> addAction(tbt_remove); } } diff --git a/sources/elementspanelwidget.h b/sources/elementspanelwidget.h index c15cdab5a..a50c1856c 100644 --- a/sources/elementspanelwidget.h +++ b/sources/elementspanelwidget.h @@ -43,6 +43,7 @@ class ElementsPanelWidget : public QWidget { QAction *delete_collection; QAction *new_element, *import_element, *edit_element, *delete_element; QAction *prj_close, *prj_edit_prop, *prj_prop_diagram, *prj_add_diagram, *prj_del_diagram, *prj_move_diagram_up, *prj_move_diagram_down; + QAction *tbt_add, *tbt_edit, *tbt_remove; QAction *copy_elements_, *move_elements_, *cancel_elements_; QMenu *context_menu; QAction *erase_textfield; @@ -72,6 +73,9 @@ class ElementsPanelWidget : public QWidget { void deleteDiagram(); void moveDiagramUp(); void moveDiagramDown(); + void addTitleBlockTemplate(); + void editTitleBlockTemplate(); + void removeTitleBlockTemplate(); void newCategory(); void newElement(); void importElement(); diff --git a/sources/qetapp.cpp b/sources/qetapp.cpp index 58039b5f6..71e2cfb5b 100644 --- a/sources/qetapp.cpp +++ b/sources/qetapp.cpp @@ -23,6 +23,7 @@ #include "elementscollectionitem.h" #include "fileelementscollection.h" #include "titleblocktemplate.h" +#include "templateeditor.h" #include "qetproject.h" #include "qtextorientationspinboxwidget.h" #include "recentfiles.h" @@ -835,6 +836,23 @@ void QETApp::openElementLocations(const QList &locations_list) } } +/** + Launch a new title block template editor to edit the given template + @param project Parent project of the template to edit + @param template_name Name of the template to edit within its parent project + If no template name is supplied, the method assumes the editor has to be + launched for a template creation. +*/ +void QETApp::openTitleBlockTemplate(QETProject *project, const QString &template_name) { + TemplateEditor *editor = new TemplateEditor(); + bool can_edit = editor -> edit(project, template_name); + if (can_edit) { + editor -> showNormal(); + } else { + QMessageBox::warning(0, tr("Erreur"), tr("Impossible d'\351diter le template demand\351")); + } +} + /** Permet a l'utilisateur de configurer QET en lancant un dialogue approprie. @see ConfigDialog diff --git a/sources/qetapp.h b/sources/qetapp.h index 577fecca9..39a61759d 100644 --- a/sources/qetapp.h +++ b/sources/qetapp.h @@ -165,6 +165,7 @@ class QETApp : public QETSingleApplication { void openProjectFiles(const QStringList &); void openElementFiles(const QStringList &); void openElementLocations(const QList &); + void openTitleBlockTemplate(QETProject *, const QString & = QString()); void configureQET(); void aboutQET(); diff --git a/sources/qeticons.cpp b/sources/qeticons.cpp index 50a382bab..96e0f8500 100644 --- a/sources/qeticons.cpp +++ b/sources/qeticons.cpp @@ -128,6 +128,7 @@ namespace QET { QIcon South; QIcon Start; QIcon Terminal; + QIcon TitleBlock; QIcon UserInformations; QIcon ViewFitWidth; QIcon ViewFitWindow; @@ -304,6 +305,7 @@ void QET::Icons::initIcons() { South .addFile(":/ico/16x16/south.png"); Start .addFile(":/ico/22x22/start.png"); Terminal .addFile(":/ico/22x22/terminal.png"); + TitleBlock .addFile(":/ico/titleblock.png"); UserInformations .addFile(":/ico/16x16/preferences-desktop-user.png"); UserInformations .addFile(":/ico/22x22/preferences-desktop-user.png"); ViewFitWidth .addFile(":/ico/22x22/view_fit_width.png"); diff --git a/sources/qeticons.h b/sources/qeticons.h index 48d60ebb5..de81b7c21 100644 --- a/sources/qeticons.h +++ b/sources/qeticons.h @@ -138,6 +138,7 @@ namespace QET { extern QIcon South; extern QIcon Start; extern QIcon Terminal; + extern QIcon TitleBlock; extern QIcon UserInformations; extern QIcon ViewFitWidth; extern QIcon ViewFitWindow; diff --git a/sources/qetproject.cpp b/sources/qetproject.cpp index ae5cbf9a9..177542307 100644 --- a/sources/qetproject.cpp +++ b/sources/qetproject.cpp @@ -312,6 +312,70 @@ QDomElement QETProject::getTemplateXmlDescriptionByName(const QString &template_ return(QDomElement()); } +/** + This methods allows adding or modifying a template embedded within the + project. This method emits the signal projectTemplatesChanged() if + necessary. + @param template_name Name / Identifier of the template - will be used to + determine whether the given description will be added or will replace an + existing one. + @param xml_elmt An \ XML element describing the + template. Its "name" attribute must equal to template_name. + @return false if a problem occured, true otherwise +*/ +bool QETProject::setTemplateXmlDescription(const QString &template_name, const QDomElement &xml_elmt) { + // checks basic stuff + if (xml_elmt.tagName() != "titleblocktemplate" || xml_elmt.attribute("name") != template_name) { + return(false); + } + + // we import the provided XML element in the project document + QDomElement import = document_root_.importNode(xml_elmt, true).toElement(); + + // we either replace the previous description + if (titleblock_templates_xml_.contains(template_name)) { + QDomElement old_description = titleblock_templates_xml_[template_name]; + if (!old_description.parentNode().isNull()) { + old_description.parentNode().replaceChild(import, old_description); + titleblock_templates_xml_[template_name] = import; + } + } else { + // or simply insert the new one + titleblock_templates_xml_.insert(template_name, import); + } + + if (titleblock_templates_.contains(template_name)) { + titleblock_templates_[template_name] -> loadFromXmlElement(titleblock_templates_xml_[template_name]); + foreach (Diagram *diagram, diagrams_) { + diagram -> titleBlockTemplateChanged(template_name); + } + } + emit(projectTemplatesChanged(this)); + + return(true); +} + +/** + This methods allows removing a template embedded within the project. This + method emits the signal projectTemplatesChanged() if necessary. + @param template_name Name of the template to be removed +*/ +void QETProject::removeTemplateByName(const QString &template_name) { + if (titleblock_templates_.contains(template_name)) { + // warn diagrams that the given template is about to be removed + foreach (Diagram *diagram, diagrams_) { + diagram -> titleBlockTemplateRemoved(template_name); /// TODO specify the default template of the project as a fallback + } + } + + // remove the template itself + titleblock_templates_xml_.remove(template_name); + titleblock_templates_.remove(template_name); + + // warn the rest of the world that the list of templates embedded within this project has changed + emit(projectTemplatesChanged(this)); +} + /** @return les dimensions par defaut utilisees lors de la creation d'un nouveau schema dans ce projet. diff --git a/sources/qetproject.h b/sources/qetproject.h index 148bb9ecd..678d5f91d 100644 --- a/sources/qetproject.h +++ b/sources/qetproject.h @@ -83,6 +83,8 @@ class QETProject : public QObject { QList embeddedTitleBlockTemplates() const; const TitleBlockTemplate *getTemplateByName(const QString &template_name); QDomElement getTemplateXmlDescriptionByName(const QString &); + bool setTemplateXmlDescription(const QString &, const QDomElement &); + void removeTemplateByName(const QString &); BorderProperties defaultBorderProperties() const; void setDefaultBorderProperties(const BorderProperties &); TitleBlockProperties defaultTitleBlockProperties() const; @@ -119,6 +121,7 @@ class QETProject : public QObject { void diagramAdded(QETProject *, Diagram *); void diagramRemoved(QETProject *, Diagram *); void readOnlyChanged(QETProject *, bool); + void projectTemplatesChanged(QETProject *); private slots: void updateDiagramsFolioData(); diff --git a/sources/templateeditor.cpp b/sources/templateeditor.cpp new file mode 100644 index 000000000..e6a42a9a2 --- /dev/null +++ b/sources/templateeditor.cpp @@ -0,0 +1,170 @@ +#include "templateeditor.h" +#include +#include "qetproject.h" +#include "qetapp.h" + +/** + Constructor + @param parent parent QWidget for this editor + @param f Windows flags for this editor + @see QWidget() +*/ +TemplateEditor::TemplateEditor(QWidget *parent, Qt::WindowFlags f) : + QWidget(parent, f), + parent_project_(0) +{ + build(); +} + +/** + Destructor +*/ +TemplateEditor::~TemplateEditor() { +} + +/** + Edit the given template. + @param project Parent project of the template to edit. + @param template_name Name of the template to edit within its parent project. +*/ +bool TemplateEditor::edit(QETProject *project, const QString &template_name) { + // we require a project we will rattach templates to + if (!project) return(false); + parent_project_ = project; + updateProjectLabel(); + + // the template name may be empty to create a new element + if (template_name.isEmpty()) { + template_name_edit_ -> setText(tr("Nouveau-modele")); + template_name_edit_ -> setReadOnly(false); + return(true); + } + + QDomElement xml_tb_template = project -> getTemplateXmlDescriptionByName(template_name); + if (!xml_tb_template.isNull()) { + QDomDocument xml_doc; + xml_doc.appendChild(xml_doc.importNode(xml_tb_template, true)); + template_name_edit_ -> setText(template_name); + template_name_edit_ -> setReadOnly(true); + template_xml_edit_ -> setPlainText(xml_doc.toString(4)); + + // stores the parent project and template name, in order to write/save the template later + template_name_ = template_name; + return(true); + } + return(false); +} + +/** + Validates the content of the current text area. It has to be a valid XML + description of a title block template for this method not to display a + message to the user. + @todo implement it. +*/ +void TemplateEditor::validate() { + QMessageBox::information( + this, + tr("Not implemented yet"), + tr("Sorry, Not implemented yet") + ); +} + +/** + Saves the content of the current text area to a template within the project. +*/ +void TemplateEditor::save() { + if (!parent_project_) return; + + // are we creating a new template? + if (!template_name_edit_ -> isReadOnly()) { + // Yes, so we must ensure the new name will not clatch with an existing ine + if (parent_project_ -> embeddedTitleBlockTemplates().contains(template_name_edit_ -> text())) { + QMessageBox::critical( + this, + tr("Un mod\350le de ce nom existe d\351j\340"), + tr("Un mod\350le de ce nom existe d\351j\340 au sein du projet - veuillez choisir un autre nom.") + ); + /// TODO propose to overwrite the existing template? + return; + } + + } + + QDomDocument xml_doc; + bool parsing = xml_doc.setContent(template_xml_edit_ -> toPlainText()); + if (!parsing) { + QMessageBox::critical( + this, + tr("Code XML non valide"), + tr("Le code XML du mod\350le ne semble pas \320tre valide. Impossible d'enregistrer le mod\350le.") + ); + return; + } + + if (!template_name_edit_ -> isReadOnly()) { + template_name_edit_ -> setReadOnly(true); + template_name_ = template_name_edit_ -> text(); + } + parent_project_ -> setTemplateXmlDescription(template_name_, xml_doc.documentElement()); +} + +/** + Exits this editor. +*/ +void TemplateEditor::quit() { + /// TODO save if needed + close(); +} + +/** + Builds the user interface. +*/ +void TemplateEditor::build() { + parent_project_label_ = new QLabel(); + updateProjectLabel(); + template_name_edit_ = new QLineEdit(); + template_xml_edit_ = new QTextEdit(); + template_xml_edit_ -> setAcceptRichText(false); + template_xml_edit_ -> setFontFamily("monospace"); + template_xml_edit_ -> setWordWrapMode(QTextOption::NoWrap); + + validate_button_ = new QPushButton(tr("V\351rifier le mod\350le")); + save_button_ = new QPushButton(tr("Enregistrer et appliquer")); + quit_button_ = new QPushButton(tr("Quitter")); + + connect(validate_button_, SIGNAL(released()), this, SLOT(validate())); + connect(save_button_, SIGNAL(released()), this, SLOT(save())); + connect(quit_button_, SIGNAL(released()), this, SLOT(quit())); + + QHBoxLayout *h_layout0 = new QHBoxLayout(); + h_layout0 -> addWidget(validate_button_); + h_layout0 -> addWidget(save_button_); + h_layout0 -> addWidget(quit_button_); + + QVBoxLayout *v_layout0 = new QVBoxLayout(); + v_layout0 -> addWidget(parent_project_label_); + v_layout0 -> addWidget(template_name_edit_); + v_layout0 -> addWidget(template_xml_edit_); + v_layout0 -> addLayout(h_layout0); + + setLayout(v_layout0); + + setWindowTitle(tr("QElectroTech - \311diteur de mod\350le de cartouche")); + resize(700, 500); +} + +/** + Updates the "Parent project:" label. +*/ +void TemplateEditor::updateProjectLabel() { + QString parent_project_title; + if (parent_project_) { + parent_project_title = parent_project_ -> pathNameTitle(); + } else { + parent_project_title = tr("Non d\351fini"); + } + + parent_project_label_ -> setText( + QString(tr("Projet parent : %1")).arg(parent_project_title) + ); +} diff --git a/sources/templateeditor.h b/sources/templateeditor.h new file mode 100644 index 000000000..10c755317 --- /dev/null +++ b/sources/templateeditor.h @@ -0,0 +1,60 @@ +/* + 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 . +*/ +#ifndef TEMPLATE_EDITOR_H +#define TEMPLATE_EDITOR_H +#include +class QETProject; +/** + This class allows the user to edit a title block template. + For the moment, it simply provides a text editor. +*/ +class TemplateEditor : public QWidget { + Q_OBJECT + + // constructors, destructor + public: + TemplateEditor(QWidget * = 0, Qt::WindowFlags = 0); + virtual ~TemplateEditor(); + private: + TemplateEditor(const TemplateEditor &); + + // method\s + public: + bool edit(QETProject *, const QString &); + + private slots: + void validate(); + void save(); + void quit(); + + private: + void build(); + void updateProjectLabel(); + + // attributes + private: + QLabel *parent_project_label_; + QLineEdit *template_name_edit_; + QTextEdit *template_xml_edit_; + QPushButton *validate_button_; + QPushButton *save_button_; + QPushButton *quit_button_; + QETProject *parent_project_; + QString template_name_; +}; +#endif diff --git a/sources/titleblocktemplate.cpp b/sources/titleblocktemplate.cpp index 74bdf1d4a..46a01fbce 100644 --- a/sources/titleblocktemplate.cpp +++ b/sources/titleblocktemplate.cpp @@ -486,7 +486,7 @@ void TitleBlockTemplate::render(QPainter &painter, const DiagramContext &diagram // run through each inidividual cell for (int j = 0 ; j < rows_heights_.count() ; ++ j) { for (int i = 0 ; i < columns_width_.count() ; ++ i) { - if (cells_[i][j].spanner_cell) continue; + if (cells_[i][j].spanner_cell || cells_[i][j].is_null) continue; // calculate the border rect of the current cell int x = lengthRange(0, cells_[i][j].num_col, widths); diff --git a/sources/titleblocktemplaterenderer.h b/sources/titleblocktemplaterenderer.h index 2f84c1180..7ac0c7e15 100644 --- a/sources/titleblocktemplaterenderer.h +++ b/sources/titleblocktemplaterenderer.h @@ -31,10 +31,10 @@ class TitleBlockTemplateRenderer : public QObject { void setContext(const DiagramContext &context); int height() const; void render(QPainter *, int); + void invalidateRenderedTemplate(); private: void renderToQPicture(int); - void invalidateRenderedTemplate(); private: const TitleBlockTemplate *titleblock_template_;