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