File indexing completed on 2024-12-22 03:35:51

0001 /*
0002     File                 : ProjectParser.h
0003     Project              : LabPlot
0004     Description          : base class for project parsers
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2017-2024 Alexander Semke <alexander.semke@web.de>
0007     SPDX-FileCopyrightText: 2019 Stefan Gerlach <stefan.gerlach@uni.kn>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 #include "ProjectParser.h"
0012 #include "backend/core/AspectTreeModel.h"
0013 #include "backend/core/Project.h"
0014 #include "backend/core/column/Column.h"
0015 #include "backend/lib/trace.h"
0016 
0017 #include <KLocalizedString>
0018 
0019 /*!
0020 \class ProjectParser
0021 \brief  base class for project parsers
0022 
0023 \ingroup datasources
0024 */
0025 ProjectParser::ProjectParser()
0026     : QObject() {
0027 }
0028 
0029 ProjectParser::~ProjectParser() {
0030     delete m_previewProject;
0031 }
0032 
0033 void ProjectParser::setProjectFileName(const QString& name) {
0034     m_projectFileName = name;
0035 
0036     // delete the previous project used to generate the preview
0037     delete m_previewProject;
0038     m_previewProject = nullptr;
0039 }
0040 
0041 const QString& ProjectParser::projectFileName() const {
0042     return m_projectFileName;
0043 }
0044 
0045 QList<AspectType> ProjectParser::topLevelClasses() const {
0046     return m_topLevelClasses;
0047 }
0048 
0049 /*!
0050  * returns the model containing the structure of the current project used for the preview in the import project dialog.
0051  * The caller takes over the ownership of the model.
0052  */
0053 QAbstractItemModel* ProjectParser::model() {
0054     WAIT_CURSOR;
0055     PERFTRACE(QStringLiteral("project model for preview created"));
0056     delete m_previewProject;
0057     m_previewProject = new Project();
0058 
0059     bool rc = load(m_previewProject, true);
0060     AspectTreeModel* model = nullptr;
0061     if (rc) {
0062         model = new AspectTreeModel(m_previewProject);
0063         model->setReadOnly(true);
0064     }
0065 
0066     RESET_CURSOR;
0067     return model;
0068 }
0069 
0070 void ProjectParser::importTo(Folder* targetFolder, const QStringList& selectedPathes) {
0071     DEBUG(Q_FUNC_INFO << ", starting import of " << STDSTRING(m_projectFileName));
0072     QDEBUG(Q_FUNC_INFO << ", selected pathes: " << selectedPathes);
0073 
0074     // import the selected objects into a temporary project
0075     auto* project = new Project();
0076     project->setPathesToLoad(selectedPathes);
0077     bool rc = load(project, false);
0078     if (!rc) {
0079         delete project;
0080         DEBUG(Q_FUNC_INFO << ", ERROR: import of " << STDSTRING(m_projectFileName) << " failed.");
0081         return;
0082     }
0083 
0084     // determine the first child of the last top level child in the list of the imported objects
0085     // we want to navigate to in the project explorer after the import
0086     auto* lastTopLevelChild = project->child<AbstractAspect>(project->childCount<AbstractAspect>() - 1);
0087     AbstractAspect* childToNavigate = nullptr;
0088     if (lastTopLevelChild && lastTopLevelChild->childCount<AbstractAspect>() > 0) {
0089         childToNavigate = lastTopLevelChild->child<AbstractAspect>(0);
0090 
0091         // we don't want to select columns, select rather their parent spreadsheet
0092         if (dynamic_cast<const Column*>(childToNavigate))
0093             childToNavigate = lastTopLevelChild;
0094     } else {
0095         childToNavigate = lastTopLevelChild;
0096     }
0097 
0098     // move all children from the temp project to the target folder
0099     targetFolder->beginMacro(i18n("%1: Import from %2", targetFolder->name(), m_projectFileName));
0100     for (auto* child : project->children<AbstractAspect>()) {
0101         auto* folder = dynamic_cast<Folder*>(child);
0102         if (folder)
0103             moveFolder(targetFolder, folder);
0104         else if (child) {
0105             project->removeChild(child);
0106 
0107             // remove the object to be imported in the target folder if it already exists
0108             auto* targetChild = targetFolder->child<AbstractAspect>(child->name());
0109             if (targetChild)
0110                 targetFolder->removeChild(targetChild);
0111 
0112             targetFolder->addChild(child);
0113         }
0114     }
0115     targetFolder->setName(project->name());
0116     targetFolder->endMacro();
0117 
0118     Project::restorePointers(targetFolder);
0119     Project::retransformElements(targetFolder);
0120 
0121     delete project;
0122 
0123     if (childToNavigate != nullptr)
0124         targetFolder->project()->navigateTo(childToNavigate->path());
0125 
0126     DEBUG(Q_FUNC_INFO << ", import of " << STDSTRING(m_projectFileName) << " DONE");
0127 }
0128 
0129 /*
0130  * moved \c sourceChildFolderToMove from its parent folder to \c targetParentFolder
0131  * keeping (not overwriting) the sub-folder structure.
0132  */
0133 void ProjectParser::moveFolder(Folder* targetParentFolder, Folder* sourceChildFolderToMove) const {
0134     auto* targetChildFolder = targetParentFolder->child<Folder>(sourceChildFolderToMove->name());
0135     if (targetChildFolder) {
0136         // folder exists already in the target parent folder,
0137         //-> recursively move its children from source into target parent folder
0138         for (auto* child : sourceChildFolderToMove->children<AbstractAspect>()) {
0139             auto* folder = dynamic_cast<Folder*>(child);
0140             if (folder) {
0141                 moveFolder(targetChildFolder, folder);
0142             } else if (child) {
0143                 sourceChildFolderToMove->removeChild(child);
0144 
0145                 // remove the object to be imported in the target folder if it's already existing
0146                 auto* targetChild = targetChildFolder->child<AbstractAspect>(child->name());
0147                 if (targetChild)
0148                     targetChildFolder->removeChild(targetChild);
0149 
0150                 targetChildFolder->addChild(child);
0151             }
0152         }
0153     } else {
0154         // folder doesn't exist yet in the target parent folder -> simply move it
0155         auto* sourceParentFolder = dynamic_cast<Folder*>(sourceChildFolderToMove->parentAspect());
0156         if (sourceParentFolder)
0157             sourceParentFolder->removeChild(sourceChildFolderToMove);
0158         targetParentFolder->addChild(sourceChildFolderToMove);
0159     }
0160 }