added saving of splitter state and recent files

Sun, 03 Nov 2019 12:56:42 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Sun, 03 Nov 2019 12:56:42 +0200
changeset 9
8b9780700b5e
parent 8
44679e468ba9
child 10
e249d97c7fe6

added saving of splitter state and recent files

locale/fi.ts file | annotate | diff | comparison | revisions
locale/sv.ts file | annotate | diff | comparison | revisions
src/document.cpp file | annotate | diff | comparison | revisions
src/document.h file | annotate | diff | comparison | revisions
src/mainwindow.cpp file | annotate | diff | comparison | revisions
src/mainwindow.h file | annotate | diff | comparison | revisions
src/mainwindow.ui file | annotate | diff | comparison | revisions
--- a/locale/fi.ts	Sun Nov 03 12:17:41 2019 +0200
+++ b/locale/fi.ts	Sun Nov 03 12:56:42 2019 +0200
@@ -113,32 +113,37 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.ui" line="48"/>
+        <location filename="../src/mainwindow.ui" line="38"/>
+        <source>Recent files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/mainwindow.ui" line="54"/>
         <source>Quit</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.ui" line="53"/>
+        <location filename="../src/mainwindow.ui" line="59"/>
         <source>Open…</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.ui" line="56"/>
+        <location filename="../src/mainwindow.ui" line="62"/>
         <source>Ctrl+O</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.ui" line="61"/>
+        <location filename="../src/mainwindow.ui" line="67"/>
         <source>New</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.ui" line="64"/>
+        <location filename="../src/mainwindow.ui" line="70"/>
         <source>Ctrl+N</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.ui" line="69"/>
+        <location filename="../src/mainwindow.ui" line="75"/>
         <source>Preferences…</source>
         <translation type="unfinished"></translation>
     </message>
@@ -153,13 +158,13 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.cpp" line="58"/>
-        <source>Could not open %1: %2</source>
+        <location filename="../src/mainwindow.cpp" line="65"/>
+        <source>Problem opening file</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.cpp" line="61"/>
-        <source>Problem opening file</source>
+        <location filename="../src/mainwindow.cpp" line="67"/>
+        <source>Could not open %1: %2</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
--- a/locale/sv.ts	Sun Nov 03 12:17:41 2019 +0200
+++ b/locale/sv.ts	Sun Nov 03 12:56:42 2019 +0200
@@ -189,6 +189,10 @@
         <source>Preferences…</source>
         <translation>Inställningar…</translation>
     </message>
+    <message>
+        <source>Recent files</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>SettingsEditor</name>
--- a/src/document.cpp	Sun Nov 03 12:17:41 2019 +0200
+++ b/src/document.cpp	Sun Nov 03 12:56:42 2019 +0200
@@ -9,9 +9,20 @@
 {
 	this->ui.setupUi(this);
 	this->ui.listView->setModel(model);
+	connect(this->ui.splitter, &QSplitter::splitterMoved, this, &Document::splitterChanged);
 }
 
 Document::~Document()
 {
 	delete &this->ui;
 }
+
+QByteArray Document::saveSplitterState() const
+{
+	return this->ui.splitter->saveState();
+}
+
+void Document::restoreSplitterState(const QByteArray& state)
+{
+	this->ui.splitter->restoreState(state);
+}
--- a/src/document.h	Sun Nov 03 12:17:41 2019 +0200
+++ b/src/document.h	Sun Nov 03 12:56:42 2019 +0200
@@ -15,7 +15,10 @@
 public:
 	explicit Document(Model* model, QWidget *parent = nullptr);
 	~Document();
-	
+	QByteArray saveSplitterState() const;
+	void restoreSplitterState(const QByteArray& state);
+signals:
+	void splitterChanged();
 private:
 	Model* model;
 	Ui::Document& ui;
--- a/src/mainwindow.cpp	Sun Nov 03 12:17:41 2019 +0200
+++ b/src/mainwindow.cpp	Sun Nov 03 12:56:42 2019 +0200
@@ -23,6 +23,7 @@
 	connect(ui->actionSettingsEditor, &QAction::triggered, this, &MainWindow::runSettingsEditor);
 	this->updateTitle();
 	this->restoreSettings();
+	this->newModel();
 }
 
 MainWindow::~MainWindow()
@@ -31,8 +32,7 @@
 
 void MainWindow::newModel()
 {
-	documents.newModel();
-	this->updateTabs();
+	this->openModelForEditing(documents.newModel());
 }
 
 void MainWindow::openModel()
@@ -44,22 +44,29 @@
 		tr("LDraw models (*.ldr *.dat)"));
 	if (not path.isEmpty())
 	{
-		QString errorString;
-		QTextStream errorStream{&errorString};
-		QString modelName = this->documents.openModel(path, errorStream);
-		if (not modelName.isEmpty())
-		{
-			Document* document = new Document{this->documents.findModelByName(modelName)};
-			this->ui->tabs->addTab(document, modelName);
-		}
-		else
-		{
-			const QString errorMessage = utility::format(
+		this->openModelFromPath(path);
+	}
+}
+
+void MainWindow::openModelFromPath(const QString& path)
+{
+	QString errorString;
+	QTextStream errorStream{&errorString};
+	QString modelName = this->documents.openModel(path, errorStream);
+	if (not modelName.isEmpty())
+	{
+		this->openModelForEditing(modelName);
+		this->addRecentlyOpenedFile(path);
+	}
+	else
+	{
+		QMessageBox::critical(
+			this,
+			tr("Problem opening file"),
+			utility::format(
 				tr("Could not open %1: %2"),
 				path,
-				errorString);
-			QMessageBox::critical(this, tr("Problem opening file"), errorMessage);
-		}
+				errorString));
 	}
 }
 
@@ -86,6 +93,27 @@
 	}
 }
 
+void MainWindow::addRecentlyOpenedFile(const QString& path)
+{
+	this->recentlyOpenedFiles.removeAll(path);
+	this->recentlyOpenedFiles.insert(0, path);
+	while (this->recentlyOpenedFiles.size() > maxRecentlyOpenedFiles)
+	{
+		this->recentlyOpenedFiles.removeLast();
+	}
+	this->saveSettings();
+	this->updateRecentlyOpenedDocumentsMenu();
+}
+
+void MainWindow::openModelForEditing(const QString& modelName)
+{
+	Document* document = new Document{this->documents.findModelByName(modelName)};
+	this->ui->tabs->addTab(document, modelName);
+	this->ui->tabs->setCurrentWidget(document);
+	document->restoreSplitterState(this->documentSplitterState);
+	connect(document, &Document::splitterChanged, this, &MainWindow::handleDocumentSplitterChange);
+}
+
 void MainWindow::runSettingsEditor()
 {
 	SettingsEditor settingsEditor{&this->settings, this};
@@ -96,6 +124,46 @@
 	}
 }
 
+void MainWindow::handleDocumentSplitterChange()
+{
+	Document* currentDocument = qobject_cast<Document*>(this->ui->tabs->currentWidget());
+	if (currentDocument != nullptr)
+	{
+		this->documentSplitterState = currentDocument->saveSplitterState();
+		for (int i = 0; i < this->ui->tabs->count(); i += 1)
+		{
+			Document* document = qobject_cast<Document*>(this->ui->tabs->widget(i));
+			if (document != nullptr and document != currentDocument)
+			{
+				document->restoreSplitterState(this->documentSplitterState);
+			}
+		}
+		this->settings.setValue("MainWindow/DocumentSplitterState", this->documentSplitterState);
+	}
+}
+
+void MainWindow::updateRecentlyOpenedDocumentsMenu()
+{
+	this->ui->menuRecentFiles->clear();
+	for (const QString& path : this->recentlyOpenedFiles)
+	{
+		QAction* action = new QAction{path, this};
+		action->setData(path);
+		this->ui->menuRecentFiles->addAction(action);
+		connect(action, &QAction::triggered, this, &MainWindow::openRecentFile);
+	}
+}
+
+void MainWindow::openRecentFile()
+{
+	QAction* action = qobject_cast<QAction*>(this->sender());
+	if (action != nullptr)
+	{
+		const QString path = action->data().toString();
+		this->openModelFromPath(path);
+	}
+}
+
 void MainWindow::changeEvent(QEvent* event)
 {
 	if (event != nullptr)
@@ -123,51 +191,6 @@
 }
 
 /**
- * @brief Creates a new tab widget for the specified model.
- * @param model Model to get a new tab widget for
- * @return widget
- */
-QWidget* MainWindow::createWidgetForModel(Model* model)
-{
-	Q_UNUSED(model);
-	QWidget* widget = new QWidget(ui->tabs);
-	QLabel* label = new QLabel("asdf", widget);
-	QVBoxLayout* layout = new QVBoxLayout;
-	layout->addWidget(label);
-	widget->setLayout(layout);
-	return widget;
-}
-
-/**
- * @brief Gets a tab widget for the specified model. If it does not exist,
- * it will be created.
- * @param model Model to get a tab widget for
- * @return widget
- */
-QWidget* MainWindow::getWidgetForModel(Model* model)
-{
-	QWidget* widget = this->modelWidgets.value(model);
-	if (widget == nullptr)
-	{
-		QWidget* const new_widget = createWidgetForModel(model);
-		this->modelWidgets[model] = new_widget;
-		return new_widget;
-	}
-	else
-	{
-		return widget;
-	}
-}
-
-/**
- * @brief Updates the tab widget
- */
-void MainWindow::updateTabs()
-{
-
-}
-
-/**
  * @brief Updates the title of the main window so to contain the app's name
  * and version as well as the open document name.
  */
@@ -184,7 +207,9 @@
  */
 void MainWindow::saveSettings()
 {
-	this->settings.setValue("mainwindow/geometry", this->saveGeometry());
+	this->settings.setValue("MainWindow/Geometry", this->saveGeometry());
+	this->settings.setValue("MainWindow/RecentlyOpened", this->recentlyOpenedFiles);
+	this->settings.setValue("MainWindow/DocumentSplitterState", this->documentSplitterState);
 	this->libraries.storeToSettings(&this->settings);
 }
 
@@ -193,11 +218,14 @@
  */
 void MainWindow::restoreSettings()
 {
-	this->restoreGeometry(this->settings.value("mainwindow/geometry").toByteArray());
+	this->restoreGeometry(this->settings.value("MainWindow/Geometry").toByteArray());
+	this->recentlyOpenedFiles = this->settings.value("MainWindow/RecentlyOpened").toStringList();
+	this->documentSplitterState = this->settings.value("MainWindow/DocumentSplitterState").toByteArray();
 	const QString systemLocale = QLocale::system().name();
 	const QVariant defaultLocale = this->settings.value("locale", systemLocale);
 	changeLanguage(defaultLocale.toString());
 	this->libraries.restoreFromSettings(&this->settings);
+	this->updateRecentlyOpenedDocumentsMenu();
 }
 
 QString MainWindow::pathToTranslation(const QString& localeCode)
--- a/src/mainwindow.h	Sun Nov 03 12:17:41 2019 +0200
+++ b/src/mainwindow.h	Sun Nov 03 12:56:42 2019 +0200
@@ -16,7 +16,11 @@
 private slots:
 	void newModel();
 	void openModel();
+	void openModelFromPath(const QString& path);
 	void runSettingsEditor();
+	void handleDocumentSplitterChange();
+	void updateRecentlyOpenedDocumentsMenu();
+	void openRecentFile();
 protected:
 	void changeEvent(QEvent* event) override;
 	void closeEvent(QCloseEvent* event) override;
@@ -28,12 +32,14 @@
 	QTranslator translator;
 	QSettings settings;
 	LibraryManager libraries;
-	QWidget* createWidgetForModel(Model* model);
-	QWidget* getWidgetForModel(Model* model);
-	void updateTabs();
+	QByteArray documentSplitterState;
+	static constexpr int maxRecentlyOpenedFiles = 10;
+	QStringList recentlyOpenedFiles;
 	void updateTitle();
 	void saveSettings();
 	void restoreSettings();
 	void changeLanguage(QString localeCode);
+	void addRecentlyOpenedFile(const QString& path);
+	void openModelForEditing(const QString& modelName);
 	static QString pathToTranslation(const QString& localeCode);
 };
--- a/src/mainwindow.ui	Sun Nov 03 12:17:41 2019 +0200
+++ b/src/mainwindow.ui	Sun Nov 03 12:56:42 2019 +0200
@@ -33,8 +33,14 @@
     <property name="title">
      <string>File</string>
     </property>
+    <widget class="QMenu" name="menuRecentFiles">
+     <property name="title">
+      <string>Recent files</string>
+     </property>
+    </widget>
     <addaction name="actionNew"/>
     <addaction name="actionOpen"/>
+    <addaction name="menuRecentFiles"/>
     <addaction name="separator"/>
     <addaction name="actionSettingsEditor"/>
     <addaction name="separator"/>

mercurial