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