3 #include "TreeViewContent.h"
12 #include <QPaintEvent>
15 #include <QtCore/qtextstream.h>
17 #include <QVBoxLayout>
22 #include "AbstractTreeItem.h"
23 #include "TableColumn.h"
24 #include "AbstractTreeModel.h"
29 TreeViewContent::TreeViewContent(
QWidget *parent) :
33 m_parentView = (TreeView *) parent;
36 m_mousePressPos =
new QPoint;
41 verticalScrollBar()->setSingleStep(1);
42 horizontalScrollBar()->setSingleStep(10);
43 m_rowHeight = QFontMetrics(font()).height() + ITEM_PADDING;
45 ASSERT(m_rowHeight > 0);
47 setMouseTracking(
true);
48 setContextMenuPolicy(Qt::ActionsContextMenu);
49 QAction *alternateRowsAct =
new QAction(
"&Alternate row colors",
this);
50 alternateRowsAct->setCheckable(
true);
51 connect(alternateRowsAct, SIGNAL(toggled(
bool)),
52 this, SLOT(setAlternatingRowColors(
bool)));
53 addAction(alternateRowsAct);
54 alternateRowsAct->setChecked(
true);
58 TreeViewContent::~TreeViewContent() {
62 delete m_mousePressPos;
63 m_mousePressPos = NULL;
71 delete m_lastShiftSelection;
72 m_lastShiftSelection = NULL;
76 QSize TreeViewContent::minimumSizeHint()
const {
77 return QWidget::minimumSizeHint();
81 QSize TreeViewContent::sizeHint() {
82 return minimumSizeHint();
86 AbstractTreeModel *TreeViewContent::getModel() {
91 void TreeViewContent::setModel(AbstractTreeModel *someModel) {
93 IString msg =
"Attempted to set a NULL model!";
98 disconnect(m_model, SIGNAL(modelModified()),
this, SLOT(refresh()));
99 disconnect(m_model, SIGNAL(filterProgressChanged(
int)),
100 this, SLOT(updateItemList()));
110 connect(m_model, SIGNAL(modelModified()),
this, SLOT(refresh()));
111 connect(m_model, SIGNAL(filterProgressChanged(
int)),
112 this, SLOT(updateItemList()));
122 void TreeViewContent::refresh() {
125 if (!m_model->isFiltering()) {
126 QSize modelVisibleSize =
128 int rowCount = modelVisibleSize.height();
129 m_contentWidth = modelVisibleSize.width() + ITEM_INDENTATION;
130 verticalScrollBar()->setRange(0, qMax(rowCount - 1, 0));
131 horizontalScrollBar()->setRange(0, m_contentWidth - viewport()->width()
132 + horizontalScrollBar()->singleStep());
136 viewport()->update();
141 bool TreeViewContent::eventFilter(
QObject *target, QEvent *event) {
142 return QObject::eventFilter(target, event);
146 void TreeViewContent::mouseDoubleClickEvent(QMouseEvent *event) {
147 QPoint pressPos =
event->pos();
148 int index = pressPos.y() / m_rowHeight;
150 if (index < m_items->size()) {
151 AbstractTreeItem *item = (*m_items)[index];
152 item->setExpanded(!item->isExpanded());
157 void TreeViewContent::mousePressEvent(QMouseEvent *event) {
158 QPoint pressPos =
event->pos();
159 int index = pressPos.y() / m_rowHeight;
164 if (index < m_items->size()) {
165 AbstractTreeItem *item = (*m_items)[index];
166 if (item->isSelectable() ||
167 (item->getFirstVisibleChild() &&
168 getArrowRect(item).contains(pressPos))) {
171 if (item->getFirstVisibleChild()) {
172 QRect arrowRect(getArrowRect(item));
178 if (event->modifiers() & Qt::ControlModifier) {
179 foreach (AbstractTreeItem * child, item->getChildren()) {
180 child->setSelected(!item->isSelected());
181 if (child->isSelected())
182 newlySelectedItems.append(child);
185 item->setSelected(!item->isSelected());
186 if (item->isSelected())
187 newlySelectedItems.append(item);
189 m_lastDirectlySelectedItem = item;
190 m_lastShiftSelection->clear();
193 if (event->modifiers() & Qt::ShiftModifier) {
194 foreach (AbstractTreeItem * i, *m_lastShiftSelection)
195 i->setSelected(
false);
197 if (m_lastDirectlySelectedItem) {
200 m_model->getItems(m_lastDirectlySelectedItem, item);
204 foreach (AbstractTreeItem * i, tmp) {
205 m_lastShiftSelection->append(i);
208 if (i->getPointerType() == AbstractTreeItem::Point) {
209 foreach (AbstractTreeItem * child, i->getChildren()) {
210 child->setSelected(
true);
211 m_lastShiftSelection->append(child);
217 m_lastShiftSelection->clear();
220 foreach (AbstractTreeItem * i, *m_lastShiftSelection) {
221 i->setSelected(
true);
222 newlySelectedItems.append(i);
226 m_model->setGlobalSelection(
false);
227 item->setSelected(
true);
228 newlySelectedItems.append(item);
229 m_lastDirectlySelectedItem = item;
231 if (item->getPointerType() == AbstractTreeItem::Point) {
232 foreach (AbstractTreeItem * child, item->getChildren()) {
233 child->setSelected(
true);
234 newlySelectedItems.append(child);
238 m_lastShiftSelection->clear();
242 emit treeSelectionChanged(newlySelectedItems);
247 m_model->setGlobalSelection(
false);
250 viewport()->update();
254 void TreeViewContent::mouseReleaseEvent(QMouseEvent *event) {
256 if (item && getArrowRect(item).contains(event->pos())) {
257 item->setExpanded(!item->isExpanded());
263 viewport()->update();
265 QWidget::mousePressEvent(event);
269 void TreeViewContent::mouseMoveEvent(QMouseEvent *event) {
270 QPoint cursorPos =
event->pos();
271 int index = cursorPos.y() / m_rowHeight;
273 m_hoveredItem->first = NULL;
274 m_hoveredItem->second =
false;
276 if (index < m_items->size() && index >= 0) {
277 AbstractTreeItem *item = (*m_items)[index];
278 if (item->isSelectable() ||
279 (item->getFirstVisibleChild() &&
280 getArrowRect(item).contains(cursorPos))) {
281 m_hoveredItem->first = item;
283 if (item->getFirstVisibleChild()) {
284 QRect arrowRect = getArrowRect(item);
285 m_hoveredItem->second = arrowRect.contains(cursorPos);
290 viewport()->update();
294 void TreeViewContent::leaveEvent(QEvent *event) {
295 m_hoveredItem->first = NULL;
296 m_hoveredItem->second =
false;
297 viewport()->update();
301 void TreeViewContent::keyPressEvent(QKeyEvent *event) {
302 if (event->key() == Qt::Key_A &&
303 event->modifiers() == Qt::ControlModifier) {
304 m_model->setGlobalSelection(
true);
305 viewport()->update();
306 emit treeSelectionChanged();
309 QWidget::keyPressEvent(event);
314 void TreeViewContent::paintEvent(QPaintEvent *event) {
316 int startRow = verticalScrollBar()->value();
317 int rowCount = (int) ceil(viewport()->height() / (double) m_rowHeight);
319 QPainter painter(viewport());
320 painter.setRenderHints(QPainter::Antialiasing |
321 QPainter::TextAntialiasing);
323 for (
int i = 0; i < rowCount; i++) {
327 QColor backgroundColor = palette().base().color();
329 if (i < m_items->size()) {
330 if (m_alternatingRowColors && (startRow + i) % 2 == 1)
331 backgroundColor = palette().alternateBase().color();
333 ASSERT(m_items->at(i));
334 if (m_items->at(i)->isSelected())
335 backgroundColor = palette().highlight().color();
339 QPoint relativeTopLeft(0, i * m_rowHeight);
340 QPoint scrollBarPos(horizontalScrollBar()->value(),
341 verticalScrollBar()->value());
342 QPoint absoluteTopLeft(relativeTopLeft + scrollBarPos);
343 QSize rowSize(viewport()->width(), (
int) m_rowHeight);
346 painter.fillRect(QRect(relativeTopLeft, rowSize), backgroundColor);
350 if (i < m_items->size() && m_hoveredItem->first == (*m_items)[i] &&
351 m_hoveredItem->first->isSelectable()) {
352 QPen prevPen(painter.pen());
353 QPen borderPen(prevPen);
354 borderPen.setWidth(1);
355 borderPen.setColor(palette().highlight().color());
356 painter.setPen(borderPen);
357 QPoint borderTopLeft(relativeTopLeft.x() - absoluteTopLeft.x(),
358 relativeTopLeft.y() + 1);
360 int rectWidth = qMax(m_contentWidth +
361 horizontalScrollBar()->singleStep(), viewport()->width());
362 QSize borderSize(rectWidth, rowSize.height() - 2);
363 painter.drawRect(QRect(borderTopLeft, borderSize));
364 painter.setPen(prevPen);
368 if (i < m_items->size())
369 paintItemText(&painter, i, absoluteTopLeft, relativeTopLeft);
373 QWidget::paintEvent(event);
378 void TreeViewContent::resizeEvent(QResizeEvent *event) {
379 QAbstractScrollArea::resizeEvent(event);
380 horizontalScrollBar()->setRange(0, m_contentWidth - viewport()->width()
381 + horizontalScrollBar()->singleStep());
386 void TreeViewContent::scrollContentsBy(
int dx,
int dy) {
387 QAbstractScrollArea::scrollContentsBy(dx, dy);
392 void TreeViewContent::nullify() {
397 m_hoveredItem = NULL;
398 m_lastDirectlySelectedItem = NULL;
399 m_lastShiftSelection = NULL;
400 m_mousePressPos = NULL;
404 void TreeViewContent::paintItemText(QPainter *painter,
405 int index, QPoint absolutePosition, QPoint relativePosition) {
407 ASSERT(index >= 0 && index < m_items->size());
409 QPoint point(-absolutePosition.x(), relativePosition.y());
411 AbstractTreeItem *item = (*m_items)[index];
425 AbstractTreeItem *iteratorItem = item;
426 while (iteratorItem->parent() && iteratorItem->parent()->parent()) {
427 point.setX(point.x() + ITEM_INDENTATION);
428 iteratorItem = iteratorItem->parent();
431 QPen originalPen = painter->pen();
432 if (item->isSelected()) {
433 painter->setPen(QPen(palette().highlightedText().color()));
439 if (item->getFirstVisibleChild()) {
442 QRect itemArrowRect(getArrowRect(item));
443 if (item == m_hoveredItem->first && item ==
m_pressedItem->first) {
445 QPainter::CompositionMode prevMode = painter->compositionMode();
446 painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
447 QColor color = palette().button().color().darker(160);
449 painter->fillRect(itemArrowRect, color);
450 painter->setCompositionMode(prevMode);
456 if ((item == m_hoveredItem->first && m_hoveredItem->second) ||
460 painter->drawRect(itemArrowRect);
465 if (item->isExpanded())
466 drawExpandedArrow(painter, itemArrowRect);
468 drawCollapsedArrow(painter, itemArrowRect);
473 point.setX(point.x() + ITEM_INDENTATION);
476 point.setY(point.y() + ITEM_PADDING / 2);
479 int textHeight = m_rowHeight - ITEM_PADDING;
480 QRect rect(point, QSize(viewport()->width() - point.x(), textHeight));
481 painter->drawText(rect, Qt::TextDontClip, item->getData().toString());
482 painter->setPen(originalPen);
487 void TreeViewContent::drawCollapsedArrow(QPainter *painter, QRect rect) {
488 rect.setTopLeft(rect.topLeft() + QPoint(4, 3));
489 rect.setBottomRight(rect.bottomRight() - QPoint(4, 2));
491 QPoint top(rect.topLeft());
492 QPoint bottom(rect.bottomLeft());
493 QPoint right(rect.right(), rect.center().y());
495 QPen prevPen = painter->pen();
496 QPen arrowPen(prevPen);
497 arrowPen.setCapStyle(Qt::RoundCap);
498 arrowPen.setJoinStyle(Qt::RoundJoin);
499 arrowPen.setWidth(2);
500 painter->setPen(arrowPen);
501 painter->drawLine(top, right);
502 painter->drawLine(bottom, right);
503 painter->setPen(prevPen);
507 void TreeViewContent::drawExpandedArrow(QPainter *painter, QRect rect) {
508 rect.setTopLeft(rect.topLeft() + QPoint(3, 4));
509 rect.setBottomRight(rect.bottomRight() - QPoint(2, 4));
511 QPoint left(rect.topLeft());
512 QPoint right(rect.topRight());
513 QPoint bottom(rect.center().x(), rect.bottom());
515 QPen prevPen = painter->pen();
516 QPen arrowPen(prevPen);
517 arrowPen.setCapStyle(Qt::RoundCap);
518 arrowPen.setJoinStyle(Qt::RoundJoin);
519 arrowPen.setWidth(2);
520 painter->setPen(arrowPen);
521 painter->drawLine(left, bottom);
522 painter->drawLine(right, bottom);
523 painter->setPen(prevPen);
527 void TreeViewContent::setAlternatingRowColors(
bool newStatus) {
528 m_alternatingRowColors = newStatus;
529 viewport()->update();
533 void TreeViewContent::updateItemList() {
534 int startRow = verticalScrollBar()->value();
535 int rowCount = (int) ceil(viewport()->height() / (double) m_rowHeight);
536 *m_items = m_model->getItems(startRow, startRow + rowCount,
537 AbstractTreeModel::AllItems,
false);
539 viewport()->update();
543 QRect TreeViewContent::getArrowRect(AbstractTreeItem *item)
const {
546 int index = m_items->indexOf(item);
547 QPoint centerOfArrow(12 - horizontalScrollBar()->value(),
548 (index * m_rowHeight) + (m_rowHeight / 2));
549 int depth = item->getDepth() - 1;
550 centerOfArrow.setX(centerOfArrow.x() + (depth * ITEM_INDENTATION));
552 arrowRect = QRect(centerOfArrow.x() - 6, centerOfArrow.y() - 6, 12, 12);
558 void TreeViewContent::scrollTo(
560 if (newlySelectedItems.size())
561 scrollTo(newlySelectedItems.last());
565 void TreeViewContent::scrollTo(AbstractTreeItem *newlySelectedItem) {
566 if (newlySelectedItem->getPointerType() == AbstractTreeItem::Measure)
567 newlySelectedItem->parent()->setExpanded(
true);
569 int row = getModel()->indexOfVisibleItem(newlySelectedItem);
572 int topRow = verticalScrollBar()->value();
575 verticalScrollBar()->setValue(row);
578 int wholeVisibleRowCount = viewport()->height() / m_rowHeight;
579 int bottomRow = topRow + wholeVisibleRowCount;
581 verticalScrollBar()->setValue(row - wholeVisibleRowCount + 1);
585 viewport()->update();