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