From 6df708028f59b1336b57016d2b483726fc9a7801 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 17 Apr 2020 02:57:56 +1000 Subject: [PATCH] core: reimplemented "open recent" functionality and opening a project from command line --- app/core.cpp | 88 +++++++++++++++++++++++++++++- app/core.h | 30 ++++++++++ app/window/mainwindow/mainmenu.cpp | 45 ++++++++++++--- app/window/mainwindow/mainmenu.h | 15 ++++- 4 files changed, 168 insertions(+), 10 deletions(-) diff --git a/app/core.cpp b/app/core.cpp index 6bd866cc3..b14e4d761 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -31,6 +31,7 @@ #include #include "audio/audiomanager.h" +#include "common/filefunctions.h" #include "common/xmlutils.h" #include "config/config.h" #include "dialog/about/about.h" @@ -123,6 +124,20 @@ void Core::Start() // Load application config Config::Load(); + // Load recently opened projects list + { + QFile recent_projects_file(GetRecentProjectsFilePath()); + if (recent_projects_file.open(QFile::ReadOnly | QFile::Text)) { + QTextStream ts(&recent_projects_file); + + while (!ts.atEnd()) { + recent_projects_.append(ts.readLine()); + } + + recent_projects_file.close(); + } + } + // // Start GUI (FIXME CLI mode) @@ -131,11 +146,20 @@ void Core::Start() StartGUI(parser.isSet(fullscreen_option)); // Load startup project + if (!startup_project_.isEmpty() && !QFileInfo::exists(startup_project_)) { + QMessageBox::warning(main_window(), + tr("Failed to open startup file"), + tr("The project \"%1\" doesn't exist. A new project will be started instead.").arg(startup_project_), + QMessageBox::Ok); + + startup_project_.clear(); + } + if (startup_project_.isEmpty()) { // If no load project is set, create a new one on open AddOpenProject(std::make_shared()); } else { - + OpenProjectInternal(startup_project_); } } @@ -144,6 +168,20 @@ void Core::Stop() // Save Config //Config::Save(); + // Save recently opened projects + { + QFile recent_projects_file(GetRecentProjectsFilePath()); + if (recent_projects_file.open(QFile::WriteOnly | QFile::Text)) { + QTextStream ts(&recent_projects_file); + + foreach (const QString& s, recent_projects_) { + ts << s << "\n"; + } + + recent_projects_file.close(); + } + } + MenuShared::DestroyInstance(); TaskManager::DestroyInstance(); @@ -209,11 +247,21 @@ void Core::SetSelectedAddableObject(const Tool::AddableObject &obj) addable_object_ = obj; } +void Core::ClearOpenRecentList() +{ + recent_projects_.clear(); +} + const bool &Core::snapping() const { return snapping_; } +const QStringList &Core::GetRecentProjects() const +{ + return recent_projects_; +} + void Core::SetTool(const Tool::Item &tool) { tool_ = tool; @@ -360,6 +408,8 @@ void Core::AddOpenProject(ProjectPtr p) { open_projects_.append(p); + PushRecentlyOpenedProject(p->filename()); + emit ProjectOpened(p.get()); } @@ -468,6 +518,8 @@ void Core::SaveAutorecovery() void Core::ProjectSaveSucceeded() { + PushRecentlyOpenedProject(GetActiveProject()->filename()); + SetProjectModified(false); } @@ -665,6 +717,26 @@ QString Core::GetProjectFilter() return QStringLiteral("%1 (*.ove)").arg(tr("Olive Project")); } +QString Core::GetRecentProjectsFilePath() +{ + return QDir(GetConfigurationLocation()).filePath(QStringLiteral("recent")); +} + +void Core::PushRecentlyOpenedProject(const QString& s) +{ + if (s.isEmpty()) { + return; + } + + int existing_index = recent_projects_.indexOf(s); + + if (existing_index >= 0) { + recent_projects_.move(existing_index, 0); + } else { + recent_projects_.prepend(s); + } +} + void Core::OpenProjectInternal(const QString &filename) { ProjectLoadManager* plm = new ProjectLoadManager(filename); @@ -732,6 +804,20 @@ SequencePtr Core::CreateNewSequenceForProject(Project* project) const return new_sequence; } +void Core::OpenProjectFromRecentList(int index) +{ + const QString& open_fn = recent_projects_.at(index); + + if (QFileInfo::exists(open_fn)) { + OpenProjectInternal(open_fn); + } else if (QMessageBox::information(main_window(), + tr("Cannot open recent project"), + tr("The project \"%1\" doesn't exist. Would you like to remove this file from the recent list?").arg(open_fn), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + recent_projects_.removeAt(index); + } +} + void Core::OpenProject() { QString file = QFileDialog::getOpenFileName(main_window_, diff --git a/app/core.h b/app/core.h index b3cc766d7..2725682a2 100644 --- a/app/core.h +++ b/app/core.h @@ -119,6 +119,11 @@ public: */ const bool& snapping() const; + /** + * @brief Returns a list of the most recently opened/saved projects + */ + const QStringList& GetRecentProjects() const; + /** * @brief Get the currently active project * @@ -206,6 +211,11 @@ public: */ SequencePtr CreateNewSequenceForProject(Project *project) const; + /** + * @brief Opens a project from the recently opened list + */ + void OpenProjectFromRecentList(int index); + public slots: /** * @brief Starts an open file dialog to load a project from file @@ -276,6 +286,11 @@ public slots: */ void SetSelectedAddableObject(const Tool::AddableObject& obj); + /** + * @brief Clears the list of recently opened/saved projects + */ + void ClearOpenRecentList(); + signals: /** * @brief Signal emitted when a project is opened @@ -307,6 +322,16 @@ private: */ static QString GetProjectFilter(); + /** + * @brief Returns the filename where the recently opened/saved projects should be stored + */ + static QString GetRecentProjectsFilePath(); + + /** + * @brief Adds a filename to the top of the recently opened projects list (or moves it if it already exists) + */ + void PushRecentlyOpenedProject(const QString &s); + /** * @brief Internal project open */ @@ -384,6 +409,11 @@ private: */ UndoStack undo_stack_; + /** + * @brief List of most recently opened/saved projects + */ + QStringList recent_projects_; + /** * @brief Static singleton core instance */ diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp index 28c324e1f..4a07bed58 100644 --- a/app/window/mainwindow/mainmenu.cpp +++ b/app/window/mainwindow/mainmenu.cpp @@ -47,8 +47,10 @@ MainMenu::MainMenu(MainWindow *parent) : file_new_menu_ = new Menu(file_menu_); MenuShared::instance()->AddItemsForNewMenu(file_new_menu_); file_open_item_ = file_menu_->AddItem("openproj", Core::instance(), &Core::OpenProject, "Ctrl+O"); - file_open_recent_menu_ = new Menu(file_menu_); - file_open_recent_clear_item_ = file_open_recent_menu_->AddItem("clearopenrecent", this, &MainMenu::ClearOpenRecentTriggered); + file_open_recent_menu_ = new Menu(file_menu_, this, &MainMenu::PopulateOpenRecent); + connect(file_open_recent_menu_, &Menu::aboutToHide, this, &MainMenu::CloseOpenRecentMenu); + file_open_recent_separator_ = file_open_recent_menu_->addSeparator(); + file_open_recent_clear_item_ = file_open_recent_menu_->AddItem("clearopenrecent", Core::instance(), &Core::ClearOpenRecentList); file_save_item_ = file_menu_->AddItem("saveproj", Core::instance(), &Core::SaveActiveProject, "Ctrl+S"); file_save_as_item_ = file_menu_->AddItem("saveprojas", Core::instance(), &Core::SaveActiveProjectAs, "Ctrl+Shift+S"); file_menu_->addSeparator(); @@ -356,6 +358,35 @@ void MainMenu::WindowMenuAboutToHide() } } +void MainMenu::PopulateOpenRecent() +{ + if (Core::instance()->GetRecentProjects().isEmpty()) { + + // Insert dummy/disabled action to show there's nothing + QAction* a = new QAction(tr("(None)")); + a->setEnabled(false); + file_open_recent_menu_->insertAction(file_open_recent_separator_, a); + + } else { + + // Populate menu with recently opened projects + for (int i=0;iGetRecentProjects().size();i++) { + QAction* a = new QAction(Core::instance()->GetRecentProjects().at(i)); + a->setData(i); + connect(a, &QAction::triggered, this, &MainMenu::OpenRecentItemTriggered); + file_open_recent_menu_->insertAction(file_open_recent_separator_, a); + } + + } +} + +void MainMenu::CloseOpenRecentMenu() +{ + while (file_open_recent_menu_->actions().first() != file_open_recent_separator_) { + file_open_recent_menu_->removeAction(file_open_recent_menu_->actions().first()); + } +} + void MainMenu::ZoomInTriggered() { PanelManager::instance()->CurrentlyFocused()->ZoomIn(); @@ -498,11 +529,6 @@ void MainMenu::ToggleShowAllTriggered() PanelManager::instance()->CurrentlyFocused()->ToggleShowAll(); } -void MainMenu::ClearOpenRecentTriggered() -{ - qDebug() << "FIXME: Stub"; -} - void MainMenu::DeleteInOutTriggered() { PanelManager::instance()->CurrentlyFocused()->DeleteInToOut(); @@ -528,6 +554,11 @@ void MainMenu::DebugLogTriggered() qDebug() << "FIXME: Stub"; } +void MainMenu::OpenRecentItemTriggered() +{ + Core::instance()->OpenProjectFromRecentList(static_cast(sender())->data().toInt()); +} + void MainMenu::Retranslate() { // MenuShared is not a QWidget and therefore does not receive a LanguageEvent, we use MainMenu's to update it diff --git a/app/window/mainwindow/mainmenu.h b/app/window/mainwindow/mainmenu.h index 12dce9069..16bcd952a 100644 --- a/app/window/mainwindow/mainmenu.h +++ b/app/window/mainwindow/mainmenu.h @@ -94,6 +94,16 @@ private slots: */ void WindowMenuAboutToHide(); + /** + * @brief Adds items to open recent menu + */ + void PopulateOpenRecent(); + + /** + * @brief Clears open recent items when menu closes + */ + void CloseOpenRecentMenu(); + /** * @brief Slot for zooming in * @@ -154,8 +164,6 @@ private slots: void ToggleShowAllTriggered(); - void ClearOpenRecentTriggered(); - void DeleteInOutTriggered(); void RippleDeleteInOutTriggered(); @@ -164,6 +172,8 @@ private slots: void DebugLogTriggered(); + void OpenRecentItemTriggered(); + private: /** * @brief Set strings based on the current application language. @@ -174,6 +184,7 @@ private: Menu* file_new_menu_; QAction* file_open_item_; Menu* file_open_recent_menu_; + QAction* file_open_recent_separator_; QAction* file_open_recent_clear_item_; QAction* file_save_item_; QAction* file_save_as_item_;