diff --git a/app/core.cpp b/app/core.cpp index d568c2a13..3240d712f 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -137,55 +137,43 @@ void Core::StartImportFootage() if (active_project_panel == nullptr // Check that we found a Project panel || (active_project = active_project_panel->project()) == nullptr) { // and that we could find an active Project - QMessageBox::critical(main_window_, tr("Import footage"), tr("Failed to find active Project panel")); + QMessageBox::critical(main_window_, tr("Failed to import footage"), tr("Failed to find active Project panel")); return; } - Folder* folder = nullptr; - - // Get the selected items from the panel - QList selected_items = active_project_panel->SelectedItems(); - - // Heuristic for finding the selected folder: - // - // - If `folder` is nullptr, we set the first folder we find. Either the item itself if it's a folder, or the - // item's parent. - // - Otherwise, if all folders found are the same, we'll use that to import into. - // - If more than one folder is found, we play it safe and import into the root folder - - for (int i=0;itype() != Item::kFolder) { - sel_item = sel_item->parent(); - - Q_ASSERT(sel_item->type() == Item::kFolder); - } - - if (folder == nullptr) { - // If the folder is nullptr, cache it as this folder - folder = static_cast(sel_item); - } else if (folder != sel_item) { - // If not, we've already cached a folder so we check if it's the same - // If it isn't, we "play it safe" and use the root folder - folder = nullptr; - break; - } - } - - // If we didn't pick up a folder from the heuristic above for whatever reason, use root - if (folder == nullptr) { - folder = active_project->root(); - } + // Get the selected folder in this panel + Folder* folder = active_project_panel->GetSelectedFolder(); ImportFiles(files, folder); } } +void Core::CreateNewFolder() +{ + // Locate the most recently focused Project panel (assume that's the panel the user wants to import into) + ProjectPanel* active_project_panel = olive::panel_focus_manager->MostRecentlyFocused(); + Project* active_project; + + if (active_project_panel == nullptr // Check that we found a Project panel + || (active_project = active_project_panel->project()) == nullptr) { // and that we could find an active Project + QMessageBox::critical(main_window_, tr("Failed to create new folder"), tr("Failed to find active Project panel")); + return; + } + + // Get the selected folder in this panel + Folder* folder = active_project_panel->GetSelectedFolder(); + + Folder* new_folder = new Folder(); + + new_folder->set_name(tr("New Folder")); + + active_project_panel->model()->AddChild(folder, new_folder); +} + void Core::AddOpenProject(ProjectPtr p) { open_projects_.append(p); + emit ProjectOpened(p.get()); } @@ -227,3 +215,17 @@ void Core::StartGUI(bool full_screen) } + +Project *Core::GetActiveProject() +{ + // Locate the most recently focused Project panel (assume that's the panel the user wants to import into) + ProjectPanel* active_project_panel = olive::panel_focus_manager->MostRecentlyFocused(); + + // If we couldn't find one, return nullptr + if (active_project_panel == nullptr) { + return nullptr; + } + + // Otherwise, return the project panel's project (which may be nullptr but in most cases shouldn't be) + return active_project_panel->project(); +} diff --git a/app/core.h b/app/core.h index 5a7905b56..4f4a5caa6 100644 --- a/app/core.h +++ b/app/core.h @@ -32,6 +32,9 @@ * * The main Olive application instance. This runs both in GUI and CLI modes (and handles what to init based on that). * It also contains various global functions/variables for use throughout Olive. + * + * The "public slots" are usually user-triggered actions and can be connected to UI elements (e.g. creating a folder, + * opening the import dialog, etc.) */ class Core : public QObject { @@ -92,6 +95,11 @@ public slots: */ void StartImportFootage(); + /** + * @brief Create a new folder in the currently active project + */ + void CreateNewFolder(); + signals: /** * @brief Signal emitted when a project is opened @@ -131,6 +139,18 @@ private: */ void StartGUI(bool full_screen); + /** + * @brief Get the currently active project + * + * Uses the UI/Panel system to determine which Project was the last focused on and assumes this is the active Project + * that the user wishes to work on. + * + * @return + * + * The active Project file, or nullptr if the heuristic couldn't find one. + */ + Project* GetActiveProject(); + /** * @brief Internal main window object */ diff --git a/app/panel/project/project.cpp b/app/panel/project/project.cpp index 5bc226cd3..f75bb8d1e 100644 --- a/app/panel/project/project.cpp +++ b/app/panel/project/project.cpp @@ -74,6 +74,16 @@ QList ProjectPanel::SelectedItems() return explorer_->SelectedItems(); } +Folder *ProjectPanel::GetSelectedFolder() +{ + return explorer_->GetSelectedFolder(); +} + +ProjectViewModel *ProjectPanel::model() +{ + return explorer_->model(); +} + void ProjectPanel::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { diff --git a/app/panel/project/project.h b/app/panel/project/project.h index 195d8ed59..c99dc4151 100644 --- a/app/panel/project/project.h +++ b/app/panel/project/project.h @@ -36,6 +36,10 @@ public: QList SelectedItems(); + Folder* GetSelectedFolder(); + + ProjectViewModel* model(); + protected: virtual void changeEvent(QEvent* e) override; diff --git a/app/project/item/item.cpp b/app/project/item/item.cpp index 0d9c9d446..11f87a683 100644 --- a/app/project/item/item.cpp +++ b/app/project/item/item.cpp @@ -39,6 +39,10 @@ void Item::add_child(Item* c) return; } + if (c->parent_ != nullptr) { + c->parent_->remove_child(c); + } + children_.append(c); c->parent_ = this; } diff --git a/app/project/projectviewmodel.cpp b/app/project/projectviewmodel.cpp index 4b0ee80d1..d46425162 100644 --- a/app/project/projectviewmodel.cpp +++ b/app/project/projectviewmodel.cpp @@ -376,6 +376,21 @@ bool ProjectViewModel::dropMimeData(const QMimeData *data, Qt::DropAction action return false; } +void ProjectViewModel::AddChild(Item *parent, Item *child) +{ + QModelIndex parent_index; + + if (parent != project_->root()) { + parent_index = CreateIndexFromItem(parent); + } + + beginInsertRows(parent_index, parent->child_count(), parent->child_count()); + + parent->add_child(child); + + endInsertRows(); +} + int ProjectViewModel::IndexOfChild(Item *item) const { // Find parent's index within its own parent diff --git a/app/project/projectviewmodel.h b/app/project/projectviewmodel.h index 019b2af50..06e4008f9 100644 --- a/app/project/projectviewmodel.h +++ b/app/project/projectviewmodel.h @@ -91,6 +91,9 @@ public: virtual QStringList mimeTypes() const override; virtual QMimeData * mimeData(const QModelIndexList &indexes) const override; virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; + + /** Other model functions */ + void AddChild(Item* parent, Item* child); private: /** * @brief Retrieve the index of `item` in its parent diff --git a/app/widget/menu/menushared.cpp b/app/widget/menu/menushared.cpp index b0e25de02..6354adb59 100644 --- a/app/widget/menu/menushared.cpp +++ b/app/widget/menu/menushared.cpp @@ -20,6 +20,8 @@ #include "menushared.h" +#include "core.h" + MenuShared olive::menu_shared; MenuShared::MenuShared() @@ -31,7 +33,7 @@ void MenuShared::Initialize() // "New" menu shared items new_project_item_ = Menu::CreateItem(this, "newproj", nullptr, nullptr, "Ctrl+N"); new_sequence_item_ = Menu::CreateItem(this, "newseq", nullptr, nullptr, "Ctrl+Shift+N"); - new_folder_item_ = Menu::CreateItem(this, "newfolder", nullptr, nullptr); + new_folder_item_ = Menu::CreateItem(this, "newfolder", &olive::core, SLOT(CreateNewFolder())); // "Edit" menu shared items edit_cut_item_ = Menu::CreateItem(this, "cut", nullptr, nullptr, "Ctrl+X"); diff --git a/app/widget/projectexplorer/projectexplorer.cpp b/app/widget/projectexplorer/projectexplorer.cpp index 5b186c9bf..1cb9089f9 100644 --- a/app/widget/projectexplorer/projectexplorer.cpp +++ b/app/widget/projectexplorer/projectexplorer.cpp @@ -200,3 +200,55 @@ QList ProjectExplorer::SelectedItems() return selected_items; } + +Folder *ProjectExplorer::GetSelectedFolder() +{ + if (project() == nullptr) { + return nullptr; + } + + Folder* folder = nullptr; + + // Get the selected items from the panel + QList selected_items = SelectedItems(); + + // Heuristic for finding the selected folder: + // + // - If `folder` is nullptr, we set the first folder we find. Either the item itself if it's a folder, or the + // item's parent. + // - Otherwise, if all folders found are the same, we'll use that to import into. + // - If more than one folder is found, we play it safe and import into the root folder + + for (int i=0;itype() != Item::kFolder) { + sel_item = sel_item->parent(); + + Q_ASSERT(sel_item->type() == Item::kFolder); + } + + if (folder == nullptr) { + // If the folder is nullptr, cache it as this folder + folder = static_cast(sel_item); + } else if (folder != sel_item) { + // If not, we've already cached a folder so we check if it's the same + // If it isn't, we "play it safe" and use the root folder + folder = nullptr; + break; + } + } + + // If we didn't pick up a folder from the heuristic above for whatever reason, use root + if (folder == nullptr) { + folder = project()->root(); + } + + return folder; +} + +ProjectViewModel *ProjectExplorer::model() +{ + return &model_; +} diff --git a/app/widget/projectexplorer/projectexplorer.h b/app/widget/projectexplorer/projectexplorer.h index e5121f73f..5f9b749ad 100644 --- a/app/widget/projectexplorer/projectexplorer.h +++ b/app/widget/projectexplorer/projectexplorer.h @@ -55,6 +55,25 @@ public: QList SelectedItems(); + /** + * @brief Use a heuristic to determine which (if any) folder is selected + * + * Generally for some import/adding processes, we assume that if a folder is selected, the user probably wants to + * create the new object in it rather than in the root. If, however, more than one folder is selected, we can't + * truly determine any folder from this and just return the root instead. + * + * @return + * + * A folder that's heuristically been determined as "selected", or the root directory if none, or nullptr if no + * project is open. + */ + Folder* GetSelectedFolder(); + + /** + * @brief Access the ViewModel model of the project + */ + ProjectViewModel* model(); + public slots: void set_view_type(olive::ProjectViewType type);