File indexing completed on 2024-04-28 08:50:45
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