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/layoutcursor.hh>
00047 #include <gecode/gist/visualnode.hh>
00048 #include <gecode/gist/drawingcursor.hh>
00049
00050 #include <gecode/search.hh>
00051 #include <gecode/search/support.hh>
00052
00053 namespace Gecode { namespace Gist {
00054
00055 TreeCanvas::TreeCanvas(Space* rootSpace, bool bab,
00056 QWidget* parent, const Options& opt)
00057 : QWidget(parent)
00058 , mutex(QMutex::Recursive)
00059 , layoutMutex(QMutex::Recursive)
00060 , finishedFlag(false)
00061 , autoHideFailed(true), autoZoom(false)
00062 , refresh(500), smoothScrollAndZoom(false), nextPit(0)
00063 , targetZoom(LayoutConfig::defScale)
00064 , metaZoomCurrent(static_cast<double>(LayoutConfig::defScale))
00065 , zoomTimerId(0)
00066 , targetScrollX(0), targetScrollY(0)
00067 , metaScrollXCurrent(0.0), metaScrollYCurrent(0.0)
00068 , scrollTimerId(0)
00069 , targetW(0), targetH(0), targetScale(0)
00070 , layoutDoneTimerId(0) {
00071 QMutexLocker locker(&mutex);
00072 curBest = (bab ? new BestNode(NULL) : NULL);
00073 if (rootSpace->status() == SS_FAILED) {
00074 rootSpace = NULL;
00075 } else {
00076 rootSpace = Gecode::Search::snapshot(rootSpace,opt);
00077 }
00078 na = new Node::NodeAllocator();
00079 root = new (*na) VisualNode(rootSpace);
00080 root->layout();
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(&searcher, SIGNAL(solution(const Space*)),
00097 this, SLOT(inspectSolution(const Space*)),
00098 Qt::BlockingQueuedConnection);
00099
00100 connect(&searcher, SIGNAL(finished(void)), this, SIGNAL(finished(void)));
00101
00102 qRegisterMetaType<Statistics>("Statistics");
00103 update();
00104 }
00105
00106 TreeCanvas::~TreeCanvas(void) { delete root; delete na; }
00107
00108 void
00109 TreeCanvas::addDoubleClickInspector(Inspector* i) {
00110 doubleClickInspectors.append(QPair<Inspector*,bool>(i,false));
00111 }
00112
00113 void
00114 TreeCanvas::activateDoubleClickInspector(int i, bool active) {
00115 doubleClickInspectors[i].second = active;
00116 }
00117
00118 void
00119 TreeCanvas::addSolutionInspector(Inspector* i) {
00120 solutionInspectors.append(QPair<Inspector*,bool>(i,false));
00121 }
00122
00123 void
00124 TreeCanvas::activateSolutionInspector(int i, bool active) {
00125 solutionInspectors[i].second = active;
00126 }
00127
00128 void
00129 TreeCanvas::scaleTree(int scale0) {
00130 QMutexLocker locker(&layoutMutex);
00131 BoundingBox bb;
00132 scale0 = std::min(std::max(scale0, LayoutConfig::minScale),
00133 LayoutConfig::maxScale);
00134 scale = (static_cast<double>(scale0)) / 100.0;
00135 bb = root->getBoundingBox();
00136 int w =
00137 static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
00138 int h =
00139 static_cast<int>(2*Layout::extent+
00140 root->getShape()->depth()*Layout::dist_y*scale);
00141 resize(w,h);
00142 emit scaleChanged(scale0);
00143 QWidget::update();
00144 }
00145
00146 void
00147 TreeCanvas::update(void) {
00148 QMutexLocker locker(&mutex);
00149 layoutMutex.lock();
00150 if (root != NULL) {
00151 root->layout();
00152 BoundingBox bb = root->getBoundingBox();
00153
00154 int w = static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
00155 int h =
00156 static_cast<int>(2*Layout::extent+
00157 root->getShape()->depth()*Layout::dist_y*scale);
00158 xtrans = -bb.left+(Layout::extent / 2);
00159 resize(w,h);
00160 }
00161 if (autoZoom)
00162 zoomToFit();
00163 layoutMutex.unlock();
00164 QWidget::update();
00165 }
00166
00167 void
00168 TreeCanvas::layoutDone(int w, int h, int scale0) {
00169 targetW = w; targetH = h; targetScale = scale0;
00170 if (layoutDoneTimerId == 0)
00171 layoutDoneTimerId = startTimer(15);
00172 }
00173
00174 void
00175 TreeCanvas::statusChanged(bool finished) {
00176 if (finished) {
00177 update();
00178 centerCurrentNode();
00179 }
00180 emit statusChanged(currentNode, stats, finished);
00181 }
00182
00183 void
00184 SearcherThread::search(VisualNode* n, bool all, TreeCanvas* ti) {
00185 node = n;
00186
00187 depth = -1;
00188 for (VisualNode* p = n; p != NULL; p = p->getParent())
00189 depth++;
00190
00191 a = all;
00192 t = ti;
00193 start();
00194 }
00195
00196 void
00197 SearcherThread::updateCanvas(void) {
00198 t->layoutMutex.lock();
00199 if (t->root == NULL)
00200 return;
00201
00202 if (t->autoHideFailed) {
00203 t->root->hideFailed();
00204 }
00205 for (VisualNode* n = t->currentNode; n != NULL; n = n->getParent()) {
00206 if (n->isHidden()) {
00207 t->currentNode->setMarked(false);
00208 t->currentNode = n;
00209 t->currentNode->setMarked(true);
00210 break;
00211 }
00212 }
00213
00214 t->root->layout();
00215 BoundingBox bb = t->root->getBoundingBox();
00216
00217 int w = static_cast<int>((bb.right-bb.left+Layout::extent)*t->scale);
00218 int h = static_cast<int>(2*Layout::extent+
00219 t->root->getShape()->depth()
00220 *Layout::dist_y*t->scale);
00221 t->xtrans = -bb.left+(Layout::extent / 2);
00222
00223 int scale0 = static_cast<int>(t->scale*100);
00224 if (t->autoZoom) {
00225 QWidget* p = t->parentWidget();
00226 if (p) {
00227 double newXScale =
00228 static_cast<double>(p->width()) / (bb.right - bb.left +
00229 Layout::extent);
00230 double newYScale =
00231 static_cast<double>(p->height()) /
00232 (t->root->getShape()->depth() * Layout::dist_y + 2*Layout::extent);
00233
00234 scale0 = static_cast<int>(std::min(newXScale, newYScale)*100);
00235 if (scale0<LayoutConfig::minScale)
00236 scale0 = LayoutConfig::minScale;
00237 if (scale0>LayoutConfig::maxAutoZoomScale)
00238 scale0 = LayoutConfig::maxAutoZoomScale;
00239 double scale = (static_cast<double>(scale0)) / 100.0;
00240
00241 w = static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
00242 h = static_cast<int>(2*Layout::extent+
00243 t->root->getShape()->depth()*Layout::dist_y*scale);
00244 }
00245 }
00246 t->layoutMutex.unlock();
00247 emit update(w,h,scale0);
00248 }
00249
00250 class SearchItem {
00251 public:
00252 VisualNode* n;
00253 int i;
00254 int noOfChildren;
00255 SearchItem(VisualNode* n0, int noOfChildren0)
00256 : n(n0), i(-1), noOfChildren(noOfChildren0) {}
00257 };
00258
00259 void
00260 SearcherThread::run() {
00261 {
00262 if (!node->isOpen())
00263 return;
00264 t->mutex.lock();
00265 emit statusChanged(false);
00266
00267 unsigned int kids =
00268 node->getNumberOfChildNodes(*t->na, t->curBest, t->stats,
00269 t->c_d, t->a_d);
00270 if (kids == 0) {
00271 t->mutex.unlock();
00272 updateCanvas();
00273 emit statusChanged(true);
00274 return;
00275 }
00276
00277 std::stack<SearchItem> stck;
00278 stck.push(SearchItem(node,kids));
00279 t->stats.maxDepth =
00280 std::max(static_cast<long unsigned int>(t->stats.maxDepth),
00281 static_cast<long unsigned int>(depth+stck.size()));
00282
00283 VisualNode* sol = NULL;
00284 int nodeCount = 0;
00285 t->stopSearchFlag = false;
00286 while (!stck.empty() && !t->stopSearchFlag) {
00287 if (t->refresh > 0 && ++nodeCount > t->refresh) {
00288 node->dirtyUp();
00289 updateCanvas();
00290 emit statusChanged(false);
00291 nodeCount = 0;
00292 }
00293 SearchItem& si = stck.top();
00294 si.i++;
00295 if (si.i == si.noOfChildren) {
00296 stck.pop();
00297 } else {
00298 VisualNode* n = si.n->getChild(si.i);
00299 if (n->isOpen()) {
00300 kids = n->getNumberOfChildNodes(*t->na, t->curBest, t->stats,
00301 t->c_d, t->a_d);
00302 if (kids == 0) {
00303 if (n->getStatus() == SOLVED) {
00304 assert(n->hasWorkingSpace());
00305 emit solution(n->getWorkingSpace());
00306 n->purge();
00307 sol = n;
00308 if (!a)
00309 break;
00310 }
00311 } else {
00312 stck.push(SearchItem(n,kids));
00313 t->stats.maxDepth =
00314 std::max(static_cast<long unsigned int>(t->stats.maxDepth),
00315 static_cast<long unsigned int>(depth+stck.size()));
00316 }
00317 }
00318 }
00319 }
00320 node->dirtyUp();
00321 t->stopSearchFlag = false;
00322 t->mutex.unlock();
00323 if (sol != NULL) {
00324 t->setCurrentNode(sol);
00325 } else {
00326 t->setCurrentNode(node);
00327 }
00328 }
00329 updateCanvas();
00330 emit statusChanged(true);
00331 if (t->finishedFlag)
00332 emit finished();
00333 }
00334
00335 void
00336 TreeCanvas::searchAll(void) {
00337 QMutexLocker locker(&mutex);
00338 searcher.search(currentNode, true, this);
00339 }
00340
00341 void
00342 TreeCanvas::searchOne(void) {
00343 QMutexLocker locker(&mutex);
00344 searcher.search(currentNode, false, this);
00345 }
00346
00347 void
00348 TreeCanvas::toggleHidden(void) {
00349 QMutexLocker locker(&mutex);
00350 currentNode->toggleHidden();
00351 update();
00352 centerCurrentNode();
00353 emit statusChanged(currentNode, stats, true);
00354 }
00355
00356 void
00357 TreeCanvas::hideFailed(void) {
00358 QMutexLocker locker(&mutex);
00359 currentNode->hideFailed();
00360 update();
00361 centerCurrentNode();
00362 emit statusChanged(currentNode, stats, true);
00363 }
00364
00365 void
00366 TreeCanvas::unhideAll(void) {
00367 QMutexLocker locker(&mutex);
00368 QMutexLocker layoutLocker(&layoutMutex);
00369 currentNode->unhideAll();
00370 update();
00371 centerCurrentNode();
00372 emit statusChanged(currentNode, stats, true);
00373 }
00374
00375 void
00376 TreeCanvas::timerEvent(QTimerEvent* e) {
00377 if (e->timerId() == zoomTimerId) {
00378 double offset = static_cast<double>(targetZoom - metaZoomCurrent) / 6.0;
00379 metaZoomCurrent += offset;
00380 scaleBar->setValue(static_cast<int>(metaZoomCurrent));
00381 if (static_cast<int>(metaZoomCurrent+.5) == targetZoom) {
00382 killTimer(zoomTimerId);
00383 zoomTimerId = 0;
00384 }
00385 } else if (e->timerId() == scrollTimerId) {
00386 QScrollArea* sa =
00387 static_cast<QScrollArea*>(parentWidget()->parentWidget());
00388
00389 double xoffset =
00390 static_cast<double>(targetScrollX - metaScrollXCurrent) / 6.0;
00391 metaScrollXCurrent += xoffset;
00392 sa->horizontalScrollBar()
00393 ->setValue(static_cast<int>(metaScrollXCurrent));
00394 double yoffset =
00395 static_cast<double>(targetScrollY - metaScrollYCurrent) / 6.0;
00396 metaScrollYCurrent += yoffset;
00397 sa->verticalScrollBar()
00398 ->setValue(static_cast<int>(metaScrollYCurrent));
00399
00400 if (static_cast<int>(metaScrollXCurrent+.5) == targetScrollX &&
00401 static_cast<int>(metaScrollYCurrent+.5) == targetScrollY) {
00402 killTimer(scrollTimerId);
00403 scrollTimerId = 0;
00404 }
00405 } else if (e->timerId() == layoutDoneTimerId) {
00406 if (!smoothScrollAndZoom) {
00407 scaleTree(targetScale);
00408 } else {
00409 metaZoomCurrent = static_cast<int>(scale*100);
00410 targetZoom = targetScale;
00411 targetZoom = std::min(std::max(targetZoom, LayoutConfig::minScale),
00412 LayoutConfig::maxAutoZoomScale);
00413 zoomTimerId = startTimer(15);
00414 }
00415 resize(targetW,targetH);
00416 QWidget::update();
00417 killTimer(layoutDoneTimerId);
00418 layoutDoneTimerId = 0;
00419 }
00420 }
00421
00422 void
00423 TreeCanvas::zoomToFit(void) {
00424 QMutexLocker locker(&layoutMutex);
00425 if (root != NULL) {
00426 BoundingBox bb;
00427 bb = root->getBoundingBox();
00428 QWidget* p = parentWidget();
00429 if (p) {
00430 double newXScale =
00431 static_cast<double>(p->width()) / (bb.right - bb.left +
00432 Layout::extent);
00433 double newYScale =
00434 static_cast<double>(p->height()) / (root->getShape()->depth() *
00435 Layout::dist_y +
00436 2*Layout::extent);
00437 int scale0 = static_cast<int>(std::min(newXScale, newYScale)*100);
00438 if (scale0<LayoutConfig::minScale)
00439 scale0 = LayoutConfig::minScale;
00440 if (scale0>LayoutConfig::maxAutoZoomScale)
00441 scale0 = LayoutConfig::maxAutoZoomScale;
00442
00443 if (!smoothScrollAndZoom) {
00444 scaleTree(scale0);
00445 } else {
00446 metaZoomCurrent = static_cast<int>(scale*100);
00447 targetZoom = scale0;
00448 targetZoom = std::min(std::max(targetZoom, LayoutConfig::minScale),
00449 LayoutConfig::maxAutoZoomScale);
00450 zoomTimerId = startTimer(15);
00451 }
00452 }
00453 }
00454 }
00455
00456 void
00457 TreeCanvas::centerCurrentNode(void) {
00458 QMutexLocker locker(&mutex);
00459 int x=0;
00460 int y=0;
00461
00462 VisualNode* c = currentNode;
00463 while (c != NULL) {
00464 x += c->getOffset();
00465 y += Layout::dist_y;
00466 c = c->getParent();
00467 }
00468
00469 x = static_cast<int>((xtrans+x)*scale); y = static_cast<int>(y*scale);
00470
00471 QScrollArea* sa =
00472 static_cast<QScrollArea*>(parentWidget()->parentWidget());
00473
00474 if (!smoothScrollAndZoom) {
00475 sa->ensureVisible(x,y);
00476 } else {
00477 x -= sa->viewport()->width() / 2;
00478 y -= sa->viewport()->height() / 2;
00479
00480 metaScrollXCurrent = sa->horizontalScrollBar()->value();
00481 metaScrollYCurrent = sa->verticalScrollBar()->value();
00482 targetScrollX = std::max(sa->horizontalScrollBar()->minimum(), x);
00483 targetScrollX = std::min(sa->horizontalScrollBar()->maximum(),
00484 targetScrollX);
00485 targetScrollY = std::max(sa->verticalScrollBar()->minimum(), y);
00486 targetScrollY = std::min(sa->verticalScrollBar()->maximum(),
00487 targetScrollY);
00488 scrollTimerId = startTimer(15);
00489 }
00490 }
00491
00492 void
00493 TreeCanvas::inspectCurrentNode(void) {
00494 QMutexLocker locker(&mutex);
00495
00496 if (currentNode->isHidden()) {
00497 toggleHidden();
00498 return;
00499 }
00500
00501 switch (currentNode->getStatus()) {
00502 case UNDETERMINED:
00503 {
00504 unsigned int kids =
00505 currentNode->getNumberOfChildNodes(*na,curBest,stats,c_d,a_d);
00506 int depth = -1;
00507 for (VisualNode* p = currentNode; p != NULL; p = p->getParent())
00508 depth++;
00509 if (kids > 0)
00510 depth++;
00511 stats.maxDepth =
00512 std::max(stats.maxDepth, depth);
00513 if (currentNode->getStatus() == SOLVED) {
00514 assert(currentNode->hasWorkingSpace());
00515 emit solution(currentNode->getWorkingSpace());
00516 currentNode->purge();
00517 }
00518 emit statusChanged(currentNode,stats,true);
00519 }
00520 break;
00521 case FAILED:
00522 case STEP:
00523 case SPECIAL:
00524 case BRANCH:
00525 case SOLVED:
00526 {
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538 if (currentNode->isRoot() && currentNode->getStatus() == FAILED)
00539 break;
00540 Space* curSpace = currentNode->getSpace(curBest,c_d,a_d);
00541 if (currentNode->getStatus() == SOLVED &&
00542 curSpace->status() != SS_SOLVED) {
00543
00544
00545 Space* dfsSpace = Gecode::dfs(curSpace);
00546 delete curSpace;
00547 curSpace = dfsSpace;
00548 }
00549 saveCurrentNode();
00550
00551 for (int i=0; i<doubleClickInspectors.size(); i++) {
00552 if (doubleClickInspectors[i].second) {
00553 doubleClickInspectors[i].first->inspect(*curSpace);
00554 }
00555 }
00556 delete curSpace;
00557 }
00558 break;
00559 }
00560
00561 currentNode->dirtyUp();
00562 update();
00563 centerCurrentNode();
00564 }
00565
00566 void
00567 TreeCanvas::inspectSolution(const Space* s) {
00568 Space* c = NULL;
00569 for (int i=0; i<solutionInspectors.size(); i++) {
00570 if (solutionInspectors[i].second) {
00571 if (c == NULL)
00572 c = s->clone();
00573 solutionInspectors[i].first->inspect(*c);
00574 }
00575 }
00576 delete c;
00577 }
00578
00579 void
00580 TreeCanvas::stopSearch(void) {
00581 stopSearchFlag = true;
00582 layoutDoneTimerId = startTimer(15);
00583 }
00584
00585 void
00586 TreeCanvas::reset(void) {
00587 QMutexLocker locker(&mutex);
00588 Space* rootSpace =
00589 root->getStatus() == FAILED ? NULL : root->getSpace(curBest,c_d,a_d);
00590 if (curBest != NULL) {
00591 delete curBest;
00592 curBest = new BestNode(NULL);
00593 }
00594 delete root;
00595 delete na;
00596 na = new Node::NodeAllocator();
00597 root = new (*na) VisualNode(rootSpace);
00598 root->setMarked(true);
00599 currentNode = root;
00600 pathHead = root;
00601 nodeMap.clear();
00602 nextPit = 0;
00603 scale = 1.0;
00604 stats = Statistics();
00605 root->layout();
00606
00607 emit statusChanged(currentNode, stats, true);
00608 update();
00609 }
00610
00611 void
00612 TreeCanvas::setPath(void) {
00613 QMutexLocker locker(&mutex);
00614 if(currentNode == pathHead)
00615 return;
00616
00617 pathHead->unPathUp();
00618 pathHead = currentNode;
00619
00620 currentNode->pathUp();
00621 currentNode->dirtyUp();
00622 update();
00623 }
00624
00625 void
00626 TreeCanvas::inspectPath(void) {
00627 QMutexLocker locker(&mutex);
00628 setCurrentNode(root);
00629 if (currentNode->isOnPath()) {
00630 inspectCurrentNode();
00631 int nextAlt = currentNode->getPathAlternative();
00632 while (nextAlt >= 0) {
00633 setCurrentNode(currentNode->getChild(nextAlt));
00634 inspectCurrentNode();
00635 nextAlt = currentNode->getPathAlternative();
00636 }
00637 }
00638 update();
00639 }
00640
00641 void
00642 TreeCanvas::emitStatusChanged(void) {
00643 emit statusChanged(currentNode, stats, true);
00644 }
00645
00646 void
00647 TreeCanvas::navUp(void) {
00648 QMutexLocker locker(&mutex);
00649
00650 VisualNode* p = currentNode->getParent();
00651
00652 setCurrentNode(p);
00653
00654 if (p != NULL) {
00655 centerCurrentNode();
00656 }
00657 }
00658
00659 void
00660 TreeCanvas::navDown(void) {
00661 QMutexLocker locker(&mutex);
00662 if (!currentNode->isHidden()) {
00663 switch (currentNode->getStatus()) {
00664 case STEP:
00665 case SPECIAL:
00666 if (currentNode->getNumberOfChildren() < 1)
00667 break;
00668 case BRANCH:
00669 {
00670 int alt = std::max(0, currentNode->getPathAlternative());
00671 VisualNode* n = currentNode->getChild(alt);
00672 setCurrentNode(n);
00673 centerCurrentNode();
00674 break;
00675 }
00676 case SOLVED:
00677 case FAILED:
00678 case UNDETERMINED:
00679 break;
00680 }
00681 }
00682 }
00683
00684 void
00685 TreeCanvas::navLeft(void) {
00686 QMutexLocker locker(&mutex);
00687 VisualNode* p = currentNode->getParent();
00688 if (p != NULL) {
00689 int alt = currentNode->getAlternative();
00690 if (alt > 0) {
00691 VisualNode* n = p->getChild(alt-1);
00692 setCurrentNode(n);
00693 centerCurrentNode();
00694 }
00695 }
00696 }
00697
00698 void
00699 TreeCanvas::navRight(void) {
00700 QMutexLocker locker(&mutex);
00701 VisualNode* p = currentNode->getParent();
00702 if (p != NULL) {
00703 unsigned int alt = currentNode->getAlternative();
00704 if (alt + 1 < p->getNumberOfChildren()) {
00705 VisualNode* n = p->getChild(alt+1);
00706 setCurrentNode(n);
00707 centerCurrentNode();
00708 }
00709 }
00710 }
00711
00712 void
00713 TreeCanvas::navRoot(void) {
00714 QMutexLocker locker(&mutex);
00715 setCurrentNode(root);
00716 centerCurrentNode();
00717 }
00718
00719 void
00720 TreeCanvas::navNextSol(bool back) {
00721 QMutexLocker locker(&mutex);
00722 NextSolCursor nsc(currentNode, back);
00723 PreorderNodeVisitor<NextSolCursor> nsv(nsc);
00724 while (nsv.next()) {}
00725 if (nsv.getCursor().node() != root) {
00726 setCurrentNode(nsv.getCursor().node());
00727 centerCurrentNode();
00728 }
00729 }
00730
00731 void
00732 TreeCanvas::navPrevSol(void) {
00733 navNextSol(true);
00734 }
00735
00736 void
00737 TreeCanvas::markCurrentNode(int pit) {
00738 QMutexLocker locker(&mutex);
00739 if(nodeMap.size() > pit && nodeMap[pit] != NULL) {
00740 setCurrentNode(nodeMap[pit]);
00741 centerCurrentNode();
00742 emit pointInTimeChanged(pit);
00743 }
00744 }
00745
00746 void
00747 TreeCanvas::saveCurrentNode(void) {
00748 QMutexLocker locker(&mutex);
00749 assert(nextPit == nodeMap.size());
00750 nodeMap << currentNode;
00751 nextPit++;
00752 }
00753
00754 void
00755 TreeCanvas::exportNodePDF(VisualNode* n) {
00756 #if QT_VERSION >= 0x040400
00757 QString filename = QFileDialog::getSaveFileName(this, tr("Export tree as pdf"), "", tr("PDF (*.pdf)"));
00758 if (filename != "") {
00759 QPrinter printer(QPrinter::ScreenResolution);
00760 QMutexLocker locker(&mutex);
00761
00762 BoundingBox bb = n->getBoundingBox();
00763 printer.setFullPage(true);
00764 printer.setPaperSize(QSizeF(bb.right-bb.left+Layout::extent,
00765 n->getShape()->depth() * Layout::dist_y +
00766 Layout::extent), QPrinter::Point);
00767 printer.setOutputFileName(filename);
00768 QPainter painter(&printer);
00769
00770 painter.setRenderHint(QPainter::Antialiasing);
00771
00772 QRect pageRect = printer.pageRect();
00773 double newXScale =
00774 static_cast<double>(pageRect.width()) / (bb.right - bb.left +
00775 Layout::extent);
00776 double newYScale =
00777 static_cast<double>(pageRect.height()) /
00778 (n->getShape()->depth() * Layout::dist_y +
00779 Layout::extent);
00780 double printScale = std::min(newXScale, newYScale);
00781 painter.scale(printScale,printScale);
00782
00783 int printxtrans = -bb.left+(Layout::extent / 2);
00784
00785 painter.translate(printxtrans, Layout::dist_y / 2);
00786 QRect clip(0,0,0,0);
00787 DrawingCursor dc(n, curBest, painter, clip, showCopies);
00788 currentNode->setMarked(false);
00789 PreorderNodeVisitor<DrawingCursor> v(dc);
00790 while (v.next()) {}
00791 currentNode->setMarked(true);
00792 }
00793 #endif
00794 }
00795
00796 void
00797 TreeCanvas::exportWholeTreePDF(void) {
00798 #if QT_VERSION >= 0x040400
00799 exportNodePDF(root);
00800 #endif
00801 }
00802
00803 void
00804 TreeCanvas::exportPDF(void) {
00805 #if QT_VERSION >= 0x040400
00806 exportNodePDF(currentNode);
00807 #endif
00808 }
00809
00810 void
00811 TreeCanvas::print(void) {
00812 QPrinter printer;
00813 if (QPrintDialog(&printer, this).exec() == QDialog::Accepted) {
00814 QMutexLocker locker(&mutex);
00815
00816 BoundingBox bb = root->getBoundingBox();
00817 QRect pageRect = printer.pageRect();
00818 double newXScale =
00819 static_cast<double>(pageRect.width()) / (bb.right - bb.left +
00820 Layout::extent);
00821 double newYScale =
00822 static_cast<double>(pageRect.height()) /
00823 (root->getShape()->depth() * Layout::dist_y +
00824 2*Layout::extent);
00825 double printScale = std::min(newXScale, newYScale)*100;
00826 if (printScale<1.0)
00827 printScale = 1.0;
00828 if (printScale > 400.0)
00829 printScale = 400.0;
00830 printScale = printScale / 100.0;
00831
00832 QPainter painter(&printer);
00833 painter.setRenderHint(QPainter::Antialiasing);
00834 painter.scale(printScale,printScale);
00835 painter.translate(xtrans, 0);
00836 QRect clip(0,0,0,0);
00837 DrawingCursor dc(root, curBest, painter, clip, showCopies);
00838 PreorderNodeVisitor<DrawingCursor> v(dc);
00839 while (v.next()) {}
00840 }
00841 }
00842
00843 VisualNode*
00844 TreeCanvas::eventNode(QEvent* event) {
00845 int x = 0;
00846 int y = 0;
00847 switch (event->type()) {
00848 case QEvent::ToolTip:
00849 {
00850 QHelpEvent* he = static_cast<QHelpEvent*>(event);
00851 x = he->x();
00852 y = he->y();
00853 break;
00854 }
00855 case QEvent::MouseButtonDblClick:
00856 case QEvent::MouseButtonPress:
00857 case QEvent::MouseButtonRelease:
00858 case QEvent::MouseMove:
00859 {
00860 QMouseEvent* me = static_cast<QMouseEvent*>(event);
00861 x = me->x();
00862 y = me->y();
00863 break;
00864 }
00865 case QEvent::ContextMenu:
00866 {
00867 QContextMenuEvent* ce = static_cast<QContextMenuEvent*>(event);
00868 x = ce->x();
00869 y = ce->y();
00870 break;
00871 }
00872 default:
00873 return NULL;
00874 }
00875 VisualNode* n;
00876 n = root->findNode(static_cast<int>(x/scale-xtrans),
00877 static_cast<int>((y-30)/scale));
00878 return n;
00879 }
00880
00881 bool
00882 TreeCanvas::event(QEvent* event) {
00883 if (mutex.tryLock()) {
00884 if (event->type() == QEvent::ToolTip) {
00885 VisualNode* n = eventNode(event);
00886 if (n != NULL && !n->isHidden() &&
00887 (n->getStatus() == BRANCH)) {
00888 QHelpEvent* he = static_cast<QHelpEvent*>(event);
00889 QToolTip::showText(he->globalPos(),
00890 QString(n->toolTip(curBest,c_d,a_d).c_str()));
00891 } else {
00892 QToolTip::hideText();
00893 }
00894 }
00895 mutex.unlock();
00896 }
00897 return QWidget::event(event);
00898 }
00899
00900 void
00901 TreeCanvas::resizeToOuter(void) {
00902 if (autoZoom)
00903 zoomToFit();
00904 }
00905
00906 void
00907 TreeCanvas::paintEvent(QPaintEvent* event) {
00908 QMutexLocker locker(&layoutMutex);
00909 QPainter painter(this);
00910 painter.setRenderHint(QPainter::Antialiasing);
00911
00912 BoundingBox bb = root->getBoundingBox();
00913 QRect origClip = event->rect();
00914 painter.translate(0, 30);
00915 painter.scale(scale,scale);
00916 painter.translate(xtrans, 0);
00917 QRect clip(static_cast<int>(origClip.x()/scale-xtrans),
00918 static_cast<int>(origClip.y()/scale),
00919 static_cast<int>(origClip.width()/scale),
00920 static_cast<int>(origClip.height()/scale));
00921 DrawingCursor dc(root, curBest, painter, clip, showCopies);
00922 PreorderNodeVisitor<DrawingCursor> v(dc);
00923
00924 while (v.next()) {}
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935 }
00936
00937 void
00938 TreeCanvas::mouseDoubleClickEvent(QMouseEvent* event) {
00939 if (mutex.tryLock()) {
00940 if(event->button() == Qt::LeftButton) {
00941 VisualNode* n = eventNode(event);
00942 if(n == currentNode) {
00943 inspectCurrentNode();
00944 event->accept();
00945 mutex.unlock();
00946 return;
00947 }
00948 }
00949 mutex.unlock();
00950 }
00951 event->ignore();
00952 }
00953
00954 void
00955 TreeCanvas::contextMenuEvent(QContextMenuEvent* event) {
00956 if (mutex.tryLock()) {
00957 VisualNode* n = eventNode(event);
00958 if (n != NULL) {
00959 setCurrentNode(n);
00960 emit contextMenu(event);
00961 event->accept();
00962 mutex.unlock();
00963 return;
00964 }
00965 mutex.unlock();
00966 }
00967 event->ignore();
00968 }
00969
00970 bool
00971 TreeCanvas::finish(void) {
00972 if (finishedFlag)
00973 return true;
00974 stopSearchFlag = true;
00975 finishedFlag = true;
00976 for (int i=0; i<doubleClickInspectors.size(); i++)
00977 doubleClickInspectors[i].first->finalize();
00978 for (int i=0; i<solutionInspectors.size(); i++)
00979 solutionInspectors[i].first->finalize();
00980 return !searcher.isRunning();
00981 }
00982
00983 void
00984 TreeCanvas::setCurrentNode(VisualNode* n) {
00985 QMutexLocker locker(&mutex);
00986 if (n != NULL) {
00987 currentNode->setMarked(false);
00988 currentNode = n;
00989 currentNode->setMarked(true);
00990 emit statusChanged(currentNode,stats,true);
00991 QWidget::update();
00992 }
00993 }
00994
00995 void
00996 TreeCanvas::mousePressEvent(QMouseEvent* event) {
00997 if (mutex.tryLock()) {
00998 if (event->button() == Qt::LeftButton) {
00999 VisualNode* n = eventNode(event);
01000 setCurrentNode(n);
01001 if (n != NULL) {
01002 event->accept();
01003 mutex.unlock();
01004 return;
01005 }
01006 }
01007 mutex.unlock();
01008 }
01009 event->ignore();
01010 }
01011
01012 void
01013 TreeCanvas::setRecompDistances(int c_d0, int a_d0) {
01014 c_d = c_d0; a_d = a_d0;
01015 }
01016
01017 void
01018 TreeCanvas::setAutoHideFailed(bool b) {
01019 autoHideFailed = b;
01020 }
01021
01022 void
01023 TreeCanvas::setAutoZoom(bool b) {
01024 autoZoom = b;
01025 if (autoZoom) {
01026 zoomToFit();
01027 }
01028 emit autoZoomChanged(b);
01029 scaleBar->setEnabled(!b);
01030 }
01031
01032 void
01033 TreeCanvas::setShowCopies(bool b) {
01034 showCopies = b;
01035 }
01036 bool
01037 TreeCanvas::getShowCopies(void) {
01038 return showCopies;
01039 }
01040
01041 bool
01042 TreeCanvas::getAutoHideFailed(void) {
01043 return autoHideFailed;
01044 }
01045
01046 bool
01047 TreeCanvas::getAutoZoom(void) {
01048 return autoZoom;
01049 }
01050
01051 void
01052 TreeCanvas::setRefresh(int i) {
01053 refresh = i;
01054 }
01055
01056 bool
01057 TreeCanvas::getSmoothScrollAndZoom(void) {
01058 return smoothScrollAndZoom;
01059 }
01060
01061 void
01062 TreeCanvas::setSmoothScrollAndZoom(bool b) {
01063 smoothScrollAndZoom = b;
01064 }
01065
01066 }}
01067
01068