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