this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2/* 3 * Main authors: 4 * Guido Tack <tack@gecode.org> 5 * 6 * Copyright: 7 * Guido Tack, 2006 8 * 9 * This file is part of Gecode, the generic constraint 10 * development environment: 11 * http://www.gecode.org 12 * 13 * Permission is hereby granted, free of charge, to any person obtaining 14 * a copy of this software and associated documentation files (the 15 * "Software"), to deal in the Software without restriction, including 16 * without limitation the rights to use, copy, modify, merge, publish, 17 * distribute, sublicense, and/or sell copies of the Software, and to 18 * permit persons to whom the Software is furnished to do so, subject to 19 * the following conditions: 20 * 21 * The above copyright notice and this permission notice shall be 22 * included in all copies or substantial portions of the Software. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 28 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 29 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 * 32 */ 33 34#include <QtGui/QPainter> 35#include <QPrinter> 36#include <QPrintDialog> 37 38#include <stack> 39#include <fstream> 40 41#include <gecode/gist/treecanvas.hh> 42 43#include <gecode/gist/nodevisitor.hh> 44#include <gecode/gist/visualnode.hh> 45#include <gecode/gist/drawingcursor.hh> 46 47#include <gecode/search.hh> 48#include <gecode/search/support.hh> 49 50namespace Gecode { namespace Gist { 51 52 TreeCanvas::TreeCanvas(Space* rootSpace, bool bab, 53 QWidget* parent, const Options& opt) 54 : QWidget(parent) 55 , mutex(QMutex::Recursive) 56 , layoutMutex(QMutex::Recursive) 57 , finishedFlag(false) 58 , compareNodes(false), compareNodesBeforeFP(false) 59 , autoHideFailed(true), autoZoom(false) 60 , refresh(500), refreshPause(0), smoothScrollAndZoom(false) 61 , moveDuringSearch(false) 62 , zoomTimeLine(500) 63 , scrollTimeLine(1000), targetX(0), sourceX(0), targetY(0), sourceY(0) 64 , targetW(0), targetH(0), targetScale(0) 65 , layoutDoneTimerId(0) { 66 QMutexLocker locker(&mutex); 67 curBest = (bab ? new BestNode(nullptr) : nullptr); 68 if (rootSpace->status() == SS_FAILED) { 69 if (!opt.clone) 70 delete rootSpace; 71 rootSpace = nullptr; 72 } else { 73 rootSpace = Gecode::Search::snapshot(rootSpace,opt); 74 } 75 na = new Node::NodeAllocator(bab); 76 int rootIdx = na->allocate(rootSpace); 77 assert(rootIdx == 0); (void) rootIdx; 78 root = (*na)[0]; 79 root->layout(*na); 80 root->setMarked(true); 81 currentNode = root; 82 pathHead = root; 83 scale = LayoutConfig::defScale / 100.0; 84 85 setAutoFillBackground(true); 86 87 connect(&searcher, SIGNAL(update(int,int,int)), this, 88 SLOT(layoutDone(int,int,int))); 89 connect(&searcher, SIGNAL(statusChanged(bool)), this, 90 SLOT(statusChanged(bool))); 91 92 connect(&searcher, SIGNAL(solution(const Space*)), 93 this, SIGNAL(solution(const Space*)), 94 Qt::BlockingQueuedConnection); 95 connect(this, SIGNAL(solution(const Space*)), 96 this, SLOT(inspectSolution(const Space*))); 97 98 connect(&searcher, SIGNAL(moveToNode(VisualNode*,bool)), 99 this, SLOT(setCurrentNode(VisualNode*,bool)), 100 Qt::BlockingQueuedConnection); 101 102 connect(&searcher, SIGNAL(searchFinished(void)), this, SIGNAL(searchFinished(void))); 103 104 connect(&scrollTimeLine, SIGNAL(frameChanged(int)), 105 this, SLOT(scroll(int))); 106 scrollTimeLine.setCurveShape(QTimeLine::EaseInOutCurve); 107 108 scaleBar = new QSlider(Qt::Vertical, this); 109 scaleBar->setObjectName("scaleBar"); 110 scaleBar->setMinimum(LayoutConfig::minScale); 111 scaleBar->setMaximum(LayoutConfig::maxScale); 112 scaleBar->setValue(LayoutConfig::defScale); 113 connect(scaleBar, SIGNAL(valueChanged(int)), 114 this, SLOT(scaleTree(int))); 115 connect(this, SIGNAL(scaleChanged(int)), scaleBar, SLOT(setValue(int))); 116 connect(&searcher, SIGNAL(scaleChanged(int)), 117 scaleBar, SLOT(setValue(int))); 118 119 connect(&zoomTimeLine, SIGNAL(frameChanged(int)), 120 scaleBar, SLOT(setValue(int))); 121 zoomTimeLine.setCurveShape(QTimeLine::EaseInOutCurve); 122 123 qRegisterMetaType<Statistics>("Statistics"); 124 update(); 125 } 126 127 TreeCanvas::~TreeCanvas(void) { 128 if (root) { 129 DisposeCursor dc(root,*na); 130 PreorderNodeVisitor<DisposeCursor>(dc).run(); 131 } 132 delete na; 133 } 134 135 void 136 TreeCanvas::addDoubleClickInspector(Inspector* i) { 137 doubleClickInspectors.append(QPair<Inspector*,bool>(i,false)); 138 } 139 140 void 141 TreeCanvas::activateDoubleClickInspector(int i, bool active) { 142 assert(i < doubleClickInspectors.size()); 143 doubleClickInspectors[i].second = active; 144 } 145 146 void 147 TreeCanvas::addSolutionInspector(Inspector* i) { 148 solutionInspectors.append(QPair<Inspector*,bool>(i,false)); 149 } 150 151 void 152 TreeCanvas::activateSolutionInspector(int i, bool active) { 153 assert(i < solutionInspectors.size()); 154 solutionInspectors[i].second = active; 155 } 156 157 void 158 TreeCanvas::addMoveInspector(Inspector* i) { 159 moveInspectors.append(QPair<Inspector*,bool>(i,false)); 160 } 161 162 void 163 TreeCanvas::activateMoveInspector(int i, bool active) { 164 assert(i < moveInspectors.size()); 165 moveInspectors[i].second = active; 166 } 167 168 void 169 TreeCanvas::addComparator(Comparator* c) { 170 comparators.append(QPair<Comparator*,bool>(c,false)); 171 } 172 173 void 174 TreeCanvas::activateComparator(int i, bool active) { 175 assert(i < comparators.size()); 176 comparators[i].second = active; 177 } 178 179 void 180 TreeCanvas::scaleTree(int scale0, int zoomx, int zoomy) { 181 QMutexLocker locker(&layoutMutex); 182 183 QSize viewport_size = size(); 184 QAbstractScrollArea* sa = 185 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget()); 186 187 if (zoomx==-1) 188 zoomx = viewport_size.width()/2; 189 if (zoomy==-1) 190 zoomy = viewport_size.height()/2; 191 192 int xoff = (sa->horizontalScrollBar()->value()+zoomx)/scale; 193 int yoff = (sa->verticalScrollBar()->value()+zoomy)/scale; 194 195 BoundingBox bb; 196 scale0 = std::min(std::max(scale0, LayoutConfig::minScale), 197 LayoutConfig::maxScale); 198 scale = (static_cast<double>(scale0)) / 100.0; 199 bb = root->getBoundingBox(); 200 int w = 201 static_cast<int>((bb.right-bb.left+Layout::extent)*scale); 202 int h = 203 static_cast<int>(2*Layout::extent+ 204 root->getShape()->depth()*Layout::dist_y*scale); 205 206 sa->horizontalScrollBar()->setRange(0,w-viewport_size.width()); 207 sa->verticalScrollBar()->setRange(0,h-viewport_size.height()); 208 sa->horizontalScrollBar()->setPageStep(viewport_size.width()); 209 sa->verticalScrollBar()->setPageStep(viewport_size.height()); 210 sa->horizontalScrollBar()->setSingleStep(Layout::extent); 211 sa->verticalScrollBar()->setSingleStep(Layout::extent); 212 213 xoff *= scale; 214 yoff *= scale; 215 216 sa->horizontalScrollBar()->setValue(xoff-zoomx); 217 sa->verticalScrollBar()->setValue(yoff-zoomy); 218 219 emit scaleChanged(scale0); 220 QWidget::update(); 221 } 222 223 void 224 TreeCanvas::update(void) { 225 QMutexLocker locker(&mutex); 226 layoutMutex.lock(); 227 if (root != nullptr) { 228 root->layout(*na); 229 BoundingBox bb = root->getBoundingBox(); 230 231 int w = static_cast<int>((bb.right-bb.left+Layout::extent)*scale); 232 int h = 233 static_cast<int>(2*Layout::extent+ 234 root->getShape()->depth()*Layout::dist_y*scale); 235 xtrans = -bb.left+(Layout::extent / 2); 236 237 QSize viewport_size = size(); 238 QAbstractScrollArea* sa = 239 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget()); 240 sa->horizontalScrollBar()->setRange(0,w-viewport_size.width()); 241 sa->verticalScrollBar()->setRange(0,h-viewport_size.height()); 242 sa->horizontalScrollBar()->setPageStep(viewport_size.width()); 243 sa->verticalScrollBar()->setPageStep(viewport_size.height()); 244 sa->horizontalScrollBar()->setSingleStep(Layout::extent); 245 sa->verticalScrollBar()->setSingleStep(Layout::extent); 246 } 247 if (autoZoom) 248 zoomToFit(); 249 layoutMutex.unlock(); 250 QWidget::update(); 251 } 252 253 void 254 TreeCanvas::scroll(void) { 255 QWidget::update(); 256 } 257 258 void 259 TreeCanvas::layoutDone(int w, int h, int scale0) { 260 targetW = w; targetH = h; targetScale = scale0; 261 262 QSize viewport_size = size(); 263 QAbstractScrollArea* sa = 264 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget()); 265 sa->horizontalScrollBar()->setRange(0,w-viewport_size.width()); 266 sa->verticalScrollBar()->setRange(0,h-viewport_size.height()); 267 268 if (layoutDoneTimerId == 0) 269 layoutDoneTimerId = startTimer(15); 270 } 271 272 void 273 TreeCanvas::statusChanged(bool finished) { 274 if (finished) { 275 update(); 276 centerCurrentNode(); 277 } 278 emit statusChanged(currentNode, stats, finished); 279 } 280 281 void 282 SearcherThread::search(VisualNode* n, bool all, TreeCanvas* ti) { 283 node = n; 284 285 depth = -1; 286 for (VisualNode* p = n; p != nullptr; p = p->getParent(*ti->na)) 287 depth++; 288 289 a = all; 290 t = ti; 291 start(); 292 } 293 294 void 295 SearcherThread::updateCanvas(void) { 296 t->layoutMutex.lock(); 297 if (t->root == nullptr) 298 return; 299 300 if (t->autoHideFailed) { 301 t->root->hideFailed(*t->na,true); 302 } 303 for (VisualNode* n = t->currentNode; n != nullptr; n=n->getParent(*t->na)) { 304 if (n->isHidden()) { 305 t->currentNode->setMarked(false); 306 t->currentNode = n; 307 t->currentNode->setMarked(true); 308 break; 309 } 310 } 311 312 t->root->layout(*t->na); 313 BoundingBox bb = t->root->getBoundingBox(); 314 315 int w = static_cast<int>((bb.right-bb.left+Layout::extent)*t->scale); 316 int h = static_cast<int>(2*Layout::extent+ 317 t->root->getShape()->depth() 318 *Layout::dist_y*t->scale); 319 t->xtrans = -bb.left+(Layout::extent / 2); 320 321 int scale0 = static_cast<int>(t->scale*100); 322 if (t->autoZoom) { 323 QWidget* p = t->parentWidget(); 324 if (p) { 325 double newXScale = 326 static_cast<double>(p->width()) / (bb.right - bb.left + 327 Layout::extent); 328 double newYScale = 329 static_cast<double>(p->height()) / 330 (t->root->getShape()->depth() * Layout::dist_y + 2*Layout::extent); 331 332 scale0 = static_cast<int>(std::min(newXScale, newYScale)*100); 333 if (scale0<LayoutConfig::minScale) 334 scale0 = LayoutConfig::minScale; 335 if (scale0>LayoutConfig::maxAutoZoomScale) 336 scale0 = LayoutConfig::maxAutoZoomScale; 337 double scale = (static_cast<double>(scale0)) / 100.0; 338 339 w = static_cast<int>((bb.right-bb.left+Layout::extent)*scale); 340 h = static_cast<int>(2*Layout::extent+ 341 t->root->getShape()->depth()*Layout::dist_y*scale); 342 } 343 } 344 345 t->layoutMutex.unlock(); 346 emit update(w,h,scale0); 347 } 348 349 /// A stack item for depth first search 350 class SearchItem { 351 public: 352 /// The node 353 VisualNode* n; 354 /// The currently explored child 355 int i; 356 /// The number of children 357 int noOfChildren; 358 /// Constructor 359 SearchItem(VisualNode* n0, int noOfChildren0) 360 : n(n0), i(-1), noOfChildren(noOfChildren0) {} 361 }; 362 363 void 364 SearcherThread::run(void) { 365 { 366 if (!node->isOpen()) 367 return; 368 t->mutex.lock(); 369 emit statusChanged(false); 370 371 unsigned int kids = 372 node->getNumberOfChildNodes(*t->na, t->curBest, t->stats, 373 t->c_d, t->a_d); 374 if (kids == 0 || node->getStatus() == STOP) { 375 t->mutex.unlock(); 376 updateCanvas(); 377 emit statusChanged(true); 378 return; 379 } 380 381 std::stack<SearchItem> stck; 382 stck.push(SearchItem(node,kids)); 383 t->stats.maxDepth = 384 std::max(static_cast<long unsigned int>(t->stats.maxDepth), 385 static_cast<long unsigned int>(depth+stck.size())); 386 387 VisualNode* sol = nullptr; 388 int nodeCount = 0; 389 t->stopSearchFlag = false; 390 while (!stck.empty() && !t->stopSearchFlag) { 391 if (t->refresh > 0 && nodeCount >= t->refresh) { 392 node->dirtyUp(*t->na); 393 updateCanvas(); 394 emit statusChanged(false); 395 nodeCount = 0; 396 if (t->refreshPause > 0) 397 msleep(t->refreshPause); 398 } 399 SearchItem& si = stck.top(); 400 si.i++; 401 if (si.i == si.noOfChildren) { 402 stck.pop(); 403 } else { 404 VisualNode* n = si.n->getChild(*t->na,si.i); 405 if (n->isOpen()) { 406 if (n->getStatus() == UNDETERMINED) 407 nodeCount++; 408 kids = n->getNumberOfChildNodes(*t->na, t->curBest, t->stats, 409 t->c_d, t->a_d); 410 if (t->moveDuringSearch) 411 emit moveToNode(n,false); 412 if (kids == 0) { 413 if (n->getStatus() == SOLVED) { 414 assert(n->hasCopy()); 415 emit solution(n->getWorkingSpace()); 416 n->purge(*t->na); 417 sol = n; 418 if (!a) 419 break; 420 } 421 } else { 422 if ( n->getStatus() != STOP ) 423 stck.push(SearchItem(n,kids)); 424 else if (!a) 425 break; 426 t->stats.maxDepth = 427 std::max(static_cast<long unsigned int>(t->stats.maxDepth), 428 static_cast<long unsigned int>(depth+stck.size())); 429 } 430 } 431 } 432 } 433 node->dirtyUp(*t->na); 434 t->stopSearchFlag = false; 435 t->mutex.unlock(); 436 if (sol != nullptr) { 437 t->setCurrentNode(sol,true,false); 438 } else { 439 t->setCurrentNode(node,true,false); 440 } 441 } 442 updateCanvas(); 443 emit statusChanged(true); 444 if (t->finishedFlag) 445 emit searchFinished(); 446 } 447 448 void 449 TreeCanvas::searchAll(void) { 450 QMutexLocker locker(&mutex); 451 searcher.search(currentNode, true, this); 452 } 453 454 void 455 TreeCanvas::searchOne(void) { 456 QMutexLocker locker(&mutex); 457 searcher.search(currentNode, false, this); 458 } 459 460 void 461 TreeCanvas::toggleHidden(void) { 462 QMutexLocker locker(&mutex); 463 currentNode->toggleHidden(*na); 464 update(); 465 centerCurrentNode(); 466 emit statusChanged(currentNode, stats, true); 467 } 468 469 void 470 TreeCanvas::hideFailed(void) { 471 QMutexLocker locker(&mutex); 472 currentNode->hideFailed(*na); 473 update(); 474 centerCurrentNode(); 475 emit statusChanged(currentNode, stats, true); 476 } 477 478 void 479 TreeCanvas::unhideAll(void) { 480 QMutexLocker locker(&mutex); 481 QMutexLocker layoutLocker(&layoutMutex); 482 currentNode->unhideAll(*na); 483 update(); 484 centerCurrentNode(); 485 emit statusChanged(currentNode, stats, true); 486 } 487 488 void 489 TreeCanvas::toggleStop(void) { 490 QMutexLocker locker(&mutex); 491 currentNode->toggleStop(*na); 492 update(); 493 centerCurrentNode(); 494 emit statusChanged(currentNode, stats, true); 495 } 496 497 void 498 TreeCanvas::unstopAll(void) { 499 QMutexLocker locker(&mutex); 500 QMutexLocker layoutLocker(&layoutMutex); 501 currentNode->unstopAll(*na); 502 update(); 503 centerCurrentNode(); 504 emit statusChanged(currentNode, stats, true); 505 } 506 507 void 508 TreeCanvas::timerEvent(QTimerEvent* e) { 509 if (e->timerId() == layoutDoneTimerId) { 510 if (!smoothScrollAndZoom) { 511 scaleTree(targetScale); 512 } else { 513 zoomTimeLine.stop(); 514 int zoomCurrent = static_cast<int>(scale*100); 515 int targetZoom = targetScale; 516 targetZoom = std::min(std::max(targetZoom, LayoutConfig::minScale), 517 LayoutConfig::maxAutoZoomScale); 518 zoomTimeLine.setFrameRange(zoomCurrent,targetZoom); 519 zoomTimeLine.start(); 520 } 521 QWidget::update(); 522 killTimer(layoutDoneTimerId); 523 layoutDoneTimerId = 0; 524 } 525 } 526 527 void 528 TreeCanvas::zoomToFit(void) { 529 QMutexLocker locker(&layoutMutex); 530 if (root != nullptr) { 531 BoundingBox bb; 532 bb = root->getBoundingBox(); 533 QWidget* p = parentWidget(); 534 if (p) { 535 double newXScale = 536 static_cast<double>(p->width()) / (bb.right - bb.left + 537 Layout::extent); 538 double newYScale = 539 static_cast<double>(p->height()) / (root->getShape()->depth() * 540 Layout::dist_y + 541 2*Layout::extent); 542 int scale0 = static_cast<int>(std::min(newXScale, newYScale)*100); 543 if (scale0<LayoutConfig::minScale) 544 scale0 = LayoutConfig::minScale; 545 if (scale0>LayoutConfig::maxAutoZoomScale) 546 scale0 = LayoutConfig::maxAutoZoomScale; 547 548 if (!smoothScrollAndZoom) { 549 scaleTree(scale0); 550 } else { 551 zoomTimeLine.stop(); 552 int zoomCurrent = static_cast<int>(scale*100); 553 int targetZoom = scale0; 554 targetZoom = std::min(std::max(targetZoom, LayoutConfig::minScale), 555 LayoutConfig::maxAutoZoomScale); 556 zoomTimeLine.setFrameRange(zoomCurrent,targetZoom); 557 zoomTimeLine.start(); 558 } 559 } 560 } 561 } 562 563 void 564 TreeCanvas::centerCurrentNode(void) { 565 QMutexLocker locker(&mutex); 566 int x=0; 567 int y=0; 568 569 VisualNode* c = currentNode; 570 while (c != nullptr) { 571 x += c->getOffset(); 572 y += Layout::dist_y; 573 c = c->getParent(*na); 574 } 575 576 x = static_cast<int>((xtrans+x)*scale); y = static_cast<int>(y*scale); 577 578 QAbstractScrollArea* sa = 579 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget()); 580 581 x -= sa->viewport()->width() / 2; 582 y -= sa->viewport()->height() / 2; 583 584 sourceX = sa->horizontalScrollBar()->value(); 585 targetX = std::max(sa->horizontalScrollBar()->minimum(), x); 586 targetX = std::min(sa->horizontalScrollBar()->maximum(), 587 targetX); 588 sourceY = sa->verticalScrollBar()->value(); 589 targetY = std::max(sa->verticalScrollBar()->minimum(), y); 590 targetY = std::min(sa->verticalScrollBar()->maximum(), 591 targetY); 592 if (!smoothScrollAndZoom) { 593 sa->horizontalScrollBar()->setValue(targetX); 594 sa->verticalScrollBar()->setValue(targetY); 595 } else { 596 scrollTimeLine.stop(); 597 scrollTimeLine.setFrameRange(0,100); 598 scrollTimeLine.setDuration(std::max(200, 599 std::min(1000, 600 std::min(std::abs(sourceX-targetX), 601 std::abs(sourceY-targetY))))); 602 scrollTimeLine.start(); 603 } 604 } 605 606 void 607 TreeCanvas::scroll(int i) { 608 QAbstractScrollArea* sa = 609 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget()); 610 double p = static_cast<double>(i)/100.0; 611 double xdiff = static_cast<double>(targetX-sourceX)*p; 612 double ydiff = static_cast<double>(targetY-sourceY)*p; 613 sa->horizontalScrollBar()->setValue(sourceX+static_cast<int>(xdiff)); 614 sa->verticalScrollBar()->setValue(sourceY+static_cast<int>(ydiff)); 615 } 616 617 void 618 TreeCanvas::inspectCurrentNode(bool fix, int inspectorNo) { 619 QMutexLocker locker(&mutex); 620 621 if (currentNode->isHidden()) { 622 toggleHidden(); 623 return; 624 } 625 626 int failedInspectorType = -1; 627 int failedInspector = -1; 628 bool needCentering = false; 629 try { 630 switch (currentNode->getStatus()) { 631 case UNDETERMINED: 632 { 633 unsigned int kids = 634 currentNode->getNumberOfChildNodes(*na,curBest,stats,c_d,a_d); 635 int depth = -1; 636 for (VisualNode* p = currentNode; p != nullptr; p=p->getParent(*na)) 637 depth++; 638 if (kids > 0) { 639 needCentering = true; 640 depth++; 641 } 642 stats.maxDepth = 643 std::max(stats.maxDepth, depth); 644 if (currentNode->getStatus() == SOLVED) { 645 assert(currentNode->hasCopy()); 646 emit solution(currentNode->getWorkingSpace()); 647 } 648 emit statusChanged(currentNode,stats,true); 649 for (int i=0; i<moveInspectors.size(); i++) { 650 if (moveInspectors[i].second) { 651 failedInspectorType = 0; 652 failedInspector = i; 653 if (currentNode->getStatus() == FAILED) { 654 if (!currentNode->isRoot()) { 655 Space* curSpace = 656 currentNode->getSpace(*na,curBest,c_d,a_d); 657 moveInspectors[i].first->inspect(*curSpace); 658 delete curSpace; 659 } 660 } else { 661 moveInspectors[i].first-> 662 inspect(*currentNode->getWorkingSpace()); 663 } 664 failedInspectorType = -1; 665 } 666 } 667 if (currentNode->getStatus() == SOLVED) { 668 currentNode->purge(*na); 669 } 670 } 671 break; 672 case FAILED: 673 case STOP: 674 case UNSTOP: 675 case BRANCH: 676 case SOLVED: 677 { 678 Space* curSpace; 679 680 if (fix) { 681 if (currentNode->isRoot() && currentNode->getStatus() == FAILED) 682 break; 683 curSpace = currentNode->getSpace(*na,curBest,c_d,a_d); 684 if (currentNode->getStatus() == SOLVED && 685 curSpace->status() != SS_SOLVED) { 686 // in the presence of weakly monotonic propagators, we may have 687 // to use search to find the solution here 688 assert(curSpace->status() == SS_BRANCH && 689 "Something went wrong - probably an incorrect brancher"); 690 Space* dfsSpace = Gecode::dfs(curSpace); 691 delete curSpace; 692 curSpace = dfsSpace; 693 } 694 } else { 695 if (currentNode->isRoot()) 696 break; 697 VisualNode* p = currentNode->getParent(*na); 698 curSpace = p->getSpace(*na,curBest,c_d,a_d); 699 switch (curSpace->status()) { 700 case SS_SOLVED: 701 case SS_FAILED: 702 break; 703 case SS_BRANCH: 704 curSpace->commit(*p->getChoice(), 705 currentNode->getAlternative(*na)); 706 break; 707 default: 708 GECODE_NEVER; 709 } 710 } 711 712 if (inspectorNo==-1) { 713 for (int i=0; i<doubleClickInspectors.size(); i++) { 714 if (doubleClickInspectors[i].second) { 715 failedInspectorType = 1; 716 failedInspector = i; 717 doubleClickInspectors[i].first->inspect(*curSpace); 718 failedInspectorType = -1; 719 } 720 } 721 } else { 722 failedInspectorType = 1; 723 failedInspector = inspectorNo; 724 doubleClickInspectors[inspectorNo].first->inspect(*curSpace); 725 failedInspectorType = -1; 726 } 727 delete curSpace; 728 } 729 break; 730 } 731 } catch (Exception& e) { 732 switch (failedInspectorType) { 733 case 0: 734 qFatal("Exception in move inspector %d: %s.\n Stopping.", 735 failedInspector, e.what()); 736 break; 737 case 1: 738 qFatal("Exception in double click inspector %d: %s.\n Stopping.", 739 failedInspector, e.what()); 740 break; 741 default: 742 qFatal("Exception: %s.\n Stopping.", e.what()); 743 break; 744 } 745 } 746 747 currentNode->dirtyUp(*na); 748 update(); 749 if (needCentering) 750 centerCurrentNode(); 751 } 752 753 void 754 TreeCanvas::inspectBeforeFP(void) { 755 inspectCurrentNode(false); 756 } 757 758 void 759 TreeCanvas::labelBranches(void) { 760 QMutexLocker locker(&mutex); 761 currentNode->labelBranches(*na,curBest,c_d,a_d); 762 update(); 763 centerCurrentNode(); 764 emit statusChanged(currentNode, stats, true); 765 } 766 void 767 TreeCanvas::labelPath(void) { 768 QMutexLocker locker(&mutex); 769 currentNode->labelPath(*na,curBest,c_d,a_d); 770 update(); 771 centerCurrentNode(); 772 emit statusChanged(currentNode, stats, true); 773 } 774 775 void 776 TreeCanvas::inspectSolution(const Space* s) { 777 int failedInspectorType = -1; 778 int failedInspector = -1; 779 try { 780 Space* c = nullptr; 781 for (int i=0; i<solutionInspectors.size(); i++) { 782 if (solutionInspectors[i].second) { 783 if (c == nullptr) 784 c = s->clone(); 785 failedInspectorType = 1; 786 failedInspector = i; 787 solutionInspectors[i].first->inspect(*c); 788 failedInspectorType = -1; 789 } 790 } 791 delete c; 792 } catch (Exception& e) { 793 switch (failedInspectorType) { 794 case 0: 795 qFatal("Exception in move inspector %d: %s.\n Stopping.", 796 failedInspector, e.what()); 797 break; 798 case 1: 799 qFatal("Exception in solution inspector %d: %s.\n Stopping.", 800 failedInspector, e.what()); 801 break; 802 default: 803 qFatal("Exception: %s.\n Stopping.", e.what()); 804 break; 805 } 806 } 807 } 808 809 void 810 TreeCanvas::stopSearch(void) { 811 stopSearchFlag = true; 812 layoutDoneTimerId = startTimer(15); 813 } 814 815 void 816 TreeCanvas::reset(void) { 817 QMutexLocker locker(&mutex); 818 Space* rootSpace = 819 root->getStatus() == FAILED ? nullptr : 820 root->getSpace(*na,curBest,c_d,a_d); 821 if (curBest != nullptr) { 822 delete curBest; 823 curBest = new BestNode(nullptr); 824 } 825 if (root) { 826 DisposeCursor dc(root,*na); 827 PreorderNodeVisitor<DisposeCursor>(dc).run(); 828 } 829 delete na; 830 na = new Node::NodeAllocator(curBest != nullptr); 831 int rootIdx = na->allocate(rootSpace); 832 assert(rootIdx == 0); (void) rootIdx; 833 root = (*na)[0]; 834 root->setMarked(true); 835 currentNode = root; 836 pathHead = root; 837 scale = 1.0; 838 stats = Statistics(); 839 for (int i=bookmarks.size(); i--;) 840 emit removedBookmark(i); 841 bookmarks.clear(); 842 root->layout(*na); 843 844 emit statusChanged(currentNode, stats, true); 845 update(); 846 } 847 848 void 849 TreeCanvas::bookmarkNode(void) { 850 QMutexLocker locker(&mutex); 851 if (!currentNode->isBookmarked()) { 852 bool ok; 853 QString text = 854 QInputDialog::getText(this, "Add bookmark", "Name:", 855 QLineEdit::Normal,"",&ok); 856 if (ok) { 857 currentNode->setBookmarked(true); 858 bookmarks.append(currentNode); 859 if (text == "") 860 text = QString("Node ")+QString().setNum(bookmarks.size()); 861 emit addedBookmark(text); 862 } 863 } else { 864 currentNode->setBookmarked(false); 865 int idx = bookmarks.indexOf(currentNode); 866 bookmarks.remove(idx); 867 emit removedBookmark(idx); 868 } 869 currentNode->dirtyUp(*na); 870 update(); 871 } 872 873 void 874 TreeCanvas::setPath(void) { 875 QMutexLocker locker(&mutex); 876 if(currentNode == pathHead) 877 return; 878 879 pathHead->unPathUp(*na); 880 pathHead = currentNode; 881 882 currentNode->pathUp(*na); 883 currentNode->dirtyUp(*na); 884 update(); 885 } 886 887 void 888 TreeCanvas::inspectPath(void) { 889 QMutexLocker locker(&mutex); 890 setCurrentNode(root); 891 if (currentNode->isOnPath()) { 892 inspectCurrentNode(); 893 int nextAlt = currentNode->getPathAlternative(*na); 894 while (nextAlt >= 0) { 895 setCurrentNode(currentNode->getChild(*na,nextAlt)); 896 inspectCurrentNode(); 897 nextAlt = currentNode->getPathAlternative(*na); 898 } 899 } 900 update(); 901 } 902 903 void 904 TreeCanvas::startCompareNodes(void) { 905 QMutexLocker locker(&mutex); 906 compareNodes = true; 907 compareNodesBeforeFP = false; 908 setCursor(QCursor(Qt::CrossCursor)); 909 } 910 911 void 912 TreeCanvas::startCompareNodesBeforeFP(void) { 913 QMutexLocker locker(&mutex); 914 compareNodes = true; 915 compareNodesBeforeFP = true; 916 setCursor(QCursor(Qt::CrossCursor)); 917 } 918 919 void 920 TreeCanvas::emitStatusChanged(void) { 921 emit statusChanged(currentNode, stats, true); 922 } 923 924 void 925 TreeCanvas::navUp(void) { 926 QMutexLocker locker(&mutex); 927 928 VisualNode* p = currentNode->getParent(*na); 929 930 setCurrentNode(p); 931 932 if (p != nullptr) { 933 centerCurrentNode(); 934 } 935 } 936 937 void 938 TreeCanvas::navDown(void) { 939 QMutexLocker locker(&mutex); 940 if (!currentNode->isHidden()) { 941 switch (currentNode->getStatus()) { 942 case STOP: 943 case UNSTOP: 944 case BRANCH: 945 { 946 int alt = std::max(0, currentNode->getPathAlternative(*na)); 947 VisualNode* n = currentNode->getChild(*na,alt); 948 setCurrentNode(n); 949 centerCurrentNode(); 950 break; 951 } 952 case SOLVED: 953 case FAILED: 954 case UNDETERMINED: 955 break; 956 } 957 } 958 } 959 960 void 961 TreeCanvas::navLeft(void) { 962 QMutexLocker locker(&mutex); 963 VisualNode* p = currentNode->getParent(*na); 964 if (p != nullptr) { 965 int alt = currentNode->getAlternative(*na); 966 if (alt > 0) { 967 VisualNode* n = p->getChild(*na,alt-1); 968 setCurrentNode(n); 969 centerCurrentNode(); 970 } 971 } 972 } 973 974 void 975 TreeCanvas::navRight(void) { 976 QMutexLocker locker(&mutex); 977 VisualNode* p = currentNode->getParent(*na); 978 if (p != nullptr) { 979 unsigned int alt = currentNode->getAlternative(*na); 980 if (alt + 1 < p->getNumberOfChildren()) { 981 VisualNode* n = p->getChild(*na,alt+1); 982 setCurrentNode(n); 983 centerCurrentNode(); 984 } 985 } 986 } 987 988 void 989 TreeCanvas::navRoot(void) { 990 QMutexLocker locker(&mutex); 991 setCurrentNode(root); 992 centerCurrentNode(); 993 } 994 995 void 996 TreeCanvas::navNextSol(bool back) { 997 QMutexLocker locker(&mutex); 998 NextSolCursor nsc(currentNode,back,*na); 999 PreorderNodeVisitor<NextSolCursor> nsv(nsc); 1000 nsv.run(); 1001 VisualNode* n = nsv.getCursor().node(); 1002 if (n != root) { 1003 setCurrentNode(n); 1004 centerCurrentNode(); 1005 } 1006 } 1007 1008 void 1009 TreeCanvas::navPrevSol(void) { 1010 navNextSol(true); 1011 } 1012 1013 void 1014 TreeCanvas::exportNodePDF(VisualNode* n) { 1015#if QT_VERSION >= 0x040400 1016 QString filename = QFileDialog::getSaveFileName(this, tr("Export tree as pdf"), "", tr("PDF (*.pdf)")); 1017 if (filename != "") { 1018 QPrinter printer(QPrinter::ScreenResolution); 1019 QMutexLocker locker(&mutex); 1020 1021 BoundingBox bb = n->getBoundingBox(); 1022 printer.setFullPage(true); 1023 printer.setPaperSize(QSizeF(bb.right-bb.left+Layout::extent, 1024 n->getShape()->depth() * Layout::dist_y + 1025 Layout::extent), QPrinter::Point); 1026 printer.setOutputFileName(filename); 1027 QPainter painter(&printer); 1028 1029 painter.setRenderHint(QPainter::Antialiasing); 1030 1031 QRect pageRect = printer.pageRect(); 1032 double newXScale = 1033 static_cast<double>(pageRect.width()) / (bb.right - bb.left + 1034 Layout::extent); 1035 double newYScale = 1036 static_cast<double>(pageRect.height()) / 1037 (n->getShape()->depth() * Layout::dist_y + 1038 Layout::extent); 1039 double printScale = std::min(newXScale, newYScale); 1040 painter.scale(printScale,printScale); 1041 1042 int printxtrans = -bb.left+(Layout::extent / 2); 1043 1044 painter.translate(printxtrans, Layout::dist_y / 2); 1045 QRect clip(0,0,0,0); 1046 DrawingCursor dc(n, *na, curBest, painter, clip, showCopies); 1047 currentNode->setMarked(false); 1048 PreorderNodeVisitor<DrawingCursor>(dc).run(); 1049 currentNode->setMarked(true); 1050 } 1051#else 1052 (void) n; 1053#endif 1054 } 1055 1056 void 1057 TreeCanvas::exportWholeTreePDF(void) { 1058#if QT_VERSION >= 0x040400 1059 exportNodePDF(root); 1060#endif 1061 } 1062 1063 void 1064 TreeCanvas::exportPDF(void) { 1065#if QT_VERSION >= 0x040400 1066 exportNodePDF(currentNode); 1067#endif 1068 } 1069 1070 void 1071 TreeCanvas::print(void) { 1072 QPrinter printer; 1073 if (QPrintDialog(&printer, this).exec() == QDialog::Accepted) { 1074 QMutexLocker locker(&mutex); 1075 1076 BoundingBox bb = root->getBoundingBox(); 1077 QRect pageRect = printer.pageRect(); 1078 double newXScale = 1079 static_cast<double>(pageRect.width()) / (bb.right - bb.left + 1080 Layout::extent); 1081 double newYScale = 1082 static_cast<double>(pageRect.height()) / 1083 (root->getShape()->depth() * Layout::dist_y + 1084 2*Layout::extent); 1085 double printScale = std::min(newXScale, newYScale)*100; 1086 if (printScale<1.0) 1087 printScale = 1.0; 1088 if (printScale > 400.0) 1089 printScale = 400.0; 1090 printScale = printScale / 100.0; 1091 1092 QPainter painter(&printer); 1093 painter.setRenderHint(QPainter::Antialiasing); 1094 painter.scale(printScale,printScale); 1095 painter.translate(xtrans, 0); 1096 QRect clip(0,0,0,0); 1097 DrawingCursor dc(root, *na, curBest, painter, clip, showCopies); 1098 PreorderNodeVisitor<DrawingCursor>(dc).run(); 1099 } 1100 } 1101 1102 VisualNode* 1103 TreeCanvas::eventNode(QEvent* event) { 1104 int x = 0; 1105 int y = 0; 1106 switch (event->type()) { 1107 case QEvent::ToolTip: 1108 { 1109 QHelpEvent* he = static_cast<QHelpEvent*>(event); 1110 x = he->x(); 1111 y = he->y(); 1112 break; 1113 } 1114 case QEvent::MouseButtonDblClick: 1115 case QEvent::MouseButtonPress: 1116 case QEvent::MouseButtonRelease: 1117 case QEvent::MouseMove: 1118 { 1119 QMouseEvent* me = static_cast<QMouseEvent*>(event); 1120 x = me->x(); 1121 y = me->y(); 1122 break; 1123 } 1124 case QEvent::ContextMenu: 1125 { 1126 QContextMenuEvent* ce = static_cast<QContextMenuEvent*>(event); 1127 x = ce->x(); 1128 y = ce->y(); 1129 break; 1130 } 1131 default: 1132 return nullptr; 1133 } 1134 QAbstractScrollArea* sa = 1135 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget()); 1136 int xoff = sa->horizontalScrollBar()->value()/scale; 1137 int yoff = sa->verticalScrollBar()->value()/scale; 1138 1139 BoundingBox bb = root->getBoundingBox(); 1140 int w = 1141 static_cast<int>((bb.right-bb.left+Layout::extent)*scale); 1142 if (w < sa->viewport()->width()) 1143 xoff -= (sa->viewport()->width()-w)/2; 1144 1145 VisualNode* n; 1146 n = root->findNode(*na, 1147 static_cast<int>(x/scale-xtrans+xoff), 1148 static_cast<int>((y-30)/scale+yoff)); 1149 return n; 1150 } 1151 1152 bool 1153 TreeCanvas::event(QEvent* event) { 1154 if (mutex.tryLock()) { 1155 if (event->type() == QEvent::ToolTip) { 1156 VisualNode* n = eventNode(event); 1157 if (n != nullptr) { 1158 QHelpEvent* he = static_cast<QHelpEvent*>(event); 1159 QToolTip::showText(he->globalPos(), 1160 QString(n->toolTip(*na,curBest, 1161 c_d,a_d).c_str())); 1162 } else { 1163 QToolTip::hideText(); 1164 } 1165 } 1166 mutex.unlock(); 1167 } 1168 return QWidget::event(event); 1169 } 1170 1171 void 1172 TreeCanvas::resizeToOuter(void) { 1173 if (autoZoom) 1174 zoomToFit(); 1175 } 1176 1177 void 1178 TreeCanvas::paintEvent(QPaintEvent* event) { 1179 QMutexLocker locker(&layoutMutex); 1180 QPainter painter(this); 1181 painter.setRenderHint(QPainter::Antialiasing); 1182 1183 QAbstractScrollArea* sa = 1184 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget()); 1185 int xoff = sa->horizontalScrollBar()->value()/scale; 1186 int yoff = sa->verticalScrollBar()->value()/scale; 1187 1188 BoundingBox bb = root->getBoundingBox(); 1189 int w = 1190 static_cast<int>((bb.right-bb.left+Layout::extent)*scale); 1191 if (w < sa->viewport()->width()) 1192 xoff -= (sa->viewport()->width()-w)/2; 1193 1194 QRect origClip = event->rect(); 1195 painter.translate(0, 30); 1196 painter.scale(scale,scale); 1197 painter.translate(xtrans-xoff, -yoff); 1198 QRect clip(static_cast<int>(origClip.x()/scale-xtrans+xoff), 1199 static_cast<int>(origClip.y()/scale+yoff), 1200 static_cast<int>(origClip.width()/scale), 1201 static_cast<int>(origClip.height()/scale)); 1202 DrawingCursor dc(root, *na, curBest, painter, clip, showCopies); 1203 PreorderNodeVisitor<DrawingCursor>(dc).run(); 1204 1205 // int nodesLayouted = 1; 1206 // clock_t t0 = clock(); 1207 // while (v.next()) { nodesLayouted++; } 1208 // double t = (static_cast<double>(clock()-t0) / CLOCKS_PER_SEC) * 1000.0; 1209 // double nps = static_cast<double>(nodesLayouted) / 1210 // (static_cast<double>(clock()-t0) / CLOCKS_PER_SEC); 1211 // std::cout << "Drawing done. " << nodesLayouted << " nodes in " 1212 // << t << " ms. " << nps << " nodes/s." << std::endl; 1213 1214 } 1215 1216 void 1217 TreeCanvas::mouseDoubleClickEvent(QMouseEvent* event) { 1218 if (mutex.tryLock()) { 1219 if(event->button() == Qt::LeftButton) { 1220 VisualNode* n = eventNode(event); 1221 if(n == currentNode) { 1222 inspectCurrentNode(); 1223 event->accept(); 1224 mutex.unlock(); 1225 return; 1226 } 1227 } 1228 mutex.unlock(); 1229 } 1230 event->ignore(); 1231 } 1232 1233 void 1234 TreeCanvas::contextMenuEvent(QContextMenuEvent* event) { 1235 if (mutex.tryLock()) { 1236 VisualNode* n = eventNode(event); 1237 if (n != nullptr) { 1238 setCurrentNode(n); 1239 emit contextMenu(event); 1240 event->accept(); 1241 mutex.unlock(); 1242 return; 1243 } 1244 mutex.unlock(); 1245 } 1246 event->ignore(); 1247 } 1248 1249 void 1250 TreeCanvas::resizeEvent(QResizeEvent* e) { 1251 QAbstractScrollArea* sa = 1252 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget()); 1253 1254 int w = sa->horizontalScrollBar()->maximum()+e->oldSize().width(); 1255 int h = sa->verticalScrollBar()->maximum()+e->oldSize().height(); 1256 1257 sa->horizontalScrollBar()->setRange(0,w-e->size().width()); 1258 sa->verticalScrollBar()->setRange(0,h-e->size().height()); 1259 sa->horizontalScrollBar()->setPageStep(e->size().width()); 1260 sa->verticalScrollBar()->setPageStep(e->size().height()); 1261 } 1262 1263 void 1264 TreeCanvas::wheelEvent(QWheelEvent* event) { 1265 if (event->modifiers() & Qt::ShiftModifier) { 1266 event->accept(); 1267 if (event->orientation() == Qt::Vertical && !autoZoom) 1268 scaleTree(scale*100+ceil(static_cast<double>(event->delta())/4.0), 1269 event->x(), event->y()); 1270 } else { 1271 event->ignore(); 1272 } 1273 } 1274 1275 bool 1276 TreeCanvas::finish(void) { 1277 if (finishedFlag) 1278 return true; 1279 stopSearchFlag = true; 1280 finishedFlag = true; 1281 for (int i=0; i<doubleClickInspectors.size(); i++) 1282 doubleClickInspectors[i].first->finalize(); 1283 for (int i=0; i<solutionInspectors.size(); i++) 1284 solutionInspectors[i].first->finalize(); 1285 for (int i=0; i<moveInspectors.size(); i++) 1286 moveInspectors[i].first->finalize(); 1287 for (int i=0; i<comparators.size(); i++) 1288 comparators[i].first->finalize(); 1289 return !searcher.isRunning(); 1290 } 1291 1292 void 1293 TreeCanvas::setCurrentNode(VisualNode* n, bool finished, bool update) { 1294 if (finished) 1295 mutex.lock(); 1296 if (update && n != nullptr && n != currentNode && 1297 n->getStatus() != UNDETERMINED && !n->isHidden()) { 1298 Space* curSpace = nullptr; 1299 for (int i=0; i<moveInspectors.size(); i++) { 1300 if (moveInspectors[i].second) { 1301 if (curSpace == nullptr) 1302 curSpace = n->getSpace(*na,curBest,c_d,a_d); 1303 try { 1304 moveInspectors[i].first->inspect(*curSpace); 1305 } catch (Exception& e) { 1306 qFatal("Exception in move inspector %d: %s.\n Stopping.", 1307 i, e.what()); 1308 } 1309 } 1310 } 1311 } 1312 if (n != nullptr) { 1313 currentNode->setMarked(false); 1314 currentNode = n; 1315 currentNode->setMarked(true); 1316 emit statusChanged(currentNode,stats,finished); 1317 if (update) { 1318 compareNodes = false; 1319 setCursor(QCursor(Qt::ArrowCursor)); 1320 QWidget::update(); 1321 } 1322 } 1323 if (finished) 1324 mutex.unlock(); 1325 } 1326 1327 void 1328 TreeCanvas::mousePressEvent(QMouseEvent* event) { 1329 if (mutex.tryLock()) { 1330 if (event->button() == Qt::LeftButton) { 1331 VisualNode* n = eventNode(event); 1332 if (compareNodes) { 1333 if (n != nullptr && n->getStatus() != UNDETERMINED && 1334 currentNode != nullptr && 1335 currentNode->getStatus() != UNDETERMINED) { 1336 Space* curSpace = nullptr; 1337 Space* compareSpace = nullptr; 1338 for (int i=0; i<comparators.size(); i++) { 1339 if (comparators[i].second) { 1340 if (curSpace == nullptr) { 1341 curSpace = currentNode->getSpace(*na,curBest,c_d,a_d); 1342 1343 if (!compareNodesBeforeFP || n->isRoot()) { 1344 compareSpace = n->getSpace(*na,curBest,c_d,a_d); 1345 } else { 1346 VisualNode* p = n->getParent(*na); 1347 compareSpace = p->getSpace(*na,curBest,c_d,a_d); 1348 switch (compareSpace->status()) { 1349 case SS_SOLVED: 1350 case SS_FAILED: 1351 break; 1352 case SS_BRANCH: 1353 compareSpace->commit(*p->getChoice(), 1354 n->getAlternative(*na)); 1355 break; 1356 default: 1357 GECODE_NEVER; 1358 } 1359 } 1360 } 1361 try { 1362 comparators[i].first->compare(*curSpace,*compareSpace); 1363 } catch (Exception& e) { 1364 qFatal("Exception in comparator %d: %s.\n Stopping.", 1365 i, e.what()); 1366 } 1367 } 1368 } 1369 } 1370 } else { 1371 setCurrentNode(n); 1372 } 1373 compareNodes = false; 1374 setCursor(QCursor(Qt::ArrowCursor)); 1375 if (n != nullptr) { 1376 event->accept(); 1377 mutex.unlock(); 1378 return; 1379 } 1380 } 1381 mutex.unlock(); 1382 } 1383 event->ignore(); 1384 } 1385 1386 void 1387 TreeCanvas::setRecompDistances(int c_d0, int a_d0) { 1388 c_d = c_d0; a_d = a_d0; 1389 } 1390 1391 void 1392 TreeCanvas::setAutoHideFailed(bool b) { 1393 autoHideFailed = b; 1394 } 1395 1396 void 1397 TreeCanvas::setAutoZoom(bool b) { 1398 autoZoom = b; 1399 if (autoZoom) { 1400 zoomToFit(); 1401 } 1402 emit autoZoomChanged(b); 1403 scaleBar->setEnabled(!b); 1404 } 1405 1406 void 1407 TreeCanvas::setShowCopies(bool b) { 1408 showCopies = b; 1409 } 1410 bool 1411 TreeCanvas::getShowCopies(void) { 1412 return showCopies; 1413 } 1414 1415 bool 1416 TreeCanvas::getAutoHideFailed(void) { 1417 return autoHideFailed; 1418 } 1419 1420 bool 1421 TreeCanvas::getAutoZoom(void) { 1422 return autoZoom; 1423 } 1424 1425 void 1426 TreeCanvas::setRefresh(int i) { 1427 refresh = i; 1428 } 1429 1430 void 1431 TreeCanvas::setRefreshPause(int i) { 1432 refreshPause = i; 1433 if (refreshPause > 0) 1434 refresh = 1; 1435 } 1436 1437 bool 1438 TreeCanvas::getSmoothScrollAndZoom(void) { 1439 return smoothScrollAndZoom; 1440 } 1441 1442 void 1443 TreeCanvas::setSmoothScrollAndZoom(bool b) { 1444 smoothScrollAndZoom = b; 1445 } 1446 1447 bool 1448 TreeCanvas::getMoveDuringSearch(void) { 1449 return moveDuringSearch; 1450 } 1451 1452 void 1453 TreeCanvas::setMoveDuringSearch(bool b) { 1454 moveDuringSearch = b; 1455 } 1456 1457}} 1458 1459// STATISTICS: gist-any