29 #include <QApplication>
34 #include <QPaintEvent>
37 #include <QContextMenuEvent>
38 #include <QMouseEvent>
40 #include <QStylePainter>
41 #include <QStyleOptionFocusRect>
45 #define DEBUG_DRAWING 0
66 bool selected,
bool current)
81 if ((f<0) || (f >= (
int)_field.size()))
84 return _field[f].text;
89 if ((f<0) || (f >= (
int)_field.size()))
97 if ((f<0) || (f >= (
int)_field.size()))
100 return _field[f].pos;
105 if ((f<0) || (f >= (
int)_field.size()))
108 return _field[f].maxLines;
114 if (!f) f =
new QFont(QApplication::font());
119 void StoredDrawParams::ensureField(
int f)
123 if ((
int)_field.size() < f+1) {
124 int oldSize = _field.size();
126 while(oldSize < f+1) {
128 _field[oldSize].maxLines = 0;
176 _field[f].maxLines = m;
222 _usedBottomCenter = 0;
223 _usedBottomRight = 0;
232 if ((_usedTopLeft >0) ||
233 (_usedTopCenter >0) ||
234 (_usedTopRight >0)) {
236 _rect.setLeft(_rect.left() + _fontHeight);
238 _rect.setTop(_rect.top() + _fontHeight);
241 if ((_usedBottomLeft >0) ||
242 (_usedBottomCenter >0) ||
243 (_usedBottomRight >0)) {
245 _rect.setRight(_rect.right() - _fontHeight);
247 _rect.setBottom(_rect.bottom() - _fontHeight);
256 if (_rect.width()<=0 || _rect.height()<=0)
return;
260 if (dp->
selected()) normal = normal.light();
261 bool isCurrent = dp->
current();
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);
275 if (r.width()<=0 || r.height()<=0)
return;
277 if (dp->
shaded() && (r.width()>0 && r.height()>0)) {
279 r.setRect(r.x(), r.y(), r.width()-1, r.height()-1);
282 bool goDark = qGray(normal.rgb())>128;
283 int rBase, gBase, bBase;
284 normal.getRgb(&rBase, &gBase, &bBase);
285 p->setBrush(Qt::NoBrush);
289 float factor = 0.1, forth=0.7, back1 =0.9, toBack2 = .7, back2 = 0.97;
293 if (s > r.height()) s = r.height();
295 forth -= .3 * (100-s)/100;
296 back1 -= .2 * (100-s)/100;
297 back2 -= .02 * (100-s)/100;
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;
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);
313 r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
314 factor = 1.0 - ((1.0 - factor) * forth);
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);
324 r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
325 factor = 1.0 - ((1.0 - factor) / back1);
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);
335 r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
336 factor = factor * back2;
341 r.setRect(r.x(), r.y(), r.width()+1, r.height()+1);
345 p->fillRect(r, normal);
355 int findBreak(
int& breakPos, QString text, QFontMetrics* fm,
int maxWidth)
360 breakPos = text.length();
361 usedWidth = fm->width(text);
362 if (usedWidth < maxWidth)
369 int halfPos = (bottomPos + breakPos)/2;
370 int halfWidth = fm->width(text, halfPos);
371 if (halfWidth < maxWidth) {
372 bottomPos = halfPos+1;
376 usedWidth = halfWidth;
377 if (breakPos - bottomPos <3)
break;
383 QChar::Category lastCat, cat;
385 lastCat = text[pos-1].category();
389 cat = text[pos-1].category();
390 if (cat == lastCat)
continue;
393 if ((cat == QChar::Letter_Uppercase) &&
394 (lastCat == QChar::Letter_Lowercase)) {
401 usedWidth = fm->width(text, breakPos);
402 if (usedWidth < maxWidth)
break;
421 usedWidth = fm->width(text);
422 if (usedWidth < maxWidth)
427 int topPos = text.length();
429 int halfPos = (breakPos + topPos)/2;
430 int halfWidth = fm->width(text.mid(halfPos));
431 if (halfWidth > maxWidth) {
436 usedWidth = halfWidth;
437 if (topPos - breakPos <3)
break;
442 QChar::Category lastCat, cat;
444 lastCat = text[pos].category();
446 while (pos < text.length()-2) {
448 cat = text[pos].category();
449 if (cat == lastCat)
continue;
452 if ((lastCat == QChar::Letter_Uppercase) &&
453 (cat == QChar::Letter_Lowercase)) {
460 usedWidth = fm->width(text.mid(breakPos));
461 if (usedWidth < maxWidth)
break;
473 _fm =
new QFontMetrics(dp->
font());
474 _fontHeight = _fm->height();
479 if (0) qDebug() <<
"DrawField: Rect " << r.x() <<
"/" << r.y()
480 <<
" - " << r.width() <<
"x" << r.height();
484 int width = (rotate ? r.height() : r.width()) -4;
485 int height = (rotate ? r.width() : r.height());
486 int lines = height / h;
489 if (lines<1)
return false;
503 bool isBottom =
false;
504 bool isCenter =
false;
505 bool isRight =
false;
509 used = &_usedTopLeft;
510 if (_usedTopLeft == 0) {
512 unused = (width - _usedTopCenter)/2;
514 unused = width - _usedTopRight;
520 used = &_usedTopCenter;
521 if (_usedTopCenter == 0) {
522 if (_usedTopLeft > _usedTopRight)
523 unused = width - 2 * _usedTopLeft;
525 unused = width - 2 * _usedTopRight;
531 used = &_usedTopRight;
532 if (_usedTopRight == 0) {
534 unused = (width - _usedTopCenter)/2;
536 unused = width - _usedTopLeft;
542 used = &_usedBottomLeft;
543 if (_usedBottomLeft == 0) {
544 if (_usedBottomCenter)
545 unused = (width - _usedBottomCenter)/2;
547 unused = width - _usedBottomRight;
554 used = &_usedBottomCenter;
555 if (_usedBottomCenter == 0) {
556 if (_usedBottomLeft > _usedBottomRight)
557 unused = width - 2 * _usedBottomLeft;
559 unused = width - 2 * _usedBottomRight;
566 used = &_usedBottomRight;
567 if (_usedBottomRight == 0) {
568 if (_usedBottomCenter)
569 unused = (width - _usedBottomCenter)/2;
571 unused = width - _usedBottomLeft;
577 if ((_usedTopLeft >0) ||
578 (_usedTopCenter >0) ||
582 else if (!isBottom) {
583 if ((_usedBottomLeft >0) ||
584 (_usedBottomCenter >0) ||
585 (_usedBottomRight >0))
588 if (lines<1)
return false;
591 int y = isBottom ? height - h : 0;
593 if (unused < 0) unused = 0;
596 y = isBottom ? (y-h) : (y+h);
599 if (lines<1)
return false;
603 _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
605 _usedTopLeft = _usedTopCenter = _usedTopRight = 0;
612 if (!dotW) dotW = _fm->width(
"...");
613 if (width < dotW)
return false;
617 QString name = dp->
text(f);
618 if (name.isEmpty())
return 0;
619 QPixmap pix = dp->
pixmap(f);
622 int pixW = pix.width();
623 int pixH = pix.height();
625 bool pixDrawn =
true;
628 if ((width < pixW + dotW) || (height < pixH)) {
637 int w = pixW + _fm->width(name);
639 if (0) qDebug() <<
" For '" << name <<
"': Unused " << unused
640 <<
", StrW " << w <<
", Width " << width;
644 if ((unused < width) && (w > unused)) {
645 y = isBottom ? (y-h) : (y+h);
648 if (lines<1)
return false;
652 _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
654 _usedTopLeft = _usedTopCenter = _usedTopRight = 0;
658 p->setPen( (qGray(dp->
backColor().rgb())>100) ? Qt::black : Qt::white);
659 p->setFont(dp->
font());
662 p->translate(r.x(), r.y()+r.height()-2);
666 p->translate(r.x()+2, r.y());
671 if ((max > 0) && (lines>max)) lines = max;
682 int origLines = lines;
686 if (w>width && lines>1) {
690 w = pixW +
findBreak(breakPos, name, _fm, width - pixW);
692 remaining = name.mid(breakPos);
694 if (name[breakPos-1].category() == QChar::Separator_Space)
695 name = name.left(breakPos-1);
697 name = name.left(breakPos);
702 remaining = name.left(breakPos);
704 if (name[breakPos].category() == QChar::Separator_Space)
705 name = name.mid(breakPos+1);
707 name = name.mid(breakPos);
711 remaining = QString();
715 name = _fm->elidedText(name, Qt::ElideRight, width - pixW);
716 w = _fm->width(name) + pixW;
727 if (pixH > h) pixY = isBottom ? y-(pixH-h) : y;
729 p->drawPixmap( x, pixY, pix);
732 pixY = isBottom ? (pixY - h - 2) : (pixY + pixH + 2);
737 if (0) qDebug() <<
" Drawing '" << name <<
"' at "
738 << x+pixW <<
"/" << y;
740 p->drawText( x+pixW, y,
742 Qt::AlignLeft, name);
743 y = isBottom ? (y-h) : (y+h);
746 if (remaining.isEmpty())
break;
748 w = pixW + _fm->width(name);
752 if (pixDrawn && (pixY>0)) {
753 if (isBottom && (pixY<y)) y = pixY;
754 if (!isBottom && (pixY>y)) y = pixY;
757 if (origLines > lines) {
759 if (lines - origLines >1) {
761 _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
763 _usedTopLeft = _usedTopCenter = _usedTopRight = 0;
767 y = isBottom ? (y+h) : (y-h);
774 _rect.setRect(r.x()+y, r.y(), r.width()-y, r.height());
776 _rect.setRect(r.x(), r.y()+y, r.width(), r.height()-y);
780 _rect.setRect(r.x(), r.y(), y+h, r.height());
782 _rect.setRect(r.x(), r.y(), r.width(), y+h);
802 if (isEmpty())
return 0;
805 for(
int i = 1; parent && i<size(); i++)
811 class TreeMapItemLessThan
818 if (!p)
return false;
822 int textNo = p->
sorting(&ascending);
826 result = i1->
text(textNo) < i2->
text(textNo);
828 return ascending ? result : !result;
850 _sortTextNo = _parent->
sorting(&_sortAscending);
854 _sortAscending =
false;
861 const QString& text1,
const QString& text2,
862 const QString& text3,
const QString& text4)
868 if (!text4.isEmpty())
setText(3, text4);
869 if (!text3.isEmpty())
setText(2, text3);
870 if (!text2.isEmpty())
setText(1, text2);
880 if (_parent) _parent->
addItem(
this);
898 if (p) _widget = p->_widget;
903 if (!item)
return false;
907 if (item == i)
return true;
951 QStringList list(
text(textNo));
957 list.prepend(i->
text(textNo));
965 if (_depth>0)
return _depth;
968 return _parent->
depth() + 1;
1012 if (_widget && (p ==
Default))
1041 if (ascending) *ascending = _sortAscending;
1048 if (_sortTextNo == textNo) {
1049 if(_sortAscending == ascending)
return;
1052 _sortAscending = ascending;
1056 _sortAscending = ascending;
1057 _sortTextNo = textNo;
1067 if (_sortTextNo != -1)
1111 if ((r.width() < 1) || (r.height() < 1))
return;
1113 if (0) qDebug() <<
"addFree(" <<
path(0).join(
"/") <<
", "
1114 << r.x() <<
"/" << r.y() <<
"-"
1115 << r.width() <<
"x" << r.height() <<
")";
1117 if (_freeRects.isEmpty()) {
1118 _freeRects.append(r);
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())) {
1132 else if ((last.top() == r.top()) && (last.height() == r.height())) {
1133 if ((last.right()+1 == r.left()) || (r.right()+1 == last.left())) {
1140 _freeRects.append(r);
1144 if (0) qDebug() <<
" united with last to ("
1145 << last.x() <<
"/" << last.y() <<
"-"
1146 << last.width() <<
"x" << last.height() <<
")";
1161 _fontHeight = fontMetrics().height();
1168 _reuseSpace =
false;
1169 _skipIncorrectBorder =
false;
1170 _drawSeparators =
false;
1171 _allowRotation =
true;
1174 _maxSelectDepth = -1;
1175 _maxDrawingDepth = -1;
1179 for(
int i=0;i<4;i++) {
1180 _drawFrame[i] =
true;
1181 _transparent[i] =
false;
1193 _needsRefresh = _base;
1195 setAttribute(Qt::WA_NoSystemBackground,
true);
1196 setFocusPolicy(Qt::StrongFocus);
1211 if (_splitMode == m)
return;
1251 default: mode =
"Unknown";
break;
1259 if (_shading == s)
return;
1267 if ((d<0) || (d>=4) || (_drawFrame[d]==b))
return;
1275 if ((d<0) || (d>=4) || (_transparent[d]==b))
return;
1277 _transparent[d] = b;
1283 if (_allowRotation == enable)
return;
1285 _allowRotation = enable;
1291 if (_visibleWidth == width && _reuseSpace == reuseSpace)
return;
1293 _visibleWidth = width;
1294 _reuseSpace = reuseSpace;
1300 if (_skipIncorrectBorder == enable)
return;
1302 _skipIncorrectBorder = enable;
1308 if (_borderWidth == w)
return;
1316 if (_maxDrawingDepth == d)
return;
1318 _maxDrawingDepth = d;
1324 return tr(
"Text %1").arg(f+1);
1354 bool TreeMapWidget::resizeAttr(
int size)
1356 if (size<0 || size>=
MAX_FIELD)
return false;
1358 if (size>(
int)_attr.size()) {
1359 int oldSize = _attr.size();
1361 while (oldSize<size) {
1375 if (((
int)_attr.size() < f+1) &&
1377 if (resizeAttr(f+1)) _attr[f].type = type;
1385 return _attr[f].type;
1390 if (((
int)_attr.size() < f+1) &&
1392 if (resizeAttr(f+1)) {
1393 _attr[f].stop = stop;
1401 return _attr[f].stop;
1406 if (((
int)_attr.size() < f+1) &&
1409 if (resizeAttr(f+1)) {
1410 _attr[f].visible = enable;
1417 if (f<0 || (
int)_attr.size()<f+1)
1420 return _attr[f].visible;
1425 if (((
int)_attr.size() < f+1) &&
1428 if (resizeAttr(f+1)) {
1429 _attr[f].forced = enable;
1430 if (_attr[f].visible)
redraw();
1436 if (f<0 || (
int)_attr.size()<f+1)
1439 return _attr[f].forced;
1444 if (((
int)_attr.size() < f+1) &&
1447 if (resizeAttr(f+1)) {
1449 if (_attr[f].visible)
redraw();
1455 if (f<0 || (
int)_attr.size()<f+1)
1458 return _attr[f].pos;
1463 if (pos ==
"TopLeft")
1465 else if (pos ==
"TopCenter")
1467 else if (pos ==
"TopRight")
1469 else if (pos ==
"BottomLeft")
1471 else if (pos ==
"BottomCenter")
1473 else if (pos ==
"BottomRight")
1475 else if (pos ==
"Default")
1489 return QString(
"unknown");
1494 if (_minimalArea == area)
return;
1496 _minimalArea = area;
1504 _selection.removeAll(i);
1505 _tmpSelection.removeAll(i);
1507 if (_current == i) _current = 0;
1508 if (_oldCurrent == i) _oldCurrent = 0;
1509 if (_pressed == i) _pressed = 0;
1510 if (_lastOver == i) _lastOver = 0;
1513 if (_needsRefresh == i) {
1516 _needsRefresh = i->
parent();
1523 QString tip, itemTip;
1526 if (!i->
text(0).isEmpty()) {
1527 itemTip = i->
text(0);
1528 if (!i->
text(1).isEmpty())
1529 itemTip +=
" (" + i->
text(1) +
')';
1544 if (!rect().contains(x, y))
return 0;
1545 if (
DEBUG_DRAWING) qDebug() <<
"item(" << x <<
"," << y <<
"):";
1554 for (idx=0; idx<list->size(); idx++) {
1558 qDebug() <<
" Checking " << i->
path(0).join(
"/") <<
" ("
1561 <<
"x" << i->
itemRect().height() <<
")";
1563 if (i->
itemRect().contains(x, y)) {
1571 if (idx == list->size()) i = 0;
1580 qDebug() <<
"item(" << x <<
"," << y <<
"): Got "
1581 << p->
path(0).join(
"/") <<
" (Size "
1583 <<
", Val " << p->
value() <<
")";
1596 if (_maxSelectDepth>=0) {
1597 int depth = i->
depth();
1598 while(i && depth > _maxSelectDepth) {
1611 while(i && ((i->
itemRect().width() <1) ||
1615 int idx = p->
children()->indexOf(i);
1632 TreeMapItem* changed = setTmpSelected(item, selected);
1633 if (!changed)
return;
1635 _selection = _tmpSelection;
1636 if (_selectionMode ==
Single)
1641 if (0) qDebug() << (selected ?
"S":
"Des") <<
"elected Item "
1642 << (item ? item->
path(0).join(
"") : QString(
"(null)"))
1643 <<
" (depth " << (item ? item->
depth() : -1)
1650 if ((_markNo == 0) && (markNo == 0))
return;
1663 if (!l2.contains(i))
1667 if (!l1.contains(i))
1679 if (!item)
return 0;
1684 if (_selectionMode ==
Single) {
1685 _tmpSelection.clear();
1686 if (selected) _tmpSelection.append(item);
1693 _tmpSelection.removeAll(i);
1695 _tmpSelection.append(item);
1698 _tmpSelection.removeAll(item);
1712 _selection.removeAll(i);
1719 return (changed != 0);
1724 if (!i)
return false;
1725 return _selection.contains(i);
1730 if (!i)
return false;
1731 return _tmpSelection.contains(i);
1744 if (i) qDebug() <<
"setCurrent(" << i->
path(0).join(
"/")
1745 <<
") - mark removed";
1750 if (old == _current)
return;
1753 if (old == _current)
return;
1771 TreeMapItem* changed = setTmpRangeSelection(i1, i2, selected);
1772 if (!changed)
return;
1774 _selection = _tmpSelection;
1775 if (_selectionMode ==
Single)
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);
1789 TreeMapItem* changed = setTmpSelected(i1, selected);
1790 TreeMapItem* changed2 = setTmpSelected(i2, selected);
1791 if (changed2) changed = changed2->
commonParent(changed);
1794 while (commonParent && !i2->
isChildOf(commonParent)) {
1796 commonParent = commonParent->
parent();
1798 if (!commonParent)
return changed;
1799 while (i2 && i2->
parent() != commonParent)
1801 if (!i2)
return changed;
1804 if (!list)
return changed;
1806 bool between =
false;
1809 if (i==i1 || i==i2)
break;
1810 changed2 = setTmpSelected(i, selected);
1811 if (changed2) changed = changed2->
commonParent(changed);
1813 else if (i==i1 || i==i2)
1827 if ( e->reason() == QContextMenuEvent::Keyboard ) {
1829 QPoint p = QPoint(r.left() + r.width()/2, r.top() + r.height()/2);
1843 _oldCurrent = _current;
1849 _inShiftDrag = e->modifiers() & Qt::ShiftModifier;
1850 _inControlDrag = e->modifiers() & Qt::ControlModifier;
1851 _lastOver = _pressed;
1856 switch(_selectionMode) {
1858 changed = setTmpSelected(item,
true);
1861 changed = setTmpSelected(item, !isTmpSelected(item));
1865 changed = setTmpSelected(item, !isTmpSelected(item));
1866 else if (_inShiftDrag) {
1868 changed = setTmpRangeSelection(sCurrent, item,
1869 !isTmpSelected(item));
1873 changed = setTmpSelected(item,
true);
1882 if (e->button() == Qt::RightButton) {
1883 TreeMapItem* changed2 = setTmpSelected(item,
true);
1884 if (changed2) changed = changed2->
commonParent(changed);
1892 if (e->button() == Qt::RightButton) {
1895 if (! (_tmpSelection == _selection)) {
1896 _selection = _tmpSelection;
1897 if (_selectionMode ==
Single)
1911 if (!_pressed)
return;
1913 if (_lastOver == over)
return;
1924 switch(_selectionMode) {
1926 changed = setTmpSelected(item,
true);
1929 changed = setTmpSelected(item, !isTmpSelected(item));
1933 changed = setTmpSelected(item, !isTmpSelected(item));
1936 changed = setTmpRangeSelection(sLast, item,
true);
1954 if (!_pressed)
return;
1960 _tmpSelection = _selection;
1965 if (! (_tmpSelection == _selection)) {
1966 _selection = _tmpSelection;
1967 if (_selectionMode ==
Single)
1971 if (!_inControlDrag && !_inShiftDrag && (_pressed == _lastOver))
1992 if (!p || p->
itemRect().isEmpty())
return -1;
1994 int idx = p->
children()->indexOf(i);
1995 if (idx<0)
return -1;
1997 while (idx < (
int)p->
children()->count()-1) {
1999 QRect r = p->
children()->at(idx)->itemRect();
2000 if (r.width()>1 && r.height()>1)
2010 if (!p || p->
itemRect().isEmpty())
return -1;
2012 int idx = p->
children()->indexOf(i);
2013 if (idx<0)
return -1;
2017 QRect r = p->
children()->at(idx)->itemRect();
2018 if (r.width()>1 && r.height()>1)
2029 if (e->key() == Qt::Key_Escape && _pressed) {
2032 if (_oldCurrent != _lastOver)
2034 if (! (_tmpSelection == _selection)) {
2036 _tmpSelection = _selection;
2044 if ((e->key() == Qt::Key_Space) ||
2045 (e->key() == Qt::Key_Return)) {
2047 switch(_selectionMode) {
2057 if ((e->modifiers() & Qt::ControlModifier) ||
2058 (e->modifiers() & Qt::ShiftModifier))
2067 if (_current && (e->key() == Qt::Key_Return))
2074 if (e->key() == Qt::Key_Down) {
2084 if (_current->
sorting(&goBack) == -1) {
2090 if ((e->key() == Qt::Key_Backspace) ||
2091 (e->key() == Qt::Key_Up)) {
2095 else if (e->key() == Qt::Key_Left) {
2097 if (p && newIdx>=0) {
2102 else if (e->key() == Qt::Key_Right) {
2104 if (p && newIdx>=0) {
2109 else if (e->key() == Qt::Key_Down) {
2111 int newIdx = _current->
index();
2113 newIdx = goBack ? (_current->
children()->count()-1) : 0;
2114 if (newIdx>=(
int)_current->
children()->count())
2115 newIdx = _current->
children()->count()-1;
2121 if (old == _current)
return;
2122 if (! (e->modifiers() & Qt::ControlModifier))
return;
2123 if (! (e->modifiers() & Qt::ShiftModifier))
return;
2125 switch(_selectionMode) {
2135 if (e->modifiers() & Qt::ControlModifier)
2150 if (event->type() == QEvent::ToolTip) {
2151 QHelpEvent *helpEvent =
static_cast<QHelpEvent *
>(
event);
2153 bool hasTip =
false;
2156 foreach(
const QRect& r, rList) {
2157 if (r.contains(helpEvent->pos())) {
2164 QToolTip::showText(helpEvent->globalPos(),
tipString(i));
2166 QToolTip::hideText();
2168 return QWidget::event(event);
2181 if (!isVisible())
return;
2183 if (_pixmap.size() != size())
2184 _needsRefresh = _base;
2186 if (_needsRefresh) {
2189 qDebug() <<
"Redrawing " << _needsRefresh->
path(0).join(
"/");
2191 if (_needsRefresh == _base) {
2193 _pixmap = QPixmap(size());
2194 _pixmap.fill(palette().color(backgroundRole()));
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));
2204 if (!_needsRefresh->
itemRect().isValid())
return;
2209 _fontHeight = fontMetrics().height();
2211 drawItems(&p, _needsRefresh);
2216 p.drawPixmap(0, 0, _pixmap, 0, 0,
2217 QWidget::width(), QWidget::height());
2220 QStylePainter p(
this);
2221 QStyleOptionFocusRect opt;
2223 opt.palette = palette();
2224 opt.state = QStyle::State_None;
2225 p.drawPrimitive( QStyle::PE_FrameFocusRect, opt );
2248 void TreeMapWidget::drawItem(QPainter* p,
2270 bool isCurrent = _current && item->
isChildOf(_current);
2271 int dd = item->
depth();
2279 d.drawBack(p, item);
2283 bool TreeMapWidget::horizontal(
TreeMapItem* i,
const QRect& r)
2287 return (i->
depth()%2)==1;
2289 return (i->
depth()%2)==0;
2295 return r.width() > r.height();
2304 void TreeMapWidget::drawItems(QPainter* p,
2308 qDebug() <<
"+drawItems(" << item->
path(0).join(
"/") <<
", "
2310 <<
"-" << item->
itemRect().width() <<
"x"
2312 <<
", Sum " << item->
sum();
2319 QRect r = QRect(origRect.x()+bw, origRect.y()+bw,
2320 origRect.width()-2*bw, origRect.height()-2*bw);
2324 bool stopDrawing =
false;
2327 if (!list || list->count()==0)
2331 if (!stopDrawing && (r.width()<=0 || r.height()<=0))
2336 (_maxDrawingDepth>=0 && item->
depth()>=_maxDrawingDepth))
2341 for (
int no=0;no<(int)_attr.size();no++) {
2343 if (!stopAt.isEmpty() && (item->
text(no) == stopAt)) {
2353 (_minimalArea > 0) &&
2354 (r.width() * r.height() < _minimalArea)) stopDrawing =
true;
2367 if ((r.height() < _fontHeight) || (r.width() < _fontHeight))
return;
2370 item->
setRotated(_allowRotation && (r.height() > r.width()));
2371 for (
int no=0;no<(int)_attr.size();no++) {
2373 d.drawField(p, no, item);
2375 r = d.remainingRect(item);
2378 qDebug() <<
"-drawItems(" << item->
path(0).join(
"/") <<
")";
2382 double user_sum, child_sum,
self;
2385 user_sum = item->
sum();
2390 child_sum += i->
value();
2392 qDebug() <<
" child: " << i->
text(0) <<
", value "
2399 if ((r.height() >= _fontHeight) && (r.width() >= _fontHeight)) {
2402 item->
setRotated(_allowRotation && (r.height() > r.width()));
2403 for (
int no=0;no<(int)_attr.size();no++) {
2406 d.drawField(p, no, item);
2408 r = d.remainingRect(item);
2411 if (orig.x() == r.x()) {
2414 orig.width(), orig.height()-r.height()));
2419 orig.width()-r.width(), orig.height()));
2422 if (user_sum == 0) {
2424 user_sum = child_sum;
2428 self = user_sum - child_sum;
2430 if (user_sum < child_sum) {
2435 user_sum = child_sum;
2441 float borderArea = origRect.width() * origRect.height();
2442 borderArea = (borderArea - r.width()*r.height())/borderArea;
2443 unsigned borderValue = (unsigned)(borderArea * user_sum);
2445 if (borderValue >
self) {
2446 if (_skipIncorrectBorder) {
2454 self -= borderValue;
2456 user_sum = child_sum +
self;
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) {
2467 sr.setWidth( self_length );
2468 r.setRect(r.x()+sr.width(), r.y(), r.width()-sr.width(), r.height());
2471 sr.setHeight( self_length );
2472 r.setRect(r.x(), r.y()+sr.height(), r.width(), r.height()-sr.height());
2478 if (0) qDebug() <<
"Item " << item->
path(0).join(
"/") <<
": SelfR "
2479 << sr.x() <<
"/" << sr.y() <<
"-" << sr.width()
2480 <<
"/" << sr.height() <<
", self " <<
self <<
"/"
2483 if ((sr.height() >= _fontHeight) && (sr.width() >= _fontHeight)) {
2486 item->
setRotated(_allowRotation && (r.height() > r.width()));
2487 for (
int no=0;no<(int)_attr.size();no++) {
2490 d.drawField(p, no, item);
2498 if (item->
sorting(&goBack) == -1) {
2503 int idx = goBack ? (list->size()-1) : 0;
2506 int len = list->count();
2507 bool drawDetails =
true;
2509 while (len>0 && user_sum>0) {
2513 int columns = (int)(sqrt((
double)len * r.width()/r.height())+.5);
2514 if (columns==0) columns = 1;
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;
2524 int nextPos = (int)((
double)r.width() * valSum / user_sum);
2525 QRect firstRect = QRect(r.x(), r.y(), nextPos, r.height());
2527 if (nextPos < _visibleWidth) {
2530 drawFill(item, p, firstRect);
2534 drawFill(item, p, r, list, firstIdx, len, goBack);
2539 drawDetails = drawItemArray(p, item, firstRect,
2540 valSum, list, firstIdx, len-lenLeft, goBack);
2542 r.setRect(r.x()+nextPos, r.y(), r.width()-nextPos, r.height());
2550 drawFill(item, p, r, list, idx, len, goBack);
2557 int len = list->count();
2558 bool drawDetails =
true;
2560 while (len>0 && user_sum>0) {
2564 int rows = (int)(sqrt((
double)len * r.height()/r.width())+.5);
2565 if (rows==0) rows = 1;
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;
2575 int nextPos = (int)((
double)r.height() * valSum / user_sum);
2576 QRect firstRect = QRect(r.x(), r.y(), r.width(), nextPos);
2578 if (nextPos < _visibleWidth) {
2580 drawFill(item, p, firstRect);
2583 drawFill(item, p, r, list, firstIdx, len, goBack);
2588 drawDetails = drawItemArray(p, item, firstRect,
2589 valSum, list, firstIdx, len-lenLeft, goBack);
2591 r.setRect(r.x(), r.y()+nextPos, r.width(), r.height()-nextPos);
2599 drawFill(item, p, r, list, idx, len, goBack);
2606 drawItemArray(p, item, r, user_sum, list, idx, list->count(), goBack);
2609 qDebug() <<
"-drawItems(" << item->
path(0).join(
"/") <<
")";
2613 void TreeMapWidget::drawFill(
TreeMapItem* i, QPainter* p,
const QRect& r)
2615 p->setBrush(Qt::Dense4Pattern);
2616 p->setPen(Qt::NoPen);
2617 p->drawRect(QRect(r.x(), r.y(), r.width()-1, r.height()-1));
2622 void TreeMapWidget::drawFill(
TreeMapItem* i, QPainter* p,
const QRect& r,
2626 qDebug() <<
" +drawFill(" << r.x() <<
"/" << r.y()
2627 <<
"-" << r.width() <<
"x" << r.height()
2628 <<
", len " << len <<
")";
2630 p->setBrush(Qt::Dense4Pattern);
2631 p->setPen(Qt::NoPen);
2632 p->drawRect(QRect(r.x(), r.y(), r.width()-1, r.height()-1));
2636 while (len>0 && (i=list->value(idx))) {
2639 qDebug() <<
" Reset Rect " << i->
path(0).join(
"/");
2642 if (goBack) --idx;
else ++idx;
2646 qDebug() <<
" -drawFill(" << r.x() <<
"/" << r.y()
2647 <<
"-" << r.width() <<
"x" << r.height()
2648 <<
", len " << len <<
")";
2652 bool TreeMapWidget::drawItemArray(QPainter* p,
TreeMapItem* item,
2653 const QRect& r,
double user_sum,
2657 if (user_sum == 0)
return false;
2659 static bool b2t =
true;
2662 if (((r.height() < _visibleWidth) &&
2663 (r.width() < _visibleWidth)) ||
2664 ((_minimalArea > 0) &&
2665 (r.width() * r.height() < _minimalArea))) {
2667 drawFill(item, p, r, list, idx, len, goBack);
2672 qDebug() <<
" +drawItemArray(" << item->
path(0).join(
"/")
2673 <<
", " << r.x() <<
"/" << r.y() <<
"-" << r.width()
2674 <<
"x" << r.height() <<
")";
2682 while (lenLeft>len/2) {
2683 valSum += list->at(idx)->value();
2684 if (goBack) --idx;
else ++idx;
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());
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);
2708 if (item->
sorting(0) == -1) drawOn =
true;
2712 drawOn = drawItemArray(p, item, secondRect, user_sum - valSum,
2713 list, idx, lenLeft, goBack);
2715 drawFill(item, p, secondRect, list, idx, len, goBack);
2719 qDebug() <<
" -drawItemArray(" << item->
path(0).join(
"/")
2725 bool hor = horizontal(item,r);
2731 if (user_sum <= 0) {
2734 qDebug() <<
"drawItemArray: Reset " << i->
path(0).join(
"/");
2737 if (goBack) --idx;
else ++idx;
2743 if (((fullRect.height() < _visibleWidth) &&
2744 (fullRect.width() < _visibleWidth)) ||
2745 ((_minimalArea > 0) &&
2746 (fullRect.width() * fullRect.height() < _minimalArea))) {
2748 drawFill(item, p, fullRect, list, idx, len, goBack);
2750 qDebug() <<
" -drawItemArray(" << item->
path(0).join(
"/")
2756 hor = fullRect.width() > fullRect.height();
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;
2763 if ((item->
sorting(0) != -1) && (nextPos < _visibleWidth)) {
2764 drawFill(item, p, fullRect, list, idx, len, goBack);
2766 qDebug() <<
" -drawItemArray(" << item->
path(0).join(
"/")
2771 QRect currRect = fullRect;
2774 currRect.setWidth(nextPos);
2777 currRect.setRect(fullRect.x(), fullRect.bottom()-nextPos+1, fullRect.width(), nextPos);
2779 currRect.setHeight(nextPos);
2783 if (nextPos >= _visibleWidth) {
2789 drawFill(item, p, currRect);
2793 if (_drawSeparators && (nextPos<lastPos)) {
2794 p->setPen(Qt::black);
2796 if (fullRect.top() <= fullRect.bottom())
2797 p->drawLine(fullRect.x() + nextPos, fullRect.top(), fullRect.x() + nextPos, fullRect.bottom());
2800 if (fullRect.left() <= fullRect.right())
2801 p->drawLine(fullRect.left(), fullRect.y() + nextPos, fullRect.right(), fullRect.y() + nextPos);
2807 fullRect.setRect(fullRect.x() + nextPos, fullRect.y(),
2808 lastPos - nextPos, fullRect.height());
2811 fullRect.setRect(fullRect.x(), fullRect.y(),
2812 fullRect.width(), lastPos-nextPos);
2814 fullRect.setRect(fullRect.x(), fullRect.y() + nextPos,
2815 fullRect.width(), lastPos-nextPos);
2819 if (goBack) --idx;
else ++idx;
2824 qDebug() <<
" -drawItemArray(" << item->
path(0).join(
"/")
2840 void TreeMapWidget::addSplitAction(QMenu* m,
const QString& s,
int v)
2842 QAction* a = m->addAction(s);
2844 a->setCheckable(
true);
2850 connect(m, SIGNAL(triggered(QAction*)),
2865 #include "treemap.moc"
void addFreeRect(const QRect &r)
virtual int borderWidth() const
bool drawField(QPainter *, int f, DrawParams *dp=0)
virtual double sum() const
QPixmap pixmap(int) const
void drawBack(QPainter *, DrawParams *dp=0)
virtual Position position(int) const =0
virtual const QFont & font() const =0
Drawing parameters for an object.
TreeMapItem(TreeMapItem *parent=0, double value=1.0)
void setPixmap(int f, const QPixmap &)
SplitMode
Split direction for nested areas: AlwaysBest: Choose split direction for every subitem according to l...
const QRect & itemRect() const
void setParent(TreeMapItem *p)
void setMaxLines(int f, int)
void setItemRect(const QRect &r)
Temporary rectangle used for drawing this item the last time.
const QFont & font() const
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...
virtual double value() const
void setRect(const QRect &)
TreeMapItem * parent() const
Parent Item.
virtual bool selected() const
Position position(int) const
virtual bool current() const
bool isChildOf(TreeMapItem *)
void setField(int f, const QString &t, const QPixmap &pm=QPixmap(), Position p=Default, int maxLines=0)
TreeMapItemLessThan treeMapItemLessThan
void setDrawParams(DrawParams *)
virtual bool shaded() const
DrawParams * drawParams()
virtual QString text(int) const =0
int nextVisible(TreeMapItem *i)
virtual bool isMarked(int) const
virtual const QFont & font() const
static int findBreak(int &breakPos, QString text, QFontMetrics *fm, int maxWidth)
virtual TreeMapItemList * children()
void setWidget(TreeMapWidget *w)
static int findBreakBackwards(int &breakPos, QString text, QFontMetrics *fm, int maxWidth)
Position
Positions for drawing into a rectangle.
TreeMapItem * commonParent()
int prevVisible(TreeMapItem *i)
void resort(bool recursive=true)
Resort according to the already set sorting.
int index() const
Temporary child item index of the child that was current() recently.
int depth() const
Depth of this item.
TreeMapItemList * _children
void clearFreeRects()
Temporary rectangle list of free space of this item.
virtual bool drawFrame() const
QStringList path(int) const
Returns a list of text strings of specified text number, from root up to this item.
void setSorting(int textNo, bool ascending=true)
Set the sorting for child drawing.
void setText(int f, const QString &)
TreeMapItem * commonParent(TreeMapItem *item)
QRect remainingRect(DrawParams *dp=0)
void setPosition(int f, Position)
virtual bool rotated() const
RectDrawing(const QRect &)
Base class of items in TreeMap.
void addItem(TreeMapItem *)
Adds an item to a parent.
virtual QColor backColor() const
virtual Position position(int) const
const QList< QRect > & freeRects() const
virtual int maxLines(int) const
virtual QPixmap pixmap(int) const =0
virtual SplitMode splitMode() const