File indexing completed on 2024-04-28 17:06:04

0001 /*
0002     SPDX-FileCopyrightText: 2008 Csaba Karai <krusader@users.sourceforge.net>
0003     SPDX-FileCopyrightText: 2008-2022 Krusader Krew <https://krusader.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "krtreewidget.h"
0009 #include "../compat.h"
0010 #include "krstyleproxy.h"
0011 
0012 // QtGui
0013 #include <QContextMenuEvent>
0014 // QtWidgets
0015 #include <QApplication>
0016 #include <QHeaderView>
0017 #include <QStyleOptionViewItem>
0018 #include <QToolTip>
0019 
0020 KrTreeWidget::KrTreeWidget(QWidget *parent)
0021     : QTreeWidget(parent)
0022     , _inResize(false)
0023 {
0024     setRootIsDecorated(false);
0025     setSortingEnabled(true);
0026     setAllColumnsShowFocus(true);
0027 
0028     _stretchingColumn = -1;
0029 
0030     auto *krstyle = new KrStyleProxy();
0031     krstyle->setParent(this);
0032     setStyle(krstyle);
0033 }
0034 
0035 bool KrTreeWidget::event(QEvent *event)
0036 {
0037     switch (event->type()) {
0038         // HACK: QT 4 Context menu key isn't handled properly
0039     case QEvent::ContextMenu: {
0040         auto *ce = dynamic_cast<QContextMenuEvent *>(event);
0041 
0042         if (ce->reason() == QContextMenuEvent::Mouse) {
0043             QPoint pos = viewport()->mapFromGlobal(ce->globalPos());
0044 
0045             QTreeWidgetItem *item = itemAt(pos);
0046             int column = columnAt(pos.x());
0047 
0048             emit itemRightClicked(item, ce->globalPos(), column);
0049             return true;
0050         } else {
0051             if (currentItem()) {
0052                 QRect r = visualItemRect(currentItem());
0053                 QPoint p = viewport()->mapToGlobal(QPoint(r.x() + 5, r.y() + 5));
0054 
0055                 emit itemRightClicked(currentItem(), p, currentColumn());
0056                 return true;
0057             }
0058         }
0059     } break;
0060     case QEvent::KeyPress: {
0061         // HACK: QT 4 Ctrl+A bug fix: Ctrl+A doesn't work if QTreeWidget contains parent / child items
0062         //       Insert doesn't change the selections for multi selection modes
0063         auto *ke = dynamic_cast<QKeyEvent *>(event);
0064         switch (ke->key()) {
0065         case Qt::Key_Insert: {
0066             if (ke->modifiers() != 0)
0067                 break;
0068 
0069             QAbstractItemView::SelectionMode mode = selectionMode();
0070 
0071             if (mode != QAbstractItemView::ContiguousSelection && mode != QAbstractItemView::ExtendedSelection && mode != QAbstractItemView::MultiSelection)
0072                 break;
0073 
0074             ke->accept();
0075 
0076             if (currentItem() == nullptr)
0077                 return true;
0078 
0079             currentItem()->setSelected(!currentItem()->isSelected());
0080             return true;
0081         }
0082         case Qt::Key_A:
0083             if (ke->modifiers() == Qt::ControlModifier) {
0084                 QAbstractItemView::SelectionMode mode = selectionMode();
0085 
0086                 if (mode == QAbstractItemView::ContiguousSelection || mode == QAbstractItemView::ExtendedSelection
0087                     || mode == QAbstractItemView::MultiSelection) {
0088                     selectAll();
0089                     ke->accept();
0090                     return true;
0091                 }
0092             }
0093             break;
0094         default:
0095             break;
0096         }
0097     } break;
0098     case QEvent::Resize: {
0099         auto *re = dynamic_cast<QResizeEvent *>(event);
0100         if (!_inResize && re->oldSize() != re->size()) {
0101             if (_stretchingColumn != -1 && columnCount()) {
0102                 QList<int> columnsSizes;
0103                 int oldSize = 0;
0104 
0105                 for (int i = 0; i != header()->count(); i++) {
0106                     columnsSizes.append(header()->sectionSize(i));
0107                     oldSize += header()->sectionSize(i);
0108                 }
0109 
0110                 bool res = QTreeWidget::event(event);
0111 
0112                 int newSize = viewport()->width();
0113                 int delta = newSize - oldSize;
0114 
0115                 if (delta) {
0116                     _inResize = true;
0117 
0118                     for (int i = 0; i != header()->count(); i++) {
0119                         if (i == _stretchingColumn) {
0120                             int newNs = columnsSizes[i] + delta;
0121                             if (newNs < 8)
0122                                 newNs = 8;
0123                             header()->resizeSection(i, newNs);
0124                         } else if (header()->sectionSize(i) != columnsSizes[i]) {
0125                             header()->resizeSection(i, columnsSizes[i]);
0126                         }
0127                     }
0128                     _inResize = false;
0129                 }
0130                 return res;
0131             }
0132         }
0133         break;
0134     }
0135     case QEvent::ToolTip: {
0136         auto *he = dynamic_cast<QHelpEvent *>(event);
0137 
0138         if (viewport()) {
0139             QPoint pos = viewport()->mapFromGlobal(he->globalPos());
0140 
0141             QTreeWidgetItem *item = itemAt(pos);
0142 
0143             int column = columnAt(pos.x());
0144 
0145             if (item) {
0146                 if (!item->toolTip(column).isEmpty())
0147                     break;
0148 
0149                 QString tip = item->text(column);
0150 
0151                 int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
0152                 int requiredWidth = QFontMetrics(font()).horizontalAdvance(tip) + 2 * textMargin;
0153 
0154                 if (column == 0 && indentation()) {
0155                     int level = 0;
0156 
0157                     QTreeWidgetItem *parent = item;
0158 
0159                     while ((parent = parent->parent()))
0160                         level++;
0161 
0162                     if (rootIsDecorated())
0163                         level++;
0164 
0165                     requiredWidth += level * indentation();
0166                 }
0167 
0168                 QIcon icon = item->icon(column);
0169                 if (!icon.isNull()) {
0170                     QStyleOptionViewItem opts = viewOptions();
0171                     QSize iconSize = icon.actualSize(opts.decorationSize);
0172                     requiredWidth += iconSize.width();
0173 
0174                     int pixmapMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr, this) + 1;
0175                     requiredWidth += 2 * pixmapMargin;
0176                 }
0177 
0178                 if (!tip.isEmpty() && (columnWidth(column) < requiredWidth))
0179                     QToolTip::showText(he->globalPos(), tip, this);
0180                 return true;
0181             }
0182         }
0183     } break;
0184     default:
0185         break;
0186     }
0187     return QTreeWidget::event(event);
0188 }