[kde-doc-english] [kde-baseapps] konqueror/src: In the session restore dialog, allow the user to select which sessions should
Dawit Alemayehu
adawit at kde.org
Tue Oct 9 23:06:14 UTC 2012
Git commit 0142a8ca11b00b5b24347b92700b7f6c5bdb3e75 by Dawit Alemayehu.
Committed on 19/09/2012 at 06:12.
Pushed by adawit into branch 'master'.
In the session restore dialog, allow the user to select which sessions should
be restored.
BUG: 260282
FIXED-IN: 4.10
REVIEW: 106503
GUI: new strings
DIGEST: Ability to select the session(s) to be restored in Konqueror.
M +336 -56 konqueror/src/konqsessionmanager.cpp
M +51 -0 konqueror/src/konqsessionmanager.h
http://commits.kde.org/kde-baseapps/0142a8ca11b00b5b24347b92700b7f6c5bdb3e75
diff --git a/konqueror/src/konqsessionmanager.cpp b/konqueror/src/konqsessionmanager.cpp
index 68a003f..ac5c691 100644
--- a/konqueror/src/konqsessionmanager.cpp
+++ b/konqueror/src/konqsessionmanager.cpp
@@ -33,12 +33,14 @@
#include <kvbox.h>
#include <khbox.h>
#include <klocale.h>
-#include <kmessagebox.h>
+#include <kdialog.h>
#include <kurl.h>
#include <ktempdir.h>
+#include <ksqueezedtextlabel.h>
#include <QPushButton>
-#include <QtCore/QFileInfo>
+#include <QCheckBox>
+#include <QFileInfo>
#include <QPoint>
#include <QtDBus/QtDBus>
#include <QtAlgorithms>
@@ -47,6 +49,12 @@
#include <QDBusArgument>
#include <QFile>
#include <QSize>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QTreeWidget>
+#include <QScrollArea>
+#include <QScrollBar>
+
class KonqSessionManagerPrivate
{
@@ -66,8 +74,291 @@ public:
K_GLOBAL_STATIC(KonqSessionManagerPrivate, myKonqSessionManagerPrivate)
+static QString viewIdFor(const QString& sessionFile, const QString& viewId)
+{
+ return (sessionFile + viewId);
+}
+
+static const QList<KConfigGroup> windowConfigGroups(const KConfig& config)
+{
+ QList<KConfigGroup> groups;
+ KConfigGroup generalGroup(&config, "General");
+ const int size = generalGroup.readEntry("Number of Windows", 0);
+ for(int i = 0; i < size; i++) {
+ groups << KConfigGroup(&config, "Window" + QString::number(i));
+ }
+ return groups;
+}
+
+SessionRestoreDialog::SessionRestoreDialog(const QStringList& sessionFilePaths, QWidget* parent)
+ : KDialog(parent, 0)
+ ,m_sessionItemsCount(0)
+ ,m_dontShowChecked(false)
+{
+ setCaption(i18nc("@title:window", "Restore Session?"));
+ setButtons(KDialog::Yes | KDialog::No | KDialog::Cancel);
+ setObjectName(QLatin1String("restoresession"));
+ setButtonGuiItem(KDialog::Yes, KGuiItem(i18nc("@action:button yes", "Restore Session"), "window-new"));
+ setButtonGuiItem(KDialog::No, KGuiItem(i18nc("@action:button no","Do Not Restore"), "dialog-close"));
+ setButtonGuiItem(KDialog::Cancel, KGuiItem(i18nc("@action:button ask later","Ask Me Later"), "chronometer"));
+ setDefaultButton(KDialog::Yes);
+ setButtonFocus(KDialog::Yes);
+ setModal(true);
+
+ QWidget *mainWidget = new QWidget(this);
+ QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget);
+ mainLayout->setSpacing(KDialog::spacingHint() * 2); // provide extra spacing
+ mainLayout->setMargin(0);
+
+ QHBoxLayout *hLayout = new QHBoxLayout();
+ hLayout->setMargin(0);
+ hLayout->setSpacing(-1); // use default spacing
+ mainLayout->addLayout(hLayout,5);
+
+ KIcon icon (QLatin1String("dialog-warning"));
+ if (!icon.isNull()) {
+ QLabel *iconLabel = new QLabel(mainWidget);
+ QStyleOption option;
+ option.initFrom(mainWidget);
+ iconLabel->setPixmap(icon.pixmap(mainWidget->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, mainWidget)));
+ QVBoxLayout *iconLayout = new QVBoxLayout();
+ iconLayout->addStretch(1);
+ iconLayout->addWidget(iconLabel);
+ iconLayout->addStretch(5);
+ hLayout->addLayout(iconLayout,0);
+ }
+
+ const QString text (i18n("Konqueror did not close correctly. Would you like to restore these previous sessions?"));
+ QLabel *messageLabel = new QLabel(text, mainWidget);
+ Qt::TextInteractionFlags flags = (Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+ messageLabel->setTextInteractionFlags(flags);
+ messageLabel->setWordWrap(true);
+
+ hLayout->addSpacing(KDialog::spacingHint());
+ hLayout->addWidget(messageLabel,5);
+
+ QTreeWidget* treeWidget = 0;
+ if (!sessionFilePaths.isEmpty()) {
+ treeWidget = new QTreeWidget(mainWidget);
+ treeWidget->setHeader(0);
+ treeWidget->setHeaderHidden(true);
+ treeWidget->setToolTip(i18nc("@tooltip:session list", "Uncheck the sessions you do not want to be restored"));
+
+ QStyleOptionViewItem styleOption;
+ styleOption.initFrom(treeWidget);
+ QFontMetrics fm(styleOption.font);
+ int w = treeWidget->width();
+ const QRect desktop = KGlobalSettings::desktopGeometry(this);
+
+ // Collect info from the sessions to restore
+ Q_FOREACH(const QString& sessionFile, sessionFilePaths) {
+ kDebug() << sessionFile;
+ QTreeWidgetItem* windowItem = 0;
+ const KConfig config(sessionFile, KConfig::SimpleConfig);
+ const QList<KConfigGroup> groups = windowConfigGroups(config);
+ Q_FOREACH(const KConfigGroup& group, groups) {
+ // To avoid a recursive search, let's do linear search on Foo_CurrentHistoryItem=1
+ Q_FOREACH(const QString& key, group.keyList()) {
+ if (key.endsWith(QLatin1String("_CurrentHistoryItem"))) {
+ const QString viewId = key.left(key.length() - qstrlen("_CurrentHistoryItem"));
+ const QString historyIndex = group.readEntry(key, QString());
+ const QString prefix = "HistoryItem" + viewId + '_' + historyIndex;
+ // Ignore the sidebar views
+ if (group.readEntry(prefix + "StrServiceName", QString()).startsWith("konq_sidebar"))
+ continue;
+ const QString url = group.readEntry(prefix + "Url", QString());
+ const QString title = group.readEntry(prefix + "Title", QString());
+ kDebug() << viewId << url << title;
+ const QString displayText = (title.trimmed().isEmpty() ? url : title);
+ if (!displayText.isEmpty()) {
+ if (!windowItem) {
+ windowItem = new QTreeWidgetItem(treeWidget);
+ const int index = sessionFilePaths.indexOf(sessionFile) + 1;
+ windowItem->setText(0, i18nc("@item:treewidget", "Window %1", index));
+ windowItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
+ windowItem->setCheckState(0, Qt::Checked);
+ windowItem->setExpanded(true);
+ }
+ QTreeWidgetItem* item = new QTreeWidgetItem (windowItem);
+ item->setText(0, displayText);
+ item->setData(0, Qt::UserRole, viewIdFor(sessionFile, viewId));
+ item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
+ item->setCheckState(0, Qt::Checked);
+ w = qMax(w, fm.width(displayText));
+ m_sessionItemsCount++;
+ }
+ }
+ }
+ }
+
+ if (windowItem) {
+ m_checkedSessionItems.insert(windowItem, windowItem->childCount());
+ }
+ }
+
+ const int borderWidth = treeWidget->width() - treeWidget->viewport()->width() + treeWidget->verticalScrollBar()->height();
+ w += borderWidth;
+ if (w > desktop.width() * 0.85) { // limit treeWidget size to 85% of screen width
+ w = qRound(desktop.width() * 0.85);
+ }
+ treeWidget->setMinimumWidth(w);
+ mainLayout->addWidget(treeWidget, 50);
+ treeWidget->setSelectionMode(QTreeWidget::NoSelection);
+ messageLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
+ }
+
+ // Do not connect the itemChanged signal until after the treewidget
+ // is completely populated to prevent the firing of the itemChanged
+ // signal while in the process of adding the original session items.
+ if (treeWidget && treeWidget->topLevelItemCount() > 0) {
+ connect(treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
+ this, SLOT(slotItemChanged(QTreeWidgetItem*,int)));
+ }
+
+ QCheckBox* checkbox = new QCheckBox(i18n("Do not ask again"), mainWidget);
+ connect(checkbox, SIGNAL(clicked(bool)), this, SLOT(slotClicked(bool)));
+ mainLayout->addWidget(checkbox);
+
+ setMainWidget(mainWidget);
+}
+
+SessionRestoreDialog::~SessionRestoreDialog()
+{
+}
+
+QStringList SessionRestoreDialog::discardedSessionList() const
+{
+ return m_discardedSessionList;
+}
+
+bool SessionRestoreDialog::isDontShowChecked() const
+{
+ return m_dontShowChecked;
+}
+
+void SessionRestoreDialog::slotClicked(bool checked)
+{
+ m_dontShowChecked = checked;
+}
+
+static void setCheckState(QTreeWidgetItem* item, int column, Qt::CheckState state)
+{
+ const bool blocked = item->treeWidget()->blockSignals(true);
+ item->setCheckState(column, state);
+ item->treeWidget()->blockSignals(blocked);
+}
+
+void SessionRestoreDialog::slotItemChanged(QTreeWidgetItem* item, int column)
+{
+ Q_ASSERT(item);
+
+ const int itemChildCount = item->childCount();
+ QTreeWidgetItem* parentItem = 0;
+
+ const bool blocked = item->treeWidget()->blockSignals(true);
+ if (itemChildCount > 0) {
+ parentItem = item;
+ for (int i = 0; i < itemChildCount; ++i) {
+ QTreeWidgetItem* childItem = item->child(i);
+ if (childItem) {
+ childItem->setCheckState(column, item->checkState(column));
+ switch (childItem->checkState(column)) {
+ case Qt::Checked:
+ m_sessionItemsCount++;
+ m_discardedSessionList.removeAll(childItem->data(column, Qt::UserRole).toString());
+ m_checkedSessionItems[item]++;
+ break;
+ case Qt::Unchecked:
+ m_sessionItemsCount--;
+ m_discardedSessionList.append(childItem->data(column, Qt::UserRole).toString());
+ m_checkedSessionItems[item]--;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ } else {
+ parentItem = item->parent();
+ switch (item->checkState(column)) {
+ case Qt::Checked:
+ m_sessionItemsCount++;
+ m_discardedSessionList.removeAll(item->data(column, Qt::UserRole).toString());
+ m_checkedSessionItems[parentItem]++;
+ break;
+ case Qt::Unchecked:
+ m_sessionItemsCount--;
+ m_discardedSessionList.append(item->data(column, Qt::UserRole).toString());
+ m_checkedSessionItems[parentItem]--;
+ break;
+ default:
+ break;
+ }
+ }
+
+ const int numCheckSessions = m_checkedSessionItems.value(parentItem);
+ switch (parentItem->checkState(column)) {
+ case Qt::Checked:
+ if (numCheckSessions == 0) {
+ parentItem->setCheckState(column, Qt::Unchecked);
+ }
+ case Qt::Unchecked:
+ if (numCheckSessions > 0) {
+ parentItem->setCheckState(column, Qt::Checked);
+ }
+ default:
+ break;
+ }
+
+ enableButton(KDialog::Yes, m_sessionItemsCount > 0);
+ item->treeWidget()->blockSignals(blocked);
+}
+
+void SessionRestoreDialog::saveDontShow(const QString& dontShowAgainName, int result)
+{
+ if (dontShowAgainName.isEmpty()) {
+ return;
+ }
+
+ KConfigGroup::WriteConfigFlags flags = KConfig::Persistent;
+ if (dontShowAgainName[0] == ':') {
+ flags |= KConfigGroup::Global;
+ }
+
+ KConfigGroup cg(KGlobal::config().data(), "Notification Messages");
+ cg.writeEntry( dontShowAgainName, result==Yes, flags );
+ cg.sync();
+}
+
+bool SessionRestoreDialog::shouldBeShown(const QString& dontShowAgainName, int* result)
+{
+ if (dontShowAgainName.isEmpty()) {
+ return true;
+ }
+
+ KConfigGroup cg(KGlobal::config().data(), "Notification Messages");
+ const QString dontAsk = cg.readEntry(dontShowAgainName, QString()).toLower();
+
+ if (dontAsk == "yes" || dontAsk == "true") {
+ if (result) {
+ *result = Yes;
+ }
+ return false;
+ }
+
+ if (dontAsk == "no" || dontAsk == "false") {
+ if (result) {
+ *result = No;
+ }
+ return false;
+ }
+
+ return true;
+}
+
KonqSessionManager::KonqSessionManager()
: m_autosaveDir(KStandardDirs::locateLocal("appdata", "autosave"))
+ , m_autosaveEnabled(false) // so that enableAutosave works
{
// Initialize dbus interfaces
new KonqSessionManagerAdaptor ( this );
@@ -87,7 +378,6 @@ KonqSessionManager::KonqSessionManager()
connect( &m_autoSaveTimer, SIGNAL(timeout()), this,
SLOT(autoSaveSession()) );
}
- m_autosaveEnabled = false; // so that enableAutosave works
enableAutosave();
}
@@ -261,17 +551,6 @@ void KonqSessionManager::restoreSessions(const QString &sessionsDir, bool
}
}
-static const QList<KConfigGroup> windowConfigGroups(const KConfig& config)
-{
- QList<KConfigGroup> groups;
- KConfigGroup generalGroup(&config, "General");
- const int size = generalGroup.readEntry("Number of Windows", 0);
- for(int i = 0; i < size; i++) {
- groups << KConfigGroup(&config, "Window" + QString::number(i));
- }
- return groups;
-}
-
void KonqSessionManager::restoreSession(const QString &sessionFilePath, bool
openTabsInsideCurrentWindow, KonqMainWindow *parent)
{
@@ -288,59 +567,61 @@ void KonqSessionManager::restoreSession(const QString &sessionFilePath, bool
}
}
-
-bool KonqSessionManager::askUserToRestoreAutosavedAbandonedSessions()
+static void removeDiscardedSessions(const QStringList& sessionFiles, const QStringList& discardedSessions)
{
- const QStringList sessionFilePaths = takeSessionsOwnership();
- if(sessionFilePaths.isEmpty())
- return false;
+ if (discardedSessions.isEmpty()) {
+ return;
+ }
- QStringList detailsList;
- // Collect info from the sessions to restore
- Q_FOREACH(const QString& sessionFile, sessionFilePaths) {
- kDebug() << sessionFile;
+ Q_FOREACH(const QString& sessionFile, sessionFiles) {
const KConfig config(sessionFile, KConfig::SimpleConfig);
- const QList<KConfigGroup> groups = windowConfigGroups(config);
- Q_FOREACH(const KConfigGroup& group, groups) {
- // To avoid a recursive search, let's do linear search on Foo_CurrentHistoryItem=1
- Q_FOREACH(const QString& key, group.keyList()) {
- if (key.endsWith("_CurrentHistoryItem")) {
- const QString viewId = key.left(key.length() - strlen("_CurrentHistoryItem"));
- const QString historyIndex = group.readEntry(key, QString());
- const QString prefix = "HistoryItem" + viewId + '_' + historyIndex;
- // Ignore the sidebar views
- if (group.readEntry(prefix + "StrServiceName", QString()).startsWith("konq_sidebar"))
- continue;
- const QString url = group.readEntry(prefix + "Url", QString());
- const QString title = group.readEntry(prefix + "Title", QString());
- kDebug() << viewId << url << title;
- if (title.trimmed().isEmpty()) {
- detailsList << url;
- } else {
- detailsList << title;
- }
+ QList<KConfigGroup> groups = windowConfigGroups(config);
+ for (int i = 0, count = groups.count(); i < count; ++i) {
+ KConfigGroup& group = groups[i];
+ const QString rootItem = group.readEntry("RootItem", "empty");
+ const QString viewsKey (rootItem + QLatin1String("_Children"));
+ QStringList views = group.readEntry(viewsKey, QStringList());
+ QMutableStringListIterator it (views);
+ while (it.hasNext()) {
+ if (discardedSessions.contains(viewIdFor(sessionFile, it.next()))) {
+ it.remove();
}
}
+ group.writeEntry(viewsKey, views);
}
}
+}
+
+bool KonqSessionManager::askUserToRestoreAutosavedAbandonedSessions()
+{
+ const QStringList sessionFilePaths = takeSessionsOwnership();
+ if(sessionFilePaths.isEmpty())
+ return false;
disableAutosave();
- switch(KMessageBox::warningYesNoCancelList(0, // there is no questionYesNoCancelList
- i18n("Konqueror did not close correctly. Would you like to restore the previous session?"),
- detailsList,
- i18nc("@title:window", "Restore Session?"),
- KGuiItem(i18n("Restore Session"), "window-new"),
- KGuiItem(i18n("Do Not Restore"), "dialog-close"),
- KGuiItem(i18n("Ask Me Later"), "chronometer"),
- "Restore session when konqueror didn't close correctly"
- ))
- {
- case KMessageBox::Yes:
+ int result;
+ QStringList discardedSessionList;
+ const QLatin1String dontAskAgainName ("Restore session when konqueror didn't close correctly");
+
+ if (SessionRestoreDialog::shouldBeShown(dontAskAgainName, &result)) {
+ SessionRestoreDialog* restoreDlg = new SessionRestoreDialog(sessionFilePaths);
+ result = restoreDlg->exec();
+ discardedSessionList = restoreDlg->discardedSessionList();
+ if (restoreDlg->isDontShowChecked()) {
+ SessionRestoreDialog::saveDontShow(dontAskAgainName, result);
+ }
+ delete restoreDlg;
+ }
+
+ switch (result) {
+ case KDialog::Yes:
+ // Remove the discarded session list files.
+ removeDiscardedSessions(sessionFilePaths, discardedSessionList);
restoreSessions(sessionFilePaths);
enableAutosave();
return true;
- case KMessageBox::No:
+ case KDialog::No:
deleteOwnedSessions();
enableAutosave();
return false;
@@ -349,8 +630,7 @@ bool KonqSessionManager::askUserToRestoreAutosavedAbandonedSessions()
QDirIterator it(dirForMyOwnedSessionFiles(),
QDir::Writable|QDir::Files);
- while (it.hasNext())
- {
+ while (it.hasNext()) {
it.next();
// remove ownership of the abandoned file
QFile::rename(it.filePath(), m_autosaveDir + '/' + it.fileName());
diff --git a/konqueror/src/konqsessionmanager.h b/konqueror/src/konqsessionmanager.h
index ee629e4..d3103ac 100644
--- a/konqueror/src/konqsessionmanager.h
+++ b/konqueror/src/konqsessionmanager.h
@@ -27,10 +27,61 @@
#include <QString>
#include <kconfig.h>
+#include <kdialog.h>
#include <konqprivate_export.h>
class QDBusMessage;
class KonqMainWindow;
+class QTreeWidgetItem;
+
+class SessionRestoreDialog : public KDialog
+{
+ Q_OBJECT
+public:
+ explicit SessionRestoreDialog(const QStringList& sessionFilePaths, QWidget* parent=0);
+ virtual ~SessionRestoreDialog();
+
+ /**
+ * Returns the list of session discarded/unselected by the user.
+ */
+ QStringList discardedSessionList() const;
+
+ /**
+ * Returns true if the don't show checkbox is checked.
+ */
+ bool isDontShowChecked() const;
+
+ /**
+ * Returns true if the corresponding session restore dialog should be shown.
+ *
+ * @param dontShowAgainName the name that identify the session restore dialog box.
+ * @param result if not null, it will be set to the result that was chosen the last
+ * time the dialog box was shown. This is only useful if the restore dialog box should
+ * be shown.
+ */
+ static bool shouldBeShown(const QString &dontShowAgainName, int* result);
+
+ /**
+ * Save the fact that the session restore dialog should not be shown again.
+ *
+ * @param dontShowAgainName the name that identify the session restore dialog. If
+ * empty, this method does nothing.
+ * @param result the value (Yes or No) that should be used as the result
+ * for the message box.
+ */
+ static void saveDontShow(const QString &dontShowAgainName, int result);
+
+private Q_SLOTS:
+ void slotClicked(bool);
+ void slotItemChanged(QTreeWidgetItem*, int);
+
+private:
+ QStringList m_discardedSessionList;
+ QHash<QTreeWidgetItem*, int> m_checkedSessionItems;
+ int m_sessionItemsCount;
+ bool m_dontShowChecked;
+};
+
/**
* This class is a singleton. It does some session related tasks:
More information about the kde-doc-english
mailing list