All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
LayerTreeView.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib 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 Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/qt/widgets/layer/explorer/LayerTreeView.cpp
22 
23  \brief A tree view for the layers of an application.
24 */
25 
26 // TerraLib
27 #include "AbstractTreeItem.h"
28 #include "LayerTreeModel.h"
29 #include "LayerTreeView.h"
30 
31 // STL
32 #include <map>
33 
34 // Boost
35 #include <boost/tuple/tuple.hpp>
36 
37 // Qt
38 #include <QDragEnterEvent>
39 #include <QDragLeaveEvent>
40 #include <QDragMoveEvent>
41 #include <QDropEvent>
42 #include <QMenu>
43 #include <QMessageBox>
44 #include <QMimeData>
45 #include <QUrl>
46 
47 /*!
48  \class te::qt::widgets::LayerTreeView::Impl
49 
50  \brief LayerTreeView implementation.
51 */
53 {
54  public:
55 
56  typedef boost::tuple<QAction*, std::string, std::string, te::qt::widgets::LayerTreeView::ContextMenuSelectionType, bool> tuple_type;
57 
59  : m_ltv(ltv)
60  {
61  }
62 
63  void add(QAction* action,
64  const std::string& menu,
65  const std::string& layerType,
67  {
68  m_menus.push_back(tuple_type(action, menu, layerType, menuSelectionType));
69  }
70 
71  void remove(QAction* action)
72  {
73  std::list<tuple_type>::iterator it = m_menus.begin();
74 
75  while(it != m_menus.end())
76  {
77  if(it->get<0>() == action)
78  {
79  std::list<tuple_type>::iterator auxit = it;
80  ++it;
81  m_menus.erase(auxit);
82  }
83  else
84  {
85  ++it;
86  }
87  }
88  }
89 
90  void showContextMenu(const QPoint& pos)
91  {
92  QMenu menu(m_ltv);
93 
94  std::list<AbstractTreeItem*> selectedItems = m_ltv->getSelectedItems();
95 
96  if(selectedItems.empty())
97  {
98  // if no items were selected, we only show the NO_ITEM_SELECTED actions
99  for(std::list<tuple_type>::const_iterator it = m_menus.begin(); it != m_menus.end(); ++it)
100  {
101  QAction* action = it->get<0>();
102  te::qt::widgets::LayerTreeView::ContextMenuSelectionType menuSelectionType = it->get<3>();
103 
104  if(menuSelectionType == te::qt::widgets::LayerTreeView::NO_ITEM_SELECTED)
105  menu.addAction(action);
106  }
107  }
108  else if(selectedItems.size() == 1)
109  {
110  // If just one item is selected we show their actions
111  te::qt::widgets::AbstractTreeItem* selectedItem = selectedItems.front();
112 
113  te::map::AbstractLayerPtr layer = selectedItem->getLayer();
114 
115  // Get the type of the selected item
116  std::string selectedItemType;
117 
118  if(layer && !layer->isValid())
119  selectedItemType = "INVALID_LAYER_ITEM";
120  else if(layer && layer->getSchema().get() && layer->getSchema()->hasRaster())
121  selectedItemType = "RASTER_LAYER_ITEM";
122  else
123  selectedItemType = selectedItem->getItemType();
124 
125  std::list<tuple_type>::const_iterator it;
126  for(it = m_menus.begin(); it != m_menus.end(); ++it)
127  {
128  QAction* action = it->get<0>();
129  std::string aItemType = it->get<2>();
130  te::qt::widgets::LayerTreeView::ContextMenuSelectionType menuSelectionType = it->get<3>();
131 
133  continue;
134 
135  if(!layer)
136  {
137  if((selectedItemType == "GROUPING_ITEM" || selectedItemType == "CHART_ITEM" || selectedItemType == "COLORMAP_ITEM") &&
138  aItemType == "ITEM_OF_LAYER")
139  {
140  menu.addAction(action);
141  }
142 
143  continue;
144  }
145 
146  if(selectedItemType == "RASTER_LAYER_ITEM" || selectedItemType == "FOLDER_LAYER_ITEM" || selectedItemType == "INVALID_LAYER_ITEM")
147  {
148  if(aItemType == selectedItemType)
149  menu.addAction(action);
150  }
151  else
152  {
153  if(aItemType.empty() || aItemType == selectedItemType)
154  menu.addAction(action);
155  }
156  }
157  }
158  else
159  {
160  // If more than one layer is selected we must look for common actions depending on the layer types
161  std::map<std::string, std::vector<QAction*> > actionsByLayerType;
162 
163  // Determine the layer types
164  std::string layerType;
165 
166  std::list<AbstractTreeItem*>::const_iterator it;
167  for(it = selectedItems.begin(); it != selectedItems.end(); ++it)
168  {
169  te::map::AbstractLayerPtr layer = (*it)->getLayer();
170  if(!layer)
171  return;
172 
173  if(!layer->isValid())
174  layerType = "INVALID_LAYER_ITEM";
175  else if(layer->getSchema().get() && layer->getSchema()->hasRaster())
176  layerType = "RASTER_LAYER_ITEM";
177  else
178  layerType = (*it)->getItemType();
179 
180  actionsByLayerType[layerType] = std::vector<QAction*>();
181  }
182 
183  // add actions to each group
184  for(std::list<tuple_type>::const_iterator it = m_menus.begin(); it != m_menus.end(); ++it)
185  {
186  QAction* action = it->get<0>();
187  std::string alayerType = it->get<2>();
188  te::qt::widgets::LayerTreeView::ContextMenuSelectionType menuSelectionType = it->get<3>();
189 
191  continue;
192 
193  layerType = alayerType;
194 
195  if(layerType.empty())
196  {
197  for(std::map<std::string, std::vector<QAction*> >::iterator it = actionsByLayerType.begin();
198  it != actionsByLayerType.end(); ++it)
199  {
200  it->second.push_back(action);
201  }
202  }
203  else
204  actionsByLayerType[layerType].push_back(action);
205  }
206 
207  // determine the common list of actions
208  std::vector<std::vector<QAction*> > setVec;
209 
210  for(std::map<std::string, std::vector<QAction*> >::iterator it = actionsByLayerType.begin();
211  it != actionsByLayerType.end(); ++it)
212  {
213  setVec.push_back(it->second);
214  }
215 
216  if(setVec.empty())
217  return;
218 
219  std::vector<QAction*> commonActions = setVec[0];
220  std::sort(commonActions.begin(), commonActions.end());
221 
222  for(std::size_t i = 1; i < setVec.size(); ++i)
223  {
224  std::sort(setVec[i].begin(), setVec[i].end());
225 
226  std::vector<QAction*> intersect;
227  std::set_intersection(commonActions.begin(), commonActions.end(),
228  setVec[i].begin(), setVec[i].end(),
229  std::inserter(intersect, intersect.begin()));
230 
231  commonActions = intersect;
232  }
233 
234  // add the actions to the popup menu
235  for(std::size_t i = 0; i < commonActions.size(); ++ i)
236  menu.addAction(commonActions[i]);
237  }
238 
239  menu.exec(pos);
240  }
241 
242  private:
243 
244  std::list<tuple_type> m_menus; //!< A list of information about context menus.
245  te::qt::widgets::LayerTreeView* m_ltv; //!< The layer tree view associated to this implementation.
246 };
247 
249  : QTreeView(parent),
250  m_pImpl(0)
251 {
252  setAcceptDrops(true);
253  setDragEnabled(true);
254 
255  setDefaultDropAction(Qt::MoveAction);
256 
257  setRootIsDecorated(true);
258  setSelectionMode(QAbstractItemView::ExtendedSelection);
259 
260  viewport()->setAutoFillBackground(true);
261 
262  // Signals and slots
263  connect(this, SIGNAL(activated(const QModelIndex&)), SLOT(onItemActivated(const QModelIndex&)));
264  connect(this, SIGNAL(clicked(const QModelIndex&)), SLOT(onItemClicked(const QModelIndex&)));
265  connect(this, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(onItemDoubleClicked(const QModelIndex&)));
266  connect(this, SIGNAL(entered(const QModelIndex&)), SLOT(onItemEntered(const QModelIndex&)));
267  connect(this, SIGNAL(pressed(const QModelIndex&)), SLOT(onItemPressed(const QModelIndex&)));
268 
269  m_pImpl = new Impl(this);
270 }
271 
273 {
274  delete m_pImpl;
275 }
276 
277 std::list<te::qt::widgets::AbstractTreeItem*> te::qt::widgets::LayerTreeView::getSelectedItems() const
278 {
279  std::list<AbstractTreeItem*> selectedItems;
280 
281  QModelIndexList indexes = selectedIndexes();
282 
283  QModelIndex idx;
284 
285  foreach(idx, indexes)
286  {
287  AbstractTreeItem* selectedItem = static_cast<AbstractTreeItem*>(idx.internalPointer());
288 
289  if(selectedItem)
290  selectedItems.push_back(selectedItem);
291  }
292 
293  return selectedItems;
294 }
295 
296 std::list<te::qt::widgets::AbstractTreeItem*> te::qt::widgets::LayerTreeView::getSelectedLayerItems() const
297 {
298  std::list<te::qt::widgets::AbstractTreeItem*> selectedItems = getSelectedItems();
299 
300  std::list<te::qt::widgets::AbstractTreeItem*> selectedLayerItems;
301 
302  std::list<te::qt::widgets::AbstractTreeItem*>::const_iterator it;
303  for(it = selectedItems.begin(); it != selectedItems.end(); ++it)
304  {
305  te::qt::widgets::AbstractTreeItem* selectedItem = *it;
306 
307  if(selectedItem->getLayer())
308  selectedLayerItems.push_back(selectedItem);
309  }
310 
311  return selectedLayerItems;
312 }
313 
314 std::list<te::qt::widgets::AbstractTreeItem*> te::qt::widgets::LayerTreeView::getSelectedSingleLayerItems() const
315 {
316  std::list<te::qt::widgets::AbstractTreeItem*> selectedLayerItems = getSelectedLayerItems();
317 
318  std::list<te::qt::widgets::AbstractTreeItem*> selectedSingleLayerItems;
319 
320  std::list<te::qt::widgets::AbstractTreeItem*>::const_iterator it;
321  for(it = selectedLayerItems.begin(); it != selectedLayerItems.end(); ++it)
322  {
323  te::qt::widgets::AbstractTreeItem* selectedLayerItem = *it;
324 
325  if(selectedLayerItem->getLayer() && selectedLayerItem->getItemType() != "FOLDER_LAYER_ITEM")
326  selectedSingleLayerItems.push_back(selectedLayerItem);
327  }
328 
329  return selectedSingleLayerItems;
330 }
331 
332 std::list<te::map::AbstractLayerPtr> te::qt::widgets::LayerTreeView::getSelectedSingleLayers() const
333 {
334  std::list<te::map::AbstractLayerPtr> selectedSingleLayers;
335 
336  std::list<te::qt::widgets::AbstractTreeItem*> selectedItems = getSelectedItems();
337 
338  std::list<te::qt::widgets::AbstractTreeItem*>::const_iterator it;
339  for(it = selectedItems.begin(); it != selectedItems.end(); ++it)
340  {
341  te::map::AbstractLayerPtr layer = (*it)->getLayer();
342 
343  if(layer && layer->getType() != "FOLDERLAYER")
344  selectedSingleLayers.push_back(layer);
345  }
346 
347  return selectedSingleLayers;
348 }
349 
350 std::list<te::map::AbstractLayerPtr> te::qt::widgets::LayerTreeView::getSelectedAndVisibleSingleLayers() const
351 {
352  std::list<te::map::AbstractLayerPtr> selectedAndVisibleSingleLayers;
353 
354  std::list<te::map::AbstractLayerPtr> selectedSingleLayers = getSelectedSingleLayers();
355 
356  std::list<te::map::AbstractLayerPtr>::const_iterator it;
357  for(it = selectedSingleLayers.begin(); it != selectedSingleLayers.end(); ++it)
358  {
359  te::map::AbstractLayerPtr layer = *it;
360  if(layer->getVisibility() == te::map::VISIBLE)
361  selectedAndVisibleSingleLayers.push_back(layer);
362  }
363 
364  return selectedAndVisibleSingleLayers;
365 }
366 
367 void te::qt::widgets::LayerTreeView::onSelectedLayersChanged(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/)
368 {
369  std::list<te::map::AbstractLayerPtr> selectedLayers;
370 
371  std::list<te::qt::widgets::AbstractTreeItem*> selectedItems = getSelectedItems();
372 
373  std::list<te::qt::widgets::AbstractTreeItem*>::const_iterator it;
374  for(it = selectedItems.begin(); it != selectedItems.end(); ++it)
375  {
376  te::map::AbstractLayerPtr selectedLayer = (*it)->getLayer();
377 
378  if(selectedLayer)
379  selectedLayers.push_back(selectedLayer);
380  }
381 
382  if(!selectedLayers.empty())
383  emit selectedLayersChanged(selectedLayers);
384 }
385 
387  const std::string& menu,
388  const std::string& itemType,
389  ContextMenuSelectionType menuSelectionType)
390 {
391  m_pImpl->add(action, menu, itemType, menuSelectionType);
392 }
393 
395 {
396  m_pImpl->remove(action);
397 }
398 
400 {
401  AbstractTreeItem* item = static_cast<AbstractTreeItem*>(index.internalPointer());
402 
403  emit activated(item);
404 }
405 
406 void te::qt::widgets::LayerTreeView::onItemClicked(const QModelIndex& index)
407 {
408  AbstractTreeItem* item = static_cast<AbstractTreeItem*>(index.internalPointer());
409 
410  emit clicked(item);
411 
412  LayerTreeModel* model = dynamic_cast<LayerTreeModel*>(this->model());
413 
414  if(model == 0)
415  return;
416 
417  if(!model->isCheckable())
418  return;
419 
420  // If the item visibility was changed, emit the signal of visibilityChanged for this item,
421  // for their descendants(if any) and for their ancestors
422  te::map::AbstractLayerPtr itemLayer = item->getLayer();
423  if((itemLayer != 0) && itemLayer->hasVisibilityChanged())
424  {
425  if(itemLayer->getType() != "FOLDERLAYER")
426  emit visibilityChanged(itemLayer);
427 
428  // For their descendants
429  std::vector<AbstractTreeItem*> descendantItems = item->getDescendants();
430  for(std::size_t i = 0; i < descendantItems.size(); ++i)
431  {
432  te::map::AbstractLayerPtr descendantLayer = descendantItems[i]->getLayer();
433 
434  if((descendantLayer != 0) && descendantLayer->hasVisibilityChanged())
435  {
436  if(descendantLayer->getType() != "FOLDERLAYER")
437  emit visibilityChanged(descendantLayer);
438  }
439  }
440 
441  // For their ancestors
442  std::vector<AbstractTreeItem*> ancestorItems = item->getAncestors();
443  for(std::size_t i = 0; i < ancestorItems.size(); ++i)
444  {
445  te::map::AbstractLayerPtr ancestorLayer = ancestorItems[i]->getLayer();
446 
447  if((ancestorLayer != 0) && ancestorLayer->hasVisibilityChanged())
448  {
449  if(ancestorLayer->getType() != "FOLDERLAYER")
450  emit visibilityChanged(ancestorLayer);
451  }
452  }
453  }
454 }
455 
457 {
458  AbstractTreeItem* item = static_cast<AbstractTreeItem*>(index.internalPointer());
459 
460  emit doubleClicked(item);
461 }
462 
463 void te::qt::widgets::LayerTreeView::onItemEntered(const QModelIndex& index)
464 {
465  AbstractTreeItem* item = static_cast<AbstractTreeItem*>(index.internalPointer());
466 
467  emit entered(item);
468 }
469 
470 void te::qt::widgets::LayerTreeView::onItemPressed(const QModelIndex& index)
471 {
472  AbstractTreeItem* item = static_cast<AbstractTreeItem*>(index.internalPointer());
473 
474  te::map::AbstractLayerPtr layer = static_cast<te::map::AbstractLayer*>(item->getLayer().get());
475 
476  if(layer)
477  layer->setVisibilityAsChanged(false);
478 
479  emit pressed(item);
480 }
481 
483 {
484  //viewport()->setStyleSheet("background-color: lightblue");
485  //viewport()->setBackgroundRole(QPalette::Highlight);
486  //e->acceptProposedAction();
487 
488  QTreeView::dragEnterEvent(e);
489 }
490 
492 {
493  if(e->keyboardModifiers() == Qt::ControlModifier)
494  e->setDropAction(Qt::CopyAction);
495  else
496  e->setDropAction(Qt::MoveAction);
497 
498  e->accept();
499 
500  QTreeView::dragMoveEvent(e);
501 }
502 
504 {
505  //viewport()->setStyleSheet("background-color: white");
506  //viewport()->setBackgroundRole(QPalette::Base);
507  //e->accept();
508 
509  QTreeView::dragLeaveEvent(e);
510 }
511 
513 {
514  //viewport()->setBackgroundRole(QPalette::Base);
515  ////viewport()->setStyleSheet("background-color: white");
516 
517  //const QMimeData* mimeData = e->mimeData();
518 
519  //if(mimeData->hasUrls())
520  //{
521  // QList<QUrl> urlList = mimeData->urls();
522 
523  // QString text;
524 
525  // for(QList<QUrl>::Iterator it = urlList.begin(); it != urlList.end(); ++it)
526  // {
527  // QString url = it->path();
528  // }
529  //}
530 
531  QTreeView::dropEvent(e);
532 }
533 
535 {
536  assert(e);
537 
538  m_pImpl->showContextMenu(e->globalPos());
539 }
A tree view for the layers of an application.
Definition: LayerTreeView.h:63
std::vector< te::qt::widgets::AbstractTreeItem * > getAncestors()
void showContextMenu(const QPoint &pos)
void dragMoveEvent(QDragMoveEvent *e)
void pressed(te::qt::widgets::AbstractTreeItem *item)
This is the base class for layers.
Definition: AbstractLayer.h:76
boost::tuple< QAction *, std::string, std::string, te::qt::widgets::LayerTreeView::ContextMenuSelectionType, bool > tuple_type
std::list< AbstractTreeItem * > getSelectedSingleLayerItems() const
It gets the single layer items that are selected in the tree view.
void add(QAction *action, const std::string &menu, const std::string &layerType, te::qt::widgets::LayerTreeView::ContextMenuSelectionType menuSelectionType)
bool isCheckable() const
It verifies if the model items are checkable or not.
The class that represents an item in a LayerTreeModel.
void onItemActivated(const QModelIndex &index)
void clicked(te::qt::widgets::AbstractTreeItem *item)
void onSelectedLayersChanged(const QItemSelection &selected, const QItemSelection &deselected)
void entered(te::qt::widgets::AbstractTreeItem *item)
virtual const std::string getItemType() const =0
It returns the item type.
void remove(QAction *action)
It removes the action from the list of context menu.
virtual te::map::AbstractLayerPtr getLayer() const =0
void doubleClicked(te::qt::widgets::AbstractTreeItem *item)
std::vector< te::qt::widgets::AbstractTreeItem * > getDescendants()
std::list< AbstractTreeItem * > getSelectedLayerItems() const
It gets the single and folder layer items that are selected in the tree view.
void onItemPressed(const QModelIndex &index)
This class defines the model used in the Qt Model/View architecture for the tree of layers...
void contextMenuEvent(QContextMenuEvent *e)
std::list< te::map::AbstractLayerPtr > getSelectedAndVisibleSingleLayers() const
It gets the single layers that are selected and visible in the tree view.
LayerTreeView implementation.
std::list< tuple_type > m_menus
A list of information about context menus.
The class that represents an item in a LayerTreeModel.
LayerTreeView(QWidget *parent=0)
Constructor.
te::qt::widgets::LayerTreeView * m_ltv
The layer tree view associated to this implementation.
void activated(te::qt::widgets::AbstractTreeItem *item)
std::list< AbstractTreeItem * > getSelectedItems() const
It gets the items that are selected in the tree view.
void dragLeaveEvent(QDragLeaveEvent *e)
void onItemDoubleClicked(const QModelIndex &index)
std::list< te::map::AbstractLayerPtr > getSelectedSingleLayers() const
It gets the single layers that are selected in the view.
A tree view for the layers of an application.
void onItemEntered(const QModelIndex &index)
void add(QAction *action, const std::string &menu="", const std::string &itemType="", ContextMenuSelectionType menuSelectionType=te::qt::widgets::LayerTreeView::UNIQUE_ITEM_SELECTED)
It adds the action to a specified menu of a given item type when a context menu is displayed...
Impl * m_pImpl
The tree view implementation.
boost::intrusive_ptr< AbstractLayer > AbstractLayerPtr
Impl(te::qt::widgets::LayerTreeView *ltv)
void dragEnterEvent(QDragEnterEvent *e)
void setVisibilityAsChanged(bool visChanged)
It sets that the status of the layer visibility is to be changed or not..
void onItemClicked(const QModelIndex &index)