Warning, file /office/skrooge/skgbasegui/skgfilteredtableview.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /*************************************************************************** 0002 * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr 0003 * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 ***************************************************************************/ 0006 /** @file 0007 * filetered SKGTableView. 0008 * 0009 * @author Stephane MANKOWSKI / Guillaume DE BURE 0010 */ 0011 #include "skgfilteredtableview.h" 0012 0013 #include <qdom.h> 0014 #include <qlineedit.h> 0015 0016 #include "skgmainpanel.h" 0017 #include "skgobjectmodelbase.h" 0018 #include "skgsortfilterproxymodel.h" 0019 0020 SKGFilteredTableView::SKGFilteredTableView(QWidget* iParent) 0021 : QWidget(iParent), m_objectModel(nullptr), m_refreshNeeded(true) 0022 { 0023 ui.setupUi(this); 0024 ui.kTitle->hide(); 0025 ui.kResetInternalFilter->hide(); 0026 connect(ui.kResetInternalFilter, &QToolButton::clicked, this, &SKGFilteredTableView::resetFilter); 0027 ui.kResetInternalFilter->setIcon(SKGServices::fromTheme(QStringLiteral("dialog-cancel"))); 0028 ui.kConfigure->setIcon(SKGServices::fromTheme(QStringLiteral("configure"))); 0029 0030 ui.kConfigure->setPopupMode(QToolButton::InstantPopup); 0031 ui.kConfigure->setAutoRaise(true); 0032 ui.kConfigure->setMenu(ui.kView->getHeaderMenu()); 0033 0034 m_timer.setSingleShot(true); 0035 connect(&m_timer, &QTimer::timeout, this, &SKGFilteredTableView::onTextFilterChanged, Qt::QueuedConnection); 0036 connect(ui.kFilterEdit, &QLineEdit::textChanged, this, [ = ]() { 0037 m_timer.start(300); 0038 }); 0039 connect(ui.kShow, &SKGShow::stateChanged, this, &SKGFilteredTableView::onFilterChanged, Qt::QueuedConnection); 0040 if (SKGMainPanel::getMainPanel() != nullptr) { 0041 connect(SKGMainPanel::getMainPanel(), &SKGMainPanel::currentPageChanged, this, &SKGFilteredTableView::pageChanged, Qt::QueuedConnection); 0042 } 0043 } 0044 0045 SKGFilteredTableView::~SKGFilteredTableView() 0046 { 0047 m_objectModel = nullptr; 0048 } 0049 0050 QString SKGFilteredTableView::getState() 0051 { 0052 QDomDocument doc(QStringLiteral("SKGML")); 0053 QDomElement root = doc.createElement(QStringLiteral("parameters")); 0054 doc.appendChild(root); 0055 0056 root.setAttribute(QStringLiteral("show"), ui.kShow->getState()); 0057 root.setAttribute(QStringLiteral("filter"), getSearchField()->text()); 0058 0059 // Memorize table settings 0060 root.setAttribute(QStringLiteral("view"), ui.kView->getState()); 0061 return doc.toString(); 0062 } 0063 0064 void SKGFilteredTableView::setState(const QString& iState) 0065 { 0066 QDomDocument doc(QStringLiteral("SKGML")); 0067 doc.setContent(iState); 0068 QDomElement root = doc.documentElement(); 0069 0070 QString show2 = root.attribute(QStringLiteral("show")); 0071 QString filter = root.attribute(QStringLiteral("filter")); 0072 0073 if (!show2.isEmpty()) { 0074 ui.kShow->setState(show2); 0075 } 0076 getSearchField()->setText(filter); 0077 0078 if (m_objectModel != nullptr) { 0079 bool previous = m_objectModel->blockRefresh(true); 0080 onFilterChanged(); 0081 m_objectModel->blockRefresh(previous); 0082 } 0083 0084 // !!! Must be done here after onFilterChanged 0085 ui.kView->setState(root.attribute(QStringLiteral("view"))); 0086 } 0087 0088 SKGShow* SKGFilteredTableView::getShowWidget() const 0089 { 0090 return ui.kShow; 0091 } 0092 0093 SKGTreeView* SKGFilteredTableView::getView() const 0094 { 0095 return ui.kView; 0096 } 0097 0098 QLineEdit* SKGFilteredTableView::getSearchField() const 0099 { 0100 return ui.kFilterEdit; 0101 } 0102 0103 void SKGFilteredTableView::onFilterChanged() 0104 { 0105 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 0106 0107 // Update model 0108 if ((m_objectModel != nullptr) && ui.kShow->isEnabled() && m_objectModel->setFilter(ui.kShow->getWhereClause())) { 0109 m_objectModel->dataModified(); 0110 } 0111 0112 QApplication::restoreOverrideCursor(); 0113 } 0114 0115 void SKGFilteredTableView::pageChanged() 0116 { 0117 if (m_refreshNeeded) { 0118 dataModified(QLatin1String(""), 0); 0119 } 0120 } 0121 0122 void SKGFilteredTableView::dataModified(const QString& iTableName, int iIdTransaction) 0123 { 0124 Q_UNUSED(iIdTransaction) 0125 0126 if (((m_objectModel != nullptr) && iTableName == m_objectModel->getTable()) || iTableName.isEmpty()) { 0127 SKGTabPage* page = SKGTabPage::parentTabPage(this); 0128 if (page != nullptr && SKGMainPanel::getMainPanel() != nullptr && page != SKGMainPanel::getMainPanel()->currentPage()) { 0129 m_refreshNeeded = true; 0130 return; 0131 } 0132 m_refreshNeeded = false; 0133 0134 if (getView()->isAutoResized()) { 0135 getView()->resizeColumnsToContentsDelayed(); 0136 } 0137 0138 getView()->onSelectionChanged(); 0139 } 0140 } 0141 0142 void SKGFilteredTableView::setModel(SKGObjectModelBase* iModel) 0143 { 0144 m_objectModel = iModel; 0145 if (m_objectModel != nullptr) { 0146 auto modelProxy = new SKGSortFilterProxyModel(this); 0147 modelProxy->setSourceModel(m_objectModel); 0148 modelProxy->setSortRole(Qt::UserRole); 0149 modelProxy->setDynamicSortFilter(true); 0150 0151 connect(modelProxy, &SKGSortFilterProxyModel::rowsInserted, ui.kView, &SKGTreeView::scroolOnSelection); 0152 ui.kView->setModel(modelProxy); 0153 0154 onTextFilterChanged(); 0155 0156 ui.kView->sortByColumn(0, Qt::AscendingOrder); 0157 connect(m_objectModel, &SKGObjectModelBase::beforeReset, ui.kView, &SKGTreeView::saveSelection); 0158 connect(m_objectModel, &SKGObjectModelBase::afterReset, ui.kView, &SKGTreeView::resetSelection); 0159 connect(m_objectModel->getDocument(), &SKGDocument::tableModified, this, &SKGFilteredTableView::dataModified, Qt::QueuedConnection); 0160 } 0161 dataModified(QLatin1String(""), 0); 0162 } 0163 0164 void SKGFilteredTableView::resetFilter() 0165 { 0166 getShowWidget()->setEnabled(true); 0167 ui.kTitle->hide(); 0168 ui.kResetInternalFilter->hide(); 0169 0170 m_objectModel->setFilter(QLatin1String("")); 0171 m_objectModel->refresh(); 0172 } 0173 0174 void SKGFilteredTableView::setFilter(const QIcon& iIcon, const QString& iText, const QString& iWhereClause) 0175 { 0176 if ((m_objectModel != nullptr) && !iWhereClause.isEmpty()) { 0177 getShowWidget()->setEnabled(false); 0178 0179 QFontMetrics fm(fontMetrics()); 0180 ui.kTitle->setComment("<html><body><b>" % SKGServices::stringToHtml(fm.elidedText(iText, Qt::ElideMiddle, 2000)) % "</b></body></html>"); 0181 ui.kTitle->setToolTip(iText); 0182 ui.kResetInternalFilter->show(); 0183 0184 ui.kTitle->setIcon(iIcon, KTitleWidget::ImageLeft); 0185 0186 m_objectModel->setFilter(iWhereClause); 0187 m_objectModel->refresh(); 0188 } 0189 } 0190 0191 void SKGFilteredTableView::onTextFilterChanged() 0192 { 0193 auto filter = ui.kFilterEdit->text(); 0194 auto modelProxy = qobject_cast<SKGSortFilterProxyModel*>(ui.kView->model()); 0195 if (modelProxy != nullptr) { 0196 modelProxy->setFilterKeyColumn(-1); 0197 modelProxy->setFilterCaseSensitivity(Qt::CaseInsensitive); 0198 modelProxy->setFilterFixedString(filter); 0199 0200 QStringList attributes; 0201 QAbstractItemModel* model = modelProxy->sourceModel(); 0202 if (model != nullptr) { 0203 int nbcol = model->columnCount(); 0204 attributes.reserve(nbcol); 0205 for (int j = 0; j < nbcol; ++j) { 0206 attributes.append(model->headerData(j, Qt::Horizontal).toString()); 0207 } 0208 } 0209 auto tooltip = i18nc("Tooltip", "<html><head/><body><p>Searching is case-insensitive. So table, Table, and TABLE are all the same.<br/>" 0210 "If you just put a word or series of words in the search box, the application will filter the table to keep all lines having these words (logical operator AND). <br/>" 0211 "If you want to add (logical operator OR) some lines, you must prefix your word by '+'.<br/>" 0212 "If you want to remove (logical operator NOT) some lines, you must prefix your word by '-'.<br/>" 0213 "If you want to search only on some columns, you must prefix your word by the beginning of column name like: col1:word.<br/>" 0214 "If you want to search only on one column, you must prefix your word by the column name and a dot like: col1.:word.<br/>" 0215 "If you want to use the character ':' in value, you must specify the column name like this: col1:value:rest.<br/>" 0216 "If you want to search for a phrase or something that contains spaces, you must put it in quotes, like: 'yes, this is a phrase'.</p>" 0217 "<p>You can also use operators '<', '>', '<=', '>=', '=' and '#' (for regular expression).</p>" 0218 "<p><span style=\"font-weight:600; text-decoration: underline;\">Examples:</span><br/>" 0219 "+val1 +val2 => Keep lines containing val1 OR val2<br/>" 0220 "+val1 -val2 => Keep lines containing val1 but NOT val2<br/>" 0221 "'abc def' => Keep lines containing the sentence 'abc def' <br/>" 0222 "'-att:abc def' => Remove lines having a column name starting by abc and containing 'abc def' <br/>" 0223 "abc:def => Keep lines having a column name starting by abc and containing def<br/>" 0224 ":abc:def => Keep lines containing 'abc:def'<br/>" 0225 "Date>2015-03-01 => Keep lines where at least one attribute starting by Date is greater than 2015-03-01<br/>" 0226 "Date.>2015-03-01 => Keep lines where at the Date attribute is greater than 2015-03-01<br/>" 0227 "Amount<10 =>Keep lines where at least one attribute starting by Amount is less than 10<br/>" 0228 "Amount=10 =>Keep lines where at least one attribute starting by Amount is equal to 10<br/>" 0229 "Amount<=10 =>Keep lines where at least one attribute starting by Amount is less or equal to 10<br/>" 0230 "abc#^d.*f$ => Keep lines having a column name starting by abc and matching the regular expression ^d.*f$</p>" 0231 "<span style=\"font-weight:600; text-decoration: underline;\">Your filter is understood like this:</span><br/>" 0232 "%1</body></html>", SKGServices::searchCriteriasToWhereClause(SKGServices::stringToSearchCriterias(filter), attributes, m_objectModel->getDocument(), true)); 0233 ui.kFilterEdit->setToolTip(tooltip); 0234 } 0235 }