QElectroTech  0.70
elementspanel.cpp
Go to the documentation of this file.
1 /*
2  Copyright 2006-2019 The QElectroTech Team
3  This file is part of QElectroTech.
4 
5  QElectroTech is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 2 of the License, or
8  (at your option) any later version.
9 
10  QElectroTech is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "elementspanel.h"
19 #include "qetapp.h"
20 #include "qetproject.h"
21 #include "diagram.h"
22 #include "qeticons.h"
23 #include "templatescollection.h"
24 
25 /*
26  Lorsque le flag ENABLE_PANEL_DND_CHECKS est defini, le panel d'elements
27  effectue des verifications lors des drag'n drop d'elements et categories.
28  Par exemple, il verifie qu'une categorie cible est accessible en ecriture
29  avant d'y autoriser le drop d'un element.
30  Supprimer ce flag permet de tester le comportement des fonctions de gestion
31  des items (copy, move, etc.).
32 */
33 #define ENABLE_PANEL_DND_CHECKS
34 
39 ElementsPanel::ElementsPanel(QWidget *parent) :
40  GenericPanel(parent),
41  first_reload_(true)
42 {
43  // selection unique
44  setSelectionMode(QAbstractItemView::SingleSelection);
45  setColumnCount(1);
46  setExpandsOnDoubleClick(true);
47  setMouseTracking(true);
48 
49  // drag'n drop autorise
50  setDragEnabled(true);
51  setAcceptDrops(true);
52  setDropIndicatorShown(true);
53  setAutoExpandDelay(1000);
54 
55  // force du noir sur une alternance de blanc (comme le schema) et de gris
56  // clair, avec du blanc sur bleu pas trop fonce pour la selection
57  QPalette qp = palette();
58  qp.setColor(QPalette::Text, Qt::black);
59  qp.setColor(QPalette::Base, Qt::white);
60  qp.setColor(QPalette::AlternateBase, QColor("#e8e8e8"));
61  qp.setColor(QPalette::Highlight, QColor("#678db2"));
62  qp.setColor(QPalette::HighlightedText, Qt::black);
63  setPalette(qp);
64 
65  // we handle double click on items ourselves
66  connect(this, &ElementsPanel::itemDoubleClicked, this, &ElementsPanel::slot_doubleClick);
67  connect(this, &GenericPanel::firstActivated, [this]() {QTimer::singleShot(250, this, SLOT(reload()));});
69 
70  //Emit a signal instead au manage is own context menu
71  setContextMenuPolicy(Qt::CustomContextMenu);
72 }
73 
78 }
79 
84 void ElementsPanel::startDrag(Qt::DropActions supportedActions) {
85  Q_UNUSED(supportedActions);
86 
88  if (tbt_location.isValid()) {
89  startTitleBlockTemplateDrag(tbt_location);
90  return;
91  }
92 }
93 
99  QString location_string = location.toString();
100 
101  QMimeData *mime_data = new QMimeData();
102  mime_data -> setText(location_string);
103  mime_data -> setData("application/x-qet-titleblock-uri", location_string.toLatin1());
104 
105  QDrag *drag = new QDrag(this);
106  drag -> setMimeData(mime_data);
107  drag -> setPixmap(QET::Icons::TitleBlock.pixmap(22, 16));
108  drag -> start(Qt::CopyAction);
109 }
110 
115  if (!filter_.isEmpty()) {
116  filter(filter_);
117  }
118 }
119 
126 QTreeWidgetItem *ElementsPanel::addProject(QETProject *project, QTreeWidgetItem *parent_item, PanelOptions options)
127 {
128  Q_UNUSED(parent_item)
129  Q_UNUSED(options)
130 
131  bool first_add = (first_reload_ || !projects_to_display_.contains(project));
132 
133  // create the QTreeWidgetItem representing the project
134  QTreeWidgetItem *qtwi_project = GenericPanel::addProject(project, nullptr, GenericPanel::All);
135  // the project will be inserted right before the common tb templates collection
136  invisibleRootItem() -> insertChild(
137  indexOfTopLevelItem(common_tbt_collection_item_),
138  qtwi_project
139  );
140  if (first_add) qtwi_project -> setExpanded(true);
141 
142  if (TitleBlockTemplatesCollection *tbt_collection = project -> embeddedTitleBlockTemplatesCollection()) {
143  if (QTreeWidgetItem *tbt_collection_qtwi = itemForTemplatesCollection(tbt_collection)) {
144  if (first_add) tbt_collection_qtwi -> setExpanded(true);
145  }
146  }
147 
148  qtwi_project -> setStatusTip(0, tr("Double-cliquez pour réduire ou développer ce projet", "Status tip"));
149 
150  return(qtwi_project);
151 }
152 
153 QTreeWidgetItem *ElementsPanel::updateTemplatesCollectionItem(QTreeWidgetItem *tbt_collection_qtwi, TitleBlockTemplatesCollection *tbt_collection, PanelOptions options, bool freshly_created) {
154  QTreeWidgetItem *tbtc_qtwi = GenericPanel::updateTemplatesCollectionItem(tbt_collection_qtwi, tbt_collection, options, freshly_created);
155  if (tbt_collection && tbt_collection -> parentProject()) {
156  tbtc_qtwi -> setText(0, tr("Cartouches embarqués"));
157  tbtc_qtwi -> setStatusTip(0, tr("Double-cliquez pour réduire ou développer cette collection de cartouches embarquée", "Status tip"));
158  }
159  return(tbtc_qtwi);
160 }
161 
162 QTreeWidgetItem *ElementsPanel::updateTemplateItem(QTreeWidgetItem *tb_template_qtwi, const TitleBlockTemplateLocation &tb_template, PanelOptions options, bool freshly_created) {
163  QTreeWidgetItem *item = GenericPanel::updateTemplateItem(tb_template_qtwi, tb_template, options, freshly_created);
164  item -> setStatusTip(
165  0,
166  tr(
167  "Glissez-déposez ce modèle de cartouche sur un folio pour l'y appliquer.",
168  "Status tip displayed when selecting a title block template"
169  )
170  );
171  return(item);
172 }
173 
177 bool ElementsPanel::matchesFilter(const QTreeWidgetItem *item, const QString& filter) const {
178  if (!item) return(false);
179 
180  // no filter => we consider the item matches
181  if (filter.isEmpty()) return(true);
182 
183  bool item_matches = item -> text(0).contains(filter, Qt::CaseInsensitive);
184 
185  return(item_matches);
186 }
187 
193 void ElementsPanel::reload(bool reload_collections) {
194  Q_UNUSED(reload_collections);
195 
196  QIcon system_icon(":/ico/16x16/qet.png");
197  QIcon user_icon(":/ico/16x16/go-home.png");
198 
199  // load the common title block templates collection
201  common_tbt_collection_item_ = addTemplatesCollection(common_tbt_collection, invisibleRootItem());
202  common_tbt_collection_item_ -> setIcon(0, system_icon);
203  common_tbt_collection_item_ -> setStatusTip(0, tr("Double-cliquez pour réduire ou développer la collection de cartouches QElectroTech", "Status tip"));
204  common_tbt_collection_item_ -> setWhatsThis(0, tr("Ceci est la collection de cartouches fournie avec QElectroTech. Installée en tant que composant système, vous ne pouvez normalement pas la personnaliser.", "\"What's this\" tip"));
205  if (first_reload_) common_tbt_collection_item_ -> setExpanded(true);
206 
207  // load the custom title block templates collection
209  custom_tbt_collection_item_ = addTemplatesCollection(custom_tbt_collection, invisibleRootItem());
210  custom_tbt_collection_item_ -> setIcon(0, user_icon);
211  custom_tbt_collection_item_ -> setStatusTip(0, tr("Double-cliquez pour réduire ou développer votre collection personnelle de cartouches", "Status tip"));
212  custom_tbt_collection_item_ -> setWhatsThis(0, tr("Ceci est votre collection personnelle de cartouches -- utilisez-la pour créer, stocker et éditer vos propres cartouches.", "\"What's this\" tip"));
213  if (first_reload_) custom_tbt_collection_item_ -> setExpanded(true);
214 
215  // add projects
216  foreach(QETProject *project, projects_to_display_.values()) {
217  addProject(project);
218  }
219 
220  // the first time, expand the first level of collections
221  if (first_reload_) first_reload_ = false;
222 }
223 
232 void ElementsPanel::slot_doubleClick(QTreeWidgetItem *qtwi, int) {
233  int qtwi_type = qtwi -> type();
234  if (qtwi_type == QET::Project) {
235  QETProject *project = valueForItem<QETProject *>(qtwi);
236  emit(requestForProject(project));
237  } else if (qtwi_type == QET::Diagram) {
238  Diagram *diagram = valueForItem<Diagram *>(qtwi);
239  emit(requestForDiagram(diagram));
240  } else if (qtwi_type == QET::TitleBlockTemplate) {
241  TitleBlockTemplateLocation tbt = valueForItem<TitleBlockTemplateLocation>(qtwi);
242  emit(requestForTitleBlockTemplate(tbt));
243  }
244 }
245 
250 QString ElementsPanel::dirPathForItem(QTreeWidgetItem *item) {
251  QString file_path = filePathForItem(item);
252  if (!file_path.isEmpty()) {
253  QFileInfo path_info(file_path);
254  if (path_info.isDir()) {
255  return(file_path);
256  }
257  else {
258  return(path_info.canonicalPath());
259  }
260  }
261  return(QString());
262 }
263 
268 QString ElementsPanel::filePathForItem(QTreeWidgetItem *item) {
269  if (!item) return(QString());
270 
272  TitleBlockTemplatesCollection *tbt_collection = tbt_location.parentCollection();
273  if (tbt_collection && tbt_collection -> hasFilePath()) {
274  return(tbt_collection -> filePath());
275  }
276  else {
277  QETProject *project = projectForItem(item);
278  if (project) {
279  return(project -> filePath());
280  }
281  }
282  return(QString());
283 }
284 
294 void ElementsPanel::filter(const QString &m, QET::Filtering filtering) {
295  QList<QTreeWidgetItem *> items = findItems("*", Qt::MatchRecursive | Qt::MatchWildcard);
296  const int expanded_role = 42; // magic number? So you consider Douglas Adams wrote about magic?
297 
298  if (filtering == QET::BeginFilter) {
299  foreach (QTreeWidgetItem *item, items) {
300  item -> setData(0, expanded_role, item -> isExpanded());
301  }
302  }
303 
304  if (filtering != QET::EndFilter) {
305  filter_ = m;
306  applyCurrentFilter(items);
307  } else { // filtering == QET::EndFilter
308  filter_ = QString();
309  QTreeWidgetItem *current_item = currentItem();
310 
311  // restore the tree as it was before the filtering
312  foreach (QTreeWidgetItem *qtwi, items) {
313  qtwi -> setHidden(false);
314  qtwi -> setExpanded(qtwi -> data(0, expanded_role).toBool());
315  }
316 
317  // avoid hiding the currently selected item
318  if (current_item) {
319  ensureHierarchyIsVisible(QList<QTreeWidgetItem *>() << current_item);
320  scrollToItem(current_item);
321  }
322  }
323 }
324 
330  addProject(project);
331  projects_to_display_ << project;
332  emit(panelContentChanged());
333 }
334 
340  if (QTreeWidgetItem *item_to_remove = itemForProject(project)) {
341  GenericPanel::deleteItem(item_to_remove);
342  projects_to_display_.remove(project);
343  }
344  emit(panelContentChanged());
345 }
346 
351  if (filter_.isEmpty()) return;
352  filter_list_ = filter_.split( '+' );
353  /*
354  qDebug() << "*******************";
355  foreach( QString filter , filter_list_ ) {
356  filter = filter.trimmed();
357  qDebug() << filter;
358  }
359  */
360 }
361 
365 void ElementsPanel::applyCurrentFilter(const QList<QTreeWidgetItem *> &items) {
366  if (filter_.isEmpty()) return;
367  buildFilterList();
368  QList<QTreeWidgetItem *> matching_items;
369 
370  foreach (QTreeWidgetItem *item, items) {
371  bool item_matches = true;
372 
373  foreach( QString filter , filter_list_ ) {
374  filter = filter.trimmed();
375  if ( !filter.isEmpty() ) {
376  item_matches &= matchesFilter(item, filter);
377  }
378  }
379  if (item_matches) matching_items << item;
380  item -> setHidden(!item_matches);
381  }
382  ensureHierarchyIsVisible(matching_items);
383 }
384 
389 void ElementsPanel::ensureHierarchyIsVisible(const QList<QTreeWidgetItem *> &items) {
390  // remonte l'arborescence pour lister les categories contenant les elements filtres
391  QSet<QTreeWidgetItem *> parent_items;
392  foreach(QTreeWidgetItem *item, items) {
393  for (QTreeWidgetItem *parent_qtwi = item -> parent() ; parent_qtwi ; parent_qtwi = parent_qtwi -> parent()) {
394  parent_items << parent_qtwi;
395  }
396  }
397 
398  // etend les parents
399  foreach(QTreeWidgetItem *parent_qtwi, parent_items) {
400  if (!parent_qtwi -> isExpanded()) parent_qtwi -> setExpanded(true);
401  }
402 
403  // affiche les parents
404  foreach(QTreeWidgetItem *parent_qtwi, parent_items) {
405  if (parent_qtwi -> isHidden()) parent_qtwi -> setHidden(false);
406  }
407 }
static TitleBlockTemplatesFilesCollection * commonTitleBlockTemplatesCollection()
Definition: qetapp.cpp:448
QStringList filter_list_
Currently applied list of filter.
Definition: elementspanel.h:88
void panelContentChanged()
ElementsPanel(QWidget *=nullptr)
void requestForDiagram(Diagram *)
QTreeWidgetItem * addProject(QETProject *, QTreeWidgetItem *=nullptr, PanelOptions=AddAllChild) override
virtual QTreeWidgetItem * addProject(QETProject *, QTreeWidgetItem *=nullptr, PanelOptions=AddAllChild)
virtual QTreeWidgetItem * itemForProject(QETProject *)
void slot_doubleClick(QTreeWidgetItem *, int)
QString dirPathForItem(QTreeWidgetItem *)
void startTitleBlockTemplateDrag(const TitleBlockTemplateLocation &)
void projectWasOpened(QETProject *)
virtual TitleBlockTemplateLocation templateLocationForItem(QTreeWidgetItem *) const
bool first_reload_
used to distinguish the first time this panel is reloaded
Definition: elementspanel.h:86
virtual QTreeWidgetItem * updateTemplatesCollectionItem(QTreeWidgetItem *, TitleBlockTemplatesCollection *, PanelOptions=AddAllChild, bool=false)
virtual void deleteItem(QTreeWidgetItem *, bool=false)
QTreeWidgetItem * custom_tbt_collection_item_
pointer to the item representing the user templates collection
Definition: elementspanel.h:85
void filter(const QString &, QET::Filtering=QET::RegularFilter)
void requestForTitleBlockTemplate(const TitleBlockTemplateLocation &)
virtual TitleBlockTemplateLocation selectedTemplateLocation() const
QIcon TitleBlock
Definition: qeticons.cpp:165
~ElementsPanel() override
void projectWasClosed(QETProject *)
static TitleBlockTemplatesFilesCollection * customTitleBlockTemplatesCollection()
Definition: qetapp.cpp:462
virtual QTreeWidgetItem * addTemplatesCollection(TitleBlockTemplatesCollection *, QTreeWidgetItem *=nullptr, PanelOptions=AddAllChild)
void ensureHierarchyIsVisible(const QList< QTreeWidgetItem *> &)
void requestForProject(QETProject *)
bool matchesFilter(const QTreeWidgetItem *, const QString &) const
virtual QETProject * projectForItem(QTreeWidgetItem *) const
QString filePathForItem(QTreeWidgetItem *)
QTreeWidgetItem * updateTemplateItem(QTreeWidgetItem *, const TitleBlockTemplateLocation &, PanelOptions, bool=false) override
QIcon tr
Definition: qeticons.cpp:204
virtual QTreeWidgetItem * updateTemplateItem(QTreeWidgetItem *, const TitleBlockTemplateLocation &, PanelOptions=AddAllChild, bool=false)
void startDrag(Qt::DropActions) override
void reload(bool=false)
ElementsPanel::reload Reload the elements tree.
void applyCurrentFilter(const QList< QTreeWidgetItem *> &)
void buildFilterList()
QSet< QETProject * > projects_to_display_
list of projects that have been added to this panel
Definition: elementspanel.h:83
bool firstActivated()
QString filter_
Currently applied filter.
Definition: elementspanel.h:87
void panelContentChange()
TitleBlockTemplatesCollection * parentCollection() const
virtual QTreeWidgetItem * itemForTemplatesCollection(TitleBlockTemplatesCollection *)
Filtering
Definition: qet.h:114
QTreeWidgetItem * common_tbt_collection_item_
pointer to the item representing the common templates collection
Definition: elementspanel.h:84
QTreeWidgetItem * updateTemplatesCollectionItem(QTreeWidgetItem *, TitleBlockTemplatesCollection *, PanelOptions=AddAllChild, bool=false) override