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.