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