diff --git a/sources/elementspanel.cpp b/sources/elementspanel.cpp index 41276aaa6..274139c98 100644 --- a/sources/elementspanel.cpp +++ b/sources/elementspanel.cpp @@ -25,6 +25,37 @@ #include "fileelementdefinition.h" #include "qeticons.h" +/** + This class implements a thread reloading the following elements + collections: + * the common collection + * the custom collection + * the embedded collection of each project listed in the projects_ + attribute. +*/ +class ReloadCollectionThread : public QThread { + public: + void run(); + /// list of projects whose embedded collection should be reloaded. + QList projects_; +}; + +/** + Reloads collections. +*/ +void ReloadCollectionThread::run() { + QETApp::commonElementsCollection() -> reload(); + QETApp::customElementsCollection() -> reload(); + + // reloads collection of every project displayed in this panel + foreach(QETProject *project, projects_) { + if (ElementsCollection *project_collection = project -> embeddedCollection()) { + project_collection -> reload(); + } + } + exit(); +} + /* Lorsque le flag ENABLE_PANEL_DND_CHECKS est defini, le panel d'elements effectue des verifications lors des drag'n drop d'elements et categories. @@ -54,7 +85,8 @@ ElementsPanel::ElementsPanel(QWidget *parent) : QTreeWidget(parent), common_collection_item_(0), - custom_collection_item_(0) + custom_collection_item_(0), + first_activation_(true) { // selection unique @@ -72,13 +104,6 @@ ElementsPanel::ElementsPanel(QWidget *parent) : // taille des elements setIconSize(QSize(50, 50)); - // charge les collections - reload(); - - // la premiere fois, etend le premier niveau des collections - if (common_collection_item_) common_collection_item_ -> setExpanded(true); - if (custom_collection_item_) custom_collection_item_ -> setExpanded(true); - // force du noir sur une alternance de blanc (comme le schema) et de gris // clair, avec du blanc sur bleu pas trop fonce pour la selection QPalette qp = palette(); @@ -514,6 +539,17 @@ void ElementsPanel::startDrag(Qt::DropActions supportedActions) { drag -> start(Qt::MoveAction | Qt::CopyAction); } +/** + @param event Object describing the received event +*/ +bool ElementsPanel::event(QEvent *event) { + if (first_activation_ && event -> type() == QEvent::WindowActivate) { + reload(false); + first_activation_ = false; + } + return(QTreeWidget::event(event)); +} + /** Methode permettant d'ajouter un projet au panel d'elements. @param qtwi_parent QTreeWidgetItem parent sous lequel sera insere le projet @@ -638,6 +674,7 @@ QTreeWidgetItem *ElementsPanel::addCategory(QTreeWidgetItem *qtwi_parent, Elemen t.setColorAt(1, QColor("#ffffff")); qtwi_category -> setBackground(0, QBrush(t)); locations_.insert(qtwi_category, category -> location()); + emit(loadingProgressed(++ loading_progress_, -1)); // reduit le dossier si besoin qtwi_category -> setExpanded(expanded_directories.contains(category -> location().toString())); @@ -646,7 +683,10 @@ QTreeWidgetItem *ElementsPanel::addCategory(QTreeWidgetItem *qtwi_parent, Elemen foreach(ElementsCategory *sub_cat, category -> categories()) addCategory(qtwi_category, sub_cat); // ajout des elements - foreach(ElementDefinition *elmt, category -> elements()) addElement(qtwi_category, elmt); + foreach(ElementDefinition *elmt, category -> elements()) { + addElement(qtwi_category, elmt); + emit(loadingProgressed(++ loading_progress_, -1)); + } return(qtwi_category); } @@ -695,19 +735,51 @@ QTreeWidgetItem *ElementsPanel::addElement(QTreeWidgetItem *qtwi_parent, Element return(qtwi); } +/** + Reloads the following collections: + * common collection + * custom collection + * collection of every project displayed in this panel +*/ +void ElementsPanel::reloadCollections() { + ReloadCollectionThread thread; + thread.projects_ = projects_to_display_.values(); + thread.start(); + while(!thread.wait(100)) { + QApplication::processEvents(); + } +} + +/** + @return the count of categories and elements within the following collections: + * common collection + * custom collection + * collection of every project displayed in this panel +*/ +int ElementsPanel::elementsCollectionItemsCount() { + int items_count = 0; + items_count += QETApp::commonElementsCollection() -> count(); + items_count += QETApp::customElementsCollection() -> count(); + foreach(QETProject *project, projects_to_display_.values()) { + if (ElementsCollection *project_collection = project -> embeddedCollection()) { + items_count += project_collection -> count(); + } + } + return(items_count); +} + /** Recharge l'arbre des elements @param reload_collections true pour relire les collections depuis leurs sources (fichiers, projets...) */ void ElementsPanel::reload(bool reload_collections) { - // sauvegarde la liste des repertoires reduits saveExpandedCategories(); if (reload_collections) { - foreach(ElementsCollection *collection, QETApp::availableCollections()) { - collection -> reload(); - } + emit(readingAboutToBegin()); + reloadCollections(); + emit(readingFinished()); } // vide l'arbre et le hash @@ -719,12 +791,22 @@ void ElementsPanel::reload(bool reload_collections) { common_collection_item_ = 0; custom_collection_item_ = 0; + // estimates the number of categories and elements to load + int items_count = elementsCollectionItemsCount(); + emit(loadingProgressed(loading_progress_ = 0, items_count)); + // chargement des elements de la collection QET common_collection_item_ = addCollection(invisibleRootItem(), QETApp::commonElementsCollection(), tr("Collection QET"), QIcon(":/ico/16x16/qet.png")); // chargement des elements de la collection utilisateur custom_collection_item_ = addCollection(invisibleRootItem(), QETApp::customElementsCollection(), tr("Collection utilisateur"), QIcon(":/ico/16x16/go-home.png")); + // the first time, expand the first level of collections + if (first_activation_) { + common_collection_item_ -> setExpanded(true); + custom_collection_item_ -> setExpanded(true); + } + // chargement des projets foreach(QETProject *project, projects_to_display_.values()) { addProject(invisibleRootItem(), project); @@ -1118,3 +1200,4 @@ void ElementsPanel::ensureHierarchyIsVisible(QList items) { if (parent_qtwi -> isHidden()) parent_qtwi -> setHidden(false); } } + diff --git a/sources/elementspanel.h b/sources/elementspanel.h index 374d2494b..b388fec12 100644 --- a/sources/elementspanel.h +++ b/sources/elementspanel.h @@ -82,15 +82,21 @@ class ElementsPanel : public QTreeWidget { Diagram *selectedDiagram() const; ElementsLocation selectedLocation() const; + void reloadCollections(); + int elementsCollectionItemsCount(); + signals: void requestForProject(QETProject *); void requestForDiagram(Diagram *); void requestForCollectionItem(ElementsCollectionItem *); void requestForMoveElements(ElementsCollectionItem *, ElementsCollectionItem *, QPoint); + void readingAboutToBegin(); + void readingFinished(); + void loadingProgressed(int, int); public slots: void slot_doubleClick(QTreeWidgetItem *, int); - void reload(bool = true); + void reload(bool = false); void filter(const QString &); void projectWasOpened(QETProject *); void projectWasClosed(QETProject *); @@ -107,6 +113,7 @@ class ElementsPanel : public QTreeWidget { void dragMoveEvent(QDragMoveEvent *); void dropEvent(QDropEvent *); void startDrag(Qt::DropActions); + bool event(QEvent *); private: QTreeWidgetItem *addProject (QTreeWidgetItem *, QETProject *); @@ -134,5 +141,7 @@ class ElementsPanel : public QTreeWidget { QHash title_blocks_directories_; QTreeWidgetItem *common_collection_item_; QTreeWidgetItem *custom_collection_item_; + int loading_progress_; + bool first_activation_; }; #endif diff --git a/sources/elementspanelwidget.cpp b/sources/elementspanelwidget.cpp index a091a30f3..9989a4257 100644 --- a/sources/elementspanelwidget.cpp +++ b/sources/elementspanelwidget.cpp @@ -44,6 +44,10 @@ @param parent Le QWidget parent de ce widget */ ElementsPanelWidget::ElementsPanelWidget(QWidget *parent) : QWidget(parent) { + // initialize the progress bar (hidden by default) + progress_bar_ = new QProgressBar(this); + progress_bar_ -> setVisible(false); + progress_bar_ -> setTextVisible(true); // initalise le panel d'elements elements_panel = new ElementsPanel(this); @@ -124,6 +128,9 @@ ElementsPanelWidget::ElementsPanelWidget(QWidget *parent) : QWidget(parent) { SLOT(handleMoveElementsRequest(ElementsCollectionItem *, ElementsCollectionItem *, const QPoint &)), Qt::QueuedConnection ); + connect(elements_panel, SIGNAL(loadingProgressed(int, int)), this, SLOT(updateProgressBar(int, int))); + connect(elements_panel, SIGNAL(readingAboutToBegin()), this, SLOT(collectionsRead())); + connect(elements_panel, SIGNAL(readingFinished()), this, SLOT(collectionsReadFinished())); // initialise la barre d'outils toolbar = new QToolBar(this); @@ -146,6 +153,7 @@ ElementsPanelWidget::ElementsPanelWidget(QWidget *parent) : QWidget(parent) { vlayout -> addWidget(toolbar); vlayout -> addWidget(filter_toolbar); vlayout -> addWidget(elements_panel); + vlayout -> addWidget(progress_bar_); vlayout -> setStretchFactor(elements_panel, 75000); setLayout(vlayout); } @@ -171,7 +179,7 @@ void ElementsPanelWidget::clearFilterTextField() { */ void ElementsPanelWidget::reloadAndFilter() { // recharge tous les elements - elements_panel -> reload(); + elements_panel -> reload(true); // reapplique le filtre elements_panel -> filter(filter_textfield -> text()); @@ -530,6 +538,44 @@ void ElementsPanelWidget::copyElements() { copyElements(dnd_item_src_, dnd_item_dst_); } +/** + Reflects the fact that collections are being read (i.e from filesystem) in + the progress bar. +*/ +void ElementsPanelWidget::collectionsRead() { + progress_bar_ -> setMinimum(0); + progress_bar_ -> setMaximum(1); + progress_bar_ -> setValue(0); + progress_bar_ -> setFormat(tr("Lecture...", "Reading of elements/categories files")); + progress_bar_ -> setVisible(true); +} + +/** + Reflects the fact that collections being read (i.e from filesystem) in the + progress bar. +*/ +void ElementsPanelWidget::collectionsReadFinished() { + progress_bar_ -> setFormat(tr("Chargement : %p%", "Visual rendering of elements/categories files - %p is the progress percentage")); +} + +/** + Updates the progress bar + @param current value that should be displayed + @param maximum maximum expected value; -1 means "use the previously known one" +*/ +void ElementsPanelWidget::updateProgressBar(int current, int maximum) { + int provided_maximum = maximum == -1 ? progress_bar_ -> maximum() : maximum; + if (provided_maximum != progress_bar_ -> maximum()) { + progress_bar_ -> setMaximum(maximum); + } + if (!current) { + progress_bar_ -> setVisible(true); + } else if (current == provided_maximum) { + QTimer::singleShot(500, progress_bar_, SLOT(hide())); + } + progress_bar_ -> setValue(current); +} + /** Copie l'item src dans l'item dst */ diff --git a/sources/elementspanelwidget.h b/sources/elementspanelwidget.h index 4bb9faa5c..dbeedcdb5 100644 --- a/sources/elementspanelwidget.h +++ b/sources/elementspanelwidget.h @@ -49,6 +49,7 @@ class ElementsPanelWidget : public QWidget { QAction *erase_textfield; QLineEdit *filter_textfield; ElementsCollectionItem *dnd_item_src_, *dnd_item_dst_; + QProgressBar *progress_bar_; // methodes public: @@ -92,6 +93,9 @@ class ElementsPanelWidget : public QWidget { void moveElements(ElementsCollectionItem *, ElementsCollectionItem *); void copyElements(); void copyElements(ElementsCollectionItem *, ElementsCollectionItem *); + void collectionsRead(); + void collectionsReadFinished(); + void updateProgressBar(int, int); private: void launchElementEditor(const ElementsLocation &); diff --git a/sources/qetapp.cpp b/sources/qetapp.cpp index c3398b154..cc7777ad8 100644 --- a/sources/qetapp.cpp +++ b/sources/qetapp.cpp @@ -92,6 +92,12 @@ QETApp::QETApp(int &argc, char **argv) : setQuitOnLastWindowClosed(false); connect(this, SIGNAL(lastWindowClosed()), this, SLOT(checkRemainingWindows())); + // loads known collections into memory (this does not include items rendering made in elements panels) + setSplashScreenStep(tr("Chargement... Lecture des collections d'\351l\351ments", "splash screen caption")); + foreach(ElementsCollection *collection, availableCollections()) { + collection -> reload(); + } + // on ouvre soit les fichiers passes en parametre soit un nouvel editeur de projet if (qet_arguments_.files().isEmpty()) { setSplashScreenStep(tr("Chargement... \311diteur de sch\351mas", "splash screen caption")); diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index f40134f2d..88eb68a4e 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -740,9 +740,11 @@ bool QETDiagramEditor::closeCurrentProject() { Ouvre un projet depuis un fichier et l'ajoute a cet editeur @param filepath Chemin du projet a ouvrir @param interactive true pour afficher des messages a l'utilisateur, false sinon + @param update_panel Whether the elements panel should be warned this + project has been added. Defaults to true. @return true si l'ouverture a reussi, false sinon */ -bool QETDiagramEditor::openAndAddProject(const QString &filepath, bool interactive) { +bool QETDiagramEditor::openAndAddProject(const QString &filepath, bool interactive, bool update_panel) { if (filepath.isEmpty()) return(false); QFileInfo filepath_info(filepath); @@ -812,14 +814,18 @@ bool QETDiagramEditor::openAndAddProject(const QString &filepath, bool interacti // on l'ajoute a la liste des fichiers recents QETApp::projectsRecentFiles() -> fileWasOpened(filepath); // ... et on l'ajoute dans l'application - return(addProject(project)); + // Note: we require the panel not to be updated when the project is added + // because it will update itself as soon as it becomes visible + return(addProject(project), update_panel); } /** Ajoute un projet @param project projet a ajouter + @param update_panel Whether the elements panel should be warned this + project has been added. Defaults to true. */ -bool QETDiagramEditor::addProject(QETProject *project) { +bool QETDiagramEditor::addProject(QETProject *project, bool update_panel) { // enregistre le projet QETApp::registerProject(project); @@ -828,7 +834,9 @@ bool QETDiagramEditor::addProject(QETProject *project) { addProjectView(project_view); // met a jour le panel d'elements - pa -> elementsPanel().projectWasOpened(project); + if (update_panel) { + pa -> elementsPanel().projectWasOpened(project); + } return(true); } diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index 868dbfd60..f698b9c31 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -52,7 +52,7 @@ class QETDiagramEditor : public QMainWindow { void closeEvent(QCloseEvent *); QList openedProjects() const; void addProjectView(ProjectView *); - bool openAndAddProject(const QString &, bool interactive = true); + bool openAndAddProject(const QString &, bool = true, bool = true); QList projectViews() const; QList editedFiles() const; ProjectView *viewForFile(const QString &) const; @@ -67,7 +67,7 @@ class QETDiagramEditor : public QMainWindow { virtual bool event(QEvent *); private: - bool addProject(QETProject *); + bool addProject(QETProject *, bool = true); ProjectView *currentProject() const; DiagramView *currentDiagram() const; ProjectView *findProject(DiagramView *) const;