Generated on for Gecode by doxygen 1.15.0
treecanvas.cpp
Go to the documentation of this file.
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Main authors:
4 * Guido Tack <tack@gecode.dev>
5 *
6 * Copyright:
7 * Guido Tack, 2006
8 *
9 * This file is part of Gecode, the generic constraint
10 * development environment:
11 * http://www.gecode.dev
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining
14 * a copy of this software and associated documentation files (the
15 * "Software"), to deal in the Software without restriction, including
16 * without limitation the rights to use, copy, modify, merge, publish,
17 * distribute, sublicense, and/or sell copies of the Software, and to
18 * permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be
22 * included in all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 *
32 */
33
34#include <QtGui/QPainter>
35#include <QPrinter>
36#include <QPrintDialog>
37
38#include <stack>
39#include <fstream>
40
42
46
47#include <gecode/search.hh>
49
50namespace Gecode { namespace Gist {
51
53 QWidget* parent, const Options& opt)
54 : QWidget(parent)
55#if QT_VERSION < 0x060000
56 , mutex(QMutex::Recursive)
57 , layoutMutex(QMutex::Recursive)
58#endif
59 , finishedFlag(false)
60 , compareNodes(false), compareNodesBeforeFP(false)
61 , autoHideFailed(true), autoZoom(false)
63 , moveDuringSearch(false)
64 , zoomTimeLine(500)
65 , scrollTimeLine(1000), targetX(0), sourceX(0), targetY(0), sourceY(0)
66 , targetW(0), targetH(0), targetScale(0)
68 QMutexLocker locker(&mutex);
69 curBest = (bab ? new BestNode(nullptr) : nullptr);
70 if (rootSpace->status() == SS_FAILED) {
71 if (!opt.clone)
72 delete rootSpace;
73 rootSpace = nullptr;
74 } else {
75 rootSpace = Gecode::Search::snapshot(rootSpace,opt);
76 }
78 int rootIdx = na->allocate(rootSpace);
79 assert(rootIdx == 0); (void) rootIdx;
80 root = (*na)[0];
81 root->layout(*na);
82 root->setMarked(true);
84 pathHead = root;
86
87 setAutoFillBackground(true);
88
89 connect(&searcher, SIGNAL(update(int,int,int)), this,
90 SLOT(layoutDone(int,int,int)));
91 connect(&searcher, SIGNAL(statusChanged(bool)), this,
92 SLOT(statusChanged(bool)));
93
94 connect(&searcher, SIGNAL(solution(const Space*)),
95 this, SIGNAL(solution(const Space*)),
96 Qt::BlockingQueuedConnection);
97 connect(this, SIGNAL(solution(const Space*)),
98 this, SLOT(inspectSolution(const Space*)));
99
100 connect(&searcher, SIGNAL(moveToNode(VisualNode*,bool)),
101 this, SLOT(setCurrentNode(VisualNode*,bool)),
102 Qt::BlockingQueuedConnection);
103
104 connect(&searcher, SIGNAL(searchFinished(void)), this, SIGNAL(searchFinished(void)));
105
106 connect(&scrollTimeLine, SIGNAL(frameChanged(int)),
107 this, SLOT(scroll(int)));
108#if QT_VERSION >= 0x060000
109 scrollTimeLine.setEasingCurve(QEasingCurve::InOutSine);
110#else
111 scrollTimeLine.setCurveShape(QTimeLine::EaseInOutCurve);
112#endif
113
114 scaleBar = new QSlider(Qt::Vertical, this);
115 scaleBar->setObjectName("scaleBar");
116 scaleBar->setMinimum(LayoutConfig::minScale);
117 scaleBar->setMaximum(LayoutConfig::maxScale);
119 connect(scaleBar, SIGNAL(valueChanged(int)),
120 this, SLOT(scaleTree(int)));
121 connect(this, SIGNAL(scaleChanged(int)), scaleBar, SLOT(setValue(int)));
122 connect(&searcher, SIGNAL(scaleChanged(int)),
123 scaleBar, SLOT(setValue(int)));
124
125 connect(&zoomTimeLine, SIGNAL(frameChanged(int)),
126 scaleBar, SLOT(setValue(int)));
127#if QT_VERSION >= 0x060000
128 zoomTimeLine.setEasingCurve(QEasingCurve::InOutSine);
129#else
130 zoomTimeLine.setCurveShape(QTimeLine::EaseInOutCurve);
131#endif
132
133 qRegisterMetaType<Statistics>("Statistics");
134 update();
135 }
136
138 if (root) {
139 DisposeCursor dc(root,*na);
141 }
142 delete na;
143 }
144
145 void
147 doubleClickInspectors.append(QPair<Inspector*,bool>(i,false));
148 }
149
150 void
152 assert(i < doubleClickInspectors.size());
153 doubleClickInspectors[i].second = active;
154 }
155
156 void
158 solutionInspectors.append(QPair<Inspector*,bool>(i,false));
159 }
160
161 void
163 assert(i < solutionInspectors.size());
164 solutionInspectors[i].second = active;
165 }
166
167 void
169 moveInspectors.append(QPair<Inspector*,bool>(i,false));
170 }
171
172 void
174 assert(i < moveInspectors.size());
175 moveInspectors[i].second = active;
176 }
177
178 void
180 comparators.append(QPair<Comparator*,bool>(c,false));
181 }
182
183 void
184 TreeCanvas::activateComparator(int i, bool active) {
185 assert(i < comparators.size());
186 comparators[i].second = active;
187 }
188
189 void
190 TreeCanvas::scaleTree(int scale0, int zoomx, int zoomy) {
191 QMutexLocker locker(&layoutMutex);
192
193 QSize viewport_size = size();
194 QAbstractScrollArea* sa =
195 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
196
197 if (zoomx==-1)
198 zoomx = viewport_size.width()/2;
199 if (zoomy==-1)
200 zoomy = viewport_size.height()/2;
201
202 int xoff = (sa->horizontalScrollBar()->value()+zoomx)/scale;
203 int yoff = (sa->verticalScrollBar()->value()+zoomy)/scale;
204
205 BoundingBox bb;
206 scale0 = std::min(std::max(scale0, LayoutConfig::minScale),
208 scale = (static_cast<double>(scale0)) / 100.0;
209 bb = root->getBoundingBox();
210 int w =
211 static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
212 int h =
213 static_cast<int>(2*Layout::extent+
214 root->getShape()->depth()*Layout::dist_y*scale);
215
216 sa->horizontalScrollBar()->setRange(0,w-viewport_size.width());
217 sa->verticalScrollBar()->setRange(0,h-viewport_size.height());
218 sa->horizontalScrollBar()->setPageStep(viewport_size.width());
219 sa->verticalScrollBar()->setPageStep(viewport_size.height());
220 sa->horizontalScrollBar()->setSingleStep(Layout::extent);
221 sa->verticalScrollBar()->setSingleStep(Layout::extent);
222
223 xoff *= scale;
224 yoff *= scale;
225
226 sa->horizontalScrollBar()->setValue(xoff-zoomx);
227 sa->verticalScrollBar()->setValue(yoff-zoomy);
228
229 emit scaleChanged(scale0);
230 QWidget::update();
231 }
232
233 void
235 QMutexLocker locker(&mutex);
236 layoutMutex.lock();
237 if (root != nullptr) {
238 root->layout(*na);
239 BoundingBox bb = root->getBoundingBox();
240
241 int w = static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
242 int h =
243 static_cast<int>(2*Layout::extent+
244 root->getShape()->depth()*Layout::dist_y*scale);
245 xtrans = -bb.left+(Layout::extent / 2);
246
247 QSize viewport_size = size();
248 QAbstractScrollArea* sa =
249 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
250 sa->horizontalScrollBar()->setRange(0,w-viewport_size.width());
251 sa->verticalScrollBar()->setRange(0,h-viewport_size.height());
252 sa->horizontalScrollBar()->setPageStep(viewport_size.width());
253 sa->verticalScrollBar()->setPageStep(viewport_size.height());
254 sa->horizontalScrollBar()->setSingleStep(Layout::extent);
255 sa->verticalScrollBar()->setSingleStep(Layout::extent);
256 }
257 if (autoZoom)
258 zoomToFit();
259 layoutMutex.unlock();
260 QWidget::update();
261 }
262
263 void
265 QWidget::update();
266 }
267
268 void
269 TreeCanvas::layoutDone(int w, int h, int scale0) {
270 targetW = w; targetH = h; targetScale = scale0;
271
272 QSize viewport_size = size();
273 QAbstractScrollArea* sa =
274 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
275 sa->horizontalScrollBar()->setRange(0,w-viewport_size.width());
276 sa->verticalScrollBar()->setRange(0,h-viewport_size.height());
277
278 if (layoutDoneTimerId == 0)
279 layoutDoneTimerId = startTimer(15);
280 }
281
282 void
283 TreeCanvas::statusChanged(bool finished) {
284 if (finished) {
285 update();
287 }
288 emit statusChanged(currentNode, stats, finished);
289 }
290
291 void
293 node = n;
294
295 depth = -1;
296 for (VisualNode* p = n; p != nullptr; p = p->getParent(*ti->na))
297 depth++;
298
299 a = all;
300 t = ti;
301 start();
302 }
303
304 void
305 SearcherThread::updateCanvas(void) {
306 t->layoutMutex.lock();
307 if (t->root == nullptr)
308 return;
309
310 if (t->autoHideFailed) {
311 t->root->hideFailed(*t->na,true);
312 }
313 for (VisualNode* n = t->currentNode; n != nullptr; n=n->getParent(*t->na)) {
314 if (n->isHidden()) {
315 t->currentNode->setMarked(false);
316 t->currentNode = n;
317 t->currentNode->setMarked(true);
318 break;
319 }
320 }
321
322 t->root->layout(*t->na);
323 BoundingBox bb = t->root->getBoundingBox();
324
325 int w = static_cast<int>((bb.right-bb.left+Layout::extent)*t->scale);
326 int h = static_cast<int>(2*Layout::extent+
327 t->root->getShape()->depth()
328 *Layout::dist_y*t->scale);
329 t->xtrans = -bb.left+(Layout::extent / 2);
330
331 int scale0 = static_cast<int>(t->scale*100);
332 if (t->autoZoom) {
333 QWidget* p = t->parentWidget();
334 if (p) {
335 double newXScale =
336 static_cast<double>(p->width()) / (bb.right - bb.left +
338 double newYScale =
339 static_cast<double>(p->height()) /
340 (t->root->getShape()->depth() * Layout::dist_y + 2*Layout::extent);
341
342 scale0 = static_cast<int>(std::min(newXScale, newYScale)*100);
343 if (scale0<LayoutConfig::minScale)
344 scale0 = LayoutConfig::minScale;
347 double scale = (static_cast<double>(scale0)) / 100.0;
348
349 w = static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
350 h = static_cast<int>(2*Layout::extent+
351 t->root->getShape()->depth()*Layout::dist_y*scale);
352 }
353 }
354
355 t->layoutMutex.unlock();
356 emit update(w,h,scale0);
357 }
358
361 public:
365 int i;
369 SearchItem(VisualNode* n0, int noOfChildren0)
370 : n(n0), i(-1), noOfChildren(noOfChildren0) {}
371 };
372
373 void
375 {
376 if (!node->isOpen())
377 return;
378 t->mutex.lock();
379 emit statusChanged(false);
380
381 unsigned int kids =
382 node->getNumberOfChildNodes(*t->na, t->curBest, t->stats,
383 t->c_d, t->a_d);
384 if (kids == 0 || node->getStatus() == STOP) {
385 t->mutex.unlock();
386 updateCanvas();
387 emit statusChanged(true);
388 return;
389 }
390
391 std::stack<SearchItem> stck;
392 stck.push(SearchItem(node,kids));
393 t->stats.maxDepth =
394 std::max(static_cast<long unsigned int>(t->stats.maxDepth),
395 static_cast<long unsigned int>(depth+stck.size()));
396
397 VisualNode* sol = nullptr;
398 int nodeCount = 0;
399 t->stopSearchFlag = false;
400 while (!stck.empty() && !t->stopSearchFlag) {
401 if (t->refresh > 0 && nodeCount >= t->refresh) {
402 node->dirtyUp(*t->na);
403 updateCanvas();
404 emit statusChanged(false);
405 nodeCount = 0;
406 if (t->refreshPause > 0)
407 msleep(t->refreshPause);
408 }
409 SearchItem& si = stck.top();
410 si.i++;
411 if (si.i == si.noOfChildren) {
412 stck.pop();
413 } else {
414 VisualNode* n = si.n->getChild(*t->na,si.i);
415 if (n->isOpen()) {
416 if (n->getStatus() == UNDETERMINED)
417 nodeCount++;
418 kids = n->getNumberOfChildNodes(*t->na, t->curBest, t->stats,
419 t->c_d, t->a_d);
420 if (t->moveDuringSearch)
421 emit moveToNode(n,false);
422 if (kids == 0) {
423 if (n->getStatus() == SOLVED) {
424 assert(n->hasCopy());
425 emit solution(n->getWorkingSpace());
426 n->purge(*t->na);
427 sol = n;
428 if (!a)
429 break;
430 }
431 } else {
432 if ( n->getStatus() != STOP )
433 stck.push(SearchItem(n,kids));
434 else if (!a)
435 break;
436 t->stats.maxDepth =
437 std::max(static_cast<long unsigned int>(t->stats.maxDepth),
438 static_cast<long unsigned int>(depth+stck.size()));
439 }
440 }
441 }
442 }
443 node->dirtyUp(*t->na);
444 t->stopSearchFlag = false;
445 t->mutex.unlock();
446 if (sol != nullptr) {
447 t->setCurrentNode(sol,true,false);
448 } else {
449 t->setCurrentNode(node,true,false);
450 }
451 }
452 updateCanvas();
453 emit statusChanged(true);
454 if (t->finishedFlag)
455 emit searchFinished();
456 }
457
458 void
460 QMutexLocker locker(&mutex);
461 searcher.search(currentNode, true, this);
462 }
463
464 void
466 QMutexLocker locker(&mutex);
467 searcher.search(currentNode, false, this);
468 }
469
470 void
472 QMutexLocker locker(&mutex);
473 currentNode->toggleHidden(*na);
474 update();
476 emit statusChanged(currentNode, stats, true);
477 }
478
479 void
481 QMutexLocker locker(&mutex);
482 currentNode->hideFailed(*na);
483 update();
485 emit statusChanged(currentNode, stats, true);
486 }
487
488 void
490 QMutexLocker locker(&mutex);
491 QMutexLocker layoutLocker(&layoutMutex);
492 currentNode->unhideAll(*na);
493 update();
495 emit statusChanged(currentNode, stats, true);
496 }
497
498 void
500 QMutexLocker locker(&mutex);
501 currentNode->toggleStop(*na);
502 update();
504 emit statusChanged(currentNode, stats, true);
505 }
506
507 void
509 QMutexLocker locker(&mutex);
510 QMutexLocker layoutLocker(&layoutMutex);
511 currentNode->unstopAll(*na);
512 update();
514 emit statusChanged(currentNode, stats, true);
515 }
516
517 void
518 TreeCanvas::timerEvent(QTimerEvent* e) {
519 if (e->timerId() == layoutDoneTimerId) {
520 if (!smoothScrollAndZoom) {
522 } else {
523 zoomTimeLine.stop();
524 int zoomCurrent = static_cast<int>(scale*100);
525 int targetZoom = targetScale;
526 targetZoom = std::min(std::max(targetZoom, LayoutConfig::minScale),
528 zoomTimeLine.setFrameRange(zoomCurrent,targetZoom);
529 zoomTimeLine.start();
530 }
531 QWidget::update();
532 killTimer(layoutDoneTimerId);
534 }
535 }
536
537 void
539 QMutexLocker locker(&layoutMutex);
540 if (root != nullptr) {
541 BoundingBox bb;
542 bb = root->getBoundingBox();
543 QWidget* p = parentWidget();
544 if (p) {
545 double newXScale =
546 static_cast<double>(p->width()) / (bb.right - bb.left +
548 double newYScale =
549 static_cast<double>(p->height()) / (root->getShape()->depth() *
552 int scale0 = static_cast<int>(std::min(newXScale, newYScale)*100);
553 if (scale0<LayoutConfig::minScale)
554 scale0 = LayoutConfig::minScale;
557
558 if (!smoothScrollAndZoom) {
559 scaleTree(scale0);
560 } else {
561 zoomTimeLine.stop();
562 int zoomCurrent = static_cast<int>(scale*100);
563 int targetZoom = scale0;
564 targetZoom = std::min(std::max(targetZoom, LayoutConfig::minScale),
566 zoomTimeLine.setFrameRange(zoomCurrent,targetZoom);
567 zoomTimeLine.start();
568 }
569 }
570 }
571 }
572
573 void
575 QMutexLocker locker(&mutex);
576 int x=0;
577 int y=0;
578
580 while (c != nullptr) {
581 x += c->getOffset();
582 y += Layout::dist_y;
583 c = c->getParent(*na);
584 }
585
586 x = static_cast<int>((xtrans+x)*scale); y = static_cast<int>(y*scale);
587
588 QAbstractScrollArea* sa =
589 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
590
591 x -= sa->viewport()->width() / 2;
592 y -= sa->viewport()->height() / 2;
593
594 sourceX = sa->horizontalScrollBar()->value();
595 targetX = std::max(sa->horizontalScrollBar()->minimum(), x);
596 targetX = std::min(sa->horizontalScrollBar()->maximum(),
597 targetX);
598 sourceY = sa->verticalScrollBar()->value();
599 targetY = std::max(sa->verticalScrollBar()->minimum(), y);
600 targetY = std::min(sa->verticalScrollBar()->maximum(),
601 targetY);
602 if (!smoothScrollAndZoom) {
603 sa->horizontalScrollBar()->setValue(targetX);
604 sa->verticalScrollBar()->setValue(targetY);
605 } else {
606 scrollTimeLine.stop();
607 scrollTimeLine.setFrameRange(0,100);
608 scrollTimeLine.setDuration(std::max(200,
609 std::min(1000,
610 std::min(std::abs(sourceX-targetX),
611 std::abs(sourceY-targetY)))));
612 scrollTimeLine.start();
613 }
614 }
615
616 void
617 TreeCanvas::scroll(int i) {
618 QAbstractScrollArea* sa =
619 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
620 double p = static_cast<double>(i)/100.0;
621 double xdiff = static_cast<double>(targetX-sourceX)*p;
622 double ydiff = static_cast<double>(targetY-sourceY)*p;
623 sa->horizontalScrollBar()->setValue(sourceX+static_cast<int>(xdiff));
624 sa->verticalScrollBar()->setValue(sourceY+static_cast<int>(ydiff));
625 }
626
627 void
628 TreeCanvas::inspectCurrentNode(bool fix, int inspectorNo) {
629 QMutexLocker locker(&mutex);
630
631 if (currentNode->isHidden()) {
632 toggleHidden();
633 return;
634 }
635
636 int failedInspectorType = -1;
637 int failedInspector = -1;
638 bool needCentering = false;
639 try {
640 switch (currentNode->getStatus()) {
641 case UNDETERMINED:
642 {
643 unsigned int kids =
644 currentNode->getNumberOfChildNodes(*na,curBest,stats,c_d,a_d);
645 int depth = -1;
646 for (VisualNode* p = currentNode; p != nullptr; p=p->getParent(*na))
647 depth++;
648 if (kids > 0) {
649 needCentering = true;
650 depth++;
651 }
652 stats.maxDepth =
653 std::max(stats.maxDepth, depth);
654 if (currentNode->getStatus() == SOLVED) {
655 assert(currentNode->hasCopy());
656 emit solution(currentNode->getWorkingSpace());
657 }
659 for (int i=0; i<moveInspectors.size(); i++) {
660 if (moveInspectors[i].second) {
661 failedInspectorType = 0;
662 failedInspector = i;
663 if (currentNode->getStatus() == FAILED) {
664 if (!currentNode->isRoot()) {
665 Space* curSpace =
666 currentNode->getSpace(*na,curBest,c_d,a_d);
667 moveInspectors[i].first->inspect(*curSpace);
668 delete curSpace;
669 }
670 } else {
671 moveInspectors[i].first->
672 inspect(*currentNode->getWorkingSpace());
673 }
674 failedInspectorType = -1;
675 }
676 }
677 if (currentNode->getStatus() == SOLVED) {
678 currentNode->purge(*na);
679 }
680 }
681 break;
682 case FAILED:
683 case STOP:
684 case UNSTOP:
685 case BRANCH:
686 case SOLVED:
687 {
688 Space* curSpace;
689
690 if (fix) {
691 if (currentNode->isRoot() && currentNode->getStatus() == FAILED)
692 break;
693 curSpace = currentNode->getSpace(*na,curBest,c_d,a_d);
694 if (currentNode->getStatus() == SOLVED &&
695 curSpace->status() != SS_SOLVED) {
696 // in the presence of weakly monotonic propagators, we may have
697 // to use search to find the solution here
698 assert(curSpace->status() == SS_BRANCH &&
699 "Something went wrong - probably an incorrect brancher");
700 Space* dfsSpace = Gecode::dfs(curSpace);
701 delete curSpace;
702 curSpace = dfsSpace;
703 }
704 } else {
705 if (currentNode->isRoot())
706 break;
707 VisualNode* p = currentNode->getParent(*na);
708 curSpace = p->getSpace(*na,curBest,c_d,a_d);
709 switch (curSpace->status()) {
710 case SS_SOLVED:
711 case SS_FAILED:
712 break;
713 case SS_BRANCH:
714 curSpace->commit(*p->getChoice(),
715 currentNode->getAlternative(*na));
716 break;
717 default:
719 }
720 }
721
722 if (inspectorNo==-1) {
723 for (int i=0; i<doubleClickInspectors.size(); i++) {
724 if (doubleClickInspectors[i].second) {
725 failedInspectorType = 1;
726 failedInspector = i;
727 doubleClickInspectors[i].first->inspect(*curSpace);
728 failedInspectorType = -1;
729 }
730 }
731 } else {
732 failedInspectorType = 1;
733 failedInspector = inspectorNo;
734 doubleClickInspectors[inspectorNo].first->inspect(*curSpace);
735 failedInspectorType = -1;
736 }
737 delete curSpace;
738 }
739 break;
740 }
741 } catch (Exception& e) {
742 switch (failedInspectorType) {
743 case 0:
744 qFatal("Exception in move inspector %d: %s.\n Stopping.",
745 failedInspector, e.what());
746 break;
747 case 1:
748 qFatal("Exception in double click inspector %d: %s.\n Stopping.",
749 failedInspector, e.what());
750 break;
751 default:
752 qFatal("Exception: %s.\n Stopping.", e.what());
753 break;
754 }
755 }
756
757 currentNode->dirtyUp(*na);
758 update();
759 if (needCentering)
761 }
762
763 void
767
768 void
770 QMutexLocker locker(&mutex);
771 currentNode->labelBranches(*na,curBest,c_d,a_d);
772 update();
774 emit statusChanged(currentNode, stats, true);
775 }
776 void
778 QMutexLocker locker(&mutex);
779 currentNode->labelPath(*na,curBest,c_d,a_d);
780 update();
782 emit statusChanged(currentNode, stats, true);
783 }
784
785 void
786 TreeCanvas::inspectSolution(const Space* s) {
787 int failedInspectorType = -1;
788 int failedInspector = -1;
789 try {
790 Space* c = nullptr;
791 for (int i=0; i<solutionInspectors.size(); i++) {
792 if (solutionInspectors[i].second) {
793 if (c == nullptr)
794 c = s->clone();
795 failedInspectorType = 1;
796 failedInspector = i;
797 solutionInspectors[i].first->inspect(*c);
798 failedInspectorType = -1;
799 }
800 }
801 delete c;
802 } catch (Exception& e) {
803 switch (failedInspectorType) {
804 case 0:
805 qFatal("Exception in move inspector %d: %s.\n Stopping.",
806 failedInspector, e.what());
807 break;
808 case 1:
809 qFatal("Exception in solution inspector %d: %s.\n Stopping.",
810 failedInspector, e.what());
811 break;
812 default:
813 qFatal("Exception: %s.\n Stopping.", e.what());
814 break;
815 }
816 }
817 }
818
819 void
821 stopSearchFlag = true;
822 layoutDoneTimerId = startTimer(15);
823 }
824
825 void
827 QMutexLocker locker(&mutex);
828 Space* rootSpace =
829 root->getStatus() == FAILED ? nullptr :
830 root->getSpace(*na,curBest,c_d,a_d);
831 if (curBest != nullptr) {
832 delete curBest;
833 curBest = new BestNode(nullptr);
834 }
835 if (root) {
836 DisposeCursor dc(root,*na);
838 }
839 delete na;
840 na = new Node::NodeAllocator(curBest != nullptr);
841 int rootIdx = na->allocate(rootSpace);
842 assert(rootIdx == 0); (void) rootIdx;
843 root = (*na)[0];
844 root->setMarked(true);
846 pathHead = root;
847 scale = 1.0;
848 stats = Statistics();
849 for (int i=bookmarks.size(); i--;)
850 emit removedBookmark(i);
851 bookmarks.clear();
852 root->layout(*na);
853
854 emit statusChanged(currentNode, stats, true);
855 update();
856 }
857
858 void
860 QMutexLocker locker(&mutex);
861 if (!currentNode->isBookmarked()) {
862 bool ok;
863 QString text =
864 QInputDialog::getText(this, "Add bookmark", "Name:",
865 QLineEdit::Normal,"",&ok);
866 if (ok) {
867 currentNode->setBookmarked(true);
868 bookmarks.append(currentNode);
869 if (text == "")
870 text = QString("Node ")+QString().setNum(bookmarks.size());
871 emit addedBookmark(text);
872 }
873 } else {
874 currentNode->setBookmarked(false);
875 int idx = bookmarks.indexOf(currentNode);
876 bookmarks.remove(idx);
877 emit removedBookmark(idx);
878 }
879 currentNode->dirtyUp(*na);
880 update();
881 }
882
883 void
885 QMutexLocker locker(&mutex);
886 if(currentNode == pathHead)
887 return;
888
889 pathHead->unPathUp(*na);
891
892 currentNode->pathUp(*na);
893 currentNode->dirtyUp(*na);
894 update();
895 }
896
897 void
899 QMutexLocker locker(&mutex);
901 if (currentNode->isOnPath()) {
903 int nextAlt = currentNode->getPathAlternative(*na);
904 while (nextAlt >= 0) {
905 setCurrentNode(currentNode->getChild(*na,nextAlt));
907 nextAlt = currentNode->getPathAlternative(*na);
908 }
909 }
910 update();
911 }
912
913 void
915 QMutexLocker locker(&mutex);
916 compareNodes = true;
917 compareNodesBeforeFP = false;
918 setCursor(QCursor(Qt::CrossCursor));
919 }
920
921 void
923 QMutexLocker locker(&mutex);
924 compareNodes = true;
926 setCursor(QCursor(Qt::CrossCursor));
927 }
928
929 void
933
934 void
936 QMutexLocker locker(&mutex);
937
938 VisualNode* p = currentNode->getParent(*na);
939
941
942 if (p != nullptr) {
944 }
945 }
946
947 void
949 QMutexLocker locker(&mutex);
950 if (!currentNode->isHidden()) {
951 switch (currentNode->getStatus()) {
952 case STOP:
953 case UNSTOP:
954 case BRANCH:
955 {
956 int alt = std::max(0, currentNode->getPathAlternative(*na));
957 VisualNode* n = currentNode->getChild(*na,alt);
960 break;
961 }
962 case SOLVED:
963 case FAILED:
964 case UNDETERMINED:
965 break;
966 }
967 }
968 }
969
970 void
972 QMutexLocker locker(&mutex);
973 VisualNode* p = currentNode->getParent(*na);
974 if (p != nullptr) {
975 int alt = currentNode->getAlternative(*na);
976 if (alt > 0) {
977 VisualNode* n = p->getChild(*na,alt-1);
980 }
981 }
982 }
983
984 void
986 QMutexLocker locker(&mutex);
987 VisualNode* p = currentNode->getParent(*na);
988 if (p != nullptr) {
989 unsigned int alt = currentNode->getAlternative(*na);
990 if (alt + 1 < p->getNumberOfChildren()) {
991 VisualNode* n = p->getChild(*na,alt+1);
994 }
995 }
996 }
997
998 void
1000 QMutexLocker locker(&mutex);
1003 }
1004
1005 void
1007 QMutexLocker locker(&mutex);
1008 NextSolCursor nsc(currentNode,back,*na);
1010 nsv.run();
1011 VisualNode* n = nsv.getCursor().node();
1012 if (n != root) {
1013 setCurrentNode(n);
1015 }
1016 }
1017
1018 void
1020 navNextSol(true);
1021 }
1022
1023 void
1024 TreeCanvas::exportNodePDF(VisualNode* n) {
1025#if QT_VERSION >= 0x040400
1026 QString filename = QFileDialog::getSaveFileName(this, tr("Export tree as pdf"), "", tr("PDF (*.pdf)"));
1027 if (filename != "") {
1028 QPrinter printer(QPrinter::ScreenResolution);
1029 QMutexLocker locker(&mutex);
1030
1031 BoundingBox bb = n->getBoundingBox();
1032 printer.setFullPage(true);
1033#if QT_VERSION >= 0x060000
1034 printer.setPageSize(QPageSize(QSizeF(bb.right-bb.left+Layout::extent,
1035 n->getShape()->depth() * Layout::dist_y +
1036 Layout::extent), QPageSize::Point));
1037#else
1038 printer.setPaperSize(QSizeF(bb.right-bb.left+Layout::extent,
1039 n->getShape()->depth() * Layout::dist_y +
1040 Layout::extent), QPrinter::Point);
1041#endif
1042 printer.setOutputFileName(filename);
1043 QPainter painter(&printer);
1044
1045 painter.setRenderHint(QPainter::Antialiasing);
1046#if QT_VERSION >= 0x060000
1047 QRect pageRect = printer.pageLayout().paintRectPixels(printer.resolution());
1048#else
1049 QRect pageRect = printer.pageRect();
1050#endif
1051 double newXScale =
1052 static_cast<double>(pageRect.width()) / (bb.right - bb.left +
1054 double newYScale =
1055 static_cast<double>(pageRect.height()) /
1056 (n->getShape()->depth() * Layout::dist_y +
1058 double printScale = std::min(newXScale, newYScale);
1059 painter.scale(printScale,printScale);
1060
1061 int printxtrans = -bb.left+(Layout::extent / 2);
1062
1063 painter.translate(printxtrans, Layout::dist_y / 2);
1064 QRect clip(0,0,0,0);
1065 DrawingCursor dc(n, *na, curBest, painter, clip, showCopies);
1066 currentNode->setMarked(false);
1068 currentNode->setMarked(true);
1069 }
1070#else
1071 (void) n;
1072#endif
1073 }
1074
1075 void
1077#if QT_VERSION >= 0x040400
1078 exportNodePDF(root);
1079#endif
1080 }
1081
1082 void
1084#if QT_VERSION >= 0x040400
1085 exportNodePDF(currentNode);
1086#endif
1087 }
1088
1089 void
1091 QPrinter printer;
1092 if (QPrintDialog(&printer, this).exec() == QDialog::Accepted) {
1093 QMutexLocker locker(&mutex);
1094
1095 BoundingBox bb = root->getBoundingBox();
1096#if QT_VERSION >= 0x060000
1097 QRect pageRect = printer.pageLayout().paintRectPixels(printer.resolution());
1098#else
1099 QRect pageRect = printer.pageRect();
1100#endif
1101 double newXScale =
1102 static_cast<double>(pageRect.width()) / (bb.right - bb.left +
1104 double newYScale =
1105 static_cast<double>(pageRect.height()) /
1106 (root->getShape()->depth() * Layout::dist_y +
1107 2*Layout::extent);
1108 double printScale = std::min(newXScale, newYScale)*100;
1109 if (printScale<1.0)
1110 printScale = 1.0;
1111 if (printScale > 400.0)
1112 printScale = 400.0;
1113 printScale = printScale / 100.0;
1114
1115 QPainter painter(&printer);
1116 painter.setRenderHint(QPainter::Antialiasing);
1117 painter.scale(printScale,printScale);
1118 painter.translate(xtrans, 0);
1119 QRect clip(0,0,0,0);
1120 DrawingCursor dc(root, *na, curBest, painter, clip, showCopies);
1122 }
1123 }
1124
1125 VisualNode*
1127 int x = 0;
1128 int y = 0;
1129 switch (event->type()) {
1130 case QEvent::ToolTip:
1131 {
1132 QHelpEvent* he = static_cast<QHelpEvent*>(event);
1133 x = he->x();
1134 y = he->y();
1135 break;
1136 }
1137 case QEvent::MouseButtonDblClick:
1138 case QEvent::MouseButtonPress:
1139 case QEvent::MouseButtonRelease:
1140 case QEvent::MouseMove:
1141 {
1142 QMouseEvent* me = static_cast<QMouseEvent*>(event);
1143#if QT_VERSION >= 0x060000
1144 x = me->position().x();
1145 y = me->position().y();
1146#else
1147 x = me->x();
1148 y = me->y();
1149#endif
1150 break;
1151 }
1152 case QEvent::ContextMenu:
1153 {
1154 QContextMenuEvent* ce = static_cast<QContextMenuEvent*>(event);
1155 x = ce->x();
1156 y = ce->y();
1157 break;
1158 }
1159 default:
1160 return nullptr;
1161 }
1162 QAbstractScrollArea* sa =
1163 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
1164 int xoff = sa->horizontalScrollBar()->value()/scale;
1165 int yoff = sa->verticalScrollBar()->value()/scale;
1166
1167 BoundingBox bb = root->getBoundingBox();
1168 int w =
1169 static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
1170 if (w < sa->viewport()->width())
1171 xoff -= (sa->viewport()->width()-w)/2;
1172
1173 VisualNode* n;
1174 n = root->findNode(*na,
1175 static_cast<int>(x/scale-xtrans+xoff),
1176 static_cast<int>((y-30)/scale+yoff));
1177 return n;
1178 }
1179
1180 bool
1182 if (mutex.tryLock()) {
1183 if (event->type() == QEvent::ToolTip) {
1185 if (n != nullptr) {
1186 QHelpEvent* he = static_cast<QHelpEvent*>(event);
1187 QToolTip::showText(he->globalPos(),
1188 QString(n->toolTip(*na,curBest,
1189 c_d,a_d).c_str()));
1190 } else {
1191 QToolTip::hideText();
1192 }
1193 }
1194 mutex.unlock();
1195 }
1196 return QWidget::event(event);
1197 }
1198
1199 void
1201 if (autoZoom)
1202 zoomToFit();
1203 }
1204
1205 void
1207 QMutexLocker locker(&layoutMutex);
1208 QPainter painter(this);
1209 painter.setRenderHint(QPainter::Antialiasing);
1210
1211 QAbstractScrollArea* sa =
1212 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
1213 int xoff = sa->horizontalScrollBar()->value()/scale;
1214 int yoff = sa->verticalScrollBar()->value()/scale;
1215
1216 BoundingBox bb = root->getBoundingBox();
1217 int w =
1218 static_cast<int>((bb.right-bb.left+Layout::extent)*scale);
1219 if (w < sa->viewport()->width())
1220 xoff -= (sa->viewport()->width()-w)/2;
1221
1222 QRect origClip = event->rect();
1223 painter.translate(0, 30);
1224 painter.scale(scale,scale);
1225 painter.translate(xtrans-xoff, -yoff);
1226 QRect clip(static_cast<int>(origClip.x()/scale-xtrans+xoff),
1227 static_cast<int>(origClip.y()/scale+yoff),
1228 static_cast<int>(origClip.width()/scale),
1229 static_cast<int>(origClip.height()/scale));
1230 DrawingCursor dc(root, *na, curBest, painter, clip, showCopies);
1232
1233 // int nodesLayouted = 1;
1234 // clock_t t0 = clock();
1235 // while (v.next()) { nodesLayouted++; }
1236 // double t = (static_cast<double>(clock()-t0) / CLOCKS_PER_SEC) * 1000.0;
1237 // double nps = static_cast<double>(nodesLayouted) /
1238 // (static_cast<double>(clock()-t0) / CLOCKS_PER_SEC);
1239 // std::cout << "Drawing done. " << nodesLayouted << " nodes in "
1240 // << t << " ms. " << nps << " nodes/s." << std::endl;
1241
1242 }
1243
1244 void
1246 if (mutex.tryLock()) {
1247 if(event->button() == Qt::LeftButton) {
1249 if(n == currentNode) {
1251 event->accept();
1252 mutex.unlock();
1253 return;
1254 }
1255 }
1256 mutex.unlock();
1257 }
1258 event->ignore();
1259 }
1260
1261 void
1263 if (mutex.tryLock()) {
1265 if (n != nullptr) {
1266 setCurrentNode(n);
1267 emit contextMenu(event);
1268 event->accept();
1269 mutex.unlock();
1270 return;
1271 }
1272 mutex.unlock();
1273 }
1274 event->ignore();
1275 }
1276
1277 void
1278 TreeCanvas::resizeEvent(QResizeEvent* e) {
1279 QAbstractScrollArea* sa =
1280 static_cast<QAbstractScrollArea*>(parentWidget()->parentWidget());
1281
1282 int w = sa->horizontalScrollBar()->maximum()+e->oldSize().width();
1283 int h = sa->verticalScrollBar()->maximum()+e->oldSize().height();
1284
1285 sa->horizontalScrollBar()->setRange(0,w-e->size().width());
1286 sa->verticalScrollBar()->setRange(0,h-e->size().height());
1287 sa->horizontalScrollBar()->setPageStep(e->size().width());
1288 sa->verticalScrollBar()->setPageStep(e->size().height());
1289 }
1290
1291 void
1293 if (event->modifiers() & Qt::ShiftModifier) {
1294 event->accept();
1295#if QT_VERSION >= 0x060000
1296 if (event->angleDelta().y() != 0 && !autoZoom)
1297 scaleTree(scale*100+ceil(static_cast<double>(event->angleDelta().y())/4.0),
1298 event->position().x(), event->position().y());
1299#else
1300 if (event->orientation() == Qt::Vertical && !autoZoom)
1301 scaleTree(scale*100+ceil(static_cast<double>(event->delta())/4.0),
1302 event->x(), event->y());
1303#endif
1304 } else {
1305 event->ignore();
1306 }
1307 }
1308
1309 bool
1311 if (finishedFlag)
1312 return true;
1313 stopSearchFlag = true;
1314 finishedFlag = true;
1315 for (int i=0; i<doubleClickInspectors.size(); i++)
1316 doubleClickInspectors[i].first->finalize();
1317 for (int i=0; i<solutionInspectors.size(); i++)
1318 solutionInspectors[i].first->finalize();
1319 for (int i=0; i<moveInspectors.size(); i++)
1320 moveInspectors[i].first->finalize();
1321 for (int i=0; i<comparators.size(); i++)
1322 comparators[i].first->finalize();
1323 return !searcher.isRunning();
1324 }
1325
1326 void
1328 if (finished)
1329 mutex.lock();
1330 if (update && n != nullptr && n != currentNode &&
1331 n->getStatus() != UNDETERMINED && !n->isHidden()) {
1332 Space* curSpace = nullptr;
1333 for (int i=0; i<moveInspectors.size(); i++) {
1334 if (moveInspectors[i].second) {
1335 if (curSpace == nullptr)
1336 curSpace = n->getSpace(*na,curBest,c_d,a_d);
1337 try {
1338 moveInspectors[i].first->inspect(*curSpace);
1339 } catch (Exception& e) {
1340 qFatal("Exception in move inspector %d: %s.\n Stopping.",
1341 i, e.what());
1342 }
1343 }
1344 }
1345 }
1346 if (n != nullptr) {
1347 currentNode->setMarked(false);
1348 currentNode = n;
1349 currentNode->setMarked(true);
1350 emit statusChanged(currentNode,stats,finished);
1351 if (update) {
1352 compareNodes = false;
1353 setCursor(QCursor(Qt::ArrowCursor));
1354 QWidget::update();
1355 }
1356 }
1357 if (finished)
1358 mutex.unlock();
1359 }
1360
1361 void
1363 if (mutex.tryLock()) {
1364 if (event->button() == Qt::LeftButton) {
1366 if (compareNodes) {
1367 if (n != nullptr && n->getStatus() != UNDETERMINED &&
1368 currentNode != nullptr &&
1369 currentNode->getStatus() != UNDETERMINED) {
1370 Space* curSpace = nullptr;
1371 Space* compareSpace = nullptr;
1372 for (int i=0; i<comparators.size(); i++) {
1373 if (comparators[i].second) {
1374 if (curSpace == nullptr) {
1375 curSpace = currentNode->getSpace(*na,curBest,c_d,a_d);
1376
1377 if (!compareNodesBeforeFP || n->isRoot()) {
1378 compareSpace = n->getSpace(*na,curBest,c_d,a_d);
1379 } else {
1380 VisualNode* p = n->getParent(*na);
1381 compareSpace = p->getSpace(*na,curBest,c_d,a_d);
1382 switch (compareSpace->status()) {
1383 case SS_SOLVED:
1384 case SS_FAILED:
1385 break;
1386 case SS_BRANCH:
1387 compareSpace->commit(*p->getChoice(),
1388 n->getAlternative(*na));
1389 break;
1390 default:
1392 }
1393 }
1394 }
1395 try {
1396 comparators[i].first->compare(*curSpace,*compareSpace);
1397 } catch (Exception& e) {
1398 qFatal("Exception in comparator %d: %s.\n Stopping.",
1399 i, e.what());
1400 }
1401 }
1402 }
1403 }
1404 } else {
1405 setCurrentNode(n);
1406 }
1407 compareNodes = false;
1408 setCursor(QCursor(Qt::ArrowCursor));
1409 if (n != nullptr) {
1410 event->accept();
1411 mutex.unlock();
1412 return;
1413 }
1414 }
1415 mutex.unlock();
1416 }
1417 event->ignore();
1418 }
1419
1420 void
1422 c_d = c_d0; a_d = a_d0;
1423 }
1424
1425 void
1429
1430 void
1432 autoZoom = b;
1433 if (autoZoom) {
1434 zoomToFit();
1435 }
1436 emit autoZoomChanged(b);
1437 scaleBar->setEnabled(!b);
1438 }
1439
1440 void
1442 showCopies = b;
1443 }
1444 bool
1446 return showCopies;
1447 }
1448
1449 bool
1453
1454 bool
1456 return autoZoom;
1457 }
1458
1459 void
1461 refresh = i;
1462 }
1463
1464 void
1466 refreshPause = i;
1467 if (refreshPause > 0)
1468 refresh = 1;
1469 }
1470
1471 bool
1475
1476 void
1480
1481 bool
1485
1486 void
1490
1491}}
1492
1493// STATISTICS: gist-any
int size(void) const
Return size of array (number of elements).
Definition array.hpp:1597
Exception: Base-class for exceptions
Definition exception.hpp:42
virtual const char * what(void) const noexcept
Return information.
Definition exception.cpp:55
Static reference to the currently best space.
Definition spacenode.hh:80
int right
Right coordinate.
Definition visualnode.hh:57
int left
Left coordinate.
Definition visualnode.hh:55
Abstract base class for comparators.
Definition gist.hh:119
A cursor that frees all memory.
A cursor that draws a tree on a QWidget.
Abstract base class for inspectors.
Definition gist.hh:99
static const int dist_y
Definition visualnode.hh:46
static const int extent
Definition visualnode.hh:47
A cursor that finds the next solution.
Cursor & getCursor(void)
Return the cursor.
NodeAllocatorBase< VisualNode > NodeAllocator
Definition node.hh:143
unsigned int getNumberOfChildren(void) const
Return the number of children.
Definition node.hpp:214
int getParent(void) const
Return the parent.
Definition node.hpp:182
int getChild(int n) const
Return index of child no n.
Definition node.hpp:195
bool isRoot(void) const
Check if this node is the root of a tree.
Definition node.hpp:211
Options for Gist
Definition gist.hh:234
Run a cursor over a tree, processing nodes in pre-order.
void run(void)
Execute visitor.
A stack item for depth first search.
VisualNode * n
The node.
int noOfChildren
The number of children.
SearchItem(VisualNode *n0, int noOfChildren0)
Constructor.
int i
The currently explored child.
void update(int w, int h, int scale0)
void solution(const Space *)
void search(VisualNode *n, bool all, TreeCanvas *ti)
void moveToNode(VisualNode *n, bool)
int depth(void) const
Return depth of the shape.
bool hasCopy(void)
Return whether the node has a copy.
const Choice * getChoice(void)
Return choice of this node.
const Space * getWorkingSpace(void) const
Return working space (if present).
int getNumberOfChildNodes(NodeAllocator &na, BestNode *curBest, Statistics &stats, int c_d, int a_d)
Compute and return the number of children.
int getAlternative(const NodeAllocator &na) const
Return alternative number of this node.
bool isOpen(void)
Return whether this node still has open children.
NodeStatus getStatus(void) const
Return current status of the node.
Definition spacenode.hpp:71
Space * getSpace(NodeAllocator &na, BestNode *curBest, int c_d, int a_d)
Return working space. Receiver must delete the space.
Definition spacenode.hpp:98
void purge(const NodeAllocator &na)
Clear working space and copy (if present and this is not the root).
Statistics about the search tree
Definition spacenode.hh:59
A canvas that displays the search tree.
Definition treecanvas.hh:93
double scale
Current scale factor.
void navNextSol(bool back=false)
Move selection to next solution (in DFS order).
void update(void)
Update display.
void zoomToFit(void)
Zoom the canvas so that the whole tree fits.
void resizeToOuter(void)
Resize to the outer widget size if auto zoom is enabled.
void activateComparator(int i, bool active)
Set active comparator.
void exportPDF(void)
Export pdf of the current subtree.
int targetX
Target x coordinate after smooth scrolling.
void wheelEvent(QWheelEvent *event)
Handle mouse wheel events.
Statistics stats
Statistics about the search tree.
void resizeEvent(QResizeEvent *event)
Handle resize event.
int targetScale
Target scale after layout.
QVector< VisualNode * > bookmarks
The bookmarks map.
SearcherThread searcher
Search engine thread.
VisualNode * currentNode
The currently selected node.
bool finish(void)
Stop search and wait for it to finish.
void exportWholeTreePDF(void)
Export pdf of the whole tree.
int xtrans
Offset on the x axis so that the tree is centered.
void activateDoubleClickInspector(int i, bool active)
Set active inspector.
void navUp(void)
Move selection to the parent of the selected node.
bool autoHideFailed
Whether to hide failed subtrees automatically.
void labelBranches(void)
Label all branches in subtree under current node.
VisualNode * eventNode(QEvent *event)
Return the node corresponding to the event position.
void contextMenuEvent(QContextMenuEvent *event)
Handle context menu event.
void startCompareNodesBeforeFP(void)
Wait for click on node to compare with current node before fixpoint.
void startCompareNodes(void)
Wait for click on node to compare with current node.
void addComparator(Comparator *c)
Add comparator c.
void inspectBeforeFP(void)
Calls inspectCurrentNode(false).
void hideFailed(void)
Hide failed subtrees of selected node.
bool getAutoZoom(void)
Return preference whether to automatically zoom to fit.
void setRefreshPause(int i)
Set refresh pause in msec.
void bookmarkNode(void)
Bookmark current node.
void print(void)
Print the tree.
void searchAll(void)
Explore complete subtree of selected node.
int refresh
Refresh rate.
QTimeLine scrollTimeLine
Timer for smooth scrolling.
int layoutDoneTimerId
Timer id for delaying the update.
void addSolutionInspector(Inspector *i)
Add inspector i.
int targetH
Target height after layout.
bool smoothScrollAndZoom
Whether to use smooth scrolling and zooming.
QTimeLine zoomTimeLine
Timer for smooth zooming.
void setPath(void)
Set the current node to be the head of the path.
void navRoot(void)
Move selection to the root node.
void statusChanged(VisualNode *, const Statistics &, bool)
Status bar update.
TreeCanvas(Space *rootSpace, bool bab, QWidget *parent, const Options &opt)
Constructor.
~TreeCanvas(void)
Destructor.
bool event(QEvent *event)
General event handler, used for displaying tool tips.
void setMoveDuringSearch(bool b)
Set preference whether to move cursor during search.
void searchOne(void)
Find next solution below selected node.
void scroll(void)
React to scroll events.
void navDown(void)
Move selection to the first child of the selected node.
QVector< QPair< Comparator *, bool > > comparators
The registered comparators, and whether they are active.
bool compareNodes
Whether node comparison action is running.
void scaleTree(int scale0, int zoomx=-1, int zoomy=-1)
Set scale factor to scale0.
void activateSolutionInspector(int i, bool active)
Set active inspector.
int c_d
The recomputation distance.
void mousePressEvent(QMouseEvent *event)
Handle mouse press event.
void navLeft(void)
Move selection to the left sibling of the selected node.
QSlider * scaleBar
The scale bar.
int targetY
Target y coordinate after smooth scrolling.
QVector< QPair< Inspector *, bool > > doubleClickInspectors
The registered click inspectors, and whether they are active.
void autoZoomChanged(bool)
The auto-zoom state was changed.
void setRefresh(int i)
Set refresh rate.
Node::NodeAllocator * na
Allocator for nodes.
BestNode * curBest
The currently best solution (for branch-and-bound).
void paintEvent(QPaintEvent *event)
Paint the tree.
GecodeQMutex mutex
Mutex for synchronizing access to the tree.
void unstopAll(void)
Do not stop at any stop node.
bool moveDuringSearch
Whether to move cursor during search.
bool getSmoothScrollAndZoom(void)
Return preference whether to use smooth scrolling and zooming.
void mouseDoubleClickEvent(QMouseEvent *event)
Handle mouse double click event.
int a_d
The adaptive recomputation distance.
void unhideAll(void)
Unhide all nodes below selected node.
void reset(void)
Reset.
void searchFinished(void)
Signals that Gist is finished.
int sourceX
Source x coordinate after smooth scrolling.
GecodeQMutex layoutMutex
Mutex for synchronizing layout and drawing.
void scaleChanged(int)
The scale factor has changed.
bool getAutoHideFailed(void)
Return preference whether to automatically hide failed subtrees.
void solution(const Space *)
Signals that a solution has been found.
int targetW
Target width after layout.
void setRecompDistances(int c_d, int a_d)
Set recomputation distances.
void addMoveInspector(Inspector *i)
Add inspector i.
bool autoZoom
Whether to zoom automatically.
void emitStatusChanged(void)
Re-emit status change information for current node.
void setAutoZoom(bool b)
Set preference whether to automatically zoom to fit.
void centerCurrentNode(void)
Center the view on the currently selected node.
void setSmoothScrollAndZoom(bool b)
Set preference whether to use smooth scrolling and zooming.
bool finishedFlag
Flag signalling that Gist is ready to be closed.
void removedBookmark(int idx)
Signals that a bookmark has been removed.
VisualNode * pathHead
The head of the currently selected path.
void activateMoveInspector(int i, bool active)
Set active inspector.
void setCurrentNode(VisualNode *n, bool finished=true, bool update=true)
Set the selected node to n.
void contextMenu(QContextMenuEvent *)
Context menu triggered.
bool stopSearchFlag
Flag signalling the search to stop.
void setShowCopies(bool b)
Set preference whether to show copies in the tree.
void labelPath(void)
Label all branches on path to root node.
void layoutDone(int w, int h, int scale0)
Layout done.
virtual void timerEvent(QTimerEvent *e)
Timer invoked for smooth zooming and scrolling.
bool getMoveDuringSearch(void)
Return preference whether to move cursor during search.
bool compareNodesBeforeFP
Whether node comparison action computes fixpoint.
void toggleStop(void)
Do not stop at selected stop node.
void toggleHidden(void)
Toggle hidden state of selected node.
void navRight(void)
Move selection to the right sibling of the selected node.
void navPrevSol(void)
Move selection to previous solution (in DFS order).
bool showCopies
Whether to show copies in the tree.
void inspectPath(void)
Call the double click inspector for all nodes on the path from root to head of the path.
bool getShowCopies(void)
Return preference whether to show copies in the tree.
VisualNode * root
The root node of the tree.
void stopSearch(void)
Stop current search.
void inspectCurrentNode(bool fix=true, int inspectorNo=-1)
Call the double click inspector for the currently selected node.
int sourceY
Target y coordinate after smooth scrolling.
void setAutoHideFailed(bool b)
Set preference whether to automatically hide failed subtrees.
void addDoubleClickInspector(Inspector *i)
Add inspector i.
int refreshPause
Time (in msec) to pause after each refresh.
QVector< QPair< Inspector *, bool > > moveInspectors
The registered move inspectors, and whether they are active.
QVector< QPair< Inspector *, bool > > solutionInspectors
The registered solution inspectors, and whether they are active.
void addedBookmark(const QString &id)
Signals that a bookmark has been added.
Node class that supports visual layout
bool isHidden(void)
Return if node is hidden.
void dirtyUp(const NodeAllocator &na)
Mark all nodes up the path to the parent as dirty.
std::string toolTip(NodeAllocator &na, BestNode *curBest, int c_d, int a_d)
Return string that is used as a tool tip.
void hideFailed(const NodeAllocator &na, bool onlyDirty=false)
Hide all failed subtrees of this node.
BoundingBox getBoundingBox(void)
Return the bounding box.
void setMarked(bool m)
Set mark of this node.
Shape * getShape(void)
Return the shape of this node.
Computation spaces.
Definition core.hpp:1775
int bab(Space *root, const Gist::Options &opt=Gist::Options::def)
Create a new stand-alone Gist for branch-and-bound search of root.
Definition gist.hpp:208
Space * clone(void) const
Clone space.
Definition core.hpp:3312
SpaceStatus status(StatusStatistics &stat)
Query space status.
Definition core.cpp:282
void commit(const Choice &c, unsigned int a)
Commit choice c for alternative a.
Definition core.hpp:3326
@ SS_BRANCH
Space must be branched (at least one brancher left)
Definition core.hpp:1717
@ SS_SOLVED
Space is solved (no brancher left)
Definition core.hpp:1716
@ SS_FAILED
Space is failed
Definition core.hpp:1715
const int maxScale
Maximum scale factor.
Definition treecanvas.hh:60
const int defScale
Default scale factor.
Definition treecanvas.hh:62
const int minScale
Minimum scale factor.
Definition treecanvas.hh:58
const int maxAutoZoomScale
Maximum scale factor for automatic zoom.
Definition treecanvas.hh:64
The Gecode Interactive Search Tool.
@ UNDETERMINED
Node that has not been explored yet.
Definition spacenode.hh:48
@ UNSTOP
Node representing ignored stop point.
Definition spacenode.hh:50
@ FAILED
Node representing failure.
Definition spacenode.hh:46
@ STOP
Node representing stop point.
Definition spacenode.hh:49
@ SOLVED
Node representing a solution.
Definition spacenode.hh:45
@ BRANCH
Node representing a branch.
Definition spacenode.hh:47
Space * snapshot(Space *s, const Options &o)
Clone space s depending on options o.
Definition support.hh:71
Gecode toplevel namespace
T * dfs(T *s, const Search::Options &o=Search::Options::def)
Invoke depth-first search engine for subclass T of space s with options o.
Definition dfs.hpp:73
#define GECODE_NEVER
Assert that this command is never executed.
Definition macros.hpp:56