All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LayerTreeView.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008-2013 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 <QtCore/QMimeData>
39 #include <QtCore/QUrl>
40 #include <QtGui/QDragEnterEvent>
41 #include <QtGui/QDragLeaveEvent>
42 #include <QtGui/QDragMoveEvent>
43 #include <QtGui/QDropEvent>
44 #include <QtGui/QMenu>
45 #include <QtGui/QMessageBox>
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->getSchema().get() && layer->getSchema()->hasRaster())
119  selectedItemType = "RASTER_LAYER_ITEM";
120  else
121  selectedItemType = selectedItem->getItemType();
122 
123  std::list<tuple_type>::const_iterator it;
124  for(it = m_menus.begin(); it != m_menus.end(); ++it)
125  {
126  QAction* action = it->get<0>();
127  std::string aItemType = it->get<2>();
128  te::qt::widgets::LayerTreeView::ContextMenuSelectionType menuSelectionType = it->get<3>();
129 
131  continue;
132 
133  if(!layer)
134  {
135  if((selectedItemType == "GROUPING_ITEM" || selectedItemType == "CHART_ITEM" || selectedItemType == "COLORMAP_ITEM") &&
136  aItemType == "ITEM_OF_LAYER")
137  {
138  menu.addAction(action);
139  }
140 
141  continue;
142  }
143 
144  if(selectedItemType == "RASTER_LAYER_ITEM" || selectedItemType == "FOLDER_LAYER_ITEM")
145  {
146  if(aItemType == selectedItemType)
147  menu.addAction(action);
148  }
149  else
150  {
151  if(aItemType.empty() || aItemType == selectedItemType)
152  menu.addAction(action);
153  }
154  }
155  }
156  else
157  {
158  // If more than one layer is selected we must look for common actions depending on the layer types
159  std::map<std::string, std::vector<QAction*> > actionsByLayerType;
160 
161  // Determine the layer types
162  std::string layerType;
163 
164  std::list<AbstractTreeItem*>::const_iterator it;
165  for(it = selectedItems.begin(); it != selectedItems.end(); ++it)
166  {
167  te::map::AbstractLayerPtr layer = (*it)->getLayer();
168  if(!layer)
169  return;
170 
171  if(layer->getSchema().get() && layer->getSchema()->hasRaster())
172  layerType = "RASTER_LAYER_ITEM";
173  else
174  layerType = (*it)->getItemType();
175 
176  actionsByLayerType[layerType] = std::vector<QAction*>();
177  }
178 
179  // add actions to each group
180  for(std::list<tuple_type>::const_iterator it = m_menus.begin(); it != m_menus.end(); ++it)
181  {
182  QAction* action = it->get<0>();
183  std::string alayerType = it->get<2>();
184  te::qt::widgets::LayerTreeView::ContextMenuSelectionType menuSelectionType = it->get<3>();
185 
187  continue;
188 
189  layerType = alayerType;
190 
191  if(layerType.empty())
192  {
193  for(std::map<std::string, std::vector<QAction*> >::iterator it = actionsByLayerType.begin();
194  it != actionsByLayerType.end(); ++it)
195  {
196  it->second.push_back(action);
197  }
198  }
199  else
200  actionsByLayerType[layerType].push_back(action);
201  }
202 
203  // determine the common list of actions
204  std::vector<std::vector<QAction*> > setVec;
205 
206  for(std::map<std::string, std::vector<QAction*> >::iterator it = actionsByLayerType.begin();
207  it != actionsByLayerType.end(); ++it)
208  {
209  setVec.push_back(it->second);
210  }
211 
212  if(setVec.empty())
213  return;
214 
215  std::vector<QAction*> commonActions = setVec[0];
216  std::sort(commonActions.begin(), commonActions.end());
217 
218  for(std::size_t i = 1; i < setVec.size(); ++i)
219  {
220  std::sort(setVec[i].begin(), setVec[i].end());
221 
222  std::vector<QAction*> intersect;
223  std::set_intersection(commonActions.begin(), commonActions.end(),
224  setVec[i].begin(), setVec[i].end(),
225  std::inserter(intersect, intersect.begin()));
226 
227  commonActions = intersect;
228  }
229 
230  // add the actions to the popup menu
231  for(std::size_t i = 0; i < commonActions.size(); ++ i)
232  menu.addAction(commonActions[i]);
233  }
234 
235  menu.exec(pos);
236  }
237 
238  private:
239 
240  std::list<tuple_type> m_menus; //!< A list of information about context menus.
241  te::qt::widgets::LayerTreeView* m_ltv; //!< The layer tree view associated to this implementation.
242 };
243 
245  : QTreeView(parent),
246  m_pImpl(0)
247 {
248  setAcceptDrops(true);
249  setDragEnabled(true);
250 
251  setDefaultDropAction(Qt::MoveAction);
252 
253  setRootIsDecorated(true);
254  setSelectionMode(QAbstractItemView::ExtendedSelection);
255 
256  viewport()->setAutoFillBackground(true);
257 
258  // Signals and slots
259  connect(this, SIGNAL(activated(const QModelIndex&)), SLOT(onItemActivated(const QModelIndex&)));
260  connect(this, SIGNAL(clicked(const QModelIndex&)), SLOT(onItemClicked(const QModelIndex&)));
261  connect(this, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(onItemDoubleClicked(const QModelIndex&)));
262  connect(this, SIGNAL(entered(const QModelIndex&)), SLOT(onItemEntered(const QModelIndex&)));
263  connect(this, SIGNAL(pressed(const QModelIndex&)), SLOT(onItemPressed(const QModelIndex&)));
264 
265  m_pImpl = new Impl(this);
266 }
267 
269 {
270  delete m_pImpl;
271 }
272 
273 std::list<te::qt::widgets::AbstractTreeItem*> te::qt::widgets::LayerTreeView::getSelectedItems() const
274 {
275  std::list<AbstractTreeItem*> selectedItems;
276 
277  QModelIndexList indexes = selectedIndexes();
278 
279  QModelIndex idx;
280 
281  foreach(idx, indexes)
282  {
283  AbstractTreeItem* selectedItem = static_cast<AbstractTreeItem*>(idx.internalPointer());
284 
285  if(selectedItem)
286  selectedItems.push_back(selectedItem);
287  }
288 
289  return selectedItems;
290 }
291 
292 std::list<te::qt::widgets::AbstractTreeItem*> te::qt::widgets::LayerTreeView::getSelectedLayerItems() const
293 {
294  std::list<te::qt::widgets::AbstractTreeItem*> selectedItems = getSelectedItems();
295 
296  std::list<te::qt::widgets::AbstractTreeItem*> selectedLayerItems;
297 
298  std::list<te::qt::widgets::AbstractTreeItem*>::const_iterator it;
299  for(it = selectedItems.begin(); it != selectedItems.end(); ++it)
300  {
301  te::qt::widgets::AbstractTreeItem* selectedItem = *it;
302 
303  if(selectedItem->getLayer())
304  selectedLayerItems.push_back(selectedItem);
305  }
306 
307  return selectedLayerItems;
308 }
309 
310 std::list<te::qt::widgets::AbstractTreeItem*> te::qt::widgets::LayerTreeView::getSelectedSingleLayerItems() const
311 {
312  std::list<te::qt::widgets::AbstractTreeItem*> selectedLayerItems = getSelectedLayerItems();
313 
314  std::list<te::qt::widgets::AbstractTreeItem*> selectedSingleLayerItems;
315 
316  std::list<te::qt::widgets::AbstractTreeItem*>::const_iterator it;
317  for(it = selectedLayerItems.begin(); it != selectedLayerItems.end(); ++it)
318  {
319  te::qt::widgets::AbstractTreeItem* selectedLayerItem = *it;
320 
321  if(selectedLayerItem->getLayer() && selectedLayerItem->getItemType() != "FOLDER_ITEM_TYPE")
322  selectedSingleLayerItems.push_back(selectedLayerItem);
323  }
324 
325  return selectedSingleLayerItems;
326 }
327 
328 std::list<te::map::AbstractLayerPtr> te::qt::widgets::LayerTreeView::getSelectedSingleLayers() const
329 {
330  std::list<te::map::AbstractLayerPtr> selectedSingleLayers;
331 
332  std::list<te::qt::widgets::AbstractTreeItem*> selectedItems = getSelectedItems();
333 
334  std::list<te::qt::widgets::AbstractTreeItem*>::const_iterator it;
335  for(it = selectedItems.begin(); it != selectedItems.end(); ++it)
336  {
337  AbstractTreeItem* item = *it;
338 
339  te::map::AbstractLayerPtr layer = (*it)->getLayer();
340 
341  if(layer && layer->getType() != "FOLDERLAYER")
342  selectedSingleLayers.push_back(layer);
343  }
344 
345  return selectedSingleLayers;
346 }
347 
348 std::list<te::map::AbstractLayerPtr> te::qt::widgets::LayerTreeView::getSelectedAndVisibleSingleLayers() const
349 {
350  std::list<te::map::AbstractLayerPtr> selectedAndVisibleSingleLayers;
351 
352  std::list<te::map::AbstractLayerPtr> selectedSingleLayers = getSelectedSingleLayers();
353 
354  std::list<te::map::AbstractLayerPtr>::const_iterator it;
355  for(it = selectedSingleLayers.begin(); it != selectedSingleLayers.end(); ++it)
356  {
357  te::map::AbstractLayerPtr layer = *it;
358  if(layer->getVisibility() == te::map::VISIBLE)
359  selectedAndVisibleSingleLayers.push_back(layer);
360  }
361 
362  return selectedAndVisibleSingleLayers;
363 }
364 
365 void te::qt::widgets::LayerTreeView::onSelectedLayersChanged(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/)
366 {
367  std::list<te::map::AbstractLayerPtr> selectedLayers;
368 
369  std::list<te::qt::widgets::AbstractTreeItem*> selectedItems = getSelectedItems();
370 
371  std::list<te::qt::widgets::AbstractTreeItem*>::const_iterator it;
372  for(it = selectedItems.begin(); it != selectedItems.end(); ++it)
373  {
374  te::map::AbstractLayerPtr selectedLayer = (*it)->getLayer();
375 
376  if(selectedLayer)
377  selectedLayers.push_back(selectedLayer);
378  }
379 
380  if(!selectedLayers.empty())
381  emit selectedLayersChanged(selectedLayers);
382 }
383 
385  const std::string& menu,
386  const std::string& itemType,
387  ContextMenuSelectionType menuSelectionType)
388 {
389  m_pImpl->add(action, menu, itemType, menuSelectionType);
390 }
391 
393 {
394  m_pImpl->remove(action);
395 }
396 
398 {
399  AbstractTreeItem* item = static_cast<AbstractTreeItem*>(index.internalPointer());
400 
401  emit activated(item);
402 }
403 
404 void te::qt::widgets::LayerTreeView::onItemClicked(const QModelIndex& index)
405 {
406  AbstractTreeItem* item = static_cast<AbstractTreeItem*>(index.internalPointer());
407 
408  emit clicked(item);
409 
410  LayerTreeModel* model = dynamic_cast<LayerTreeModel*>(this->model());
411 
412  if(model == 0)
413  return;
414 
415  if(!model->isCheckable())
416  return;
417 
418  // If the item visibility was changed, emit the signal of visibilityChanged for this item,
419  // for their descendants(if any) and for their ancestors
420  te::map::AbstractLayerPtr itemLayer = item->getLayer();
421  if((itemLayer != 0) && itemLayer->hasVisibilityChanged())
422  {
423  if(itemLayer->getType() != "FOLDERLAYER")
424  emit visibilityChanged(itemLayer);
425 
426  // For their descendants
427  std::vector<AbstractTreeItem*> descendantItems = item->getDescendants();
428  for(std::size_t i = 0; i < descendantItems.size(); ++i)
429  {
430  te::map::AbstractLayerPtr descendantLayer = descendantItems[i]->getLayer();
431 
432  if((descendantLayer != 0) && descendantLayer->hasVisibilityChanged())
433  {
434  if(descendantLayer->getType() != "FOLDERLAYER")
435  emit visibilityChanged(descendantLayer);
436  }
437  }
438 
439  // For their ancestors
440  std::vector<AbstractTreeItem*> ancestorItems = item->getAncestors();
441  for(std::size_t i = 0; i < ancestorItems.size(); ++i)
442  {
443  te::map::AbstractLayerPtr ancestorLayer = ancestorItems[i]->getLayer();
444 
445  if((ancestorLayer != 0) && ancestorLayer->hasVisibilityChanged())
446  {
447  if(ancestorLayer->getType() != "FOLDERLAYER")
448  emit visibilityChanged(ancestorLayer);
449  }
450  }
451  }
452 }
453 
455 {
456  AbstractTreeItem* item = static_cast<AbstractTreeItem*>(index.internalPointer());
457 
458  emit doubleClicked(item);
459 }
460 
461 void te::qt::widgets::LayerTreeView::onItemEntered(const QModelIndex& index)
462 {
463  AbstractTreeItem* item = static_cast<AbstractTreeItem*>(index.internalPointer());
464 
465  emit entered(item);
466 }
467 
468 void te::qt::widgets::LayerTreeView::onItemPressed(const QModelIndex& index)
469 {
470  AbstractTreeItem* item = static_cast<AbstractTreeItem*>(index.internalPointer());
471 
472  te::map::AbstractLayerPtr layer = static_cast<te::map::AbstractLayer*>(item->getLayer().get());
473 
474  if(layer)
475  layer->setVisibilityAsChanged(false);
476 
477  emit pressed(item);
478 }
479 
481 {
482  //viewport()->setStyleSheet("background-color: lightblue");
483  //viewport()->setBackgroundRole(QPalette::Highlight);
484  //e->acceptProposedAction();
485 
486  QTreeView::dragEnterEvent(e);
487 }
488 
490 {
491  if(e->keyboardModifiers() == Qt::ControlModifier)
492  e->setDropAction(Qt::CopyAction);
493  else
494  e->setDropAction(Qt::MoveAction);
495 
496  e->accept();
497 
498  QTreeView::dragMoveEvent(e);
499 }
500 
502 {
503  //viewport()->setStyleSheet("background-color: white");
504  //viewport()->setBackgroundRole(QPalette::Base);
505  //e->accept();
506 
507  QTreeView::dragLeaveEvent(e);
508 }
509 
511 {
512  //viewport()->setBackgroundRole(QPalette::Base);
513  ////viewport()->setStyleSheet("background-color: white");
514 
515  //const QMimeData* mimeData = e->mimeData();
516 
517  //if(mimeData->hasUrls())
518  //{
519  // QList<QUrl> urlList = mimeData->urls();
520 
521  // QString text;
522 
523  // for(QList<QUrl>::Iterator it = urlList.begin(); it != urlList.end(); ++it)
524  // {
525  // QString url = it->path();
526  // }
527  //}
528 
529  QTreeView::dropEvent(e);
530 }
531 
533 {
534  assert(e);
535 
536  m_pImpl->showContextMenu(e->globalPos());
537 }
std::list< tuple_type > m_menus
A list of information about context menus.
void clicked(te::qt::widgets::AbstractTreeItem *item)
virtual te::map::AbstractLayerPtr getLayer() const =0
void contextMenuEvent(QContextMenuEvent *e)
void onItemClicked(const QModelIndex &index)
std::list< AbstractTreeItem * > getSelectedLayerItems() const
It gets the single and folder layer items that are selected in the tree view.
LayerTreeView implementation.
boost::tuple< QAction *, std::string, std::string, te::qt::widgets::LayerTreeView::ContextMenuSelectionType, bool > tuple_type
This is the base class for layers.
Definition: AbstractLayer.h:76
std::list< AbstractTreeItem * > getSelectedSingleLayerItems() const
It gets the single layer items that are selected in the tree view.
void onSelectedLayersChanged(const QItemSelection &selected, const QItemSelection &deselected)
std::list< AbstractTreeItem * > getSelectedItems() const
It gets the items that are selected in the tree view.
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...
void setVisibilityAsChanged(bool visChanged)
It sets that the status of the layer visibility is to be changed or not..
void activated(te::qt::widgets::AbstractTreeItem *item)
void onItemDoubleClicked(const QModelIndex &index)
void remove(QAction *action)
It removes the action from the list of context menu.
virtual const std::string getItemType() const =0
It returns the item type.
std::list< te::map::AbstractLayerPtr > getSelectedAndVisibleSingleLayers() const
It gets the single layers that are selected and visible in the tree view.
std::list< te::map::AbstractLayerPtr > getSelectedSingleLayers() const
It gets the single layers that are selected in the view.
Impl(te::qt::widgets::LayerTreeView *ltv)
void dragEnterEvent(QDragEnterEvent *e)
te::qt::widgets::LayerTreeView * m_ltv
The layer tree view associated to this implementation.
void onItemPressed(const QModelIndex &index)
void entered(te::qt::widgets::AbstractTreeItem *item)
std::vector< te::qt::widgets::AbstractTreeItem * > getAncestors()
A tree view for the layers of an application.
Definition: LayerTreeView.h:63
void showContextMenu(const QPoint &pos)
void dragMoveEvent(QDragMoveEvent *e)
Impl * m_pImpl
The tree view implementation.
void dragLeaveEvent(QDragLeaveEvent *e)
The class that represents an item in a LayerTreeModel.
This class defines the model used in the Qt Model/View architecture for the tree of layers...
void pressed(te::qt::widgets::AbstractTreeItem *item)
void onItemEntered(const QModelIndex &index)
void add(QAction *action, const std::string &menu, const std::string &layerType, te::qt::widgets::LayerTreeView::ContextMenuSelectionType menuSelectionType)
boost::intrusive_ptr< AbstractLayer > AbstractLayerPtr
std::vector< te::qt::widgets::AbstractTreeItem * > getDescendants()
bool isCheckable() const
It verifies if the model items are checkable or not.
void onItemActivated(const QModelIndex &index)
void doubleClicked(te::qt::widgets::AbstractTreeItem *item)
LayerTreeView(QWidget *parent=0)
Constructor.
A tree view for the layers of an application.
The class that represents an item in a LayerTreeModel.