9#include "AbstractTreeModel.h"
14#include <QFutureWatcher>
21#include <QtConcurrentFilter>
23#include <QtConcurrentMap>
29#include "BusyLeafItem.h"
31#include "ControlMeasure.h"
32#include "ControlNet.h"
33#include "ControlPoint.h"
34#include "IException.h"
36#include "AbstractTreeItem.h"
37#include "FilterWidget.h"
42 AbstractTreeModel::AbstractTreeModel(ControlNet *controlNet, TreeView *v,
43 QObject *parent) :
QObject(parent), m_view(v), m_cNet(controlNet) {
45 m_filterWatcher = NULL;
46 m_rebuildWatcher = NULL;
49 m_expandedState = NULL;
50 m_selectedState = NULL;
51 m_guisFilterWidget = NULL;
52 m_localFilterWidgetCopy = NULL;
55 m_busyItem =
new BusyLeafItem(NULL);
56 rootItem =
new RootItem;
57 m_expandedState =
new QList< QPair< QString, QString > >;
58 m_selectedState =
new QList< QPair< QString, QString > >;
61 m_filterWatcher =
new QFutureWatcher< QAtomicPointer< AbstractTreeItem > >;
62 m_rebuildWatcher =
new QFutureWatcher< QAtomicPointer< RootItem > >;
64 connect(m_filterWatcher, SIGNAL(finished()),
this, SLOT(applyFilterDone()));
65 connect(m_rebuildWatcher, SIGNAL(finished()),
this, SLOT(rebuildItemsDone()));
67 connect(m_filterWatcher, SIGNAL(progressValueChanged(
int)),
68 this, SIGNAL(filterProgressChanged(
int)));
69 connect(m_filterWatcher, SIGNAL(progressRangeChanged(
int,
int)),
70 this, SIGNAL(filterProgressRangeChanged(
int,
int)));
71 connect(m_rebuildWatcher, SIGNAL(progressValueChanged(
int)),
72 this, SIGNAL(rebuildProgressChanged(
int)));
73 connect(m_rebuildWatcher, SIGNAL(progressRangeChanged(
int,
int)),
74 this, SIGNAL(rebuildProgressRangeChanged(
int,
int)));
77 m_filterAgain =
false;
78 m_filterRunning =
false;
79 m_rebuildRunning =
false;
81 m_rebuildPending =
false;
85 AbstractTreeModel::~AbstractTreeModel() {
86 delete m_filterWatcher;
87 m_filterWatcher = NULL;
89 delete m_rebuildWatcher;
90 m_rebuildWatcher = NULL;
98 delete m_expandedState;
99 m_expandedState = NULL;
101 delete m_selectedState;
102 m_selectedState = NULL;
107 delete m_localFilterWidgetCopy;
108 m_localFilterWidgetCopy = NULL;
110 m_guisFilterWidget = NULL;
118 QList< AbstractTreeItem * > AbstractTreeModel::getItems(
int start,
int end,
119 InterestingItemsFlag flags,
bool ignoreExpansion) {
120 QList< AbstractTreeItem * > foundItems;
121 int rowCount = end - start;
122 const AbstractTreeItem *lastVisibleFilteredItem =
123 rootItem->getLastVisibleFilteredItem();
125 bool grabToEnd = (start >= 0 && end < 0);
127 if (lastVisibleFilteredItem && (rowCount > 0 || grabToEnd) &&
128 rootItem->childCount()) {
130 AbstractTreeItem *currentItem = rootItem->getFirstVisibleChild();
132 if (currentItem && !itemIsInteresting(currentItem, flags)) {
133 currentItem = nextItem(currentItem, flags, ignoreExpansion);
136 bool listStillValid =
true;
138 while (row < start && listStillValid && currentItem) {
140 listStillValid = (currentItem != lastVisibleFilteredItem ||
141 currentItem == currentItem->parent()->getLastVisibleChild());
144 currentItem = nextItem(currentItem, flags, ignoreExpansion);
147 while ((row < end || grabToEnd) && listStillValid && currentItem) {
148 foundItems.append(currentItem);
149 listStillValid = (currentItem != lastVisibleFilteredItem ||
150 currentItem == currentItem->parent()->getLastVisibleChild());
154 currentItem = nextItem(currentItem, flags, ignoreExpansion);
160 while (!grabToEnd && isFiltering() && foundItems.size() < rowCount) {
161 foundItems.append(m_busyItem);
169 QList< AbstractTreeItem * > AbstractTreeModel::getItems(
170 AbstractTreeItem *item1, AbstractTreeItem *item2,
171 InterestingItemsFlag flags,
bool ignoreExpansion) {
172 QList< AbstractTreeItem * > foundItems;
174 if (rootItem->childCount()) {
175 AbstractTreeItem *start = NULL;
177 AbstractTreeItem *curItem = rootItem->getFirstVisibleChild();
179 while (!start && curItem) {
180 if (curItem == item1)
182 else if (curItem == item2)
186 curItem = nextItem(curItem, flags, ignoreExpansion);
190 QString msg =
"The first item passed to getItems(AbstractTreeItem*, "
191 "AbstractTreeItem*) is not visible in this model's tree";
192 throw IException(IException::Programmer, msg, _FILEINFO_);
195 AbstractTreeItem *end = item2;
201 void (QList<AbstractTreeItem *>::*someKindaPend)(
202 AbstractTreeItem * const &);
205 if (start == item2) {
210 while (curItem && curItem != end) {
211 (foundItems.*someKindaPend)(curItem);
212 curItem = nextItem(curItem, flags, ignoreExpansion);
216 QString msg =
"The second item passed to getItems(AbstractTreeItem*, "
217 "AbstractTreeItem*) is not visible in this model's tree";
218 throw IException(IException::Programmer, msg, _FILEINFO_);
221 (foundItems.*someKindaPend)(end);
228 QList< AbstractTreeItem * > AbstractTreeModel::getSelectedItems(
229 InterestingItemsFlag flags,
bool ignoreExpansion) {
230 QList< AbstractTreeItem * > selectedItems;
232 if (!isFiltering()) {
233 AbstractTreeItem *currentItem = rootItem->getFirstVisibleChild();
235 if (currentItem && !itemIsInteresting(currentItem, flags))
236 currentItem = nextItem(currentItem, flags, ignoreExpansion);
238 while (currentItem) {
239 if (currentItem->isSelected())
240 selectedItems.append(currentItem);
242 currentItem = nextItem(currentItem, flags, ignoreExpansion);
246 return selectedItems;
250 QMutex *AbstractTreeModel::getMutex()
const {
255 int AbstractTreeModel::getItemCount(InterestingItemsFlag flags)
const {
256 return getItemCount(rootItem, flags);
260 int AbstractTreeModel::getTopLevelItemCount()
const {
261 return rootItem->childCount();
264 int AbstractTreeModel::getVisibleItemCount(InterestingItemsFlag flags,
265 bool ignoreExpansion)
const {
266 AbstractTreeItem *currentItem = rootItem->getFirstVisibleChild();
269 if (!isFiltering()) {
272 while (currentItem) {
273 if (itemIsInteresting(currentItem, flags)) {
277 currentItem = nextItem(currentItem, flags, ignoreExpansion);
285 int AbstractTreeModel::getVisibleTopLevelItemCount()
const {
286 AbstractTreeItem *currentItem = rootItem->getFirstVisibleChild();
289 if (!isFiltering()) {
292 while (currentItem) {
294 currentItem = currentItem->getNextVisiblePeer();
302 int AbstractTreeModel::indexOfVisibleItem(AbstractTreeItem
const *item,
303 InterestingItemsFlag flags,
bool ignoreExpansion)
const {
304 AbstractTreeItem *currentItem = rootItem->getFirstVisibleChild();
307 if (!isFiltering()) {
308 while (currentItem && currentItem != item) {
309 if (itemIsInteresting(currentItem, flags))
312 currentItem = nextItem(currentItem, flags, ignoreExpansion);
325 void AbstractTreeModel::setFrozen(
bool newFrozenState) {
326 m_frozen = newFrozenState;
328 if (m_rebuildPending) {
330 m_rebuildPending =
false;
339 bool AbstractTreeModel::isFrozen()
const {
344 void AbstractTreeModel::queueRebuild() {
345 m_rebuildPending =
true;
349 bool AbstractTreeModel::isFiltering()
const {
350 return m_filterRunning;
354 bool AbstractTreeModel::isRebuilding()
const {
355 return m_rebuildRunning;
359 void AbstractTreeModel::setFilter(FilterWidget *fw) {
360 m_guisFilterWidget = fw;
362 connect(m_guisFilterWidget, SIGNAL(filterChanged()),
363 this, SLOT(applyFilter()));
369 void AbstractTreeModel::clear() {
373 rootItem =
new RootItem;
377 ControlNet *AbstractTreeModel::getControlNetwork()
const {
382 QFutureWatcher< QAtomicPointer< RootItem > > *
383 AbstractTreeModel::getRebuildWatcher()
const {
384 return m_rebuildWatcher;
388 RootItem *AbstractTreeModel::getRootItem()
const {
393 TreeView *AbstractTreeModel::getView()
const {
398 void AbstractTreeModel::stopWorking() {
399 m_filterWatcher->cancel();
400 m_filterWatcher->waitForFinished();
401 m_rebuildWatcher->cancel();
402 m_rebuildWatcher->waitForFinished();
407 QSize AbstractTreeModel::getVisibleSize(
int indentation)
const {
410 if (!isFiltering()) {
411 int visibleRowCount = 0;
414 if (rootItem && rootItem->getFirstVisibleChild()) {
417 while (current != NULL) {
418 int depth = current->getDepth();
421 maxWidth = qMax(maxWidth,
422 current->getDataWidth() + indentation * depth);
423 current = nextItem(current, AllItems,
false);
427 size = QSize(maxWidth, visibleRowCount);
434 void AbstractTreeModel::applyFilter() {
437 if (!m_frozen && !m_filterAgain && m_guisFilterWidget &&
438 m_rebuildWatcher->isFinished()) {
440 QFuture< QAtomicPointer< AbstractTreeItem> > futureRoot;
442 if (m_filterRunning) {
443 m_filterAgain =
true;
444 futureRoot = m_filterWatcher->future();
450 emit filterCountsChanged(-1, getTopLevelItemCount());
453 if (m_localFilterWidgetCopy) {
454 delete m_localFilterWidgetCopy;
455 m_localFilterWidgetCopy = NULL;
458 m_localFilterWidgetCopy =
new FilterWidget(*m_guisFilterWidget);
463 m_filterRunning =
true;
464 rootItem->setLastVisibleFilteredItem(NULL);
465 futureRoot = QtConcurrent::filteredReduced(rootItem->getChildren(),
466 FilterFunctor(m_localFilterWidgetCopy),
467 &FilterFunctor::updateTopLevelLinks,
468 QtConcurrent::OrderedReduce | QtConcurrent::SequentialReduce);
470 m_filterWatcher->setFuture(futureRoot);
476 void AbstractTreeModel::setGlobalSelection(
bool selected,
477 InterestingItemsFlag flags) {
478 selectItems(rootItem, selected, flags);
482 void AbstractTreeModel::selectItems(
483 AbstractTreeItem *item,
bool selected, InterestingItemsFlag flags) {
484 if (item && itemIsInteresting(item, flags)) {
485 item->setSelected(selected);
488 if (item->childCount()) {
489 foreach (AbstractTreeItem * childItem, item->getChildren()) {
490 selectItems(childItem, selected, flags);
496 bool AbstractTreeModel::itemIsInteresting(AbstractTreeItem *item,
497 InterestingItemsFlag flags) {
498 AbstractTreeItem::InternalPointerType pointerType =
499 item->getPointerType();
501 if ((pointerType == AbstractTreeItem::Point && flags.testFlag(PointItems)) ||
502 (pointerType == AbstractTreeItem::Measure && flags.testFlag(MeasureItems)) ||
503 (pointerType == AbstractTreeItem::ImageAndNet && flags.testFlag(ImageItems))) {
512 int AbstractTreeModel::getItemCount(AbstractTreeItem *item,
513 InterestingItemsFlag flags)
const {
516 if (item && itemIsInteresting(item, flags)) {
520 if (item->childCount()) {
521 foreach (AbstractTreeItem * childItem, item->getChildren()) {
522 count += getItemCount(childItem, flags);
530 AbstractTreeItem *AbstractTreeModel::nextItem(AbstractTreeItem *current,
531 InterestingItemsFlag flags,
bool ignoreExpansion)
const {
534 if ((ignoreExpansion || current->isExpanded()) &&
535 current->getFirstVisibleChild())
536 current = current->getFirstVisibleChild();
537 else if (current->getNextVisiblePeer())
538 current = current->getNextVisiblePeer();
539 else if (current->parent())
540 current = current->parent()->getNextVisiblePeer();
544 while (current && !itemIsInteresting(current, flags));
551 void AbstractTreeModel::applyFilterDone() {
552 m_filterRunning =
false;
555 m_filterAgain =
false;
559 emit modelModified();
560 emit filterCountsChanged(getVisibleTopLevelItemCount(),
561 getTopLevelItemCount());
566 void AbstractTreeModel::rebuildItemsDone() {
569 QAtomicPointer< RootItem > newRootPtr = m_rebuildWatcher->future();
570 RootItem *newRoot = newRootPtr.loadAcquire();
572 if (newRoot && newRoot->childCount()) {
585 setRebuilding(
false);
586 emit modelModified();
590 AbstractTreeModel::FilterFunctor::FilterFunctor(
591 FilterWidget *fw) : m_filter(fw) {
595 AbstractTreeModel::FilterFunctor::FilterFunctor(FilterFunctor
const &other) {
596 m_filter = other.m_filter;
600 AbstractTreeModel::FilterFunctor::~FilterFunctor() {
604 bool AbstractTreeModel::FilterFunctor::operator()(
605 AbstractTreeItem *
const &item)
const {
611 AbstractTreeModel::FilterFunctor &
612 AbstractTreeModel::FilterFunctor::operator=(FilterFunctor
const &other) {
614 m_filter = other.m_filter;
620 void AbstractTreeModel::FilterFunctor::filterWorker(
621 AbstractTreeItem *item)
const {
622 switch (item->getPointerType()) {
624 case AbstractTreeItem::Point:
625 item->setVisible((!m_filter || m_filter->evaluate(
626 (ControlPoint *) item->getPointer())) ?
true : false);
629 case AbstractTreeItem::Measure:
630 item->setVisible((!m_filter || m_filter->evaluate(
631 (ControlMeasure *) item->getPointer())) ?
true : false);
634 case AbstractTreeItem::ImageAndNet:
635 item->setVisible((!m_filter || m_filter->evaluate(
636 (QPair<QString, ControlNet *> *) item->getPointer())) ?
true : false);
639 case AbstractTreeItem::None:
640 item->setVisible(
true);
645 if (item->getFirstVisibleChild())
646 item->setFirstVisibleChild(NULL);
648 if (item->getLastVisibleChild())
649 item->setLastVisibleChild(NULL);
651 item->setNextVisiblePeer(NULL);
655 if (item->childCount()) {
656 for (
int i = 0; i < item->childCount(); i++) {
657 AbstractTreeItem *child = item->childAt(i);
660 if (child->isVisible()) {
661 if (!item->getFirstVisibleChild()) {
662 item->setFirstVisibleChild(child);
663 item->setLastVisibleChild(child);
666 item->getLastVisibleChild()->setNextVisiblePeer(child);
667 item->setLastVisibleChild(child);
675 void AbstractTreeModel::FilterFunctor::updateTopLevelLinks(
676 QAtomicPointer< AbstractTreeItem > & root,
677 AbstractTreeItem *
const &item) {
679 if ( root.testAndSetOrdered(NULL, item->parent()) ) {
680 AbstractTreeItem *loadedRoot = root.loadAcquire();
681 loadedRoot->setFirstVisibleChild(NULL);
682 loadedRoot->setLastVisibleChild(NULL);
683 loadedRoot->setLastVisibleFilteredItem(NULL);
687 AbstractTreeItem *loadedRoot = root.loadAcquire();
688 if (item->isVisible()) {
689 if (!loadedRoot->getFirstVisibleChild()) {
690 loadedRoot->setFirstVisibleChild(item);
691 loadedRoot->setLastVisibleChild(item);
694 loadedRoot->getLastVisibleChild()->setNextVisiblePeer(item);
695 loadedRoot->setLastVisibleChild(item);
698 loadedRoot->setLastVisibleFilteredItem(item);
Base class for an item in the tree.
This is free and unencumbered software released into the public domain.
This is free and unencumbered software released into the public domain.