File indexing completed on 2024-05-19 05:08:30
0001 /* 0002 SPDX-FileCopyrightText: 2019 Thomas Baumgart <tbaumgart@kde.org> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "columnselector.h" 0007 0008 // ---------------------------------------------------------------------------- 0009 // QT Includes 0010 0011 #include <QList> 0012 #include <QHeaderView> 0013 #include <QMenu> 0014 #include <QPoint> 0015 #include <QDebug> 0016 0017 // ---------------------------------------------------------------------------- 0018 // KDE Includes 0019 0020 #include <KLocalizedString> 0021 #include <KSharedConfig> 0022 #include <KConfigGroup> 0023 0024 // ---------------------------------------------------------------------------- 0025 // Project Includes 0026 0027 #include "mymoneyenums.h" 0028 0029 /// @todo add feature to group multiple column selectors for the same view 0030 /// in different instances by group name. 0031 0032 class ColumnSelectorPrivate 0033 { 0034 Q_DECLARE_PUBLIC(ColumnSelector) 0035 0036 public: 0037 ColumnSelectorPrivate(ColumnSelector* qq) 0038 : q_ptr(qq) 0039 , treeView(nullptr) 0040 , tableView(nullptr) 0041 , headerView(nullptr) 0042 , model(nullptr) 0043 , storageOffset(0) 0044 , isInit(false) 0045 , columnSelectionEnabled(true) 0046 { 0047 } 0048 0049 void setColumnHidden(int col, bool state) 0050 { 0051 if (treeView) { 0052 treeView->setColumnHidden(col, state); 0053 } 0054 else if (tableView) { 0055 tableView->setColumnHidden(col, state); 0056 } 0057 } 0058 0059 bool isColumnHidden(int col) 0060 { 0061 if (treeView) { 0062 return treeView->isColumnHidden(col); 0063 } 0064 else if (tableView) { 0065 return tableView->isColumnHidden(col); 0066 } 0067 return false; 0068 } 0069 0070 void init(const QString& _configGroupName) 0071 { 0072 Q_Q(ColumnSelector); 0073 0074 configGroupName = _configGroupName; 0075 0076 if ((treeView || tableView) && model) { 0077 const auto maxColumn = model->columnCount(); 0078 QList<int> visibleColumns; 0079 0080 if (!configGroupName.isEmpty()) { 0081 // restore the headers when we have a group name 0082 const auto grp = KSharedConfig::openConfig()->group(configGroupName); 0083 const auto columnNames = grp.readEntry("HeaderState", QByteArray()); 0084 headerView->restoreState(columnNames); 0085 0086 visibleColumns = grp.readEntry<int>("ColumnsSelection", QList<int>()); 0087 // add the storage offset during loading operation 0088 for (auto &column : visibleColumns) { 0089 if (applyStorageOffsetColumns.contains(column + storageOffset)) { 0090 column += storageOffset; 0091 } 0092 } 0093 } 0094 0095 if (visibleColumns.isEmpty()) { 0096 // in case no column was marked as visible so far, all should 0097 for (int col = 0; col < maxColumn; ++col) { 0098 visibleColumns += col; 0099 } 0100 } 0101 0102 // now setup the initial visibility of the columns 0103 for (int col = 0; col < maxColumn; ++col) { 0104 if (alwaysHiddenColumns.contains(col)) { 0105 setColumnHidden(col, true); 0106 } else if (alwaysVisibleColumns.contains(col) || visibleColumns.contains(col)) { 0107 setColumnHidden(col, false); 0108 } else { 0109 setColumnHidden(col, true); 0110 } 0111 } 0112 0113 // allow context menu to be opened on tree header for columns selection 0114 headerView->setContextMenuPolicy(Qt::CustomContextMenu); 0115 0116 if (!isInit) { 0117 q->connect(headerView, &QWidget::customContextMenuRequested, q, &ColumnSelector::slotColumnsMenu); 0118 q->connect(headerView, &QHeaderView::sectionResized, q, &ColumnSelector::slotUpdateHeaderState); 0119 q->connect(headerView, &QHeaderView::sectionMoved, q, &ColumnSelector::slotUpdateHeaderState); 0120 isInit = true; 0121 } 0122 0123 } else if (!(treeView || tableView)) { 0124 qDebug() << "WARNING: You must not create a ColumnSelector without a view"; 0125 } 0126 } 0127 0128 ColumnSelector* q_ptr; 0129 0130 QTreeView* treeView; 0131 QTableView* tableView; 0132 QHeaderView* headerView; 0133 QAbstractItemModel* model; 0134 0135 QVector<int> selectableColumns; 0136 QVector<int> alwaysHiddenColumns; 0137 QVector<int> alwaysVisibleColumns; 0138 QVector<int> applyStorageOffsetColumns; 0139 QString configGroupName; 0140 0141 int storageOffset; 0142 bool isInit; 0143 bool columnSelectionEnabled; 0144 }; 0145 0146 0147 ColumnSelector::ColumnSelector(QTableView* view, const QString& configGroupName, int offset, const QVector<int>& columns) 0148 : d_ptr(new ColumnSelectorPrivate(this)) 0149 { 0150 Q_D(ColumnSelector); 0151 d->tableView = view; 0152 d->headerView = view->horizontalHeader(); 0153 d->model = view->model(); 0154 d->storageOffset = offset; 0155 d->applyStorageOffsetColumns = columns; 0156 d->init(configGroupName); 0157 } 0158 0159 ColumnSelector::ColumnSelector(QTreeView* view, const QString& configGroupName, int offset, const QVector<int>& columns) 0160 : d_ptr(new ColumnSelectorPrivate(this)) 0161 { 0162 Q_D(ColumnSelector); 0163 d->treeView = view; 0164 d->headerView = view->header(); 0165 d->model = view->model(); 0166 d->storageOffset = offset; 0167 d->applyStorageOffsetColumns = columns; 0168 d->init(configGroupName); 0169 } 0170 0171 ColumnSelector::~ColumnSelector() 0172 { 0173 Q_D(ColumnSelector); 0174 delete d; 0175 } 0176 0177 void ColumnSelector::slotUpdateHeaderState() 0178 { 0179 Q_D(ColumnSelector); 0180 if (!d->configGroupName.isEmpty()) { 0181 auto grp = KSharedConfig::openConfig()->group(d->configGroupName); 0182 grp.writeEntry("HeaderState", d->headerView->saveState()); 0183 grp.sync(); 0184 } 0185 } 0186 0187 void ColumnSelector::slotColumnsMenu(const QPoint) 0188 { 0189 Q_D(ColumnSelector); 0190 0191 if (!d->columnSelectionEnabled) { 0192 return; 0193 } 0194 0195 // create actions menu 0196 QList<QAction *> actions; 0197 const auto maxColumn = d->headerView->count(); 0198 0199 for (int col = 0; col < maxColumn; ++col) { 0200 if (d->alwaysHiddenColumns.contains(col)) 0201 continue; 0202 if (d->alwaysVisibleColumns.contains(col)) 0203 continue; 0204 if (!d->selectableColumns.isEmpty()) { 0205 if (!d->selectableColumns.contains(col)) { 0206 continue; 0207 } 0208 } 0209 auto a = new QAction(nullptr); 0210 a->setObjectName(QString::number(col)); 0211 a->setText(d->model->headerData(col, Qt::Horizontal, eMyMoney::Model::LongDisplayRole).toString()); 0212 a->setCheckable(true); 0213 a->setChecked(!d->isColumnHidden(col)); 0214 actions.append(a); 0215 } 0216 0217 // if there are any actions present menu 0218 if (!actions.isEmpty()) { 0219 QMenu menu(i18n("Displayed columns")); 0220 menu.addActions(actions); 0221 0222 // execute menu and get result 0223 const auto retAction = menu.exec(QCursor::pos()); 0224 if (retAction) { 0225 d->setColumnHidden(retAction->objectName().toInt(), !retAction->isChecked()); 0226 0227 QList<int> visibleColumns; 0228 0229 for (int col = 0; col < maxColumn; ++col) { 0230 if (d->alwaysHiddenColumns.contains(col)) 0231 continue; 0232 // in case a column is always visible, we 0233 // add it to the list for backward compatibility 0234 if (!d->alwaysVisibleColumns.contains(col)) { 0235 if (!d->selectableColumns.isEmpty() && !d->selectableColumns.contains(col)) 0236 continue; 0237 } 0238 if (!d->isColumnHidden(col)) { 0239 visibleColumns.append(col); 0240 } 0241 } 0242 if (!d->configGroupName.isEmpty()) { 0243 auto grp = KSharedConfig::openConfig()->group(d->configGroupName); 0244 // subtract offset during storage operation 0245 for (auto &column : visibleColumns) { 0246 if (d->applyStorageOffsetColumns.contains(column)) { 0247 column -= d->storageOffset; 0248 } 0249 } 0250 grp.writeEntry("ColumnsSelection", visibleColumns); 0251 } 0252 0253 // do this as last statement as it contains the sync of the grp 0254 slotUpdateHeaderState(); 0255 Q_EMIT columnsChanged(); 0256 } 0257 } 0258 } 0259 0260 void ColumnSelector::setAlwaysHidden(QVector<int> columns) 0261 { 0262 Q_D(ColumnSelector); 0263 0264 d->alwaysHiddenColumns = columns; 0265 for (int i = 0; i < columns.count(); ++i) { 0266 auto col = columns.at(i); 0267 d->setColumnHidden(col, true); 0268 d->alwaysVisibleColumns.removeAll(col); 0269 } 0270 } 0271 0272 void ColumnSelector::setAlwaysVisible(QVector<int> columns) 0273 { 0274 Q_D(ColumnSelector); 0275 0276 d->alwaysVisibleColumns = columns; 0277 for (int i = 0; i < columns.count(); ++i) { 0278 auto col = columns.at(i); 0279 d->setColumnHidden(col, false); 0280 d->alwaysHiddenColumns.removeAll(col); 0281 } 0282 } 0283 0284 void ColumnSelector::setSelectable(QVector<int> columns) 0285 { 0286 Q_D(ColumnSelector); 0287 0288 d->selectableColumns = columns; 0289 } 0290 0291 void ColumnSelector::setModel(QAbstractItemModel* model) 0292 { 0293 Q_D(ColumnSelector); 0294 d->model = model; 0295 d->init(d->configGroupName); 0296 } 0297 0298 QVector<int> ColumnSelector::columns() const 0299 { 0300 Q_D(const ColumnSelector); 0301 0302 QVector<int> columns; 0303 const auto maxColumn = d->headerView->count(); 0304 0305 for (int col = 0; col < maxColumn; ++col) { 0306 columns.append(col); 0307 } 0308 return columns; 0309 } 0310 0311 const QString& ColumnSelector::configGroupName() const 0312 { 0313 Q_D(const ColumnSelector); 0314 return d->configGroupName; 0315 } 0316 0317 void ColumnSelector::setColumnSelectionEnabled() 0318 { 0319 Q_D(ColumnSelector); 0320 d->columnSelectionEnabled = true; 0321 } 0322 0323 void ColumnSelector::setColumnSelectionDisabled() 0324 { 0325 Q_D(ColumnSelector); 0326 d->columnSelectionEnabled = false; 0327 }