File indexing completed on 2024-04-28 16:30:31
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 implements classes SKGNodeObject. 0008 * 0009 * @author Stephane MANKOWSKI / Guillaume DE BURE 0010 */ 0011 #include "skgnodeobject.h" 0012 0013 #include <klocalizedstring.h> 0014 #include <qicon.h> 0015 0016 #include "skgdefine.h" 0017 #include "skgdocument.h" 0018 #include "skgtraces.h" 0019 0020 SKGNodeObject::SKGNodeObject(): SKGNodeObject(nullptr) 0021 {} 0022 0023 SKGNodeObject::SKGNodeObject(SKGDocument* iDocument, int iID): SKGNamedObject(iDocument, QStringLiteral("v_node"), iID), opened(false) 0024 {} 0025 0026 SKGNodeObject::~SKGNodeObject() 0027 = default; 0028 0029 SKGNodeObject::SKGNodeObject(const SKGNodeObject& iObject) : SKGNamedObject(iObject), opened(false) 0030 {} 0031 0032 SKGNodeObject::SKGNodeObject(const SKGObjectBase& iObject) : SKGNamedObject(iObject.getDocument(), QStringLiteral("v_node"), iObject.getID()), opened(false) 0033 {} 0034 0035 SKGNodeObject& SKGNodeObject::operator= (const SKGObjectBase& iObject) 0036 { 0037 copyFrom(iObject); 0038 return *this; 0039 } 0040 0041 SKGNodeObject& SKGNodeObject::operator= (const SKGNodeObject& iObject) 0042 { 0043 copyFrom(iObject); 0044 return *this; 0045 } 0046 0047 SKGError SKGNodeObject::setName(const QString& iName) 0048 { 0049 SKGError err; 0050 if (iName.contains(OBJECTSEPARATOR)) { 0051 err = SKGError(ERR_FAIL, i18nc("Error message: an invalid character was found", "The name '%1' is invalid : the '%2' character is forbidden ", iName, QString(OBJECTSEPARATOR))); 0052 } else { 0053 err = SKGNamedObject::setName(iName); 0054 } 0055 return err; 0056 } 0057 0058 QString SKGNodeObject::getWhereclauseId() const 0059 { 0060 // Could we use the id 0061 QString output = SKGObjectBase::getWhereclauseId(); // clazy:exclude=skipped-base-method 0062 if (output.isEmpty()) { 0063 if (!(getAttribute(QStringLiteral("t_name")).isEmpty())) { 0064 output = "t_name='" % SKGServices::stringToSqlString(getAttribute(QStringLiteral("t_name"))) % '\''; 0065 } 0066 QString rd_node_id = getAttribute(QStringLiteral("rd_node_id")); 0067 if (!output.isEmpty()) { 0068 output += QStringLiteral(" AND "); 0069 } 0070 if (rd_node_id.isEmpty()) { 0071 output += QStringLiteral("(rd_node_id=0 OR rd_node_id IS NULL OR rd_node_id='')"); 0072 } else { 0073 output += "rd_node_id=" % rd_node_id; 0074 } 0075 } 0076 return output; 0077 } 0078 0079 QString SKGNodeObject::getFullName() const 0080 { 0081 return getAttribute(QStringLiteral("t_fullname")); 0082 } 0083 0084 SKGError SKGNodeObject::setData(const QString& iData) 0085 { 0086 return setAttribute(QStringLiteral("t_data"), iData); 0087 } 0088 0089 QString SKGNodeObject::getData() const 0090 { 0091 return getAttribute(QStringLiteral("t_data")); 0092 } 0093 0094 bool SKGNodeObject::isFolder() const 0095 { 0096 return getData().isEmpty(); 0097 } 0098 0099 SKGError SKGNodeObject::setIcon(const QString& iIcon) 0100 { 0101 return setAttribute(QStringLiteral("t_icon"), iIcon); 0102 } 0103 0104 QIcon SKGNodeObject::getIcon() const 0105 { 0106 QStringList overlay; 0107 if (isAutoStart()) { 0108 overlay.push_back(QStringLiteral("media-playback-start")); 0109 } 0110 return SKGServices::fromTheme(getAttribute(QStringLiteral("t_icon")), overlay); 0111 } 0112 0113 SKGError SKGNodeObject::setAutoStart(bool iAutoStart) 0114 { 0115 return setAttribute(QStringLiteral("t_autostart"), iAutoStart ? QStringLiteral("Y") : QStringLiteral("N")); 0116 } 0117 0118 bool SKGNodeObject::isAutoStart() const 0119 { 0120 return (getAttribute(QStringLiteral("t_autostart")) == QStringLiteral("Y")); 0121 } 0122 0123 SKGError SKGNodeObject::setOrder(double iOrder) 0124 { 0125 SKGError err; 0126 double order = iOrder; 0127 if (order == -1) { 0128 order = 1; 0129 SKGStringListList result; 0130 err = getDocument()->executeSelectSqliteOrder(QStringLiteral("SELECT max(f_sortorder) from node"), result); 0131 if (!err && result.count() == 2) { 0132 order = SKGServices::stringToDouble(result.at(1).at(0)) + 1; 0133 } 0134 } 0135 IFOKDO(err, setAttribute(QStringLiteral("f_sortorder"), SKGServices::doubleToString(order))) 0136 return err; 0137 } 0138 0139 double SKGNodeObject::getOrder() const 0140 { 0141 return SKGServices::stringToDouble(getAttribute(QStringLiteral("f_sortorder"))); 0142 } 0143 0144 SKGError SKGNodeObject::createPathNode(SKGDocument* iDocument, 0145 const QString& iFullPath, 0146 SKGNodeObject& oNode, 0147 bool iRenameIfAlreadyExist) 0148 { 0149 SKGError err; 0150 SKGTRACEINFUNCRC(10, err) 0151 SKGTRACEL(10) << "Input parameter [iFullPath]=" << iFullPath << SKGENDL; 0152 // Check if node is already existing 0153 if (!iRenameIfAlreadyExist && iDocument != nullptr) { 0154 iDocument->getObject(QStringLiteral("v_node"), "t_fullname='" % SKGServices::stringToSqlString(iFullPath) % '\'', oNode); 0155 } 0156 if (oNode.getID() == 0) { 0157 // No, we have to create it 0158 // Search node separator 0159 int posSeparator = iFullPath.lastIndexOf(OBJECTSEPARATOR); 0160 if (posSeparator == -1) { 0161 oNode = SKGNodeObject(iDocument); 0162 err = oNode.setName(iFullPath); 0163 0164 // Check if already existing 0165 if (!err && iRenameIfAlreadyExist) { 0166 int index = 1; 0167 while (!err && oNode.exist()) { 0168 index++; 0169 err = oNode.setName(iFullPath % " (" % SKGServices::intToString(index) % ')'); 0170 } 0171 } 0172 0173 IFOKDO(err, oNode.setIcon(QStringLiteral("folder-orange"))) 0174 IFOKDO(err, oNode.setOrder(-1)) 0175 IFOKDO(err, oNode.save()) 0176 } else { 0177 // Get first and second parts of the branch 0178 QString first = iFullPath.mid(0, posSeparator); 0179 QString second = iFullPath.mid(posSeparator + QString(OBJECTSEPARATOR).length(), iFullPath.length() - posSeparator - QString(OBJECTSEPARATOR).length()); 0180 0181 // Get first node 0182 SKGNodeObject FirstNode; 0183 err = SKGNodeObject::createPathNode(iDocument, first, FirstNode); 0184 0185 IFOK(err) { 0186 // Get second node 0187 err = FirstNode.addNode(oNode); 0188 0189 // Add second under first 0190 IFOKDO(err, oNode.setName(second)) 0191 0192 // Check if already existing 0193 if (!err && iRenameIfAlreadyExist) { 0194 int index = 2; 0195 while (!err && oNode.exist()) { 0196 err = oNode.setName(second % " (" % SKGServices::intToString(index) % ')'); 0197 ++index; 0198 } 0199 } 0200 0201 // save 0202 IFOKDO(err, oNode.setIcon(QStringLiteral("folder-orange"))) 0203 IFOKDO(err, oNode.setOrder(-1)) 0204 IFOKDO(err, oNode.save()) 0205 } 0206 } 0207 } 0208 0209 return err; 0210 } 0211 0212 SKGError SKGNodeObject::addNode(SKGNodeObject& oNode) 0213 { 0214 SKGError err; 0215 SKGTRACEINFUNCRC(10, err) 0216 if (getID() == 0) { 0217 err = SKGError(ERR_FAIL, i18nc("Error message: Something failed because of a database issue", "%1 failed because linked object is not yet saved in the database.", QStringLiteral("SKGNodeObject::addNode"))); 0218 } else { 0219 oNode = SKGNodeObject(getDocument()); 0220 err = oNode.setAttribute(QStringLiteral("rd_node_id"), SKGServices::intToString(getID())); 0221 } 0222 return err; 0223 } 0224 0225 SKGError SKGNodeObject::removeParentNode() 0226 { 0227 return setAttribute(QStringLiteral("rd_node_id"), QLatin1String("")); 0228 } 0229 0230 SKGError SKGNodeObject::setParentNode(const SKGNodeObject& iNode) 0231 { 0232 SKGError err; 0233 SKGTRACEINFUNCRC(10, err) 0234 if (iNode.getID() == 0) { 0235 err = SKGError(ERR_FAIL, i18nc("Error message: Something failed because of a database issue", "%1 failed because linked object is not yet saved in the database.", QStringLiteral("SKGNodeObject::setParentNode"))); 0236 } else { 0237 // Check if it is a loop 0238 SKGNodeObject current = iNode; 0239 do { 0240 if (current == *this) { 0241 err = SKGError(ERR_FAIL, i18nc("Error message: Loops are forbidden in Skrooge data structures", "You cannot create a loop, ie parent and child with the same name. For example, A > A is a loop. A > B > A is another kind of loop")); 0242 } else { 0243 SKGNodeObject parentNode; 0244 current.getParentNode(parentNode); 0245 current = parentNode; 0246 } 0247 } while (!err && current.getID() != 0); 0248 0249 IFOKDO(err, setAttribute(QStringLiteral("rd_node_id"), SKGServices::intToString(iNode.getID()))) 0250 } 0251 return err; 0252 } 0253 0254 SKGError SKGNodeObject::getParentNode(SKGNodeObject& oNode) const 0255 { 0256 SKGError err; 0257 QString parent_id = getAttribute(QStringLiteral("rd_node_id")); 0258 if (!parent_id.isEmpty()) { 0259 err = getDocument()->getObject(QStringLiteral("v_node"), "id=" % parent_id, oNode); 0260 } else { 0261 oNode = SKGNodeObject(); 0262 } 0263 return err; 0264 } 0265 0266 SKGError SKGNodeObject::getNodes(SKGListSKGObjectBase& oNodeList) const 0267 { 0268 return getDocument()->getObjects(QStringLiteral("v_node"), "rd_node_id=" % SKGServices::intToString(getID()) % " ORDER BY f_sortorder, t_name", oNodeList); 0269 } 0270 0271