diff --git a/qelectrotech.pro b/qelectrotech.pro index 60494adf1..37c2ab303 100644 --- a/qelectrotech.pro +++ b/qelectrotech.pro @@ -9,6 +9,7 @@ unix { INSTALL_PREFIX = '/usr/local/' QET_BINARY_PATH = 'bin/' QET_COMMON_COLLECTION_PATH = 'share/qelectrotech/elements/' + QET_COMMON_TBT_PATH = 'share/qelectrotech/titleblocks/' QET_LANG_PATH = 'share/qelectrotech/lang/' QET_EXAMPLES_PATH = 'share/qelectrotech/examples/' QET_LICENSE_PATH = 'doc/qelectrotech/' @@ -25,6 +26,7 @@ win32 { INSTALL_PREFIX = './' QET_BINARY_PATH = './' QET_COMMON_COLLECTION_PATH = 'elements/' + QET_COMMON_TBT_PATH = 'titleblocks/' QET_LANG_PATH = 'lang/' QET_LICENSE_PATH = './' } @@ -34,6 +36,7 @@ macx { INSTALL_PREFIX = '/usr/local/' QET_BINARY_PATH = 'bin/' QET_COMMON_COLLECTION_PATH = '../Resources/elements/' + QET_COMMON_TBT_PATH = '../Resources/titleblocks/' QET_LANG_PATH = '../Resources/lang/' QET_EXAMPLES_PATH = 'share/qelectrotech/examples/' QET_LICENSE_PATH = 'doc/qelectrotech/' @@ -47,6 +50,9 @@ macx { # Commenter la ligne ci-dessous pour desactiver l'option --common-elements-dir DEFINES += QET_ALLOW_OVERRIDE_CED_OPTION +# Comment the line below to disable the --common-tbt-dir option +DEFINES += QET_ALLOW_OVERRIDE_CTBTD_OPTION + # Commenter la ligne ci-dessous pour desactiver l'option --config-dir DEFINES += QET_ALLOW_OVERRIDE_CD_OPTION @@ -88,6 +94,9 @@ target.path = $$join(INSTALL_PREFIX,,,$${QET_BINARY_PATH}) elements.path = $$join(INSTALL_PREFIX,,,$${QET_COMMON_COLLECTION_PATH}) elements.files = elements/* +tbt.path = $$join(INSTALL_PREFIX,,,$${QET_COMMON_TBT_PATH}) +tbt.files = titleblocks/* + lang.path = $$join(INSTALL_PREFIX,,,$${QET_LANG_PATH}) lang.files = $$replace(TRANSLATIONS, '.ts', '.qm') @@ -136,6 +145,8 @@ unix { # Chemin de la collection commune ; par defaut : elements/ dans le repertoire d'execution DEFINES += QET_COMMON_COLLECTION_PATH=$$join(COMPIL_PREFIX,,,$${QET_COMMON_COLLECTION_PATH}) + + DEFINES += QET_COMMON_TBT_PATH=$$join(COMPIL_PREFIX,,,$${QET_COMMON_TBT_PATH}) } # Options de compilation specifiques a MacOS X diff --git a/sources/elementspanel.cpp b/sources/elementspanel.cpp index 438555d1a..93214b1bd 100644 --- a/sources/elementspanel.cpp +++ b/sources/elementspanel.cpp @@ -25,6 +25,7 @@ #include "fileelementscollection.h" #include "fileelementdefinition.h" #include "qeticons.h" +#include "templatescollection.h" /** This class implements a thread reloading the following elements @@ -204,8 +205,12 @@ bool ElementsPanel::itemIsWritable(QTreeWidgetItem *qtwi) const { @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)); +bool ElementsPanel::itemIsATitleBlockTemplatesCollection(QTreeWidgetItem *qtwi) const { + return( + qtwi == custom_tbt_collection_item_ || + qtwi == common_tbt_collection_item_ || + title_blocks_collections_.contains(qtwi) + ); } /** @@ -213,9 +218,7 @@ bool ElementsPanel::itemIsATitleBlockTemplatesDirectory(QTreeWidgetItem *qtwi) c @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())); + return(title_blocks_.contains(qtwi)); } /** @@ -333,7 +336,7 @@ bool ElementsPanel::selectedItemIsWritable() const { templates directory */ bool ElementsPanel::selectedItemIsATitleBlockTemplatesDirectory() const { - return(itemIsATitleBlockTemplatesDirectory(currentItem())); + return(itemIsATitleBlockTemplatesCollection(currentItem())); } /** @@ -563,9 +566,9 @@ bool ElementsPanel::event(QEvent *event) { @return Le QTreeWidgetItem insere le plus haut */ QTreeWidgetItem *ElementsPanel::addProject(QTreeWidgetItem *qtwi_parent, QETProject *project) { - // le projet sera insere juste avant la collection commune + // the project will be inserted right before the common tb templates collection QTreeWidgetItem *last_project = 0; - if (int common_collection_item_idx = indexOfTopLevelItem(common_collection_item_)) { + if (int common_collection_item_idx = indexOfTopLevelItem(common_tbt_collection_item_)) { last_project = topLevelItem(common_collection_item_idx - 1); } @@ -584,14 +587,10 @@ 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 *)) - ); + // add the embedded title block templates collection + addTitleBlockTemplatesCollection(qtwi_project, project -> embeddedTitleBlockTemplatesCollection()); - // ajoute la collection du projet + // add the embedded elements collection addCollection(qtwi_project, project -> embeddedCollection(), tr("Collection projet")); return(qtwi_project); @@ -738,6 +737,64 @@ QTreeWidgetItem *ElementsPanel::addElement(QTreeWidgetItem *qtwi_parent, Element return(qtwi); } +/** + Adds \a collection under \a qtwi_parent with the given \a label and \a icon. + @param qtwi_parent Parent QTreeWidgetItem + @param collection Title block templates collection to be added to the panel + @param label Label for the returned QTreeWidgetItem + @param icon Label for the returned QTreeWidgetItem + @return the QTreeWidgetItem representing the collection +*/ +QTreeWidgetItem *ElementsPanel::addTitleBlockTemplatesCollection( + QTreeWidgetItem *qtwi_parent, + TitleBlockTemplatesCollection *collection, + const QString &label, + const QIcon &icon +) { + if (!collection) return(0); + + // check whether we have an item for the given collection + QTreeWidgetItem *qtwi_tbt_collection = title_blocks_collections_.key(collection); + if (!qtwi_tbt_collection) { + // the collection has not been added yet + QString final_label(label.isEmpty() ? tr("Mod\350les de cartouche") : label); + QIcon final_icon(icon.isNull() ? QET::Icons::TitleBlock : icon); + + // create the QTreeWidgetItem representing the collection itself + qtwi_tbt_collection = new QTreeWidgetItem(qtwi_parent, QStringList(final_label)); + qtwi_tbt_collection -> setIcon(0, final_icon); + qtwi_tbt_collection -> setToolTip(0, collection -> location().toString()); + qtwi_tbt_collection -> setExpanded(true); + title_blocks_collections_.insert(qtwi_tbt_collection, collection); + + // ensure the added collection will inform us about its changes + connect( + collection, + SIGNAL(changed(TitleBlockTemplatesCollection*, const QString &)), + this, + SLOT(titleBlockTemplatesCollectionChanged(TitleBlockTemplatesCollection*, const QString &)) + ); + } else { + // the collection has already been added + // remove the child title block templates + foreach(QTreeWidgetItem *qtwi_tbt, qtwi_tbt_collection -> takeChildren()) { + deleteItem(qtwi_tbt); + } + } + + // add the templates + foreach (QString template_name, collection -> templates()) { + QString final_name = titleBlockTemplateNameToDisplay(template_name); + TitleBlockTemplateLocation template_location = collection -> location(template_name); + + QTreeWidgetItem *qtwi_tbt = new QTreeWidgetItem(qtwi_tbt_collection, QStringList(final_name)); + qtwi_tbt -> setToolTip(0, template_location.toString()); + qtwi_tbt -> setIcon(0, QET::Icons::TitleBlock); + title_blocks_.insert(qtwi_tbt, template_location); + } + return(qtwi_tbt_collection); +} + /** Reloads the following collections: * common collection @@ -790,34 +847,49 @@ void ElementsPanel::reload(bool reload_collections) { locations_.clear(); projects_.clear(); diagrams_.clear(); - title_blocks_directories_.clear(); + title_blocks_collections_.clear(); + title_blocks_.clear(); common_collection_item_ = 0; custom_collection_item_ = 0; + QIcon system_icon(":/ico/16x16/qet.png"); + QIcon user_icon(":/ico/16x16/go-home.png"); + + // estimates the number of categories and elements to load int items_count = elementsCollectionItemsCount(); emit(loadingProgressed(loading_progress_ = 0, items_count)); + // load the common title block templates collection + TitleBlockTemplatesCollection *common_tbt_collection = QETApp::commonTitleBlockTemplatesCollection(); + common_tbt_collection_item_ = addTitleBlockTemplatesCollection(invisibleRootItem(), common_tbt_collection, common_tbt_collection -> title(), system_icon); + if (first_reload_) common_tbt_collection_item_ -> setExpanded(true); + // chargement des elements de la collection QET if (QETApp::commonElementsCollection()->rootCategory()) { - common_collection_item_ = addCollection(invisibleRootItem(), QETApp::commonElementsCollection(), tr("Collection QET"), QIcon(":/ico/16x16/qet.png")); + common_collection_item_ = addCollection(invisibleRootItem(), QETApp::commonElementsCollection(), tr("Collection QET"), system_icon); if (first_reload_) common_collection_item_ -> setExpanded(true); } + // load the custom title block templates collection + TitleBlockTemplatesCollection *custom_tbt_collection = QETApp::customTitleBlockTemplatesCollection(); + custom_tbt_collection_item_ = addTitleBlockTemplatesCollection(invisibleRootItem(), custom_tbt_collection, custom_tbt_collection -> title(), user_icon); + if (first_reload_) custom_tbt_collection_item_ -> setExpanded(true); + // chargement des elements de la collection utilisateur if (QETApp::customElementsCollection()->rootCategory()) { - custom_collection_item_ = addCollection(invisibleRootItem(), QETApp::customElementsCollection(), tr("Collection utilisateur"), QIcon(":/ico/16x16/go-home.png")); + custom_collection_item_ = addCollection(invisibleRootItem(), QETApp::customElementsCollection(), tr("Collection utilisateur"), user_icon); if (first_reload_) custom_collection_item_ -> setExpanded(true); } - // the first time, expand the first level of collections - if (first_reload_) first_reload_ = false; - // chargement des projets foreach(QETProject *project, projects_to_display_.values()) { addProject(invisibleRootItem(), project); } + // the first time, expand the first level of collections + if (first_reload_) first_reload_ = false; + // reselectionne le dernier element selectionne if (!last_selected_item.isNull()) { QTreeWidgetItem *qtwi = findLocation(last_selected_item); @@ -843,9 +915,7 @@ void ElementsPanel::slot_doubleClick(QTreeWidgetItem *qtwi, int) { } else if (ElementsCollectionItem *item = collectionItemForItem(qtwi)) { emit(requestForCollectionItem(item)); } else if (itemIsATitleBlockTemplate(qtwi)) { - if (QETProject *project = projectForTitleBlockTemplate(qtwi)) { - emit(requestForTitleBlockTemplate(project, nameOfTitleBlockTemplate(qtwi))); - } + emit(requestForTitleBlockTemplate(title_blocks_[qtwi])); } } @@ -899,8 +969,10 @@ 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); + } else if (title_blocks_collections_.contains(removed_item)) { + title_blocks_collections_.remove(removed_item); + } else if (title_blocks_.contains(removed_item)) { + title_blocks_.remove(removed_item); } // supprime les eventuels enfants de l'item @@ -928,27 +1000,18 @@ ElementsCategory *ElementsPanel::categoryForPos(const QPoint &pos) { } /** - @param qtwi A QTreeWidgetItem, supposed to represent a templates directory - @return the project that embeds the given templates directory, if - applicable, 0 otherwise + @param qtwi A QTreeWidgetItem, supposed to represent either a title block + @template or a title block templates collection. return the adequate title + @block template location */ -QETProject *ElementsPanel::projectForTitleBlockTemplatesDirectory(QTreeWidgetItem *qtwi) { - if (title_blocks_directories_.contains(qtwi)) { - return(title_blocks_directories_[qtwi]); +TitleBlockTemplateLocation ElementsPanel::locationForTitleBlockTemplate(QTreeWidgetItem *qtwi) { + if (title_blocks_.contains(qtwi)) { + // the QTreeWidgetItem is a title block template + return(title_blocks_[qtwi]); + } else if (title_blocks_collections_.contains(qtwi)) { + return(title_blocks_collections_[qtwi] -> location()); } - 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); + return(TitleBlockTemplateLocation()); } /** @@ -956,8 +1019,8 @@ QETProject *ElementsPanel::projectForTitleBlockTemplate(QTreeWidgetItem *qtwi) { @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()); + if (title_blocks_.contains(qtwi)) { + return(title_blocks_[qtwi].name()); } return(QString()); } @@ -1034,11 +1097,16 @@ void ElementsPanel::projectInformationsChanged(QETProject *project) { } /** - Handles the fact that the title block templates of a project changed. - @param project the modified project + @param collection Title block templates collection that changed and should be updated + @param template_name Name of the changed template (unused) */ -void ElementsPanel::projectTemplatesChanged(QETProject *project) { - updateProjectTemplates(project); +void ElementsPanel::titleBlockTemplatesCollectionChanged(TitleBlockTemplatesCollection*collection, const QString &template_name) { + Q_UNUSED(template_name) + + QTreeWidgetItem *qtwi_parent = title_blocks_collections_.key(collection); + if (!qtwi_parent) qtwi_parent = invisibleRootItem(); + + addTitleBlockTemplatesCollection(qtwi_parent, collection); } /** @@ -1156,7 +1224,7 @@ void ElementsPanel::updateProjectItemInformations(QETProject *project) { // determine le nom et l'icone du projet QString final_name(project -> pathNameTitle()); - QString final_tooltip = project -> filePath(); + QString final_tooltip = QDir::toNativeSeparators(project -> filePath()); if (final_tooltip.isEmpty()) { final_tooltip = tr( "Pas de fichier", @@ -1173,7 +1241,7 @@ void ElementsPanel::updateProjectItemInformations(QETProject *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) { +/*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; @@ -1194,13 +1262,18 @@ void ElementsPanel::updateProjectTemplates(QETProject *project) { } // 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 + TitleBlockTemplatesCollection *collection = project -> embeddedTitleBlockTemplatesCollection(); + if (!collection) { + // this stinks... + return; } -} + foreach (QString titleblock_name, collection -> templates()) { + QString final_name = titleBlockTemplateNameToDisplay(titleblock_name); + QTreeWidgetItem *titleblock_template_qtwi = new QTreeWidgetItem(titleblock_templates_qtwi, QStringList(final_name)); + titleblock_template_qtwi -> setIcon(0, QET::Icons::TitleBlock); + titleblocks_.insert(titleblock_template_qtwi, collection -> location(titleblock_name)); + } +}*/ /** Updates the label of a diagram displayed by the elements panel @@ -1245,6 +1318,14 @@ QString ElementsPanel::diagramTitleToDisplay(Diagram *diagram) const { return(displayed_label); } +/** + @param template_name Name of a title block template + @return a displayable title +*/ +QString ElementsPanel::titleBlockTemplateNameToDisplay(const QString &template_name) const { + return(tr("Mod\350le \"%1\"", "used to display a title block template").arg(template_name)); +} + /** @param items une liste de QTreeWidgetItem pour lesquels il faut s'assurer que eux et leurs parents sont visibles diff --git a/sources/elementspanel.h b/sources/elementspanel.h index e7a38e620..4e10d8eaa 100644 --- a/sources/elementspanel.h +++ b/sources/elementspanel.h @@ -19,6 +19,7 @@ #define PANELAPPAREILS_H #include #include "elementslocation.h" +#include "templatelocation.h" class QETProject; class Diagram; class ElementsCollection; @@ -26,6 +27,8 @@ class ElementsCollectionItem; class ElementsCategory; class ElementDefinition; class ElementsCollectionCache; +class TitleBlockTemplatesFilesCollection; + /** Cette classe represente le panel d'appareils (en tant qu'element graphique) dans lequel l'utilisateur choisit les composants de @@ -52,7 +55,7 @@ class ElementsPanel : public QTreeWidget { bool itemIsADiagram(QTreeWidgetItem *) const; bool itemHasLocation(QTreeWidgetItem *) const; bool itemIsWritable(QTreeWidgetItem *) const; - bool itemIsATitleBlockTemplatesDirectory(QTreeWidgetItem *) const; + bool itemIsATitleBlockTemplatesCollection(QTreeWidgetItem *) const; bool itemIsATitleBlockTemplate(QTreeWidgetItem *) const; // methodes pour obtenir ce que represente un item donne @@ -62,8 +65,7 @@ class ElementsPanel : public QTreeWidget { ElementsLocation locationForItem(QTreeWidgetItem *) const; ElementsCategory *categoryForItem(QTreeWidgetItem *); ElementsCategory *categoryForPos(const QPoint &); - QETProject *projectForTitleBlockTemplatesDirectory(QTreeWidgetItem *); - QETProject *projectForTitleBlockTemplate(QTreeWidgetItem *); + TitleBlockTemplateLocation locationForTitleBlockTemplate(QTreeWidgetItem *); QString nameOfTitleBlockTemplate(QTreeWidgetItem *); // methodes pour determiner ce que represente l'item selectionne @@ -91,7 +93,7 @@ class ElementsPanel : public QTreeWidget { void requestForDiagram(Diagram *); void requestForCollectionItem(ElementsCollectionItem *); void requestForMoveElements(ElementsCollectionItem *, ElementsCollectionItem *, QPoint); - void requestForTitleBlockTemplate(QETProject *, const QString &); + void requestForTitleBlockTemplate(const TitleBlockTemplateLocation &); void readingAboutToBegin(); void readingFinished(); void loadingProgressed(int, int); @@ -103,7 +105,7 @@ class ElementsPanel : public QTreeWidget { void projectWasOpened(QETProject *); void projectWasClosed(QETProject *); void projectInformationsChanged(QETProject *); - void projectTemplatesChanged(QETProject *); + void titleBlockTemplatesCollectionChanged(TitleBlockTemplatesCollection*, const QString & = QString()); void diagramWasAdded(QETProject *, Diagram *); void diagramWasRemoved(QETProject *, Diagram *); void diagramTitleChanged(QETProject *, Diagram *); @@ -123,14 +125,15 @@ class ElementsPanel : public QTreeWidget { QTreeWidgetItem *addCollection(QTreeWidgetItem *, ElementsCollection *, const QString & = QString(), const QIcon & = QIcon()); QTreeWidgetItem *addCategory (QTreeWidgetItem *, ElementsCategory *, const QString & = QString(), const QIcon & = QIcon()); QTreeWidgetItem *addElement (QTreeWidgetItem *, ElementDefinition *, const QString & = QString()); + QTreeWidgetItem *addTitleBlockTemplatesCollection(QTreeWidgetItem *, TitleBlockTemplatesCollection *, const QString & = QString(), const QIcon & = QIcon()); void saveExpandedCategories(); QTreeWidgetItem *findLocation(const ElementsLocation &) const; QTreeWidgetItem *findLocation(const QString &) const; void deleteItem(QTreeWidgetItem *); void updateProjectItemInformations(QETProject *); - void updateProjectTemplates(QETProject *); void updateDiagramLabel(QTreeWidgetItem *, int); QString diagramTitleToDisplay(Diagram *) const; + QString titleBlockTemplateNameToDisplay(const QString &) const; void ensureHierarchyIsVisible(QList); // attributs @@ -138,12 +141,15 @@ class ElementsPanel : public QTreeWidget { QStringList expanded_directories; QString last_selected_item; QHash locations_; + QHash title_blocks_; QSet projects_to_display_; QHash projects_; QHash diagrams_; - QHash title_blocks_directories_; + QHash title_blocks_collections_; QTreeWidgetItem *common_collection_item_; + QTreeWidgetItem *common_tbt_collection_item_; QTreeWidgetItem *custom_collection_item_; + QTreeWidgetItem *custom_tbt_collection_item_; int loading_progress_; bool first_activation_; bool first_reload_; diff --git a/sources/elementspanelwidget.cpp b/sources/elementspanelwidget.cpp index 003f41023..e34918f22 100644 --- a/sources/elementspanelwidget.cpp +++ b/sources/elementspanelwidget.cpp @@ -131,9 +131,9 @@ ElementsPanelWidget::ElementsPanelWidget(QWidget *parent) : QWidget(parent) { ); connect( elements_panel, - SIGNAL(requestForTitleBlockTemplate(QETProject *, const QString &)), + SIGNAL(requestForTitleBlockTemplate(const TitleBlockTemplateLocation &)), QETApp::instance(), - SLOT(openTitleBlockTemplate(QETProject *, const QString &)) + SLOT(openTitleBlockTemplate(const TitleBlockTemplateLocation &)) ); connect(elements_panel, SIGNAL(loadingProgressed(int, int)), this, SLOT(updateProgressBar(int, int))); connect(elements_panel, SIGNAL(readingAboutToBegin()), this, SLOT(collectionsRead())); @@ -263,15 +263,9 @@ 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); + if (elements_panel -> itemIsATitleBlockTemplatesCollection(current_item)) { + TitleBlockTemplateLocation location = elements_panel -> locationForTitleBlockTemplate(current_item); + QETApp::instance() -> openTitleBlockTemplate(location); } } @@ -281,9 +275,7 @@ void ElementsPanelWidget::addTitleBlockTemplate() { 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); + QETApp::instance() -> openTitleBlockTemplate(elements_panel -> locationForTitleBlockTemplate(current_item)); } } @@ -293,11 +285,10 @@ void ElementsPanelWidget::editTitleBlockTemplate() { 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); - TitleBlockTemplateLocation template_location(parent_project, template_name); - TitleBlockTemplateDeleter template_deleter(template_location, this); - template_deleter.exec(); + TitleBlockTemplateDeleter( + elements_panel -> locationForTitleBlockTemplate(current_item), + this + ).exec(); } } @@ -380,14 +371,19 @@ void ElementsPanelWidget::updateButtons() { prj_move_diagram_up -> setEnabled(is_writable && diagram_position > 0); prj_move_diagram_down -> setEnabled(is_writable && diagram_position < project_diagrams_count - 1); setElementsActionEnabled(false); - } else if (elements_panel -> selectedItemIsATitleBlockTemplatesDirectory()) { - bool is_writable = !(elements_panel -> projectForTitleBlockTemplatesDirectory(elements_panel -> currentItem()) -> isReadOnly()); - tbt_add -> setEnabled(is_writable); - setElementsActionEnabled(false); - } else if (elements_panel -> selectedItemIsATitleBlockTemplate()) { - bool is_writable = !(elements_panel -> projectForTitleBlockTemplate(elements_panel -> currentItem()) -> isReadOnly()); - tbt_edit -> setEnabled(is_writable); - tbt_remove -> setEnabled(is_writable); + } else if ( + elements_panel -> selectedItemIsATitleBlockTemplatesDirectory() || + elements_panel -> selectedItemIsATitleBlockTemplate() + ) { + QTreeWidgetItem *item = elements_panel -> currentItem(); + TitleBlockTemplateLocation location = elements_panel -> locationForTitleBlockTemplate(item); + bool is_writable; + if (location.isValid()) { + is_writable = !location.parentCollection() -> isReadOnly(); + tbt_add -> setEnabled(is_writable); + tbt_edit -> setEnabled(is_writable); + tbt_remove -> setEnabled(is_writable); + } setElementsActionEnabled(false); } } @@ -474,7 +470,7 @@ 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)) { + } else if (elements_panel -> itemIsATitleBlockTemplatesCollection(item)) { context_menu -> addAction(tbt_add); } else if (elements_panel -> itemIsATitleBlockTemplate(item)) { context_menu -> addAction(tbt_edit); diff --git a/sources/qetapp.cpp b/sources/qetapp.cpp index fc5c5c9e6..a4dddc913 100644 --- a/sources/qetapp.cpp +++ b/sources/qetapp.cpp @@ -29,6 +29,7 @@ #include "qtextorientationspinboxwidget.h" #include "recentfiles.h" #include "qeticons.h" +#include "templatescollection.h" #include #include #define QUOTE(x) STRINGIFY(x) @@ -37,12 +38,17 @@ #ifdef QET_ALLOW_OVERRIDE_CED_OPTION QString QETApp::common_elements_dir = QString(); #endif +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION +QString QETApp::common_tbt_dir_ = QString(); +#endif #ifdef QET_ALLOW_OVERRIDE_CD_OPTION QString QETApp::config_dir = QString(); #endif QString QETApp::lang_dir = QString(); FileElementsCollection *QETApp::common_collection = 0; FileElementsCollection *QETApp::custom_collection = 0; +TitleBlockTemplatesFilesCollection *QETApp::common_tbt_collection_; +TitleBlockTemplatesFilesCollection *QETApp::custom_tbt_collection_; ElementsCollectionCache *QETApp::collections_cache_ = 0; QMap QETApp::registered_projects_ = QMap(); uint QETApp::next_project_id = 0; @@ -131,6 +137,8 @@ QETApp::~QETApp() { delete qsti; delete custom_collection; delete common_collection; + if (custom_tbt_collection_) delete custom_tbt_collection_; + if (common_tbt_collection_) delete common_tbt_collection_; } /** @@ -288,6 +296,49 @@ QList QETApp::availableCollections() { return(coll_list); } +/** + @return the common title block templates collection, i.e. the one provided + by QElecrotTech +*/ +TitleBlockTemplatesFilesCollection *QETApp::commonTitleBlockTemplatesCollection() { + if (!common_tbt_collection_) { + common_tbt_collection_ = new TitleBlockTemplatesFilesCollection(QETApp::commonTitleBlockTemplatesDir()); + common_tbt_collection_ -> setTitle(tr("Cartouches QET", "title of the title block templates collection provided by QElectroTech")); + common_tbt_collection_ -> setProtocol("commontbt"); + } + return(common_tbt_collection_); +} + +/** + @return the custom title block templates collection, i.e. the one managed + by the end user +*/ +TitleBlockTemplatesFilesCollection *QETApp::customTitleBlockTemplatesCollection() { + if (!custom_tbt_collection_) { + custom_tbt_collection_ = new TitleBlockTemplatesFilesCollection(QETApp::customTitleBlockTemplatesDir()); + custom_tbt_collection_ -> setTitle(tr("Cartouches utilisateur", "title of the user's title block templates collection")); + custom_tbt_collection_ -> setProtocol("customtbt"); + } + return(custom_tbt_collection_); +} + +/** + @return the list of all available title block tempaltes collections, + beginning with the common and custom ones, plus the projects-embedded ones. +*/ +QList QETApp::availableTitleBlockTemplatesCollections() { + QList collections_list; + + collections_list << common_tbt_collection_; + collections_list << custom_tbt_collection_; + + foreach(QETProject *opened_project, registered_projects_) { + collections_list << opened_project -> embeddedTitleBlockTemplatesCollection(); + } + + return(collections_list); +} + /** @return le nom de l'utilisateur courant */ @@ -332,6 +383,36 @@ QString QETApp::customElementsDir() { return(configDir() + "elements/"); } +/** + @return the path of the directory containing the common title block + templates collection. +*/ +QString QETApp::commonTitleBlockTemplatesDir() { +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION + if (common_tbt_dir_ != QString()) return(common_tbt_dir_); +#endif +#ifndef QET_COMMON_TBT_PATH + // without any compile-time option, use the "titleblocks" directory next to the executable binary + return(QCoreApplication::applicationDirPath() + "/titleblocks/"); +#else + #ifndef QET_COMMON_COLLECTION_PATH_RELATIVE_TO_BINARY_PATH + // the compile-time option represents a usual path (be it absolute or relative) + return(QUOTE(QET_COMMON_TBT_PATH)); + #else + // the compile-time option represents a path relative to the directory that contains the executable binary + return(QCoreApplication::applicationDirPath() + "/" + QUOTE(QET_COMMON_TBT_PATH)); + #endif +#endif +} + +/** + @return the path of the directory containing the custom title block + templates collection. +*/ +QString QETApp::customTitleBlockTemplatesDir() { + return(configDir() + "titleblocks/"); +} + /** Renvoie le dossier de configuration de QET, c-a-d le chemin du dossier dans lequel QET lira les informations de configuration et de personnalisation @@ -371,6 +452,10 @@ QString QETApp::realPath(const QString &sym_path) { directory = commonElementsDir(); } else if (sym_path.startsWith("custom://")) { directory = customElementsDir(); + } else if (sym_path.startsWith("commontbt://")) { + directory = commonTitleBlockTemplatesDir(); + } else if (sym_path.startsWith("customtbt://")) { + directory = customTitleBlockTemplatesDir(); } else return(QString()); return(directory + QDir::toNativeSeparators(sym_path.right(sym_path.length() - 9))); } @@ -429,6 +514,20 @@ void QETApp::overrideCommonElementsDir(const QString &new_ced) { } #endif +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION +/** + Define the path of the directory containing the common title block + tempaltes collection. +*/ +void QETApp::overrideCommonTitleBlockTemplatesDir(const QString &new_ctbtd) { + QFileInfo new_ctbtd_info(new_ctbtd); + if (new_ctbtd_info.isDir()) { + common_tbt_dir_ = new_ctbtd_info.absoluteFilePath(); + if (!common_tbt_dir_.endsWith("/")) common_tbt_dir_ += "/"; + } +} +#endif + #ifdef QET_ALLOW_OVERRIDE_CD_OPTION /** Redefinit le chemin du dossier de configuration @@ -556,10 +655,7 @@ QList QETApp::titleBlockTemplateEditors(QETProjec // foreach known template editor foreach (QETTitleBlockTemplateEditor *tbt_editor, titleBlockTemplateEditors()) { - // retrieve the location of the currently edited template - TitleBlockTemplateLocation tbt_editor_loc(tbt_editor -> location()); - - if (tbt_editor_loc.project() == project) { + if (tbt_editor -> location().parentProject() == project) { editors << tbt_editor; } } @@ -903,9 +999,9 @@ void QETApp::openElementLocations(const QList &locations_list) 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) { +void QETApp::openTitleBlockTemplate(const TitleBlockTemplateLocation &location) { QETTitleBlockTemplateEditor *qet_template_editor = new QETTitleBlockTemplateEditor(); - qet_template_editor -> edit(project, template_name); + qet_template_editor -> edit(location); qet_template_editor -> showMaximized(); } @@ -1004,6 +1100,11 @@ void QETApp::parseArguments() { overrideCommonElementsDir(qet_arguments_.commonElementsDir()); } #endif +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION + if (qet_arguments_.commonTitleBlockTemplatesDirSpecified()) { + overrideCommonTitleBlockTemplatesDir(qet_arguments_.commonTitleBlockTemplatesDir()); + } +#endif #ifdef QET_ALLOW_OVERRIDE_CD_OPTION if (qet_arguments_.configDirSpecified()) { overrideConfigDir(qet_arguments_.configDir()); @@ -1081,6 +1182,7 @@ void QETApp::initStyle() { Cette methode creera, si necessaire : * le dossier de configuration * le dossier de la collection perso + * the directory for custom title blocks */ void QETApp::initConfiguration() { // cree les dossiers de configuration si necessaire @@ -1090,6 +1192,9 @@ void QETApp::initConfiguration() { QDir custom_elements_dir(QETApp::customElementsDir()); if (!custom_elements_dir.exists()) custom_elements_dir.mkpath(QETApp::customElementsDir()); + QDir custom_tbt_dir(QETApp::customTitleBlockTemplatesDir()); + if (!custom_tbt_dir.exists()) custom_tbt_dir.mkpath(QETApp::customTitleBlockTemplatesDir()); + // lit le fichier de configuration qet_settings = new QSettings(configDir() + "qelectrotech.conf", QSettings::IniFormat, this); @@ -1271,6 +1376,9 @@ void QETApp::printHelp() { #ifdef QET_ALLOW_OVERRIDE_CED_OPTION + tr(" --common-elements-dir=DIR Definir le dossier de la collection d'elements\n") #endif +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION + + tr(" --common-tbt-dir=DIR Definir le dossier de la collection de modeles de cartouches\n") +#endif #ifdef QET_ALLOW_OVERRIDE_CD_OPTION + tr(" --config-dir=DIR Definir le dossier de configuration\n") #endif diff --git a/sources/qetapp.h b/sources/qetapp.h index f2d0437ea..ec8f5378e 100644 --- a/sources/qetapp.h +++ b/sources/qetapp.h @@ -21,6 +21,7 @@ #include #include #include "elementslocation.h" +#include "templatelocation.h" #include "qetarguments.h" class AboutQET; class QETDiagramEditor; @@ -32,6 +33,8 @@ class FileElementsCollection; class ElementsCategory; class ElementDefinition; class TitleBlockTemplate; +class TitleBlockTemplatesCollection; +class TitleBlockTemplatesFilesCollection; class QETProject; class QETTitleBlockTemplateEditor; class QTextOrientationSpinBoxWidget; @@ -65,9 +68,15 @@ class QETApp : public QETSingleApplication { static ElementsCollection *customElementsCollection(); static QList availableCollections(); + static TitleBlockTemplatesFilesCollection *commonTitleBlockTemplatesCollection(); + static TitleBlockTemplatesFilesCollection *customTitleBlockTemplatesCollection(); + static QList availableTitleBlockTemplatesCollections(); + static QString userName(); static QString commonElementsDir(); static QString customElementsDir(); + static QString commonTitleBlockTemplatesDir(); + static QString customTitleBlockTemplatesDir(); static bool registerProject(QETProject *); static bool unregisterProject(QETProject *); static QMap registeredProjects(); @@ -86,6 +95,12 @@ class QETApp : public QETSingleApplication { private: static QString common_elements_dir; ///< Dossier contenant la collection d'elements commune #endif +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION + public: + static void overrideCommonTitleBlockTemplatesDir(const QString &); + private: + static QString common_tbt_dir_; ///< Directory containing the common title block templates collection +#endif #ifdef QET_ALLOW_OVERRIDE_CD_OPTION public: static void overrideConfigDir(const QString &); @@ -145,6 +160,8 @@ class QETApp : public QETSingleApplication { static FileElementsCollection *common_collection; static FileElementsCollection *custom_collection; + static TitleBlockTemplatesFilesCollection *common_tbt_collection_; + static TitleBlockTemplatesFilesCollection *custom_tbt_collection_; static ElementsCollectionCache *collections_cache_; static QMap registered_projects_; static uint next_project_id; @@ -176,7 +193,7 @@ class QETApp : public QETSingleApplication { void openProjectFiles(const QStringList &); void openElementFiles(const QStringList &); void openElementLocations(const QList &); - void openTitleBlockTemplate(QETProject *, const QString & = QString()); + void openTitleBlockTemplate(const TitleBlockTemplateLocation &); void configureQET(); void aboutQET(); diff --git a/sources/qetarguments.cpp b/sources/qetarguments.cpp index be0a501eb..f25933a04 100644 --- a/sources/qetarguments.cpp +++ b/sources/qetarguments.cpp @@ -56,6 +56,9 @@ QETArguments::QETArguments(const QETArguments &qet_arguments) : #ifdef QET_ALLOW_OVERRIDE_CED_OPTION common_elements_dir_(qet_arguments.common_elements_dir_), #endif +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION +common_tbt_dir_(qet_arguments.common_tbt_dir_), +#endif #ifdef QET_ALLOW_OVERRIDE_CD_OPTION config_dir_(qet_arguments.config_dir_), #endif @@ -78,6 +81,9 @@ QETArguments &QETArguments::operator=(const QETArguments &qet_arguments) { #ifdef QET_ALLOW_OVERRIDE_CED_OPTION common_elements_dir_ = qet_arguments.common_elements_dir_; #endif +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION + common_tbt_dir_ = qet_arguments.common_tbt_dir_; +#endif #ifdef QET_ALLOW_OVERRIDE_CD_OPTION config_dir_ = qet_arguments.config_dir_; #endif @@ -159,6 +165,9 @@ void QETArguments::clear() { #ifdef QET_ALLOW_OVERRIDE_CED_OPTION common_elements_dir_.clear(); #endif +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION + common_tbt_dir_.clear(); +#endif #ifdef QET_ALLOW_OVERRIDE_CD_OPTION config_dir_.clear(); #endif @@ -205,6 +214,7 @@ void QETArguments::handleFileArgument(const QString &file) { Gere les arguments correspondant potentiellement a une option. Les options reconnues sont : * --common-elements-dir= + * --common-tbt-dir * --config-dir= * --lang-dir= * --help @@ -235,6 +245,13 @@ void QETArguments::handleOptionArgument(const QString &option) { } #endif +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION + QString ctbtd_arg("--common-tbt-dir="); + if (option.startsWith(ctbtd_arg)) { + common_tbt_dir_ = option.mid(ctbtd_arg.length()); + return; + } +#endif #ifdef QET_ALLOW_OVERRIDE_CD_OPTION QString cd_arg("--config-dir="); if (option.startsWith(cd_arg)) { @@ -270,8 +287,26 @@ bool QETArguments::commonElementsDirSpecified() const { QString QETArguments::commonElementsDir() const { return(common_elements_dir_); } - #endif + +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION +/** + @return true if the user has specified a directory for the common title + block templates collection +*/ +bool QETArguments::commonTitleBlockTemplatesDirSpecified() const { + return(!common_tbt_dir_.isEmpty()); +} + +/** + @return the directory of the common title block templates collection + specified by the user. If none were specified, return an empty string. +*/ +QString QETArguments::commonTitleBlockTemplatesDir() const { + return(common_tbt_dir_); +} +#endif + #ifdef QET_ALLOW_OVERRIDE_CD_OPTION /** @return true si l'utilisateur a specifie un dossier pour la configuration. diff --git a/sources/qetarguments.h b/sources/qetarguments.h index a83d2888e..c051d3b11 100644 --- a/sources/qetarguments.h +++ b/sources/qetarguments.h @@ -46,6 +46,10 @@ class QETArguments : public QObject { virtual bool commonElementsDirSpecified() const; virtual QString commonElementsDir() const; #endif +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION + virtual bool commonTitleBlockTemplatesDirSpecified() const; + virtual QString commonTitleBlockTemplatesDir() const; +#endif #ifdef QET_ALLOW_OVERRIDE_CD_OPTION virtual bool configDirSpecified() const; virtual QString configDir() const; @@ -73,6 +77,9 @@ class QETArguments : public QObject { #ifdef QET_ALLOW_OVERRIDE_CED_OPTION QString common_elements_dir_; #endif +#ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION + QString common_tbt_dir_; +#endif #ifdef QET_ALLOW_OVERRIDE_CD_OPTION QString config_dir_; #endif diff --git a/sources/qetproject.cpp b/sources/qetproject.cpp index a6cc50fa2..d3dcc0b6b 100644 --- a/sources/qetproject.cpp +++ b/sources/qetproject.cpp @@ -39,7 +39,8 @@ QETProject::QETProject(int diagrams, QObject *parent) : QObject(parent), collection_(0), project_qet_version_(-1), - read_only_(false) + read_only_(false), + titleblocks_(this) { // 0 a n schema(s) vide(s) int diagrams_count = qMax(0, diagrams); @@ -55,6 +56,7 @@ QETProject::QETProject(int diagrams, QObject *parent) : // une categorie dediee aux elements integres automatiquement ensureIntegrationCategoryExists(); + setupTitleBlockTemplatesCollection(); } /** @@ -66,7 +68,8 @@ QETProject::QETProject(const QString &path, QObject *parent) : QObject(parent), collection_(0), project_qet_version_(-1), - read_only_(false) + read_only_(false), + titleblocks_(this) { // ouvre le fichier QFile project_file(path); @@ -86,6 +89,8 @@ QETProject::QETProject(const QString &path, QObject *parent) : // et construit le projet readProjectXml(); + setupTitleBlockTemplatesCollection(); + // passe le projet en lecture seule si le fichier l'est QFileInfo project_file_info(path); if (!project_file_info.isWritable()) { @@ -101,13 +106,16 @@ QETProject::QETProject(const QDomElement &xml_element, QObject *parent) : QObject(parent), collection_(0), project_qet_version_(-1), - read_only_(false) + read_only_(false), + titleblocks_(this) { // copie le contenu XML document_root_.appendChild(document_root_.importNode(xml_element, true)); // et construit le projet readProjectXml(); + + setupTitleBlockTemplatesCollection(); } /** @@ -166,6 +174,13 @@ ElementsCollection *QETProject::embeddedCollection() const { return(collection_); } +/** + @return the title block templates collection enbeedded within this project +*/ +TitleBlockTemplatesProjectCollection *QETProject::embeddedTitleBlockTemplatesCollection() { + return(&titleblocks_); +} + /** @return le chemin du fichier dans lequel ce projet est enregistre */ @@ -286,8 +301,8 @@ void QETProject::setTitle(const QString &title) { /** @return the list of the titleblock templates embedded within this project */ -QList QETProject::embeddedTitleBlockTemplates() const { - return(titleblock_templates_xml_.keys()); +QList QETProject::embeddedTitleBlockTemplates() { + return(titleblocks_.templates()); } /** @@ -296,24 +311,7 @@ QList QETProject::embeddedTitleBlockTemplates() const { name within the project */ const TitleBlockTemplate *QETProject::getTemplateByName(const QString &template_name) { - // Do we have already loaded this template? - if (titleblock_templates_.contains(template_name)) { - return(titleblock_templates_[template_name]); - } - - // No? Do we even know of it? - if (!titleblock_templates_xml_.contains(template_name)) { - return(0); - } - - // Ok, we have its XML description, we have to generate an TitleBlockTemplate object - TitleBlockTemplate *titleblock_template = new TitleBlockTemplate(this); - if (titleblock_template -> loadFromXmlElement(titleblock_templates_xml_[template_name])) { - titleblock_templates_.insert(template_name, titleblock_template); - return(titleblock_template); - } else { - return(0); - } + return(titleblocks_.getTemplate(template_name)); } /** @@ -322,16 +320,12 @@ const TitleBlockTemplate *QETProject::getTemplateByName(const QString &template_ if the project does not have such an titleblock template */ QDomElement QETProject::getTemplateXmlDescriptionByName(const QString &template_name) { - if (titleblock_templates_xml_.contains(template_name)) { - return(titleblock_templates_xml_[template_name]); - } - return(QDomElement()); + return(titleblocks_.getTemplateXmlDescription(template_name)); } /** This methods allows adding or modifying a template embedded within the - project. This method emits the signal projectTemplatesChanged() if - necessary. + project. @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. @@ -340,53 +334,15 @@ QDomElement QETProject::getTemplateXmlDescriptionByName(const QString &template_ @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_.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); + return(titleblocks_.setTemplateXmlDescription(template_name, xml_elmt)); } /** - This methods allows removing a template embedded within the project. This - method emits the signal projectTemplatesChanged() if necessary. + This methods allows removing a template embedded within the project. @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(titleblocks_.removeTemplate(template_name)); } /** @@ -451,11 +407,11 @@ QDomDocument QETProject::toXml() { xml_doc.appendChild(project_root); // titleblock templates, if any - if (titleblock_templates_xml_.count()) { - qDebug() << qPrintable(QString("QETProject::toXml() : exporting %1 titleblock templates").arg(titleblock_templates_xml_.count())); + if (titleblocks_.templates().count()) { QDomElement titleblocktemplates_elmt = xml_doc.createElement("titleblocktemplates"); - foreach (QDomElement e, titleblock_templates_xml_) { - titleblocktemplates_elmt.appendChild(e); + foreach (QString template_name, titleblocks_.templates()) { + QDomElement e = titleblocks_.getTemplateXmlDescription(template_name); + titleblocktemplates_elmt.appendChild(xml_doc.importNode(e, true)); } project_root.appendChild(titleblocktemplates_elmt); } @@ -818,6 +774,25 @@ void QETProject::diagramOrderChanged(int old_index, int new_index) { updateDiagramsFolioData(); } +/** + Set up signals/slots connections related to the title block templates + collection. +*/ +void QETProject::setupTitleBlockTemplatesCollection() { + connect( + &titleblocks_, + SIGNAL(changed(TitleBlockTemplatesCollection *, const QString &)), + this, + SLOT(updateDiagramsTitleBlockTemplate(TitleBlockTemplatesCollection *, const QString &)) + ); + connect( + &titleblocks_, + SIGNAL(aboutToRemove(TitleBlockTemplatesCollection *, const QString &)), + this, + SLOT(removeDiagramsTitleBlockTemplate(TitleBlockTemplatesCollection *, const QString &)) + ); +} + /** @return un pointeur vers la categorie racine de la collection embarquee, ou 0 si celle-ci n'est pas accessible. @@ -923,18 +898,7 @@ void QETProject::readDiagramsXml() { Loads the embedded template from the XML description of the project */ void QETProject::readEmbeddedTemplatesXml() { - foreach (QDomElement e, QET::findInDomElement(document_root_.documentElement(), "titleblocktemplates", "titleblocktemplate")) { - // each titleblock template must have a name - if (!e.hasAttribute("name")) continue; - QString titleblock_template_name = e.attribute("name"); - - // if several templates have the same name, we keep the first one encountered - if (titleblock_templates_xml_.contains(titleblock_template_name)) continue; - - // we simply store the XML element describing the titleblock template, - // without any further analysis for the moment - titleblock_templates_xml_.insert(titleblock_template_name, e); - } + titleblocks_.fromXml(document_root_.documentElement()); } /** @@ -1148,6 +1112,33 @@ void QETProject::updateDiagramsFolioData() { } } +/** + Inform each diagram that the \a template_name title block changed. + @param collection Title block templates collection + @param template_name Name of the changed template +*/ +void QETProject::updateDiagramsTitleBlockTemplate(TitleBlockTemplatesCollection *collection, const QString &template_name) { + Q_UNUSED(collection) + + foreach (Diagram *diagram, diagrams_) { + diagram -> titleBlockTemplateChanged(template_name); + } +} + +/** + Inform each diagram that the \a template_name title block is about to be removed. + @param collection Title block templates collection + @param template_name Name of the removed template +*/ +void QETProject::removeDiagramsTitleBlockTemplate(TitleBlockTemplatesCollection *collection, const QString &template_name) { + Q_UNUSED(collection) + + // warn diagrams that the given template is about to be removed + foreach (Diagram *diagram, diagrams_) { + diagram -> titleBlockTemplateRemoved(template_name); + } +} + /** Copie l'element integ_elmt dans la categorie target_cat en utilisant le gestionnaire handler ; en cas d'erreur, error_message est rempli. diff --git a/sources/qetproject.h b/sources/qetproject.h index 2cfbd7d3f..8b47766cf 100644 --- a/sources/qetproject.h +++ b/sources/qetproject.h @@ -24,6 +24,7 @@ #include "borderproperties.h" #include "conductorproperties.h" #include "titleblockproperties.h" +#include "templatescollection.h" class Diagram; class ElementsCollection; class ElementsCategory; @@ -75,6 +76,7 @@ class QETProject : public QObject { QList diagrams() const; int folioIndex(const Diagram *) const; ElementsCollection *embeddedCollection() const; + TitleBlockTemplatesProjectCollection *embeddedTitleBlockTemplatesCollection(); QString filePath(); void setFilePath(const QString &); QString currentDir() const; @@ -82,7 +84,7 @@ class QETProject : public QObject { QString title() const; qreal declaredQElectroTechVersion(); void setTitle(const QString &); - QList embeddedTitleBlockTemplates() const; + QList embeddedTitleBlockTemplates(); const TitleBlockTemplate *getTemplateByName(const QString &template_name); QDomElement getTemplateXmlDescriptionByName(const QString &); bool setTemplateXmlDescription(const QString &, const QDomElement &); @@ -123,12 +125,14 @@ class QETProject : public QObject { void diagramAdded(QETProject *, Diagram *); void diagramRemoved(QETProject *, Diagram *); void readOnlyChanged(QETProject *, bool); - void projectTemplatesChanged(QETProject *); private slots: void updateDiagramsFolioData(); + void updateDiagramsTitleBlockTemplate(TitleBlockTemplatesCollection *, const QString &); + void removeDiagramsTitleBlockTemplate(TitleBlockTemplatesCollection *, const QString &); private: + void setupTitleBlockTemplatesCollection(); ElementsCategory *rootCategory() const; void readProjectXml(); void readDiagramsXml(); @@ -168,9 +172,7 @@ class QETProject : public QObject { ConductorProperties default_conductor_properties_; /// Proprietes par defaut du cartouche pour les nouveaux schemas dans ce projet TitleBlockProperties default_titleblock_properties_; - /// XML descriptions of embedded titleblock templates - QHash titleblock_templates_xml_; - /// Already parsed embedded titleblock templates - QHash titleblock_templates_; + /// Embedded title block templates collection + TitleBlockTemplatesProjectCollection titleblocks_; }; #endif diff --git a/sources/titleblock/qettemplateeditor.cpp b/sources/titleblock/qettemplateeditor.cpp index fb306f1fa..a5ccc39d4 100644 --- a/sources/titleblock/qettemplateeditor.cpp +++ b/sources/titleblock/qettemplateeditor.cpp @@ -32,7 +32,6 @@ QETTitleBlockTemplateEditor::QETTitleBlockTemplateEditor(QWidget *parent) : QMainWindow(parent), read_only(false), - parent_project_(0), tb_template_(0), logo_manager_(0) { @@ -54,7 +53,30 @@ QETTitleBlockTemplateEditor::~QETTitleBlockTemplateEditor() { @return the location of the currently edited template */ TitleBlockTemplateLocation QETTitleBlockTemplateEditor::location() const { - return(TitleBlockTemplateLocation(parent_project_, template_name_)); + return(location_); +} + +/** + @param location Location of the tile block template to be edited. +*/ +bool QETTitleBlockTemplateEditor::edit(const TitleBlockTemplateLocation &location) { + // the template name may be empty to create a new one + const TitleBlockTemplate *tb_template_orig; + if (location.name().isEmpty()) { + // loads the default title block template provided by the application + // it will be used as a start point to design the title block + tb_template_orig = QETApp::defaultTitleBlockTemplate(); + } else { + tb_template_orig = location.getTemplate(); + } + if (!tb_template_orig) { + /// TODO The TBT does not exist, manage error + return(false); + } + + location_ = location; + editCopyOf(tb_template_orig); + return(true); } /** @@ -82,9 +104,42 @@ bool QETTitleBlockTemplateEditor::edit(QETProject *project, const QString &templ return(false); } - tb_template_ = tb_template_orig -> clone(); - parent_project_ = project; - template_name_ = template_name; + location_.setParentCollection(project -> embeddedTitleBlockTemplatesCollection()); + location_.setName(template_name); + return(editCopyOf(tb_template_orig)); +} + +/** + @param file_path Path of the template file to edit. + @return false if a problem occured while opening the template, true otherwise. +*/ +bool QETTitleBlockTemplateEditor::edit(const QString &file_path) { + // get title block template object from the file, edit it + TitleBlockTemplate *tbt = new TitleBlockTemplate(); + bool loading = tbt -> loadFromXmlFile(file_path); + if (!loading) { + /// TODO the file opening failed, warn the user? + return(false); + } + return(edit(tbt)); +} + +/** + @param tbt Title block template to be edited + @return false if a problem occured while opening the template, true otherwise. +*/ +bool QETTitleBlockTemplateEditor::editCopyOf(const TitleBlockTemplate *tbt) { + if (!tbt) return(false); + return(edit(tbt -> clone())); +} + +/** + @param tbt Title block template to be directly edited + @return false if a problem occured while opening the template, true otherwise. +*/ +bool QETTitleBlockTemplateEditor::edit(TitleBlockTemplate *tbt) { + if (!tbt) return(false); + tb_template_ = tbt; template_edition_area_view_ -> setTitleBlockTemplate(tb_template_); template_cell_editor_widget_ -> updateLogosComboBox(tb_template_); updateEditorTitle(); @@ -242,6 +297,9 @@ void QETTitleBlockTemplateEditor::initWidgets() { ); } +/** + Initialize the logo manager +*/ void QETTitleBlockTemplateEditor::initLogoManager() { logo_manager_ = new TitleBlockTemplateLogoManager(tb_template_); connect( @@ -302,7 +360,7 @@ void QETTitleBlockTemplateEditor::updateEditorTitle() { ); QString title; - if (template_name_.isEmpty()) { + if (location_.name().isEmpty()) { title = min_title; } else { title = QString( @@ -310,38 +368,37 @@ void QETTitleBlockTemplateEditor::updateEditorTitle() { "%1 - %2", "window title: %1 is the base window title, %2 is a template name" ) - ).arg(min_title).arg(template_name_); + ).arg(min_title).arg(location_.name()); } setWindowTitle(title); } /** - Save the template as \a name within \a project. + Save the template under the provided location. @see QETProject::setTemplateXmlDescription() - @param project Parent project - @param name Template name + @param location Location where the title block template should be saved. */ -void QETTitleBlockTemplateEditor::saveAs(QETProject *project, const QString &name) { - if (!project || name.isEmpty()) return; +void QETTitleBlockTemplateEditor::saveAs(const TitleBlockTemplateLocation &location) { + TitleBlockTemplatesCollection *collection = location.parentCollection(); + if (!collection) return; QDomDocument doc; QDomElement elmt = doc.createElement("root"); tb_template_ -> saveToXmlElement(elmt); - elmt.setAttribute("name", name); + elmt.setAttribute("name", location.name()); doc.appendChild(elmt); - project -> setTemplateXmlDescription(name, elmt); + collection -> setTemplateXmlDescription(location.name(), elmt); - parent_project_ = project; - template_name_ = name; + location_ = location; } /** Save the currently edited title block template back to its parent project. */ void QETTitleBlockTemplateEditor::save() { - if (parent_project_ && !template_name_.isEmpty()) { - saveAs(parent_project_, template_name_); + if (location_.isValid()) { + saveAs(location_); } else { saveAs(); } @@ -353,13 +410,14 @@ void QETTitleBlockTemplateEditor::save() { void QETTitleBlockTemplateEditor::saveAs() { TitleBlockTemplateLocation location = getTitleBlockTemplateLocationFromUser(); if (location.isValid()) { - saveAs(location.project(), location.name()); + saveAs(location); } } /** - Ask the user for a title block template location - @return The location chosen by the user, or an empty TitleBlockTemplateLocation if the user cancelled the dialog + Ask the user for a title block template location @return The location chosen + by the user, or an empty TitleBlockTemplateLocation if the user cancelled the + dialog */ TitleBlockTemplateLocation QETTitleBlockTemplateEditor::getTitleBlockTemplateLocationFromUser() { TitleBlockTemplateLocationChooser *chooser = new TitleBlockTemplateLocationChooser(location()); diff --git a/sources/titleblock/qettemplateeditor.h b/sources/titleblock/qettemplateeditor.h index 2efbc4a1a..722d8e5c9 100644 --- a/sources/titleblock/qettemplateeditor.h +++ b/sources/titleblock/qettemplateeditor.h @@ -51,10 +51,8 @@ class QETTitleBlockTemplateEditor : public QMainWindow { /// actions QAction *save_, *save_as_, *quit_, *configure_, *about_qt_, *about_qet_, *merge_cells_, *split_cell_; QAction *zoom_in_, *zoom_out_, *zoom_fit_, *zoom_reset_; - /// Parent project of the currently edited template - QETProject *parent_project_; - /// Name of the currently edited template - QString template_name_; + /// Location of the currently edited template + TitleBlockTemplateLocation location_; /// Template Object edited TitleBlockTemplate *tb_template_; /// Template preview @@ -84,7 +82,11 @@ class QETTitleBlockTemplateEditor : public QMainWindow { public slots: void selectedCellsChanged(QList); + bool edit(const TitleBlockTemplateLocation &); bool edit(QETProject *, const QString &); + bool edit(const QString &); + bool editCopyOf(const TitleBlockTemplate *); + bool edit(TitleBlockTemplate *); void editLogos(); void save(); void saveAs(); @@ -96,7 +98,7 @@ class QETTitleBlockTemplateEditor : public QMainWindow { void pushGridUndoCommand(TitleBlockTemplateCommand *); void pushUndoCommand(QUndoCommand *); void updateEditorTitle(); - void saveAs(QETProject *, const QString &); + void saveAs(const TitleBlockTemplateLocation &); }; #endif diff --git a/sources/titleblock/templatedeleter.cpp b/sources/titleblock/templatedeleter.cpp index 7d81f3b89..b292c740c 100644 --- a/sources/titleblock/templatedeleter.cpp +++ b/sources/titleblock/templatedeleter.cpp @@ -43,10 +43,12 @@ TitleBlockTemplateDeleter::~TitleBlockTemplateDeleter() { */ bool TitleBlockTemplateDeleter::exec() { if (!template_location_.isValid()) return(false); - QETProject *project = template_location_.project(); - QString name = template_location_.name(); - if (!project -> embeddedTitleBlockTemplates().contains(name)) { + QString name = template_location_.name(); + TitleBlockTemplatesCollection *collection = template_location_.parentCollection(); + if (!collection) return(false); + + if (!collection -> templates().contains(name)) { return(false); } @@ -65,6 +67,6 @@ bool TitleBlockTemplateDeleter::exec() { if (answer != QMessageBox::Yes) return(false); // delete the title block template - project -> removeTemplateByName(name); + collection -> removeTemplate(name); return(true); } diff --git a/sources/titleblock/templatelocation.cpp b/sources/titleblock/templatelocation.cpp index 9207bba17..b4fa6f5d6 100644 --- a/sources/titleblock/templatelocation.cpp +++ b/sources/titleblock/templatelocation.cpp @@ -16,14 +16,16 @@ along with QElectroTech. If not, see . */ #include "templatelocation.h" +#include "templatescollection.h" +#include "qetapp.h" /** Constructor - @param project Parent project of the title block template + @param collection Parent collection of the title block template @param name Name of the title block template within its parent project or collection */ -TitleBlockTemplateLocation::TitleBlockTemplateLocation(QETProject *project, const QString &name) : - project_(project), +TitleBlockTemplateLocation::TitleBlockTemplateLocation(const QString &name, TitleBlockTemplatesCollection *collection) : + collection_(collection), name_(name) { } @@ -35,18 +37,18 @@ TitleBlockTemplateLocation::~TitleBlockTemplateLocation() { } /** - @return the parent project of the template, or 0 if none was defined + @return the parent collection of the template, or 0 if none was defined */ -QETProject *TitleBlockTemplateLocation::project() const { - return(project_); +TitleBlockTemplatesCollection *TitleBlockTemplateLocation::parentCollection() const { + return(collection_); } /** - @param project The new parent project of the template, or 0 if none + @param project The new parent collection of the template, or 0 if none applies. */ -void TitleBlockTemplateLocation::setProject(QETProject *project) { - project_ = project; +void TitleBlockTemplateLocation::setParentCollection(TitleBlockTemplatesCollection *collection) { + collection_ = collection; } /** @@ -67,5 +69,43 @@ void TitleBlockTemplateLocation::setName(const QString &name) { @return true if this location is null, false otherwise */ bool TitleBlockTemplateLocation::isValid() const { - return(project_ && !name_.isEmpty()); + return(!name_.isEmpty()); +} + +/** + @return A string representation of the location +*/ +QString TitleBlockTemplateLocation::toString() const { + return(protocol() + QString("://") + name_); +} + +/** + This is a convenience method equivalent to + parentCollection() -> parentProject(). +*/ +QETProject *TitleBlockTemplateLocation::parentProject() const { + if (collection_) { + return(collection_ -> parentProject()); + } + return(0); +} + +/** + This is a convenience method equivalent to + parentCollection() -> protocol(). +*/ +QString TitleBlockTemplateLocation::protocol() const { + if (collection_) { + return(collection_ -> protocol()); + } + return("unknown"); +} + +/** + This is a convenience method equivalent to + parentCollection() -> getTemplate(...). +*/ +TitleBlockTemplate *TitleBlockTemplateLocation::getTemplate() const { + if (!collection_ || name_.isEmpty()) return(0); + return(collection_ -> getTemplate(name_)); } diff --git a/sources/titleblock/templatelocation.h b/sources/titleblock/templatelocation.h index 1178cb6e2..7a24612d9 100644 --- a/sources/titleblock/templatelocation.h +++ b/sources/titleblock/templatelocation.h @@ -19,6 +19,8 @@ #define TITLEBLOCK_SLASH_TEMPLATE_LOCATION_H #include class QETProject; +class TitleBlockTemplate; +class TitleBlockTemplatesCollection; /** This class represents the location of a title block template. @@ -26,20 +28,24 @@ class QETProject; class TitleBlockTemplateLocation { // constructor, destructor public: - TitleBlockTemplateLocation(QETProject * = 0, const QString & = QString()); + TitleBlockTemplateLocation(const QString & = QString(), TitleBlockTemplatesCollection * = 0); virtual ~TitleBlockTemplateLocation(); // methods public: - QETProject *project() const; - void setProject(QETProject *); + TitleBlockTemplatesCollection *parentCollection() const; + void setParentCollection(TitleBlockTemplatesCollection *); QString name() const; void setName(const QString &); bool isValid() const; + QString toString() const; + QETProject *parentProject() const; + QString protocol() const; + TitleBlockTemplate *getTemplate() const; // attributes private: - QETProject *project_; ///< Parent project of the template, if any - QString name_; ///< Name of the template + TitleBlockTemplatesCollection *collection_; ///< Collection the template belongs to + QString name_; ///< Name of the template }; #endif diff --git a/sources/titleblock/templatelocationchooser.cpp b/sources/titleblock/templatelocationchooser.cpp index ad09f29a5..bb95faad5 100644 --- a/sources/titleblock/templatelocationchooser.cpp +++ b/sources/titleblock/templatelocationchooser.cpp @@ -1,6 +1,7 @@ #include "templatelocationchooser.h" #include "qetapp.h" #include "qetproject.h" +#include "templatescollection.h" /** Constructor @@ -27,15 +28,14 @@ TitleBlockTemplateLocationChooser::~TitleBlockTemplateLocationChooser() { @return the current location */ TitleBlockTemplateLocation TitleBlockTemplateLocationChooser::location() const { - return(TitleBlockTemplateLocation(project(), name())); + return(TitleBlockTemplateLocation(name(), collection())); } /** - @return the currently selected project + @return the currently selected collection */ -QETProject *TitleBlockTemplateLocationChooser::project() const { - uint project_id = projects_ -> itemData(projects_ -> currentIndex()).toUInt(); - return(QETApp::project(project_id)); +TitleBlockTemplatesCollection *TitleBlockTemplateLocationChooser::collection() const { + return(collections_index_[collections_ -> currentIndex()]); } /** @@ -51,15 +51,7 @@ QString TitleBlockTemplateLocationChooser::name() const { @param location to be displayed by this widget */ void TitleBlockTemplateLocationChooser::setLocation(const TitleBlockTemplateLocation &location) { - // we need a project id - int project_id = QETApp::projectId(location.project()); - if (project_id == -1) return; - - // attempt to find this project id in our project combo box - int project_index = projects_ -> findData(QVariant(static_cast(project_id))); - if (project_index == -1) return; - - projects_ -> setCurrentIndex(project_index); + collections_ -> setCurrentIndex(collections_index_.keys(location.parentCollection()).first()); if (!location.name().isEmpty()) { int template_index = templates_ -> findText(location.name()); @@ -76,43 +68,64 @@ void TitleBlockTemplateLocationChooser::setLocation(const TitleBlockTemplateLoca @param location Initial location displayed by the widget */ void TitleBlockTemplateLocationChooser::init() { - projects_ = new QComboBox(); + collections_ = new QComboBox(); templates_ = new QComboBox(); new_name_ = new QLineEdit(); - QMap projects = QETApp::registeredProjects(); - foreach (uint project_id, projects.keys()) { - projects_ -> addItem(projects[project_id] -> title(), project_id); - } - updateTemplates(); - connect(projects_, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTemplates())); + updateCollections(); + connect(collections_, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTemplates())); + connect(templates_, SIGNAL(currentIndexChanged(int)), this, SLOT(updateNewName())); QFormLayout *form_layout = new QFormLayout(); - form_layout -> addRow(tr("Projet parent", "used in save as form"), projects_); - form_layout -> addRow(tr("Modèle existant", "used in save as form"), templates_); - form_layout -> addRow(tr("ou nouveau nom", "used in save as form"), new_name_); + form_layout -> addRow(tr("Collection parente", "used in save as form"), collections_); + form_layout -> addRow(tr("Modèle existant", "used in save as form"), templates_); + form_layout -> addRow(tr("ou nouveau nom", "used in save as form"), new_name_); setLayout(form_layout); } +/** + Update the collections list +*/ +void TitleBlockTemplateLocationChooser::updateCollections() { + collections_ -> clear(); + collections_index_.clear(); + + int index = 0; + foreach(TitleBlockTemplatesCollection *collection, QETApp::availableTitleBlockTemplatesCollections()) { + collections_ -> addItem(collection -> title()); + collections_index_.insert(index, collection); + ++ index; + } + + updateTemplates(); +} + /** Update the templates list according to the selected project. */ void TitleBlockTemplateLocationChooser::updateTemplates() { - int current_index = projects_ -> currentIndex(); - if (current_index == -1) return; - - uint project_id = projects_ -> itemData(current_index).toUInt(); - QETProject *project = QETApp::project(project_id); - if (!project) return; + TitleBlockTemplatesCollection *current_collection = collection(); + if (!current_collection) return; templates_ -> clear(); templates_ -> addItem(tr("Nouveau modèle (entrez son nom)", "combox box entry"), QVariant(false)); - QStringList available_templates = project -> embeddedTitleBlockTemplates(); + QStringList available_templates = current_collection -> templates(); if (available_templates.count()) { templates_ -> insertSeparator(1); foreach (QString template_name, available_templates) { templates_ -> addItem(template_name, QVariant(true)); } } + + updateNewName(); +} + +/** + Enable or diable the "new name" text field depending of the selected + template. +*/ +void TitleBlockTemplateLocationChooser::updateNewName() { + int template_index = templates_ -> currentIndex(); + new_name_ -> setEnabled(!template_index); } diff --git a/sources/titleblock/templatelocationchooser.h b/sources/titleblock/templatelocationchooser.h index bf7aeb0b0..717a9870e 100644 --- a/sources/titleblock/templatelocationchooser.h +++ b/sources/titleblock/templatelocationchooser.h @@ -19,6 +19,8 @@ #define TITLEBLOCK_SLASH_LOCATION_CHOOSER_H #include #include "templatelocation.h" +class TitleBlockTemplateCollection; + /** This class is a widget that allows the user to choose a target title block template. @@ -35,7 +37,7 @@ class TitleBlockTemplateLocationChooser : public QWidget { // methods public: TitleBlockTemplateLocation location() const; - QETProject *project() const; + TitleBlockTemplatesCollection *collection() const; QString name() const; void setLocation(const TitleBlockTemplateLocation &); private: @@ -43,12 +45,16 @@ class TitleBlockTemplateLocationChooser : public QWidget { // slots private slots: + void updateCollections(); void updateTemplates(); + void updateNewName(); // attributes private: - QComboBox *projects_; ///< Projects combo box - QComboBox *templates_; ///< Existing templates combo box - QLineEdit *new_name_; ///< New template name textfield + QComboBox *collections_; ///< Collections combo box + /// Collections index within the combo box + QHash collections_index_; + QComboBox *templates_; ///< Existing templates combo box + QLineEdit *new_name_; ///< New template name textfield }; #endif diff --git a/sources/titleblock/templatescollection.cpp b/sources/titleblock/templatescollection.cpp new file mode 100644 index 000000000..fb61c6976 --- /dev/null +++ b/sources/titleblock/templatescollection.cpp @@ -0,0 +1,464 @@ +/* + Copyright 2006-2012 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 . +*/ +#include "templatescollection.h" +#include "titleblocktemplate.h" +#include "qetapp.h" +#include "qetproject.h" + +/** + Constructor + @param parent Parent QObject +*/ +TitleBlockTemplatesCollection::TitleBlockTemplatesCollection(QObject *parent) : + QObject(parent), + protocol_("unknown") +{ +} + +/** + Destructor +*/ +TitleBlockTemplatesCollection::~TitleBlockTemplatesCollection() { +} + +/** + @return the title of this collection +*/ +QString TitleBlockTemplatesCollection::title() const { + return(title_); +} + +/** + @oaram title New title for this collection +*/ +void TitleBlockTemplatesCollection::setTitle(const QString &title) { + title_ = title; +} + +/** + @return the protocol used by this collection ; examples: commontbt, + customtbt, embedtbt, ... +*/ +QString TitleBlockTemplatesCollection::protocol() const { + return(protocol_); +} + +/** + Define the protocol for this collection + @param protocol New protocol for this collection +*/ +void TitleBlockTemplatesCollection::setProtocol(const QString &protocol) { + if (!protocol.isEmpty()) protocol_ = protocol; +} + +/** + @return the project this collection is affiliated to, or 0 if this + collection is not related to any project. +*/ +QETProject *TitleBlockTemplatesCollection::parentProject() { + return(0); +} + +/** + Constructor + @param project Parent project + @param parent Parent QObject +*/ +TitleBlockTemplatesProjectCollection::TitleBlockTemplatesProjectCollection(QETProject *project, QObject *parent) : + TitleBlockTemplatesCollection(parent), + project_(project) +{ +} + +/** + Destructor +*/ +TitleBlockTemplatesProjectCollection::~TitleBlockTemplatesProjectCollection() { +} + +/** + @return a human readable title for this collection +*/ +QString TitleBlockTemplatesProjectCollection::title() const { + if (!title_.isEmpty()) return(title_); + + // if the title attribute is empty, we generate a suitable one using the + // parent project + QString final_title; + if (project_) { + QString project_title = project_ -> title(); + if (project_title.isEmpty()) { + final_title = QString( + tr( + "Cartouches du projet sans titre (id %1)", + "collection title when the parent project has an empty title -- %1 is the project internal id" + ) + ); + final_title = final_title.arg(QETApp::projectId(project_)); + } else { + final_title = QString( + tr( + "Cartouches du projet \"%1\"", + "collection title when the project has a suitble title -- %1 is the project title" + ) + ); + final_title = final_title.arg(project_title); + } + } + return(final_title); +} + +/** + @return the protocol used to mention this collection +*/ +QString TitleBlockTemplatesProjectCollection::protocol() const { + if (project_) { + int project_id = QETApp::projectId(project_); + if (project_id != -1) { + return(QString("project%1+embedtbt").arg(project_id)); + } + } + // fall back on the parent method + return(TitleBlockTemplatesCollection::protocol()); +} + +/** + @return the parent project of this project collection +*/ +QETProject *TitleBlockTemplatesProjectCollection::parentProject() { + return(project_); +} + +/** + @return the list of title block templates embedded within the project. +*/ +QStringList TitleBlockTemplatesProjectCollection::templates() { + return(titleblock_templates_xml_.keys()); +} + +/** + @param template_name Name of the requested template + @return the requested template, or 0 if there is no valid template of this + name within the project +*/ +TitleBlockTemplate *TitleBlockTemplatesProjectCollection::getTemplate(const QString &template_name){ + // Do we have already loaded this template? + if (titleblock_templates_.contains(template_name)) { + return(titleblock_templates_[template_name]); + } + + // No? Do we even know of it? + if (!titleblock_templates_xml_.contains(template_name)) { + return(0); + } + + // Ok, we have its XML description, we have to generate a TitleBlockTemplate object + TitleBlockTemplate *titleblock_template = new TitleBlockTemplate(this); + if (titleblock_template -> loadFromXmlElement(titleblock_templates_xml_[template_name])) { + titleblock_templates_.insert(template_name, titleblock_template); + return(titleblock_template); + } else { + return(0); + } +} + +/** + @param template_name Name of the requested template + @return the XML description of the requested template, or a null QDomElement + if the project does not have such an titleblock template +*/ +QDomElement TitleBlockTemplatesProjectCollection::getTemplateXmlDescription(const QString &template_name) { + if (titleblock_templates_xml_.contains(template_name)) { + return(titleblock_templates_xml_[template_name]); + } + return(QDomElement()); +} + +/** + This methods allows adding or modifying a template embedded within the + project. This method emits the signal changed() 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 TitleBlockTemplatesProjectCollection::setTemplateXmlDescription(const QString &template_name, const QDomElement &xml_elmt) { + // check basic stuff + if (xml_elmt.tagName() != "titleblocktemplate" || xml_elmt.attribute("name") != template_name) { + return(false); + } + + // we *require* a project (at least for the moment...) + if (!project_) return(false); + + // we import the provided XML element in the project document + QDomElement import = xml_document_.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_.insert(template_name, import); + + if (titleblock_templates_.contains(template_name)) { + titleblock_templates_[template_name] -> loadFromXmlElement(titleblock_templates_xml_[template_name]); + } + emit(changed(this, template_name)); + + return(true); +} + +/** + This methods allows removing a template embedded within the project. This + method emits the signal changed() if necessary. + @param template_name Name of the template to be removed +*/ +void TitleBlockTemplatesProjectCollection::removeTemplate(const QString &template_name) { + emit(aboutToRemove(this, template_name)); + + // 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(changed(this, template_name)); +} + +/** + @param template_name Name of the requested template + @return the location object for the requested template +*/ +TitleBlockTemplateLocation TitleBlockTemplatesProjectCollection::location(const QString &template_name) { + return(TitleBlockTemplateLocation(template_name, this)); +} + +/** + @return true if this collection is read only +*/ +bool TitleBlockTemplatesProjectCollection::isReadOnly() const { + if (project_) { + return(project_ -> isReadOnly()); + } + return(false); +} + +/** + @param xml_element XML element to be parsed to load title block templates +*/ +void TitleBlockTemplatesProjectCollection::fromXml(const QDomElement &xml_element) { + foreach (QDomElement e, QET::findInDomElement(xml_element, "titleblocktemplates", "titleblocktemplate")) { + // each titleblock template must have a name + if (!e.hasAttribute("name")) continue; + QString titleblock_template_name = e.attribute("name"); + + // if several templates have the same name, we keep the first one encountered + if (titleblock_templates_xml_.contains(titleblock_template_name)) continue; + + // we simply store the XML element describing the titleblock template, + // without any further analysis for the moment + titleblock_templates_xml_.insert(titleblock_template_name, e); + } +} + +/** + Constructor + @param path Path of the directory containing the collection + @param parent Parent QObject +*/ +TitleBlockTemplatesFilesCollection::TitleBlockTemplatesFilesCollection(const QString &path, QObject *parent) : + TitleBlockTemplatesCollection(parent), + dir_( + path, + QString("*%1").arg(TITLEBLOCKS_FILE_EXTENSION), + QDir::SortFlags(QDir::Name | QDir::IgnoreCase), + QDir::Readable | QDir::Files + ) +{ + if (dir_.exists()) { + watcher_.addPath(dir_.canonicalPath()); + } + connect(&watcher_, SIGNAL(directoryChanged(const QString &)), this, SLOT(fileSystemChanged(const QString &))); +} + +/** + Destructor +*/ +TitleBlockTemplatesFilesCollection::~TitleBlockTemplatesFilesCollection() { +} + +/** + @return the canonical path of the directory hosting this collection. +*/ +QString TitleBlockTemplatesFilesCollection::path(const QString &template_name) const { + if (template_name.isEmpty()) { + return(dir_.canonicalPath()); + } else { + return(dir_.absoluteFilePath(toFileName(template_name))); + } +} + +/** + @return the list of templates contained in this collection +*/ +QStringList TitleBlockTemplatesFilesCollection::templates() { + QStringList templates_names; + QRegExp replace_regexp(QString("%1$").arg(TITLEBLOCKS_FILE_EXTENSION)); + foreach(QString name, dir_.entryList()) { + templates_names << name.replace(replace_regexp, ""); + } + return(templates_names); +} + +/** + @return the template which name is \a template_name, or 0 if the template + could not be loaded. +*/ +TitleBlockTemplate *TitleBlockTemplatesFilesCollection::getTemplate(const QString &template_name) { + if (!templates().contains(template_name)) return(0); + + TitleBlockTemplate *tbtemplate = new TitleBlockTemplate(); + QString tbt_file_path = path(template_name); + + bool loading = tbtemplate -> loadFromXmlFile(tbt_file_path); + if (!loading) { + delete tbtemplate; + return(0); + } + return(tbtemplate); +} + +/** + @param template_name Name of a template (which has to already exist) + @return the XML description for the \a template_name template, or a null QDomElement if no such template exists. +*/ +QDomElement TitleBlockTemplatesFilesCollection::getTemplateXmlDescription(const QString &template_name) { + QString xml_file_path = path(template_name); + + QFileInfo xml_file_info(xml_file_path); + if (!xml_file_info.exists() || !xml_file_info.isReadable()) { + return(QDomElement()); + } + + QFile xml_file(xml_file_path); + if (!xml_file.open(QIODevice::ReadOnly)) { + return(QDomElement()); + } + + QDomDocument *xml_document = new QDomDocument(); + bool xml_parsing = xml_document -> setContent(&xml_file); + if (!xml_parsing) { + delete xml_document; + return(QDomElement()); + } + return(xml_document -> documentElement()); +} + +/** + Set the XML description of the \a template_name template to \a xml_element. + @param template_name Name of a template (which does not have to already exist) + @param xml_element XML element describing the template +*/ +bool TitleBlockTemplatesFilesCollection::setTemplateXmlDescription(const QString &template_name, const QDomElement &xml_element) { + if (template_name.isEmpty()) return(false); + + // prevent the watcher from emitting signals while we open and write to file + blockSignals(true); + + QFile xml_file(path(template_name)); + if (!xml_file.open(QIODevice::WriteOnly | QIODevice::Text)) { + return(false); + } + QDomDocument doc; + doc.appendChild(doc.importNode(xml_element, true)); + + QTextStream out(&xml_file); + out.setCodec("UTF-8"); + out << doc.toString(4); + xml_file.close(); + + // emit a single signal for the change + blockSignals(false); + emit(changed(this, template_name)); + return(true); +} + +/** + Remove the \a template_name template. +*/ +void TitleBlockTemplatesFilesCollection::removeTemplate(const QString &template_name) { + emit(aboutToRemove(this, template_name)); + // prevent the watcher from emitting signals while we open and write to file + blockSignals(true); + + dir_.remove(toFileName(template_name)); + + // emit a single signal for the removal + blockSignals(false); + emit(changed(this, template_name)); +} + +/** + @param template_name Name of a template supposed to be contained within + this collection. + @return +*/ +TitleBlockTemplateLocation TitleBlockTemplatesFilesCollection::location(const QString &template_name) { + return(TitleBlockTemplateLocation(template_name, this)); +} + +/** + @return true if this collection is read only, false otherwise +*/ +bool TitleBlockTemplatesFilesCollection::isReadOnly() const { + QFileInfo info(dir_.canonicalPath()); + return(!info.isWritable()); +} + +/** + @param file_name A file name + @return the template name for \a file_name +*/ +QString TitleBlockTemplatesFilesCollection::toTemplateName(const QString &file_name) { + static QRegExp replace_regexp(QString("%1$").arg(TITLEBLOCKS_FILE_EXTENSION)); + QString template_name(file_name); + return(template_name.replace(replace_regexp, "")); +} + +/** + @param template_name A template name + @return the file name for \a template_name +*/ +QString TitleBlockTemplatesFilesCollection::toFileName(const QString &template_name) { + return(QString("%1%2").arg(template_name).arg(TITLEBLOCKS_FILE_EXTENSION)); +} + +/** + Handle the changes occuring on the file system. + @param str Path of the directory that changed. +*/ +void TitleBlockTemplatesFilesCollection::fileSystemChanged(const QString &str) { + Q_UNUSED(str); + dir_.refresh(); + emit(changed(this)); +} diff --git a/sources/titleblock/templatescollection.h b/sources/titleblock/templatescollection.h new file mode 100644 index 000000000..826bacb8c --- /dev/null +++ b/sources/titleblock/templatescollection.h @@ -0,0 +1,148 @@ +/* + Copyright 2006-2012 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 TITLEBLOCK_SLASH_TEMPLATES_COLLECTION_H +#define TITLEBLOCK_SLASH_TEMPLATES_COLLECTION_H +#define TITLEBLOCKS_FILE_EXTENSION ".titleblock" +#include +#include +#include "templatelocation.h" +class TitleBlockTemplate; +class QETProject; + +/** + This abstract class represents a generic collection of title block templates. + Unlike elements collections, title block templates collections do not provide + a tree structure. Instead, they provide a simple, flat list of available + templates. +*/ +class TitleBlockTemplatesCollection : public QObject { + Q_OBJECT + + // Constructors, destructor + public: + TitleBlockTemplatesCollection(QObject *parent); + virtual ~TitleBlockTemplatesCollection(); + private: + TitleBlockTemplatesCollection(const TitleBlockTemplatesCollection &); + + // methods + public: + virtual QStringList templates() = 0; + virtual TitleBlockTemplate *getTemplate(const QString &) = 0; + virtual QDomElement getTemplateXmlDescription(const QString &) = 0; + virtual bool setTemplateXmlDescription(const QString &, const QDomElement &) = 0; + virtual void removeTemplate(const QString &) = 0; + virtual TitleBlockTemplateLocation location(const QString & = QString()) = 0; + virtual bool isReadOnly() const = 0; + virtual QString title() const; + virtual void setTitle(const QString &); + virtual QString protocol() const; + virtual void setProtocol(const QString &); + virtual QETProject *parentProject(); + + signals: + void changed(TitleBlockTemplatesCollection *, const QString & = QString()); + void aboutToRemove(TitleBlockTemplatesCollection *, const QString &); + + // attributes + protected: + /// Human-readable title for this collection + QString title_; + /// Protocol used to designate this collection + QString protocol_; + /// Already parsed embedded titleblock templates + QHash titleblock_templates_; +}; + +/** + This class represents a simple abastraction layer for a collection of title + block templates embedded within a project. +*/ +class TitleBlockTemplatesProjectCollection : public TitleBlockTemplatesCollection { + Q_OBJECT + + // Constructors, destructor + public: + TitleBlockTemplatesProjectCollection(QETProject *, QObject *parent = 0); + virtual ~TitleBlockTemplatesProjectCollection(); + private: + TitleBlockTemplatesProjectCollection(const TitleBlockTemplatesProjectCollection &); + + // methods + public: + virtual QString title() const; + virtual QString protocol() const; + virtual QETProject *parentProject(); + virtual QStringList templates(); + virtual TitleBlockTemplate *getTemplate(const QString &); + virtual QDomElement getTemplateXmlDescription(const QString &); + virtual bool setTemplateXmlDescription(const QString &, const QDomElement &); + virtual void removeTemplate(const QString &); + virtual TitleBlockTemplateLocation location(const QString & = QString()); + virtual bool isReadOnly() const; + virtual void fromXml(const QDomElement &); + + // attributes + private: + /// Parent project + QETProject *project_; + /// Parent QDomDocument for stored QDomElements + QDomDocument xml_document_; + /// XML descriptions of embedded titleblock templates + QHash titleblock_templates_xml_; +}; + +/** + This classe represents a simple abastraction layer for a file-based title + block templates directory. +*/ +class TitleBlockTemplatesFilesCollection : public TitleBlockTemplatesCollection { + Q_OBJECT + + // Constructors, destructor + public: + TitleBlockTemplatesFilesCollection(const QString &, QObject * = 0); + virtual ~TitleBlockTemplatesFilesCollection(); + private: + TitleBlockTemplatesFilesCollection(const TitleBlockTemplatesFilesCollection &); + + // methods + public: + QString path(const QString & = QString()) const; + virtual QStringList templates(); + virtual TitleBlockTemplate *getTemplate(const QString &); + virtual QDomElement getTemplateXmlDescription(const QString &); + virtual bool setTemplateXmlDescription(const QString &, const QDomElement &); + virtual void removeTemplate(const QString &); + virtual TitleBlockTemplateLocation location(const QString & = QString()); + virtual bool isReadOnly() const; + + static QString toTemplateName(const QString &); + static QString toFileName(const QString &); + + private slots: + void fileSystemChanged(const QString &str); + + // attributes + private: + /// File System Watcher object to track the files changes made outside the application + QFileSystemWatcher watcher_; + /// Collection real directory + QDir dir_; +}; +#endif