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 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
00662
00663
00664
00665
00666
00667
00668
00669
00670
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
00681
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
01197
01198
01199
01200
01201
01202
01203
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