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