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