diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 9e00b7d1a..491e70a88 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -143,6 +143,16 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() minWidth->setDefaultValue (325); minWidth->setRange (50, 10000); minWidth->setToolTip ("Minimum width of subviews."); + + Setting *saveState = createSetting (Type_CheckBox, "save-state", "Save window size and position"); + saveState->setDefaultValue ("true"); + saveState->setToolTip ("Remember window size and position between editing sessions."); + + Setting *saveX = createSetting (Type_CheckBox, "x-save-state-workaround", "X windows workaround"); + saveX->setDefaultValue ("false"); + saveX->setToolTip ("Some X window managers don't remember the windows state before being" + " maximized. In such environments exiting while maximized will correctly start in a maximized" + " window, but restoring back to the normal size won't work. Try this workaround."); } declareSection ("records", "Records"); @@ -458,6 +468,21 @@ QString CSMSettings::UserSettings::setting(const QString &viewKey, const QString return QString(); } +QVariant CSMSettings::UserSettings::value(const QString &viewKey, const QVariant &value) +{ + if(value != QVariant()) + { + mSettingDefinitions->setValue (viewKey, value); + return value; + } + else if(mSettingDefinitions->contains(viewKey)) + { + return mSettingDefinitions->value (viewKey); + } + + return QVariant(); +} + bool CSMSettings::UserSettings::hasSettingDefinitions (const QString &viewKey) const { return (mSettingDefinitions->contains (viewKey)); diff --git a/apps/opencs/model/settings/usersettings.hpp b/apps/opencs/model/settings/usersettings.hpp index 5188a9842..c4c5ea583 100644 --- a/apps/opencs/model/settings/usersettings.hpp +++ b/apps/opencs/model/settings/usersettings.hpp @@ -82,6 +82,8 @@ namespace CSMSettings { QString setting(const QString &viewKey, const QString &value = QString()); + QVariant value(const QString &viewKey, const QVariant &value = QVariant()); + private: void buildSettingModelDefaults(); diff --git a/apps/opencs/view/doc/operations.cpp b/apps/opencs/view/doc/operations.cpp index 7ee4b8726..934c94a96 100644 --- a/apps/opencs/view/doc/operations.cpp +++ b/apps/opencs/view/doc/operations.cpp @@ -19,6 +19,7 @@ CSVDoc::Operations::Operations() setVisible (false); setFixedHeight (widgetContainer->height()); setTitleBarWidget (new QWidget (this)); + setObjectName (QString("operations")); // needed to suppress warning while saving window state } void CSVDoc::Operations::setProgress (int current, int max, int type, int threads) diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index df1e7ee49..230812eb0 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -8,6 +8,8 @@ CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) /// \todo add a button to the title bar that clones this sub view setWindowTitle (QString::fromUtf8 (mUniversalId.toString().c_str())); + // set object name to suppress warning while saving window state + setObjectName (QString::fromUtf8 (mUniversalId.toString().c_str())); setAttribute(Qt::WA_DeleteOnClose); } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 5636fff94..02852ab52 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -32,6 +32,23 @@ void CSVDoc::View::closeEvent (QCloseEvent *event) event->ignore(); else { + if (mSaveWindowState) + { + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + if (isMaximized() && mXWorkaround) + { + userSettings.setDefinitions("window/maximized", (QStringList() << "true")); + userSettings.saveDefinitions(); // store previously saved geometry & state + } + else + { + userSettings.value("window/geometry", saveGeometry()); + userSettings.value("window/state", saveState()); + userSettings.setDefinitions("window/maximized", (QStringList() << "false")); + userSettings.saveDefinitions(); + } + } + // closeRequest() returns true if last document mViewManager.removeDocAndView(mDocument); } @@ -381,22 +398,35 @@ void CSVDoc::View::updateActions() CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), - mViewTotal (totalViews) + mViewTotal (totalViews), mSaveWindowState(false), mXWorkaround(false) { - int width = CSMSettings::UserSettings::instance().settingValue - ("window/default-width").toInt(); + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + mXWorkaround = userSettings.settingValue ("window/x-save-state-workaround").toStdString() == "true"; + mSaveWindowState = userSettings.setting ("window/save-state", "true").toStdString() == "true"; - int height = CSMSettings::UserSettings::instance().settingValue - ("window/default-height").toInt(); + // check if saved state should be used and whether it is the first time + if (mSaveWindowState && userSettings.hasSettingDefinitions ("window/maximized")) + { + restoreGeometry(userSettings.value("window/geometry").toByteArray()); + restoreState(userSettings.value("window/state").toByteArray()); - width = std::max(width, 300); - height = std::max(height, 300); + if (mXWorkaround && userSettings.settingValue ("window/maximized").toStdString() == "true") + setWindowState(windowState() | Qt::WindowMaximized); + } + else + { + int width = userSettings.settingValue ("window/default-width").toInt(); + int height = userSettings.settingValue ("window/default-height").toInt(); - // trick to get the window decorations and their sizes - show(); - hide(); - resize (width - (frameGeometry().width() - geometry().width()), - height - (frameGeometry().height() - geometry().height())); + width = std::max(width, 300); + height = std::max(height, 300); + + // trick to get the window decorations and their sizes + show(); + hide(); + resize (width - (frameGeometry().width() - geometry().width()), + height - (frameGeometry().height() - geometry().height())); + } mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); @@ -770,6 +800,12 @@ void CSVDoc::View::updateUserSetting (const QString &name, const QStringList &li if (name=="window/hide-subview") updateSubViewIndicies (0); + if (name == "window/save-state") + mSaveWindowState = list.at(0) == "true"; + + if (name == "window/x-save-state-workaround") + mXWorkaround = list.at(0) == "true"; + foreach (SubView *subView, mSubViews) { subView->updateUserSetting (name, list); @@ -815,3 +851,33 @@ void CSVDoc::View::closeRequest (SubView *subView) else if (mViewManager.closeRequest (this)) mViewManager.removeDocAndView (mDocument); } + +// for more reliable detetion of isMaximized(), see https://bugreports.qt.io/browse/QTBUG-30085 +void CSVDoc::View::saveWindowState() +{ + if (!isMaximized()) + { + // update but don't save to config file yet + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + userSettings.value("window/geometry", saveGeometry()); + userSettings.value("window/state", saveState()); + } +} + +// For X11 where Qt does not remember pre-maximised state +void CSVDoc::View::moveEvent (QMoveEvent *event) +{ + if (mXWorkaround && mSaveWindowState) + QMetaObject::invokeMethod(this, "saveWindowState", Qt::QueuedConnection); + + QMainWindow::moveEvent(event); +} + +// For X11 where Qt does not remember pre-maximised state +void CSVDoc::View::resizeEvent (QResizeEvent *event) +{ + if (mXWorkaround && mSaveWindowState) + QMetaObject::invokeMethod(this, "saveWindowState", Qt::QueuedConnection); + + QMainWindow::resizeEvent(event); +} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 32d7159c2..398f4fa67 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -48,6 +48,9 @@ namespace CSVDoc QMainWindow mSubViewWindow; GlobalDebugProfileMenu *mGlobalDebugProfileMenu; + bool mSaveWindowState; + bool mXWorkaround; + // not implemented View (const View&); @@ -112,6 +115,11 @@ namespace CSVDoc /// Function called by view manager when user preferences are updated void updateEditorSetting (const QString &, const QString &); + protected: + + virtual void moveEvent(QMoveEvent * event); + virtual void resizeEvent(QResizeEvent * event); + signals: void newGameRequest(); @@ -228,6 +236,8 @@ namespace CSVDoc void stop(); void closeRequest (SubView *subView); + + void saveWindowState(); }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 6362f9659..106f147f9 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -405,6 +405,27 @@ bool CSVDoc::ViewManager::removeDocument (CSVDoc::View *view) else remainingViews.push_back(*iter); } + + // FIXME: seems removeDocument() and closeRequest() are duplicated functionality + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + if (remainingViews.empty() && !mViews.empty() && + userSettings.settingValue ("window/save-state").toStdString() == "true") + { + if (userSettings.settingValue ("window/x-save-state-workaround").toStdString() == "true" + && mViews.back()->isMaximized()) + { + userSettings.setDefinitions("window/maximized", (QStringList() << "true")); + userSettings.saveDefinitions(); // store previously saved geometry & state + } + else + { + userSettings.value("window/geometry", mViews.back()->saveGeometry()); + userSettings.value("window/state", mViews.back()->saveState()); + userSettings.setDefinitions("window/maximized", (QStringList() << "false")); + userSettings.saveDefinitions(); + } + } + mDocumentManager.removeDocument(document); mViews = remainingViews; }