File indexing completed on 2024-06-16 04:51:16
0001 /* 0002 This file is part of KOrganizer. 0003 0004 SPDX-FileCopyrightText: 2008 Thomas Thrainer <tom_t@gmx.at> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0 0007 */ 0008 0009 #include "todoviewview.h" 0010 0011 #include <KDatePickerPopup> 0012 #include <KLocalizedString> 0013 #include <QMenu> 0014 0015 #include <QAction> 0016 #include <QContextMenuEvent> 0017 #include <QEvent> 0018 #include <QHeaderView> 0019 #include <QMouseEvent> 0020 #include <chrono> 0021 0022 using namespace std::chrono_literals; 0023 0024 TodoViewView::TodoViewView(QWidget *parent) 0025 : QTreeView(parent) 0026 { 0027 header()->installEventFilter(this); 0028 setAlternatingRowColors(true); 0029 connect(&mExpandTimer, &QTimer::timeout, this, &TodoViewView::expandParent); 0030 mExpandTimer.setInterval(1s); 0031 header()->setStretchLastSection(false); 0032 mStartPopupMenu = new KDatePickerPopup(KDatePickerPopup::NoDate | KDatePickerPopup::DatePicker | KDatePickerPopup::Words, QDate::currentDate(), this); 0033 } 0034 0035 bool TodoViewView::isEditing(const QModelIndex &index) const 0036 { 0037 return state() & QAbstractItemView::EditingState && currentIndex() == index; 0038 } 0039 0040 bool TodoViewView::eventFilter(QObject *watched, QEvent *event) 0041 { 0042 Q_UNUSED(watched) 0043 if (event->type() == QEvent::ContextMenu) { 0044 auto e = static_cast<QContextMenuEvent *>(event); 0045 0046 if (!mHeaderPopup) { 0047 mHeaderPopup = new QMenu(this); 0048 mHeaderPopup->setTitle(i18n("View Columns")); 0049 // First entry can't be disabled 0050 for (int i = 1; i < model()->columnCount(); ++i) { 0051 QAction *tmp = mHeaderPopup->addAction(model()->headerData(i, Qt::Horizontal).toString()); 0052 tmp->setData(QVariant(i)); 0053 tmp->setCheckable(true); 0054 mColumnActions << tmp; 0055 } 0056 0057 connect(mHeaderPopup, &QMenu::triggered, this, &TodoViewView::toggleColumnHidden); 0058 } 0059 0060 for (QAction *action : std::as_const(mColumnActions)) { 0061 int column = action->data().toInt(); 0062 action->setChecked(!isColumnHidden(column)); 0063 } 0064 0065 mHeaderPopup->popup(mapToGlobal(e->pos())); 0066 return true; 0067 } 0068 0069 return false; 0070 } 0071 0072 KDatePickerPopup *TodoViewView::startPopupMenu() 0073 { 0074 return mStartPopupMenu; 0075 } 0076 0077 void TodoViewView::toggleColumnHidden(QAction *action) 0078 { 0079 if (action->isChecked()) { 0080 showColumn(action->data().toInt()); 0081 } else { 0082 hideColumn(action->data().toInt()); 0083 } 0084 0085 Q_EMIT visibleColumnCountChanged(); 0086 } 0087 0088 QModelIndex TodoViewView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) 0089 { 0090 QModelIndex current = currentIndex(); 0091 if (!current.isValid()) { 0092 return QTreeView::moveCursor(cursorAction, modifiers); 0093 } 0094 0095 switch (cursorAction) { 0096 case MoveNext: { 0097 // try to find an editable item right of the current one 0098 QModelIndex tmp = getNextEditableIndex(current.sibling(current.row(), current.column() + 1), 1); 0099 if (tmp.isValid()) { 0100 return tmp; 0101 } 0102 0103 // check if the current item is expanded, and find an editable item 0104 // just below it if so 0105 current = current.sibling(current.row(), 0); 0106 if (isExpanded(current)) { 0107 tmp = getNextEditableIndex(model()->index(0, 0, current), 1); 0108 if (tmp.isValid()) { 0109 return tmp; 0110 } 0111 } 0112 0113 // find an editable item in the item below the currently edited one 0114 tmp = getNextEditableIndex(current.sibling(current.row() + 1, 0), 1); 0115 if (tmp.isValid()) { 0116 return tmp; 0117 } 0118 0119 // step back a hierarchy level, and search for an editable item there 0120 while (current.isValid()) { 0121 current = current.parent(); 0122 tmp = getNextEditableIndex(current.sibling(current.row() + 1, 0), 1); 0123 if (tmp.isValid()) { 0124 return tmp; 0125 } 0126 } 0127 return {}; 0128 } 0129 case MovePrevious: { 0130 // try to find an editable item left of the current one 0131 QModelIndex tmp = getNextEditableIndex(current.sibling(current.row(), current.column() - 1), -1); 0132 if (tmp.isValid()) { 0133 return tmp; 0134 } 0135 0136 int lastCol = model()->columnCount(QModelIndex()) - 1; 0137 0138 // search on top of the item, also include expanded items 0139 tmp = current.sibling(current.row() - 1, 0); 0140 while (tmp.isValid() && isExpanded(tmp)) { 0141 tmp = model()->index(model()->rowCount(tmp) - 1, 0, tmp); 0142 } 0143 if (tmp.isValid()) { 0144 tmp = getNextEditableIndex(tmp.sibling(tmp.row(), lastCol), -1); 0145 if (tmp.isValid()) { 0146 return tmp; 0147 } 0148 } 0149 0150 // step back a hierarchy level, and search for an editable item there 0151 current = current.parent(); 0152 return getNextEditableIndex(current.sibling(current.row(), lastCol), -1); 0153 } 0154 default: 0155 break; 0156 } 0157 0158 return QTreeView::moveCursor(cursorAction, modifiers); 0159 } 0160 0161 QModelIndex TodoViewView::getNextEditableIndex(const QModelIndex &cur, int inc) 0162 { 0163 if (!cur.isValid()) { 0164 return {}; 0165 } 0166 0167 QModelIndex tmp; 0168 int colCount = model()->columnCount(QModelIndex()); 0169 int end = inc == 1 ? colCount : -1; 0170 0171 for (int c = cur.column(); c != end; c += inc) { 0172 tmp = cur.sibling(cur.row(), c); 0173 if ((tmp.flags() & Qt::ItemIsEditable) && !isIndexHidden(tmp)) { 0174 return tmp; 0175 } 0176 } 0177 return {}; 0178 } 0179 0180 void TodoViewView::mouseReleaseEvent(QMouseEvent *event) 0181 { 0182 mExpandTimer.stop(); 0183 0184 if (mIgnoreNextMouseRelease) { 0185 mIgnoreNextMouseRelease = false; 0186 return; 0187 } 0188 0189 if (!indexAt(event->pos()).isValid()) { 0190 clearSelection(); 0191 event->accept(); 0192 } else { 0193 QTreeView::mouseReleaseEvent(event); 0194 } 0195 } 0196 0197 void TodoViewView::mouseMoveEvent(QMouseEvent *event) 0198 { 0199 mExpandTimer.stop(); 0200 QTreeView::mouseMoveEvent(event); 0201 } 0202 0203 void TodoViewView::mousePressEvent(QMouseEvent *event) 0204 { 0205 mExpandTimer.stop(); 0206 QModelIndex index = indexAt(event->pos()); 0207 if (index.isValid() && event->button() == Qt::LeftButton) { 0208 mExpandTimer.start(); 0209 } 0210 0211 QTreeView::mousePressEvent(event); 0212 } 0213 0214 void TodoViewView::expandParent() 0215 { 0216 QModelIndex index = indexAt(viewport()->mapFromGlobal(QCursor::pos())); 0217 if (index.isValid()) { 0218 mIgnoreNextMouseRelease = true; 0219 QKeyEvent keyEvent = QKeyEvent(QEvent::KeyPress, Qt::Key_Asterisk, Qt::NoModifier); 0220 QTreeView::keyPressEvent(&keyEvent); 0221 } 0222 } 0223 0224 #include "moc_todoviewview.cpp"