1 /*
2 SPDX-FileCopyrightText: 2017 Smith AR <audoban@openmailbox.org>
3 SPDX-FileCopyrightText: 2017 Michail Vourlakos <mvourlakos@gmail.com>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #include "importer.h"
9
10 // local
11 #include <coretypes.h>
12 #include "manager.h"
13 #include "../lattecorona.h"
14 #include "../screenpool.h"
15 #include "../layout/abstractlayout.h"
16 #include "../settings/universalsettings.h"
17 #include "../templates/templatesmanager.h"
18 #include "../tools/commontools.h"
19
20 // Qt
21 #include <QFile>
22 #include <QLatin1String>
23
24 // KDE
25 #include <KArchive/KTar>
26 #include <KArchive/KArchiveEntry>
27 #include <KArchive/KArchiveDirectory>
28 #include <KConfigGroup>
29 #include <KLocalizedString>
30 #include <KNotification>
31
32
33 enum SessionType
34 {
35 DefaultSession = 0,
36 AlternativeSession
37 };
38
39 namespace Latte {
40 namespace Layouts {
41
Importer(QObject * parent)42 Importer::Importer(QObject *parent)
43 : QObject(parent)
44 {
45 m_manager = qobject_cast<Layouts::Manager *>(parent);
46
47 qDebug() << " IMPORTER, STORAGE TEMP DIR ::: " << m_storageTmpDir.path();
48 }
49
~Importer()50 Importer::~Importer()
51 {
52 }
53
updateOldConfiguration()54 bool Importer::updateOldConfiguration()
55 {
56 QFile oldAppletsFile(Latte::configPath() + "/lattedock-appletsrc");
57
58 if (!oldAppletsFile.exists()) {
59 return false;
60 }
61
62 //! import standard old configuration and create the relevant layouts
63 importOldLayout(Latte::configPath() + "/lattedock-appletsrc", i18n("My Layout"));
64 importOldLayout(Latte::configPath() + "/lattedock-appletsrc", i18n("Alternative"), true);
65
66 QFile extFile(Latte::configPath() + "/lattedockextrc");
67
68 //! import also the old user layouts into the new architecture
69 if (extFile.exists()) {
70 KSharedConfigPtr extFileConfig = KSharedConfig::openConfig(extFile.fileName());
71 KConfigGroup externalSettings = KConfigGroup(extFileConfig, "External");
72 QStringList userLayouts = externalSettings.readEntry("userLayouts", QStringList());
73
74 for(const auto &userConfig : userLayouts) {
75 qDebug() << "user layout : " << userConfig;
76 importOldConfiguration(userConfig);
77 }
78 }
79
80 m_manager->corona()->universalSettings()->setVersion(2);
81 m_manager->corona()->universalSettings()->setSingleModeLayoutName(i18n("My Layout"));
82
83 return true;
84 }
85
importOldLayout(QString oldAppletsPath,QString newName,bool alternative,QString exportDirectory)86 bool Importer::importOldLayout(QString oldAppletsPath, QString newName, bool alternative, QString exportDirectory)
87 {
88 QString newLayoutPath = layoutCanBeImported(oldAppletsPath, newName, exportDirectory);
89 qDebug() << "New Layout Should be created: " << newLayoutPath;
90
91 KSharedConfigPtr oldFile = KSharedConfig::openConfig(oldAppletsPath);
92 KSharedConfigPtr newFile = KSharedConfig::openConfig(newLayoutPath);
93
94 KConfigGroup containments = KConfigGroup(oldFile, "Containments");
95 KConfigGroup copiedContainments = KConfigGroup(newFile, "Containments");
96
97 QList<int> systrays;
98
99 bool atLeastOneContainmentWasFound{false};
100
101 //! first copy the latte containments that correspond to the correct session
102 //! and find also the systrays that should be copied also
103 for(const auto &containmentId : containments.groupList()) {
104 KConfigGroup containmentGroup = containments.group(containmentId);
105
106 QString plugin = containmentGroup.readEntry("plugin", QString());
107 SessionType session = (SessionType)containmentGroup.readEntry("session", (int)DefaultSession);
108
109 bool shouldImport = false;
110
111 if (plugin == QLatin1String("org.kde.latte.containment") && session == DefaultSession && !alternative) {
112 qDebug() << containmentId << " - " << plugin << " - " << session;
113 shouldImport = true;
114 } else if (plugin == QLatin1String("org.kde.latte.containment") && session == AlternativeSession && alternative) {
115 qDebug() << containmentId << " - " << plugin << " - " << session;
116 shouldImport = true;
117 }
118
119 // this latte containment should be imported
120 if (shouldImport) {
121 auto applets = containments.group(containmentId).group("Applets");
122
123 for(const auto &applet : applets.groupList()) {
124 KConfigGroup appletSettings = applets.group(applet).group("Configuration");
125
126 int systrayId = appletSettings.readEntry("SystrayContainmentId", "-1").toInt();
127
128 if (systrayId != -1) {
129 systrays.append(systrayId);
130 qDebug() << "systray was found in the containment...";
131 break;
132 }
133 }
134
135 KConfigGroup newContainment = copiedContainments.group(containmentId);
136 containmentGroup.copyTo(&newContainment);
137 atLeastOneContainmentWasFound = true;
138 }
139 }
140
141 //! not even one latte containment was found for that layout so we must break
142 //! the code here
143 if (!atLeastOneContainmentWasFound) {
144 return false;
145 }
146
147 //! copy also the systrays that were discovered
148 for(const auto &containmentId : containments.groupList()) {
149 int cId = containmentId.toInt();
150
151 if (systrays.contains(cId)) {
152 KConfigGroup containmentGroup = containments.group(containmentId);
153 KConfigGroup newContainment = copiedContainments.group(containmentId);
154 containmentGroup.copyTo(&newContainment);
155 }
156 }
157
158 copiedContainments.sync();
159
160 KConfigGroup oldGeneralSettings = KConfigGroup(oldFile, "General");
161
162 QStringList layoutLaunchers;
163
164 if (!alternative) {
165 layoutLaunchers = oldGeneralSettings.readEntry("globalLaunchers_default", QStringList());
166 } else {
167 layoutLaunchers = oldGeneralSettings.readEntry("globalLaunchers_alternative", QStringList());
168 }
169
170 //! update also the layout settings correctly
171 Layout::AbstractLayout newLayout(this, newLayoutPath, newName);
172 newLayout.setVersion(2);
173 newLayout.setLaunchers(layoutLaunchers);
174
175 //newLayout.setShowInMenu(true);
176
177 if (alternative) {
178 newLayout.setColor("purple");
179 } else {
180 newLayout.setColor("blue");
181 }
182
183 return true;
184 }
185
standardPaths(bool localfirst)186 QStringList Importer::standardPaths(bool localfirst)
187 {
188 QStringList paths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
189
190 if (localfirst) {
191 return paths;
192 } else {
193 QStringList reversed;
194
195 for (int i=paths.count()-1; i>=0; i--) {
196 reversed << paths[i];
197 }
198
199 return reversed;
200 }
201 }
202
standardPathsFor(QString subPath,bool localfirst)203 QStringList Importer::standardPathsFor(QString subPath, bool localfirst)
204 {
205 QStringList paths = standardPaths(localfirst);
206
207 QString separator = subPath.startsWith("/") ? "" : "/";
208
209 for (int i=0; i<paths.count(); ++i) {
210 paths[i] = paths[i] + separator + subPath;
211 }
212
213 return paths;
214 }
215
standardPath(QString subPath,bool localfirst)216 QString Importer::standardPath(QString subPath, bool localfirst)
217 {
218 QStringList paths = standardPaths(localfirst);
219
220 for(const auto &pt : paths) {
221 QString ptF = pt + "/" +subPath;
222 if (QFileInfo(ptF).exists()) {
223 return ptF;
224 }
225 }
226
227 //! in any case that above fails
228 if (QFileInfo("/usr/share/"+subPath).exists()) {
229 return "/usr/share/"+subPath;
230 }
231
232 return "";
233 }
234
storageTmpDir() const235 QString Importer::storageTmpDir() const
236 {
237 return m_storageTmpDir.path();
238 }
239
layoutCanBeImported(QString oldAppletsPath,QString newName,QString exportDirectory)240 QString Importer::layoutCanBeImported(QString oldAppletsPath, QString newName, QString exportDirectory)
241 {
242 QFile oldAppletsrc(oldAppletsPath);
243
244 //! old file doesn't exist
245 if (!oldAppletsrc.exists()) {
246 return QString();
247 }
248
249 KSharedConfigPtr lConfig = KSharedConfig::openConfig(oldAppletsPath);
250 KConfigGroup m_layoutGroup = KConfigGroup(lConfig, "LayoutSettings");
251 int layoutVersion = m_layoutGroup.readEntry("version", 1);
252
253 //! old file layout appears to not be old as its version is >=2
254 if (layoutVersion >= 2) {
255 return QString();
256 }
257
258 QDir layoutDir(exportDirectory.isNull() ? layoutUserDir() : exportDirectory);
259
260 if (!layoutDir.exists() && exportDirectory.isNull()) {
261 QDir(Latte::configPath()).mkdir("latte");
262 }
263
264 //! set up the new layout name
265 if (newName.isEmpty()) {
266 int extension = oldAppletsrc.fileName().lastIndexOf(".latterc");
267
268 if (extension > 0) {
269 //! remove the last 8 characters that contain the extension
270 newName = oldAppletsrc.fileName().remove(extension, 8);
271 } else {
272 newName = oldAppletsrc.fileName();
273 }
274 }
275
276 QString newLayoutPath = layoutDir.absolutePath() + "/" + newName + ".layout.latte";
277 QFile newLayoutFile(newLayoutPath);
278
279 QStringList filter;
280 filter.append(QString(newName + "*.layout.latte"));
281 QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks);
282
283 //! if the newLayout already exists provide a newName that doesn't
284 if (files.count() >= 1) {
285 int newCounter = files.count() + 1;
286
287 newLayoutPath = layoutDir.absolutePath() + "/" + newName + "-" + QString::number(newCounter) + ".layout.latte";
288 }
289
290 return newLayoutPath;
291 }
292
importOldConfiguration(QString oldConfigPath,QString newName)293 bool Importer::importOldConfiguration(QString oldConfigPath, QString newName)
294 {
295 QFile oldConfigFile(oldConfigPath);
296
297 if (!oldConfigFile.exists()) {
298 return false;
299 }
300
301 KTar archive(oldConfigPath, QStringLiteral("application/x-tar"));
302 archive.open(QIODevice::ReadOnly);
303
304 if (!archive.isOpen()) {
305 return false;
306 }
307
308 auto rootDir = archive.directory();
309 QTemporaryDir uniqueTempDir;
310 QDir tempDir{uniqueTempDir.path()};
311
312 qDebug() << "temp layout directory : " << tempDir.absolutePath();
313
314 if (rootDir) {
315 if (!tempDir.exists())
316 tempDir.mkpath(tempDir.absolutePath());
317
318 for(const auto &name : rootDir->entries()) {
319 auto fileEntry = rootDir->file(name);
320
321 if (fileEntry && (fileEntry->name() == QLatin1String("lattedockrc")
322 || fileEntry->name() == QLatin1String("lattedock-appletsrc"))) {
323 if (!fileEntry->copyTo(tempDir.absolutePath())) {
324 qInfo() << i18nc("import/export config", "The extracted file could not be copied!!!");
325 archive.close();
326 return false;
327 }
328 } else {
329 qInfo() << i18nc("import/export config", "The file has a wrong format!!!");
330 archive.close();
331 return false;
332 }
333 }
334 } else {
335 qInfo() << i18nc("import/export config", "The temp directory could not be created!!!");
336 archive.close();
337 return false;
338 }
339
340 //! only if the above has passed we must process the files
341 QString appletsPath(tempDir.absolutePath() + "/lattedock-appletsrc");
342 QString screensPath(tempDir.absolutePath() + "/lattedockrc");
343
344 if (!QFile(appletsPath).exists() || !QFile(screensPath).exists()) {
345 return false;
346 }
347
348
349 if (newName.isEmpty()) {
350 int lastSlash = oldConfigPath.lastIndexOf("/");
351 newName = oldConfigPath.remove(0, lastSlash + 1);
352
353 int ext = newName.lastIndexOf(".latterc");
354 newName = newName.remove(ext, 8);
355 }
356
357 if (!importOldLayout(appletsPath, newName)) {
358 return false;
359 }
360
361 //! the old configuration contains also screen values, these must be updated also
362 /*
363 * do not use any deprecated screen ids
364 * KSharedConfigPtr oldScreensConfig = KSharedConfig::openConfig(screensPath);
365 KConfigGroup m_screensGroup = KConfigGroup(oldScreensConfig, "ScreenConnectors");
366
367 //restore the known ids to connector mappings
368 for(const QString &key : m_screensGroup.keyList()) {
369 QString connector = m_screensGroup.readEntry(key, QString());
370 int id = key.toInt();
371
372 if (id >= 10 && !m_manager->corona()->screenPool()->hasScreenId(id)) {
373 m_manager->corona()->screenPool()->insertScreenMapping(id, connector);
374 }
375 }*/
376
377 return true;
378 }
379
exportFullConfiguration(QString file)380 bool Importer::exportFullConfiguration(QString file)
381 {
382 if (QFile::exists(file) && !QFile::remove(file)) {
383 return false;
384 }
385
386 KTar archive(file, QStringLiteral("application/x-tar"));
387
388 if (!archive.open(QIODevice::WriteOnly)) {
389 return false;
390 }
391
392 archive.addLocalFile(QString(Latte::configPath() + "/lattedockrc"), QStringLiteral("lattedockrc"));
393
394 for(const auto &layoutName : availableLayouts()) {
395 archive.addLocalFile(layoutUserFilePath(layoutName), QString("latte/" + layoutName + ".layout.latte"));
396 }
397
398 //! custom templates
399 QDir templatesDir(Latte::configPath() + "/latte/templates");
400 QStringList filters;
401 filters.append(QString("*.layout.latte"));
402 QStringList templates = templatesDir.entryList(filters, QDir::Files | QDir::Hidden | QDir::NoSymLinks);
403
404 for (int i=0; i<templates.count(); ++i) {
405 QString templatePath = templatesDir.path() + "/" + templates[i];
406 archive.addLocalFile(templatePath, QString("latte/templates/" + templates[i]));
407 }
408
409 filters.clear();
410 filters.append(QString("*.view.latte"));
411 templates = templatesDir.entryList(filters, QDir::Files | QDir::Hidden | QDir::NoSymLinks);
412
413 for (int i=0; i<templates.count(); ++i) {
414 QString templatePath = templatesDir.path() + "/" + templates[i];
415 archive.addLocalFile(templatePath, QString("latte/templates/" + templates[i]));
416 }
417
418 archive.close();
419
420 return true;
421 }
422
fileVersion(QString file)423 Importer::LatteFileVersion Importer::fileVersion(QString file)
424 {
425 if (!QFile::exists(file))
426 return UnknownFileType;
427
428 if (file.endsWith(".layout.latte")) {
429 KSharedConfigPtr lConfig = KSharedConfig::openConfig(QFileInfo(file).absoluteFilePath());
430 KConfigGroup layoutGroup = KConfigGroup(lConfig, "LayoutSettings");
431 int version = layoutGroup.readEntry("version", 1);
432
433 if (version == 2)
434 return Importer::LayoutVersion2;
435 else
436 return Importer::UnknownFileType;
437 }
438
439 if (!file.endsWith(".latterc")) {
440 return Importer::UnknownFileType;
441 }
442
443 KTar archive(file, QStringLiteral("application/x-tar"));
444 archive.open(QIODevice::ReadOnly);
445
446 //! if the file isnt a tar archive
447 if (!archive.isOpen()) {
448 return Importer::UnknownFileType;
449 }
450
451 QTemporaryDir archiveTempDir;
452
453 bool version1rc = false;
454 bool version1applets = false;
455
456 bool version2rc = false;
457 bool version2LatteDir = false;
458 bool version2layout = false;
459
460 archive.directory()->copyTo(archiveTempDir.path());
461
462
463 //rc file
464 QString rcFile(archiveTempDir.path() + "/lattedockrc");
465
466 if (QFile(rcFile).exists()) {
467 KSharedConfigPtr lConfig = KSharedConfig::openConfig(rcFile);
468 KConfigGroup universalGroup = KConfigGroup(lConfig, "UniversalSettings");
469 int version = universalGroup.readEntry("version", 1);
470
471 if (version == 1) {
472 version1rc = true;
473 } else if (version == 2) {
474 version2rc = true;
475 }
476 }
477
478 //applets file
479 QString appletsFile(archiveTempDir.path() + "/lattedock-appletsrc");
480
481 if (QFile(appletsFile).exists() && version1rc) {
482 KSharedConfigPtr lConfig = KSharedConfig::openConfig(appletsFile);
483 KConfigGroup generalGroup = KConfigGroup(lConfig, "LayoutSettings");
484 int version = generalGroup.readEntry("version", 1);
485
486 if (version == 1) {
487 version1applets = true;
488 } else if (version == 2) {
489 version2layout = true;
490 }
491 }
492
493 //latte directory
494 QString latteDir(archiveTempDir.path() + "/latte");
495
496 if (QDir(latteDir).exists()) {
497 version2LatteDir = true;
498 }
499
500 if (version1applets) {
501 return ConfigVersion1;
502 } else if (version2rc && version2LatteDir) {
503 return ConfigVersion2;
504 }
505
506 return Importer::UnknownFileType;
507 }
508
importHelper(QString fileName)509 bool Importer::importHelper(QString fileName)
510 {
511 LatteFileVersion version = fileVersion(fileName);
512
513 if ((version != ConfigVersion1) && (version != ConfigVersion2)) {
514 return false;
515 }
516
517 KTar archive(fileName, QStringLiteral("application/x-tar"));
518 archive.open(QIODevice::ReadOnly);
519
520 if (!archive.isOpen()) {
521 return false;
522 }
523
524 QDir latteDir(layoutUserDir());
525
526 if (latteDir.exists()) {
527 latteDir.removeRecursively();
528 }
529
530 archive.directory()->copyTo(Latte::configPath());
531
532 return true;
533 }
534
isAutostartEnabled()535 bool Importer::isAutostartEnabled()
536 {
537 QFile autostartFile(Latte::configPath() + "/autostart/org.kde.latte-dock.desktop");
538 return autostartFile.exists();
539 }
540
enableAutostart()541 void Importer::enableAutostart()
542 {
543 //! deprecated old file
544 QFile oldAutostartFile(Latte::configPath() + "/autostart/latte-dock.desktop");
545
546 if (oldAutostartFile.exists()) {
547 //! remove deprecated file
548 oldAutostartFile.remove();
549 }
550
551 QFile autostartFile(Latte::configPath() + "/autostart/org.kde.latte-dock.desktop");
552 QFile metaFile(standardPath("applications/org.kde.latte-dock.desktop", false));
553
554 if (autostartFile.exists()) {
555 //! if autostart file already exists, do nothing
556 return;
557 }
558
559 if (metaFile.exists()) {
560 //! check if autostart folder exists and create otherwise
561 QDir autostartDir(Latte::configPath() + "/autostart");
562 if (!autostartDir.exists()) {
563 QDir configDir(Latte::configPath());
564 configDir.mkdir("autostart");
565 }
566
567 metaFile.copy(autostartFile.fileName());
568 }
569 }
570
disableAutostart()571 void Importer::disableAutostart()
572 {
573 QFile oldAutostartFile(Latte::configPath() + "/autostart/latte-dock.desktop");
574
575 if (oldAutostartFile.exists()) {
576 //! remove deprecated file
577 oldAutostartFile.remove();
578 }
579
580 QFile autostartFile(Latte::configPath() + "/autostart/org.kde.latte-dock.desktop");
581
582 if (autostartFile.exists()) {
583 autostartFile.remove();
584 }
585 }
586
hasViewTemplate(const QString & name)587 bool Importer::hasViewTemplate(const QString &name)
588 {
589 return availableViewTemplates().contains(name);
590 }
591
importLayout(const QString & fileName,const QString & suggestedLayoutName)592 QString Importer::importLayout(const QString &fileName, const QString &suggestedLayoutName)
593 {
594 QString newLayoutName = importLayoutHelper(fileName, suggestedLayoutName);
595
596 if (!newLayoutName.isEmpty()) {
597 emit newLayoutAdded(layoutUserFilePath(newLayoutName));
598 }
599
600 return newLayoutName;
601 }
602
importLayoutHelper(const QString & fileName,const QString & suggestedLayoutName)603 QString Importer::importLayoutHelper(const QString &fileName, const QString &suggestedLayoutName)
604 {
605 LatteFileVersion version = fileVersion(fileName);
606
607 if (version != LayoutVersion2) {
608 return QString();
609 }
610
611 QString newLayoutName = !suggestedLayoutName.isEmpty() ? suggestedLayoutName : Layout::AbstractLayout::layoutName(fileName);
612 newLayoutName = uniqueLayoutName(newLayoutName);
613
614 QString newPath = layoutUserFilePath(newLayoutName);
615
616 QDir localLayoutsDir(layoutUserDir());
617
618 if (!localLayoutsDir.exists()) {
619 QDir(Latte::configPath()).mkdir("latte");
620 }
621
622 QFile(fileName).copy(newPath);
623
624 QFileInfo newFileInfo(newPath);
625
626 if (newFileInfo.exists() && !newFileInfo.isWritable()) {
627 QFile(newPath).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther);
628 }
629
630 return newLayoutName;
631 }
632
availableLayouts()633 QStringList Importer::availableLayouts()
634 {
635 QDir layoutDir(layoutUserDir());
636 QStringList filter;
637 filter.append(QString("*.layout.latte"));
638 QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks);
639
640 QStringList layoutNames;
641
642 for(const auto &file : files) {
643 layoutNames.append(Layout::AbstractLayout::layoutName(file));
644 }
645
646 return layoutNames;
647 }
648
availableViewTemplates()649 QStringList Importer::availableViewTemplates()
650 {
651 QStringList templates;
652
653 QDir localDir(layoutUserDir() + "/templates");
654 QStringList filter;
655 filter.append(QString("*.view.latte"));
656 QStringList files = localDir.entryList(filter, QDir::Files | QDir::NoSymLinks);
657
658 for(const auto &file : files) {
659 templates.append(Templates::Manager::templateName(file));
660 }
661
662 QDir systemDir(systemShellDataPath()+"/contents/templates");
663 QStringList sfiles = systemDir.entryList(filter, QDir::Files | QDir::NoSymLinks);
664
665 for(const auto &file : sfiles) {
666 QString name = Templates::Manager::templateName(file);
667 if (!templates.contains(name)) {
668 templates.append(name);
669 }
670 }
671
672 return templates;
673 }
674
availableLayoutTemplates()675 QStringList Importer::availableLayoutTemplates()
676 {
677 QStringList templates;
678
679 QDir localDir(layoutUserDir() + "/templates");
680 QStringList filter;
681 filter.append(QString("*.layout.latte"));
682 QStringList files = localDir.entryList(filter, QDir::Files | QDir::NoSymLinks);
683
684 for(const auto &file : files) {
685 templates.append(Templates::Manager::templateName(file));
686 }
687
688 QDir systemDir(systemShellDataPath()+"/contents/templates");
689 QStringList sfiles = systemDir.entryList(filter, QDir::Files | QDir::NoSymLinks);
690
691 for(const auto &file : sfiles) {
692 QString name = Templates::Manager::templateName(file);
693 if (!templates.contains(name)) {
694 templates.append(name);
695 }
696 }
697
698 return templates;
699 }
700
nameOfConfigFile(const QString & fileName)701 QString Importer::nameOfConfigFile(const QString &fileName)
702 {
703 int lastSlash = fileName.lastIndexOf("/");
704 QString tempLayoutFile = fileName;
705 QString layoutName = tempLayoutFile.remove(0, lastSlash + 1);
706
707 int ext = layoutName.lastIndexOf(".latterc");
708 layoutName = layoutName.remove(ext, 8);
709
710 return layoutName;
711 }
712
layoutExists(QString layoutName)713 bool Importer::layoutExists(QString layoutName)
714 {
715 return QFile::exists(layoutUserFilePath(layoutName));
716 }
717
718
layoutUserDir()719 QString Importer::layoutUserDir()
720 {
721 return QString(Latte::configPath() + "/latte");
722 }
723
layoutUserFilePath(QString layoutName)724 QString Importer::layoutUserFilePath(QString layoutName)
725 {
726 return QString(layoutUserDir() + "/" + layoutName + ".layout.latte");
727 }
728
systemShellDataPath()729 QString Importer::systemShellDataPath()
730 {
731 QStringList paths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
732 QString rootpath = paths.count() > 0 ? paths[paths.count()-1] : "/usr/share";
733 return rootpath + "/plasma/shells/org.kde.latte.shell";
734 }
735
layoutTemplateSystemFilePath(const QString & name)736 QString Importer::layoutTemplateSystemFilePath(const QString &name)
737 {
738 return systemShellDataPath() + "/contents/templates/" + name + ".layout.latte";
739 }
740
uniqueLayoutName(QString name)741 QString Importer::uniqueLayoutName(QString name)
742 {
743 int pos_ = name.lastIndexOf(QRegExp(QString(" - [0-9]+")));
744
745 if (layoutExists(name) && pos_ > 0) {
746 name = name.left(pos_);
747 }
748
749 int i = 2;
750
751 QString namePart = name;
752
753 while (layoutExists(name)) {
754 name = namePart + " - " + QString::number(i);
755 i++;
756 }
757
758 return name;
759 }
760
checkRepairMultipleLayoutsLinkedFile()761 QStringList Importer::checkRepairMultipleLayoutsLinkedFile()
762 {
763 QString linkedFilePath = layoutUserFilePath(Layout::MULTIPLELAYOUTSHIDDENNAME);
764 KSharedConfigPtr filePtr = KSharedConfig::openConfig(linkedFilePath);
765 KConfigGroup linkedContainments = KConfigGroup(filePtr, "Containments");
766
767 //! layoutName and its Containments
768 QHash<QString, QStringList> linkedLayoutContainmentGroups;
769
770 for(const auto &cId : linkedContainments.groupList()) {
771 QString layoutName = linkedContainments.group(cId).readEntry("layoutId", QString());
772
773 if (!layoutName.isEmpty()) {
774 qDebug() << layoutName;
775 linkedLayoutContainmentGroups[layoutName].append(cId);
776 linkedContainments.group(cId).writeEntry("layoutId", QString());
777 }
778 }
779
780 QStringList updatedLayouts;
781
782 for(const auto &layoutName : linkedLayoutContainmentGroups.uniqueKeys()) {
783 if (layoutName != Layout::MULTIPLELAYOUTSHIDDENNAME && layoutExists(layoutName)) {
784 updatedLayouts << layoutName;
785 KSharedConfigPtr layoutFilePtr = KSharedConfig::openConfig(layoutUserFilePath(layoutName));
786 KConfigGroup origLayoutContainments = KConfigGroup(layoutFilePtr, "Containments");
787
788 //Clear old containments
789 origLayoutContainments.deleteGroup();
790
791 //Update containments
792 for(const auto &cId : linkedLayoutContainmentGroups[layoutName]) {
793 KConfigGroup newContainment = origLayoutContainments.group(cId);
794 linkedContainments.group(cId).copyTo(&newContainment);
795 linkedContainments.group(cId).deleteGroup();
796 }
797
798 origLayoutContainments.sync();
799 }
800 }
801
802 //! clear all remaining ghost containments
803 for(const auto &cId : linkedContainments.groupList()) {
804 linkedContainments.group(cId).deleteGroup();
805 }
806
807 linkedContainments.sync();
808
809 return updatedLayouts;
810 }
811
812 }
813 }
814