Warning, file /office/skrooge/skgbasegui/skgobjectmodelbase.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 * This file defines classes SKGObjectModelBase. 0008 * 0009 * @author Stephane MANKOWSKI / Guillaume DE BURE 0010 */ 0011 #include "skgobjectmodelbase.h" 0012 0013 #include <kcolorscheme.h> 0014 #include <kformat.h> 0015 #include <klocalizedstring.h> 0016 0017 #include <qapplication.h> 0018 #include <qcolor.h> 0019 #include <qdir.h> 0020 #include <qicon.h> 0021 #include <qmimedata.h> 0022 0023 #include "skgdocument.h" 0024 #include "skgmainpanel.h" 0025 #include "skgnodeobject.h" 0026 #include "skgpropertyobject.h" 0027 #include "skgtraces.h" 0028 #include "skgtransactionmng.h" 0029 0030 SKGObjectModelBase::SKGObjectModelBase(SKGDocument* iDocument, 0031 const QString& iTable, 0032 QString iWhereClause, 0033 QWidget* iParent, 0034 QString iParentAttribute, 0035 bool iResetOnCreation) 0036 : QAbstractItemModel(iParent), m_isResetRealyNeeded(iResetOnCreation), m_cache(new QMap<QString, QVariant>()), m_document(iDocument), 0037 m_whereClause(std::move(iWhereClause)), 0038 m_parentAttribute(std::move(iParentAttribute)), 0039 m_doctransactionTable(false), m_nodeTable(false), m_parametersTable(false), 0040 m_refreshBlocked(false) 0041 { 0042 SKGTRACEINFUNC(1) 0043 0044 setTable(iTable); 0045 0046 connect(m_document, &SKGDocument::tableModified, this, &SKGObjectModelBase::dataModified); 0047 if (SKGMainPanel::getMainPanel() != nullptr) { 0048 connect(SKGMainPanel::getMainPanel(), &SKGMainPanel::currentPageChanged, this, &SKGObjectModelBase::pageChanged, Qt::QueuedConnection); 0049 } 0050 } 0051 0052 SKGObjectModelBase::~SKGObjectModelBase() 0053 { 0054 SKGTRACEINFUNC(1) 0055 clear(); 0056 m_document = nullptr; 0057 delete m_cache; 0058 m_cache = nullptr; 0059 } 0060 0061 void SKGObjectModelBase::clear() 0062 { 0063 SKGTRACEINFUNC(1) 0064 QHashIterator<int, SKGObjectBase*> i(m_objectsHashTable); 0065 while (i.hasNext()) { 0066 i.next(); 0067 SKGObjectBase* val = i.value(); 0068 delete val; 0069 val = nullptr; 0070 } 0071 0072 m_listObjects.clear(); 0073 m_parentChildRelations.clear(); 0074 m_childParentRelations.clear(); 0075 m_objectsHashTable.clear(); 0076 m_objectsHashTableRows.clear(); 0077 } 0078 0079 SKGDocument::SKGModelTemplateList SKGObjectModelBase::getSchemas() const 0080 { 0081 return m_listSchema; 0082 } 0083 0084 void SKGObjectModelBase::setSupportedAttributes(const QStringList& iListAttribute) 0085 { 0086 SKGTRACEINFUNC(1) 0087 m_listSupported.clear(); 0088 m_listVisibility.clear(); 0089 m_listSize.clear(); 0090 0091 QStringList l = iListAttribute; 0092 if (!m_listSchema.isEmpty()) { 0093 l += SKGServices::splitCSVLine(m_listSchema.at(0).schema); 0094 } 0095 0096 QStringList attributesAvailablesTmp; 0097 if (!m_listSchema.isEmpty()) { 0098 attributesAvailablesTmp = SKGServices::splitCSVLine(m_listSchema.at(0).schema); 0099 } 0100 int nb = attributesAvailablesTmp.count(); 0101 QStringList attributesAvailables; 0102 attributesAvailables.reserve(nb); 0103 for (int i = 0; i < nb; ++i) { 0104 attributesAvailables.push_back(attributesAvailablesTmp.at(i).split('|').at(0)); 0105 } 0106 0107 nb = l.count(); 0108 for (int i = 0; i < nb; ++i) { 0109 QStringList values = l.at(i).split('|'); 0110 int nbValues = values.count(); 0111 const QString& att = values.at(0); 0112 0113 if (nbValues > 0 && !m_listSupported.contains(att) && attributesAvailables.contains(att)) { 0114 m_listSupported.push_back(att); 0115 bool visible = true; 0116 if (nbValues > 1) { 0117 visible = (i == 0 || values.at(1) == QStringLiteral("Y")); // First column is always visible to support grouping 0118 } 0119 m_listVisibility.push_back(visible); 0120 if (nbValues > 2) { 0121 m_listSize.push_back(SKGServices::stringToInt(values.at(2))); 0122 } else { 0123 m_listSize.push_back(-1); 0124 } 0125 } 0126 } 0127 0128 m_isResetRealyNeeded = true; 0129 } 0130 0131 bool SKGObjectModelBase::setFilter(const QString& iWhereClause) 0132 { 0133 if (iWhereClause != m_whereClause) { 0134 m_isResetRealyNeeded = true; 0135 } 0136 m_whereClause = iWhereClause; 0137 return m_isResetRealyNeeded; 0138 } 0139 0140 void SKGObjectModelBase::setTable(const QString& iTable) 0141 { 0142 if (iTable != m_table) { 0143 if (!m_table.isEmpty()) { 0144 m_isResetRealyNeeded = true; 0145 } 0146 m_table = iTable; 0147 m_realTable = SKGServices::getRealTable(m_table); 0148 if (m_document != nullptr) { 0149 m_listSchema = m_document->getDisplaySchemas(m_realTable); 0150 } 0151 } 0152 } 0153 0154 QString SKGObjectModelBase::getTable() const 0155 { 0156 return m_table; 0157 } 0158 0159 void SKGObjectModelBase::setGroupBy(const QString& iAttribute) 0160 { 0161 if (iAttribute != m_groupby) { 0162 m_isResetRealyNeeded = true; 0163 m_groupby = iAttribute; 0164 } 0165 } 0166 0167 QString SKGObjectModelBase::getGroupBy() const 0168 { 0169 return m_groupby; 0170 } 0171 0172 QString SKGObjectModelBase::getParentChildAttribute() const 0173 { 0174 return m_parentAttribute; 0175 } 0176 0177 QString SKGObjectModelBase::getRealTable() const 0178 { 0179 return m_realTable; 0180 } 0181 0182 QString SKGObjectModelBase::getWhereClause() const 0183 { 0184 return m_whereClause; 0185 } 0186 0187 SKGDocument* SKGObjectModelBase::getDocument() const 0188 { 0189 return m_document; 0190 } 0191 0192 void SKGObjectModelBase::buidCache() 0193 { 0194 SKGTRACEINFUNC(1) 0195 m_doctransactionTable = (getRealTable() == QStringLiteral("doctransaction")); 0196 m_nodeTable = (getRealTable() == QStringLiteral("node")); 0197 m_parametersTable = (getRealTable() == QStringLiteral("parameters")); 0198 0199 // Get std colors 0200 KColorScheme scheme(QPalette::Normal); 0201 m_fontNegativeColor = QVariant::fromValue(scheme.foreground(KColorScheme::NegativeText).color()); 0202 } 0203 0204 bool SKGObjectModelBase::blockRefresh(bool iBlocked) 0205 { 0206 bool previous = m_refreshBlocked; 0207 m_refreshBlocked = iBlocked; 0208 return previous; 0209 } 0210 0211 bool SKGObjectModelBase::isRefreshBlocked() 0212 { 0213 return m_refreshBlocked; 0214 } 0215 0216 void SKGObjectModelBase::refresh() 0217 { 0218 if (!m_isResetRealyNeeded || isRefreshBlocked()) { 0219 return; 0220 } 0221 SKGTRACEIN(1, "SKGObjectModelBase::refresh-" % getTable()) 0222 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 0223 beginResetModel(); 0224 Q_EMIT beforeReset(); 0225 m_cache->clear(); 0226 { 0227 _SKGTRACEINFUNC(10) 0228 clear(); 0229 m_listAttibutes.clear(); 0230 m_listAttributeTypes.clear(); 0231 /*beginRemoveRows(QModelIndex(), 0, rowCount(QModelIndex())-1); 0232 endRemoveRows();*/ 0233 } 0234 0235 { 0236 _SKGTRACEINFUNC(10) 0237 QStringList listAttibutesTmp; 0238 if (m_document != nullptr && m_document->getAttributesList(m_table, listAttibutesTmp).isSucceeded()) { 0239 m_isResetRealyNeeded = false; 0240 if (!listAttibutesTmp.isEmpty()) { 0241 // Filter attributes 0242 int nb = m_listSupported.count(); 0243 if (nb == 0) { 0244 setSupportedAttributes(QStringList()); 0245 nb = m_listSupported.count(); 0246 } 0247 for (int i = 0 ; i < nb ; ++i) { 0248 QString att = m_listSupported.at(i); 0249 if (listAttibutesTmp.contains(att) || att.startsWith(QLatin1String("p_"))) { 0250 m_listAttibutes.push_back(att); 0251 if (att.startsWith(QLatin1String("t_")) || att.startsWith(QLatin1String("p_")) || 0252 att == QLatin1String("d_DATEWEEK") || att == QLatin1String("d_DATEMONTH") || att == QLatin1String("d_DATEQUARTER") || att == QLatin1String("d_DATESEMESTER") || att == QLatin1String("d_DATEYEAR")) { 0253 m_listAttributeTypes.push_back(SKGServices::TEXT); 0254 } else if (att.startsWith(QLatin1String("f_"))) { 0255 m_listAttributeTypes.push_back(SKGServices::FLOAT); 0256 } else if (att.startsWith(QLatin1String("i_"))) { 0257 m_listAttributeTypes.push_back(SKGServices::INTEGER); 0258 } else if (att.startsWith(QLatin1String("d_"))) { 0259 m_listAttributeTypes.push_back(SKGServices::DATE); 0260 } else { 0261 m_listAttributeTypes.push_back(SKGServices::OTHER); 0262 } 0263 } 0264 } 0265 0266 // Remove double 0267 nb = m_listAttibutes.count(); 0268 for (int i = nb - 1 ; i >= 0 ; --i) { 0269 QString att = m_listAttibutes.at(i); 0270 if (att.contains(QStringLiteral("_REAL"))) { 0271 att.replace(QStringLiteral("_REAL"), QStringLiteral("_")); 0272 int p = m_listAttibutes.indexOf(att); 0273 if (p == -1) { 0274 att = att.toLower(); 0275 p = m_listAttibutes.indexOf(att); 0276 } 0277 if (p != -1) { 0278 m_listAttibutes.removeAt(p); 0279 m_listAttributeTypes.removeAt(p); 0280 if (p < i) { 0281 --i; 0282 } 0283 } 0284 } 0285 } 0286 } 0287 0288 // Get objects 0289 QString wc = m_whereClause; 0290 if (!m_groupby.isEmpty()) { 0291 if (wc.isEmpty()) { 0292 wc = QStringLiteral("1=1"); 0293 } 0294 if (m_groupby.startsWith(QLatin1String("p_"))) { 0295 wc += " ORDER BY (SELECT t_value FROM parameters WHERE t_uuid_parent=" % getTable() % ".id||'-" % getRealTable() % "' AND t_name='" % m_groupby % "')"; 0296 } else { 0297 wc += " ORDER BY " % m_groupby; 0298 } 0299 } 0300 if (m_document != nullptr) { 0301 m_document->getObjects(m_table, wc, m_listObjects); 0302 } 0303 0304 // Initialize object to treat 0305 QString currentGroup; 0306 int currentGoupId = 0; 0307 bool groupByDate = (m_groupby.startsWith(QLatin1String("d_")) && 0308 m_groupby != QLatin1String("d_DATEWEEK") && 0309 m_groupby != QLatin1String("d_DATEMONTH") && 0310 m_groupby != QLatin1String("d_DATEQUARTER") && 0311 m_groupby != QLatin1String("d_DATESEMESTER") && 0312 m_groupby != QLatin1String("d_DATEYEAR")); 0313 0314 bool groupByNum = (m_groupby.startsWith(QLatin1String("f_")) || m_groupby.startsWith(QLatin1String("i_"))); 0315 int nb = m_listObjects.count(); 0316 SKGTRACEL(1) << nb << " objects found" << SKGENDL; 0317 for (int t = 0; t < nb; ++t) { 0318 auto c = new SKGObjectBase(m_listObjects.at(t)); 0319 int id = (c != nullptr ? c->getID() : 0); 0320 0321 int idparent = 0; 0322 if (m_groupby.isEmpty()) { 0323 // Grouping by tree 0324 if (!m_parentAttribute.isEmpty()) { 0325 int idp = SKGServices::stringToInt(c->getAttribute(m_parentAttribute)); 0326 if (idp > 0) { 0327 idparent = idp; 0328 } 0329 } 0330 } else { 0331 // Grouping on specified attribute 0332 QString att = getAttributeForGrouping(*c, m_groupby); 0333 if (groupByDate) { 0334 QDate date = SKGServices::stringToTime(att).date(); 0335 if (date == QDate::currentDate()) { 0336 att = i18nc("A group name for grouping by date attibute", "Today"); 0337 } else if (date > QDate::currentDate()) { 0338 // In future 0339 if (date < QDate::currentDate().addDays(7)) { 0340 att = i18nc("A group name for grouping by date attibute", "Next 7 days"); 0341 } else if (date < QDate::currentDate().addDays(15)) { 0342 att = i18nc("A group name for grouping by date attibute", "Next 15 days"); 0343 } else if (date < QDate::currentDate().addMonths(1)) { 0344 att = i18nc("A group name for grouping by date attibute", "Next month"); 0345 } else if (date < QDate::currentDate().addMonths(3)) { 0346 att = i18nc("A group name for grouping by date attibute", "Next 3 months"); 0347 } else if (date < QDate::currentDate().addMonths(6)) { 0348 att = i18nc("A group name for grouping by date attibute", "Next 6 months"); 0349 } else if (date < QDate::currentDate().addYears(1)) { 0350 att = i18nc("A group name for grouping by date attibute", "Next year"); 0351 } else if (date < QDate::currentDate().addYears(3)) { 0352 att = i18nc("A group name for grouping by date attibute", "Next 3 years"); 0353 } else { 0354 att = i18nc("A group name for grouping by date attibute", "Far away in the future"); 0355 } 0356 } else { 0357 // In the past 0358 if (date > QDate::currentDate().addDays(-7)) { 0359 att = i18nc("A group name for grouping by date attibute", "Last 7 days"); 0360 } else if (date > QDate::currentDate().addDays(-15)) { 0361 att = i18nc("A group name for grouping by date attibute", "Last 15 days"); 0362 } else if (date > QDate::currentDate().addMonths(-1)) { 0363 att = i18nc("A group name for grouping by date attibute", "Last month"); 0364 } else if (date > QDate::currentDate().addMonths(-3)) { 0365 att = i18nc("A group name for grouping by date attibute", "Last 3 months"); 0366 } else if (date > QDate::currentDate().addMonths(-6)) { 0367 att = i18nc("A group name for grouping by date attibute", "Last 6 months"); 0368 } else if (date > QDate::currentDate().addYears(-1)) { 0369 att = i18nc("A group name for grouping by date attibute", "Last year"); 0370 } else if (date > QDate::currentDate().addYears(-3)) { 0371 att = i18nc("A group name for grouping by date attibute", "Last 3 years"); 0372 } else { 0373 att = i18nc("A group name for grouping by date attibute", "Far away in the past"); 0374 } 0375 } 0376 } else if (groupByNum) { 0377 if (att != QChar(8734)) { 0378 double d = SKGServices::stringToDouble(att); 0379 if (d > 10000.0) { 0380 att = i18nc("A group name for grouping by numerical attibute", "> 10000"); 0381 } else if (d > 1000.0) { 0382 att = i18nc("A group name for grouping by numerical attibute", "> 1000"); 0383 } else if (d > 100.0) { 0384 att = i18nc("A group name for grouping by numerical attibute", "> 100"); 0385 } else if (d > 10.0) { 0386 att = i18nc("A group name for grouping by numerical attibute", "> 10"); 0387 } else if (d > 0.0) { 0388 att = i18nc("A group name for grouping by numerical attibute", "> 0"); 0389 } else if (d < -10000.0) { 0390 att = i18nc("A group name for grouping by numerical attibute", "< -10000"); 0391 } else if (d < -1000.0) { 0392 att = i18nc("A group name for grouping by numerical attibute", "< -1000"); 0393 } else if (d < -100.0) { 0394 att = i18nc("A group name for grouping by numerical attibute", "< -100"); 0395 } else if (d < -10.0) { 0396 att = i18nc("A group name for grouping by numerical attibute", "< -10"); 0397 } else if (d < 0.0) { 0398 att = i18nc("A group name for grouping by numerical attibute", "< 0"); 0399 } else { 0400 att = i18nc("A group name for grouping by numerical attibute", "= 0"); 0401 } 0402 } 0403 } 0404 if (att != currentGroup || currentGoupId == 0) { 0405 // Addition of a new group 0406 currentGroup = att; 0407 currentGoupId--; 0408 auto group = new SKGObjectBase(m_document, QLatin1String(""), currentGoupId); 0409 group->setAttribute(QStringLiteral("t_title"), currentGroup); 0410 0411 m_childParentRelations.insert(currentGoupId, 0); 0412 0413 QList<int> childrensids = m_parentChildRelations.value(0); 0414 childrensids.push_back(currentGoupId); 0415 0416 m_parentChildRelations.insert(0, childrensids); 0417 m_objectsHashTableRows.insert(currentGoupId, childrensids.count() - 1); 0418 m_objectsHashTable.insert(currentGoupId, group); 0419 } 0420 0421 idparent = currentGoupId; 0422 } 0423 0424 m_childParentRelations.insert(id, idparent); 0425 0426 QList<int> childrensids = m_parentChildRelations.value(idparent); 0427 childrensids.push_back(id); 0428 0429 m_parentChildRelations.insert(idparent, childrensids); 0430 m_objectsHashTableRows.insert(id, childrensids.count() - 1); 0431 m_objectsHashTable.insert(id, c); 0432 } 0433 } 0434 0435 // Build cache 0436 buidCache(); 0437 } 0438 endResetModel(); 0439 Q_EMIT afterReset(); 0440 0441 QApplication::restoreOverrideCursor(); 0442 } 0443 0444 bool SKGObjectModelBase::hasChildren(const QModelIndex& iParent) const 0445 { 0446 if (iParent.column() > 0) { 0447 return false; 0448 } 0449 _SKGTRACEINFUNC(10) 0450 0451 if (iParent.isValid() && m_parentAttribute.isEmpty() && m_groupby.isEmpty()) { 0452 return false; 0453 } 0454 return QAbstractItemModel::hasChildren(iParent); 0455 } 0456 0457 int SKGObjectModelBase::rowCount(const QModelIndex& iParent) const 0458 { 0459 if (iParent.column() > 0) { 0460 return 0; 0461 } 0462 _SKGTRACEINFUNC(10) 0463 0464 int idParent = 0; 0465 if (iParent.isValid()) { 0466 idParent = iParent.internalId(); 0467 } 0468 0469 return m_parentChildRelations.value(idParent).count(); 0470 } 0471 0472 int SKGObjectModelBase::columnCount(const QModelIndex& iParent) const 0473 { 0474 Q_UNUSED(iParent) 0475 return m_listAttibutes.count(); 0476 } 0477 0478 QModelIndex SKGObjectModelBase::index(int row, int column, const QModelIndex& iParent) const 0479 { 0480 if (!hasIndex(row, column, iParent)) { 0481 return {}; 0482 } 0483 _SKGTRACEINFUNC(10) 0484 0485 int idParent = 0; 0486 if (iParent.isValid()) { 0487 idParent = iParent.internalId(); 0488 } 0489 0490 int idChild = m_parentChildRelations.value(idParent).at(row); 0491 0492 // SKGTRACE << table << "-" << idParent << "(" << row << ") ==> " << idChild << SKGENDL; 0493 return (idChild != 0 ? createIndex(row, column, idChild) : QModelIndex()); 0494 } 0495 0496 QModelIndex SKGObjectModelBase::parent(const QModelIndex& iIndex) const 0497 { 0498 if (!iIndex.isValid()) { 0499 return {}; 0500 } 0501 _SKGTRACEINFUNC(10) 0502 0503 int idChild = 0; 0504 if (iIndex.isValid()) { 0505 idChild = iIndex.internalId(); 0506 } 0507 0508 int idParent = m_childParentRelations.value(idChild); 0509 int row = m_objectsHashTableRows.value(idParent); 0510 // SKGTRACE << table << "-" << idChild << "(" << row << ") <== " << idParent << SKGENDL; 0511 return idParent != 0 ? createIndex(row, 0, idParent) : QModelIndex(); 0512 } 0513 0514 int SKGObjectModelBase::getIndexAttribute(const QString& iAttributeName) const 0515 { 0516 int output = m_listAttibutes.indexOf(iAttributeName); 0517 if (output == -1) { 0518 SKGTRACE << "[" << iAttributeName << "] not found in [" << getRealTable() << "]" << SKGENDL; 0519 } 0520 return output; 0521 } 0522 0523 QString SKGObjectModelBase::getAttribute(int iIndex) const 0524 { 0525 return m_listAttibutes.value(iIndex); 0526 } 0527 0528 SKGServices::AttributeType SKGObjectModelBase::getAttributeType(int iIndex) const 0529 { 0530 return m_listAttributeTypes.value(iIndex); 0531 } 0532 0533 QVariant SKGObjectModelBase::headerData(int iSection, Qt::Orientation iOrientation, int iRole) const 0534 { 0535 _SKGTRACEINFUNC(10) 0536 0537 if (iOrientation == Qt::Horizontal) { 0538 if (iRole == Qt::DisplayRole) { 0539 QString att; 0540 if (iSection >= 0 && iSection < m_listAttibutes.count()) { 0541 att = m_listAttibutes.at(iSection); 0542 } else { 0543 att = SKGServices::intToString(iSection); 0544 } 0545 0546 return getDocument()->getDisplay(getTable() % '.' % att).remove(getTable() % '.'); 0547 } 0548 if (iRole == Qt::UserRole) { 0549 QString att; 0550 if (iSection >= 0 && iSection < m_listAttibutes.count()) { 0551 att = m_listAttibutes.at(iSection); 0552 } else { 0553 att = SKGServices::intToString(iSection); 0554 } 0555 0556 int indexAtt = m_listSupported.indexOf(att); 0557 0558 att = getDocument()->getDisplay(getTable() % '.' % att).remove(getTable() % '.'); 0559 0560 0561 if (indexAtt >= 0 && indexAtt < m_listVisibility.count()) { 0562 bool visible = m_listVisibility.at(indexAtt); 0563 att += QStringLiteral("|") % (visible ? QStringLiteral("Y") : QStringLiteral("N")); 0564 if (indexAtt >= 0 && indexAtt < m_listSize.count()) { 0565 att += '|' % SKGServices::intToString(m_listSize.at(indexAtt)); 0566 } 0567 } 0568 return att; 0569 } 0570 if (iRole == Qt::DecorationRole) { 0571 QString att; 0572 if (iSection >= 0 && iSection < m_listAttibutes.count()) { 0573 att = m_listAttibutes.at(iSection); 0574 } else { 0575 att = SKGServices::intToString(iSection); 0576 } 0577 0578 return getDocument()->getIcon(getTable() % '.' % att); 0579 } 0580 } 0581 return QVariant(); 0582 } 0583 0584 SKGObjectBase SKGObjectModelBase::getObject(const QModelIndex& iIndex) const 0585 { 0586 SKGObjectBase* obj = getObjectPointer(iIndex); 0587 SKGObjectBase output; 0588 if (obj != nullptr) { 0589 output = *obj; 0590 } 0591 return output; 0592 } 0593 0594 SKGObjectBase* SKGObjectModelBase::getObjectPointer(const QModelIndex& iIndex) const 0595 { 0596 _SKGTRACEINFUNC(10) 0597 return m_objectsHashTable.value(iIndex.internalId()); 0598 } 0599 0600 QVariant SKGObjectModelBase::data(const QModelIndex& iIndex, int iRole) const 0601 { 0602 if (!iIndex.isValid()) { 0603 return QVariant(); 0604 } 0605 _SKGTRACEINFUNC(10) 0606 // Build cache id 0607 QString idcache = getObjectPointer(iIndex)->getUniqueID() % 0608 "-" % SKGServices::intToString(iIndex.row()) % 0609 "-" % SKGServices::intToString(iIndex.column()) % 0610 "-" % SKGServices::intToString(iRole); 0611 0612 // Check cache 0613 if (!m_cache->contains(idcache)) { 0614 // Compute value 0615 m_cache->insert(idcache, computeData(iIndex, iRole)); 0616 } 0617 0618 return m_cache->value(idcache); 0619 } 0620 0621 QVariant SKGObjectModelBase::computeData(const QModelIndex& iIndex, int iRole) const 0622 { 0623 if (!iIndex.isValid()) { 0624 return QVariant(); 0625 } 0626 _SKGTRACEINFUNC(10) 0627 0628 switch (iRole) { 0629 case Qt::BackgroundRole: { 0630 SKGObjectBase* obj = getObjectPointer(iIndex); 0631 if (obj->getTable().isEmpty()) { 0632 // This is a group 0633 return QApplication::palette().brush(QPalette::Button); 0634 } 0635 break; 0636 } 0637 case Qt::DisplayRole: 0638 case Qt::EditRole: 0639 case Qt::UserRole: { 0640 SKGObjectBase* obj = getObjectPointer(iIndex); 0641 QString att = m_listAttibutes.at(iIndex.column()); 0642 if (obj->getTable().isEmpty()) { 0643 // This is a group 0644 if (iIndex.column() == 0) { 0645 if (iRole == Qt::UserRole) { 0646 return -obj->getID(); // For sorting 0647 } 0648 int nb = rowCount(iIndex); 0649 0650 // Is it possible to compute sums of f_CURRENTAMOUNT ? 0651 int posAmount = m_listAttibutes.indexOf(QStringLiteral("f_CURRENTAMOUNT")); 0652 if (posAmount == -1) { 0653 posAmount = m_listAttibutes.indexOf(QStringLiteral("f_REALCURRENTAMOUNT")); 0654 } 0655 if (posAmount != -1 && nb > 0) { 0656 // Compute sums 0657 double sum = 0.0; 0658 double average = 0.0; 0659 double min = std::numeric_limits<double>::max(); 0660 double max = -std::numeric_limits<double>::max(); 0661 for (int i = 0; i < nb ; ++i) { 0662 double amount = data(SKGObjectModelBase::index(i, posAmount, iIndex), Qt::UserRole).toDouble(); 0663 sum += amount; 0664 max = qMax(max, amount); 0665 min = qMin(min, amount); 0666 } 0667 average = sum / nb; 0668 0669 return i18nc("How to display a grouping title. Here \"title (count) Sum= [min , average , max]\"", "%1: %2 (%3) Sum=%4 [%5 , %6 , %7]", 0670 getDocument()->getDisplay(m_groupby), 0671 obj->getAttribute(QStringLiteral("t_title")), 0672 nb, 0673 formatMoney(sum), 0674 formatMoney(min), 0675 formatMoney(average), 0676 formatMoney(max)); 0677 } 0678 return i18nc("How to display a grouping title. Here \"title (count)\"", "%1: %2 (%3)", 0679 getDocument()->getDisplay(m_groupby), 0680 obj->getAttribute(QStringLiteral("t_title")), 0681 nb); 0682 } 0683 return ""; 0684 } 0685 QString val; 0686 if (att.startsWith(QLatin1String("p_"))) { 0687 // This is a property 0688 val = obj->getProperty(att.right(att.count() - 2)); 0689 } else { 0690 // This is a real attribute 0691 val = obj->getAttribute(att); 0692 0693 switch (getAttributeType(iIndex.column())) { 0694 case SKGServices::FLOAT: { 0695 double dval = SKGServices::stringToDouble(val); 0696 return dval; 0697 } 0698 case SKGServices::INTEGER: { 0699 return SKGServices::stringToInt(val); 0700 } 0701 case SKGServices::DATE: { 0702 QDate dval = SKGServices::stringToTime(val).date(); 0703 if (iRole == Qt::DisplayRole) { 0704 return SKGMainPanel::dateToString(dval); 0705 } 0706 if (iRole == Qt::UserRole) { 0707 return dval; 0708 } 0709 } 0710 default: { 0711 } 0712 } 0713 0714 if (m_doctransactionTable && att == QStringLiteral("t_savestep")) { 0715 return ""; 0716 } 0717 } 0718 0719 // return val+"("+SKGServices::intToString(rowCount(index))+")"; 0720 return val; 0721 } 0722 0723 case Qt::FontRole: { 0724 SKGObjectBase* obj = getObjectPointer(iIndex); 0725 // Text color 0726 if (obj->getTable().isEmpty()) { 0727 // This is a group 0728 if (iIndex.column() == 0) { 0729 QFont f; 0730 f.setBold(true); 0731 0732 return QVariant::fromValue(f); 0733 } 0734 return ""; 0735 } 0736 0737 int propertyId = data(iIndex, 101).toInt(); 0738 if (propertyId != 0) { 0739 SKGPropertyObject p(m_document, propertyId); 0740 if (!p.getUrl().scheme().isEmpty()) { 0741 QFont f; 0742 f.setUnderline(true); 0743 0744 return QVariant::fromValue(f); 0745 } 0746 } 0747 break; 0748 } 0749 case Qt::TextColorRole: { 0750 // Text color 0751 if (getAttributeType(iIndex.column()) == SKGServices::FLOAT) { 0752 QVariant value_displayed = SKGObjectModelBase::data(iIndex, Qt::UserRole); 0753 bool ok = false; 0754 double value_double = value_displayed.toDouble(&ok); 0755 if (ok && value_double < 0) { 0756 return m_fontNegativeColor; 0757 } 0758 } 0759 0760 int propertyId = data(iIndex, 101).toInt(); 0761 if (propertyId != 0) { 0762 SKGPropertyObject p(m_document, propertyId); 0763 if (!p.getUrl().scheme().isEmpty()) { 0764 KColorScheme scheme(QPalette::Normal); 0765 return QVariant::fromValue(scheme.foreground(KColorScheme::ActiveText).color()); 0766 } 0767 } 0768 break; 0769 } 0770 case Qt::TextAlignmentRole: { 0771 // Text alignment 0772 SKGServices::AttributeType attType = getAttributeType(iIndex.column()); 0773 return static_cast<int>(Qt::AlignVCenter | (attType == SKGServices::FLOAT || attType == SKGServices::INTEGER ? Qt::AlignRight : Qt::AlignLeft)); 0774 } 0775 case Qt::DecorationRole: { 0776 // Decoration 0777 SKGObjectBase* obj = getObjectPointer(iIndex); 0778 QString att = m_listAttibutes.at(iIndex.column()); 0779 if (obj->getTable().isEmpty()) { 0780 // This is a group 0781 if (iIndex.column() == 0) { 0782 return QVariant::fromValue(SKGServices::fromTheme(QStringLiteral("arrow-right"))); 0783 }; 0784 return ""; 0785 } 0786 if (iIndex.column() == 0 && m_nodeTable) { 0787 SKGNodeObject node(*obj); 0788 return QVariant::fromValue(node.getIcon()); 0789 } 0790 if (iIndex.column() == 0 && m_doctransactionTable) { 0791 return QVariant::fromValue(SKGServices::fromTheme(obj->getAttribute(QStringLiteral("t_mode")) == QStringLiteral("U") ? QStringLiteral("edit-undo") : QStringLiteral("edit-redo"))); 0792 } 0793 if (m_doctransactionTable && att == QStringLiteral("t_savestep")) { 0794 if (obj->getAttribute(QStringLiteral("t_savestep")) == QStringLiteral("Y")) { 0795 return QVariant::fromValue(SKGServices::fromTheme(QStringLiteral("document-save"))); 0796 } 0797 } 0798 0799 break; 0800 } 0801 case Qt::ToolTipRole: { 0802 // Tooltip 0803 QString toolTipString; 0804 SKGObjectBase* obj = getObjectPointer(iIndex); 0805 0806 if (obj != nullptr && m_document != nullptr) { 0807 if (m_doctransactionTable) { 0808 SKGDocument::SKGMessageList msg; 0809 m_document->getMessages(obj->getID(), msg); 0810 int nbMessages = msg.count(); 0811 if (nbMessages > 0) { 0812 for (int i = 0; i < nbMessages; ++i) { 0813 if (i != 0) { 0814 toolTipString += '\n'; 0815 } 0816 toolTipString += msg.at(i).Text; 0817 } 0818 } 0819 } else if (getAttributeType(iIndex.column()) == SKGServices::DATE) { 0820 QString att = m_listAttibutes.at(iIndex.column()); 0821 QString val = obj->getAttribute(att); 0822 0823 QDate dval = SKGServices::stringToTime(val).date(); 0824 QString fancyDate = QLocale().toString(dval, QLocale::LongFormat); 0825 QString shortDate = QLocale().toString(dval, QLocale::ShortFormat); 0826 0827 if (shortDate != fancyDate) { 0828 toolTipString = shortDate; 0829 } 0830 } 0831 0832 // Add properties 0833 QStringList props = obj->getProperties(); 0834 if (!props.isEmpty() && !toolTipString.isEmpty()) { 0835 toolTipString += '\n'; 0836 } 0837 for (const auto& prop : qAsConst(props)) { 0838 if (!toolTipString.isEmpty()) { 0839 toolTipString += '\n'; 0840 } 0841 toolTipString += i18nc("To display a property and its value", "%1=%2", prop, obj->getProperty(prop)); 0842 } 0843 0844 // Add UUID 0845 IFSKGTRACEL(1) { 0846 toolTipString += '\n' % obj->getUniqueID(); 0847 } 0848 } 0849 return toolTipString; 0850 } 0851 case 99: { 0852 SKGObjectBase* obj = getObjectPointer(iIndex); 0853 if (obj != nullptr) { 0854 return SKGServices::stringToDouble(obj->getAttribute(QStringLiteral("f_sortorder"))); 0855 } 0856 break; 0857 } 0858 case 101: { 0859 SKGObjectBase* obj = getObjectPointer(iIndex); 0860 // Is it a URL ? 0861 QString att = m_listAttibutes.at(iIndex.column()); 0862 if (att.startsWith(QLatin1String("p_"))) { 0863 SKGPropertyObject p(obj->getPropertyObject(att.right(att.count() - 2))); 0864 if (!p.getUrl().scheme().isEmpty()) { 0865 return QVariant::fromValue(p.getID()); 0866 } 0867 } else if (m_parametersTable && att == QStringLiteral("t_value")) { 0868 SKGPropertyObject p(*obj); 0869 if (!p.getUrl().scheme().isEmpty()) { 0870 return QVariant::fromValue(p.getID()); 0871 } 0872 } 0873 return 0; 0874 } 0875 default : { 0876 } 0877 } 0878 0879 return QVariant(); 0880 } 0881 0882 Qt::ItemFlags SKGObjectModelBase::flags(const QModelIndex& iIndex) const 0883 { 0884 _SKGTRACEINFUNC(10) 0885 0886 Qt::ItemFlags f = QAbstractItemModel::flags(iIndex) | Qt::ItemIsDropEnabled; 0887 0888 if (iIndex.isValid()) { 0889 f |= Qt::ItemIsUserCheckable; 0890 } 0891 0892 if (m_nodeTable && iIndex.isValid()) { 0893 f |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled; 0894 } 0895 0896 if (iIndex.isValid()) { 0897 QString att = m_listAttibutes.at(iIndex.column()); 0898 if (att.toLower() == att || !getDocument()->getRealAttribute(att).isEmpty()) { 0899 f |= Qt::ItemIsEditable; 0900 } 0901 SKGObjectBase* obj = getObjectPointer(iIndex); 0902 if (obj->getTable().isEmpty()) { 0903 f = Qt::ItemIsEnabled; 0904 } 0905 } 0906 0907 return f; 0908 } 0909 0910 bool SKGObjectModelBase::setData(const QModelIndex& iIndex, const QVariant& iValue, int iRole) 0911 { 0912 if (!iIndex.isValid()) { 0913 return false; 0914 } 0915 0916 if (iRole == Qt::EditRole) { 0917 SKGError err; 0918 if (m_nodeTable) { 0919 SKGNodeObject obj(getObject(iIndex)); 0920 QString name = iValue.toString(); 0921 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Bookmark update '%1'", name), err) 0922 IFOKDO(err, err = obj.setName(name)) 0923 IFOKDO(err, obj.save()) 0924 } else { 0925 SKGObjectBase obj(getObject(iIndex)); 0926 0927 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Update object"), err) 0928 SKGObjectBase obj2(obj.getDocument(), obj.getRealTable(), obj.getID()); // To be sure this is not a complex object 0929 QString att = m_listAttibutes.at(iIndex.column()); 0930 IFOKDO(err, obj2.setAttribute(att, att.startsWith(QLatin1String("d_")) && iValue.canConvert<QDateTime>() ? SKGServices::dateToSqlString(iValue.toDateTime()) : iValue.toString())) 0931 IFOKDO(err, obj2.save()) 0932 } 0933 0934 SKGMainPanel::displayErrorMessage(err); 0935 return !err; 0936 } 0937 return QAbstractItemModel::setData(iIndex, iValue, iRole); 0938 } 0939 0940 Qt::DropActions SKGObjectModelBase::supportedDragActions() const 0941 { 0942 return (m_nodeTable ? Qt::MoveAction : Qt::IgnoreAction); 0943 } 0944 0945 Qt::DropActions SKGObjectModelBase::supportedDropActions() const 0946 { 0947 return Qt::MoveAction | Qt::LinkAction | Qt::CopyAction; 0948 } 0949 0950 QStringList SKGObjectModelBase::mimeTypes() const 0951 { 0952 QStringList types; 0953 types << "application/skg." % getRealTable() % ".ids"; 0954 types << QStringLiteral("application/data"); 0955 types << QStringLiteral("text/uri-list"); 0956 return types; 0957 } 0958 0959 QMimeData* SKGObjectModelBase::mimeData(const QModelIndexList& iIndexes) const 0960 { 0961 auto md = new QMimeData(); 0962 QByteArray encodedData; 0963 0964 QDataStream stream(&encodedData, QIODevice::WriteOnly); 0965 0966 QString t = getTable(); 0967 for (const auto& idx : qAsConst(iIndexes)) { 0968 if (idx.isValid() && idx.column() == 0) { 0969 SKGObjectBase obj = getObject(idx); 0970 t = obj.getRealTable(); 0971 stream << t; 0972 stream << obj.getID(); 0973 } 0974 } 0975 0976 md->setData("application/skg." % t % ".ids", encodedData); 0977 return md; 0978 } 0979 0980 bool SKGObjectModelBase::dropMimeData(const QMimeData* iData, 0981 Qt::DropAction iAction, 0982 int iRow, int iColumn, 0983 const QModelIndex& iParent) 0984 { 0985 Q_UNUSED(iRow) 0986 if (iAction == Qt::IgnoreAction) { 0987 return true; 0988 } 0989 if ((iData == nullptr) || !(iData->hasFormat(QStringLiteral("application/skg.node.ids")) || iData->hasUrls())) { 0990 return false; // TODO(Stephane MANKOWSKI): accept all 0991 } 0992 if (iColumn > 0) { 0993 return false; 0994 } 0995 0996 SKGError err; 0997 // Drop files 0998 if (iData->hasUrls() && iParent.isValid() && getRealTable() != QStringLiteral("node")) { 0999 QList<QUrl> urls = iData->urls(); 1000 int nb = urls.count(); 1001 { 1002 SKGObjectBase obj(getObject(iParent)); 1003 1004 SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Property creation"), err, nb) 1005 for (int i = 0; !err && i < nb; ++i) { 1006 QString name = i18n("File"); 1007 int idx = 1; 1008 while (!err && !obj.getProperty(name).isEmpty()) { 1009 idx++; 1010 name = i18n("File") % " (" % SKGServices::intToString(idx) % ')'; 1011 } 1012 QString f = urls.at(i).toLocalFile(); 1013 err = obj.setProperty(name, f, iAction == Qt::LinkAction ? QLatin1String("") : f); 1014 if (!err && iAction == Qt::MoveAction) { 1015 QFile(f).remove(); 1016 } 1017 IFOKDO(err, getDocument()->stepForward(i + 1)) 1018 } 1019 } 1020 } else if (iData->hasFormat(QStringLiteral("application/skg.node.ids"))) { 1021 // Drop nodes 1022 QByteArray encodedData = iData->data(QStringLiteral("application/skg.node.ids")); 1023 QDataStream stream(&encodedData, QIODevice::ReadOnly); 1024 QStringList newItems; 1025 1026 QModelIndex parentIndex = iParent; 1027 SKGNodeObject parentNode; 1028 if (parentIndex.isValid()) { 1029 parentNode = getObject(parentIndex); 1030 if (!parentNode.isFolder()) { 1031 // The parent is not a directory 1032 parentNode.getParentNode(parentNode); 1033 parentIndex = parentIndex.parent(); 1034 } 1035 } 1036 { 1037 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Move bookmark"), err) 1038 1039 double min = 0; 1040 double max = 0; 1041 if (iRow >= 1) { 1042 QModelIndex previousIndex = SKGObjectModelBase::index(iRow - 1, 0, parentIndex); 1043 SKGNodeObject previousObject(getObject(previousIndex)); 1044 min = previousObject.getOrder(); 1045 } 1046 1047 if (iRow >= rowCount(parentIndex)) { 1048 max = min + 1; 1049 } else { 1050 QModelIndex nextIndex = SKGObjectModelBase::index(iRow, 0, parentIndex); 1051 SKGNodeObject nextObject(getObject(nextIndex)); 1052 max = nextObject.getOrder(); 1053 } 1054 if (max <= min) { 1055 max = min + 1; 1056 } 1057 1058 while (!stream.atEnd() && !err) { 1059 int o_id; 1060 QString o_table; 1061 stream >> o_table; 1062 stream >> o_id; 1063 1064 // Set parent 1065 SKGNodeObject child(getDocument(), o_id); 1066 err = child.load(); 1067 QString oldName = child.getDisplayName(); 1068 IFOK(err) { 1069 if (parentIndex.isValid()) { 1070 err = child.setParentNode(parentNode); 1071 } else { 1072 err = child.removeParentNode(); 1073 } 1074 } 1075 1076 // Set order 1077 IFOKDO(err, child.setOrder((min + max) / 2.0)) 1078 1079 // Save 1080 IFOKDO(err, child.save()) 1081 1082 // Send message 1083 IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The bookmark '%1' has been moved to '%2'", oldName, child.getDisplayName()), SKGDocument::Hidden)) 1084 } 1085 } 1086 } 1087 SKGMainPanel::displayErrorMessage(err); 1088 return !err; 1089 } 1090 1091 void SKGObjectModelBase::pageChanged() 1092 { 1093 if (m_isResetRealyNeeded) { 1094 dataModified(QLatin1String(""), 0); 1095 } 1096 } 1097 1098 void SKGObjectModelBase::dataModified(const QString& iTableName, int iIdTransaction) 1099 { 1100 if (getTable() == iTableName || iTableName.isEmpty()) { 1101 SKGTRACEINFUNC(1) 1102 SKGTRACEL(1) << "getTable=" << getRealTable() << SKGENDL; 1103 SKGTRACEL(1) << "Parameters=" << iTableName << " , " << iIdTransaction << SKGENDL; 1104 SKGTabPage* page = SKGTabPage::parentTabPage(qobject_cast< QWidget* >(this->QObject::parent())); 1105 SKGTabPage* cpage = SKGMainPanel::getMainPanel() != nullptr ? SKGMainPanel::getMainPanel()->currentPage() : nullptr; 1106 if (page != nullptr && page != cpage) { 1107 m_isResetRealyNeeded = true; 1108 return; 1109 } 1110 1111 // Full refresh 1112 m_isResetRealyNeeded = true; 1113 1114 // Refresh model 1115 refresh(); 1116 } 1117 } 1118 1119 QString SKGObjectModelBase::getAttributeForGrouping(const SKGObjectBase& iObject, const QString& iAttribute) const 1120 { 1121 if (iAttribute.startsWith(QLatin1String("p_"))) { 1122 // This is a property 1123 return iObject.getProperty(iAttribute.right(iAttribute.count() - 2)); 1124 } 1125 // This is a real attribute 1126 return iObject.getAttribute(iAttribute); 1127 } 1128 1129 QString SKGObjectModelBase::formatMoney(double iValue) const 1130 { 1131 return SKGServices::doubleToString(iValue); 1132 }