From 074f8c7ccb685fb9fa2a51dec5049637e727a9c2 Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Thu, 21 Apr 2016 14:45:42 +1000 Subject: [PATCH] Kate session panel: fixed handling of volatile sessions. Also bug fixes and improved model-view code separation Signed-off-by: Michele Calgaro --- cmake | 2 +- kate/app/kateapp.cpp | 2 +- kate/app/katesession.cpp | 141 +++++++++++++++++++++------------- kate/app/katesession.h | 47 ++++++++---- kate/app/katesessionpanel.cpp | 103 +++++++++++++++++++------ kate/app/katesessionpanel.h | 14 +++- 6 files changed, 213 insertions(+), 96 deletions(-) diff --git a/cmake b/cmake index 1d8a7873c..416e4baaa 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 1d8a7873c0e0660c58a2d0d7b054d216d5f06b0a +Subproject commit 416e4baaa96058a323968657ee51d5eb0ff0c5c6 diff --git a/kate/app/kateapp.cpp b/kate/app/kateapp.cpp index 06b0c0ecb..aeecc5fac 100644 --- a/kate/app/kateapp.cpp +++ b/kate/app/kateapp.cpp @@ -172,7 +172,7 @@ bool KateApp::startupKate() } else { - sessionManager()->newSession(sessName, true); + sessionManager()->newSession(sessName); } } else diff --git a/kate/app/katesession.cpp b/kate/app/katesession.cpp index 9fc865d52..91d0ad05a 100644 --- a/kate/app/katesession.cpp +++ b/kate/app/katesession.cpp @@ -71,7 +71,7 @@ namespace const char *KSM_DIR = "kate/sessions"; const char *KSM_FILE = "sessions.list"; const char *KSM_SESSIONS_COUNT = "Sessions count"; - const char *KSM_ACTIVE_SESSION_ID = "Active session id"; + const char *KSM_LAST_SESSION_ID = "Last session id"; const char *KSM_SESSIONS_LIST = "Sessions list"; } @@ -90,7 +90,12 @@ KateSession::KateSession(const KateSession &session, const TQString &newSessionN m_readOnly(false), m_documents(session.m_documents), m_config(NULL) { createFilename(); - m_config = dynamic_cast(session.m_config->copyTo(m_filename)); + if (session.m_config) + { + m_config = new KSimpleConfig(m_filename); + session.m_config->copyTo(m_filename, m_config); + m_config->sync(); + } } //------------------------------------ @@ -108,6 +113,12 @@ void KateSession::setSessionName(const TQString &sessionName) m_sessionName = sessionName.isEmpty() ? i18n(KS_UNNAMED) : sessionName; } +//------------------------------------ +bool KateSession::isStillVolatile() const +{ + return m_filename.isEmpty() && m_sessionName == i18n(KS_UNNAMED); +} + //------------------------------------ void KateSession::load(bool includeGUIInfo) { @@ -167,7 +178,7 @@ void KateSession::load(bool includeGUIInfo) m_sessionName = i18n(KS_UNNAMED); } - // Update e all current documents if necessary + // Update all current documents if necessary if (includeGUIInfo) { activate(); @@ -238,31 +249,31 @@ void KateSession::activate() { KateDocManager::self()->closeAllDocuments(); } + Kate::Document::setOpenErrorDialogsActivated(false); if (m_config) { KateApp::self()->documentManager()->restoreDocumentList(m_config); - } - - // load main windows info, if it exists - if (m_config && m_config->hasGroup(KS_OPEN_MAINWINDOWS)) - { - m_config->setGroup(KS_OPEN_MAINWINDOWS); - int mwCount = m_config->readUnsignedNumEntry(KS_COUNT, 1); - for (int i=0; ihasGroup(KS_OPEN_MAINWINDOWS)) { - if (i >= (int)KateApp::self()->mainWindows()) - { - KateApp::self()->newMainWindow(m_config, TQString("MainWindow%1").arg(i)); - } - else + m_config->setGroup(KS_OPEN_MAINWINDOWS); + int mwCount = m_config->readUnsignedNumEntry(KS_COUNT, 1); + for (int i = 0; i < mwCount; ++i) { - m_config->setGroup(TQString("MainWindow%1").arg(i)); - KateApp::self()->mainWindow(i)->readProperties(m_config); + if (i >= (int)KateApp::self()->mainWindows()) + { + KateApp::self()->newMainWindow(m_config, TQString("MainWindow%1").arg(i)); + } + else + { + m_config->setGroup(TQString("MainWindow%1").arg(i)); + KateApp::self()->mainWindow(i)->readProperties(m_config); + } } } } - Kate::Document::setOpenErrorDialogsActivated(true); } @@ -310,7 +321,7 @@ KateSessionManager* KateSessionManager::self() //------------------------------------ KateSessionManager::KateSessionManager() : m_baseDir(locateLocal("data", KSM_DIR)+"/"), m_configFile(m_baseDir + KSM_FILE), - m_activeSessionId(0), m_firstActivation(true), m_sessions(), m_config(NULL) + m_activeSessionId(INVALID_SESSION), m_lastSessionId(INVALID_SESSION), m_sessions(), m_config(NULL) { m_sessions.setAutoDelete(true); @@ -321,7 +332,7 @@ KateSessionManager::KateSessionManager() : m_config = new KSimpleConfig(m_configFile); m_config->setGroup(KSM_SESSIONS_LIST); sessionsCount = m_config->readNumEntry(KSM_SESSIONS_COUNT, 0); - m_activeSessionId = m_config->readNumEntry(KSM_ACTIVE_SESSION_ID, 0); + m_lastSessionId = m_config->readNumEntry(KSM_LAST_SESSION_ID, INVALID_SESSION); for (int i = 0; i < sessionsCount; ++i) { TQString urlStr = m_config->readEntry(TQString("URL_%1").arg(i)); @@ -347,19 +358,19 @@ KateSessionManager::KateSessionManager() : { m_sessions.append(new KateSession(*this, TQString::null, TQString::null)); } - if (m_activeSessionId < 0 || m_activeSessionId >= (int)m_sessions.count()) + if (m_lastSessionId < 0 || m_lastSessionId >= (int)m_sessions.count()) { - m_activeSessionId = 0; // Invalid active session was detected. Use first in the list + m_lastSessionId = 0; // Invalid last session was detected. Use first in the list } //NOTE do not activate any session in the KateSessionManager costructor // since Kate's main window may not be ready yet. The initial session - // will be activated by KateApp::startupKate() or void KateApp::restoreKate() + // will be activated by KateApp::startupKate() or KateApp::restoreKate() } //------------------------------------ KateSessionManager::~KateSessionManager() { - saveConfig(); + saveConfig(true); if (m_config) { delete m_config; @@ -376,7 +387,7 @@ KateSessionManager::~KateSessionManager() // FIXME An option need to be added to Configure Kate -> Sessions to allow Kate to ask about // saving unnamed sessions before closing the current session. Default value is off as per // point above. -void KateSessionManager::saveConfig() +void KateSessionManager::saveConfig(bool saveSessions) { if (!m_config) { @@ -388,11 +399,14 @@ void KateSessionManager::saveConfig() } m_config->setGroup(KSM_SESSIONS_LIST); m_config->writeEntry(KSM_SESSIONS_COUNT, m_sessions.count()); - m_config->writeEntry(KSM_ACTIVE_SESSION_ID, m_activeSessionId); + m_config->writeEntry(KSM_LAST_SESSION_ID, m_activeSessionId); for (int i = 0; i < (int)m_sessions.count(); ++i) { - // Save the session first, to make sure a new session has an associated file - m_sessions[i]->save(false); + //FIXME need to consider when sessions has to be saved. + if (saveSessions) + { + saveSession(i, false, false); + } m_config->writeEntry(TQString("URL_%1").arg(i), m_sessions[i]->getSessionFilename()); } m_config->sync(); @@ -424,7 +438,7 @@ KateSession* KateSessionManager::getSessionFromId(int sessionId) int KateSessionManager::getSessionIdFromName(const TQString &name) { if (name.isEmpty()) - return KateSessionManager::INVALID_SESSION; + return INVALID_SESSION; for (int i = 0; i < (int)m_sessions.count(); ++i) { @@ -432,23 +446,24 @@ int KateSessionManager::getSessionIdFromName(const TQString &name) return i; } - return KateSessionManager::INVALID_SESSION; + return INVALID_SESSION; } //------------------------------------ bool KateSessionManager::activateSession(int sessionId, bool saveCurr) { - if (sessionId < 0) + if (sessionId < 0 || sessionId >= (int)m_sessions.count()) { return false; } - if (!m_firstActivation && sessionId == m_activeSessionId) + if (sessionId == m_activeSessionId) { return true; } - if (!m_firstActivation) + int oldSessionId = m_activeSessionId; + if (m_activeSessionId != INVALID_SESSION) { // Do this only if a session has already been activated earlier, if (KateApp::self()->activeMainWindow()) @@ -457,30 +472,38 @@ bool KateSessionManager::activateSession(int sessionId, bool saveCurr) if (!KateApp::self()->activeMainWindow()->queryClose_internal()) return false; } - if (saveCurr && m_activeSessionId != INVALID_SESSION) + if (saveCurr) { - m_sessions[m_activeSessionId]->save(true); + saveSession(m_activeSessionId, true); + } + else if (m_sessions[m_activeSessionId]->isStillVolatile()) + { + // Automatically delete unstored and unnamed sessions when activating another one + m_sessions.remove(m_activeSessionId); // this also deletes the KateSession item since auto-deletion is enabled + m_activeSessionId = INVALID_SESSION; + if (sessionId > oldSessionId) + { + --sessionId; + } + emit sessionDeleted(oldSessionId); + oldSessionId = INVALID_SESSION; } } - int oldSessionId = m_activeSessionId; m_activeSessionId = sessionId; m_sessions[sessionId]->activate(); - m_firstActivation = false; + m_lastSessionId = INVALID_SESSION; emit sessionActivated(m_activeSessionId, oldSessionId); return true; } //------------------------------------ -int KateSessionManager::newSession(const TQString &sessionName, bool activate) +int KateSessionManager::newSession(const TQString &sessionName, bool saveCurr) { m_sessions.append(new KateSession(*this, sessionName, TQString::null)); int newSessionId = m_sessions.count() - 1; emit sessionCreated(newSessionId); - if (activate) - { - activateSession(newSessionId, m_activeSessionId != INVALID_SESSION); - } + activateSession(newSessionId, saveCurr); return newSessionId; } @@ -498,9 +521,12 @@ int KateSessionManager::cloneSession(int sessionId, const TQString &sessionName, // If cloning the active session, the new session will contain the current status // and the original session will be restored to the last saved state (save as... functionality) - m_sessions[newSessionId]->save(true); - reloadActiveSession(); - +/* saveSession(newSessionId, sessionId == m_activeSessionId); + if (sessionId == m_activeSessionId) + { + reloadActiveSession(); + } +*/ if (activate) { activateSession(newSessionId, m_activeSessionId != INVALID_SESSION); @@ -511,27 +537,26 @@ int KateSessionManager::cloneSession(int sessionId, const TQString &sessionName, //------------------------------------ bool KateSessionManager::restoreLastSession() { - if (!m_firstActivation) + if (m_activeSessionId != INVALID_SESSION) { return false; } - // NOTE: m_activeSessionId contains the id of the last active session - return activateSession(m_activeSessionId, false); + return activateSession(m_lastSessionId, false); } //------------------------------------------- -void KateSessionManager::saveSession(int sessionId) +void KateSessionManager::saveSession(int sessionId, bool saveGUIInfo, bool setReadOnly) { if (sessionId < 0 || sessionId >= (int)m_sessions.count()) { return; } - m_sessions[sessionId]->save(sessionId == m_activeSessionId); + m_sessions[sessionId]->save(saveGUIInfo, setReadOnly); emit sessionSaved(sessionId); } //------------------------------------------- -bool KateSessionManager::deleteSession(int sessionId) +bool KateSessionManager::deleteSession(int sessionId, int actSessId) { if (sessionId < 0 || sessionId >= (int)m_sessions.count()) { @@ -555,10 +580,16 @@ bool KateSessionManager::deleteSession(int sessionId) m_activeSessionId = INVALID_SESSION; } emit sessionDeleted(sessionId); - // if the active session was deleted, create a new unnamed session and activate it if (m_activeSessionId == INVALID_SESSION) { - newSession(); + if (m_sessions.count() > 0 && actSessId >= 0 && actSessId < (int)m_sessions.count()) + { + activateSession(actSessId, false); + } + else + { + newSession(); + } } return true; @@ -646,7 +677,7 @@ void KateSessionManager::setSessionReadOnlyStatus(int sessionId, bool readOnly) m_sessions[sessionId]->setReadOnly(readOnly); // Session is saved one last time when making it read only - m_sessions[sessionId]->save(sessionId == m_activeSessionId, true); + saveSession(sessionId, sessionId == m_activeSessionId, true); } //END KateSessionManager diff --git a/kate/app/katesession.h b/kate/app/katesession.h index 01357798b..4b1a63126 100644 --- a/kate/app/katesession.h +++ b/kate/app/katesession.h @@ -98,6 +98,12 @@ class KateSession */ const TQString& getSessionFilename() const { return m_filename; } + /** + * @return whether the session is still volatile, i.e. it has never + * been saved and never been named + */ + bool isStillVolatile() const; + /** * @return the number of documents in the session */ @@ -163,8 +169,6 @@ class KateSession * @note The Kate session manager takes ownership of each session object it handles. */ //FIXME update the sessions.list file when switching to another session or to a new session -//FIXME create a new unnamed session and switch to another session. The first session is saved without -//asking the user for a new session name. This is wrong. class KateSessionManager : public TQObject { Q_OBJECT @@ -187,11 +191,6 @@ class KateSessionManager : public TQObject */ ~KateSessionManager(); - /** - * Save session manager info - */ - void saveConfig(); - /** * @return the session files folder name */ @@ -249,13 +248,14 @@ class KateSessionManager : public TQObject bool activateSession(int sessionId, bool saveCurr = true); /** - * Create a new session and activate it if required + * Create a new session and activate it * @param sessionName new session name - * @param activate if true, activate the new session after creation + * @param saveCurr if true, save the current session before activating the new one * @return the id of the newly created session * @emit sessionCreated + * @emit sessionDeleted (only when leaving an unstored and unnamed session) */ - int newSession(const TQString &sessionName = TQString::null, bool activate = true); + int newSession(const TQString &sessionName = TQString::null, bool saveCurr = true); /** * Create a new session and activate it if required @@ -290,15 +290,18 @@ class KateSessionManager : public TQObject * @param sessionId the id of the session to save * @emit sessionSaved */ - void saveSession(int sessionId); + void saveSession(int sessionId) { saveSession(sessionId, sessionId == m_activeSessionId); } /** * Delete the specified session * @param sessionId the id of the session to delete + * @param actSessId the id of the next session to activate. + * If INVALID_SESSION or invalid, create a new empty session. + * This is only meaningful when deleting the current active session. * @return whether the session has been deleted or not * @emit sessionDeleted */ - bool deleteSession(int sessionId); + bool deleteSession(int sessionId, int actSessId); /** * Move the specified session forward in the session list (by one position) @@ -370,6 +373,12 @@ class KateSessionManager : public TQObject protected: KateSessionManager(); + /** + * Save session manager info + * @param saveSessions if true, all sessions will be saved again + */ + void saveConfig(bool saveSessions); + /** * Swap the position of the two specified sessions in the session list * @param sessionId1 the id of the first session @@ -378,11 +387,20 @@ class KateSessionManager : public TQObject */ void swapSessionsPosition(int sessionId1, int sessionId2); + /** + * Save the specified session + * @param sessionId the id of the session to save + * @param saveGUIInfo if true, save also the information about the GUI elements + * @param setReadOnly necessary to save a session that has to be turned to read only + * @emit sessionSaved + */ + void saveSession(int sessionId, bool saveGUIInfo, bool setReadOnly = false); + TQString m_baseDir; // folder where session files are stored TQString m_configFile; // file where the session list config is stored - int m_activeSessionId; // index of the active session - bool m_firstActivation; // true until at least one session has been activated + int m_activeSessionId; // id of the active session + int m_lastSessionId; // id of the last active session before closing Kate TQPtrList m_sessions; // session list KSimpleConfig *m_config; // session manager config @@ -408,6 +426,7 @@ class KateSessionChooserItem : public TDEListViewItem //BEGIN KateSessionChooser +//FIXME create one single KateSessionChooser and reuse it all the time class KateSessionChooser : public KDialogBase { Q_OBJECT diff --git a/kate/app/katesessionpanel.cpp b/kate/app/katesessionpanel.cpp index 827dc403d..0c28726bd 100644 --- a/kate/app/katesessionpanel.cpp +++ b/kate/app/katesessionpanel.cpp @@ -19,6 +19,7 @@ #include "katesessionpanel.h" #include "katesessionpanel.moc" +#include "kateapp.h" #include "katemainwindow.h" #include "kateviewmanager.h" #include "katesession.h" @@ -195,7 +196,7 @@ void KateSessionPanel::setup_toolbar() a = new TDEAction(i18n("New"), SmallIcon("list-add"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotNewSession()), m_actionCollection, "session_new"); - a->setWhatsThis(i18n("Create a new session.")); + a->setWhatsThis(i18n("Create a new session and switch to it.")); a->plug(m_toolbar); a = new TDEAction(i18n("Save"), SmallIcon("document-save"), 0, @@ -253,13 +254,20 @@ void KateSessionPanel::setup_toolbar() //------------------------------------------- void KateSessionPanel::slotNewSession() { - KateSessionNameChooser *nameChooser = new KateSessionNameChooser(this, true); + KateSessionNameChooser *nameChooser = new KateSessionNameChooser(this, false); int result = nameChooser->exec(); if (result == TQDialog::Accepted) { - m_sessionManager->newSession(nameChooser->getSessionName(), nameChooser->getActivateFlag()); + int res = handleVolatileSession(); + if (res == KMessageBox::Cancel) + { + return; + } + else + { + m_sessionManager->newSession(nameChooser->getSessionName(), res == KMessageBox::Yes); + } } - delete nameChooser; } //------------------------------------------- @@ -278,7 +286,7 @@ void KateSessionPanel::slotSaveSession() return; } - if (ks->getSessionFilename().isEmpty() && ks->getSessionName() == i18n(KS_UNNAMED)) + if (ks->isStillVolatile()) { // Session has never been saved before. Ask user for a session name first slotSaveSessionAs(); @@ -305,15 +313,9 @@ void KateSessionPanel::slotSaveSessionAs() return; } - // If the session was never saved before, the session will be saved with a new name. - // If the session was already saved once, it will be cloned into a new session. - bool cloneSession = true; - //FIXME replace ks->getSessionFilename().isEmpty() with a function that tests for m_fileExists - if (ks->getSessionFilename().isEmpty() && ks->getSessionName() == i18n(KS_UNNAMED)) - { - // Session has never been saved before. - cloneSession = false; - } + // If the session was never saved or named before, the session will be saved with a new name. + // If the session was already saved or named once, it will be cloned into a new session. + bool cloneSession = !ks->isStillVolatile(); // Get new session name KateSessionNameChooser *nameChooser = new KateSessionNameChooser(this, cloneSession); int result = nameChooser->exec(); @@ -332,7 +334,6 @@ void KateSessionPanel::slotSaveSessionAs() } } - delete nameChooser; slotSelectionChanged(); // Update the toolbar button status } @@ -358,11 +359,23 @@ void KateSessionPanel::slotDeleteSession() } int result = KMessageBox::warningContinueCancel(this, - i18n("Do you really want to delete the session '%1'?").arg(sessionItem->text(0)), + i18n("Do you really want to delete the session \"%1\"?").arg(sessionItem->text(0)), i18n("Delete session"), KStdGuiItem::del()); if (result == KMessageBox::Continue) { - m_sessionManager->deleteSession(sessionItem->getSessionId()); + int sessionId = sessionItem->getSessionId(); + if (sessionId == m_sessionManager->getActiveSessionId()) + { + // First check if all documents can be closed safely + if (KateApp::self()->activeMainWindow()) + { + if (!KateApp::self()->activeMainWindow()->queryClose_internal()) + return; + } + } + //FIXME add options to let user decide what to do when deleting the current session + //(open previous/next session, create new empty session) + m_sessionManager->deleteSession(sessionId, KateSessionManager::INVALID_SESSION); } } @@ -397,7 +410,15 @@ void KateSessionPanel::slotActivateSession() int newSessionId = newSessionItem->getSessionId(); if (newSessionId != currSessionId) { - m_sessionManager->activateSession(newSessionId); + int res = handleVolatileSession(); + if (res == KMessageBox::Cancel) + { + return; + } + else + { + m_sessionManager->activateSession(newSessionId, res == KMessageBox::Yes); + } } } @@ -520,12 +541,18 @@ void KateSessionPanel::slotSelectionChanged() void KateSessionPanel::slotSessionActivated(int newSessionId, int oldSessionId) { // Move the active session marker - TQListViewItem *item = m_listview->firstChild(); - for (int idx = 0; idx < oldSessionId; ++idx) - { - item = item->nextSibling(); - } - item->setPixmap(m_columnPixmap, TQPixmap()); + TQListViewItem *item = NULL; + if (oldSessionId != KateSessionManager::INVALID_SESSION) + { + // Old volatile sessions may have already been deleted. + // Remove the marker only for valid sessions. + item = m_listview->firstChild(); + for (int idx = 0; idx < oldSessionId; ++idx) + { + item = item->nextSibling(); + } + item->setPixmap(m_columnPixmap, TQPixmap()); + } item = m_listview->firstChild(); for (int idx = 0; idx < newSessionId; ++idx) @@ -654,4 +681,32 @@ void KateSessionPanel::slotLVSessionRenamed(TQListViewItem *item) m_sessionManager->renameSession(sessionItem->getSessionId(), sessionItem->text(m_columnName)); } + +//------------------------------------------- +int KateSessionPanel::handleVolatileSession() +{ + const KateSession *ks = m_sessionManager->getActiveSession(); + if (!ks || !ks->isStillVolatile()) + { + return (!ks ? KMessageBox::No : KMessageBox::Yes); + } + + int msgres = KMessageBox::warningYesNoCancel(this, i18n("

You are leaving a volatile session." + "

Do you want to save or discard it?").arg(ks->getSessionName()), + i18n("Close session"), KStdGuiItem::save(), KStdGuiItem::discard()); + if (msgres == KMessageBox::Yes) + { + KateSessionNameChooser *nameChooser = new KateSessionNameChooser(this, false); + int result = nameChooser->exec(); + if (result == TQDialog::Accepted) + { + m_sessionManager->renameSession(m_sessionManager->getActiveSessionId(), nameChooser->getSessionName()); + } + else + { + msgres = KMessageBox::Cancel; + } + } + return msgres; +} //END KateSessionPanel diff --git a/kate/app/katesessionpanel.h b/kate/app/katesessionpanel.h index 2dd7347a7..6899d68e9 100644 --- a/kate/app/katesessionpanel.h +++ b/kate/app/katesessionpanel.h @@ -41,6 +41,7 @@ class TDEActionCollection; //BEGIN KateSessionNameChooser +//FIXME create one single KateSessionNameChooser and reuse it all the time class KateSessionNameChooser : public KDialogBase { Q_OBJECT @@ -137,8 +138,19 @@ class KateSessionPanel : public TQVBox void slotSessionRenamed(int sessionId); void slotLVSessionRenamed(TQListViewItem *item); - private: + protected: void setup_toolbar(); + + /* In case the current session is still volatile, asks the user whether + he wants to save or discard the session. + Returns one of the following: + - KMessageBox::Cancel : the user wants to abort the current operation + - KMessageBox::No : the user wants to discard the session and continue + - KMessageBox::Yes : the user wants to save the session and continue + In case the user decides to save the session, the function also sets + the new session name provided in the dialog box. + */ + int handleVolatileSession(); KateMainWindow *m_mainWin; KateViewManager *m_viewManager;