File indexing completed on 2024-04-21 04:58:20

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2008 Eduardo Robles Elvira <edulix@gmail.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "konqsessionmanager.h"
0009 #include "konqmisc.h"
0010 #include "konqmainwindow.h"
0011 #include "konqsessionmanager_interface.h"
0012 #include "konqsessionmanageradaptor.h"
0013 #include "konqviewmanager.h"
0014 #include "konqsettingsxt.h"
0015 
0016 #ifdef KActivities_FOUND
0017 #include "activitymanager.h"
0018 #if QT_VERSION_MAJOR < 6
0019 #include <KActivities/Consumer>
0020 #else //QT_VERSION_MAJOR
0021 #include <PlasmaActivities/Consumer>
0022 #endif //QT_VERSION_MAJOR
0023 #endif //KActivities_FOUND
0024 
0025 #include "konqdebug.h"
0026 #include <kio/deletejob.h>
0027 #include <KLocalizedString>
0028 #include <KWindowInfo>
0029 #include <KX11Extras>
0030 
0031 #include <QUrl>
0032 #include <QIcon>
0033 #include <ksqueezedtextlabel.h>
0034 
0035 #include <QPushButton>
0036 #include <QCheckBox>
0037 #include <QFileInfo>
0038 #include <QDBusConnection>
0039 #include <QDBusConnectionInterface>
0040 #include <QtAlgorithms>
0041 #include <QDirIterator>
0042 #include <QDir>
0043 #include <QFile>
0044 #include <QSize>
0045 #include <QVBoxLayout>
0046 #include <QHBoxLayout>
0047 #include <QTreeWidget>
0048 #include <QScrollBar>
0049 #include <QApplication>
0050 #include <QStandardPaths>
0051 #include <QSessionManager>
0052 #include <KConfigGroup>
0053 #include <QDialogButtonBox>
0054 #include <KGuiItem>
0055 #include <QScreen>
0056 #include <KSharedConfig>
0057 
0058 #include "konqapplication.h"
0059 #include <QMessageBox>
0060 
0061 class KonqSessionManagerPrivate
0062 {
0063 public:
0064     KonqSessionManagerPrivate()
0065         : instance(nullptr)
0066     {
0067     }
0068 
0069     ~KonqSessionManagerPrivate()
0070     {
0071         delete instance;
0072     }
0073 
0074     KonqSessionManager *instance;
0075 };
0076 
0077 Q_GLOBAL_STATIC(KonqSessionManagerPrivate, myKonqSessionManagerPrivate)
0078 
0079 static QString viewIdFor(const QString &sessionFile, const QString &viewId)
0080 {
0081     return (sessionFile + viewId);
0082 }
0083 
0084 static const QList<KConfigGroup> windowConfigGroups(/*NOT const, we'll use writeEntry*/ KConfig &config)
0085 {
0086     QList<KConfigGroup> groups;
0087     KConfigGroup generalGroup(&config, "General");
0088     const int size = generalGroup.readEntry("Number of Windows", 0);
0089     for (int i = 0; i < size; i++) {
0090         groups << KConfigGroup(&config, "Window" + QString::number(i));
0091     }
0092     return groups;
0093 }
0094 
0095 SessionRestoreDialog::SessionRestoreDialog(const QStringList &sessionFilePaths, QWidget *parent)
0096     : QDialog(parent)
0097     , m_sessionItemsCount(0)
0098     , m_dontShowChecked(false)
0099 {
0100     setObjectName(QStringLiteral("restoresession"));
0101     setWindowTitle(i18nc("@title:window", "Restore Session?"));
0102     setModal(true);
0103 
0104     QVBoxLayout *mainLayout = new QVBoxLayout(this);
0105 
0106     QHBoxLayout *hLayout = new QHBoxLayout();
0107     hLayout->setContentsMargins(0, 0, 0, 0);
0108     mainLayout->addLayout(hLayout, 5);
0109 
0110     QIcon icon = QIcon::fromTheme(QLatin1String("dialog-warning"));
0111     if (!icon.isNull()) {
0112         QLabel *iconLabel = new QLabel(this);
0113         iconLabel->setPixmap(icon.pixmap(style()->pixelMetric(QStyle::PM_MessageBoxIconSize)));
0114         QVBoxLayout *iconLayout = new QVBoxLayout();
0115         iconLayout->addStretch(1);
0116         iconLayout->addWidget(iconLabel);
0117         iconLayout->addStretch(5);
0118         hLayout->addLayout(iconLayout, 0);
0119         hLayout->addSpacing(style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing));
0120     }
0121 
0122     const QString text(i18n("Konqueror did not close correctly. Would you like to restore these previous sessions?"));
0123     QLabel *messageLabel = new QLabel(text, this);
0124     Qt::TextInteractionFlags flags = (Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
0125     messageLabel->setTextInteractionFlags(flags);
0126     messageLabel->setWordWrap(true);
0127 
0128     hLayout->addWidget(messageLabel, 5);
0129 
0130     Q_ASSERT(!sessionFilePaths.isEmpty());
0131     m_treeWidget = new QTreeWidget(this);
0132     m_treeWidget->setHeader(nullptr);
0133     m_treeWidget->setHeaderHidden(true);
0134     m_treeWidget->setToolTip(i18nc("@tooltip:session list", "Uncheck the sessions you do not want to be restored"));
0135 
0136     QStyleOptionViewItem styleOption;
0137     styleOption.initFrom(m_treeWidget);
0138     QFontMetrics fm(styleOption.font);
0139     int w = m_treeWidget->width();
0140     const QRect desktop = screen()->geometry();
0141 
0142     // Collect info from the sessions to restore
0143     for (const QString &sessionFile: sessionFilePaths) {
0144         qCDebug(KONQUEROR_LOG) << sessionFile;
0145         QTreeWidgetItem *windowItem = nullptr;
0146         KConfig config(sessionFile, KConfig::SimpleConfig);
0147         const QList<KConfigGroup> groups = windowConfigGroups(config);
0148         for (const KConfigGroup &group: groups) {
0149             // To avoid a recursive search, let's do linear search on Foo_CurrentHistoryItem=1
0150             for (const QString &key: group.keyList()) {
0151                 if (key.endsWith(QLatin1String("_CurrentHistoryItem"))) {
0152                     const QString viewId = key.left(key.length() - qstrlen("_CurrentHistoryItem"));
0153                     const QString historyIndex = group.readEntry(key, QString());
0154                     const QString prefix = "HistoryItem" + viewId + '_' + historyIndex;
0155                     // Ignore the sidebar views
0156                     if (group.readEntry(prefix + "StrServiceName", QString()).startsWith(QLatin1String("konq_sidebar"))) {
0157                         continue;
0158                     }
0159                     const QString url = group.readEntry(prefix + "Url", QString());
0160                     const QString title = group.readEntry(prefix + "Title", QString());
0161                     qCDebug(KONQUEROR_LOG) << viewId << url << title;
0162                     const QString displayText = (title.trimmed().isEmpty() ? url : title);
0163                     if (!displayText.isEmpty()) {
0164                         if (!windowItem) {
0165                             windowItem = new QTreeWidgetItem(m_treeWidget);
0166                             const int index = sessionFilePaths.indexOf(sessionFile) + 1;
0167                             windowItem->setText(0, i18nc("@item:treewidget", "Window %1", index));
0168                             windowItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
0169                             windowItem->setCheckState(0, Qt::Checked);
0170                             windowItem->setExpanded(true);
0171                         }
0172                         QTreeWidgetItem *item = new QTreeWidgetItem(windowItem);
0173                         item->setText(0, displayText);
0174                         item->setData(0, Qt::UserRole, viewIdFor(sessionFile, viewId));
0175                         item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
0176                         item->setCheckState(0, Qt::Checked);
0177                         w = qMax(w, fm.horizontalAdvance(displayText));
0178                         m_sessionItemsCount++;
0179                     }
0180                 }
0181             }
0182         }
0183 
0184         if (windowItem) {
0185             m_checkedSessionItems.insert(windowItem, windowItem->childCount());
0186         }
0187     }
0188 
0189     const int borderWidth = m_treeWidget->width() - m_treeWidget->viewport()->width() + m_treeWidget->verticalScrollBar()->height();
0190     w += borderWidth;
0191     if (w > desktop.width() * 0.85) { // limit treeWidget size to 85% of screen width
0192         w = qRound(desktop.width() * 0.85);
0193     }
0194     m_treeWidget->setMinimumWidth(w);
0195     mainLayout->addWidget(m_treeWidget, 50);
0196     m_treeWidget->setSelectionMode(QTreeWidget::NoSelection);
0197     messageLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
0198 
0199     // Do not connect the itemChanged signal until after the treewidget
0200     // is completely populated to prevent the firing of the itemChanged
0201     // signal while in the process of adding the original session items.
0202     connect(m_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
0203             this, SLOT(slotItemChanged(QTreeWidgetItem*,int)));
0204 
0205     QCheckBox *checkbox = new QCheckBox(i18n("Do not ask again"), this);
0206     connect(checkbox, &QCheckBox::clicked, this, &SessionRestoreDialog::slotClicked);
0207     mainLayout->addWidget(checkbox);
0208 
0209     m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::No|QDialogButtonBox::Yes);
0210     mainLayout->addWidget(m_buttonBox);
0211     QPushButton *yesButton = m_buttonBox->button(QDialogButtonBox::Yes);
0212     QPushButton *noButton = m_buttonBox->button(QDialogButtonBox::No);
0213     QPushButton *cancelButton = m_buttonBox->button(QDialogButtonBox::Cancel);
0214 
0215     connect(yesButton, &QPushButton::clicked, this, [this]() { done(QDialogButtonBox::Yes); });
0216     connect(noButton, &QPushButton::clicked, this, [this]() { done(QDialogButtonBox::No); });
0217     connect(cancelButton, &QPushButton::clicked, this, [this]() { reject(); });
0218 
0219     KGuiItem::assign(yesButton, KGuiItem(i18nc("@action:button yes", "Restore Session"), QStringLiteral("window-new")));
0220     KGuiItem::assign(noButton, KGuiItem(i18nc("@action:button no", "Do Not Restore"), QStringLiteral("dialog-close")));
0221     KGuiItem::assign(cancelButton, KGuiItem(i18nc("@action:button ask later", "Ask Me Later"), QStringLiteral("chronometer")));
0222 
0223     yesButton->setDefault(true);
0224     yesButton->setFocus();
0225 }
0226 
0227 SessionRestoreDialog::~SessionRestoreDialog()
0228 {
0229 }
0230 
0231 bool SessionRestoreDialog::isEmpty() const
0232 {
0233     return m_treeWidget->topLevelItemCount() == 0;
0234 }
0235 
0236 QStringList SessionRestoreDialog::discardedSessionList() const
0237 {
0238     return m_discardedSessionList;
0239 }
0240 
0241 bool SessionRestoreDialog::isDontShowChecked() const
0242 {
0243     return m_dontShowChecked;
0244 }
0245 
0246 void SessionRestoreDialog::slotClicked(bool checked)
0247 {
0248     m_dontShowChecked = checked;
0249 }
0250 
0251 void SessionRestoreDialog::slotItemChanged(QTreeWidgetItem *item, int column)
0252 {
0253     Q_ASSERT(item);
0254 
0255     const int itemChildCount = item->childCount();
0256     QTreeWidgetItem *parentItem = nullptr;
0257 
0258     const bool blocked = item->treeWidget()->blockSignals(true);
0259     if (itemChildCount > 0) {
0260         parentItem = item;
0261         for (int i = 0; i < itemChildCount; ++i) {
0262             QTreeWidgetItem *childItem = item->child(i);
0263             if (childItem) {
0264                 childItem->setCheckState(column, item->checkState(column));
0265                 switch (childItem->checkState(column)) {
0266                 case Qt::Checked:
0267                     m_sessionItemsCount++;
0268                     m_discardedSessionList.removeAll(childItem->data(column, Qt::UserRole).toString());
0269                     m_checkedSessionItems[item]++;
0270                     break;
0271                 case Qt::Unchecked:
0272                     m_sessionItemsCount--;
0273                     m_discardedSessionList.append(childItem->data(column, Qt::UserRole).toString());
0274                     m_checkedSessionItems[item]--;
0275                     break;
0276                 default:
0277                     break;
0278                 }
0279             }
0280         }
0281     } else {
0282         parentItem = item->parent();
0283         switch (item->checkState(column)) {
0284         case Qt::Checked:
0285             m_sessionItemsCount++;
0286             m_discardedSessionList.removeAll(item->data(column, Qt::UserRole).toString());
0287             m_checkedSessionItems[parentItem]++;
0288             break;
0289         case Qt::Unchecked:
0290             m_sessionItemsCount--;
0291             m_discardedSessionList.append(item->data(column, Qt::UserRole).toString());
0292             m_checkedSessionItems[parentItem]--;
0293             break;
0294         default:
0295             break;
0296         }
0297     }
0298 
0299     const int numCheckSessions = m_checkedSessionItems.value(parentItem);
0300     switch (parentItem->checkState(column)) {
0301     case Qt::Checked:
0302         if (numCheckSessions == 0) {
0303             parentItem->setCheckState(column, Qt::Unchecked);
0304         }
0305         break;
0306     case Qt::Unchecked:
0307         if (numCheckSessions > 0) {
0308             parentItem->setCheckState(column, Qt::Checked);
0309         }
0310     default:
0311         break;
0312     }
0313 
0314     m_buttonBox->button(QDialogButtonBox::Yes)->setEnabled(m_sessionItemsCount>0);
0315     item->treeWidget()->blockSignals(blocked);
0316 }
0317 
0318 void SessionRestoreDialog::saveDontShow(const QString &dontShowAgainName, int result)
0319 {
0320     if (dontShowAgainName.isEmpty()) {
0321         return;
0322     }
0323 
0324     KConfigGroup::WriteConfigFlags flags = KConfig::Persistent;
0325     if (dontShowAgainName[0] == ':') {
0326         flags |= KConfigGroup::Global;
0327     }
0328 
0329     KConfigGroup cg(KSharedConfig::openConfig().data(), "Notification Messages");
0330     cg.writeEntry(dontShowAgainName, result == QDialogButtonBox::Yes, flags);
0331     cg.sync();
0332 }
0333 
0334 bool SessionRestoreDialog::shouldBeShown(const QString &dontShowAgainName, int *result)
0335 {
0336     if (dontShowAgainName.isEmpty()) {
0337         return true;
0338     }
0339 
0340     KConfigGroup cg(KSharedConfig::openConfig().data(), "Notification Messages");
0341     const QString dontAsk = cg.readEntry(dontShowAgainName, QString()).toLower();
0342 
0343     if (dontAsk == QLatin1String("yes") || dontAsk == QLatin1String("true")) {
0344         if (result) {
0345             *result = QDialogButtonBox::Yes;
0346         }
0347         return false;
0348     }
0349 
0350     if (dontAsk == QLatin1String("no") || dontAsk == QLatin1String("false")) {
0351         if (result) {
0352             *result = QDialogButtonBox::No;
0353         }
0354         return false;
0355     }
0356 
0357     return true;
0358 }
0359 
0360 KonqSessionManager::KonqSessionManager()
0361     : m_autosaveDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QLatin1Char('/') + "autosave")
0362     , m_autosaveEnabled(false) // so that enableAutosave works
0363     , m_createdOwnedByDir(false)
0364     , m_sessionConfig(nullptr)
0365 #ifdef KActivities_FOUND
0366     , m_activityManager(new ActivityManager(this))
0367 #endif
0368 {
0369     // Initialize dbus interfaces
0370     new KonqSessionManagerAdaptor(this);
0371 
0372     const QString dbusPath = QStringLiteral("/KonqSessionManager");
0373     const QString dbusInterface = QStringLiteral("org.kde.Konqueror.SessionManager");
0374 
0375     QDBusConnection dbus = QDBusConnection::sessionBus();
0376     dbus.registerObject(dbusPath, this);
0377     m_baseService = KonqMisc::encodeFilename(dbus.baseService());
0378     dbus.connect(QString(), dbusPath, dbusInterface, QStringLiteral("saveCurrentSession"), this, SLOT(slotSaveCurrentSession(QString)));
0379 
0380     // Initialize the timer
0381     const int interval = KonqSettings::autoSaveInterval();
0382     if (interval > 0) {
0383         m_autoSaveTimer.setInterval(interval * 1000);
0384         connect(&m_autoSaveTimer, &QTimer::timeout, this, &KonqSessionManager::autoSaveSession);
0385     }
0386     enableAutosave();
0387 
0388     connect(qApp, &QGuiApplication::commitDataRequest, this, &KonqSessionManager::slotCommitData);
0389     connect(qApp, &QGuiApplication::lastWindowClosed, this, &KonqSessionManager::saveSessionAtExit);
0390 }
0391 
0392 KonqSessionManager::~KonqSessionManager()
0393 {
0394     if (m_sessionConfig) {
0395         QFile::remove(m_sessionConfig->name());
0396     }
0397     delete m_sessionConfig;
0398 }
0399 
0400 void KonqSessionManager::restoreSessionSavedAtLogout()
0401 {
0402     askUserToRestoreAutosavedAbandonedSessions();
0403 
0404     m_preloadedWindowsNumber.clear();
0405     int n = 1;
0406     while (KonqMainWindow::canBeRestored(n)) {
0407         const QString className = KXmlGuiWindow::classNameOfToplevel(n);
0408 
0409         //The !m_preloadedWindowsNumber.contains(n) check avoid restoring preloaded windows
0410         if (className == QLatin1String("KonqMainWindow") && !m_preloadedWindowsNumber.contains(n)) {
0411             KonqMainWindow * mw = new KonqMainWindow();
0412             mw->restore(n);
0413 
0414             //m_preloadedWindowsNumber is set from the readGlobalProperties of the first (n==1) window.
0415             //This means that the first window is always restored, even if it was preloaded (because readGlobalProperties
0416             //is called from restore). For the first window, we need to check whether it was preloaded, and in that case
0417             //delete it afterwards
0418             if (n == 1 && m_preloadedWindowsNumber.contains(1)) {
0419                 mw->deleteLater();
0420             }
0421         } else  {
0422             qCWarning(KONQUEROR_LOG) << "Unknown class" << className << "in session saved data!";
0423         }
0424         ++n;
0425     }
0426     m_preloadedWindowsNumber.clear();
0427 }
0428 
0429 
0430 // Don't restore preloaded konquerors
0431 void KonqSessionManager::slotCommitData(QSessionManager &sm)
0432 {
0433     QList<KonqMainWindow*> const *windows = KonqMainWindow::mainWindowList();
0434     if (std::all_of(windows->constBegin(), windows->constEnd(), [](KonqMainWindow *w){return w->isPreloaded();})) {
0435         sm.setRestartHint(QSessionManager::RestartNever);
0436     }
0437 }
0438 
0439 void KonqSessionManager::disableAutosave()
0440 {
0441     if (!m_autosaveEnabled) {
0442         return;
0443     }
0444 
0445     m_autosaveEnabled = false;
0446     m_autoSaveTimer.stop();
0447     if (m_sessionConfig) {
0448         QFile::remove(m_sessionConfig->name());
0449         delete m_sessionConfig;
0450         m_sessionConfig = nullptr;
0451     }
0452 }
0453 
0454 void KonqSessionManager::enableAutosave()
0455 {
0456     if (m_autosaveEnabled) {
0457         return;
0458     }
0459 
0460     // Create the config file for autosaving current session
0461     QString filename = QLatin1String("autosave/") + m_baseService;
0462     const QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QLatin1Char('/') + filename;
0463 
0464     delete m_sessionConfig;
0465     m_sessionConfig = new KConfig(filePath, KConfig::SimpleConfig);
0466     //qCDebug(KONQUEROR_LOG) << "config filename:" << m_sessionConfig->name();
0467 
0468     m_autosaveEnabled = true;
0469     m_autoSaveTimer.start();
0470 }
0471 
0472 void KonqSessionManager::deleteOwnedSessions()
0473 {
0474     // Not dealing with the sessions about to remove anymore
0475     if (m_createdOwnedByDir && QDir(dirForMyOwnedSessionFiles()).removeRecursively()) {
0476         m_createdOwnedByDir = false;
0477     }
0478 }
0479 
0480 KonqSessionManager *KonqSessionManager::self()
0481 {
0482     if (!myKonqSessionManagerPrivate->instance) {
0483         myKonqSessionManagerPrivate->instance = new KonqSessionManager();
0484     }
0485 
0486     return myKonqSessionManagerPrivate->instance;
0487 }
0488 
0489 void KonqSessionManager::autoSaveSession()
0490 {
0491     if (!m_autosaveEnabled) {
0492         return;
0493     }
0494 
0495     const bool isActive = m_autoSaveTimer.isActive();
0496     if (isActive) {
0497         m_autoSaveTimer.stop();
0498     }
0499 
0500     saveCurrentSessionToFile(m_sessionConfig);
0501     m_sessionConfig->sync();
0502     m_sessionConfig->markAsClean();
0503 
0504     // Now that we have saved current session it's safe to remove our owned_by
0505     // directory
0506     deleteOwnedSessions();
0507 
0508     if (isActive) {
0509         m_autoSaveTimer.start();
0510     }
0511 }
0512 
0513 void KonqSessionManager::saveCurrentSessions(const QString &path)
0514 {
0515     emit saveCurrentSession(path);
0516 }
0517 
0518 void KonqSessionManager::slotSaveCurrentSession(const QString &path)
0519 {
0520     const QString filename = path + '/' + m_baseService;
0521     saveCurrentSessionToFile(filename);
0522 }
0523 
0524 void KonqSessionManager::saveCurrentSessionToFile(const QString &sessionConfigPath, KonqMainWindow *mainWindow)
0525 {
0526     QFile::remove(sessionConfigPath);
0527     KConfig config(sessionConfigPath, KConfig::SimpleConfig);
0528 
0529     QList<KonqMainWindow *> mainWindows;
0530     if (mainWindow) {
0531         mainWindows << mainWindow;
0532     }
0533     saveCurrentSessionToFile(&config, mainWindows);
0534 }
0535 
0536 void KonqSessionManager::saveCurrentSessionToFile(KConfig *config, const QList<KonqMainWindow *> &theMainWindows)
0537 {
0538     QList<KonqMainWindow *> mainWindows = theMainWindows;
0539 
0540     if (mainWindows.isEmpty() && KonqMainWindow::mainWindowList()) {
0541         mainWindows = *KonqMainWindow::mainWindowList();
0542     }
0543 
0544     unsigned int counter = 0;
0545 
0546     if (mainWindows.isEmpty()) {
0547         return;
0548     }
0549 
0550     for (KonqMainWindow *window: mainWindows) {
0551         if (!window->isPreloaded()) {
0552             KConfigGroup configGroup(config, "Window" + QString::number(counter));
0553             window->saveProperties(configGroup);
0554             KWindowInfo info(window->winId(), NET::Properties(), NET::WM2Activities);
0555             configGroup.writeEntry("Activities", info.activities());
0556             counter++;
0557         }
0558     }
0559 
0560     KConfigGroup configGroup(config, "General");
0561     configGroup.writeEntry("Number of Windows", counter);
0562 }
0563 
0564 void KonqSessionManager::saveSessionAtExit()
0565 {
0566     if (qApp->isSavingSession()) {
0567         return;
0568     }
0569     bool saveSessions = KSharedConfig::openConfig()->group(QStringLiteral("UserSettings")).readEntry(QStringLiteral("RestoreLastState"), false);
0570     if (!saveSessions) {
0571         return;
0572     }
0573     QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
0574     if (!path.isEmpty()) {
0575         const QList<KonqMainWindow*> windows = KonqMainWindow::mainWindows();
0576         if (windows.count() == 1 && windows.at(0)->isPreloaded())  {
0577             return;
0578         }
0579         saveCurrentSessionToFile(QDir(path).absoluteFilePath("last_session"));
0580     }
0581 }
0582 
0583 QString KonqSessionManager::autosaveDirectory() const
0584 {
0585     return m_autosaveDir;
0586 }
0587 
0588 QStringList KonqSessionManager::takeSessionsOwnership()
0589 {
0590     // Tell to other konqueror instances that we are the one dealing with
0591     // these sessions
0592     QDir dir(dirForMyOwnedSessionFiles());
0593     QDir parentDir(m_autosaveDir);
0594 
0595     if (!dir.exists()) {
0596         m_createdOwnedByDir = parentDir.mkdir("owned_by" + m_baseService);
0597     }
0598 
0599     QDirIterator it(m_autosaveDir, QDir::Writable | QDir::Files | QDir::Dirs |
0600                     QDir::NoDotAndDotDot);
0601 
0602     QStringList sessionFilePaths;
0603     QDBusConnectionInterface *idbus = QDBusConnection::sessionBus().interface();
0604 
0605     while (it.hasNext()) {
0606         it.next();
0607         // this is the case where another konq started to restore that session,
0608         // but crashed immediately. So we try to restore that session again
0609         if (it.fileInfo().isDir()) {
0610             // The remove() removes the "owned_by" part
0611             if (!idbus->isServiceRegistered(
0612                         KonqMisc::decodeFilename(it.fileName().remove(0, 8)))) {
0613                 QDirIterator it2(it.filePath(), QDir::Writable | QDir::Files);
0614                 while (it2.hasNext()) {
0615                     it2.next();
0616                     // take ownership of the abandoned file
0617                     const QString newFileName = dirForMyOwnedSessionFiles() +
0618                                                 '/' + it2.fileName();
0619                     QFile::rename(it2.filePath(), newFileName);
0620                     sessionFilePaths.append(newFileName);
0621                 }
0622                 // Remove the old directory
0623                 QDir(it.filePath()).removeRecursively();
0624             }
0625         } else { // it's a file
0626             if (!idbus->isServiceRegistered(KonqMisc::decodeFilename(it.fileName()))) {
0627                 // and it's abandoned: take its ownership
0628                 const QString newFileName = dirForMyOwnedSessionFiles() + '/' +
0629                                             it.fileName();
0630                 QFile::rename(it.filePath(), newFileName);
0631                 sessionFilePaths.append(newFileName);
0632             }
0633         }
0634     }
0635 
0636     return sessionFilePaths;
0637 }
0638 
0639 void KonqSessionManager::restoreSessions(const QStringList &sessionFilePathsList,
0640         bool openTabsInsideCurrentWindow, KonqMainWindow *parent)
0641 {
0642     for (const QString &sessionFilePath: sessionFilePathsList) {
0643         restoreSession(sessionFilePath, openTabsInsideCurrentWindow, parent);
0644     }
0645 }
0646 
0647 void KonqSessionManager::restoreSessions(const QString &sessionsDir, bool
0648         openTabsInsideCurrentWindow, KonqMainWindow *parent)
0649 {
0650     QDirIterator it(sessionsDir, QDir::Readable | QDir::Files);
0651 
0652     while (it.hasNext()) {
0653         QFileInfo fi(it.next());
0654         restoreSession(fi.filePath(), openTabsInsideCurrentWindow, parent);
0655     }
0656 }
0657 
0658 void KonqSessionManager::restoreSession(const QString &sessionFilePath, bool
0659                                         openTabsInsideCurrentWindow, KonqMainWindow *parent)
0660 {
0661     if (!QFile::exists(sessionFilePath)) {
0662         return;
0663     }
0664 
0665     KConfig config(sessionFilePath, KConfig::SimpleConfig);
0666     const QList<KConfigGroup> groups = windowConfigGroups(config);
0667     for (const KConfigGroup &configGroup: groups) {
0668         if (!openTabsInsideCurrentWindow) {
0669             KonqViewManager::openSavedWindow(configGroup)->show();
0670         } else {
0671             parent->viewManager()->openSavedWindow(configGroup, true);
0672         }
0673     }
0674 }
0675 
0676 bool KonqSessionManager::restoreSessionSavedAtExit()
0677 {
0678     KConfigGroup grp = KSharedConfig::openConfig()->group(QStringLiteral("UserSettings"));
0679     if (!grp.readEntry(QStringLiteral("RestoreLastState"), false)) {
0680         return false;
0681     }
0682 
0683     QString lastSessionPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("last_session"));
0684     if (lastSessionPath.isEmpty()) {
0685         return false;
0686     }
0687 
0688     restoreSession(lastSessionPath);
0689     QFile(lastSessionPath).remove();
0690 
0691     return !KonqMainWindow::mainWindows().isEmpty();
0692 }
0693 
0694 static void removeDiscardedSessions(const QStringList &sessionFiles, const QStringList &discardedSessions)
0695 {
0696     if (discardedSessions.isEmpty()) {
0697         return;
0698     }
0699 
0700     for (const QString &sessionFile: sessionFiles) {
0701         KConfig config(sessionFile, KConfig::SimpleConfig);
0702         QList<KConfigGroup> groups = windowConfigGroups(config);
0703         for (int i = 0, count = groups.count(); i < count; ++i) {
0704             KConfigGroup &group = groups[i];
0705             const QString rootItem = group.readEntry("RootItem", "empty");
0706             const QString viewsKey(rootItem + QLatin1String("_Children"));
0707             QStringList views = group.readEntry(viewsKey, QStringList());
0708             QMutableStringListIterator it(views);
0709             while (it.hasNext()) {
0710                 if (discardedSessions.contains(viewIdFor(sessionFile, it.next()))) {
0711                     it.remove();
0712                 }
0713             }
0714             group.writeEntry(viewsKey, views);
0715         }
0716     }
0717 }
0718 
0719 bool KonqSessionManager::askUserToRestoreAutosavedAbandonedSessions()
0720 {
0721     const QStringList sessionFilePaths = takeSessionsOwnership();
0722     if (sessionFilePaths.isEmpty()) {
0723         return false;
0724     }
0725 
0726     disableAutosave();
0727 
0728     int result;
0729     QStringList discardedSessionList;
0730     const QLatin1String dontAskAgainName("Restore session when konqueror didn't close correctly");
0731 
0732     if (SessionRestoreDialog::shouldBeShown(dontAskAgainName, &result)) {
0733         SessionRestoreDialog *restoreDlg = new SessionRestoreDialog(sessionFilePaths);
0734         if (restoreDlg->isEmpty()) {
0735             result = QDialogButtonBox::No;
0736         } else {
0737             result = restoreDlg->exec();
0738             discardedSessionList = restoreDlg->discardedSessionList();
0739             if (restoreDlg->isDontShowChecked()) {
0740                 SessionRestoreDialog::saveDontShow(dontAskAgainName, result);
0741             }
0742         }
0743         delete restoreDlg;
0744     }
0745 
0746     switch (result) {
0747     case QDialogButtonBox::Yes:
0748         // Remove the discarded session list files.
0749         removeDiscardedSessions(sessionFilePaths, discardedSessionList);
0750         restoreSessions(sessionFilePaths);
0751         enableAutosave();
0752         return true;
0753     case QDialogButtonBox::No:
0754         deleteOwnedSessions();
0755         enableAutosave();
0756         return false;
0757     default:
0758         // Remove the ownership of the currently owned files
0759         QDirIterator it(dirForMyOwnedSessionFiles(),
0760                         QDir::Writable | QDir::Files);
0761 
0762         while (it.hasNext()) {
0763             it.next();
0764             // remove ownership of the abandoned file
0765             QFile::rename(it.filePath(), m_autosaveDir + '/' + it.fileName());
0766         }
0767         // Remove the owned_by directory
0768         QDir(dirForMyOwnedSessionFiles()).removeRecursively();
0769         enableAutosave();
0770         return false;
0771     }
0772 }
0773 
0774 void KonqSessionManager::setPreloadedWindowsNumber(const QList<int> &numbers)
0775 {
0776     m_preloadedWindowsNumber = numbers;
0777 }
0778 
0779 void KonqSessionManager::registerMainWindow(KonqMainWindow* window)
0780 {
0781 #ifdef KActivities_FOUND
0782     m_activityManager->registerMainWindow(window);
0783 #else
0784     Q_UNUSED(window);
0785 #endif
0786 }
0787 
0788 #ifdef KActivities_FOUND
0789 ActivityManager * KonqSessionManager::activityManager()
0790 {
0791     return m_activityManager;
0792 }
0793 #endif