Generated on Wed Jul 27 2011 15:08:35 for Gecode by doxygen 1.7.4
treecanvas.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Guido Tack <tack@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Guido Tack, 2006
00008  *
00009  *  Last modified:
00010  *     $Date: 2010-09-30 09:44:05 +0200 (Thu, 30 Sep 2010) $ by $Author: tack $
00011  *     $Revision: 11431 $
00012  *
00013  *  This file is part of Gecode, the generic constraint
00014  *  development environment:
00015  *     http://www.gecode.org
00016  *
00017  * Permission is hereby granted, free of charge, to any person obtaining
00018  * a copy of this software and associated documentation files (the
00019  * "Software"), to deal in the Software without restriction, including
00020  * without limitation the rights to use, copy, modify, merge, publish,
00021  * distribute, sublicense, and/or sell copies of the Software, and to
00022  * permit persons to whom the Software is furnished to do so, subject to
00023  * the following conditions:
00024  *
00025  * The above copyright notice and this permission notice shall be
00026  * included in all copies or substantial portions of the Software.
00027  *
00028  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00029  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00030  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00031  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00032  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00033  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00034  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00035  *
00036  */
00037 
00038 #include <QtGui/QPainter>
00039 
00040 #include <stack>
00041 #include <fstream>
00042 
00043 #include <gecode/gist/treecanvas.hh>
00044 
00045 #include <gecode/gist/nodevisitor.hh>
00046 #include <gecode/gist/visualnode.hh>
00047 #include <gecode/gist/drawingcursor.hh>
00048 
00049 #include <gecode/search.hh>
00050 #include <gecode/search/support.hh>
00051 
00052 namespace Gecode { namespace Gist {
00053 
00054   TreeCanvas::TreeCanvas(Space* rootSpace, bool bab,
00055                          QWidget* parent, const Options& opt)
00056     : QWidget(parent)
00057     , mutex(QMutex::Recursive)
00058     , layoutMutex(QMutex::Recursive)
00059     , finishedFlag(false)
00060     , compareNodes(false), compareNodesBeforeFP(false)
00061     , autoHideFailed(true), autoZoom(false)
00062     , refresh(500), refreshPause(0), smoothScrollAndZoom(false)
00063     , zoomTimeLine(500)
00064     , scrollTimeLine(1000), targetX(0), sourceX(0), targetY(0), sourceY(0)
00065     , targetW(0), targetH(0), targetScale(0)
00066     , layoutDoneTimerId(0) {
00067       QMutexLocker locker(&mutex);
00068       curBest = (bab ? new BestNode(NULL) : NULL);
00069       if (rootSpace->status() == SS_FAILED) {
00070         rootSpace = NULL;
00071       } else {
00072         rootSpace = Gecode::Search::snapshot(rootSpace,opt);
00073       }
00074       na = new Node::NodeAllocator(bab);
00075       int rootIdx = na->allocate(rootSpace);
00076       assert(rootIdx == 0); (void) rootIdx;
00077       root = (*na)[0];
00078       root->layout(*na);
00079       root->setMarked(true);
00080       currentNode = root;
00081       pathHead = root;
00082       scale = LayoutConfig::defScale / 100.0;
00083 
00084       setAutoFillBackground(true);
00085 
00086       connect(&searcher, SIGNAL(update(int,int,int)), this,
00087                          SLOT(layoutDone(int,int,int)));
00088       connect(&searcher, SIGNAL(statusChanged(bool)), this,
00089               SLOT(statusChanged(bool)));
00090 
00091       connect(&searcher, SIGNAL(solution(const Space*)),
00092               this, SIGNAL(solution(const Space*)),
00093               Qt::BlockingQueuedConnection);
00094       connect(&searcher, SIGNAL(solution(const Space*)),
00095               this, SLOT(inspectSolution(const Space*)),
00096               Qt::BlockingQueuedConnection);
00097 
00098       connect(&searcher, SIGNAL(searchFinished(void)), this, SIGNAL(searchFinished(void)));
00099 
00100       connect(&scrollTimeLine, SIGNAL(frameChanged(int)),
00101               this, SLOT(scroll(int)));
00102       scrollTimeLine.setCurveShape(QTimeLine::EaseInOutCurve);
00103 
00104       scaleBar = new QSlider(Qt::Vertical, this);
00105       scaleBar->setObjectName("scaleBar");
00106       scaleBar->setMinimum(LayoutConfig::minScale);
00107       scaleBar->setMaximum(LayoutConfig::maxScale);
00108       scaleBar->setValue(LayoutConfig::defScale);
00109       connect(scaleBar, SIGNAL(valueChanged(int)),
00110               this, SLOT(scaleTree(int)));
00111       connect(this, SIGNAL(scaleChanged(int)), scaleBar, SLOT(setValue(int)));
00112       connect(&searcher, SIGNAL(scaleChanged(int)),
00113               scaleBar, SLOT(setValue(int)));
00114 
00115       connect(&zoomTimeLine, SIGNAL(frameChanged(int)),
00116               scaleBar, SLOT(setValue(int)));
00117       zoomTimeLine.setCurveShape(QTimeLine::EaseInOutCurve);
00118 
00119       qRegisterMetaType<Statistics>("Statistics");
00120       update();
00121   }
00122 
00123   TreeCanvas::~TreeCanvas(void) {
00124     if (root) {
00125       DisposeCursor dc(root,*na);
00126       PreorderNodeVisitor<DisposeCursor>(dc).run();
00127     }
00128     delete na;
00129   }
00130 
00131   void
00132   TreeCanvas::addDoubleClickInspector(Inspector* i) {
00133     doubleClickInspectors.append(QPair<Inspector*,bool>(i,false));
00134   }
00135 
00136   void
00137   TreeCanvas::activateDoubleClickInspector(int i, bool active) {
00138     assert(i < doubleClickInspectors.size());
00139     doubleClickInspectors[i].second = active;
00140   }
00141 
00142   void
00143   TreeCanvas::addSolutionInspector(Inspector* i) {
00144     solutionInspectors.append(QPair<Inspector*,bool>(i,false));
00145   }
00146 
00147   void
00148   TreeCanvas::activateSolutionInspector(int i, bool active) {
00149     assert(i < solutionInspectors.size());
00150     solutionInspectors[i].second = active;
00151   }
00152 
00153   void
00154   TreeCanvas::addMoveInspector(Inspector* i) {
00155     moveInspectors.append(QPair<Inspector*,bool>(i,false));
00156   }
00157 
00158   void
00159   TreeCanvas::activateMoveInspector(int i, bool active) {
00160     assert(i < moveInspectors.size());
00161     moveInspectors[i].second = active;
00162   }
00163 
00164   void
00165   TreeCanvas::addComparator(Comparator* c) {
00166     comparators.append(QPair<Comparator*,bool>(c,false));
00167   }
00168 
00169   void
00170   TreeCanvas::activateComparator(int i, bool active) {
00171     assert(i < comparators.size());
00172     comparators[i].second = active;
00173   }
00174 
00175   void
00176   TreeCanvas::scaleTree(int scale0, int zoomx, int zoomy) {
00177     QMutexLocker locker(&layoutMutex);
00178 
00179     QSize viewport_size = size();
00180     QAbstractScrollArea* sa =
00181       static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
00182 
00183     if (zoomx==-1)
00184       zoomx = viewport_size.width()/2;
00185     if (zoomy==-1)
00186       zoomy = viewport_size.height()/2;
00187 
00188     int xoff = (sa->horizontalScrollBar()->value()+zoomx)/scale;
00189     int yoff = (sa->verticalScrollBar()->value()+zoomy)/scale;
00190 
00191     BoundingBox bb;
00192     scale0 = std::min(std::max(scale0, LayoutConfig::minScale),
00193                       LayoutConfig::maxScale);
00194     scale = (static_cast<double>(scale0)) / 100.0;
00195     bb = root->getBoundingBox();
00196     int w =
00197       static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
00198     int h =
00199       static_cast<int>(2*Layout::extent+
00200         root->getShape()->depth()*Layout::dist_y*scale);
00201 
00202     sa->horizontalScrollBar()->setRange(0,w-viewport_size.width());
00203     sa->verticalScrollBar()->setRange(0,h-viewport_size.height());
00204     sa->horizontalScrollBar()->setPageStep(viewport_size.width());
00205     sa->verticalScrollBar()->setPageStep(viewport_size.height());
00206     sa->horizontalScrollBar()->setSingleStep(Layout::extent);
00207     sa->verticalScrollBar()->setSingleStep(Layout::extent);
00208 
00209     xoff *= scale;
00210     yoff *= scale;
00211 
00212     sa->horizontalScrollBar()->setValue(xoff-zoomx);
00213     sa->verticalScrollBar()->setValue(yoff-zoomy);
00214 
00215     emit scaleChanged(scale0);
00216     QWidget::update();
00217   }
00218 
00219   void
00220   TreeCanvas::update(void) {
00221     QMutexLocker locker(&mutex);
00222     layoutMutex.lock();
00223     if (root != NULL) {
00224       root->layout(*na);
00225       BoundingBox bb = root->getBoundingBox();
00226 
00227       int w = static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
00228       int h =
00229         static_cast<int>(2*Layout::extent+
00230           root->getShape()->depth()*Layout::dist_y*scale);
00231       xtrans = -bb.left+(Layout::extent / 2);
00232       
00233       QSize viewport_size = size();
00234       QAbstractScrollArea* sa =
00235         static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
00236       sa->horizontalScrollBar()->setRange(0,w-viewport_size.width());
00237       sa->verticalScrollBar()->setRange(0,h-viewport_size.height());
00238       sa->horizontalScrollBar()->setPageStep(viewport_size.width());
00239       sa->verticalScrollBar()->setPageStep(viewport_size.height());
00240       sa->horizontalScrollBar()->setSingleStep(Layout::extent);
00241       sa->verticalScrollBar()->setSingleStep(Layout::extent);
00242     }
00243     if (autoZoom)
00244       zoomToFit();
00245     layoutMutex.unlock();
00246     QWidget::update();
00247   }
00248 
00249   void
00250   TreeCanvas::scroll(void) {
00251     QWidget::update();
00252   }
00253 
00254   void
00255   TreeCanvas::layoutDone(int w, int h, int scale0) {
00256     targetW = w; targetH = h; targetScale = scale0;
00257 
00258     QSize viewport_size = size();
00259     QAbstractScrollArea* sa =
00260       static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
00261     sa->horizontalScrollBar()->setRange(0,w-viewport_size.width());
00262     sa->verticalScrollBar()->setRange(0,h-viewport_size.height());
00263 
00264     if (layoutDoneTimerId == 0)
00265       layoutDoneTimerId = startTimer(15);
00266   }
00267 
00268   void
00269   TreeCanvas::statusChanged(bool finished) {
00270     if (finished) {
00271       update();
00272       centerCurrentNode();
00273     }
00274     emit statusChanged(currentNode, stats, finished);
00275   }
00276 
00277   void
00278   SearcherThread::search(VisualNode* n, bool all, TreeCanvas* ti) {
00279     node = n;
00280     
00281     depth = -1;
00282     for (VisualNode* p = n; p != NULL; p = p->getParent(*ti->na))
00283       depth++;
00284     
00285     a = all;
00286     t = ti;
00287     start();
00288   }
00289 
00290   void
00291   SearcherThread::updateCanvas(void) {
00292     t->layoutMutex.lock();
00293     if (t->root == NULL)
00294       return;
00295 
00296     if (t->autoHideFailed) {
00297       t->root->hideFailed(*t->na,true);
00298     }
00299     for (VisualNode* n = t->currentNode; n != NULL; n=n->getParent(*t->na)) {
00300       if (n->isHidden()) {
00301         t->currentNode->setMarked(false);
00302         t->currentNode = n;
00303         t->currentNode->setMarked(true);
00304         break;
00305       }
00306     }
00307     
00308     t->root->layout(*t->na);
00309     BoundingBox bb = t->root->getBoundingBox();
00310 
00311     int w = static_cast<int>((bb.right-bb.left+Layout::extent)*t->scale);
00312     int h = static_cast<int>(2*Layout::extent+
00313                              t->root->getShape()->depth()
00314                               *Layout::dist_y*t->scale);
00315     t->xtrans = -bb.left+(Layout::extent / 2);
00316 
00317     int scale0 = static_cast<int>(t->scale*100);
00318     if (t->autoZoom) {
00319       QWidget* p = t->parentWidget();
00320       if (p) {
00321         double newXScale =
00322           static_cast<double>(p->width()) / (bb.right - bb.left +
00323                                              Layout::extent);
00324         double newYScale =
00325           static_cast<double>(p->height()) /
00326           (t->root->getShape()->depth() * Layout::dist_y + 2*Layout::extent);
00327 
00328         scale0 = static_cast<int>(std::min(newXScale, newYScale)*100);
00329         if (scale0<LayoutConfig::minScale)
00330           scale0 = LayoutConfig::minScale;
00331         if (scale0>LayoutConfig::maxAutoZoomScale)
00332           scale0 = LayoutConfig::maxAutoZoomScale;
00333         double scale = (static_cast<double>(scale0)) / 100.0;
00334 
00335         w = static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
00336         h = static_cast<int>(2*Layout::extent+
00337                              t->root->getShape()->depth()*Layout::dist_y*scale);
00338       }
00339     }
00340 
00341     t->layoutMutex.unlock();
00342     emit update(w,h,scale0);
00343   }
00344 
00346   class SearchItem {
00347   public:
00349     VisualNode* n;
00351     int i;
00353     int noOfChildren;
00355     SearchItem(VisualNode* n0, int noOfChildren0)
00356       : n(n0), i(-1), noOfChildren(noOfChildren0) {}
00357   };
00358 
00359   void
00360   SearcherThread::run() {
00361     {
00362       if (!node->isOpen())
00363         return;
00364       t->mutex.lock();
00365       emit statusChanged(false);
00366 
00367       unsigned int kids = 
00368         node->getNumberOfChildNodes(*t->na, t->curBest, t->stats,
00369                                     t->c_d, t->a_d);
00370       if (kids == 0 || node->getStatus() == STOP) {
00371         t->mutex.unlock();
00372         updateCanvas();
00373         emit statusChanged(true);
00374         return;
00375       }
00376 
00377       std::stack<SearchItem> stck;
00378       stck.push(SearchItem(node,kids));
00379       t->stats.maxDepth =
00380         std::max(static_cast<long unsigned int>(t->stats.maxDepth), 
00381                  static_cast<long unsigned int>(depth+stck.size()));
00382 
00383       VisualNode* sol = NULL;
00384       int nodeCount = 0;
00385       t->stopSearchFlag = false;
00386       while (!stck.empty() && !t->stopSearchFlag) {
00387         if (t->refresh > 0 && nodeCount >= t->refresh) {
00388           node->dirtyUp(*t->na);
00389           updateCanvas();
00390           emit statusChanged(false);
00391           nodeCount = 0;
00392           if (t->refreshPause > 0)
00393             msleep(t->refreshPause);
00394         }
00395         SearchItem& si = stck.top();
00396         si.i++;
00397         if (si.i == si.noOfChildren) {
00398           stck.pop();
00399         } else {
00400           VisualNode* n = si.n->getChild(*t->na,si.i);
00401           if (n->isOpen()) {
00402             if (n->getStatus() == UNDETERMINED)
00403               nodeCount++;
00404             kids = n->getNumberOfChildNodes(*t->na, t->curBest, t->stats,
00405                                             t->c_d, t->a_d);
00406             if (kids == 0) {
00407               if (n->getStatus() == SOLVED) {
00408                 assert(n->hasCopy());
00409                 emit solution(n->getWorkingSpace());
00410                 n->purge(*t->na);
00411                 sol = n;
00412                 if (!a)
00413                   break;
00414               }
00415             } else {
00416               if ( n->getStatus() != STOP )
00417                 stck.push(SearchItem(n,kids));
00418               else if (!a)
00419                 break;
00420               t->stats.maxDepth =
00421                 std::max(static_cast<long unsigned int>(t->stats.maxDepth), 
00422                          static_cast<long unsigned int>(depth+stck.size()));
00423             }
00424           }
00425         }
00426       }
00427       node->dirtyUp(*t->na);
00428       t->stopSearchFlag = false;
00429       t->mutex.unlock();
00430       if (sol != NULL) {
00431         t->setCurrentNode(sol,false);
00432       } else {
00433         t->setCurrentNode(node,false);
00434       }
00435     }
00436     updateCanvas();
00437     emit statusChanged(true);
00438     if (t->finishedFlag)
00439       emit searchFinished();
00440   }
00441 
00442   void
00443   TreeCanvas::searchAll(void) {
00444     QMutexLocker locker(&mutex);
00445     searcher.search(currentNode, true, this);
00446   }
00447 
00448   void
00449   TreeCanvas::searchOne(void) {
00450     QMutexLocker locker(&mutex);
00451     searcher.search(currentNode, false, this);
00452   }
00453 
00454   void
00455   TreeCanvas::toggleHidden(void) {
00456     QMutexLocker locker(&mutex);
00457     currentNode->toggleHidden(*na);
00458     update();
00459     centerCurrentNode();
00460     emit statusChanged(currentNode, stats, true);
00461   }
00462 
00463   void
00464   TreeCanvas::hideFailed(void) {
00465     QMutexLocker locker(&mutex);
00466     currentNode->hideFailed(*na);
00467     update();
00468     centerCurrentNode();
00469     emit statusChanged(currentNode, stats, true);
00470   }
00471 
00472   void
00473   TreeCanvas::unhideAll(void) {
00474     QMutexLocker locker(&mutex);
00475     QMutexLocker layoutLocker(&layoutMutex);
00476     currentNode->unhideAll(*na);
00477     update();
00478     centerCurrentNode();
00479     emit statusChanged(currentNode, stats, true);
00480   }
00481 
00482   void
00483   TreeCanvas::toggleStop(void) {
00484     QMutexLocker locker(&mutex);
00485     currentNode->toggleStop(*na);
00486     update();
00487     centerCurrentNode();
00488     emit statusChanged(currentNode, stats, true);
00489   }
00490 
00491   void
00492   TreeCanvas::unstopAll(void) {
00493     QMutexLocker locker(&mutex);
00494     QMutexLocker layoutLocker(&layoutMutex);
00495     currentNode->unstopAll(*na);
00496     update();
00497     centerCurrentNode();
00498     emit statusChanged(currentNode, stats, true);    
00499   }
00500 
00501   void
00502   TreeCanvas::timerEvent(QTimerEvent* e) {
00503     if (e->timerId() == layoutDoneTimerId) {
00504       if (!smoothScrollAndZoom) {
00505         scaleTree(targetScale);
00506       } else {
00507         zoomTimeLine.stop();
00508         int zoomCurrent = static_cast<int>(scale*100);
00509         int targetZoom = targetScale;
00510         targetZoom = std::min(std::max(targetZoom, LayoutConfig::minScale),
00511                               LayoutConfig::maxAutoZoomScale);
00512         zoomTimeLine.setFrameRange(zoomCurrent,targetZoom);
00513         zoomTimeLine.start();
00514       }
00515       QWidget::update();
00516       killTimer(layoutDoneTimerId);
00517       layoutDoneTimerId = 0;
00518     }
00519   }
00520 
00521   void
00522   TreeCanvas::zoomToFit(void) {
00523     QMutexLocker locker(&layoutMutex);
00524     if (root != NULL) {
00525       BoundingBox bb;
00526       bb = root->getBoundingBox();
00527       QWidget* p = parentWidget();
00528       if (p) {
00529         double newXScale =
00530           static_cast<double>(p->width()) / (bb.right - bb.left +
00531                                              Layout::extent);
00532         double newYScale =
00533           static_cast<double>(p->height()) / (root->getShape()->depth() * 
00534                                               Layout::dist_y +
00535                                               2*Layout::extent);
00536         int scale0 = static_cast<int>(std::min(newXScale, newYScale)*100);
00537         if (scale0<LayoutConfig::minScale)
00538           scale0 = LayoutConfig::minScale;
00539         if (scale0>LayoutConfig::maxAutoZoomScale)
00540           scale0 = LayoutConfig::maxAutoZoomScale;
00541 
00542         if (!smoothScrollAndZoom) {
00543           scaleTree(scale0);
00544         } else {
00545           zoomTimeLine.stop();
00546           int zoomCurrent = static_cast<int>(scale*100);
00547           int targetZoom = scale0;
00548           targetZoom = std::min(std::max(targetZoom, LayoutConfig::minScale),
00549                                 LayoutConfig::maxAutoZoomScale);
00550           zoomTimeLine.setFrameRange(zoomCurrent,targetZoom);
00551           zoomTimeLine.start();
00552         }
00553       }
00554     }
00555   }
00556 
00557   void
00558   TreeCanvas::centerCurrentNode(void) {
00559     QMutexLocker locker(&mutex);
00560     int x=0;
00561     int y=0;
00562 
00563     VisualNode* c = currentNode;
00564     while (c != NULL) {
00565       x += c->getOffset();
00566       y += Layout::dist_y;
00567       c = c->getParent(*na);
00568     }
00569 
00570     x = static_cast<int>((xtrans+x)*scale); y = static_cast<int>(y*scale);
00571 
00572     QAbstractScrollArea* sa =
00573       static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
00574 
00575     x -= sa->viewport()->width() / 2;
00576     y -= sa->viewport()->height() / 2;
00577 
00578     sourceX = sa->horizontalScrollBar()->value();
00579     targetX = std::max(sa->horizontalScrollBar()->minimum(), x);
00580     targetX = std::min(sa->horizontalScrollBar()->maximum(),
00581                        targetX);
00582     sourceY = sa->verticalScrollBar()->value();
00583     targetY = std::max(sa->verticalScrollBar()->minimum(), y);
00584     targetY = std::min(sa->verticalScrollBar()->maximum(),
00585                        targetY);
00586     if (!smoothScrollAndZoom) {
00587       sa->horizontalScrollBar()->setValue(targetX);
00588       sa->verticalScrollBar()->setValue(targetY);
00589     } else {
00590       scrollTimeLine.stop();
00591       scrollTimeLine.setFrameRange(0,100);
00592       scrollTimeLine.setDuration(std::max(200,
00593         std::min(1000,
00594         std::min(std::abs(sourceX-targetX),
00595                  std::abs(sourceY-targetY)))));
00596       scrollTimeLine.start();
00597     }
00598   }
00599 
00600   void
00601   TreeCanvas::scroll(int i) {
00602     QAbstractScrollArea* sa =
00603       static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
00604     double p = static_cast<double>(i)/100.0;
00605     double xdiff = static_cast<double>(targetX-sourceX)*p;
00606     double ydiff = static_cast<double>(targetY-sourceY)*p;
00607     sa->horizontalScrollBar()->setValue(sourceX+static_cast<int>(xdiff));
00608     sa->verticalScrollBar()->setValue(sourceY+static_cast<int>(ydiff));
00609   }
00610 
00611   void
00612   TreeCanvas::inspectCurrentNode(bool fix, int inspectorNo) {
00613     QMutexLocker locker(&mutex);
00614 
00615     if (currentNode->isHidden()) {
00616       toggleHidden();
00617       return;
00618     }
00619 
00620     int failedInspectorType = -1;
00621     int failedInspector = -1;
00622     bool needCentering = false;
00623     try {
00624       switch (currentNode->getStatus()) {
00625       case UNDETERMINED:
00626           {
00627             unsigned int kids =  
00628               currentNode->getNumberOfChildNodes(*na,curBest,stats,c_d,a_d);
00629             int depth = -1;
00630             for (VisualNode* p = currentNode; p != NULL; p=p->getParent(*na))
00631               depth++;
00632             if (kids > 0) {
00633               needCentering = true;
00634               depth++;
00635             }
00636             stats.maxDepth =
00637               std::max(stats.maxDepth, depth);
00638             if (currentNode->getStatus() == SOLVED) {
00639               assert(currentNode->hasCopy());
00640               emit solution(currentNode->getWorkingSpace());
00641               currentNode->purge(*na);
00642             }
00643             emit statusChanged(currentNode,stats,true);
00644             for (int i=0; i<moveInspectors.size(); i++) {
00645               if (moveInspectors[i].second) {
00646                 failedInspectorType = 0;
00647                 failedInspector = i;
00648                 moveInspectors[i].first->
00649                   inspect(*currentNode->getWorkingSpace());
00650                 failedInspectorType = -1;
00651               }
00652             }
00653           }
00654           break;
00655       case FAILED:
00656       case STOP:
00657       case UNSTOP:
00658       case BRANCH:
00659       case SOLVED:
00660         {
00661           // SizeCursor sc(currentNode);
00662           // PreorderNodeVisitor<SizeCursor> pnv(sc);
00663           // int nodes = 1;
00664           // while (pnv.next()) { nodes++; }
00665           // std::cout << "sizeof(VisualNode): " << sizeof(VisualNode)
00666           //           << std::endl;
00667           // std::cout << "Size: " << (pnv.getCursor().s)/1024 << std::endl;
00668           // std::cout << "Nodes: " << nodes << std::endl;
00669           // std::cout << "Size / node: " << (pnv.getCursor().s)/nodes
00670           //           << std::endl;
00671 
00672           Space* curSpace;
00673         
00674           if (fix) {
00675             if (currentNode->isRoot() && currentNode->getStatus() == FAILED)
00676               break;
00677             curSpace = currentNode->getSpace(*na,curBest,c_d,a_d);
00678             if (currentNode->getStatus() == SOLVED &&
00679                 curSpace->status() != SS_SOLVED) {
00680               // in the presence of weakly monotonic propagators, we may have to
00681               // use search to find the solution here
00682               Space* dfsSpace = Gecode::dfs(curSpace);
00683               delete curSpace;
00684               curSpace = dfsSpace;
00685             }          
00686           } else {
00687             if (currentNode->isRoot())
00688               break;
00689             VisualNode* p = currentNode->getParent(*na);
00690             curSpace = p->getSpace(*na,curBest,c_d,a_d);
00691             switch (curSpace->status()) {
00692             case SS_SOLVED:
00693             case SS_FAILED:
00694               break;
00695             case SS_BRANCH:
00696               curSpace->commit(*p->getChoice(), 
00697                                currentNode->getAlternative(*na));
00698               break;
00699             default:
00700               GECODE_NEVER;
00701             }
00702           }
00703 
00704           if (inspectorNo==-1) {
00705             for (int i=0; i<doubleClickInspectors.size(); i++) {
00706               if (doubleClickInspectors[i].second) {
00707                 failedInspectorType = 1;
00708                 failedInspector = i;
00709                 doubleClickInspectors[i].first->inspect(*curSpace);
00710                 failedInspectorType = -1;
00711               }
00712             }
00713           } else {
00714             failedInspectorType = 1;
00715             failedInspector = inspectorNo;
00716             doubleClickInspectors[inspectorNo].first->inspect(*curSpace);
00717             failedInspectorType = -1;
00718           }
00719           delete curSpace;
00720         }
00721         break;
00722       }
00723     } catch (Exception e) {
00724       switch (failedInspectorType) {
00725       case 0:
00726         std::cerr << "Exception in move inspector "
00727                   << failedInspector;
00728         break;
00729       case 1:
00730         std::cerr << "Exception in double-click inspector "
00731                   << failedInspector;
00732         break;
00733       default:
00734         std::cerr << "Exception ";
00735         break;
00736       }
00737       std::cerr << ": " << e.what() << "." << std::endl;
00738       std::cerr << "Stopping..." << std::endl;
00739       std::exit(EXIT_FAILURE);
00740     }
00741 
00742     currentNode->dirtyUp(*na);
00743     update();
00744     if (needCentering)
00745       centerCurrentNode();
00746   }
00747   
00748   void
00749   TreeCanvas::inspectBeforeFP(void) {
00750     inspectCurrentNode(false);
00751   }
00752 
00753   void
00754   TreeCanvas::inspectSolution(const Space* s) {
00755     int failedInspectorType = -1;
00756     int failedInspector = -1;
00757     try {
00758       Space* c = NULL;
00759       for (int i=0; i<solutionInspectors.size(); i++) {
00760         if (solutionInspectors[i].second) {
00761           if (c == NULL)
00762             c = s->clone();
00763           failedInspectorType = 1;
00764           failedInspector = i;
00765           solutionInspectors[i].first->inspect(*c);
00766           failedInspectorType = -1;
00767         }
00768       }
00769       for (int i=0; i<moveInspectors.size(); i++) {
00770         if (moveInspectors[i].second) {
00771           if (c == NULL)
00772             c = s->clone();
00773           failedInspectorType = 0;
00774           failedInspector = i;
00775           moveInspectors[i].first->inspect(*c);
00776           failedInspectorType = -1;
00777         }
00778       }
00779       delete c;
00780     } catch (Exception e) {
00781       switch (failedInspectorType) {
00782       case 0:
00783         std::cerr << "Exception in move inspector "
00784                   << failedInspector;
00785         break;
00786       case 1:
00787         std::cerr << "Exception in solution inspector "
00788                   << failedInspector;
00789         break;
00790       default:
00791         std::cerr << "Exception ";
00792         break;
00793       }
00794       std::cerr << ": " << e.what() << "." << std::endl;
00795       std::cerr << "Stopping..." << std::endl;
00796       std::exit(EXIT_FAILURE);      
00797     }
00798   }
00799 
00800   void
00801   TreeCanvas::stopSearch(void) {
00802     stopSearchFlag = true;
00803     layoutDoneTimerId = startTimer(15);
00804   }
00805 
00806   void
00807   TreeCanvas::reset(void) {
00808     QMutexLocker locker(&mutex);
00809     Space* rootSpace =
00810       root->getStatus() == FAILED ? NULL : 
00811                            root->getSpace(*na,curBest,c_d,a_d);
00812     if (curBest != NULL) {
00813       delete curBest;
00814       curBest = new BestNode(NULL);
00815     }
00816     if (root) {
00817       DisposeCursor dc(root,*na);
00818       PreorderNodeVisitor<DisposeCursor>(dc).run();
00819     }
00820     delete na;
00821     na = new Node::NodeAllocator(curBest != NULL);
00822     int rootIdx = na->allocate(rootSpace);
00823     assert(rootIdx == 0); (void) rootIdx;
00824     root = (*na)[0];
00825     root->setMarked(true);
00826     currentNode = root;
00827     pathHead = root;
00828     scale = 1.0;
00829     stats = Statistics();
00830     for (int i=bookmarks.size(); i--;)
00831       emit removedBookmark(i);
00832     bookmarks.clear();
00833     root->layout(*na);
00834 
00835     emit statusChanged(currentNode, stats, true);
00836     update();
00837   }
00838 
00839   void
00840   TreeCanvas::bookmarkNode(void) {
00841     QMutexLocker locker(&mutex);
00842     if (!currentNode->isBookmarked()) {
00843       bool ok;
00844       QString text =
00845         QInputDialog::getText(this, "Add bookmark", "Name:", 
00846                               QLineEdit::Normal,"",&ok);
00847       if (ok) {
00848         currentNode->setBookmarked(true);
00849         bookmarks.append(currentNode);
00850         if (text == "")
00851           text = QString("Node ")+QString().setNum(bookmarks.size());
00852         emit addedBookmark(text);
00853       }
00854     } else {
00855       currentNode->setBookmarked(false);
00856       int idx = bookmarks.indexOf(currentNode);
00857       bookmarks.remove(idx);
00858       emit removedBookmark(idx);
00859     }
00860     currentNode->dirtyUp(*na);
00861     update();
00862   }
00863   
00864   void
00865   TreeCanvas::setPath(void) {
00866     QMutexLocker locker(&mutex);
00867     if(currentNode == pathHead)
00868       return;
00869 
00870     pathHead->unPathUp(*na);
00871     pathHead = currentNode;
00872 
00873     currentNode->pathUp(*na);
00874     currentNode->dirtyUp(*na);
00875     update();
00876   }
00877 
00878   void
00879   TreeCanvas::inspectPath(void) {
00880     QMutexLocker locker(&mutex);
00881     setCurrentNode(root);
00882     if (currentNode->isOnPath()) {
00883       inspectCurrentNode();
00884       int nextAlt = currentNode->getPathAlternative(*na);
00885       while (nextAlt >= 0) {
00886         setCurrentNode(currentNode->getChild(*na,nextAlt));
00887         inspectCurrentNode();
00888         nextAlt = currentNode->getPathAlternative(*na);
00889       }
00890     }
00891     update();
00892   }
00893 
00894   void
00895   TreeCanvas::startCompareNodes(void) {
00896     QMutexLocker locker(&mutex);
00897     compareNodes = true;
00898     compareNodesBeforeFP = false;
00899     setCursor(QCursor(Qt::CrossCursor));
00900   }
00901 
00902   void
00903   TreeCanvas::startCompareNodesBeforeFP(void) {
00904     QMutexLocker locker(&mutex);
00905     compareNodes = true;
00906     compareNodesBeforeFP = true;
00907     setCursor(QCursor(Qt::CrossCursor));
00908   }
00909 
00910   void
00911   TreeCanvas::emitStatusChanged(void) {
00912     emit statusChanged(currentNode, stats, true);
00913   }
00914 
00915   void
00916   TreeCanvas::navUp(void) {
00917     QMutexLocker locker(&mutex);
00918 
00919     VisualNode* p = currentNode->getParent(*na);
00920 
00921     setCurrentNode(p);
00922 
00923     if (p != NULL) {
00924       centerCurrentNode();
00925     }
00926   }
00927 
00928   void
00929   TreeCanvas::navDown(void) {
00930     QMutexLocker locker(&mutex);
00931     if (!currentNode->isHidden()) {
00932       switch (currentNode->getStatus()) {
00933       case STOP:
00934       case UNSTOP:
00935       case BRANCH:
00936           {
00937             int alt = std::max(0, currentNode->getPathAlternative(*na));
00938             VisualNode* n = currentNode->getChild(*na,alt);
00939             setCurrentNode(n);
00940             centerCurrentNode();
00941             break;
00942           }
00943       case SOLVED:
00944       case FAILED:
00945       case UNDETERMINED:
00946         break;
00947       }
00948     }
00949   }
00950 
00951   void
00952   TreeCanvas::navLeft(void) {
00953     QMutexLocker locker(&mutex);
00954     VisualNode* p = currentNode->getParent(*na);
00955     if (p != NULL) {
00956       int alt = currentNode->getAlternative(*na);
00957       if (alt > 0) {
00958         VisualNode* n = p->getChild(*na,alt-1);
00959         setCurrentNode(n);
00960         centerCurrentNode();
00961       }
00962     }
00963   }
00964 
00965   void
00966   TreeCanvas::navRight(void) {
00967     QMutexLocker locker(&mutex);
00968     VisualNode* p = currentNode->getParent(*na);
00969     if (p != NULL) {
00970       unsigned int alt = currentNode->getAlternative(*na);
00971       if (alt + 1 < p->getNumberOfChildren()) {
00972         VisualNode* n = p->getChild(*na,alt+1);
00973         setCurrentNode(n);
00974         centerCurrentNode();
00975       }
00976     }
00977   }
00978 
00979   void
00980   TreeCanvas::navRoot(void) {
00981     QMutexLocker locker(&mutex);
00982     setCurrentNode(root);
00983     centerCurrentNode();
00984   }
00985 
00986   void
00987   TreeCanvas::navNextSol(bool back) {
00988     QMutexLocker locker(&mutex);
00989     NextSolCursor nsc(currentNode,back,*na);
00990     PreorderNodeVisitor<NextSolCursor> nsv(nsc);
00991     nsv.run();
00992     VisualNode* n = nsv.getCursor().node();
00993     if (n != root) {
00994       setCurrentNode(n);
00995       centerCurrentNode();
00996     }
00997   }
00998 
00999   void
01000   TreeCanvas::navPrevSol(void) {
01001     navNextSol(true);
01002   }
01003 
01004   void
01005   TreeCanvas::exportNodePDF(VisualNode* n) {
01006 #if QT_VERSION >= 0x040400
01007     QString filename = QFileDialog::getSaveFileName(this, tr("Export tree as pdf"), "", tr("PDF (*.pdf)"));
01008     if (filename != "") {
01009       QPrinter printer(QPrinter::ScreenResolution);
01010       QMutexLocker locker(&mutex);
01011 
01012       BoundingBox bb = n->getBoundingBox();
01013       printer.setFullPage(true);
01014       printer.setPaperSize(QSizeF(bb.right-bb.left+Layout::extent,
01015                                   n->getShape()->depth() * Layout::dist_y +
01016                                   Layout::extent), QPrinter::Point);
01017       printer.setOutputFileName(filename);
01018       QPainter painter(&printer);
01019 
01020       painter.setRenderHint(QPainter::Antialiasing);
01021 
01022       QRect pageRect = printer.pageRect();
01023       double newXScale =
01024         static_cast<double>(pageRect.width()) / (bb.right - bb.left +
01025                                                  Layout::extent);
01026       double newYScale =
01027         static_cast<double>(pageRect.height()) /
01028                             (n->getShape()->depth() * Layout::dist_y +
01029                              Layout::extent);
01030       double printScale = std::min(newXScale, newYScale);
01031       painter.scale(printScale,printScale);
01032 
01033       int printxtrans = -bb.left+(Layout::extent / 2);
01034 
01035       painter.translate(printxtrans, Layout::dist_y / 2);
01036       QRect clip(0,0,0,0);
01037       DrawingCursor dc(n, *na, curBest, painter, clip, showCopies);
01038       currentNode->setMarked(false);
01039       PreorderNodeVisitor<DrawingCursor>(dc).run();
01040       currentNode->setMarked(true);
01041     }
01042 #else
01043     (void) n;
01044 #endif
01045   }
01046 
01047   void
01048   TreeCanvas::exportWholeTreePDF(void) {
01049 #if QT_VERSION >= 0x040400
01050     exportNodePDF(root);
01051 #endif
01052   }
01053 
01054   void
01055   TreeCanvas::exportPDF(void) {
01056 #if QT_VERSION >= 0x040400
01057     exportNodePDF(currentNode);
01058 #endif
01059   }
01060 
01061   void
01062   TreeCanvas::print(void) {
01063     QPrinter printer;
01064     if (QPrintDialog(&printer, this).exec() == QDialog::Accepted) {
01065       QMutexLocker locker(&mutex);
01066 
01067       BoundingBox bb = root->getBoundingBox();
01068       QRect pageRect = printer.pageRect();
01069       double newXScale =
01070         static_cast<double>(pageRect.width()) / (bb.right - bb.left +
01071                                                  Layout::extent);
01072       double newYScale =
01073         static_cast<double>(pageRect.height()) /
01074                             (root->getShape()->depth() * Layout::dist_y +
01075                              2*Layout::extent);
01076       double printScale = std::min(newXScale, newYScale)*100;
01077       if (printScale<1.0)
01078         printScale = 1.0;
01079       if (printScale > 400.0)
01080         printScale = 400.0;
01081       printScale = printScale / 100.0;
01082 
01083       QPainter painter(&printer);
01084       painter.setRenderHint(QPainter::Antialiasing);
01085       painter.scale(printScale,printScale);
01086       painter.translate(xtrans, 0);
01087       QRect clip(0,0,0,0);
01088       DrawingCursor dc(root, *na, curBest, painter, clip, showCopies);
01089       PreorderNodeVisitor<DrawingCursor>(dc).run();
01090     }
01091   }
01092 
01093   VisualNode*
01094   TreeCanvas::eventNode(QEvent* event) {
01095     int x = 0;
01096     int y = 0;
01097     switch (event->type()) {
01098     case QEvent::ToolTip:
01099         {
01100           QHelpEvent* he = static_cast<QHelpEvent*>(event);
01101           x = he->x();
01102           y = he->y();
01103           break;
01104         }
01105     case QEvent::MouseButtonDblClick:
01106     case QEvent::MouseButtonPress:
01107     case QEvent::MouseButtonRelease:
01108     case QEvent::MouseMove:
01109         {
01110           QMouseEvent* me = static_cast<QMouseEvent*>(event);
01111           x = me->x();
01112           y = me->y();
01113           break;
01114         }
01115     case QEvent::ContextMenu:
01116         {
01117           QContextMenuEvent* ce = static_cast<QContextMenuEvent*>(event);
01118           x = ce->x();
01119           y = ce->y();
01120           break;
01121         }
01122     default:
01123       return NULL;
01124     }
01125     QAbstractScrollArea* sa =
01126       static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
01127     int xoff = sa->horizontalScrollBar()->value()/scale;
01128     int yoff = sa->verticalScrollBar()->value()/scale;
01129 
01130     BoundingBox bb = root->getBoundingBox();
01131     int w =
01132       static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
01133     if (w < sa->viewport()->width())
01134       xoff -= (sa->viewport()->width()-w)/2;
01135     
01136     VisualNode* n;
01137     n = root->findNode(*na,
01138                        static_cast<int>(x/scale-xtrans+xoff),
01139                        static_cast<int>((y-30)/scale+yoff));
01140     return n;
01141   }
01142 
01143   bool
01144   TreeCanvas::event(QEvent* event) {
01145     if (mutex.tryLock()) {
01146       if (event->type() == QEvent::ToolTip) {
01147         VisualNode* n = eventNode(event);
01148         if (n != NULL && !n->isHidden() &&
01149             (n->getStatus() == BRANCH || n->getStatus() == STOP)) {
01150           QHelpEvent* he = static_cast<QHelpEvent*>(event);
01151           QToolTip::showText(he->globalPos(),
01152                              QString(n->toolTip(curBest,c_d,a_d).c_str()));
01153         } else {
01154           QToolTip::hideText();
01155         }
01156       }
01157       mutex.unlock();
01158     }
01159     return QWidget::event(event);
01160   }
01161 
01162   void
01163   TreeCanvas::resizeToOuter(void) {
01164     if (autoZoom)
01165       zoomToFit();
01166   }
01167 
01168   void
01169   TreeCanvas::paintEvent(QPaintEvent* event) {
01170     QMutexLocker locker(&layoutMutex);
01171     QPainter painter(this);
01172     painter.setRenderHint(QPainter::Antialiasing);
01173 
01174     QAbstractScrollArea* sa =
01175       static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
01176     int xoff = sa->horizontalScrollBar()->value()/scale;
01177     int yoff = sa->verticalScrollBar()->value()/scale;
01178 
01179     BoundingBox bb = root->getBoundingBox();
01180     int w =
01181       static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
01182     if (w < sa->viewport()->width())
01183       xoff -= (sa->viewport()->width()-w)/2;
01184 
01185     QRect origClip = event->rect();
01186     painter.translate(0, 30);
01187     painter.scale(scale,scale);
01188     painter.translate(xtrans-xoff, -yoff);
01189     QRect clip(static_cast<int>(origClip.x()/scale-xtrans+xoff),
01190                static_cast<int>(origClip.y()/scale+yoff),
01191                static_cast<int>(origClip.width()/scale),
01192                static_cast<int>(origClip.height()/scale));
01193     DrawingCursor dc(root, *na, curBest, painter, clip, showCopies);
01194     PreorderNodeVisitor<DrawingCursor>(dc).run();
01195 
01196     // int nodesLayouted = 1;
01197     // clock_t t0 = clock();
01198     // while (v.next()) { nodesLayouted++; }
01199     // double t = (static_cast<double>(clock()-t0) / CLOCKS_PER_SEC) * 1000.0;
01200     // double nps = static_cast<double>(nodesLayouted) /
01201     //   (static_cast<double>(clock()-t0) / CLOCKS_PER_SEC);
01202     // std::cout << "Drawing done. " << nodesLayouted << " nodes in "
01203     //   << t << " ms. " << nps << " nodes/s." << std::endl;
01204 
01205   }
01206 
01207   void
01208   TreeCanvas::mouseDoubleClickEvent(QMouseEvent* event) {
01209     if (mutex.tryLock()) {
01210       if(event->button() == Qt::LeftButton) {
01211         VisualNode* n = eventNode(event);
01212         if(n == currentNode) {
01213           inspectCurrentNode();
01214           event->accept();
01215           mutex.unlock();
01216           return;
01217         }
01218       }
01219       mutex.unlock();
01220     }
01221     event->ignore();
01222   }
01223 
01224   void
01225   TreeCanvas::contextMenuEvent(QContextMenuEvent* event) {
01226     if (mutex.tryLock()) {
01227       VisualNode* n = eventNode(event);
01228       if (n != NULL) {
01229         setCurrentNode(n);
01230         emit contextMenu(event);
01231         event->accept();
01232         mutex.unlock();
01233         return;
01234       }
01235       mutex.unlock();
01236     }
01237     event->ignore();
01238   }
01239 
01240   void
01241   TreeCanvas::resizeEvent(QResizeEvent* e) {
01242     QAbstractScrollArea* sa =
01243       static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
01244 
01245     int w = sa->horizontalScrollBar()->maximum()+e->oldSize().width();
01246     int h = sa->verticalScrollBar()->maximum()+e->oldSize().height();
01247 
01248     sa->horizontalScrollBar()->setRange(0,w-e->size().width());
01249     sa->verticalScrollBar()->setRange(0,h-e->size().height());
01250     sa->horizontalScrollBar()->setPageStep(e->size().width());
01251     sa->verticalScrollBar()->setPageStep(e->size().height());
01252   }
01253 
01254   void
01255   TreeCanvas::wheelEvent(QWheelEvent* event) {
01256     if (event->modifiers() & Qt::ShiftModifier) {
01257       event->accept();
01258       if (event->orientation() == Qt::Vertical && !autoZoom)
01259         scaleTree(scale*100+ceil(static_cast<double>(event->delta())/4.0),
01260                   event->x(), event->y());
01261     } else {
01262       event->ignore();
01263     }
01264   }
01265 
01266   bool
01267   TreeCanvas::finish(void) {
01268     if (finishedFlag)
01269       return true;
01270     stopSearchFlag = true;
01271     finishedFlag = true;
01272     for (int i=0; i<doubleClickInspectors.size(); i++)
01273       doubleClickInspectors[i].first->finalize();
01274     for (int i=0; i<solutionInspectors.size(); i++)
01275       solutionInspectors[i].first->finalize();
01276     for (int i=0; i<moveInspectors.size(); i++)
01277       moveInspectors[i].first->finalize();
01278     for (int i=0; i<comparators.size(); i++)
01279       comparators[i].first->finalize();
01280     return !searcher.isRunning();
01281   }
01282 
01283   void
01284   TreeCanvas::setCurrentNode(VisualNode* n, bool update) {
01285     QMutexLocker locker(&mutex);
01286     if (update && n != NULL && n != currentNode &&
01287         n->getStatus() != UNDETERMINED && !n->isHidden()) {
01288       Space* curSpace = NULL;
01289       for (int i=0; i<moveInspectors.size(); i++) {
01290         if (moveInspectors[i].second) {
01291           if (curSpace == NULL)
01292             curSpace = n->getSpace(*na,curBest,c_d,a_d);
01293           try {
01294             moveInspectors[i].first->inspect(*curSpace);
01295           } catch (Exception e) {
01296             std::cerr << "Exception in move inspector " << i
01297                       << ": " << e.what() << "." << std::endl;
01298             std::cerr << "Stopping..." << std::endl;
01299             std::exit(EXIT_FAILURE);
01300           }
01301         }
01302       }
01303     }
01304     if (n != NULL) {
01305       currentNode->setMarked(false);
01306       currentNode = n;
01307       currentNode->setMarked(true);
01308       emit statusChanged(currentNode,stats,true);
01309       if (update) {
01310         compareNodes = false;
01311         setCursor(QCursor(Qt::ArrowCursor));
01312         QWidget::update();
01313       }
01314     }
01315   }
01316 
01317   void
01318   TreeCanvas::mousePressEvent(QMouseEvent* event) {
01319     if (mutex.tryLock()) {
01320       if (event->button() == Qt::LeftButton) {
01321         VisualNode* n = eventNode(event);
01322         if (compareNodes) {
01323           if (n != NULL && n->getStatus() != UNDETERMINED &&
01324               currentNode != NULL &&
01325               currentNode->getStatus() != UNDETERMINED) {
01326             Space* curSpace = NULL;
01327             Space* compareSpace = NULL;
01328             for (int i=0; i<comparators.size(); i++) {
01329               if (comparators[i].second) {
01330                 if (curSpace == NULL) {
01331                   curSpace = currentNode->getSpace(*na,curBest,c_d,a_d);
01332 
01333                   if (!compareNodesBeforeFP || n->isRoot()) {
01334                     compareSpace = n->getSpace(*na,curBest,c_d,a_d);
01335                   } else {
01336                     VisualNode* p = n->getParent(*na);
01337                     compareSpace = p->getSpace(*na,curBest,c_d,a_d);
01338                     switch (compareSpace->status()) {
01339                     case SS_SOLVED:
01340                     case SS_FAILED:
01341                       break;
01342                     case SS_BRANCH:
01343                       compareSpace->commit(*p->getChoice(), 
01344                                            n->getAlternative(*na));
01345                       break;
01346                     default:
01347                       GECODE_NEVER;
01348                     }
01349                   }
01350                 }
01351                 comparators[i].first->compare(*curSpace,*compareSpace);
01352               }
01353             }
01354           }
01355         } else {
01356           setCurrentNode(n);
01357         }
01358         compareNodes = false;
01359         setCursor(QCursor(Qt::ArrowCursor));
01360         if (n != NULL) {
01361           event->accept();
01362           mutex.unlock();
01363           return;
01364         }
01365       }
01366       mutex.unlock();
01367     }
01368     event->ignore();
01369   }
01370 
01371   void
01372   TreeCanvas::setRecompDistances(int c_d0, int a_d0) {
01373     c_d = c_d0; a_d = a_d0;
01374   }
01375 
01376   void
01377   TreeCanvas::setAutoHideFailed(bool b) {
01378     autoHideFailed = b;
01379   }
01380 
01381   void
01382   TreeCanvas::setAutoZoom(bool b) {
01383     autoZoom = b;
01384     if (autoZoom) {
01385       zoomToFit();
01386     }
01387     emit autoZoomChanged(b);
01388     scaleBar->setEnabled(!b);
01389   }
01390 
01391   void
01392   TreeCanvas::setShowCopies(bool b) {
01393     showCopies = b;
01394   }
01395   bool
01396   TreeCanvas::getShowCopies(void) {
01397     return showCopies;
01398   }
01399 
01400   bool
01401   TreeCanvas::getAutoHideFailed(void) {
01402     return autoHideFailed;
01403   }
01404 
01405   bool
01406   TreeCanvas::getAutoZoom(void) {
01407     return autoZoom;
01408   }
01409 
01410   void
01411   TreeCanvas::setRefresh(int i) {
01412     refresh = i;
01413   }
01414 
01415   void
01416   TreeCanvas::setRefreshPause(int i) {
01417     refreshPause = i;
01418     if (refreshPause > 0)
01419       refresh = 1;
01420   }
01421 
01422   bool
01423   TreeCanvas::getSmoothScrollAndZoom(void) {
01424     return smoothScrollAndZoom;
01425   }
01426 
01427   void
01428   TreeCanvas::setSmoothScrollAndZoom(bool b) {
01429     smoothScrollAndZoom = b;
01430   }
01431 
01432 }}
01433 
01434 // STATISTICS: gist-any