1 /*
2     This file is part of the KDE project
3     SPDX-FileCopyrightText: 2008 Eduardo Robles Elvira <edulix@gmail.com>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "konqsessionmanager.h"
9 #include "konqmisc.h"
10 #include "konqmainwindow.h"
11 #include "konqsessionmanager_interface.h"
12 #include "konqsessionmanageradaptor.h"
13 #include "konqviewmanager.h"
14 #include "konqsettingsxt.h"
15 
16 #include "konqdebug.h"
17 #include <kio/deletejob.h>
18 #include <KLocalizedString>
19 #include <QUrl>
20 #include <QIcon>
21 #include <ksqueezedtextlabel.h>
22 
23 #include <QPushButton>
24 #include <QCheckBox>
25 #include <QFileInfo>
26 #include <QDBusConnection>
27 #include <QDBusConnectionInterface>
28 #include <QtAlgorithms>
29 #include <QDirIterator>
30 #include <QDir>
31 #include <QFile>
32 #include <QSize>
33 #include <QVBoxLayout>
34 #include <QHBoxLayout>
35 #include <QTreeWidget>
36 #include <QScrollBar>
37 #include <QApplication>
38 #include <QDesktopWidget>
39 #include <QStandardPaths>
40 #include <QSessionManager>
41 #include <KSharedConfig>
42 #include <KConfigGroup>
43 #include <QDialogButtonBox>
44 #include <KGuiItem>
45 
46 class KonqSessionManagerPrivate
47 {
48 public:
KonqSessionManagerPrivate()49     KonqSessionManagerPrivate()
50         : instance(nullptr)
51     {
52     }
53 
~KonqSessionManagerPrivate()54     ~KonqSessionManagerPrivate()
55     {
56         delete instance;
57     }
58 
59     KonqSessionManager *instance;
60 };
61 
Q_GLOBAL_STATIC(KonqSessionManagerPrivate,myKonqSessionManagerPrivate)62 Q_GLOBAL_STATIC(KonqSessionManagerPrivate, myKonqSessionManagerPrivate)
63 
64 static QString viewIdFor(const QString &sessionFile, const QString &viewId)
65 {
66     return (sessionFile + viewId);
67 }
68 
windowConfigGroups(KConfig & config)69 static const QList<KConfigGroup> windowConfigGroups(/*NOT const, we'll use writeEntry*/ KConfig &config)
70 {
71     QList<KConfigGroup> groups;
72     KConfigGroup generalGroup(&config, "General");
73     const int size = generalGroup.readEntry("Number of Windows", 0);
74     for (int i = 0; i < size; i++) {
75         groups << KConfigGroup(&config, "Window" + QString::number(i));
76     }
77     return groups;
78 }
79 
SessionRestoreDialog(const QStringList & sessionFilePaths,QWidget * parent)80 SessionRestoreDialog::SessionRestoreDialog(const QStringList &sessionFilePaths, QWidget *parent)
81     : QDialog(parent)
82     , m_sessionItemsCount(0)
83     , m_dontShowChecked(false)
84 {
85     setObjectName(QStringLiteral("restoresession"));
86     setWindowTitle(i18nc("@title:window", "Restore Session?"));
87     setModal(true);
88 
89     QVBoxLayout *mainLayout = new QVBoxLayout(this);
90 
91     QHBoxLayout *hLayout = new QHBoxLayout();
92     hLayout->setContentsMargins(0, 0, 0, 0);
93     mainLayout->addLayout(hLayout, 5);
94 
95     QIcon icon = QIcon::fromTheme(QLatin1String("dialog-warning"));
96     if (!icon.isNull()) {
97         QLabel *iconLabel = new QLabel(this);
98         iconLabel->setPixmap(icon.pixmap(style()->pixelMetric(QStyle::PM_MessageBoxIconSize)));
99         QVBoxLayout *iconLayout = new QVBoxLayout();
100         iconLayout->addStretch(1);
101         iconLayout->addWidget(iconLabel);
102         iconLayout->addStretch(5);
103         hLayout->addLayout(iconLayout, 0);
104         hLayout->addSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
105     }
106 
107     const QString text(i18n("Konqueror did not close correctly. Would you like to restore these previous sessions?"));
108     QLabel *messageLabel = new QLabel(text, this);
109     Qt::TextInteractionFlags flags = (Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
110     messageLabel->setTextInteractionFlags(flags);
111     messageLabel->setWordWrap(true);
112 
113     hLayout->addWidget(messageLabel, 5);
114 
115     Q_ASSERT(!sessionFilePaths.isEmpty());
116     m_treeWidget = new QTreeWidget(this);
117     m_treeWidget->setHeader(nullptr);
118     m_treeWidget->setHeaderHidden(true);
119     m_treeWidget->setToolTip(i18nc("@tooltip:session list", "Uncheck the sessions you do not want to be restored"));
120 
121     QStyleOptionViewItem styleOption;
122     styleOption.initFrom(m_treeWidget);
123     QFontMetrics fm(styleOption.font);
124     int w = m_treeWidget->width();
125     const QRect desktop = QApplication::desktop()->screenGeometry(this);
126 
127     // Collect info from the sessions to restore
128     Q_FOREACH (const QString &sessionFile, sessionFilePaths) {
129         qCDebug(KONQUEROR_LOG) << sessionFile;
130         QTreeWidgetItem *windowItem = nullptr;
131         KConfig config(sessionFile, KConfig::SimpleConfig);
132         const QList<KConfigGroup> groups = windowConfigGroups(config);
133         Q_FOREACH (const KConfigGroup &group, groups) {
134             // To avoid a recursive search, let's do linear search on Foo_CurrentHistoryItem=1
135             Q_FOREACH (const QString &key, group.keyList()) {
136                 if (key.endsWith(QLatin1String("_CurrentHistoryItem"))) {
137                     const QString viewId = key.left(key.length() - qstrlen("_CurrentHistoryItem"));
138                     const QString historyIndex = group.readEntry(key, QString());
139                     const QString prefix = "HistoryItem" + viewId + '_' + historyIndex;
140                     // Ignore the sidebar views
141                     if (group.readEntry(prefix + "StrServiceName", QString()).startsWith(QLatin1String("konq_sidebar"))) {
142                         continue;
143                     }
144                     const QString url = group.readEntry(prefix + "Url", QString());
145                     const QString title = group.readEntry(prefix + "Title", QString());
146                     qCDebug(KONQUEROR_LOG) << viewId << url << title;
147                     const QString displayText = (title.trimmed().isEmpty() ? url : title);
148                     if (!displayText.isEmpty()) {
149                         if (!windowItem) {
150                             windowItem = new QTreeWidgetItem(m_treeWidget);
151                             const int index = sessionFilePaths.indexOf(sessionFile) + 1;
152                             windowItem->setText(0, i18nc("@item:treewidget", "Window %1", index));
153                             windowItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
154                             windowItem->setCheckState(0, Qt::Checked);
155                             windowItem->setExpanded(true);
156                         }
157                         QTreeWidgetItem *item = new QTreeWidgetItem(windowItem);
158                         item->setText(0, displayText);
159                         item->setData(0, Qt::UserRole, viewIdFor(sessionFile, viewId));
160                         item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
161                         item->setCheckState(0, Qt::Checked);
162                         w = qMax(w, fm.horizontalAdvance(displayText));
163                         m_sessionItemsCount++;
164                     }
165                 }
166             }
167         }
168 
169         if (windowItem) {
170             m_checkedSessionItems.insert(windowItem, windowItem->childCount());
171         }
172     }
173 
174     const int borderWidth = m_treeWidget->width() - m_treeWidget->viewport()->width() + m_treeWidget->verticalScrollBar()->height();
175     w += borderWidth;
176     if (w > desktop.width() * 0.85) { // limit treeWidget size to 85% of screen width
177         w = qRound(desktop.width() * 0.85);
178     }
179     m_treeWidget->setMinimumWidth(w);
180     mainLayout->addWidget(m_treeWidget, 50);
181     m_treeWidget->setSelectionMode(QTreeWidget::NoSelection);
182     messageLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
183 
184     // Do not connect the itemChanged signal until after the treewidget
185     // is completely populated to prevent the firing of the itemChanged
186     // signal while in the process of adding the original session items.
187     connect(m_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
188             this, SLOT(slotItemChanged(QTreeWidgetItem*,int)));
189 
190     QCheckBox *checkbox = new QCheckBox(i18n("Do not ask again"), this);
191     connect(checkbox, &QCheckBox::clicked, this, &SessionRestoreDialog::slotClicked);
192     mainLayout->addWidget(checkbox);
193 
194     m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::No|QDialogButtonBox::Yes);
195     mainLayout->addWidget(m_buttonBox);
196     QPushButton *yesButton = m_buttonBox->button(QDialogButtonBox::Yes);
197     QPushButton *noButton = m_buttonBox->button(QDialogButtonBox::No);
198     QPushButton *cancelButton = m_buttonBox->button(QDialogButtonBox::Cancel);
199 
200     connect(yesButton, &QPushButton::clicked, this, [this]() { done(QDialogButtonBox::Yes); });
201     connect(noButton, &QPushButton::clicked, this, [this]() { done(QDialogButtonBox::No); });
202     connect(cancelButton, &QPushButton::clicked, this, [this]() { reject(); });
203 
204     KGuiItem::assign(yesButton, KGuiItem(i18nc("@action:button yes", "Restore Session"), QStringLiteral("window-new")));
205     KGuiItem::assign(noButton, KGuiItem(i18nc("@action:button no", "Do Not Restore"), QStringLiteral("dialog-close")));
206     KGuiItem::assign(cancelButton, KGuiItem(i18nc("@action:button ask later", "Ask Me Later"), QStringLiteral("chronometer")));
207 
208     yesButton->setDefault(true);
209     yesButton->setFocus();
210 }
211 
~SessionRestoreDialog()212 SessionRestoreDialog::~SessionRestoreDialog()
213 {
214 }
215 
isEmpty() const216 bool SessionRestoreDialog::isEmpty() const
217 {
218     return m_treeWidget->topLevelItemCount() == 0;
219 }
220 
discardedSessionList() const221 QStringList SessionRestoreDialog::discardedSessionList() const
222 {
223     return m_discardedSessionList;
224 }
225 
isDontShowChecked() const226 bool SessionRestoreDialog::isDontShowChecked() const
227 {
228     return m_dontShowChecked;
229 }
230 
slotClicked(bool checked)231 void SessionRestoreDialog::slotClicked(bool checked)
232 {
233     m_dontShowChecked = checked;
234 }
235 
slotItemChanged(QTreeWidgetItem * item,int column)236 void SessionRestoreDialog::slotItemChanged(QTreeWidgetItem *item, int column)
237 {
238     Q_ASSERT(item);
239 
240     const int itemChildCount = item->childCount();
241     QTreeWidgetItem *parentItem = nullptr;
242 
243     const bool blocked = item->treeWidget()->blockSignals(true);
244     if (itemChildCount > 0) {
245         parentItem = item;
246         for (int i = 0; i < itemChildCount; ++i) {
247             QTreeWidgetItem *childItem = item->child(i);
248             if (childItem) {
249                 childItem->setCheckState(column, item->checkState(column));
250                 switch (childItem->checkState(column)) {
251                 case Qt::Checked:
252                     m_sessionItemsCount++;
253                     m_discardedSessionList.removeAll(childItem->data(column, Qt::UserRole).toString());
254                     m_checkedSessionItems[item]++;
255                     break;
256                 case Qt::Unchecked:
257                     m_sessionItemsCount--;
258                     m_discardedSessionList.append(childItem->data(column, Qt::UserRole).toString());
259                     m_checkedSessionItems[item]--;
260                     break;
261                 default:
262                     break;
263                 }
264             }
265         }
266     } else {
267         parentItem = item->parent();
268         switch (item->checkState(column)) {
269         case Qt::Checked:
270             m_sessionItemsCount++;
271             m_discardedSessionList.removeAll(item->data(column, Qt::UserRole).toString());
272             m_checkedSessionItems[parentItem]++;
273             break;
274         case Qt::Unchecked:
275             m_sessionItemsCount--;
276             m_discardedSessionList.append(item->data(column, Qt::UserRole).toString());
277             m_checkedSessionItems[parentItem]--;
278             break;
279         default:
280             break;
281         }
282     }
283 
284     const int numCheckSessions = m_checkedSessionItems.value(parentItem);
285     switch (parentItem->checkState(column)) {
286     case Qt::Checked:
287         if (numCheckSessions == 0) {
288             parentItem->setCheckState(column, Qt::Unchecked);
289         }
290         break;
291     case Qt::Unchecked:
292         if (numCheckSessions > 0) {
293             parentItem->setCheckState(column, Qt::Checked);
294         }
295     default:
296         break;
297     }
298 
299     m_buttonBox->button(QDialogButtonBox::Yes)->setEnabled(m_sessionItemsCount>0);
300     item->treeWidget()->blockSignals(blocked);
301 }
302 
saveDontShow(const QString & dontShowAgainName,int result)303 void SessionRestoreDialog::saveDontShow(const QString &dontShowAgainName, int result)
304 {
305     if (dontShowAgainName.isEmpty()) {
306         return;
307     }
308 
309     KConfigGroup::WriteConfigFlags flags = KConfig::Persistent;
310     if (dontShowAgainName[0] == ':') {
311         flags |= KConfigGroup::Global;
312     }
313 
314     KConfigGroup cg(KSharedConfig::openConfig().data(), "Notification Messages");
315     cg.writeEntry(dontShowAgainName, result == QDialogButtonBox::Yes, flags);
316     cg.sync();
317 }
318 
shouldBeShown(const QString & dontShowAgainName,int * result)319 bool SessionRestoreDialog::shouldBeShown(const QString &dontShowAgainName, int *result)
320 {
321     if (dontShowAgainName.isEmpty()) {
322         return true;
323     }
324 
325     KConfigGroup cg(KSharedConfig::openConfig().data(), "Notification Messages");
326     const QString dontAsk = cg.readEntry(dontShowAgainName, QString()).toLower();
327 
328     if (dontAsk == QLatin1String("yes") || dontAsk == QLatin1String("true")) {
329         if (result) {
330             *result = QDialogButtonBox::Yes;
331         }
332         return false;
333     }
334 
335     if (dontAsk == QLatin1String("no") || dontAsk == QLatin1String("false")) {
336         if (result) {
337             *result = QDialogButtonBox::No;
338         }
339         return false;
340     }
341 
342     return true;
343 }
344 
KonqSessionManager()345 KonqSessionManager::KonqSessionManager()
346     : m_autosaveDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QLatin1Char('/') + "autosave")
347     , m_autosaveEnabled(false) // so that enableAutosave works
348     , m_createdOwnedByDir(false)
349     , m_sessionConfig(nullptr)
350 {
351     // Initialize dbus interfaces
352     new KonqSessionManagerAdaptor(this);
353 
354     const QString dbusPath = QStringLiteral("/KonqSessionManager");
355     const QString dbusInterface = QStringLiteral("org.kde.Konqueror.SessionManager");
356 
357     QDBusConnection dbus = QDBusConnection::sessionBus();
358     dbus.registerObject(dbusPath, this);
359     m_baseService = KonqMisc::encodeFilename(dbus.baseService());
360     dbus.connect(QString(), dbusPath, dbusInterface, QStringLiteral("saveCurrentSession"), this, SLOT(slotSaveCurrentSession(QString)));
361 
362     // Initialize the timer
363     const int interval = KonqSettings::autoSaveInterval();
364     if (interval > 0) {
365         m_autoSaveTimer.setInterval(interval * 1000);
366         connect(&m_autoSaveTimer, SIGNAL(timeout()), this,
367                 SLOT(autoSaveSession()));
368     }
369     enableAutosave();
370 
371     connect(qApp, &QGuiApplication::commitDataRequest, this, &KonqSessionManager::slotCommitData);
372 }
373 
~KonqSessionManager()374 KonqSessionManager::~KonqSessionManager()
375 {
376     if (m_sessionConfig) {
377         QFile::remove(m_sessionConfig->name());
378     }
379     delete m_sessionConfig;
380 }
381 
382 // Don't restore preloaded konquerors
slotCommitData(QSessionManager & sm)383 void KonqSessionManager::slotCommitData(QSessionManager &sm)
384 {
385     if (!m_autosaveEnabled) {
386         sm.setRestartHint(QSessionManager::RestartNever);
387     }
388 }
389 
disableAutosave()390 void KonqSessionManager::disableAutosave()
391 {
392     if (!m_autosaveEnabled) {
393         return;
394     }
395 
396     m_autosaveEnabled = false;
397     m_autoSaveTimer.stop();
398     if (m_sessionConfig) {
399         QFile::remove(m_sessionConfig->name());
400         delete m_sessionConfig;
401         m_sessionConfig = nullptr;
402     }
403 }
404 
enableAutosave()405 void KonqSessionManager::enableAutosave()
406 {
407     if (m_autosaveEnabled) {
408         return;
409     }
410 
411     // Create the config file for autosaving current session
412     QString filename = QLatin1String("autosave/") + m_baseService;
413     const QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QLatin1Char('/') + filename;
414 
415     delete m_sessionConfig;
416     m_sessionConfig = new KConfig(filePath, KConfig::SimpleConfig);
417     //qCDebug(KONQUEROR_LOG) << "config filename:" << m_sessionConfig->name();
418 
419     m_autosaveEnabled = true;
420     m_autoSaveTimer.start();
421 }
422 
deleteOwnedSessions()423 void KonqSessionManager::deleteOwnedSessions()
424 {
425     // Not dealing with the sessions about to remove anymore
426     if (m_createdOwnedByDir && QDir(dirForMyOwnedSessionFiles()).removeRecursively()) {
427         m_createdOwnedByDir = false;
428     }
429 }
430 
self()431 KonqSessionManager *KonqSessionManager::self()
432 {
433     if (!myKonqSessionManagerPrivate->instance) {
434         myKonqSessionManagerPrivate->instance = new KonqSessionManager();
435     }
436 
437     return myKonqSessionManagerPrivate->instance;
438 }
439 
autoSaveSession()440 void KonqSessionManager::autoSaveSession()
441 {
442     if (!m_autosaveEnabled) {
443         return;
444     }
445 
446     const bool isActive = m_autoSaveTimer.isActive();
447     if (isActive) {
448         m_autoSaveTimer.stop();
449     }
450 
451     saveCurrentSessionToFile(m_sessionConfig);
452     m_sessionConfig->sync();
453     m_sessionConfig->markAsClean();
454 
455     // Now that we have saved current session it's safe to remove our owned_by
456     // directory
457     deleteOwnedSessions();
458 
459     if (isActive) {
460         m_autoSaveTimer.start();
461     }
462 }
463 
saveCurrentSessions(const QString & path)464 void KonqSessionManager::saveCurrentSessions(const QString &path)
465 {
466     emit saveCurrentSession(path);
467 }
468 
slotSaveCurrentSession(const QString & path)469 void KonqSessionManager::slotSaveCurrentSession(const QString &path)
470 {
471     const QString filename = path + '/' + m_baseService;
472     saveCurrentSessionToFile(filename);
473 }
474 
saveCurrentSessionToFile(const QString & sessionConfigPath,KonqMainWindow * mainWindow)475 void KonqSessionManager::saveCurrentSessionToFile(const QString &sessionConfigPath, KonqMainWindow *mainWindow)
476 {
477     QFile::remove(sessionConfigPath);
478     KConfig config(sessionConfigPath, KConfig::SimpleConfig);
479 
480     QList<KonqMainWindow *> mainWindows;
481     if (mainWindow) {
482         mainWindows << mainWindow;
483     }
484     saveCurrentSessionToFile(&config, mainWindows);
485 }
486 
saveCurrentSessionToFile(KConfig * config,const QList<KonqMainWindow * > & theMainWindows)487 void KonqSessionManager::saveCurrentSessionToFile(KConfig *config, const QList<KonqMainWindow *> &theMainWindows)
488 {
489     QList<KonqMainWindow *> mainWindows = theMainWindows;
490 
491     if (mainWindows.isEmpty() && KonqMainWindow::mainWindowList()) {
492         mainWindows = *KonqMainWindow::mainWindowList();
493     }
494 
495     unsigned int counter = 0;
496 
497     if (mainWindows.isEmpty()) {
498         return;
499     }
500 
501     foreach (KonqMainWindow *window, mainWindows) {
502         if (!window->isPreloaded()) {
503             KConfigGroup configGroup(config, "Window" + QString::number(counter));
504             window->saveProperties(configGroup);
505             counter++;
506         }
507     }
508 
509     KConfigGroup configGroup(config, "General");
510     configGroup.writeEntry("Number of Windows", counter);
511 }
512 
autosaveDirectory() const513 QString KonqSessionManager::autosaveDirectory() const
514 {
515     return m_autosaveDir;
516 }
517 
takeSessionsOwnership()518 QStringList KonqSessionManager::takeSessionsOwnership()
519 {
520     // Tell to other konqueror instances that we are the one dealing with
521     // these sessions
522     QDir dir(dirForMyOwnedSessionFiles());
523     QDir parentDir(m_autosaveDir);
524 
525     if (!dir.exists()) {
526         m_createdOwnedByDir = parentDir.mkdir("owned_by" + m_baseService);
527     }
528 
529     QDirIterator it(m_autosaveDir, QDir::Writable | QDir::Files | QDir::Dirs |
530                     QDir::NoDotAndDotDot);
531 
532     QStringList sessionFilePaths;
533     QDBusConnectionInterface *idbus = QDBusConnection::sessionBus().interface();
534 
535     while (it.hasNext()) {
536         it.next();
537         // this is the case where another konq started to restore that session,
538         // but crashed immediately. So we try to restore that session again
539         if (it.fileInfo().isDir()) {
540             // The remove() removes the "owned_by" part
541             if (!idbus->isServiceRegistered(
542                         KonqMisc::decodeFilename(it.fileName().remove(0, 8)))) {
543                 QDirIterator it2(it.filePath(), QDir::Writable | QDir::Files);
544                 while (it2.hasNext()) {
545                     it2.next();
546                     // take ownership of the abandoned file
547                     const QString newFileName = dirForMyOwnedSessionFiles() +
548                                                 '/' + it2.fileName();
549                     QFile::rename(it2.filePath(), newFileName);
550                     sessionFilePaths.append(newFileName);
551                 }
552                 // Remove the old directory
553                 QDir(it.filePath()).removeRecursively();
554             }
555         } else { // it's a file
556             if (!idbus->isServiceRegistered(KonqMisc::decodeFilename(it.fileName()))) {
557                 // and it's abandoned: take its ownership
558                 const QString newFileName = dirForMyOwnedSessionFiles() + '/' +
559                                             it.fileName();
560                 QFile::rename(it.filePath(), newFileName);
561                 sessionFilePaths.append(newFileName);
562             }
563         }
564     }
565 
566     return sessionFilePaths;
567 }
568 
restoreSessions(const QStringList & sessionFilePathsList,bool openTabsInsideCurrentWindow,KonqMainWindow * parent)569 void KonqSessionManager::restoreSessions(const QStringList &sessionFilePathsList,
570         bool openTabsInsideCurrentWindow, KonqMainWindow *parent)
571 {
572     foreach (const QString &sessionFilePath, sessionFilePathsList) {
573         restoreSession(sessionFilePath, openTabsInsideCurrentWindow, parent);
574     }
575 }
576 
restoreSessions(const QString & sessionsDir,bool openTabsInsideCurrentWindow,KonqMainWindow * parent)577 void KonqSessionManager::restoreSessions(const QString &sessionsDir, bool
578         openTabsInsideCurrentWindow, KonqMainWindow *parent)
579 {
580     QDirIterator it(sessionsDir, QDir::Readable | QDir::Files);
581 
582     while (it.hasNext()) {
583         QFileInfo fi(it.next());
584         restoreSession(fi.filePath(), openTabsInsideCurrentWindow, parent);
585     }
586 }
587 
restoreSession(const QString & sessionFilePath,bool openTabsInsideCurrentWindow,KonqMainWindow * parent)588 void KonqSessionManager::restoreSession(const QString &sessionFilePath, bool
589                                         openTabsInsideCurrentWindow, KonqMainWindow *parent)
590 {
591     if (!QFile::exists(sessionFilePath)) {
592         return;
593     }
594 
595     KConfig config(sessionFilePath, KConfig::SimpleConfig);
596     const QList<KConfigGroup> groups = windowConfigGroups(config);
597     Q_FOREACH (const KConfigGroup &configGroup, groups) {
598         if (!openTabsInsideCurrentWindow) {
599             KonqViewManager::openSavedWindow(configGroup)->show();
600         } else {
601             parent->viewManager()->openSavedWindow(configGroup, true);
602         }
603     }
604 }
605 
removeDiscardedSessions(const QStringList & sessionFiles,const QStringList & discardedSessions)606 static void removeDiscardedSessions(const QStringList &sessionFiles, const QStringList &discardedSessions)
607 {
608     if (discardedSessions.isEmpty()) {
609         return;
610     }
611 
612     Q_FOREACH (const QString &sessionFile, sessionFiles) {
613         KConfig config(sessionFile, KConfig::SimpleConfig);
614         QList<KConfigGroup> groups = windowConfigGroups(config);
615         for (int i = 0, count = groups.count(); i < count; ++i) {
616             KConfigGroup &group = groups[i];
617             const QString rootItem = group.readEntry("RootItem", "empty");
618             const QString viewsKey(rootItem + QLatin1String("_Children"));
619             QStringList views = group.readEntry(viewsKey, QStringList());
620             QMutableStringListIterator it(views);
621             while (it.hasNext()) {
622                 if (discardedSessions.contains(viewIdFor(sessionFile, it.next()))) {
623                     it.remove();
624                 }
625             }
626             group.writeEntry(viewsKey, views);
627         }
628     }
629 }
630 
askUserToRestoreAutosavedAbandonedSessions()631 bool KonqSessionManager::askUserToRestoreAutosavedAbandonedSessions()
632 {
633     const QStringList sessionFilePaths = takeSessionsOwnership();
634     if (sessionFilePaths.isEmpty()) {
635         return false;
636     }
637 
638     disableAutosave();
639 
640     int result;
641     QStringList discardedSessionList;
642     const QLatin1String dontAskAgainName("Restore session when konqueror didn't close correctly");
643 
644     if (SessionRestoreDialog::shouldBeShown(dontAskAgainName, &result)) {
645         SessionRestoreDialog *restoreDlg = new SessionRestoreDialog(sessionFilePaths);
646         if (restoreDlg->isEmpty()) {
647             result = QDialogButtonBox::No;
648         } else {
649             result = restoreDlg->exec();
650             discardedSessionList = restoreDlg->discardedSessionList();
651             if (restoreDlg->isDontShowChecked()) {
652                 SessionRestoreDialog::saveDontShow(dontAskAgainName, result);
653             }
654         }
655         delete restoreDlg;
656     }
657 
658     switch (result) {
659     case QDialogButtonBox::Yes:
660         // Remove the discarded session list files.
661         removeDiscardedSessions(sessionFilePaths, discardedSessionList);
662         restoreSessions(sessionFilePaths);
663         enableAutosave();
664         return true;
665     case QDialogButtonBox::No:
666         deleteOwnedSessions();
667         enableAutosave();
668         return false;
669     default:
670         // Remove the ownership of the currently owned files
671         QDirIterator it(dirForMyOwnedSessionFiles(),
672                         QDir::Writable | QDir::Files);
673 
674         while (it.hasNext()) {
675             it.next();
676             // remove ownership of the abandoned file
677             QFile::rename(it.filePath(), m_autosaveDir + '/' + it.fileName());
678         }
679         // Remove the owned_by directory
680         QDir(dirForMyOwnedSessionFiles()).removeRecursively();
681         enableAutosave();
682         return false;
683     }
684 }
685 
686