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