• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdesdk API Reference
  • KDE Home
  • Contact Us
 

kcachegrind

  • sources
  • kde-4.14
  • kdesdk
  • kcachegrind
  • libviews
treemap.cpp
Go to the documentation of this file.
1 /* This file is part of KCachegrind.
2  Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
3 
4  KCachegrind is free software; you can redistribute it and/or
5  modify it under the terms of the GNU General Public
6  License as published by the Free Software Foundation, version 2.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; see the file COPYING. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 */
18 
19 /*
20  * A Widget for visualizing hierarchical metrics as areas.
21  * The API is similar to QListView.
22  */
23 
24 #include "treemap.h"
25 
26 #include <math.h>
27 #include <QAction>
28 #include <QMenu>
29 #include <QApplication>
30 #include <QDebug>
31 #include <QPainter>
32 #include <QStyle>
33 #include <QPixmap>
34 #include <QPaintEvent>
35 #include <QKeyEvent>
36 #include <QShowEvent>
37 #include <QContextMenuEvent>
38 #include <QMouseEvent>
39 #include <QToolTip>
40 #include <QStylePainter>
41 #include <QStyleOptionFocusRect>
42 
43 
44 // set this to 1 to enable debug output
45 #define DEBUG_DRAWING 0
46 #define MAX_FIELD 12
47 
48 
49 //
50 // StoredDrawParams
51 //
52 StoredDrawParams::StoredDrawParams()
53 {
54  _selected = false;
55  _current = false;
56  _shaded = true;
57  _rotated = false;
58  _drawFrame = true;
59 
60  _backColor = Qt::white;
61 
62  // field array has size 0
63 }
64 
65 StoredDrawParams::StoredDrawParams(const QColor& c,
66  bool selected, bool current)
67 {
68  _backColor = c;
69 
70  _selected = selected;
71  _current = current;
72  _shaded = true;
73  _rotated = false;
74  _drawFrame = true;
75 
76  // field array has size 0
77 }
78 
79 QString StoredDrawParams::text(int f) const
80 {
81  if ((f<0) || (f >= (int)_field.size()))
82  return QString();
83 
84  return _field[f].text;
85 }
86 
87 QPixmap StoredDrawParams::pixmap(int f) const
88 {
89  if ((f<0) || (f >= (int)_field.size()))
90  return QPixmap();
91 
92  return _field[f].pix;
93 }
94 
95 DrawParams::Position StoredDrawParams::position(int f) const
96 {
97  if ((f<0) || (f >= (int)_field.size()))
98  return Default;
99 
100  return _field[f].pos;
101 }
102 
103 int StoredDrawParams::maxLines(int f) const
104 {
105  if ((f<0) || (f >= (int)_field.size()))
106  return 0;
107 
108  return _field[f].maxLines;
109 }
110 
111 const QFont& StoredDrawParams::font() const
112 {
113  static QFont* f = 0;
114  if (!f) f = new QFont(QApplication::font());
115 
116  return *f;
117 }
118 
119 void StoredDrawParams::ensureField(int f)
120 {
121  if (f<0 || f>=MAX_FIELD) return;
122 
123  if ((int)_field.size() < f+1) {
124  int oldSize = _field.size();
125  _field.resize(f+1);
126  while(oldSize < f+1) {
127  _field[oldSize].pos = Default;
128  _field[oldSize].maxLines = 0;
129  oldSize++;
130  }
131  }
132 }
133 
134 
135 void StoredDrawParams::setField(int f, const QString& t, const QPixmap& pm,
136  Position p, int maxLines)
137 {
138  if (f<0 || f>=MAX_FIELD) return;
139  ensureField(f);
140 
141  _field[f].text = t;
142  _field[f].pix = pm;
143  _field[f].pos = p;
144  _field[f].maxLines = maxLines;
145 }
146 
147 void StoredDrawParams::setText(int f, const QString& t)
148 {
149  if (f<0 || f>=MAX_FIELD) return;
150  ensureField(f);
151 
152  _field[f].text = t;
153 }
154 
155 void StoredDrawParams::setPixmap(int f, const QPixmap& pm)
156 {
157  if (f<0 || f>=MAX_FIELD) return;
158  ensureField(f);
159 
160  _field[f].pix = pm;
161 }
162 
163 void StoredDrawParams::setPosition(int f, Position p)
164 {
165  if (f<0 || f>=MAX_FIELD) return;
166  ensureField(f);
167 
168  _field[f].pos = p;
169 }
170 
171 void StoredDrawParams::setMaxLines(int f, int m)
172 {
173  if (f<0 || f>=MAX_FIELD) return;
174  ensureField(f);
175 
176  _field[f].maxLines = m;
177 }
178 
179 
180 
181 //
182 // RectDrawing
183 //
184 
185 RectDrawing::RectDrawing(const QRect& r)
186 {
187  _fm = 0;
188  _dp = 0;
189  setRect(r);
190 }
191 
192 
193 RectDrawing::~RectDrawing()
194 {
195  delete _fm;
196  delete _dp;
197 }
198 
199 DrawParams* RectDrawing::drawParams()
200 {
201  if (!_dp)
202  _dp = new StoredDrawParams();
203 
204  return _dp;
205 }
206 
207 
208 void RectDrawing::setDrawParams(DrawParams* dp)
209 {
210  delete _dp;
211  _dp = dp;
212 }
213 
214 void RectDrawing::setRect(const QRect& r)
215 {
216  _rect = r;
217 
218  _usedTopLeft = 0;
219  _usedTopCenter = 0;
220  _usedTopRight = 0;
221  _usedBottomLeft = 0;
222  _usedBottomCenter = 0;
223  _usedBottomRight = 0;
224 
225  _fontHeight = 0;
226 }
227 
228 QRect RectDrawing::remainingRect(DrawParams* dp)
229 {
230  if (!dp) dp = drawParams();
231 
232  if ((_usedTopLeft >0) ||
233  (_usedTopCenter >0) ||
234  (_usedTopRight >0)) {
235  if (dp->rotated())
236  _rect.setLeft(_rect.left() + _fontHeight);
237  else
238  _rect.setTop(_rect.top() + _fontHeight);
239  }
240 
241  if ((_usedBottomLeft >0) ||
242  (_usedBottomCenter >0) ||
243  (_usedBottomRight >0)) {
244  if (dp->rotated())
245  _rect.setRight(_rect.right() - _fontHeight);
246  else
247  _rect.setBottom(_rect.bottom() - _fontHeight);
248  }
249  return _rect;
250 }
251 
252 
253 void RectDrawing::drawBack(QPainter* p, DrawParams* dp)
254 {
255  if (!dp) dp = drawParams();
256  if (_rect.width()<=0 || _rect.height()<=0) return;
257 
258  QRect r = _rect;
259  QColor normal = dp->backColor();
260  if (dp->selected()) normal = normal.light();
261  bool isCurrent = dp->current();
262 
263  if (dp->drawFrame() || isCurrent) {
264  // 3D raised/sunken frame effect...
265  QColor high = normal.light();
266  QColor low = normal.dark();
267  p->setPen( isCurrent ? low:high);
268  p->drawLine(r.left(), r.top(), r.right(), r.top());
269  p->drawLine(r.left(), r.top(), r.left(), r.bottom());
270  p->setPen( isCurrent ? high:low);
271  p->drawLine(r.right(), r.top(), r.right(), r.bottom());
272  p->drawLine(r.left(), r.bottom(), r.right(), r.bottom());
273  r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
274  }
275  if (r.width()<=0 || r.height()<=0) return;
276 
277  if (dp->shaded() && (r.width()>0 && r.height()>0)) {
278  // adjustment for drawRect semantic in Qt4: decrement height/width
279  r.setRect(r.x(), r.y(), r.width()-1, r.height()-1);
280 
281  // some shading
282  bool goDark = qGray(normal.rgb())>128;
283  int rBase, gBase, bBase;
284  normal.getRgb(&rBase, &gBase, &bBase);
285  p->setBrush(Qt::NoBrush);
286 
287  // shade parameters:
288  int d = 7;
289  float factor = 0.1, forth=0.7, back1 =0.9, toBack2 = .7, back2 = 0.97;
290 
291  // coefficient corrections because of rectangle size
292  int s = r.width();
293  if (s > r.height()) s = r.height();
294  if (s<100) {
295  forth -= .3 * (100-s)/100;
296  back1 -= .2 * (100-s)/100;
297  back2 -= .02 * (100-s)/100;
298  }
299 
300 
301  // maximal color difference
302  int rDiff = goDark ? -rBase/d : (255-rBase)/d;
303  int gDiff = goDark ? -gBase/d : (255-gBase)/d;
304  int bDiff = goDark ? -bBase/d : (255-bBase)/d;
305 
306  QColor shadeColor;
307  while (factor<.95 && (r.width()>=0 && r.height()>=0)) {
308  shadeColor.setRgb((int)(rBase+factor*rDiff+.5),
309  (int)(gBase+factor*gDiff+.5),
310  (int)(bBase+factor*bDiff+.5));
311  p->setPen(shadeColor);
312  p->drawRect(r);
313  r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
314  factor = 1.0 - ((1.0 - factor) * forth);
315  }
316 
317  // and back (1st half)
318  while (factor>toBack2 && (r.width()>=0 && r.height()>=0)) {
319  shadeColor.setRgb((int)(rBase+factor*rDiff+.5),
320  (int)(gBase+factor*gDiff+.5),
321  (int)(bBase+factor*bDiff+.5));
322  p->setPen(shadeColor);
323  p->drawRect(r);
324  r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
325  factor = 1.0 - ((1.0 - factor) / back1);
326  }
327 
328  // and back (2nd half)
329  while (factor>.01 && (r.width()>=0 && r.height()>=0)) {
330  shadeColor.setRgb((int)(rBase+factor*rDiff+.5),
331  (int)(gBase+factor*gDiff+.5),
332  (int)(bBase+factor*bDiff+.5));
333  p->setPen(shadeColor);
334  p->drawRect(r);
335  r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
336  factor = factor * back2;
337  }
338 
339  normal = shadeColor;
340  // for filling, width and height has to be incremented again
341  r.setRect(r.x(), r.y(), r.width()+1, r.height()+1);
342  }
343 
344  // fill inside
345  p->fillRect(r, normal);
346 }
347 
348 
349 /* Helper for drawField
350  * Find a line break position in a string, given a font and maximum width
351  *
352  * Returns the actually used width, and sets <breakPos>
353  */
354 static
355 int findBreak(int& breakPos, QString text, QFontMetrics* fm, int maxWidth)
356 {
357  int usedWidth;
358 
359  // does full text fit?
360  breakPos = text.length();
361  usedWidth = fm->width(text);
362  if (usedWidth < maxWidth)
363  return usedWidth;
364 
365  // binary search for best break position in [bottomPos,breakPos].
366  // We want the result of the binary search to be a bit too large
367  int bottomPos = 0;
368  while(1) {
369  int halfPos = (bottomPos + breakPos)/2;
370  int halfWidth = fm->width(text, halfPos);
371  if (halfWidth < maxWidth) {
372  bottomPos = halfPos+1;
373  continue;
374  }
375  breakPos = halfPos;
376  usedWidth = halfWidth;
377  if (breakPos - bottomPos <3) break;
378  }
379 
380  // final position by taking break boundaries into account.
381  // possible break boundaries are changing char categories,
382  // but not middle of "Aa"
383  QChar::Category lastCat, cat;
384  int pos = breakPos;
385  lastCat = text[pos-1].category();
386  // at minimum 2 chars before break
387  while (pos > 2) {
388  pos--;
389  cat = text[pos-1].category();
390  if (cat == lastCat) continue;
391 
392  // "Aa" has not a possible break inbetween
393  if ((cat == QChar::Letter_Uppercase) &&
394  (lastCat == QChar::Letter_Lowercase)) {
395  lastCat = cat;
396  continue;
397  }
398  lastCat = cat;
399 
400  breakPos = pos;
401  usedWidth = fm->width(text, breakPos);
402  if (usedWidth < maxWidth) break;
403  }
404  return usedWidth;
405 }
406 
407 
408 /* Helper for drawField
409  * Find last line break position in a string from backwards,
410  * given a font and maximum width
411  *
412  * Returns the actually used width, and sets <breakPos>
413  */
414 static
415 int findBreakBackwards(int& breakPos, QString text, QFontMetrics* fm, int maxWidth)
416 {
417  int usedWidth;
418 
419  // does full text fit?
420  breakPos = 0;
421  usedWidth = fm->width(text);
422  if (usedWidth < maxWidth)
423  return usedWidth;
424 
425  // binary search for best break position in [breakPos,topPos].
426  // We want the result of the binary search to be a bit too small
427  int topPos = text.length();
428  while(1) {
429  int halfPos = (breakPos + topPos)/2;
430  int halfWidth = fm->width(text.mid(halfPos));
431  if (halfWidth > maxWidth) {
432  topPos = halfPos-1;
433  continue;
434  }
435  breakPos = halfPos;
436  usedWidth = halfWidth;
437  if (topPos - breakPos <3) break;
438  }
439 
440  // final position by taking break boundaries into account.
441  // possible break boundaries are changing char categories but not middle of "Aa"
442  QChar::Category lastCat, cat;
443  int pos = breakPos;
444  lastCat = text[pos].category();
445  // at minimum 2 chars before break
446  while (pos < text.length()-2) {
447  pos++;
448  cat = text[pos].category();
449  if (cat == lastCat) continue;
450 
451  // "Aa" has not a possible break inbetween
452  if ((lastCat == QChar::Letter_Uppercase) &&
453  (cat == QChar::Letter_Lowercase)) {
454  lastCat = cat;
455  continue;
456  }
457  lastCat = cat;
458 
459  breakPos = pos;
460  usedWidth = fm->width(text.mid(breakPos));
461  if (usedWidth < maxWidth) break;
462  }
463  return usedWidth;
464 }
465 
466 
467 
468 bool RectDrawing::drawField(QPainter* p, int f, DrawParams* dp)
469 {
470  if (!dp) dp = drawParams();
471 
472  if (!_fm) {
473  _fm = new QFontMetrics(dp->font());
474  _fontHeight = _fm->height();
475  }
476 
477  QRect r = _rect;
478 
479  if (0) qDebug() << "DrawField: Rect " << r.x() << "/" << r.y()
480  << " - " << r.width() << "x" << r.height();
481 
482  int h = _fontHeight;
483  bool rotate = dp->rotated();
484  int width = (rotate ? r.height() : r.width()) -4;
485  int height = (rotate ? r.width() : r.height());
486  int lines = height / h;
487 
488  // stop if there is no space available
489  if (lines<1) return false;
490 
491  // calculate free space in first line (<unused>)
492  int pos = dp->position(f);
493  if (pos == DrawParams::Default) {
494  switch(f%4) {
495  case 0: pos = DrawParams::TopLeft; break;
496  case 1: pos = DrawParams::TopRight; break;
497  case 2: pos = DrawParams::BottomRight; break;
498  case 3: pos = DrawParams::BottomLeft; break;
499  }
500  }
501 
502  int unused = 0;
503  bool isBottom = false;
504  bool isCenter = false;
505  bool isRight = false;
506  int* used = 0;
507  switch(pos) {
508  case DrawParams::TopLeft:
509  used = &_usedTopLeft;
510  if (_usedTopLeft == 0) {
511  if (_usedTopCenter)
512  unused = (width - _usedTopCenter)/2;
513  else
514  unused = width - _usedTopRight;
515  }
516  break;
517 
518  case DrawParams::TopCenter:
519  isCenter = true;
520  used = &_usedTopCenter;
521  if (_usedTopCenter == 0) {
522  if (_usedTopLeft > _usedTopRight)
523  unused = width - 2 * _usedTopLeft;
524  else
525  unused = width - 2 * _usedTopRight;
526  }
527  break;
528 
529  case DrawParams::TopRight:
530  isRight = true;
531  used = &_usedTopRight;
532  if (_usedTopRight == 0) {
533  if (_usedTopCenter)
534  unused = (width - _usedTopCenter)/2;
535  else
536  unused = width - _usedTopLeft;
537  }
538  break;
539 
540  case DrawParams::BottomLeft:
541  isBottom = true;
542  used = &_usedBottomLeft;
543  if (_usedBottomLeft == 0) {
544  if (_usedBottomCenter)
545  unused = (width - _usedBottomCenter)/2;
546  else
547  unused = width - _usedBottomRight;
548  }
549  break;
550 
551  case DrawParams::BottomCenter:
552  isCenter = true;
553  isBottom = true;
554  used = &_usedBottomCenter;
555  if (_usedBottomCenter == 0) {
556  if (_usedBottomLeft > _usedBottomRight)
557  unused = width - 2 * _usedBottomLeft;
558  else
559  unused = width - 2 * _usedBottomRight;
560  }
561  break;
562 
563  case DrawParams::BottomRight:
564  isRight = true;
565  isBottom = true;
566  used = &_usedBottomRight;
567  if (_usedBottomRight == 0) {
568  if (_usedBottomCenter)
569  unused = (width - _usedBottomCenter)/2;
570  else
571  unused = width - _usedBottomLeft;
572  }
573  break;
574  }
575 
576  if (isBottom) {
577  if ((_usedTopLeft >0) ||
578  (_usedTopCenter >0) ||
579  (_usedTopRight >0))
580  lines--;
581  }
582  else if (!isBottom) {
583  if ((_usedBottomLeft >0) ||
584  (_usedBottomCenter >0) ||
585  (_usedBottomRight >0))
586  lines--;
587  }
588  if (lines<1) return false;
589 
590 
591  int y = isBottom ? height - h : 0;
592 
593  if (unused < 0) unused = 0;
594  if (unused == 0) {
595  // no space available in last line at this position
596  y = isBottom ? (y-h) : (y+h);
597  lines--;
598 
599  if (lines<1) return false;
600 
601  // new line: reset used space
602  if (isBottom)
603  _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
604  else
605  _usedTopLeft = _usedTopCenter = _usedTopRight = 0;
606 
607  unused = width;
608  }
609 
610  // stop as soon as possible when there is no space for "..."
611  static int dotW = 0;
612  if (!dotW) dotW = _fm->width("...");
613  if (width < dotW) return false;
614 
615  // get text and pixmap now, only if we need to, because it is possible
616  // that they are calculated on demand (and this can take some time)
617  QString name = dp->text(f);
618  if (name.isEmpty()) return 0;
619  QPixmap pix = dp->pixmap(f);
620 
621  // check if pixmap can be drawn
622  int pixW = pix.width();
623  int pixH = pix.height();
624  int pixY = 0;
625  bool pixDrawn = true;
626  if (pixW>0) {
627  pixW += 2; // X distance from pix
628  if ((width < pixW + dotW) || (height < pixH)) {
629  // do not draw
630  pixW = 0;
631  }
632  else
633  pixDrawn = false;
634  }
635 
636  // width of text and pixmap to be drawn
637  int w = pixW + _fm->width(name);
638 
639  if (0) qDebug() << " For '" << name << "': Unused " << unused
640  << ", StrW " << w << ", Width " << width;
641 
642  // if we have limited space at 1st line:
643  // use it only if whole name does fit in last line...
644  if ((unused < width) && (w > unused)) {
645  y = isBottom ? (y-h) : (y+h);
646  lines--;
647 
648  if (lines<1) return false;
649 
650  // new line: reset used space
651  if (isBottom)
652  _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
653  else
654  _usedTopLeft = _usedTopCenter = _usedTopRight = 0;
655  }
656 
657  p->save();
658  p->setPen( (qGray(dp->backColor().rgb())>100) ? Qt::black : Qt::white);
659  p->setFont(dp->font());
660  if (rotate) {
661  //p->translate(r.x()+2, r.y()+r.height());
662  p->translate(r.x(), r.y()+r.height()-2);
663  p->rotate(270);
664  }
665  else
666  p->translate(r.x()+2, r.y());
667 
668 
669  // adjust available lines according to maxLines
670  int max = dp->maxLines(f);
671  if ((max > 0) && (lines>max)) lines = max;
672 
673  /* loop over name parts to break up string depending on available width.
674  * every char category change is supposed a possible break,
675  * with the exception Uppercase=>Lowercase.
676  * It is good enough for numbers, Symbols...
677  *
678  * If the text is to be written at the bottom, we start with the
679  * end of the string (so everything is reverted)
680  */
681  QString remaining;
682  int origLines = lines;
683  while (lines>0) {
684 
685  // more than one line: search for line break
686  if (w>width && lines>1) {
687  int breakPos;
688 
689  if (!isBottom) {
690  w = pixW + findBreak(breakPos, name, _fm, width - pixW);
691 
692  remaining = name.mid(breakPos);
693  // remove space on break point
694  if (name[breakPos-1].category() == QChar::Separator_Space)
695  name = name.left(breakPos-1);
696  else
697  name = name.left(breakPos);
698  }
699  else { // bottom
700  w = pixW + findBreakBackwards(breakPos, name, _fm, width - pixW);
701 
702  remaining = name.left(breakPos);
703  // remove space on break point
704  if (name[breakPos].category() == QChar::Separator_Space)
705  name = name.mid(breakPos+1);
706  else
707  name = name.mid(breakPos);
708  }
709  }
710  else
711  remaining = QString();
712 
713  /* truncate and add ... if needed */
714  if (w > width) {
715  name = _fm->elidedText(name, Qt::ElideRight, width - pixW);
716  w = _fm->width(name) + pixW;
717  }
718 
719  int x = 0;
720  if (isCenter)
721  x = (width - w)/2;
722  else if (isRight)
723  x = width - w;
724 
725  if (!pixDrawn) {
726  pixY = y+(h-pixH)/2; // default: center vertically
727  if (pixH > h) pixY = isBottom ? y-(pixH-h) : y;
728 
729  p->drawPixmap( x, pixY, pix);
730 
731  // for distance to next text
732  pixY = isBottom ? (pixY - h - 2) : (pixY + pixH + 2);
733  pixDrawn = true;
734  }
735 
736 
737  if (0) qDebug() << " Drawing '" << name << "' at "
738  << x+pixW << "/" << y;
739 
740  p->drawText( x+pixW, y,
741  width - pixW, h,
742  Qt::AlignLeft, name);
743  y = isBottom ? (y-h) : (y+h);
744  lines--;
745 
746  if (remaining.isEmpty()) break;
747  name = remaining;
748  w = pixW + _fm->width(name);
749  }
750 
751  // make sure the pix stays visible
752  if (pixDrawn && (pixY>0)) {
753  if (isBottom && (pixY<y)) y = pixY;
754  if (!isBottom && (pixY>y)) y = pixY;
755  }
756 
757  if (origLines > lines) {
758  // if only 1 line written, do not reset _used* vars
759  if (lines - origLines >1) {
760  if (isBottom)
761  _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
762  else
763  _usedTopLeft = _usedTopCenter = _usedTopRight = 0;
764  }
765 
766  // take back one line
767  y = isBottom ? (y+h) : (y-h);
768  if (used) *used = w;
769  }
770 
771  // update free space
772  if (!isBottom) {
773  if (rotate)
774  _rect.setRect(r.x()+y, r.y(), r.width()-y, r.height());
775  else
776  _rect.setRect(r.x(), r.y()+y, r.width(), r.height()-y);
777  }
778  else {
779  if (rotate)
780  _rect.setRect(r.x(), r.y(), y+h, r.height());
781  else
782  _rect.setRect(r.x(), r.y(), r.width(), y+h);
783  }
784 
785  p->restore();
786 
787  return true;
788 }
789 
790 
791 
792 
793 
794 
795 //
796 // TreeMapItemList
797 //
798 
799 
800 TreeMapItem* TreeMapItemList::commonParent()
801 {
802  if (isEmpty()) return 0;
803 
804  TreeMapItem* parent = first();
805  for(int i = 1; parent && i<size(); i++)
806  parent = parent->commonParent(at(i));
807 
808  return parent;
809 }
810 
811 class TreeMapItemLessThan
812 {
813 public:
814  bool operator()(const TreeMapItem* i1, const TreeMapItem* i2) const
815  {
816  TreeMapItem* p = i1->parent();
817  // should not happen
818  if (!p) return false;
819 
820  bool ascending;
821  bool result;
822  int textNo = p->sorting(&ascending);
823  if (textNo < 0)
824  result = i1->value() < i2->value();
825  else
826  result = i1->text(textNo) < i2->text(textNo);
827 
828  return ascending ? result : !result;
829  }
830 };
831 
832 TreeMapItemLessThan treeMapItemLessThan;
833 
834 // TreeMapItem
835 
836 TreeMapItem::TreeMapItem(TreeMapItem* parent, double value)
837 {
838  _value = value;
839  _parent = parent;
840 
841  _sum = 0;
842  _children = 0;
843  _widget = 0;
844  _index = -1;
845  _depth = -1; // not set
846  _unused_self = 0;
847 
848  if (_parent) {
849  // take sorting from parent
850  _sortTextNo = _parent->sorting(&_sortAscending);
851  _parent->addItem(this);
852  }
853  else {
854  _sortAscending = false;
855  _sortTextNo = -1; // default: no sorting
856  }
857 }
858 
859 
860 TreeMapItem::TreeMapItem(TreeMapItem* parent, double value,
861  const QString& text1, const QString& text2,
862  const QString& text3, const QString& text4)
863 {
864  _value = value;
865  _parent = parent;
866 
867  // this resizes the text vector only if needed
868  if (!text4.isEmpty()) setText(3, text4);
869  if (!text3.isEmpty()) setText(2, text3);
870  if (!text2.isEmpty()) setText(1, text2);
871  setText(0, text1);
872 
873  _sum = 0;
874  _children = 0;
875  _widget = 0;
876  _index = -1;
877  _depth = -1; // not set
878  _unused_self = 0;
879 
880  if (_parent) _parent->addItem(this);
881 }
882 
883 TreeMapItem::~TreeMapItem()
884 {
885  if (_children) {
886  qDeleteAll(*_children);
887  delete _children;
888  _children = 0;
889  }
890 
891  // finally, notify widget about deletion
892  if (_widget) _widget->deletingItem(this);
893 }
894 
895 void TreeMapItem::setParent(TreeMapItem* p)
896 {
897  _parent = p;
898  if (p) _widget = p->_widget;
899 }
900 
901 bool TreeMapItem::isChildOf(TreeMapItem* item)
902 {
903  if (!item) return false;
904 
905  TreeMapItem* i = this;
906  while (i) {
907  if (item == i) return true;
908  i = i->_parent;
909  }
910  return false;
911 }
912 
913 TreeMapItem* TreeMapItem::commonParent(TreeMapItem* item)
914 {
915  while (item && !isChildOf(item)) {
916  item = item->parent();
917  }
918  return item;
919 }
920 
921 void TreeMapItem::redraw()
922 {
923  if (_widget)
924  _widget->redraw(this);
925 }
926 
927 void TreeMapItem::clear()
928 {
929  if (_children) {
930  // delete selected items below this item from selection
931  if (_widget) _widget->clearSelection(this);
932 
933  qDeleteAll(*_children);
934  delete _children;
935  _children = 0;
936  }
937 }
938 
939 
940 // invalidates current children and forces redraw
941 // this is only useful when children are created on demand in items()
942 void TreeMapItem::refresh()
943 {
944  clear();
945  redraw();
946 }
947 
948 
949 QStringList TreeMapItem::path(int textNo) const
950 {
951  QStringList list(text(textNo));
952 
953  TreeMapItem* i = _parent;
954  while (i) {
955  QString text = i->text(textNo);
956  if (!text.isEmpty())
957  list.prepend(i->text(textNo));
958  i = i->_parent;
959  }
960  return list;
961 }
962 
963 int TreeMapItem::depth() const
964 {
965  if (_depth>0) return _depth;
966 
967  if (_parent)
968  return _parent->depth() + 1;
969  return 1;
970 }
971 
972 
973 bool TreeMapItem::initialized()
974 {
975  if (!_children) {
976  _children = new TreeMapItemList;
977  return false;
978  }
979  return true;
980 }
981 
982 void TreeMapItem::addItem(TreeMapItem* i)
983 {
984  if (!i) return;
985 
986  if (!_children)
987  _children = new TreeMapItemList;
988 
989  i->setParent(this);
990 
991  _children->append(i); // preserve insertion order
992  if (sorting(0) != -1)
993  qSort(_children->begin(), _children->end(), treeMapItemLessThan);
994 }
995 
996 
997 // default implementations of virtual functions
998 
999 double TreeMapItem::value() const
1000 {
1001  return _value;
1002 }
1003 
1004 double TreeMapItem::sum() const
1005 {
1006  return _sum;
1007 }
1008 
1009 DrawParams::Position TreeMapItem::position(int f) const
1010 {
1011  Position p = StoredDrawParams::position(f);
1012  if (_widget && (p == Default))
1013  p = _widget->fieldPosition(f);
1014 
1015  return p;
1016 }
1017 
1018 // use widget font
1019 const QFont& TreeMapItem::font() const
1020 {
1021  return _widget->currentFont();
1022 }
1023 
1024 
1025 bool TreeMapItem::isMarked(int) const
1026 {
1027  return false;
1028 }
1029 
1030 
1031 int TreeMapItem::borderWidth() const
1032 {
1033  if (_widget)
1034  return _widget->borderWidth();
1035 
1036  return 2;
1037 }
1038 
1039 int TreeMapItem::sorting(bool* ascending) const
1040 {
1041  if (ascending) *ascending = _sortAscending;
1042  return _sortTextNo;
1043 }
1044 
1045 // do *not* set sorting recursively
1046 void TreeMapItem::setSorting(int textNo, bool ascending)
1047 {
1048  if (_sortTextNo == textNo) {
1049  if(_sortAscending == ascending) return;
1050  if (textNo == -1) {
1051  // when no sorting is done, order change does not do anything
1052  _sortAscending = ascending;
1053  return;
1054  }
1055  }
1056  _sortAscending = ascending;
1057  _sortTextNo = textNo;
1058 
1059  if (_children && _sortTextNo != -1)
1060  qSort(_children->begin(), _children->end(), treeMapItemLessThan);
1061 }
1062 
1063 void TreeMapItem::resort(bool recursive)
1064 {
1065  if (!_children) return;
1066 
1067  if (_sortTextNo != -1)
1068  qSort(_children->begin(), _children->end(), treeMapItemLessThan);
1069 
1070  if (recursive)
1071  foreach(TreeMapItem* i, *_children)
1072  i->resort(recursive);
1073 }
1074 
1075 
1076 TreeMapItem::SplitMode TreeMapItem::splitMode() const
1077 {
1078  if (_widget)
1079  return _widget->splitMode();
1080 
1081  return Best;
1082 }
1083 
1084 int TreeMapItem::rtti() const
1085 {
1086  return 0;
1087 }
1088 
1089 TreeMapItemList* TreeMapItem::children()
1090 {
1091  if (!_children)
1092  _children = new TreeMapItemList;
1093 
1094  return _children;
1095 }
1096 
1097 void TreeMapItem::clearItemRect()
1098 {
1099  _rect = QRect();
1100  clearFreeRects();
1101 }
1102 
1103 void TreeMapItem::clearFreeRects()
1104 {
1105  _freeRects.clear();
1106 }
1107 
1108 void TreeMapItem::addFreeRect(const QRect& r)
1109 {
1110  // do not add invalid rects
1111  if ((r.width() < 1) || (r.height() < 1)) return;
1112 
1113  if (0) qDebug() << "addFree(" << path(0).join("/") << ", "
1114  << r.x() << "/" << r.y() << "-"
1115  << r.width() << "x" << r.height() << ")";
1116 
1117  if (_freeRects.isEmpty()) {
1118  _freeRects.append(r);
1119  return;
1120  }
1121 
1122  // join rect with last rect if possible
1123  // this saves memory and does not make the tooltip flicker
1124  QRect& last = _freeRects.last();
1125  bool replaced = false;
1126  if ((last.left() == r.left()) && (last.width() == r.width())) {
1127  if ((last.bottom()+1 == r.top()) || (r.bottom()+1 == last.top())) {
1128  last |= r;
1129  replaced = true;
1130  }
1131  }
1132  else if ((last.top() == r.top()) && (last.height() == r.height())) {
1133  if ((last.right()+1 == r.left()) || (r.right()+1 == last.left())) {
1134  last |= r;
1135  replaced = true;
1136  }
1137  }
1138 
1139  if (!replaced) {
1140  _freeRects.append(r);
1141  return;
1142  }
1143 
1144  if (0) qDebug() << " united with last to ("
1145  << last.x() << "/" << last.y() << "-"
1146  << last.width() << "x" << last.height() << ")";
1147 }
1148 
1149 
1150 
1151 // TreeMapWidget
1152 
1153 TreeMapWidget::TreeMapWidget(TreeMapItem* base,
1154  QWidget* parent)
1155  : QWidget(parent)
1156 {
1157  _base = base;
1158  _base->setWidget(this);
1159 
1160  _font = font();
1161  _fontHeight = fontMetrics().height();
1162 
1163 
1164  // default behaviour
1165  _selectionMode = Single;
1166  _splitMode = TreeMapItem::AlwaysBest;
1167  _visibleWidth = 2;
1168  _reuseSpace = false;
1169  _skipIncorrectBorder = false;
1170  _drawSeparators = false;
1171  _allowRotation = true;
1172  _borderWidth = 2;
1173  _shading = true; // beautiful is default!
1174  _maxSelectDepth = -1; // unlimited
1175  _maxDrawingDepth = -1; // unlimited
1176  _minimalArea = -1; // unlimited
1177  _markNo = 0;
1178 
1179  for(int i=0;i<4;i++) {
1180  _drawFrame[i] = true;
1181  _transparent[i] = false;
1182  }
1183 
1184  // _stopAtText will be unset on resizing (per default)
1185  // _textVisible will be true on resizing (per default)
1186  // _forceText will be false on resizing (per default)
1187 
1188  // start state: _selection is an empty list
1189  _current = 0;
1190  _oldCurrent = 0;
1191  _pressed = 0;
1192  _lastOver = 0;
1193  _needsRefresh = _base;
1194 
1195  setAttribute(Qt::WA_NoSystemBackground, true);
1196  setFocusPolicy(Qt::StrongFocus);
1197 }
1198 
1199 TreeMapWidget::~TreeMapWidget()
1200 {
1201  delete _base;
1202 }
1203 
1204 const QFont& TreeMapWidget::currentFont() const
1205 {
1206  return _font;
1207 }
1208 
1209 void TreeMapWidget::setSplitMode(TreeMapItem::SplitMode m)
1210 {
1211  if (_splitMode == m) return;
1212 
1213  _splitMode = m;
1214  redraw();
1215 }
1216 
1217 TreeMapItem::SplitMode TreeMapWidget::splitMode() const
1218 {
1219  return _splitMode;
1220 }
1221 
1222 bool TreeMapWidget::setSplitMode(const QString& mode)
1223 {
1224  if (mode == "Bisection") setSplitMode(TreeMapItem::Bisection);
1225  else if (mode == "Columns") setSplitMode(TreeMapItem::Columns);
1226  else if (mode == "Rows") setSplitMode(TreeMapItem::Rows);
1227  else if (mode == "AlwaysBest") setSplitMode(TreeMapItem::AlwaysBest);
1228  else if (mode == "Best") setSplitMode(TreeMapItem::Best);
1229  else if (mode == "HAlternate") setSplitMode(TreeMapItem::HAlternate);
1230  else if (mode == "VAlternate") setSplitMode(TreeMapItem::VAlternate);
1231  else if (mode == "Horizontal") setSplitMode(TreeMapItem::Horizontal);
1232  else if (mode == "Vertical") setSplitMode(TreeMapItem::Vertical);
1233  else return false;
1234 
1235  return true;
1236 }
1237 
1238 QString TreeMapWidget::splitModeString() const
1239 {
1240  QString mode;
1241  switch(splitMode()) {
1242  case TreeMapItem::Bisection: mode = "Bisection"; break;
1243  case TreeMapItem::Columns: mode = "Columns"; break;
1244  case TreeMapItem::Rows: mode = "Rows"; break;
1245  case TreeMapItem::AlwaysBest: mode = "AlwaysBest"; break;
1246  case TreeMapItem::Best: mode = "Best"; break;
1247  case TreeMapItem::HAlternate: mode = "HAlternate"; break;
1248  case TreeMapItem::VAlternate: mode = "VAlternate"; break;
1249  case TreeMapItem::Horizontal: mode = "Horizontal"; break;
1250  case TreeMapItem::Vertical: mode = "Vertical"; break;
1251  default: mode = "Unknown"; break;
1252  }
1253  return mode;
1254 }
1255 
1256 
1257 void TreeMapWidget::setShadingEnabled(bool s)
1258 {
1259  if (_shading == s) return;
1260 
1261  _shading = s;
1262  redraw();
1263 }
1264 
1265 void TreeMapWidget::drawFrame(int d, bool b)
1266 {
1267  if ((d<0) || (d>=4) || (_drawFrame[d]==b)) return;
1268 
1269  _drawFrame[d] = b;
1270  redraw();
1271 }
1272 
1273 void TreeMapWidget::setTransparent(int d, bool b)
1274 {
1275  if ((d<0) || (d>=4) || (_transparent[d]==b)) return;
1276 
1277  _transparent[d] = b;
1278  redraw();
1279 }
1280 
1281 void TreeMapWidget::setAllowRotation(bool enable)
1282 {
1283  if (_allowRotation == enable) return;
1284 
1285  _allowRotation = enable;
1286  redraw();
1287 }
1288 
1289 void TreeMapWidget::setVisibleWidth(int width, bool reuseSpace)
1290 {
1291  if (_visibleWidth == width && _reuseSpace == reuseSpace) return;
1292 
1293  _visibleWidth = width;
1294  _reuseSpace = reuseSpace;
1295  redraw();
1296 }
1297 
1298 void TreeMapWidget::setSkipIncorrectBorder(bool enable)
1299 {
1300  if (_skipIncorrectBorder == enable) return;
1301 
1302  _skipIncorrectBorder = enable;
1303  redraw();
1304 }
1305 
1306 void TreeMapWidget::setBorderWidth(int w)
1307 {
1308  if (_borderWidth == w) return;
1309 
1310  _borderWidth = w;
1311  redraw();
1312 }
1313 
1314 void TreeMapWidget::setMaxDrawingDepth(int d)
1315 {
1316  if (_maxDrawingDepth == d) return;
1317 
1318  _maxDrawingDepth = d;
1319  redraw();
1320 }
1321 
1322 QString TreeMapWidget::defaultFieldType(int f) const
1323 {
1324  return tr("Text %1").arg(f+1);
1325 }
1326 
1327 QString TreeMapWidget::defaultFieldStop(int) const
1328 {
1329  return QString();
1330 }
1331 
1332 bool TreeMapWidget::defaultFieldVisible(int f) const
1333 {
1334  return (f<2);
1335 }
1336 
1337 bool TreeMapWidget::defaultFieldForced(int) const
1338 {
1339  return false;
1340 }
1341 
1342 DrawParams::Position TreeMapWidget::defaultFieldPosition(int f) const
1343 {
1344  switch(f%4) {
1345  case 0: return DrawParams::TopLeft;
1346  case 1: return DrawParams::TopRight;
1347  case 2: return DrawParams::BottomRight;
1348  case 3: return DrawParams::BottomLeft;
1349  default:break;
1350  }
1351  return DrawParams::TopLeft;
1352 }
1353 
1354 bool TreeMapWidget::resizeAttr(int size)
1355 {
1356  if (size<0 || size>=MAX_FIELD) return false;
1357 
1358  if (size>(int)_attr.size()) {
1359  int oldSize = _attr.size();
1360  _attr.resize(size);
1361  while (oldSize<size) {
1362  _attr[oldSize].type = defaultFieldType(oldSize);
1363  _attr[oldSize].stop = defaultFieldStop(oldSize);
1364  _attr[oldSize].visible = defaultFieldVisible(oldSize);
1365  _attr[oldSize].forced = defaultFieldForced(oldSize);
1366  _attr[oldSize].pos = defaultFieldPosition(oldSize);
1367  oldSize++;
1368  }
1369  }
1370  return true;
1371 }
1372 
1373 void TreeMapWidget::setFieldType(int f, const QString& type)
1374 {
1375  if (((int)_attr.size() < f+1) &&
1376  (type == defaultFieldType(f))) return;
1377  if (resizeAttr(f+1)) _attr[f].type = type;
1378 
1379  // no need to redraw: the type string is not visible in the TreeMap
1380 }
1381 
1382 QString TreeMapWidget::fieldType(int f) const
1383 {
1384  if (f<0 || (int)_attr.size()<f+1) return defaultFieldType(f);
1385  return _attr[f].type;
1386 }
1387 
1388 void TreeMapWidget::setFieldStop(int f, const QString& stop)
1389 {
1390  if (((int)_attr.size() < f+1) &&
1391  (stop == defaultFieldStop(f))) return;
1392  if (resizeAttr(f+1)) {
1393  _attr[f].stop = stop;
1394  redraw();
1395  }
1396 }
1397 
1398 QString TreeMapWidget::fieldStop(int f) const
1399 {
1400  if (f<0 || (int)_attr.size()<f+1) return defaultFieldStop(f);
1401  return _attr[f].stop;
1402 }
1403 
1404 void TreeMapWidget::setFieldVisible(int f, bool enable)
1405 {
1406  if (((int)_attr.size() < f+1) &&
1407  (enable == defaultFieldVisible(f))) return;
1408 
1409  if (resizeAttr(f+1)) {
1410  _attr[f].visible = enable;
1411  redraw();
1412  }
1413 }
1414 
1415 bool TreeMapWidget::fieldVisible(int f) const
1416 {
1417  if (f<0 || (int)_attr.size()<f+1)
1418  return defaultFieldVisible(f);
1419 
1420  return _attr[f].visible;
1421 }
1422 
1423 void TreeMapWidget::setFieldForced(int f, bool enable)
1424 {
1425  if (((int)_attr.size() < f+1) &&
1426  (enable == defaultFieldForced(f))) return;
1427 
1428  if (resizeAttr(f+1)) {
1429  _attr[f].forced = enable;
1430  if (_attr[f].visible) redraw();
1431  }
1432 }
1433 
1434 bool TreeMapWidget::fieldForced(int f) const
1435 {
1436  if (f<0 || (int)_attr.size()<f+1)
1437  return defaultFieldForced(f);
1438 
1439  return _attr[f].forced;
1440 }
1441 
1442 void TreeMapWidget::setFieldPosition(int f, TreeMapItem::Position pos)
1443 {
1444  if (((int)_attr.size() < f+1) &&
1445  (pos == defaultFieldPosition(f))) return;
1446 
1447  if (resizeAttr(f+1)) {
1448  _attr[f].pos = pos;
1449  if (_attr[f].visible) redraw();
1450  }
1451 }
1452 
1453 DrawParams::Position TreeMapWidget::fieldPosition(int f) const
1454 {
1455  if (f<0 || (int)_attr.size()<f+1)
1456  return defaultFieldPosition(f);
1457 
1458  return _attr[f].pos;
1459 }
1460 
1461 void TreeMapWidget::setFieldPosition(int f, const QString& pos)
1462 {
1463  if (pos == "TopLeft")
1464  setFieldPosition(f, DrawParams::TopLeft);
1465  else if (pos == "TopCenter")
1466  setFieldPosition(f, DrawParams::TopCenter);
1467  else if (pos == "TopRight")
1468  setFieldPosition(f, DrawParams::TopRight);
1469  else if (pos == "BottomLeft")
1470  setFieldPosition(f, DrawParams::BottomLeft);
1471  else if (pos == "BottomCenter")
1472  setFieldPosition(f, DrawParams::BottomCenter);
1473  else if (pos == "BottomRight")
1474  setFieldPosition(f, DrawParams::BottomRight);
1475  else if (pos == "Default")
1476  setFieldPosition(f, DrawParams::Default);
1477 }
1478 
1479 QString TreeMapWidget::fieldPositionString(int f) const
1480 {
1481  TreeMapItem::Position pos = fieldPosition(f);
1482  if (pos == DrawParams::TopLeft) return QString("TopLeft");
1483  if (pos == DrawParams::TopCenter) return QString("TopCenter");
1484  if (pos == DrawParams::TopRight) return QString("TopRight");
1485  if (pos == DrawParams::BottomLeft) return QString("BottomLeft");
1486  if (pos == DrawParams::BottomCenter) return QString("BottomCenter");
1487  if (pos == DrawParams::BottomRight) return QString("BottomRight");
1488  if (pos == DrawParams::Default) return QString("Default");
1489  return QString("unknown");
1490 }
1491 
1492 void TreeMapWidget::setMinimalArea(int area)
1493 {
1494  if (_minimalArea == area) return;
1495 
1496  _minimalArea = area;
1497  redraw();
1498 }
1499 
1500 
1501 void TreeMapWidget::deletingItem(TreeMapItem* i)
1502 {
1503  // remove any references to the item to be deleted
1504  _selection.removeAll(i);
1505  _tmpSelection.removeAll(i);
1506 
1507  if (_current == i) _current = 0;
1508  if (_oldCurrent == i) _oldCurrent = 0;
1509  if (_pressed == i) _pressed = 0;
1510  if (_lastOver == i) _lastOver = 0;
1511 
1512  // do not redraw a deleted item
1513  if (_needsRefresh == i) {
1514  // we can safely redraw the parent, as deleting order is
1515  // from child to parent; i.e. i->parent() is existing.
1516  _needsRefresh = i->parent();
1517  }
1518 }
1519 
1520 
1521 QString TreeMapWidget::tipString(TreeMapItem* i) const
1522 {
1523  QString tip, itemTip;
1524 
1525  while (i) {
1526  if (!i->text(0).isEmpty()) {
1527  itemTip = i->text(0);
1528  if (!i->text(1).isEmpty())
1529  itemTip += " (" + i->text(1) + ')';
1530 
1531  if (!tip.isEmpty())
1532  tip += '\n';
1533 
1534  tip += itemTip;
1535  }
1536  i = i->parent();
1537  }
1538  return tip;
1539 }
1540 
1541 TreeMapItem* TreeMapWidget::item(int x, int y) const
1542 {
1543 
1544  if (!rect().contains(x, y)) return 0;
1545  if (DEBUG_DRAWING) qDebug() << "item(" << x << "," << y << "):";
1546 
1547  TreeMapItem* p = _base;
1548  TreeMapItem* i;
1549  while (1) {
1550  TreeMapItemList* list = p->children();
1551  i = 0;
1552  if (list) {
1553  int idx;
1554  for (idx=0; idx<list->size(); idx++) {
1555  i = list->at(idx);
1556 
1557  if (DEBUG_DRAWING)
1558  qDebug() << " Checking " << i->path(0).join("/") << " ("
1559  << i->itemRect().x() << "/" << i->itemRect().y()
1560  << "-" << i->itemRect().width()
1561  << "x" << i->itemRect().height() << ")";
1562 
1563  if (i->itemRect().contains(x, y)) {
1564 
1565  if (DEBUG_DRAWING) qDebug() << " .. Got. Index " << idx;
1566 
1567  p->setIndex(idx);
1568  break;
1569  }
1570  }
1571  if (idx == list->size()) i = 0; // not contained in child
1572  }
1573 
1574  if (!i) {
1575  static TreeMapItem* last = 0;
1576  if (p != last) {
1577  last = p;
1578 
1579  if (DEBUG_DRAWING)
1580  qDebug() << "item(" << x << "," << y << "): Got "
1581  << p->path(0).join("/") << " (Size "
1582  << p->itemRect().width() << "x" << p->itemRect().height()
1583  << ", Val " << p->value() << ")";
1584  }
1585 
1586  return p;
1587  }
1588  p = i;
1589  }
1590  return 0;
1591 }
1592 
1593 TreeMapItem* TreeMapWidget::possibleSelection(TreeMapItem* i) const
1594 {
1595  if (i) {
1596  if (_maxSelectDepth>=0) {
1597  int depth = i->depth();
1598  while(i && depth > _maxSelectDepth) {
1599  i = i->parent();
1600  depth--;
1601  }
1602  }
1603  }
1604  return i;
1605 }
1606 
1607 TreeMapItem* TreeMapWidget::visibleItem(TreeMapItem* i) const
1608 {
1609  if (i) {
1610  /* Must have a visible area */
1611  while(i && ((i->itemRect().width() <1) ||
1612  (i->itemRect().height() <1))) {
1613  TreeMapItem* p = i->parent();
1614  if (!p) break;
1615  int idx = p->children()->indexOf(i);
1616  idx--;
1617  if (idx<0)
1618  i = p;
1619  else
1620  i = p->children()->at(idx);
1621  }
1622  }
1623  return i;
1624 }
1625 
1626 void TreeMapWidget::setSelected(TreeMapItem* item, bool selected)
1627 {
1628  if (!item) return;
1629  item = possibleSelection(item);
1630  setCurrent(item);
1631 
1632  TreeMapItem* changed = setTmpSelected(item, selected);
1633  if (!changed) return;
1634 
1635  _selection = _tmpSelection;
1636  if (_selectionMode == Single)
1637  emit selectionChanged(item);
1638  emit selectionChanged();
1639  redraw(changed);
1640 
1641  if (0) qDebug() << (selected ? "S":"Des") << "elected Item "
1642  << (item ? item->path(0).join("") : QString("(null)"))
1643  << " (depth " << (item ? item->depth() : -1)
1644  << ")";
1645 }
1646 
1647 void TreeMapWidget::setMarked(int markNo, bool redrawWidget)
1648 {
1649  // if there is no marking, return
1650  if ((_markNo == 0) && (markNo == 0)) return;
1651 
1652  _markNo = markNo;
1653  if (!clearSelection() && redrawWidget) redraw();
1654 }
1655 
1656 /* Returns all items which appear only in one of the given lists */
1657 TreeMapItemList TreeMapWidget::diff(TreeMapItemList& l1,
1658  TreeMapItemList& l2)
1659 {
1660  TreeMapItemList l;
1661 
1662  foreach(TreeMapItem* i, l1)
1663  if (!l2.contains(i))
1664  l.append(i);
1665 
1666  foreach(TreeMapItem* i, l2)
1667  if (!l1.contains(i))
1668  l.append(i);
1669 
1670  return l;
1671 }
1672 
1673 /* Only modifies _tmpSelection.
1674  * Returns 0 when no change happened, otherwise the TreeMapItem that has
1675  * to be redrawn for all changes.
1676  */
1677 TreeMapItem* TreeMapWidget::setTmpSelected(TreeMapItem* item, bool selected)
1678 {
1679  if (!item) return 0;
1680  if (_selectionMode == NoSelection) return 0;
1681 
1682  TreeMapItemList old = _tmpSelection;
1683 
1684  if (_selectionMode == Single) {
1685  _tmpSelection.clear();
1686  if (selected) _tmpSelection.append(item);
1687  }
1688  else {
1689  if (selected) {
1690  // first remove any selection which is parent or child of <item>
1691  foreach(TreeMapItem* i, _tmpSelection)
1692  if (i->isChildOf(item) || item->isChildOf(i))
1693  _tmpSelection.removeAll(i);
1694 
1695  _tmpSelection.append(item);
1696  }
1697  else
1698  _tmpSelection.removeAll(item);
1699  }
1700 
1701  return diff(old, _tmpSelection).commonParent();
1702 }
1703 
1704 
1705 bool TreeMapWidget::clearSelection(TreeMapItem* parent)
1706 {
1707  TreeMapItemList old = _selection;
1708 
1709  // remove any selection which is child of <parent>
1710  foreach(TreeMapItem* i, _selection)
1711  if (i->isChildOf(parent))
1712  _selection.removeAll(i);
1713 
1714  TreeMapItem* changed = diff(old, _selection).commonParent();
1715  if (changed) {
1716  changed->redraw();
1717  emit selectionChanged();
1718  }
1719  return (changed != 0);
1720 }
1721 
1722 bool TreeMapWidget::isSelected(TreeMapItem* i) const
1723 {
1724  if (!i) return false;
1725  return _selection.contains(i);
1726 }
1727 
1728 bool TreeMapWidget::isTmpSelected(TreeMapItem* i)
1729 {
1730  if (!i) return false;
1731  return _tmpSelection.contains(i);
1732 }
1733 
1734 
1735 void TreeMapWidget::setCurrent(TreeMapItem* i, bool kbd)
1736 {
1737  TreeMapItem* old = _current;
1738  _current = i;
1739 
1740  if (_markNo >0) {
1741  // remove mark
1742  _markNo = 0;
1743 
1744  if (i) qDebug() << "setCurrent(" << i->path(0).join("/")
1745  << ") - mark removed";
1746 
1747  // always complete redraw needed to remove mark
1748  redraw();
1749 
1750  if (old == _current) return;
1751  }
1752  else {
1753  if (old == _current) return;
1754 
1755  if (old) old->redraw();
1756  if (i) i->redraw();
1757  }
1758 
1759  //qDebug() << "Current Item " << (i ? qPrintable(i->path()) : "(null)");
1760 
1761  emit currentChanged(i, kbd);
1762 }
1763 
1764 void TreeMapWidget::setRangeSelection(TreeMapItem* i1,
1765  TreeMapItem* i2, bool selected)
1766 {
1767  i1 = possibleSelection(i1);
1768  i2 = possibleSelection(i2);
1769  setCurrent(i2);
1770 
1771  TreeMapItem* changed = setTmpRangeSelection(i1, i2, selected);
1772  if (!changed) return;
1773 
1774  _selection = _tmpSelection;
1775  if (_selectionMode == Single)
1776  emit selectionChanged(i2);
1777  emit selectionChanged();
1778  redraw(changed);
1779 }
1780 
1781 TreeMapItem* TreeMapWidget::setTmpRangeSelection(TreeMapItem* i1,
1782  TreeMapItem* i2,
1783  bool selected)
1784 {
1785  if ((i1 == 0) && (i2 == 0)) return 0;
1786  if ((i1 == 0) || i1->isChildOf(i2)) return setTmpSelected(i2, selected);
1787  if ((i2 == 0) || i2->isChildOf(i1)) return setTmpSelected(i1, selected);
1788 
1789  TreeMapItem* changed = setTmpSelected(i1, selected);
1790  TreeMapItem* changed2 = setTmpSelected(i2, selected);
1791  if (changed2) changed = changed2->commonParent(changed);
1792 
1793  TreeMapItem* commonParent = i1;
1794  while (commonParent && !i2->isChildOf(commonParent)) {
1795  i1 = commonParent;
1796  commonParent = commonParent->parent();
1797  }
1798  if (!commonParent) return changed;
1799  while (i2 && i2->parent() != commonParent)
1800  i2 = i2->parent();
1801  if (!i2) return changed;
1802 
1803  TreeMapItemList* list = commonParent->children();
1804  if (!list) return changed;
1805 
1806  bool between = false;
1807  foreach(TreeMapItem* i, *list) {
1808  if (between) {
1809  if (i==i1 || i==i2) break;
1810  changed2 = setTmpSelected(i, selected);
1811  if (changed2) changed = changed2->commonParent(changed);
1812  }
1813  else if (i==i1 || i==i2)
1814  between = true;
1815  }
1816 
1817  return changed;
1818 }
1819 
1820 void TreeMapWidget::contextMenuEvent( QContextMenuEvent* e )
1821 {
1822  //qDebug() << "TreeMapWidget::contextMenuEvent";
1823 
1824  if ( receivers( SIGNAL(contextMenuRequested(TreeMapItem*, const QPoint &)) ) )
1825  e->accept();
1826 
1827  if ( e->reason() == QContextMenuEvent::Keyboard ) {
1828  QRect r = (_current) ? _current->itemRect() : _base->itemRect();
1829  QPoint p = QPoint(r.left() + r.width()/2, r.top() + r.height()/2);
1830  emit contextMenuRequested(_current, p);
1831  }
1832  else {
1833  TreeMapItem* i = item(e->x(), e->y());
1834  emit contextMenuRequested(i, e->pos());
1835  }
1836 }
1837 
1838 
1839 void TreeMapWidget::mousePressEvent( QMouseEvent* e )
1840 {
1841  //qDebug() << "TreeMapWidget::mousePressEvent";
1842 
1843  _oldCurrent = _current;
1844 
1845  TreeMapItem* i = item(e->x(), e->y());
1846 
1847  _pressed = i;
1848 
1849  _inShiftDrag = e->modifiers() & Qt::ShiftModifier;
1850  _inControlDrag = e->modifiers() & Qt::ControlModifier;
1851  _lastOver = _pressed;
1852 
1853  TreeMapItem* changed = 0;
1854  TreeMapItem* item = possibleSelection(_pressed);
1855 
1856  switch(_selectionMode) {
1857  case Single:
1858  changed = setTmpSelected(item, true);
1859  break;
1860  case Multi:
1861  changed = setTmpSelected(item, !isTmpSelected(item));
1862  break;
1863  case Extended:
1864  if (_inControlDrag)
1865  changed = setTmpSelected(item, !isTmpSelected(item));
1866  else if (_inShiftDrag) {
1867  TreeMapItem* sCurrent = possibleSelection(_current);
1868  changed = setTmpRangeSelection(sCurrent, item,
1869  !isTmpSelected(item));
1870  }
1871  else {
1872  _selectionMode = Single;
1873  changed = setTmpSelected(item, true);
1874  _selectionMode = Extended;
1875  }
1876  break;
1877  default:
1878  break;
1879  }
1880 
1881  // item under mouse always selected on right button press
1882  if (e->button() == Qt::RightButton) {
1883  TreeMapItem* changed2 = setTmpSelected(item, true);
1884  if (changed2) changed = changed2->commonParent(changed);
1885  }
1886 
1887  setCurrent(_pressed);
1888 
1889  if (changed)
1890  redraw(changed);
1891 
1892  if (e->button() == Qt::RightButton) {
1893 
1894  // emit selection change
1895  if (! (_tmpSelection == _selection)) {
1896  _selection = _tmpSelection;
1897  if (_selectionMode == Single)
1898  emit selectionChanged(_lastOver);
1899  emit selectionChanged();
1900  }
1901  _pressed = 0;
1902  _lastOver = 0;
1903  emit rightButtonPressed(i, e->pos());
1904  }
1905 }
1906 
1907 void TreeMapWidget::mouseMoveEvent( QMouseEvent* e )
1908 {
1909  //qDebug() << "TreeMapWidget::mouseMoveEvent";
1910 
1911  if (!_pressed) return;
1912  TreeMapItem* over = item(e->x(), e->y());
1913  if (_lastOver == over) return;
1914 
1915  setCurrent(over);
1916  if (over == 0) {
1917  _lastOver = 0;
1918  return;
1919  }
1920 
1921  TreeMapItem* changed = 0;
1922  TreeMapItem* item = possibleSelection(over);
1923 
1924  switch(_selectionMode) {
1925  case Single:
1926  changed = setTmpSelected(item, true);
1927  break;
1928  case Multi:
1929  changed = setTmpSelected(item, !isTmpSelected(item));
1930  break;
1931  case Extended:
1932  if (_inControlDrag)
1933  changed = setTmpSelected(item, !isTmpSelected(item));
1934  else {
1935  TreeMapItem* sLast = possibleSelection(_lastOver);
1936  changed = setTmpRangeSelection(sLast, item, true);
1937  }
1938  break;
1939 
1940  default:
1941  break;
1942  }
1943 
1944  _lastOver = over;
1945 
1946  if (changed)
1947  redraw(changed);
1948 }
1949 
1950 void TreeMapWidget::mouseReleaseEvent( QMouseEvent* )
1951 {
1952  //qDebug() << "TreeMapWidget::mouseReleaseEvent";
1953 
1954  if (!_pressed) return;
1955 
1956  if (!_lastOver) {
1957  // take back
1958  setCurrent(_oldCurrent);
1959  TreeMapItem* changed = diff(_tmpSelection, _selection).commonParent();
1960  _tmpSelection = _selection;
1961  if (changed)
1962  redraw(changed);
1963  }
1964  else {
1965  if (! (_tmpSelection == _selection)) {
1966  _selection = _tmpSelection;
1967  if (_selectionMode == Single)
1968  emit selectionChanged(_lastOver);
1969  emit selectionChanged();
1970  }
1971  if (!_inControlDrag && !_inShiftDrag && (_pressed == _lastOver))
1972  emit clicked(_lastOver);
1973  }
1974 
1975  _pressed = 0;
1976  _lastOver = 0;
1977 }
1978 
1979 
1980 void TreeMapWidget::mouseDoubleClickEvent( QMouseEvent* e )
1981 {
1982  TreeMapItem* over = item(e->x(), e->y());
1983 
1984  emit doubleClicked(over);
1985 }
1986 
1987 
1988 /* returns -1 if nothing visible found */
1989 int nextVisible(TreeMapItem* i)
1990 {
1991  TreeMapItem* p = i->parent();
1992  if (!p || p->itemRect().isEmpty()) return -1;
1993 
1994  int idx = p->children()->indexOf(i);
1995  if (idx<0) return -1;
1996 
1997  while (idx < (int)p->children()->count()-1) {
1998  idx++;
1999  QRect r = p->children()->at(idx)->itemRect();
2000  if (r.width()>1 && r.height()>1)
2001  return idx;
2002  }
2003  return -1;
2004 }
2005 
2006 /* returns -1 if nothing visible found */
2007 int prevVisible(TreeMapItem* i)
2008 {
2009  TreeMapItem* p = i->parent();
2010  if (!p || p->itemRect().isEmpty()) return -1;
2011 
2012  int idx = p->children()->indexOf(i);
2013  if (idx<0) return -1;
2014 
2015  while (idx > 0) {
2016  idx--;
2017  QRect r = p->children()->at(idx)->itemRect();
2018  if (r.width()>1 && r.height()>1)
2019  return idx;
2020  }
2021  return -1;
2022 }
2023 
2024 
2025 
2026 
2027 void TreeMapWidget::keyPressEvent( QKeyEvent* e )
2028 {
2029  if (e->key() == Qt::Key_Escape && _pressed) {
2030 
2031  // take back
2032  if (_oldCurrent != _lastOver)
2033  setCurrent(_oldCurrent);
2034  if (! (_tmpSelection == _selection)) {
2035  TreeMapItem* changed = diff(_tmpSelection, _selection).commonParent();
2036  _tmpSelection = _selection;
2037  if (changed)
2038  redraw(changed);
2039  }
2040  _pressed = 0;
2041  _lastOver = 0;
2042  }
2043 
2044  if ((e->key() == Qt::Key_Space) ||
2045  (e->key() == Qt::Key_Return)) {
2046 
2047  switch(_selectionMode) {
2048  case NoSelection:
2049  break;
2050  case Single:
2051  setSelected(_current, true);
2052  break;
2053  case Multi:
2054  setSelected(_current, !isSelected(_current));
2055  break;
2056  case Extended:
2057  if ((e->modifiers() & Qt::ControlModifier) ||
2058  (e->modifiers() & Qt::ShiftModifier))
2059  setSelected(_current, !isSelected(_current));
2060  else {
2061  _selectionMode = Single;
2062  setSelected(_current, true);
2063  _selectionMode = Extended;
2064  }
2065  }
2066 
2067  if (_current && (e->key() == Qt::Key_Return))
2068  emit returnPressed(_current);
2069 
2070  return;
2071  }
2072 
2073  if (!_current) {
2074  if (e->key() == Qt::Key_Down) {
2075  setCurrent(_base, true);
2076  }
2077  return;
2078  }
2079 
2080  TreeMapItem* old = _current, *newItem;
2081  TreeMapItem* p = _current->parent();
2082 
2083  bool goBack;
2084  if (_current->sorting(&goBack) == -1) {
2085  // noSorting
2086  goBack = false;
2087  }
2088 
2089 
2090  if ((e->key() == Qt::Key_Backspace) ||
2091  (e->key() == Qt::Key_Up)) {
2092  newItem = visibleItem(p);
2093  setCurrent(newItem, true);
2094  }
2095  else if (e->key() == Qt::Key_Left) {
2096  int newIdx = goBack ? nextVisible(_current) : prevVisible(_current);
2097  if (p && newIdx>=0) {
2098  p->setIndex(newIdx);
2099  setCurrent(p->children()->at(newIdx), true);
2100  }
2101  }
2102  else if (e->key() == Qt::Key_Right) {
2103  int newIdx = goBack ? prevVisible(_current) : nextVisible(_current);
2104  if (p && newIdx>=0) {
2105  p->setIndex(newIdx);
2106  setCurrent(p->children()->at(newIdx), true);
2107  }
2108  }
2109  else if (e->key() == Qt::Key_Down) {
2110  if (_current->children() && _current->children()->count()>0) {
2111  int newIdx = _current->index();
2112  if (newIdx<0)
2113  newIdx = goBack ? (_current->children()->count()-1) : 0;
2114  if (newIdx>=(int)_current->children()->count())
2115  newIdx = _current->children()->count()-1;
2116  newItem = visibleItem(_current->children()->at(newIdx));
2117  setCurrent(newItem, true);
2118  }
2119  }
2120 
2121  if (old == _current) return;
2122  if (! (e->modifiers() & Qt::ControlModifier)) return;
2123  if (! (e->modifiers() & Qt::ShiftModifier)) return;
2124 
2125  switch(_selectionMode) {
2126  case NoSelection:
2127  break;
2128  case Single:
2129  setSelected(_current, true);
2130  break;
2131  case Multi:
2132  setSelected(_current, !isSelected(_current));
2133  break;
2134  case Extended:
2135  if (e->modifiers() & Qt::ControlModifier)
2136  setSelected(_current, !isSelected(_current));
2137  else
2138  setSelected(_current, isSelected(old));
2139  }
2140 }
2141 
2142 void TreeMapWidget::fontChange( const QFont& )
2143 {
2144  redraw();
2145 }
2146 
2147 // react on tooltip events
2148 bool TreeMapWidget::event(QEvent *event)
2149 {
2150  if (event->type() == QEvent::ToolTip) {
2151  QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
2152  TreeMapItem* i = item(helpEvent->pos().x(), helpEvent->pos().y());
2153  bool hasTip = false;
2154  if (i) {
2155  const QList<QRect>& rList = i->freeRects();
2156  foreach(const QRect& r, rList) {
2157  if (r.contains(helpEvent->pos())) {
2158  hasTip = true;
2159  break;
2160  }
2161  }
2162  }
2163  if (hasTip)
2164  QToolTip::showText(helpEvent->globalPos(), tipString(i));
2165  else
2166  QToolTip::hideText();
2167  }
2168  return QWidget::event(event);
2169 }
2170 
2171 void TreeMapWidget::paintEvent( QPaintEvent * )
2172 {
2173  drawTreeMap();
2174 }
2175 
2176 // Updates screen from shadow buffer,
2177 // but redraws before if needed
2178 void TreeMapWidget::drawTreeMap()
2179 {
2180  // no need to draw if hidden
2181  if (!isVisible()) return;
2182 
2183  if (_pixmap.size() != size())
2184  _needsRefresh = _base;
2185 
2186  if (_needsRefresh) {
2187 
2188  if (DEBUG_DRAWING)
2189  qDebug() << "Redrawing " << _needsRefresh->path(0).join("/");
2190 
2191  if (_needsRefresh == _base) {
2192  // redraw whole widget
2193  _pixmap = QPixmap(size());
2194  _pixmap.fill(palette().color(backgroundRole()));
2195  }
2196  QPainter p(&_pixmap);
2197  if (_needsRefresh == _base) {
2198  p.setPen(Qt::black);
2199  p.drawRect(QRect(2, 2, QWidget::width()-5, QWidget::height()-5));
2200  _base->setItemRect(QRect(3, 3, QWidget::width()-6, QWidget::height()-6));
2201  }
2202  else {
2203  // only subitem
2204  if (!_needsRefresh->itemRect().isValid()) return;
2205  }
2206 
2207  // reset cached font object; it could have been changed
2208  _font = font();
2209  _fontHeight = fontMetrics().height();
2210 
2211  drawItems(&p, _needsRefresh);
2212  _needsRefresh = 0;
2213  }
2214 
2215  QPainter p(this);
2216  p.drawPixmap(0, 0, _pixmap, 0, 0,
2217  QWidget::width(), QWidget::height());
2218 
2219  if (hasFocus()) {
2220  QStylePainter p(this);
2221  QStyleOptionFocusRect opt;
2222  opt.rect = rect();
2223  opt.palette = palette();
2224  opt.state = QStyle::State_None;
2225  p.drawPrimitive( QStyle::PE_FrameFocusRect, opt );
2226  }
2227 }
2228 
2229 
2230 
2231 void TreeMapWidget::redraw(TreeMapItem* i)
2232 {
2233  if (!i) return;
2234 
2235  if (!_needsRefresh)
2236  _needsRefresh = i;
2237  else {
2238  if (!i->isChildOf(_needsRefresh))
2239  _needsRefresh = _needsRefresh->commonParent(i);
2240  }
2241 
2242  if (isVisible()) {
2243  // delayed drawing if we have multiple redraw requests
2244  update();
2245  }
2246 }
2247 
2248 void TreeMapWidget::drawItem(QPainter* p,
2249  TreeMapItem* item)
2250 {
2251  bool isSelected = false;
2252 
2253  if (_markNo>0) {
2254  for(TreeMapItem* i = item; i; i=i->parent()) {
2255  if (i->isMarked(_markNo)) {
2256  isSelected = true;
2257  break;
2258  }
2259  }
2260  }
2261  else {
2262  foreach(TreeMapItem* i, _tmpSelection) {
2263  if (item->isChildOf(i)) {
2264  isSelected = true;
2265  break;
2266  }
2267  }
2268  }
2269 
2270  bool isCurrent = _current && item->isChildOf(_current);
2271  int dd = item->depth();
2272  if (isTransparent(dd)) return;
2273 
2274  RectDrawing d(item->itemRect());
2275  item->setSelected(isSelected);
2276  item->setCurrent(isCurrent);
2277  item->setShaded(_shading);
2278  item->drawFrame(drawFrame(dd));
2279  d.drawBack(p, item);
2280 }
2281 
2282 
2283 bool TreeMapWidget::horizontal(TreeMapItem* i, const QRect& r)
2284 {
2285  switch(i->splitMode()) {
2286  case TreeMapItem::HAlternate:
2287  return (i->depth()%2)==1;
2288  case TreeMapItem::VAlternate:
2289  return (i->depth()%2)==0;
2290  case TreeMapItem::Horizontal:
2291  return true;
2292  case TreeMapItem::Vertical:
2293  return false;
2294  default:
2295  return r.width() > r.height();
2296  }
2297  return false;
2298 }
2299 
2300 
2304 void TreeMapWidget::drawItems(QPainter* p,
2305  TreeMapItem* item)
2306 {
2307  if (DEBUG_DRAWING)
2308  qDebug() << "+drawItems(" << item->path(0).join("/") << ", "
2309  << item->itemRect().x() << "/" << item->itemRect().y()
2310  << "-" << item->itemRect().width() << "x"
2311  << item->itemRect().height() << "), Val " << item->value()
2312  << ", Sum " << item->sum();
2313 
2314  drawItem(p, item);
2315  item->clearFreeRects();
2316 
2317  QRect origRect = item->itemRect();
2318  int bw = item->borderWidth();
2319  QRect r = QRect(origRect.x()+bw, origRect.y()+bw,
2320  origRect.width()-2*bw, origRect.height()-2*bw);
2321 
2322  TreeMapItemList* list = item->children();
2323 
2324  bool stopDrawing = false;
2325 
2326  // only subdivide if there are children
2327  if (!list || list->count()==0)
2328  stopDrawing = true;
2329 
2330  // only subdivide if there is enough space
2331  if (!stopDrawing && (r.width()<=0 || r.height()<=0))
2332  stopDrawing = true;
2333 
2334  // stop drawing if maximum depth is reached
2335  if (!stopDrawing &&
2336  (_maxDrawingDepth>=0 && item->depth()>=_maxDrawingDepth))
2337  stopDrawing = true;
2338 
2339  // stop drawing if stopAtText is reached
2340  if (!stopDrawing)
2341  for (int no=0;no<(int)_attr.size();no++) {
2342  QString stopAt = fieldStop(no);
2343  if (!stopAt.isEmpty() && (item->text(no) == stopAt)) {
2344  stopDrawing = true;
2345  break;
2346  }
2347  }
2348 
2349  // area size is checked later...
2350 #if 0
2351  // stop drawing if minimal area size is reached
2352  if (!stopDrawing &&
2353  (_minimalArea > 0) &&
2354  (r.width() * r.height() < _minimalArea)) stopDrawing = true;
2355 #endif
2356 
2357  if (stopDrawing) {
2358  if (list) {
2359  // invalidate rects
2360  foreach(TreeMapItem* i, *list)
2361  i->clearItemRect();
2362  }
2363  // tooltip appears on whole item rect
2364  item->addFreeRect(item->itemRect());
2365 
2366  // if we have space for text...
2367  if ((r.height() < _fontHeight) || (r.width() < _fontHeight)) return;
2368 
2369  RectDrawing d(r);
2370  item->setRotated(_allowRotation && (r.height() > r.width()));
2371  for (int no=0;no<(int)_attr.size();no++) {
2372  if (!fieldVisible(no)) continue;
2373  d.drawField(p, no, item);
2374  }
2375  r = d.remainingRect(item);
2376 
2377  if (DEBUG_DRAWING)
2378  qDebug() << "-drawItems(" << item->path(0).join("/") << ")";
2379  return;
2380  }
2381 
2382  double user_sum, child_sum, self;
2383 
2384  // user supplied sum
2385  user_sum = item->sum();
2386 
2387  // own sum
2388  child_sum = 0;
2389  foreach(TreeMapItem* i, *list) {
2390  child_sum += i->value();
2391  if (DEBUG_DRAWING)
2392  qDebug() << " child: " << i->text(0) << ", value "
2393  << i->value();
2394  }
2395 
2396  QRect orig = r;
2397 
2398  // if we have space for text...
2399  if ((r.height() >= _fontHeight) && (r.width() >= _fontHeight)) {
2400 
2401  RectDrawing d(r);
2402  item->setRotated(_allowRotation && (r.height() > r.width()));
2403  for (int no=0;no<(int)_attr.size();no++) {
2404  if (!fieldVisible(no)) continue;
2405  if (!fieldForced(no)) continue;
2406  d.drawField(p, no, item);
2407  }
2408  r = d.remainingRect(item);
2409  }
2410 
2411  if (orig.x() == r.x()) {
2412  // Strings on top
2413  item->addFreeRect(QRect(orig.x(), orig.y(),
2414  orig.width(), orig.height()-r.height()));
2415  }
2416  else {
2417  // Strings on the left
2418  item->addFreeRect(QRect(orig.x(), orig.y(),
2419  orig.width()-r.width(), orig.height()));
2420  }
2421 
2422  if (user_sum == 0) {
2423  // user did not supply any sum
2424  user_sum = child_sum;
2425  self = 0;
2426  }
2427  else {
2428  self = user_sum - child_sum;
2429 
2430  if (user_sum < child_sum) {
2431  //qDebug() << "TreeMWidget " <<
2432  // item->path() << ": User sum " << user_sum << " < Child Items sum " << child_sum;
2433 
2434  // invalid user supplied sum: ignore and use calculate sum
2435  user_sum = child_sum;
2436  self = 0.0;
2437  }
2438  else {
2439  // Try to put the border waste in self
2440  // percent of wasted space on border...
2441  float borderArea = origRect.width() * origRect.height();
2442  borderArea = (borderArea - r.width()*r.height())/borderArea;
2443  unsigned borderValue = (unsigned)(borderArea * user_sum);
2444 
2445  if (borderValue > self) {
2446  if (_skipIncorrectBorder) {
2447  r = origRect;
2448  // should add my self to nested self and set my self =0
2449  }
2450  else
2451  self = 0.0;
2452  }
2453  else
2454  self -= borderValue;
2455 
2456  user_sum = child_sum + self;
2457  }
2458  }
2459 
2460  bool rotate = (_allowRotation && (r.height() > r.width()));
2461  int self_length = (int)( ((rotate) ? r.width() : r.height()) *
2462  self / user_sum + .5);
2463  if (self_length > 0) {
2464  // take space for self cost
2465  QRect sr = r;
2466  if (rotate) {
2467  sr.setWidth( self_length );
2468  r.setRect(r.x()+sr.width(), r.y(), r.width()-sr.width(), r.height());
2469  }
2470  else {
2471  sr.setHeight( self_length );
2472  r.setRect(r.x(), r.y()+sr.height(), r.width(), r.height()-sr.height());
2473  }
2474 
2475  // set selfRect (not occupied by children) for tooltip
2476  item->addFreeRect(sr);
2477 
2478  if (0) qDebug() << "Item " << item->path(0).join("/") << ": SelfR "
2479  << sr.x() << "/" << sr.y() << "-" << sr.width()
2480  << "/" << sr.height() << ", self " << self << "/"
2481  << user_sum;
2482 
2483  if ((sr.height() >= _fontHeight) && (sr.width() >= _fontHeight)) {
2484 
2485  RectDrawing d(sr);
2486  item->setRotated(_allowRotation && (r.height() > r.width()));
2487  for (int no=0;no<(int)_attr.size();no++) {
2488  if (!fieldVisible(no)) continue;
2489  if (fieldForced(no)) continue;
2490  d.drawField(p, no, item);
2491  }
2492  }
2493 
2494  user_sum -= self;
2495  }
2496 
2497  bool goBack;
2498  if (item->sorting(&goBack) == -1) {
2499  // noSorting
2500  goBack = false;
2501  }
2502 
2503  int idx = goBack ? (list->size()-1) : 0;
2504 
2505  if (item->splitMode() == TreeMapItem::Columns) {
2506  int len = list->count();
2507  bool drawDetails = true;
2508 
2509  while (len>0 && user_sum>0) {
2510  int firstIdx = idx;
2511  double valSum = 0;
2512  int lenLeft = len;
2513  int columns = (int)(sqrt((double)len * r.width()/r.height())+.5);
2514  if (columns==0) columns = 1; //should never be needed
2515 
2516  while (lenLeft>0 && ((double)valSum*(len-lenLeft) <
2517  (double)len*user_sum/columns/columns)) {
2518  valSum += list->at(idx)->value();
2519  if (goBack) --idx; else ++idx;
2520  lenLeft--;
2521  }
2522 
2523  // we always split horizontally
2524  int nextPos = (int)((double)r.width() * valSum / user_sum);
2525  QRect firstRect = QRect(r.x(), r.y(), nextPos, r.height());
2526 
2527  if (nextPos < _visibleWidth) {
2528  if (item->sorting(0) == -1) {
2529  // fill current rect with hash pattern
2530  drawFill(item, p, firstRect);
2531  }
2532  else {
2533  // fill rest with hash pattern
2534  drawFill(item, p, r, list, firstIdx, len, goBack);
2535  break;
2536  }
2537  }
2538  else {
2539  drawDetails = drawItemArray(p, item, firstRect,
2540  valSum, list, firstIdx, len-lenLeft, goBack);
2541  }
2542  r.setRect(r.x()+nextPos, r.y(), r.width()-nextPos, r.height());
2543  user_sum -= valSum;
2544  len = lenLeft;
2545 
2546  if (!drawDetails) {
2547  if (item->sorting(0) == -1)
2548  drawDetails = true;
2549  else {
2550  drawFill(item, p, r, list, idx, len, goBack);
2551  break;
2552  }
2553  }
2554  }
2555  }
2556  else if (item->splitMode() == TreeMapItem::Rows) {
2557  int len = list->count();
2558  bool drawDetails = true;
2559 
2560  while (len>0 && user_sum>0) {
2561  int firstIdx = idx;
2562  double valSum = 0;
2563  int lenLeft = len;
2564  int rows = (int)(sqrt((double)len * r.height()/r.width())+.5);
2565  if (rows==0) rows = 1; //should never be needed
2566 
2567  while (lenLeft>0 && ((double)valSum*(len-lenLeft) <
2568  (double)len*user_sum/rows/rows)) {
2569  valSum += list->at(idx)->value();
2570  if (goBack) --idx; else ++idx;
2571  lenLeft--;
2572  }
2573 
2574  // we always split horizontally
2575  int nextPos = (int)((double)r.height() * valSum / user_sum);
2576  QRect firstRect = QRect(r.x(), r.y(), r.width(), nextPos);
2577 
2578  if (nextPos < _visibleWidth) {
2579  if (item->sorting(0) == -1) {
2580  drawFill(item, p, firstRect);
2581  }
2582  else {
2583  drawFill(item, p, r, list, firstIdx, len, goBack);
2584  break;
2585  }
2586  }
2587  else {
2588  drawDetails = drawItemArray(p, item, firstRect,
2589  valSum, list, firstIdx, len-lenLeft, goBack);
2590  }
2591  r.setRect(r.x(), r.y()+nextPos, r.width(), r.height()-nextPos);
2592  user_sum -= valSum;
2593  len = lenLeft;
2594 
2595  if (!drawDetails) {
2596  if (item->sorting(0) == -1)
2597  drawDetails = true;
2598  else {
2599  drawFill(item, p, r, list, idx, len, goBack);
2600  break;
2601  }
2602  }
2603  }
2604  }
2605  else
2606  drawItemArray(p, item, r, user_sum, list, idx, list->count(), goBack);
2607 
2608  if (DEBUG_DRAWING)
2609  qDebug() << "-drawItems(" << item->path(0).join("/") << ")";
2610 }
2611 
2612 // fills area with a pattern if to small to draw children
2613 void TreeMapWidget::drawFill(TreeMapItem* i, QPainter* p, const QRect& r)
2614 {
2615  p->setBrush(Qt::Dense4Pattern);
2616  p->setPen(Qt::NoPen);
2617  p->drawRect(QRect(r.x(), r.y(), r.width()-1, r.height()-1));
2618  i->addFreeRect(r);
2619 }
2620 
2621 // fills area with a pattern if to small to draw children
2622 void TreeMapWidget::drawFill(TreeMapItem* i, QPainter* p, const QRect& r,
2623  TreeMapItemList* list, int idx, int len, bool goBack)
2624 {
2625  if (DEBUG_DRAWING)
2626  qDebug() << " +drawFill(" << r.x() << "/" << r.y()
2627  << "-" << r.width() << "x" << r.height()
2628  << ", len " << len << ")";
2629 
2630  p->setBrush(Qt::Dense4Pattern);
2631  p->setPen(Qt::NoPen);
2632  p->drawRect(QRect(r.x(), r.y(), r.width()-1, r.height()-1));
2633  i->addFreeRect(r);
2634 
2635  // reset rects
2636  while (len>0 && (i=list->value(idx))) {
2637 
2638  if (DEBUG_DRAWING)
2639  qDebug() << " Reset Rect " << i->path(0).join("/");
2640 
2641  i->clearItemRect();
2642  if (goBack) --idx; else ++idx;
2643  len--;
2644  }
2645  if (DEBUG_DRAWING)
2646  qDebug() << " -drawFill(" << r.x() << "/" << r.y()
2647  << "-" << r.width() << "x" << r.height()
2648  << ", len " << len << ")";
2649 }
2650 
2651 // returns false if rect gets to small
2652 bool TreeMapWidget::drawItemArray(QPainter* p, TreeMapItem* item,
2653  const QRect& r, double user_sum,
2654  TreeMapItemList* list, int idx, int len,
2655  bool goBack)
2656 {
2657  if (user_sum == 0) return false;
2658 
2659  static bool b2t = true;
2660 
2661  // stop recursive bisection for small rectangles
2662  if (((r.height() < _visibleWidth) &&
2663  (r.width() < _visibleWidth)) ||
2664  ((_minimalArea > 0) &&
2665  (r.width() * r.height() < _minimalArea))) {
2666 
2667  drawFill(item, p, r, list, idx, len, goBack);
2668  return false;
2669  }
2670 
2671  if (DEBUG_DRAWING)
2672  qDebug() << " +drawItemArray(" << item->path(0).join("/")
2673  << ", " << r.x() << "/" << r.y() << "-" << r.width()
2674  << "x" << r.height() << ")";
2675 
2676  if (len>2 && (item->splitMode() == TreeMapItem::Bisection)) {
2677 
2678  int firstIdx = idx;
2679  double valSum = 0;
2680  int lenLeft = len;
2681  //while (lenLeft>0 && valSum<user_sum/2) {
2682  while (lenLeft>len/2) {
2683  valSum += list->at(idx)->value();
2684  if (goBack) --idx; else ++idx;
2685  lenLeft--;
2686  }
2687 
2688  // draw first half...
2689  bool drawOn;
2690  QRect secondRect;
2691 
2692  if (r.width() > r.height()) {
2693  int halfPos = (int)((double)r.width() * valSum / user_sum);
2694  QRect firstRect = QRect(r.x(), r.y(), halfPos, r.height());
2695  drawOn = drawItemArray(p, item, firstRect,
2696  valSum, list, firstIdx, len-lenLeft, goBack);
2697  secondRect.setRect(r.x()+halfPos, r.y(), r.width()-halfPos, r.height());
2698  }
2699  else {
2700  int halfPos = (int)((double)r.height() * valSum / user_sum);
2701  QRect firstRect = QRect(r.x(), r.y(), r.width(), halfPos);
2702  drawOn = drawItemArray(p, item, firstRect,
2703  valSum, list, firstIdx, len-lenLeft, goBack);
2704  secondRect.setRect(r.x(), r.y()+halfPos, r.width(), r.height()-halfPos);
2705  }
2706 
2707  // if no sorting, do not stop drawing
2708  if (item->sorting(0) == -1) drawOn = true;
2709 
2710  // second half
2711  if (drawOn)
2712  drawOn = drawItemArray(p, item, secondRect, user_sum - valSum,
2713  list, idx, lenLeft, goBack);
2714  else {
2715  drawFill(item, p, secondRect, list, idx, len, goBack);
2716  }
2717 
2718  if (DEBUG_DRAWING)
2719  qDebug() << " -drawItemArray(" << item->path(0).join("/")
2720  << ")";
2721 
2722  return drawOn;
2723  }
2724 
2725  bool hor = horizontal(item,r);
2726 
2727  TreeMapItem* i;
2728  QRect fullRect = r;
2729  while (len>0) {
2730  i = list->at(idx);
2731  if (user_sum <= 0) {
2732 
2733  if (DEBUG_DRAWING)
2734  qDebug() << "drawItemArray: Reset " << i->path(0).join("/");
2735 
2736  i->clearItemRect();
2737  if (goBack) --idx; else ++idx;
2738  len--;
2739  continue;
2740  }
2741 
2742  // stop drawing for small rectangles
2743  if (((fullRect.height() < _visibleWidth) &&
2744  (fullRect.width() < _visibleWidth)) ||
2745  ((_minimalArea > 0) &&
2746  (fullRect.width() * fullRect.height() < _minimalArea))) {
2747 
2748  drawFill(item, p, fullRect, list, idx, len, goBack);
2749  if (DEBUG_DRAWING)
2750  qDebug() << " -drawItemArray(" << item->path(0).join("/")
2751  << "): Stop";
2752  return false;
2753  }
2754 
2755  if (i->splitMode() == TreeMapItem::AlwaysBest)
2756  hor = fullRect.width() > fullRect.height();
2757 
2758  int lastPos = hor ? fullRect.width() : fullRect.height();
2759  double val = i->value();
2760  int nextPos = (user_sum <= 0.0) ? 0: (int)(lastPos * val / user_sum +.5);
2761  if (nextPos>lastPos) nextPos = lastPos;
2762 
2763  if ((item->sorting(0) != -1) && (nextPos < _visibleWidth)) {
2764  drawFill(item, p, fullRect, list, idx, len, goBack);
2765  if (DEBUG_DRAWING)
2766  qDebug() << " -drawItemArray(" << item->path(0).join("/")
2767  << "): Stop";
2768  return false;
2769  }
2770 
2771  QRect currRect = fullRect;
2772 
2773  if (hor)
2774  currRect.setWidth(nextPos);
2775  else {
2776  if (b2t)
2777  currRect.setRect(fullRect.x(), fullRect.bottom()-nextPos+1, fullRect.width(), nextPos);
2778  else
2779  currRect.setHeight(nextPos);
2780  }
2781 
2782  // do not draw very small rectangles:
2783  if (nextPos >= _visibleWidth) {
2784  i->setItemRect(currRect);
2785  drawItems(p, i);
2786  }
2787  else {
2788  i->clearItemRect();
2789  drawFill(item, p, currRect);
2790  }
2791 
2792  // draw Separator
2793  if (_drawSeparators && (nextPos<lastPos)) {
2794  p->setPen(Qt::black);
2795  if (hor) {
2796  if (fullRect.top() <= fullRect.bottom())
2797  p->drawLine(fullRect.x() + nextPos, fullRect.top(), fullRect.x() + nextPos, fullRect.bottom());
2798  }
2799  else {
2800  if (fullRect.left() <= fullRect.right())
2801  p->drawLine(fullRect.left(), fullRect.y() + nextPos, fullRect.right(), fullRect.y() + nextPos);
2802  }
2803  nextPos++;
2804  }
2805 
2806  if (hor)
2807  fullRect.setRect(fullRect.x() + nextPos, fullRect.y(),
2808  lastPos - nextPos, fullRect.height());
2809  else {
2810  if (b2t)
2811  fullRect.setRect(fullRect.x(), fullRect.y(),
2812  fullRect.width(), lastPos-nextPos);
2813  else
2814  fullRect.setRect(fullRect.x(), fullRect.y() + nextPos,
2815  fullRect.width(), lastPos-nextPos);
2816  }
2817 
2818  user_sum -= val;
2819  if (goBack) --idx; else ++idx;
2820  len--;
2821  }
2822 
2823  if (DEBUG_DRAWING)
2824  qDebug() << " -drawItemArray(" << item->path(0).join("/")
2825  << "): Continue";
2826 
2827  return true;
2828 }
2829 
2830 
2831 /*----------------------------------------------------------------
2832  * Popup menus for option setting
2833  */
2834 
2835 void TreeMapWidget::splitActivated(QAction* a)
2836 {
2837  setSplitMode( (TreeMapItem::SplitMode) a->data().toInt());
2838 }
2839 
2840 void TreeMapWidget::addSplitAction(QMenu* m, const QString& s, int v)
2841 {
2842  QAction* a = m->addAction(s);
2843  a->setData(v);
2844  a->setCheckable(true);
2845  a->setChecked(splitMode() == v);
2846 }
2847 
2848 void TreeMapWidget::addSplitDirectionItems(QMenu* m)
2849 {
2850  connect(m, SIGNAL(triggered(QAction*)),
2851  this, SLOT(splitActivated(QAction*)) );
2852 
2853  addSplitAction(m, tr("Recursive Bisection"), TreeMapItem::Bisection);
2854  addSplitAction(m, tr("Columns"), TreeMapItem::Columns);
2855  addSplitAction(m, tr("Rows"), TreeMapItem::Rows);
2856  addSplitAction(m, tr("Always Best"), TreeMapItem::AlwaysBest);
2857  addSplitAction(m, tr("Best"), TreeMapItem::Best);
2858  addSplitAction(m, tr("Alternate (V)"), TreeMapItem::VAlternate);
2859  addSplitAction(m, tr("Alternate (H)"), TreeMapItem::HAlternate);
2860  addSplitAction(m, tr("Horizontal"), TreeMapItem::Horizontal);
2861  addSplitAction(m, tr("Vertical"), TreeMapItem::Vertical);
2862 }
2863 
2864 
2865 #include "treemap.moc"
QStylePainter
TreeMapWidget::base
TreeMapItem * base() const
Returns the TreeMapItem filling out the widget space.
Definition: treemap.h:410
StoredDrawParams::setSelected
void setSelected(bool b)
Definition: treemap.h:126
TreeMapItem::initialized
bool initialized()
Definition: treemap.cpp:973
TreeMapItem::addFreeRect
void addFreeRect(const QRect &r)
Definition: treemap.cpp:1108
TreeMapItem::clear
void clear()
Definition: treemap.cpp:927
QList::clear
void clear()
TreeMapItem::borderWidth
virtual int borderWidth() const
Definition: treemap.cpp:1031
QRect::setBottom
void setBottom(int y)
StoredDrawParams::setCurrent
void setCurrent(bool b)
Definition: treemap.h:127
QEvent
RectDrawing::drawField
bool drawField(QPainter *, int f, DrawParams *dp=0)
Definition: treemap.cpp:468
QPixmap::size
QSize size() const
TreeMapWidget::setFieldStop
void setFieldStop(int, const QString &)
Stop drawing at item with name.
Definition: treemap.cpp:1388
QWidget
TreeMapWidget::splitMode
TreeMapItem::SplitMode splitMode() const
Definition: treemap.cpp:1217
QKeyEvent::modifiers
Qt::KeyboardModifiers modifiers() const
StoredDrawParams::_shaded
bool _shaded
Definition: treemap.h:136
QEvent::type
Type type() const
TreeMapItem::sum
virtual double sum() const
Definition: treemap.cpp:1004
TreeMapWidget::setFieldPosition
void setFieldPosition(int, DrawParams::Position)
Set the field position in the area.
Definition: treemap.cpp:1442
QWidget::palette
const QPalette & palette() const
RectDrawing::~RectDrawing
~RectDrawing()
Definition: treemap.cpp:193
TreeMapWidget::item
TreeMapItem * item(int x, int y) const
Returns the area item at position x/y, independent from any maxSelectDepth setting.
Definition: treemap.cpp:1541
TreeMapWidget::setSplitMode
void setSplitMode(TreeMapItem::SplitMode m)
for setting/getting global split direction
Definition: treemap.cpp:1209
TreeMapItem::Horizontal
Definition: treemap.h:238
QPixmap::width
int width() const
TreeMapItem::_sum
double _sum
Definition: treemap.h:366
QPainter::fillRect
void fillRect(const QRectF &rectangle, const QBrush &brush)
TreeMapWidget::tipString
virtual QString tipString(TreeMapItem *i) const
Return tooltip string to show for a item (can be rich text) Default implementation gives lines with "...
Definition: treemap.cpp:1521
StoredDrawParams::pixmap
QPixmap pixmap(int) const
Definition: treemap.cpp:87
QColor::light
QColor light(int factor) const
QPixmap::fill
void fill(const QColor &color)
QRect::right
int right() const
TreeMapWidget::addSplitDirectionItems
void addSplitDirectionItems(QMenu *)
Populate given menu with option items.
Definition: treemap.cpp:2848
RectDrawing::drawBack
void drawBack(QPainter *, DrawParams *dp=0)
Definition: treemap.cpp:253
DrawParams::position
virtual Position position(int) const =0
QWidget::setFocusPolicy
void setFocusPolicy(Qt::FocusPolicy policy)
TreeMapWidget::setShadingEnabled
void setShadingEnabled(bool s)
Definition: treemap.cpp:1257
QAction::setChecked
void setChecked(bool)
QAction::data
QVariant data() const
TreeMapItem::redraw
void redraw()
Definition: treemap.cpp:921
QFont
StoredDrawParams::_rotated
bool _rotated
Definition: treemap.h:137
QMouseEvent::x
int x() const
QMouseEvent::y
int y() const
TreeMapWidget::setSelected
void setSelected(TreeMapItem *, bool selected=true)
Selects or unselects an item.
Definition: treemap.cpp:1626
QList< TreeMapItem * >::at
const T & at(int i) const
QMenu::addAction
void addAction(QAction *action)
TreeMapItem::clearItemRect
void clearItemRect()
Definition: treemap.cpp:1097
QWidget::visible
visible
QPainter::save
void save()
QHelpEvent::pos
const QPoint & pos() const
TreeMapItem::rtti
virtual int rtti() const
Definition: treemap.cpp:1084
DrawParams::font
virtual const QFont & font() const =0
QWidget::setAttribute
void setAttribute(Qt::WidgetAttribute attribute, bool on)
DrawParams
Drawing parameters for an object.
Definition: treemap.h:53
TreeMapWidget::TreeMapWidget
TreeMapWidget(TreeMapItem *base, QWidget *parent=0)
Definition: treemap.cpp:1153
QRect::height
int height() const
TreeMapItem::TreeMapItem
TreeMapItem(TreeMapItem *parent=0, double value=1.0)
Definition: treemap.cpp:836
TreeMapWidget::~TreeMapWidget
~TreeMapWidget()
Definition: treemap.cpp:1199
StoredDrawParams::setPixmap
void setPixmap(int f, const QPixmap &)
Definition: treemap.cpp:155
QRect::x
int x() const
QRect::y
int y() const
TreeMapWidget::setMinimalArea
void setMinimalArea(int area)
Minimal area for rectangles to draw.
Definition: treemap.cpp:1492
TreeMapItem::SplitMode
SplitMode
Split direction for nested areas: AlwaysBest: Choose split direction for every subitem according to l...
Definition: treemap.h:235
QWidget::hasFocus
bool hasFocus() const
TreeMapItem::Columns
Definition: treemap.h:235
QPoint
QFontMetrics
QMouseEvent
QStringList::join
QString join(const QString &separator) const
TreeMapWidget::visibleItem
TreeMapItem * visibleItem(TreeMapItem *) const
Returns the nearest item with a visible area; this can be the given item itself.
Definition: treemap.cpp:1607
QPainter::rotate
void rotate(qreal angle)
TreeMapWidget::NoSelection
Definition: treemap.h:401
TreeMapWidget::fieldPosition
DrawParams::Position fieldPosition(int) const
Definition: treemap.cpp:1453
TreeMapItem::itemRect
const QRect & itemRect() const
Definition: treemap.h:293
QPainter::drawLine
void drawLine(const QLineF &line)
TreeMapWidget::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *)
Definition: treemap.cpp:1950
StoredDrawParams::setShaded
void setShaded(bool b)
Definition: treemap.h:128
QColor::setRgb
void setRgb(int r, int g, int b, int a)
TreeMapWidget::setFieldVisible
void setFieldVisible(int, bool)
Should the text with number textNo be visible? This is only done if remaining space is enough to allo...
Definition: treemap.cpp:1404
TreeMapWidget::setBorderWidth
void setBorderWidth(int w)
Definition: treemap.cpp:1306
TreeMapItem::setParent
void setParent(TreeMapItem *p)
Definition: treemap.cpp:895
TreeMapWidget::Multi
Definition: treemap.h:401
QToolTip::showText
void showText(const QPoint &pos, const QString &text, QWidget *w)
TreeMapWidget::mouseDoubleClickEvent
void mouseDoubleClickEvent(QMouseEvent *)
Definition: treemap.cpp:1980
QObject::tr
QString tr(const char *sourceText, const char *disambiguation, int n)
StoredDrawParams::setMaxLines
void setMaxLines(int f, int)
Definition: treemap.cpp:171
TreeMapItem::setItemRect
void setItemRect(const QRect &r)
Temporary rectangle used for drawing this item the last time.
Definition: treemap.h:291
DrawParams::BottomCenter
Definition: treemap.h:68
QWidget::update
void update()
QStylePainter::drawPrimitive
void drawPrimitive(QStyle::PrimitiveElement pe, const QStyleOption &option)
QPoint::x
int x() const
QPoint::y
int y() const
TreeMapWidget::fieldForced
bool fieldForced(int) const
Definition: treemap.cpp:1434
StoredDrawParams::font
const QFont & font() const
Definition: treemap.cpp:111
QColor::dark
QColor dark(int factor) const
QList< TreeMapItem * >::size
int size() const
DrawParams::TopLeft
Definition: treemap.h:67
TreeMapWidget::isSelected
bool isSelected(TreeMapItem *i) const
Definition: treemap.cpp:1722
TreeMapItem::sorting
virtual int sorting(bool *ascending) const
Returns the text number after that sorting is done or -1 for no sorting, -2 for value() sorting (defa...
Definition: treemap.cpp:1039
TreeMapItem::value
virtual double value() const
Definition: treemap.cpp:999
QList::value
T value(int i) const
TreeMapWidget::defaultFieldType
QString defaultFieldType(int) const
Definition: treemap.cpp:1322
TreeMapWidget::fieldStop
QString fieldStop(int) const
Definition: treemap.cpp:1398
QList::indexOf
int indexOf(const T &value, int from) const
TreeMapWidget::setTransparent
void setTransparent(int d, bool b)
Definition: treemap.cpp:1273
TreeMapWidget::returnPressed
void returnPressed(TreeMapItem *)
QWidget::width
int width() const
TreeMapWidget::mouseMoveEvent
void mouseMoveEvent(QMouseEvent *)
Definition: treemap.cpp:1907
RectDrawing::setRect
void setRect(const QRect &)
Definition: treemap.cpp:214
MAX_FIELD
#define MAX_FIELD
Definition: treemap.cpp:46
TreeMapItem::~TreeMapItem
virtual ~TreeMapItem()
Definition: treemap.cpp:883
QWidget::size
QSize size() const
StoredDrawParams::selected
bool selected() const
Definition: treemap.h:110
StoredDrawParams::_drawFrame
bool _drawFrame
Definition: treemap.h:138
QPainter::drawRect
void drawRect(const QRectF &rectangle)
QObject::name
const char * name() const
QRect
TreeMapWidget::mousePressEvent
void mousePressEvent(QMouseEvent *)
Definition: treemap.cpp:1839
TreeMapItem::parent
TreeMapItem * parent() const
Parent Item.
Definition: treemap.h:285
QPainter::setFont
void setFont(const QFont &font)
DrawParams::selected
virtual bool selected() const
Definition: treemap.h:84
TreeMapWidget::redraw
void redraw()
Definition: treemap.h:630
QApplication::font
QFont font()
QContextMenuEvent::x
int x() const
QContextMenuEvent::y
int y() const
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
TreeMapWidget::paintEvent
void paintEvent(QPaintEvent *)
Definition: treemap.cpp:2171
QVector::resize
void resize(int size)
TreeMapWidget::setAllowRotation
void setAllowRotation(bool)
Do we allow the texts to be rotated by 90 degrees for better fitting?
Definition: treemap.cpp:1281
TreeMapItem::_value
double _value
Definition: treemap.h:366
StoredDrawParams::position
Position position(int) const
Definition: treemap.cpp:95
QVariant::toInt
int toInt(bool *ok) const
TreeMapWidget::clicked
void clicked(TreeMapItem *)
QRect::top
int top() const
QColor::rgb
QRgb rgb() const
TreeMapItem::refresh
void refresh()
Definition: treemap.cpp:942
QContextMenuEvent
StoredDrawParams
Definition: treemap.h:95
TreeMapWidget::fieldVisible
bool fieldVisible(int) const
Definition: treemap.cpp:1415
QPainter::setPen
void setPen(const QColor &color)
QHelpEvent::globalPos
const QPoint & globalPos() const
QRect::setTop
void setTop(int y)
TreeMapWidget::defaultFieldStop
QString defaultFieldStop(int) const
Definition: treemap.cpp:1327
TreeMapWidget::currentChanged
void currentChanged(TreeMapItem *, bool keyboard)
This signal is emitted if the current item changes.
DrawParams::current
virtual bool current() const
Definition: treemap.h:85
QRect::left
int left() const
QMouseEvent::button
Qt::MouseButton button() const
TreeMapWidget::defaultFieldForced
bool defaultFieldForced(int) const
Definition: treemap.cpp:1337
TreeMapItem::AlwaysBest
Definition: treemap.h:236
QWidget::backgroundRole
QPalette::ColorRole backgroundRole() const
QPainter::drawPixmap
void drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
QList< TreeMapItem * >::isEmpty
bool isEmpty() const
TreeMapWidget::selectionChanged
void selectionChanged()
QPainter
QRect::setWidth
void setWidth(int width)
QString::isEmpty
bool isEmpty() const
QList::removeAll
int removeAll(const T &value)
TreeMapItem::isChildOf
bool isChildOf(TreeMapItem *)
Definition: treemap.cpp:901
TreeMapWidget::possibleSelection
TreeMapItem * possibleSelection(TreeMapItem *) const
Returns the item possible for selection.
Definition: treemap.cpp:1593
QFontMetrics::elidedText
QString elidedText(const QString &text, Qt::TextElideMode mode, int width, int flags) const
DrawParams::TopRight
Definition: treemap.h:67
StoredDrawParams::setField
void setField(int f, const QString &t, const QPixmap &pm=QPixmap(), Position p=Default, int maxLines=0)
Definition: treemap.cpp:135
treeMapItemLessThan
TreeMapItemLessThan treeMapItemLessThan
Definition: treemap.cpp:832
StoredDrawParams::text
QString text(int) const
Definition: treemap.cpp:79
DrawParams::Default
Definition: treemap.h:69
QWidget::pos
QPoint pos() const
QPainter::setBrush
void setBrush(const QBrush &brush)
QPainter::drawText
void drawText(const QPointF &position, const QString &text)
TreeMapWidget::setVisibleWidth
void setVisibleWidth(int width, bool reuseSpace=false)
Items usually have a size proportional to their value().
Definition: treemap.cpp:1289
RectDrawing::setDrawParams
void setDrawParams(DrawParams *)
Definition: treemap.cpp:208
TreeMapWidget::drawTreeMap
void drawTreeMap()
Definition: treemap.cpp:2178
TreeMapItem::Rows
Definition: treemap.h:235
TreeMapWidget::setCurrent
void setCurrent(TreeMapItem *, bool kbd=false)
Sets the current item.
Definition: treemap.cpp:1735
QRect::contains
bool contains(const QPoint &point, bool proper) const
QList< TreeMapItem * >::first
T & first()
DrawParams::shaded
virtual bool shaded() const
Definition: treemap.h:86
QString
QList< QRect >
StoredDrawParams::_backColor
QColor _backColor
Definition: treemap.h:133
StoredDrawParams::_current
bool _current
Definition: treemap.h:135
TreeMapWidget::setFieldType
void setFieldType(int, const QString &)
Set the type name of a field.
Definition: treemap.cpp:1373
QColor
TreeMapWidget::Single
Definition: treemap.h:401
RectDrawing::drawParams
DrawParams * drawParams()
Definition: treemap.cpp:199
TreeMapWidget::contextMenuEvent
void contextMenuEvent(QContextMenuEvent *)
Definition: treemap.cpp:1820
DrawParams::text
virtual QString text(int) const =0
TreeMapItem::Vertical
Definition: treemap.h:238
TreeMapWidget::borderWidth
int borderWidth() const
Definition: treemap.h:604
nextVisible
int nextVisible(TreeMapItem *i)
Definition: treemap.cpp:1989
TreeMapItem::isMarked
virtual bool isMarked(int) const
Definition: treemap.cpp:1025
QStringList
QWidget::rect
QRect rect() const
TreeMapWidget::clearSelection
bool clearSelection(TreeMapItem *parent=0)
Clear selection of all selected items which are children of parent.
Definition: treemap.cpp:1705
QPixmap
TreeMapItem::Bisection
Definition: treemap.h:235
TreeMapWidget::event
bool event(QEvent *event)
Definition: treemap.cpp:2148
QInputEvent::modifiers
Qt::KeyboardModifiers modifiers() const
TreeMapWidget::redraw
void redraw(TreeMapItem *)
Redraws an item with all children.
Definition: treemap.cpp:2231
QAction::setData
void setData(const QVariant &userData)
TreeMapItem::font
virtual const QFont & font() const
Definition: treemap.cpp:1019
QStyleOptionFocusRect
findBreak
static int findBreak(int &breakPos, QString text, QFontMetrics *fm, int maxWidth)
Definition: treemap.cpp:355
QList::end
iterator end()
QKeyEvent::key
int key() const
QMenu
QEvent::accept
void accept()
TreeMapItem::children
virtual TreeMapItemList * children()
Definition: treemap.cpp:1089
TreeMapItem::setWidget
void setWidget(TreeMapWidget *w)
Definition: treemap.h:318
QPixmap::height
int height() const
QWidget::font
const QFont & font() const
QRect::isEmpty
bool isEmpty() const
StoredDrawParams::setRotated
void setRotated(bool b)
Definition: treemap.h:129
findBreakBackwards
static int findBreakBackwards(int &breakPos, QString text, QFontMetrics *fm, int maxWidth)
Definition: treemap.cpp:415
QFontMetrics::width
int width(const QString &text, int len) const
QList::contains
bool contains(const T &value) const
QToolTip::hideText
void hideText()
QRect::isValid
bool isValid() const
QAction::setCheckable
void setCheckable(bool)
DrawParams::Position
Position
Positions for drawing into a rectangle.
Definition: treemap.h:67
TreeMapItemList::commonParent
TreeMapItem * commonParent()
Definition: treemap.cpp:800
QPainter::restore
void restore()
prevVisible
int prevVisible(TreeMapItem *i)
Definition: treemap.cpp:2007
TreeMapItem::Best
Definition: treemap.h:236
TreeMapWidget::setSkipIncorrectBorder
void setSkipIncorrectBorder(bool enable=true)
If a children value() is almost the parents sum(), it can happen that the border to be drawn for visi...
Definition: treemap.cpp:1298
QKeyEvent
QRect::setRight
void setRight(int x)
TreeMapWidget::setRangeSelection
void setRangeSelection(TreeMapItem *i1, TreeMapItem *i2, bool selected)
Selects or unselects items in a range.
Definition: treemap.cpp:1764
TreeMapWidget::Extended
Definition: treemap.h:401
TreeMapItem::resort
void resort(bool recursive=true)
Resort according to the already set sorting.
Definition: treemap.cpp:1063
QContextMenuEvent::pos
const QPoint & pos() const
QRect::width
int width() const
TreeMapItem::index
int index() const
Temporary child item index of the child that was current() recently.
Definition: treemap.h:308
QString::mid
QString mid(int position, int n) const
QWidget::fontMetrics
QFontMetrics fontMetrics() const
TreeMapWidget::isTransparent
bool isTransparent(int d) const
Definition: treemap.h:513
TreeMapItem::depth
int depth() const
Depth of this item.
Definition: treemap.cpp:963
TreeMapItem::_children
TreeMapItemList * _children
Definition: treemap.h:365
StoredDrawParams::StoredDrawParams
StoredDrawParams()
Definition: treemap.cpp:52
TreeMapItem::clearFreeRects
void clearFreeRects()
Temporary rectangle list of free space of this item.
Definition: treemap.cpp:1103
QRect::setRect
void setRect(int x, int y, int width, int height)
StoredDrawParams::maxLines
int maxLines(int) const
Definition: treemap.cpp:103
TreeMapItem::setIndex
void setIndex(int i)
Definition: treemap.h:309
QRect::setHeight
void setHeight(int height)
QAction
TreeMapWidget::setMarked
void setMarked(int markNo=1, bool redraw=true)
Switches on the marking .
Definition: treemap.cpp:1647
QList::last
T & last()
treemap.h
DrawParams::BottomLeft
Definition: treemap.h:68
TreeMapWidget::doubleClicked
void doubleClicked(TreeMapItem *)
QColor::getRgb
void getRgb(int *r, int *g, int *b, int *a) const
TreeMapWidget::splitModeString
QString splitModeString() const
Definition: treemap.cpp:1238
DrawParams::TopCenter
Definition: treemap.h:67
QFontMetrics::height
int height() const
QRect::bottom
int bottom() const
DrawParams::drawFrame
virtual bool drawFrame() const
Definition: treemap.h:88
TreeMapItem::path
QStringList path(int) const
Returns a list of text strings of specified text number, from root up to this item.
Definition: treemap.cpp:949
RectDrawing
Definition: treemap.h:164
QString::length
int length() const
TreeMapItem::setSorting
void setSorting(int textNo, bool ascending=true)
Set the sorting for child drawing.
Definition: treemap.cpp:1046
StoredDrawParams::setText
void setText(int f, const QString &)
Definition: treemap.cpp:147
QPainter::translate
void translate(const QPointF &offset)
TreeMapItem::commonParent
TreeMapItem * commonParent(TreeMapItem *item)
Definition: treemap.cpp:913
QString::left
QString left(int n) const
TreeMapWidget::rightButtonPressed
void rightButtonPressed(TreeMapItem *, const QPoint &)
RectDrawing::remainingRect
QRect remainingRect(DrawParams *dp=0)
Definition: treemap.cpp:228
TreeMapWidget::currentFont
const QFont & currentFont() const
Returns a reference to the current widget font.
Definition: treemap.cpp:1204
TreeMapWidget::defaultFieldPosition
DrawParams::Position defaultFieldPosition(int) const
Definition: treemap.cpp:1342
TreeMapWidget::keyPressEvent
void keyPressEvent(QKeyEvent *)
Definition: treemap.cpp:2027
QList::prepend
void prepend(const T &value)
StoredDrawParams::setPosition
void setPosition(int f, Position)
Definition: treemap.cpp:163
TreeMapWidget::fieldPositionString
QString fieldPositionString(int) const
Definition: treemap.cpp:1479
TreeMapWidget::defaultFieldVisible
bool defaultFieldVisible(int) const
Definition: treemap.cpp:1332
TreeMapItem::VAlternate
Definition: treemap.h:237
QMouseEvent::pos
const QPoint & pos() const
QPaintEvent
TreeMapWidget::fontChange
void fontChange(const QFont &)
Definition: treemap.cpp:2142
TreeMapWidget::drawFrame
void drawFrame(int d, bool b)
Definition: treemap.cpp:1265
DrawParams::rotated
virtual bool rotated() const
Definition: treemap.h:87
DEBUG_DRAWING
#define DEBUG_DRAWING
Definition: treemap.cpp:45
QContextMenuEvent::reason
Reason reason() const
StoredDrawParams::drawFrame
bool drawFrame() const
Definition: treemap.h:114
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject::parent
QObject * parent() const
QVector::size
int size() const
QHelpEvent
QPaintDevice::depth
int depth() const
RectDrawing::RectDrawing
RectDrawing(const QRect &)
Definition: treemap.cpp:185
TreeMapItem
Base class of items in TreeMap.
Definition: treemap.h:220
TreeMapItem::addItem
void addItem(TreeMapItem *)
Adds an item to a parent.
Definition: treemap.cpp:982
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QWidget::event
virtual bool event(QEvent *event)
QRect::setLeft
void setLeft(int x)
DrawParams::backColor
virtual QColor backColor() const
Definition: treemap.h:81
TreeMapItem::position
virtual Position position(int) const
Definition: treemap.cpp:1009
QList::begin
iterator begin()
TreeMapWidget::deletingItem
void deletingItem(TreeMapItem *)
Definition: treemap.cpp:1501
TreeMapItem::freeRects
const QList< QRect > & freeRects() const
Definition: treemap.h:302
StoredDrawParams::_selected
bool _selected
Definition: treemap.h:134
TreeMapWidget::splitActivated
void splitActivated(QAction *)
Definition: treemap.cpp:2835
TreeMapWidget::setMaxDrawingDepth
void setMaxDrawingDepth(int d)
Maximal nesting depth.
Definition: treemap.cpp:1314
DrawParams::BottomRight
Definition: treemap.h:68
QWidget::height
int height() const
DrawParams::maxLines
virtual int maxLines(int) const
Definition: treemap.h:78
TreeMapWidget::setFieldForced
void setFieldForced(int, bool)
Should the drawing of the name into the rectangle be forced? This enables drawing of the name before ...
Definition: treemap.cpp:1423
DrawParams::pixmap
virtual QPixmap pixmap(int) const =0
QObject::receivers
int receivers(const char *signal) const
TreeMapWidget::fieldType
QString fieldType(int) const
Definition: treemap.cpp:1382
TreeMapItem::HAlternate
Definition: treemap.h:237
TreeMapWidget::contextMenuRequested
void contextMenuRequested(TreeMapItem *, const QPoint &)
TreeMapItemList
Definition: treemap.h:201
TreeMapItem::splitMode
virtual SplitMode splitMode() const
Definition: treemap.cpp:1076
StoredDrawParams::current
bool current() const
Definition: treemap.h:111
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:39:50 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kcachegrind

Skip menu "kcachegrind"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdesdk API Reference

Skip menu "kdesdk API Reference"
  • kapptemplate
  • kcachegrind
  • kompare
  • lokalize
  • umbrello
  •   umbrello

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal