mirror of
https://github.com/KDE/latte-dock.git
synced 2025-01-14 09:18:06 +03:00
94914ee578
--if the app crashed and the user trys to reopen Latte then the Containments must first return to their Original Layouts. This code provides that and informs also the user during the startup.
583 lines
18 KiB
C++
583 lines
18 KiB
C++
/*
|
|
* Copyright 2017 Smith AR <audoban@openmailbox.org>
|
|
* Michail Vourlakos <mvourlakos@gmail.com>
|
|
*
|
|
* This file is part of Latte-Dock
|
|
*
|
|
* Latte-Dock is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* Latte-Dock is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "importer.h"
|
|
|
|
#include "layoutmanager.h"
|
|
#include "layout.h"
|
|
#include "screenpool.h"
|
|
#include "../liblattedock/dock.h"
|
|
|
|
#include <QFile>
|
|
#include <QTemporaryDir>
|
|
|
|
#include <KArchive/KTar>
|
|
#include <KArchive/KArchiveEntry>
|
|
#include <KArchive/KArchiveDirectory>
|
|
#include <KConfigGroup>
|
|
#include <KLocalizedString>
|
|
#include <KNotification>
|
|
|
|
|
|
namespace Latte {
|
|
|
|
Importer::Importer(QObject *parent)
|
|
: QObject(parent)
|
|
{
|
|
m_manager = qobject_cast<LayoutManager *>(parent);
|
|
}
|
|
|
|
Importer::~Importer()
|
|
{
|
|
}
|
|
|
|
bool Importer::updateOldConfiguration()
|
|
{
|
|
QFile oldAppletsFile(QDir::homePath() + "/.config/lattedock-appletsrc");
|
|
|
|
if (!oldAppletsFile.exists()) {
|
|
return false;
|
|
}
|
|
|
|
//! import standard old configuration and create the relevant layouts
|
|
importOldLayout(QDir::homePath() + "/.config/lattedock-appletsrc", i18n("My Layout"));
|
|
importOldLayout(QDir::homePath() + "/.config/lattedock-appletsrc", i18n("Alternative"), true);
|
|
|
|
QFile extFile(QDir::homePath() + "/.config/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());
|
|
|
|
foreach (auto userConfig, userLayouts) {
|
|
qDebug() << "user layout : " << userConfig;
|
|
importOldConfiguration(userConfig);
|
|
}
|
|
}
|
|
|
|
m_manager->corona()->universalSettings()->setCurrentLayoutName(i18n("My Layout"));
|
|
m_manager->corona()->universalSettings()->setVersion(2);
|
|
|
|
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<int> 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
|
|
foreach (auto containmentId, containments.groupList()) {
|
|
KConfigGroup containmentGroup = containments.group(containmentId);
|
|
|
|
QString plugin = containmentGroup.readEntry("plugin", QString());
|
|
Dock::SessionType session = (Dock::SessionType)containmentGroup.readEntry("session", (int)Dock::DefaultSession);
|
|
|
|
bool shouldImport = false;
|
|
|
|
if (plugin == "org.kde.latte.containment" && session == Dock::DefaultSession && !alternative) {
|
|
qDebug() << containmentId << " - " << plugin << " - " << session;
|
|
shouldImport = true;
|
|
} else if (plugin == "org.kde.latte.containment" && session == Dock::AlternativeSession && alternative) {
|
|
qDebug() << containmentId << " - " << plugin << " - " << session;
|
|
shouldImport = true;
|
|
}
|
|
|
|
// this latte containment should be imported
|
|
if (shouldImport) {
|
|
auto applets = containments.group(containmentId).group("Applets");
|
|
|
|
foreach (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
|
|
foreach (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 newLayout(this, newLayoutPath, newName);
|
|
newLayout.setVersion(2);
|
|
newLayout.setLaunchers(layoutLaunchers);
|
|
|
|
newLayout.setShowInMenu(true);
|
|
|
|
if (alternative) {
|
|
newLayout.setColor("purple");
|
|
} else {
|
|
newLayout.setColor("blue");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
QString Importer::layoutCanBeImported(QString oldAppletsPath, QString newName, QString exportDirectory)
|
|
{
|
|
QFile oldAppletsrc(oldAppletsPath);
|
|
|
|
//! old file doesnt exist
|
|
if (!oldAppletsrc.exists()) {
|
|
return QString();
|
|
}
|
|
|
|
KSharedConfigPtr lConfig = KSharedConfig::openConfig(oldAppletsPath);
|
|
KConfigGroup m_layoutGroup = KConfigGroup(lConfig, "LayoutSettings");
|
|
int layoutVersion = m_layoutGroup.readEntry("version", 1);
|
|
|
|
//! old file layout appears to not be old as its version is >=2
|
|
if (layoutVersion >= 2) {
|
|
return QString();
|
|
}
|
|
|
|
QDir layoutDir(exportDirectory.isNull() ? QDir::homePath() + "/.config/latte" : exportDirectory);
|
|
|
|
if (!layoutDir.exists() && exportDirectory.isNull()) {
|
|
QDir(QDir::homePath() + "/.config").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 doesnt
|
|
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());
|
|
|
|
foreach (auto &name, rootDir->entries()) {
|
|
auto fileEntry = rootDir->file(name);
|
|
|
|
if (fileEntry && (fileEntry->name() == "lattedockrc"
|
|
|| fileEntry->name() == "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
|
|
KSharedConfigPtr oldScreensConfig = KSharedConfig::openConfig(screensPath);
|
|
KConfigGroup m_screensGroup = KConfigGroup(oldScreensConfig, "ScreenConnectors");
|
|
|
|
//restore the known ids to connector mappings
|
|
foreach (const QString &key, m_screensGroup.keyList()) {
|
|
QString connector = m_screensGroup.readEntry(key, QString());
|
|
int id = key.toInt();
|
|
|
|
if (id >= 10 && !m_manager->corona()->screenPool()->knownIds().contains(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(QDir::homePath() + "/.config/lattedockrc"), QStringLiteral("lattedockrc"));
|
|
archive.addLocalDirectory(QString(QDir::homePath() + "/.config/latte"), QStringLiteral("latte"));
|
|
|
|
archive.close();
|
|
|
|
return true;
|
|
}
|
|
|
|
Importer::LatteFileVersion Importer::fileVersion(QString file)
|
|
{
|
|
if (!QFile::exists(file))
|
|
return UnknownFileType;
|
|
|
|
if (file.endsWith(".layout.latte")) {
|
|
KSharedConfigPtr lConfig = KSharedConfig::openConfig(QFileInfo(file).absoluteFilePath());
|
|
KConfigGroup layoutGroup = KConfigGroup(lConfig, "LayoutSettings");
|
|
int version = layoutGroup.readEntry("version", 1);
|
|
|
|
if (version == 2)
|
|
return Importer::LayoutVersion2;
|
|
else
|
|
return Importer::UnknownFileType;
|
|
}
|
|
|
|
if (!file.endsWith(".latterc")) {
|
|
return Importer::UnknownFileType;
|
|
}
|
|
|
|
KTar archive(file, QStringLiteral("application/x-tar"));
|
|
archive.open(QIODevice::ReadOnly);
|
|
|
|
//! if the file isnt a tar archive
|
|
if (!archive.isOpen()) {
|
|
return Importer::UnknownFileType;
|
|
}
|
|
|
|
QTemporaryDir archiveTempDir;
|
|
|
|
bool version1rc = false;
|
|
bool version1applets = false;
|
|
|
|
bool version2rc = false;
|
|
bool version2LatteDir = false;
|
|
bool version2layout = false;
|
|
|
|
archive.directory()->copyTo(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 && 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;
|
|
}
|
|
|
|
QString latteDirPath(QDir::homePath() + "/.config/latte");
|
|
QDir latteDir(latteDirPath);
|
|
|
|
if (latteDir.exists()) {
|
|
latteDir.removeRecursively();
|
|
}
|
|
|
|
archive.directory()->copyTo(QString(QDir::homePath() + "/.config"));
|
|
|
|
return true;
|
|
}
|
|
|
|
QString Importer::importLayoutHelper(QString fileName)
|
|
{
|
|
LatteFileVersion version = fileVersion(fileName);
|
|
|
|
if (version != LayoutVersion2) {
|
|
return QString();
|
|
}
|
|
|
|
QString newLayoutName = Layout::layoutName(fileName);
|
|
newLayoutName = uniqueLayoutName(newLayoutName);
|
|
|
|
QFile(fileName).copy(QDir::homePath() + "/.config/latte/" + newLayoutName + ".layout.latte");
|
|
|
|
return newLayoutName;
|
|
|
|
}
|
|
|
|
QStringList Importer::availableLayouts()
|
|
{
|
|
QDir layoutDir(QDir::homePath() + "/.config/latte");
|
|
QStringList filter;
|
|
filter.append(QString("*.layout.latte"));
|
|
QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks);
|
|
|
|
QStringList layoutNames;
|
|
|
|
foreach (auto file, files) {
|
|
layoutNames.append(Layout::layoutName(file));
|
|
}
|
|
|
|
return layoutNames;
|
|
}
|
|
|
|
|
|
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(layoutFilePath(layoutName));
|
|
}
|
|
|
|
|
|
QString Importer::layoutFilePath(QString layoutName)
|
|
{
|
|
return QString(QDir::homePath() + "/.config/latte/" + layoutName + ".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 = QDir::homePath() + "/.config/latte/" + Layout::MultipleLayoutsName + ".layout.latte";
|
|
KSharedConfigPtr filePtr = KSharedConfig::openConfig(linkedFilePath);
|
|
KConfigGroup linkedContainments = KConfigGroup(filePtr, "Containments");
|
|
|
|
//! layoutName and its Containments
|
|
QHash<QString, QStringList> linkedLayoutContainmentGroups;
|
|
|
|
foreach (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;
|
|
|
|
foreach (auto layoutName, linkedLayoutContainmentGroups.uniqueKeys()) {
|
|
if (layoutName != Layout::MultipleLayoutsName && layoutExists(layoutName)) {
|
|
updatedLayouts << layoutName;
|
|
KSharedConfigPtr layoutFilePtr = KSharedConfig::openConfig(layoutFilePath(layoutName));
|
|
KConfigGroup origLayoutContainments = KConfigGroup(layoutFilePtr, "Containments");
|
|
|
|
//Clear old containments
|
|
origLayoutContainments.deleteGroup();
|
|
|
|
//Update containments
|
|
foreach (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
|
|
foreach (auto cId, linkedContainments.groupList()) {
|
|
linkedContainments.group(cId).deleteGroup();
|
|
}
|
|
|
|
linkedContainments.sync();
|
|
|
|
return updatedLayouts;
|
|
}
|
|
|
|
}
|