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