/* SPDX-FileCopyrightText: 2017 Smith AR SPDX-FileCopyrightText: 2017 Michail Vourlakos SPDX-License-Identifier: GPL-2.0-or-later */ #include "importer.h" // local #include #include "manager.h" #include "../lattecorona.h" #include "../screenpool.h" #include "../layout/abstractlayout.h" #include "../settings/universalsettings.h" #include "../templates/templatesmanager.h" #include "../tools/commontools.h" // Qt #include #include // KDE #include #include #include #include #include #include enum SessionType { DefaultSession = 0, AlternativeSession }; namespace Latte { namespace Layouts { Importer::Importer(QObject *parent) : QObject(parent) { m_manager = qobject_cast(parent); qDebug() << " IMPORTER, STORAGE TEMP DIR ::: " << m_storageTmpDir.path(); } Importer::~Importer() { } bool Importer::updateOldConfiguration() { QFile oldAppletsFile(Latte::configPath() + "/lattedock-appletsrc"); if (!oldAppletsFile.exists()) { return false; } //! import standard old configuration and create the relevant layouts importOldLayout(Latte::configPath() + "/lattedock-appletsrc", i18n("My Layout")); importOldLayout(Latte::configPath() + "/lattedock-appletsrc", i18n("Alternative"), true); QFile extFile(Latte::configPath() + "/lattedockextrc"); //! import also the old user layouts into the new architecture if (extFile.exists()) { KSharedConfigPtr extFileConfig = KSharedConfig::openConfig(extFile.fileName()); KConfigGroup externalSettings = KConfigGroup(extFileConfig, "External"); QStringList userLayouts = externalSettings.readEntry("userLayouts", QStringList()); for(const auto &userConfig : userLayouts) { qDebug() << "user layout : " << userConfig; importOldConfiguration(userConfig); } } m_manager->corona()->universalSettings()->setVersion(2); m_manager->corona()->universalSettings()->setSingleModeLayoutName(i18n("My Layout")); return true; } bool Importer::importOldLayout(QString oldAppletsPath, QString newName, bool alternative, QString exportDirectory) { QString newLayoutPath = layoutCanBeImported(oldAppletsPath, newName, exportDirectory); qDebug() << "New Layout Should be created: " << newLayoutPath; KSharedConfigPtr oldFile = KSharedConfig::openConfig(oldAppletsPath); KSharedConfigPtr newFile = KSharedConfig::openConfig(newLayoutPath); KConfigGroup containments = KConfigGroup(oldFile, "Containments"); KConfigGroup copiedContainments = KConfigGroup(newFile, "Containments"); QList systrays; bool atLeastOneContainmentWasFound{false}; //! first copy the latte containments that correspond to the correct session //! and find also the systrays that should be copied also for(const auto &containmentId : containments.groupList()) { KConfigGroup containmentGroup = containments.group(containmentId); QString plugin = containmentGroup.readEntry("plugin", QString()); SessionType session = (SessionType)containmentGroup.readEntry("session", (int)DefaultSession); bool shouldImport = false; if (plugin == QLatin1String("org.kde.latte.containment") && session == DefaultSession && !alternative) { qDebug() << containmentId << " - " << plugin << " - " << session; shouldImport = true; } else if (plugin == QLatin1String("org.kde.latte.containment") && session == AlternativeSession && alternative) { qDebug() << containmentId << " - " << plugin << " - " << session; shouldImport = true; } // this latte containment should be imported if (shouldImport) { auto applets = containments.group(containmentId).group("Applets"); for(const auto &applet : applets.groupList()) { KConfigGroup appletSettings = applets.group(applet).group("Configuration"); int systrayId = appletSettings.readEntry("SystrayContainmentId", "-1").toInt(); if (systrayId != -1) { systrays.append(systrayId); qDebug() << "systray was found in the containment..."; break; } } KConfigGroup newContainment = copiedContainments.group(containmentId); containmentGroup.copyTo(&newContainment); atLeastOneContainmentWasFound = true; } } //! not even one latte containment was found for that layout so we must break //! the code here if (!atLeastOneContainmentWasFound) { return false; } //! copy also the systrays that were discovered for(const auto &containmentId : containments.groupList()) { int cId = containmentId.toInt(); if (systrays.contains(cId)) { KConfigGroup containmentGroup = containments.group(containmentId); KConfigGroup newContainment = copiedContainments.group(containmentId); containmentGroup.copyTo(&newContainment); } } copiedContainments.sync(); KConfigGroup oldGeneralSettings = KConfigGroup(oldFile, "General"); QStringList layoutLaunchers; if (!alternative) { layoutLaunchers = oldGeneralSettings.readEntry("globalLaunchers_default", QStringList()); } else { layoutLaunchers = oldGeneralSettings.readEntry("globalLaunchers_alternative", QStringList()); } //! update also the layout settings correctly Layout::AbstractLayout newLayout(this, newLayoutPath, newName); newLayout.setVersion(2); newLayout.setLaunchers(layoutLaunchers); //newLayout.setShowInMenu(true); if (alternative) { newLayout.setColor("purple"); } else { newLayout.setColor("blue"); } return true; } QStringList Importer::standardPaths(bool localfirst) { QStringList paths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); if (localfirst) { return paths; } else { QStringList reversed; for (int i=paths.count()-1; i>=0; i--) { reversed << paths[i]; } return reversed; } } QStringList Importer::standardPathsFor(QString subPath, bool localfirst) { QStringList paths = standardPaths(localfirst); QString separator = subPath.startsWith("/") ? "" : "/"; for (int i=0; i=2 if (layoutVersion >= 2) { return QString(); } QDir layoutDir(exportDirectory.isNull() ? layoutUserDir() : exportDirectory); if (!layoutDir.exists() && exportDirectory.isNull()) { QDir(Latte::configPath()).mkdir("latte"); } //! set up the new layout name if (newName.isEmpty()) { int extension = oldAppletsrc.fileName().lastIndexOf(".latterc"); if (extension > 0) { //! remove the last 8 characters that contain the extension newName = oldAppletsrc.fileName().remove(extension, 8); } else { newName = oldAppletsrc.fileName(); } } QString newLayoutPath = layoutDir.absolutePath() + "/" + newName + ".layout.latte"; QFile newLayoutFile(newLayoutPath); QStringList filter; filter.append(QString(newName + "*.layout.latte")); QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks); //! if the newLayout already exists provide a newName that doesn't if (files.count() >= 1) { int newCounter = files.count() + 1; newLayoutPath = layoutDir.absolutePath() + "/" + newName + "-" + QString::number(newCounter) + ".layout.latte"; } return newLayoutPath; } bool Importer::importOldConfiguration(QString oldConfigPath, QString newName) { QFile oldConfigFile(oldConfigPath); if (!oldConfigFile.exists()) { return false; } KTar archive(oldConfigPath, QStringLiteral("application/x-tar")); archive.open(QIODevice::ReadOnly); if (!archive.isOpen()) { return false; } auto rootDir = archive.directory(); QTemporaryDir uniqueTempDir; QDir tempDir{uniqueTempDir.path()}; qDebug() << "temp layout directory : " << tempDir.absolutePath(); if (rootDir) { if (!tempDir.exists()) tempDir.mkpath(tempDir.absolutePath()); for(const auto &name : rootDir->entries()) { auto fileEntry = rootDir->file(name); if (fileEntry && (fileEntry->name() == QLatin1String("lattedockrc") || fileEntry->name() == QLatin1String("lattedock-appletsrc"))) { if (!fileEntry->copyTo(tempDir.absolutePath())) { qInfo() << i18nc("import/export config", "The extracted file could not be copied!!!"); archive.close(); return false; } } else { qInfo() << i18nc("import/export config", "The file has a wrong format!!!"); archive.close(); return false; } } } else { qInfo() << i18nc("import/export config", "The temp directory could not be created!!!"); archive.close(); return false; } //! only if the above has passed we must process the files QString appletsPath(tempDir.absolutePath() + "/lattedock-appletsrc"); QString screensPath(tempDir.absolutePath() + "/lattedockrc"); if (!QFile(appletsPath).exists() || !QFile(screensPath).exists()) { return false; } if (newName.isEmpty()) { int lastSlash = oldConfigPath.lastIndexOf("/"); newName = oldConfigPath.remove(0, lastSlash + 1); int ext = newName.lastIndexOf(".latterc"); newName = newName.remove(ext, 8); } if (!importOldLayout(appletsPath, newName)) { return false; } //! the old configuration contains also screen values, these must be updated also /* * do not use any deprecated screen ids * KSharedConfigPtr oldScreensConfig = KSharedConfig::openConfig(screensPath); KConfigGroup m_screensGroup = KConfigGroup(oldScreensConfig, "ScreenConnectors"); //restore the known ids to connector mappings for(const QString &key : m_screensGroup.keyList()) { QString connector = m_screensGroup.readEntry(key, QString()); int id = key.toInt(); if (id >= 10 && !m_manager->corona()->screenPool()->hasScreenId(id)) { m_manager->corona()->screenPool()->insertScreenMapping(id, connector); } }*/ return true; } bool Importer::exportFullConfiguration(QString file) { if (QFile::exists(file) && !QFile::remove(file)) { return false; } KTar archive(file, QStringLiteral("application/x-tar")); if (!archive.open(QIODevice::WriteOnly)) { return false; } archive.addLocalFile(QString(Latte::configPath() + "/lattedockrc"), QStringLiteral("lattedockrc")); for(const auto &layoutName : availableLayouts()) { archive.addLocalFile(layoutUserFilePath(layoutName), QString("latte/" + layoutName + ".layout.latte")); } //! custom templates QDir templatesDir(Latte::configPath() + "/latte/templates"); QStringList filters; filters.append(QString("*.layout.latte")); QStringList templates = templatesDir.entryList(filters, QDir::Files | QDir::Hidden | QDir::NoSymLinks); for (int i=0; icopyTo(archiveTempDir.path()); //rc file QString rcFile(archiveTempDir.path() + "/lattedockrc"); if (QFile(rcFile).exists()) { KSharedConfigPtr lConfig = KSharedConfig::openConfig(rcFile); KConfigGroup universalGroup = KConfigGroup(lConfig, "UniversalSettings"); int version = universalGroup.readEntry("version", 1); if (version == 1) { version1rc = true; } else if (version == 2) { version2rc = true; } } //applets file QString appletsFile(archiveTempDir.path() + "/lattedock-appletsrc"); if (QFile(appletsFile).exists() && version1rc) { KSharedConfigPtr lConfig = KSharedConfig::openConfig(appletsFile); KConfigGroup generalGroup = KConfigGroup(lConfig, "LayoutSettings"); int version = generalGroup.readEntry("version", 1); if (version == 1) { version1applets = true; } else if (version == 2) { version2layout = true; } } //latte directory QString latteDir(archiveTempDir.path() + "/latte"); if (QDir(latteDir).exists()) { version2LatteDir = true; } if (version1applets) { return ConfigVersion1; } else if (version2rc && version2LatteDir) { return ConfigVersion2; } return Importer::UnknownFileType; } bool Importer::importHelper(QString fileName) { LatteFileVersion version = fileVersion(fileName); if ((version != ConfigVersion1) && (version != ConfigVersion2)) { return false; } KTar archive(fileName, QStringLiteral("application/x-tar")); archive.open(QIODevice::ReadOnly); if (!archive.isOpen()) { return false; } QDir latteDir(layoutUserDir()); if (latteDir.exists()) { latteDir.removeRecursively(); } archive.directory()->copyTo(Latte::configPath()); return true; } bool Importer::isAutostartEnabled() { QFile autostartFile(Latte::configPath() + "/autostart/org.kde.latte-dock.desktop"); return autostartFile.exists(); } void Importer::enableAutostart() { //! deprecated old file QFile oldAutostartFile(Latte::configPath() + "/autostart/latte-dock.desktop"); if (oldAutostartFile.exists()) { //! remove deprecated file oldAutostartFile.remove(); } QFile autostartFile(Latte::configPath() + "/autostart/org.kde.latte-dock.desktop"); QFile metaFile(standardPath("applications/org.kde.latte-dock.desktop", false)); if (autostartFile.exists()) { //! if autostart file already exists, do nothing return; } if (metaFile.exists()) { //! check if autostart folder exists and create otherwise QDir autostartDir(Latte::configPath() + "/autostart"); if (!autostartDir.exists()) { QDir configDir(Latte::configPath()); configDir.mkdir("autostart"); } metaFile.copy(autostartFile.fileName()); } } void Importer::disableAutostart() { QFile oldAutostartFile(Latte::configPath() + "/autostart/latte-dock.desktop"); if (oldAutostartFile.exists()) { //! remove deprecated file oldAutostartFile.remove(); } QFile autostartFile(Latte::configPath() + "/autostart/org.kde.latte-dock.desktop"); if (autostartFile.exists()) { autostartFile.remove(); } } bool Importer::hasViewTemplate(const QString &name) { return availableViewTemplates().contains(name); } QString Importer::importLayout(const QString &fileName, const QString &suggestedLayoutName) { QString newLayoutName = importLayoutHelper(fileName, suggestedLayoutName); if (!newLayoutName.isEmpty()) { emit newLayoutAdded(layoutUserFilePath(newLayoutName)); } return newLayoutName; } QString Importer::importLayoutHelper(const QString &fileName, const QString &suggestedLayoutName) { LatteFileVersion version = fileVersion(fileName); if (version != LayoutVersion2) { return QString(); } QString newLayoutName = !suggestedLayoutName.isEmpty() ? suggestedLayoutName : Layout::AbstractLayout::layoutName(fileName); newLayoutName = uniqueLayoutName(newLayoutName); QString newPath = layoutUserFilePath(newLayoutName); QDir localLayoutsDir(layoutUserDir()); if (!localLayoutsDir.exists()) { QDir(Latte::configPath()).mkdir("latte"); } QFile(fileName).copy(newPath); QFileInfo newFileInfo(newPath); if (newFileInfo.exists() && !newFileInfo.isWritable()) { QFile(newPath).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } return newLayoutName; } QStringList Importer::availableLayouts() { QDir layoutDir(layoutUserDir()); QStringList filter; filter.append(QString("*.layout.latte")); QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks); QStringList layoutNames; for(const auto &file : files) { layoutNames.append(Layout::AbstractLayout::layoutName(file)); } return layoutNames; } QStringList Importer::availableViewTemplates() { QStringList templates; QDir localDir(layoutUserDir() + "/templates"); QStringList filter; filter.append(QString("*.view.latte")); QStringList files = localDir.entryList(filter, QDir::Files | QDir::NoSymLinks); for(const auto &file : files) { templates.append(Templates::Manager::templateName(file)); } QDir systemDir(systemShellDataPath()+"/contents/templates"); QStringList sfiles = systemDir.entryList(filter, QDir::Files | QDir::NoSymLinks); for(const auto &file : sfiles) { QString name = Templates::Manager::templateName(file); if (!templates.contains(name)) { templates.append(name); } } return templates; } QStringList Importer::availableLayoutTemplates() { QStringList templates; QDir localDir(layoutUserDir() + "/templates"); QStringList filter; filter.append(QString("*.layout.latte")); QStringList files = localDir.entryList(filter, QDir::Files | QDir::NoSymLinks); for(const auto &file : files) { templates.append(Templates::Manager::templateName(file)); } QDir systemDir(systemShellDataPath()+"/contents/templates"); QStringList sfiles = systemDir.entryList(filter, QDir::Files | QDir::NoSymLinks); for(const auto &file : sfiles) { QString name = Templates::Manager::templateName(file); if (!templates.contains(name)) { templates.append(name); } } return templates; } QString Importer::nameOfConfigFile(const QString &fileName) { int lastSlash = fileName.lastIndexOf("/"); QString tempLayoutFile = fileName; QString layoutName = tempLayoutFile.remove(0, lastSlash + 1); int ext = layoutName.lastIndexOf(".latterc"); layoutName = layoutName.remove(ext, 8); return layoutName; } bool Importer::layoutExists(QString layoutName) { return QFile::exists(layoutUserFilePath(layoutName)); } QString Importer::layoutUserDir() { return QString(Latte::configPath() + "/latte"); } QString Importer::layoutUserFilePath(QString layoutName) { return QString(layoutUserDir() + "/" + layoutName + ".layout.latte"); } QString Importer::systemShellDataPath() { QStringList paths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); QString rootpath = paths.count() > 0 ? paths[paths.count()-1] : "/usr/share"; return rootpath + "/plasma/shells/org.kde.latte.shell"; } QString Importer::layoutTemplateSystemFilePath(const QString &name) { return systemShellDataPath() + "/contents/templates/" + name + ".layout.latte"; } QString Importer::uniqueLayoutName(QString name) { int pos_ = name.lastIndexOf(QRegExp(QString(" - [0-9]+"))); if (layoutExists(name) && pos_ > 0) { name = name.left(pos_); } int i = 2; QString namePart = name; while (layoutExists(name)) { name = namePart + " - " + QString::number(i); i++; } return name; } QStringList Importer::checkRepairMultipleLayoutsLinkedFile() { QString linkedFilePath = layoutUserFilePath(Layout::MULTIPLELAYOUTSHIDDENNAME); KSharedConfigPtr filePtr = KSharedConfig::openConfig(linkedFilePath); KConfigGroup linkedContainments = KConfigGroup(filePtr, "Containments"); //! layoutName and its Containments QHash linkedLayoutContainmentGroups; for(const auto &cId : linkedContainments.groupList()) { QString layoutName = linkedContainments.group(cId).readEntry("layoutId", QString()); if (!layoutName.isEmpty()) { qDebug() << layoutName; linkedLayoutContainmentGroups[layoutName].append(cId); linkedContainments.group(cId).writeEntry("layoutId", QString()); } } QStringList updatedLayouts; for(const auto &layoutName : linkedLayoutContainmentGroups.uniqueKeys()) { if (layoutName != Layout::MULTIPLELAYOUTSHIDDENNAME && layoutExists(layoutName)) { updatedLayouts << layoutName; KSharedConfigPtr layoutFilePtr = KSharedConfig::openConfig(layoutUserFilePath(layoutName)); KConfigGroup origLayoutContainments = KConfigGroup(layoutFilePtr, "Containments"); //Clear old containments origLayoutContainments.deleteGroup(); //Update containments for(const auto &cId : linkedLayoutContainmentGroups[layoutName]) { KConfigGroup newContainment = origLayoutContainments.group(cId); linkedContainments.group(cId).copyTo(&newContainment); linkedContainments.group(cId).deleteGroup(); } origLayoutContainments.sync(); } } //! clear all remaining ghost containments for(const auto &cId : linkedContainments.groupList()) { linkedContainments.group(cId).deleteGroup(); } linkedContainments.sync(); return updatedLayouts; } } }