USGS

Isis 3.0 Object Programmers' Reference

Home

ImageTreeWidget.cpp
1 #include "ImageTreeWidget.h"
2 
3 #include <algorithm>
4 
5 #include <QAction>
6 #include <QApplication>
7 #include <QDebug>
8 #include <QDropEvent>
9 #include <QMenu>
10 #include <QProgressBar>
11 #include <QSettings>
12 #include <QScrollBar>
13 #include <QTime>
14 
15 #include "Directory.h"
16 #include "IException.h"
17 #include "Image.h"
18 #include "ImageDisplayProperties.h"
19 #include "ImageList.h"
20 #include "ImageTreeWidgetItem.h"
21 #include "ProgressBar.h"
22 
23 namespace Isis {
24 
33  m_queuedSelectionChanged = false;
34  m_directory = directory;
35 
36  QStringList header;
37 
38  ImageTreeWidgetItem::TreeColumn col = ImageTreeWidgetItem::NameColumn;
39  while(col < ImageTreeWidgetItem::BlankColumn) {
40  header << ImageTreeWidgetItem::treeColumnToString(col);
41  col = (ImageTreeWidgetItem::TreeColumn)(col + 1);
42  }
43 
44  setHeaderLabels(header);
45 
46  hideColumn(ImageTreeWidgetItem::ImageColumn);
47  hideColumn(ImageTreeWidgetItem::LabelColumn);
48  hideColumn(ImageTreeWidgetItem::ResolutionColumn);
49  hideColumn(ImageTreeWidgetItem::EmissionAngleColumn);
50  hideColumn(ImageTreeWidgetItem::IncidenceAngleColumn);
51  hideColumn(ImageTreeWidgetItem::PhaseAngleColumn);
52  hideColumn(ImageTreeWidgetItem::AspectRatioColumn);
53  hideColumn(ImageTreeWidgetItem::SampleResolutionColumn);
54  hideColumn(ImageTreeWidgetItem::LineResolutionColumn);
55  hideColumn(ImageTreeWidgetItem::NorthAzimuthColumn);
56  hideColumn(ImageTreeWidgetItem::BlankColumn);
57 
58  // Read and apply default visibilities from config, if different than defaults
59  QSettings settings(
60  FileName(QString("$HOME/.Isis/%1/fileList.config").arg(QApplication::applicationName()))
61  .expanded(),
62  QSettings::NativeFormat);
63  settings.beginGroup("ColumnsVisible");
64 
65  col = ImageTreeWidgetItem::FootprintColumn;
66  while(col < ImageTreeWidgetItem::BlankColumn) {
67  bool visible = !isColumnHidden(col);
68 
69  if (settings.value(QString("%1Visible").arg(ImageTreeWidgetItem::treeColumnToString(col)),
70  visible).toBool() != visible) {
71  if (visible)
72  hideColumn(col);
73  else
74  showColumn(col);
75  }
76 
77  col = (ImageTreeWidgetItem::TreeColumn)(col + 1);
78  }
79  settings.endGroup();
80 
81  setContextMenuPolicy(Qt::DefaultContextMenu);
82 
83  setSortingEnabled(true);
84  sortItems(ImageTreeWidgetItem::NameColumn, Qt::AscendingOrder);
85 
86  connect(this, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
87  this, SLOT(onItemChanged(QTreeWidgetItem *, int)));
88  connect(this, SIGNAL(itemSelectionChanged()),
89  this, SLOT(onSelectionChanged()));
90 
91  // This is set up to do a single selection changed after all selections have changed, instead
92  // of 1 selection changed per 1 changed item.
93  connect(this, SIGNAL(queueSelectionChanged()),
94  this, SLOT(onQueuedSelectionChanged()), Qt::QueuedConnection);
95 
96  // Similar issue, but not as bad of a slow-down. Still enough to warrant the effort though.
97  connect(this, SIGNAL(queueReadDisplayProperties()),
98  this, SLOT(onQueuedReadDisplayProperties()), Qt::QueuedConnection);
99 
100  setSelectionMode(QAbstractItemView::ExtendedSelection);
101  setDragDropOverwriteMode(false);
102  }
103 
104 
105  ImageTreeWidget::~ImageTreeWidget() {
106  QAction *contextAction;
107  foreach(contextAction, actions()) {
108  removeAction(contextAction);
109  }
110  }
111 
112 
113  QList<QAction *> ImageTreeWidget::actions() {
114 
115  QList<QAction *> results;
116  if (!m_setFileListColsAct) {
117  m_setFileListColsAct = new QAction("Set Current File List &Columns as Default", this);
118  m_setFileListColsAct->setWhatsThis(tr("Use the currently visible columns in the file list as "
119  "the default when no project has been opened"));
120  connect(m_setFileListColsAct, SIGNAL(triggered(bool)),
121  this, SLOT(setDefaultFileListCols()));
122  }
123  results.append(m_setFileListColsAct);
124 
125  return results;
126  }
127 
128 
129  QTreeWidgetItem *ImageTreeWidget::addGroup(QString imageListName, QString groupName, int index) {
130  if (index >= 0) {
131  disableSort();
132  }
133  QTreeWidgetItem *imageList = imageListTreeItem(imageListName);
134  QTreeWidgetItem *group = createGroup(imageList, groupName, index);
135 
136  verticalScrollBar()->setMaximum(verticalScrollBar()->maximum() + 25);
137  return group;
138  }
139 
140 
141  QTreeWidgetItem *ImageTreeWidget::createGroup(QTreeWidgetItem *imageListItem, QString groupName,
142  int index) {
143  if (!imageListItem)
144  imageListItem = invisibleRootItem();
145 
146  if (groupName.isEmpty()) {
147  groupName = QString("Group %1").arg(imageListItem->childCount() + 1);
148  }
149 
150  QTreeWidgetItem *result = new QTreeWidgetItem;
151  result->setText(0, groupName);
152  result->setFlags(Qt::ItemIsEditable |
153  Qt::ItemIsUserCheckable |
154  Qt::ItemIsEnabled |
155  Qt::ItemIsSelectable |
156  Qt::ItemIsDragEnabled |
157  Qt::ItemIsDropEnabled);
158  result->setData(0, Qt::UserRole, ImageGroupType);
159 
160  if (index == -1) {
161  index = imageListItem->childCount();
162  }
163 
164  imageListItem->insertChild(index, result);
165 
166  // This needs to be after the insert child call
167  result->setExpanded(true);
168 
169  return result;
170  }
171 
172 
173  QTreeWidgetItem *ImageTreeWidget::createImageListNameItem(QString name) {
174  QTreeWidgetItem *result = new QTreeWidgetItem;
175  result->setText(0, name);
176  result->setData(0, Qt::UserRole, ImageListNameType);
177  result->setExpanded(true);
178 
179  return result;
180  }
181 
182 
183  void ImageTreeWidget::refit() {
184  ImageTreeWidgetItem::TreeColumn col = ImageTreeWidgetItem::NameColumn;
185  while(col < ImageTreeWidgetItem::BlankColumn) {
186  // Resize the name column to the expanded version's data.
187  if (col == ImageTreeWidgetItem::NameColumn) {
188  QList<bool> expandedStates;
189  for (int groupIndex = 0; groupIndex < topLevelItemCount(); groupIndex++) {
190  expandedStates.append(topLevelItem(groupIndex)->isExpanded());
191  topLevelItem(groupIndex)->setExpanded(true);
192  }
193 
194  resizeColumnToContents(col);
195 
196  for (int groupIndex = 0; groupIndex < topLevelItemCount(); groupIndex++) {
197  topLevelItem(groupIndex)->setExpanded(expandedStates[groupIndex]);
198  }
199  }
200  else {
201  resizeColumnToContents(col);
202  }
203 
204  col = (ImageTreeWidgetItem::TreeColumn)(col + 1);
205  }
206  }
207 
208 
209  void ImageTreeWidget::disableSort() {
210  sortItems(ImageTreeWidgetItem::BlankColumn, Qt::AscendingOrder);
211  }
212 
213 
214  void ImageTreeWidget::enqueueReadDisplayProperties(ImageTreeWidgetItem *item) {
215  m_queuedReadDisplayPropertiesItems.append(item);
216 
217  if (m_queuedReadDisplayPropertiesItems.count() == 1) {
218  emit queueReadDisplayProperties();
219  }
220  }
221 
222 
223  QList<QAction *> ImageTreeWidget::getViewActions() {
224  if (m_viewActs.empty()) {
225  ImageTreeWidgetItem::TreeColumn col =
226  ImageTreeWidgetItem::FootprintColumn;
227 
228  while(col < ImageTreeWidgetItem::BlankColumn) {
229  QAction *showHide = new QAction("", this);
230  showHide->setData(col);
231 
232  connect(showHide, SIGNAL(triggered()),
233  this, SLOT(toggleColumnVisible()));
234 
235  m_viewActs.append(showHide);
236 
237  col = (ImageTreeWidgetItem::TreeColumn)(col + 1);
238  }
239 
240  updateViewActs();
241  }
242 
243  return m_viewActs;
244  }
245 
246 
247  void ImageTreeWidget::updateViewActs() {
248  if (!m_viewActs.empty()) {
249  int viewActIndex = 0;
250  ImageTreeWidgetItem::TreeColumn col =
251  ImageTreeWidgetItem::FootprintColumn;
252 
253  while(col < ImageTreeWidgetItem::BlankColumn) {
254  bool visible = !isColumnHidden(col);
255  QAction *showHide = m_viewActs[viewActIndex];
256 
257  if (!visible) {
258  showHide->setText("Show " +
259  ImageTreeWidgetItem::treeColumnToString(col) + " Column");
260  }
261  else {
262  showHide->setText("Hide " +
263  ImageTreeWidgetItem::treeColumnToString(col) + " Column");
264  }
265 
266  col = (ImageTreeWidgetItem::TreeColumn)(col + 1);
267  viewActIndex ++;
268  }
269  }
270  }
271 
272 
276  void ImageTreeWidget::setDefaultFileListCols() {
277  QSettings settings(
278  FileName(
279  QString("$HOME/.Isis/%1/fileList.config").arg(QApplication::applicationName()))
280  .expanded(),
281  QSettings::NativeFormat);
282  settings.beginGroup("ColumnsVisible");
283 
284  ImageTreeWidgetItem::TreeColumn col =
285  ImageTreeWidgetItem::FootprintColumn;
286 
287  while(col < ImageTreeWidgetItem::BlankColumn) {
288  bool visible = !isColumnHidden(col);
289 
290  settings.setValue(QString("%1Visible").arg(ImageTreeWidgetItem::treeColumnToString(col)),
291  visible);
292 
293  col = (ImageTreeWidgetItem::TreeColumn)(col + 1);
294  }
295 
296  settings.endGroup();
297  }
298 
299 
300  ImageTreeWidgetItem *ImageTreeWidget::prepCube(ImageList *imageList, Image *image) {
301  try {
302  ImageTreeWidgetItem *item = new ImageTreeWidgetItem(imageList, image);
303 
304  connect(image->displayProperties(), SIGNAL(destroyed(QObject *)),
305  this, SLOT(imageDeleted(QObject *)));
306  connect(image->displayProperties(), SIGNAL(propertyChanged(DisplayProperties *)),
307  this, SLOT(propertiesChanged(DisplayProperties *)));
308 
309  m_displayPropsToTreeItemLookup[image->displayProperties()] = item;
310 
311  return item;
312  }
313  catch(IException &e) {
314  e.print();
315  }
316 
317  return NULL;
318  }
319 
320 
321  ImageList ImageTreeWidget::imagesInView() {
322  ImageList results;
323 
324  QTreeWidgetItemIterator it(this, QTreeWidgetItemIterator::UserFlag);
325 
326  while(*it) {
327  QTreeWidgetItem *item = *it;
328 
329  if (item->type() == QTreeWidgetItem::UserType) {
330  ImageTreeWidgetItem *mosItem = (ImageTreeWidgetItem *)item;
331  results.append(mosItem->image());
332  }
333 
334  it ++;
335  }
336 
337  return results;
338  }
339 
340 
341  ImageTreeWidget::ImagePosition::ImagePosition() {
342  init();
343  }
344 
345 
346  ImageTreeWidget::ImagePosition::ImagePosition(int outerIndex, int innerIndex) {
347  init();
348 
349  setPosition(outerIndex, innerIndex);
350  }
351 
352 
353  ImageTreeWidget::ImagePosition::ImagePosition(const ImagePosition &other) :
354  m_group(other.m_group), m_index(other.m_index) {
355  }
356 
357 
358  ImageTreeWidget::ImagePosition::~ImagePosition() {
359  init();
360  }
361 
362 
363  void ImageTreeWidget::ImagePosition::setPosition(int group, int index) {
364  if (group >= 0 && index >= 0) {
365  m_group = group;
366  m_index = index;
367  }
368  else {
369  init();
370  }
371  }
372 
373 
374  int ImageTreeWidget::ImagePosition::group() const {
375  return m_group;
376  }
377 
378 
379  int ImageTreeWidget::ImagePosition::index() const {
380  return m_index;
381  }
382 
383 
384  bool ImageTreeWidget::ImagePosition::isValid() const {
385  return (m_group != -1 && m_index != -1);
386  }
387 
388 
389  void ImageTreeWidget::ImagePosition::swap(ImagePosition &other) {
390  std::swap(m_group, other.m_group);
391  std::swap(m_index, other.m_index);
392  }
393 
394 
395  bool ImageTreeWidget::ImagePosition::operator<(const ImagePosition &rhs) {
396  bool lessThan = false;
397  if (group() < rhs.group()) {
398  lessThan = true;
399  }
400  else if (group() == rhs.group() && index() < rhs.index()) {
401  lessThan = true;
402  }
403 
404  return lessThan;
405  }
406 
407 
408  ImageTreeWidget::ImagePosition &ImageTreeWidget::ImagePosition::operator=(
409  const ImagePosition &rhs) {
410  ImagePosition copy(rhs);
411  swap(copy);
412 
413  return *this;
414  }
415 
416 
417  void ImageTreeWidget::ImagePosition::init() {
418  m_group = -1;
419  m_index = -1;
420  }
421 
422  void ImageTreeWidget::dropEvent(QDropEvent *event) {
423  QTreeWidgetItem *droppedAtItem = itemAt(event->pos());
424 
425  if(droppedAtItem) {
426  disableSort();
427  QTreeWidgetItem *droppedAtGroup = droppedAtItem;
428 
429  if(droppedAtGroup->type() != QTreeWidgetItem::Type)
430  droppedAtGroup = droppedAtItem->parent();
431 
432  bool draggedGroup = groupInList(selectedItems());
433  bool draggedItem = mosaicItemInList(selectedItems());
434 
435  // Moving items around...
436  if(draggedItem && !draggedGroup) {
437  int insertPosition = 0;
438 
439  if(droppedAtGroup != droppedAtItem) {
440  insertPosition = droppedAtGroup->indexOfChild(droppedAtItem) + 1;
441  }
442 
443  QTreeWidgetItem *toBeMoved;
444  foreach(toBeMoved, selectedItems()) {
445  if(toBeMoved != droppedAtItem) {
446  QTreeWidgetItem *parent = toBeMoved->parent();
447 
448  // We need to make sure we handle moving a child within the
449  // same group and how that effects the insert position
450  int childOrigIndex = parent->indexOfChild(toBeMoved);
451 
452  parent->takeChild(childOrigIndex);
453 
454  int actualInsertPos = insertPosition;
455 
456  if(parent == droppedAtGroup && childOrigIndex < insertPosition)
457  actualInsertPos --;
458 
459  droppedAtGroup->insertChild(actualInsertPos, toBeMoved);
460 
461  // This makes multiple items dragged to bottom of group work
462  if(insertPosition != droppedAtGroup->childCount())
463  insertPosition ++;
464  }
465  }
466  }
467  else if(!draggedItem && draggedGroup) {
468  QTreeWidgetItem *toBeMoved;
469 
470  foreach(toBeMoved, selectedItems()) {
471  if(toBeMoved != droppedAtGroup) {
472  int dropPosition = indexOfTopLevelItem(droppedAtGroup);
473 
474  takeTopLevelItem(indexOfTopLevelItem(toBeMoved));
475  insertTopLevelItem(dropPosition, toBeMoved);
476  }
477  }
478  }
479  }
480  }
481 
492 //void ImageTreeWidget::dropEvent(QDropEvent *event) {
493 // QTreeWidgetItem *droppedAtItem = itemAt(event->pos());
494 //
495 // if (droppedAtItem) {
496 // disableSort();
497 // QTreeWidgetItem *droppedAtList = droppedAtItem;
498 // QTreeWidgetItem *droppedAtGroup = droppedAtItem;
499 //
500 // // Try to figure out which list / group they dropped into
501 // while (droppedAtList->data(0, Qt::UserRole).toInt() != ImageListNameType &&
502 // droppedAtList != invisibleRootItem()) {
503 // droppedAtList = droppedAtList->parent();
504 //
505 // if (!droppedAtList)
506 // droppedAtList = invisibleRootItem();
507 // }
508 //
509 // while (droppedAtGroup && droppedAtGroup->data(0, Qt::UserRole).toInt() != ImageGroupType) {
510 // droppedAtGroup = droppedAtGroup->parent();
511 // }
512 //
513 // QString droppedListName = droppedAtList->text(0);
514 //
515 // // Figure out from which list they're moving items from (to verify they aren't moving
516 // // between file lists)
517 // QTreeWidgetItem *firstItemToBeMoved = NULL;
518 // QString draggedListName;
519 //
520 // if (selectedItems().count()) {
521 // firstItemToBeMoved = selectedItems()[0];
522 //
523 // if (firstItemToBeMoved->data(0, Qt::UserRole).toInt() == ImageGroupType) {
524 // draggedListName = firstItemToBeMoved->parent()->text(0);
525 // }
526 // else if (firstItemToBeMoved->type() == QTreeWidgetItem::UserType) {
527 // draggedListName = ((ImageTreeWidgetItem *)firstItemToBeMoved)->imageListName();
528 // }
529 // else {
530 // firstItemToBeMoved = NULL;
531 // }
532 // }
533 //
534 // bool draggedGroup = groupInList(selectedItems());
535 // bool draggedItem = mosaicItemInList(selectedItems());
536 //
537 // if (firstItemToBeMoved && (draggedListName == droppedListName || droppedListName.isEmpty())) {
538 // // If they dropped images into a list item (but not a group), consider it a new group in
539 // // the list
540 // if (droppedAtList && !droppedAtGroup && !draggedGroup && draggedItem) {
541 // droppedAtGroup = addGroup(droppedListName);
542 // }
543 //
544 // // Moving items around...
545 // if (draggedItem && !draggedGroup) {
546 // int insertPosition = 0;
547 //
548 // if (droppedAtGroup != droppedAtItem) {
549 // insertPosition = droppedAtGroup->indexOfChild(droppedAtItem) + 1;
550 // }
551 //
552 // QTreeWidgetItem *toBeMoved;
553 // foreach(toBeMoved, selectedItems()) {
554 // if (toBeMoved != droppedAtItem) {
555 // QTreeWidgetItem *parent = toBeMoved->parent();
556 //
557 // // We need to make sure we handle moving a child within the
558 // // same group and how that effects the insert position
559 // int childOrigIndex = parent->indexOfChild(toBeMoved);
560 //
561 // parent->takeChild(childOrigIndex);
562 //
563 // int actualInsertPos = insertPosition;
564 //
565 // if (parent == droppedAtGroup && childOrigIndex < insertPosition)
566 // actualInsertPos --;
567 //
568 // droppedAtGroup->insertChild(actualInsertPos, toBeMoved);
569 //
570 // // This makes multiple items dragged to bottom of group work
571 // if (insertPosition != droppedAtGroup->childCount())
572 // insertPosition ++;
573 // }
574 // }
575 // }
576 // else if (!draggedItem && draggedGroup && droppedAtGroup) {
577 // QTreeWidgetItem *toBeMoved;
578 //
579 // foreach(toBeMoved, selectedItems()) {
580 // if (toBeMoved != droppedAtGroup) {
581 // int dropPosition = droppedAtList->indexOfChild(droppedAtGroup);
582 //
583 // droppedAtList->takeChild(droppedAtList->indexOfChild(toBeMoved));
584 // droppedAtList->insertChild(dropPosition, toBeMoved);
585 // }
586 // }
587 // }
588 // }
589 // }
590 //}
591 
592 
597  void ImageTreeWidget::mousePressEvent(QMouseEvent *event) {
598  switch(event->type()) {
599  case QEvent::MouseButtonPress: {
600  if (event->button() == Qt::RightButton &&
601  itemAt(event->pos()) == NULL) {
602  setCurrentItem(NULL);
603  }
604  break;
605  }
606 
607  default:
608  break;
609  }
610 
611  QTreeWidget::mousePressEvent(event);
612  }
613 
614 
615  void ImageTreeWidget::contextMenuEvent(QContextMenuEvent *event) {
616  ImageList selectedCubes = selectedDisplays();
617 
618  bool selectedGroup = groupInList(selectedItems());
619  bool selectedCube = mosaicItemInList(selectedItems());
620 
621  Project *project = NULL;
622 
623  if (m_directory)
624  project = m_directory->project();
625 
626  QList<QAction *> supportedActions = selectedCubes.supportedActions(project);
627 
628  if (m_directory) {
629  supportedActions.append(NULL);
630  supportedActions.append(m_directory->supportedActions(&selectedCubes));
631  }
632 
633  QMenu menu;
634  foreach(QAction *action, supportedActions) {
635  if (action != NULL)
636  menu.addAction(action);
637  else
638  menu.addSeparator();
639  }
640 
641  menu.addSeparator();
642 
643  if (!selectedCube && selectedGroup) {
644  if (selectedItems().size() == 1 && selectedItems()[0]->childCount()) {
645  QAction *close = menu.addAction("Close Cubes in Group");
646  connect(close, SIGNAL(triggered()),
647  this, SLOT(requestCloseSelected()));
648  }
649 
650  if (selectedItems().size() == 1) {
651  QAction *rename = menu.addAction("Rename Group");
652  connect(rename, SIGNAL(triggered()),
653  this, SLOT(renameSelectedGroup()));
654 
655  QAction *group = menu.addAction("Insert Group");
656  connect(group, SIGNAL(triggered()),
657  this, SLOT(addGroup()));
658  }
659 
660  QAction *removeGroup = NULL;
661 
662  if (selectedItems().size() == 1)
663  removeGroup = menu.addAction("Delete Group");
664  else
665  removeGroup = menu.addAction("Delete Groups");
666 
667  connect(removeGroup, SIGNAL(triggered()),
668  this, SLOT(deleteSelectedGroups()));
669  }
670 
671  if (selectedCube && !selectedGroup) {
672  QAction *close = NULL;
673 
674  if (selectedItems().size() == 1)
675  close = menu.addAction("Close Cube");
676  else
677  close = menu.addAction("Close Cubes");
678 
679  connect(close, SIGNAL(triggered()),
680  this, SLOT(requestCloseSelected()));
681  }
682 
683  if (!selectedCube && !selectedGroup) {
684  QAction *group = menu.addAction("Add Group");
685 
686  connect(group, SIGNAL(triggered()),
687  this, SLOT(addGroup()));
688  }
689 
690  menu.exec(event->globalPos());
691  }
692 
693 
701  int index = -1;
702 
703  QTreeWidgetItem *newGroupParent = NULL;
704  QString newGroupParentText = "";
705 
706  if (selectedItems().size() == 1) {
707  if (selectedItems()[0]->data(0, Qt::UserRole).toInt() == ImageGroupType) {
708  newGroupParent = selectedItems()[0]->parent();
709  if (newGroupParent) {
710  index = newGroupParent->indexOfChild(selectedItems()[0]);
711  }
712  else {
713  newGroupParent = invisibleRootItem();
714  index = indexOfTopLevelItem(selectedItems()[0]);
715  }
716  }
717  else if (selectedItems()[0]->data(0, Qt::UserRole).toInt() == ImageListNameType) {
718  newGroupParent = selectedItems()[0];
719  }
720  }
721 
722  if (newGroupParent) {
723  newGroupParentText = newGroupParent->text(0);
724  }
725  return addGroup(newGroupParentText, "", index);
726  }
727 
728 
729  void ImageTreeWidget::deleteSelectedGroups() {
730  // Close the cubes in these groups
731  requestCloseSelected();
732 
733  QTreeWidgetItem *toBeDeleted;
734  foreach(toBeDeleted, selectedItems()) {
735  if (toBeDeleted->type() == QTreeWidgetItem::Type) {
736  delete toBeDeleted;
737  }
738  }
739  }
740 
741 
742  void ImageTreeWidget::imageDeleted(QObject *imageObj) {
743  ImageDisplayProperties *imagedisp = (ImageDisplayProperties *)imageObj;
744  ImageTreeWidgetItem *item = treeItem(imagedisp);
745 
746  if (item && item->parent()) {
747  m_displayPropsToTreeItemLookup.remove(imagedisp);
748 
749  item->forgetImage();
750  delete item->parent()->takeChild( item->parent()->indexOfChild(item) );
751  }
752  }
753 
754 
755  void ImageTreeWidget::onItemChanged(QTreeWidgetItem *item, int) {
756  if (item->type() == QTreeWidgetItem::UserType) {
757  ((ImageTreeWidgetItem *)item)->update(true);
758  }
759  }
760 
761 
762  void ImageTreeWidget::onSelectionChanged() {
763  if (!m_queuedSelectionChanged) {
764  emit queueSelectionChanged();
765  m_queuedSelectionChanged = true;
766  }
767  }
768 
769 
770  void ImageTreeWidget::onQueuedReadDisplayProperties() {
771  QTreeWidgetItem *newlySelectedItem = NULL;
772 
773  foreach (ImageTreeWidgetItem *item, m_queuedReadDisplayPropertiesItems) {
774  bool wasSelected = item->isSelected();
775  item->update(false);
776 
777  if (!wasSelected && item->isSelected()) {
778  newlySelectedItem = item;
779  }
780  }
781 
782  if (newlySelectedItem) {
783  scrollToItem(newlySelectedItem);
784  }
785 
786  m_queuedReadDisplayPropertiesItems.clear();
787  }
788 
789 
790  void ImageTreeWidget::onQueuedSelectionChanged() {
791  // This boolean is very important to speed. Please test with 50,000+ images if/when considering
792  // removing it.
793  m_queuedSelectionChanged = false;
794 
795  QTreeWidgetItemIterator it(this, QTreeWidgetItemIterator::UserFlag);
796 
797  while(*it) {
798  QTreeWidgetItem *item = *it;
799 
800  if (item->type() == QTreeWidgetItem::UserType) {
801  ImageTreeWidgetItem *imageItem = (ImageTreeWidgetItem *)item;
802  imageItem->update(true);
803  }
804 
805  it ++;
806  }
807 
808  updateDragAndDropability();
809  }
810 
811 
812  void ImageTreeWidget::propertiesChanged(DisplayProperties *changed) {
813  enqueueReadDisplayProperties(treeItem(changed));
814  }
815 
816 
817  void ImageTreeWidget::renameSelectedGroup() {
818  if (selectedItems().size() == 1 &&
819  selectedItems()[0]->type() == QTreeWidgetItem::Type) {
820  QTreeWidgetItem *groupToEdit = selectedItems()[0];
821  editItem(groupToEdit);
822  }
823  }
824 
825 
826  void ImageTreeWidget::requestCloseSelected() {
827  QTreeWidgetItemIterator it(this, QTreeWidgetItemIterator::UserFlag);
828 
829  while(*it) {
830  QTreeWidgetItem *item = *it;
831 
832  // We get at least one item of the wrong type
833  if (item->type() == QTreeWidgetItem::UserType) {
834  if (item->isSelected() || item->parent()->isSelected()) {
835  ImageTreeWidgetItem *mosItem = (ImageTreeWidgetItem *)item;
836  mosItem->image()->deleteLater();
837  }
838  }
839 
840  it ++;
841  }
842  }
843 
844 
845  void ImageTreeWidget::toggleColumnVisible() {
846  int column = ((QAction *)sender())->data().toInt();
847  setColumnHidden(column, !isColumnHidden(column));
848 
849  if (!m_viewActs.empty())
850  updateViewActs();
851 
852  refit();
853  }
854 
855 
856  void ImageTreeWidget::updateDragAndDropability() {
857  QList<QTreeWidgetItem *> selected = selectedItems();
858  bool selectedGroup = groupInList(selected);
859  bool selectedItem = mosaicItemInList(selected);
860 
861  if (selectedGroup && selectedItem) {
862  setDragDropMode(QAbstractItemView::NoDragDrop);
863  }
864  else {
865  setDragDropMode(QAbstractItemView::DragDrop);
866  }
867  }
868 
869 
870  bool ImageTreeWidget::groupInList(QList<QTreeWidgetItem *> items) {
871  QListIterator<QTreeWidgetItem *> it(items);
872 
873  while (it.hasNext()) {
874  QTreeWidgetItem *item = it.next();
875 
876  if (item->type() == QTreeWidgetItem::Type)
877  return true;
878  }
879 
880  return false;
881  }
882 
883 
884  bool ImageTreeWidget::mosaicItemInList(QList<QTreeWidgetItem *> items) {
885  QListIterator<QTreeWidgetItem *> it(items);
886 
887  while (it.hasNext()) {
888  QTreeWidgetItem *item = it.next();
889 
890  if (item->type() == QTreeWidgetItem::UserType)
891  return true;
892  }
893 
894  return false;
895  }
896 
897  ImageList ImageTreeWidget::selectedDisplays() {
898  ImageList selected;
899  QTreeWidgetItemIterator it(this, QTreeWidgetItemIterator::UserFlag);
900 
901  while(*it) {
902  QTreeWidgetItem *item = *it;
903 
904  // We get at least one item of the wrong type
905  if (item->type() == QTreeWidgetItem::UserType) {
906  ImageTreeWidgetItem *mosItem = (ImageTreeWidgetItem *)item;
907  if (mosItem->isSelected() || mosItem->parent()->isSelected()) {
908  selected.append(mosItem->image());
909  }
910  }
911 
912  it ++;
913  }
914 
915  return selected;
916  }
917 
918 
928  QTreeWidgetItem *result = NULL;
929 
930  if (imageListName.isEmpty()) {
931  result = invisibleRootItem();
932  }
933  else {
934  QTreeWidgetItemIterator it(this);
935 
936  while(*it && !result) {
937  QTreeWidgetItem *item = *it;
938 
939  if (item->data(0, Qt::UserRole).toInt() == ImageListNameType) {
940  if (item->text(0) == imageListName) {
941  result = item;
942  }
943  }
944 
945  it ++;
946  }
947  }
948 
949  if (!result) {
950  result = createImageListNameItem(imageListName);
951  addTopLevelItem(result);
952  }
953 
954  return result;
955  }
956 
957 
958  ImageTreeWidgetItem *ImageTreeWidget::treeItem(DisplayProperties *displayProps) {
959  return m_displayPropsToTreeItemLookup[displayProps];
960  }
961 
962 
963  ImageTreeWidgetItem *ImageTreeWidget::treeItem(Image *image) {
964  return treeItem(image->displayProperties());
965  }
966 }