9#include "TreeViewContent.h"
21#include <QtCore/qtextstream.h>
25#include "IException.h"
28#include "AbstractTreeItem.h"
29#include "TableColumn.h"
30#include "AbstractTreeModel.h"
34 TreeViewContent::TreeViewContent(
QWidget *parent) :
38 m_parentView = (TreeView *) parent;
40 m_items =
new QList< AbstractTreeItem * >;
41 m_mousePressPos =
new QPoint;
42 m_pressedItem =
new QPair< AbstractTreeItem *, bool >(NULL,
false);
43 m_hoveredItem =
new QPair< AbstractTreeItem *, bool >(NULL,
false);
44 m_lastShiftSelection =
new QList<AbstractTreeItem *>;
46 verticalScrollBar()->setSingleStep(1);
47 horizontalScrollBar()->setSingleStep(10);
48 m_rowHeight = QFontMetrics(font()).height() + ITEM_PADDING;
51 setMouseTracking(
true);
52 setContextMenuPolicy(Qt::ActionsContextMenu);
53 QAction *alternateRowsAct =
new QAction(
"&Alternate row colors",
this);
54 alternateRowsAct->setCheckable(
true);
55 connect(alternateRowsAct, SIGNAL(toggled(
bool)),
56 this, SLOT(setAlternatingRowColors(
bool)));
57 addAction(alternateRowsAct);
58 alternateRowsAct->setChecked(
true);
62 TreeViewContent::~TreeViewContent() {
66 delete m_mousePressPos;
67 m_mousePressPos = NULL;
75 delete m_lastShiftSelection;
76 m_lastShiftSelection = NULL;
80 QSize TreeViewContent::minimumSizeHint()
const {
81 return QWidget::minimumSizeHint();
85 QSize TreeViewContent::sizeHint()
const {
86 return minimumSizeHint();
90 AbstractTreeModel *TreeViewContent::getModel() {
95 void TreeViewContent::setModel(AbstractTreeModel *someModel) {
97 IString msg =
"Attempted to set a NULL model!";
98 throw IException(IException::Programmer, msg, _FILEINFO_);
102 disconnect(m_model, SIGNAL(modelModified()),
this, SLOT(refresh()));
103 disconnect(m_model, SIGNAL(filterProgressChanged(
int)),
104 this, SLOT(updateItemList()));
106 SIGNAL(treeSelectionChanged(QList< AbstractTreeItem * >)),
108 SIGNAL(treeSelectionChanged(QList< AbstractTreeItem * >)));
109 disconnect(m_model, SIGNAL(tableSelectionChanged(QList<AbstractTreeItem *>)),
110 this, SLOT(scrollTo(QList<AbstractTreeItem *>)));
114 connect(m_model, SIGNAL(modelModified()),
this, SLOT(refresh()));
115 connect(m_model, SIGNAL(filterProgressChanged(
int)),
116 this, SLOT(updateItemList()));
117 connect(
this, SIGNAL(treeSelectionChanged(QList< AbstractTreeItem * >)),
118 m_model, SIGNAL(treeSelectionChanged(QList< AbstractTreeItem * >)));
119 connect(m_model, SIGNAL(tableSelectionChanged(QList<AbstractTreeItem *>)),
120 this, SLOT(scrollTo(QList<AbstractTreeItem *>)));
126 void TreeViewContent::refresh() {
129 if (!m_model->isFiltering()) {
130 QSize modelVisibleSize =
131 m_model->getVisibleSize(ITEM_INDENTATION);
132 int rowCount = modelVisibleSize.height();
133 m_contentWidth = modelVisibleSize.width() + ITEM_INDENTATION;
134 verticalScrollBar()->setRange(0, qMax(rowCount - 1, 0));
135 horizontalScrollBar()->setRange(0, m_contentWidth - viewport()->width()
136 + horizontalScrollBar()->singleStep());
140 viewport()->update();
145 bool TreeViewContent::eventFilter(
QObject *target, QEvent *event) {
146 return QObject::eventFilter(target, event);
150 void TreeViewContent::mouseDoubleClickEvent(QMouseEvent *event) {
151 QPoint pressPos =
event->pos();
152 int index = pressPos.y() / m_rowHeight;
154 if (index < m_items->size()) {
155 AbstractTreeItem *item = (*m_items)[index];
156 item->setExpanded(!item->isExpanded());
161 void TreeViewContent::mousePressEvent(QMouseEvent *event) {
162 QPoint pressPos =
event->pos();
163 int index = pressPos.y() / m_rowHeight;
165 m_pressedItem->first = NULL;
166 m_pressedItem->second =
false;
168 if (index < m_items->size()) {
169 AbstractTreeItem *item = (*m_items)[index];
170 if (item->isSelectable() ||
171 (item->getFirstVisibleChild() &&
172 getArrowRect(item).contains(pressPos))) {
173 m_pressedItem->first = item;
175 if (item->getFirstVisibleChild()) {
176 QRect arrowRect(getArrowRect(item));
177 m_pressedItem->second = arrowRect.contains(pressPos);
180 QList< AbstractTreeItem * > newlySelectedItems;
181 if (!m_pressedItem->second) {
182 if (event->modifiers() & Qt::ControlModifier) {
183 foreach (AbstractTreeItem * child, item->getChildren()) {
184 child->setSelected(!item->isSelected());
185 if (child->isSelected())
186 newlySelectedItems.append(child);
189 item->setSelected(!item->isSelected());
190 if (item->isSelected())
191 newlySelectedItems.append(item);
193 m_lastDirectlySelectedItem = item;
194 m_lastShiftSelection->clear();
197 if (event->modifiers() & Qt::ShiftModifier) {
198 foreach (AbstractTreeItem * i, *m_lastShiftSelection)
199 i->setSelected(
false);
201 if (m_lastDirectlySelectedItem) {
203 QList< AbstractTreeItem * > tmp =
204 m_model->getItems(m_lastDirectlySelectedItem, item);
208 foreach (AbstractTreeItem * i, tmp) {
209 m_lastShiftSelection->append(i);
212 if (i->getPointerType() == AbstractTreeItem::Point) {
213 foreach (AbstractTreeItem * child, i->getChildren()) {
214 child->setSelected(
true);
215 m_lastShiftSelection->append(child);
221 m_lastShiftSelection->clear();
224 foreach (AbstractTreeItem * i, *m_lastShiftSelection) {
225 i->setSelected(
true);
226 newlySelectedItems.append(i);
230 m_model->setGlobalSelection(
false);
231 item->setSelected(
true);
232 newlySelectedItems.append(item);
233 m_lastDirectlySelectedItem = item;
235 if (item->getPointerType() == AbstractTreeItem::Point) {
236 foreach (AbstractTreeItem * child, item->getChildren()) {
237 child->setSelected(
true);
238 newlySelectedItems.append(child);
242 m_lastShiftSelection->clear();
246 emit treeSelectionChanged(newlySelectedItems);
251 m_model->setGlobalSelection(
false);
254 viewport()->update();
258 void TreeViewContent::mouseReleaseEvent(QMouseEvent *event) {
259 AbstractTreeItem *item = m_pressedItem->first;
260 if (item && getArrowRect(item).contains(event->pos())) {
261 item->setExpanded(!item->isExpanded());
265 m_pressedItem->first = NULL;
266 m_pressedItem->second =
false;
267 viewport()->update();
269 QWidget::mousePressEvent(event);
273 void TreeViewContent::mouseMoveEvent(QMouseEvent *event) {
274 QPoint cursorPos =
event->pos();
275 int index = cursorPos.y() / m_rowHeight;
277 m_hoveredItem->first = NULL;
278 m_hoveredItem->second =
false;
280 if (index < m_items->size() && index >= 0) {
281 AbstractTreeItem *item = (*m_items)[index];
282 if (item->isSelectable() ||
283 (item->getFirstVisibleChild() &&
284 getArrowRect(item).contains(cursorPos))) {
285 m_hoveredItem->first = item;
287 if (item->getFirstVisibleChild()) {
288 QRect arrowRect = getArrowRect(item);
289 m_hoveredItem->second = arrowRect.contains(cursorPos);
294 viewport()->update();
298 void TreeViewContent::leaveEvent(QEvent *event) {
299 m_hoveredItem->first = NULL;
300 m_hoveredItem->second =
false;
301 viewport()->update();
305 void TreeViewContent::keyPressEvent(QKeyEvent *event) {
306 if (event->key() == Qt::Key_A &&
307 event->modifiers() == Qt::ControlModifier) {
308 m_model->setGlobalSelection(
true);
309 viewport()->update();
310 emit treeSelectionChanged();
313 QWidget::keyPressEvent(event);
318 void TreeViewContent::paintEvent(QPaintEvent *event) {
320 int startRow = verticalScrollBar()->value();
321 int rowCount = (int) ceil(viewport()->height() / (double) m_rowHeight);
323 QPainter painter(viewport());
324 painter.setRenderHints(QPainter::Antialiasing |
325 QPainter::TextAntialiasing);
327 for (
int i = 0; i < rowCount; i++) {
331 QColor backgroundColor = palette().base().color();
333 if (i < m_items->size()) {
334 if (m_alternatingRowColors && (startRow + i) % 2 == 1)
335 backgroundColor = palette().alternateBase().color();
337 if (m_items->at(i)->isSelected())
338 backgroundColor = palette().highlight().color();
342 QPoint relativeTopLeft(0, i * m_rowHeight);
343 QPoint scrollBarPos(horizontalScrollBar()->value(),
344 verticalScrollBar()->value());
345 QPoint absoluteTopLeft(relativeTopLeft + scrollBarPos);
346 QSize rowSize(viewport()->width(), (
int) m_rowHeight);
349 painter.fillRect(QRect(relativeTopLeft, rowSize), backgroundColor);
353 if (i < m_items->size() && m_hoveredItem->first == (*m_items)[i] &&
354 m_hoveredItem->first->isSelectable()) {
355 QPen prevPen(painter.pen());
356 QPen borderPen(prevPen);
357 borderPen.setWidth(1);
358 borderPen.setColor(palette().highlight().color());
359 painter.setPen(borderPen);
360 QPoint borderTopLeft(relativeTopLeft.x() - absoluteTopLeft.x(),
361 relativeTopLeft.y() + 1);
363 int rectWidth = qMax(m_contentWidth +
364 horizontalScrollBar()->singleStep(), viewport()->width());
365 QSize borderSize(rectWidth, rowSize.height() - 2);
366 painter.drawRect(QRect(borderTopLeft, borderSize));
367 painter.setPen(prevPen);
371 if (i < m_items->size())
372 paintItemText(&painter, i, absoluteTopLeft, relativeTopLeft);
376 QWidget::paintEvent(event);
381 void TreeViewContent::resizeEvent(QResizeEvent *event) {
382 QAbstractScrollArea::resizeEvent(event);
383 horizontalScrollBar()->setRange(0, m_contentWidth - viewport()->width()
384 + horizontalScrollBar()->singleStep());
389 void TreeViewContent::scrollContentsBy(
int dx,
int dy) {
390 QAbstractScrollArea::scrollContentsBy(dx, dy);
395 void TreeViewContent::nullify() {
399 m_pressedItem = NULL;
400 m_hoveredItem = NULL;
401 m_lastDirectlySelectedItem = NULL;
402 m_lastShiftSelection = NULL;
403 m_mousePressPos = NULL;
407 void TreeViewContent::paintItemText(QPainter *painter,
408 int index, QPoint absolutePosition, QPoint relativePosition) {
410 QPoint point(-absolutePosition.x(), relativePosition.y());
412 AbstractTreeItem *item = (*m_items)[index];
426 AbstractTreeItem *iteratorItem = item;
427 while (iteratorItem->parent() && iteratorItem->parent()->parent()) {
428 point.setX(point.x() + ITEM_INDENTATION);
429 iteratorItem = iteratorItem->parent();
432 QPen originalPen = painter->pen();
433 if (item->isSelected()) {
434 painter->setPen(QPen(palette().highlightedText().color()));
440 if (item->getFirstVisibleChild()) {
443 QRect itemArrowRect(getArrowRect(item));
444 if (item == m_hoveredItem->first && item == m_pressedItem->first) {
445 if (m_pressedItem->second && m_hoveredItem->second) {
446 QPainter::CompositionMode prevMode = painter->compositionMode();
447 painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
448 QColor color = palette().button().color().darker(160);
450 painter->fillRect(itemArrowRect, color);
451 painter->setCompositionMode(prevMode);
457 if ((item == m_hoveredItem->first && m_hoveredItem->second) ||
458 (item == m_pressedItem->first && m_pressedItem->second)) {
459 if (!m_pressedItem->first ||
460 (item == m_pressedItem->first && m_pressedItem->second)) {
461 painter->drawRect(itemArrowRect);
466 if (item->isExpanded())
467 drawExpandedArrow(painter, itemArrowRect);
469 drawCollapsedArrow(painter, itemArrowRect);
474 point.setX(point.x() + ITEM_INDENTATION);
477 point.setY(point.y() + ITEM_PADDING / 2);
480 int textHeight = m_rowHeight - ITEM_PADDING;
481 QRect rect(point, QSize(viewport()->width() - point.x(), textHeight));
482 painter->drawText(rect, Qt::TextDontClip, item->getData().toString());
483 painter->setPen(originalPen);
488 void TreeViewContent::drawCollapsedArrow(QPainter *painter, QRect rect) {
489 rect.setTopLeft(rect.topLeft() + QPoint(4, 3));
490 rect.setBottomRight(rect.bottomRight() - QPoint(4, 2));
492 QPoint top(rect.topLeft());
493 QPoint bottom(rect.bottomLeft());
494 QPoint right(rect.right(), rect.center().y());
496 QPen prevPen = painter->pen();
497 QPen arrowPen(prevPen);
498 arrowPen.setCapStyle(Qt::RoundCap);
499 arrowPen.setJoinStyle(Qt::RoundJoin);
500 arrowPen.setWidth(2);
501 painter->setPen(arrowPen);
502 painter->drawLine(top, right);
503 painter->drawLine(bottom, right);
504 painter->setPen(prevPen);
508 void TreeViewContent::drawExpandedArrow(QPainter *painter, QRect rect) {
509 rect.setTopLeft(rect.topLeft() + QPoint(3, 4));
510 rect.setBottomRight(rect.bottomRight() - QPoint(2, 4));
512 QPoint left(rect.topLeft());
513 QPoint right(rect.topRight());
514 QPoint bottom(rect.center().x(), rect.bottom());
516 QPen prevPen = painter->pen();
517 QPen arrowPen(prevPen);
518 arrowPen.setCapStyle(Qt::RoundCap);
519 arrowPen.setJoinStyle(Qt::RoundJoin);
520 arrowPen.setWidth(2);
521 painter->setPen(arrowPen);
522 painter->drawLine(left, bottom);
523 painter->drawLine(right, bottom);
524 painter->setPen(prevPen);
528 void TreeViewContent::setAlternatingRowColors(
bool newStatus) {
529 m_alternatingRowColors = newStatus;
530 viewport()->update();
534 void TreeViewContent::updateItemList() {
535 int startRow = verticalScrollBar()->value();
536 int rowCount = (int) ceil(viewport()->height() / (double) m_rowHeight);
537 *m_items = m_model->getItems(startRow, startRow + rowCount,
538 AbstractTreeModel::AllItems,
false);
540 viewport()->update();
544 QRect TreeViewContent::getArrowRect(AbstractTreeItem *item)
const {
547 int index = m_items->indexOf(item);
548 QPoint centerOfArrow(12 - horizontalScrollBar()->value(),
549 (index * m_rowHeight) + (m_rowHeight / 2));
550 int depth = item->getDepth() - 1;
551 centerOfArrow.setX(centerOfArrow.x() + (depth * ITEM_INDENTATION));
553 arrowRect = QRect(centerOfArrow.x() - 6, centerOfArrow.y() - 6, 12, 12);
559 void TreeViewContent::scrollTo(
560 QList< AbstractTreeItem * > newlySelectedItems) {
561 if (newlySelectedItems.size())
562 scrollTo(newlySelectedItems.last());
566 void TreeViewContent::scrollTo(AbstractTreeItem *newlySelectedItem) {
567 if (newlySelectedItem->getPointerType() == AbstractTreeItem::Measure)
568 newlySelectedItem->parent()->setExpanded(
true);
570 int row = getModel()->indexOfVisibleItem(newlySelectedItem);
573 int topRow = verticalScrollBar()->value();
576 verticalScrollBar()->setValue(row);
579 int wholeVisibleRowCount = viewport()->height() / m_rowHeight;
580 int bottomRow = topRow + wholeVisibleRowCount;
582 verticalScrollBar()->setValue(row - wholeVisibleRowCount + 1);
586 viewport()->update();
This is free and unencumbered software released into the public domain.