Generated on Tue Jul 27 2010 21:59:10 for Gecode by doxygen 1.7.1

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