diff --git a/src/blackgui/menus/menuaction.h b/src/blackgui/menus/menuaction.h index 7d55e2e8d..535b963e3 100644 --- a/src/blackgui/menus/menuaction.h +++ b/src/blackgui/menus/menuaction.h @@ -176,6 +176,9 @@ namespace BlackGui //! View load/save static const QString &pathViewLoadSave() { static const QString p("View.18.LoadSave"); return p; } + //! View cut and paste + static const QString &pathViewCutPaste() { static const QString p("View.18.CutPaste"); return p; } + // ---- nested dock widgets ---- //! Nested dock widget diff --git a/src/blackgui/views/viewbase.cpp b/src/blackgui/views/viewbase.cpp index 746e05cfe..5dc597a67 100644 --- a/src/blackgui/views/viewbase.cpp +++ b/src/blackgui/views/viewbase.cpp @@ -63,7 +63,9 @@ #include "blackmisc/weather/windlayerlist.h" #include "blackmisc/worker.h" +#include #include +#include #include #include #include @@ -266,13 +268,35 @@ namespace BlackGui case MenuClear: { ma.addAction(BlackMisc::CIcons::delete16(), "Clear", CMenuAction::pathViewAddRemove(), { this, &CViewBaseNonTemplate::ps_clear }); break; } case MenuFilter: { - ma.addAction(CIcons::filter16(), "Filter", CMenuAction::pathViewFilter(), { this, &CViewBaseNonTemplate::ps_displayFilterDialog }, CShortcut::keyDisplayFilter()); - ma.addAction(CIcons::filter16(), "Remove Filter", CMenuAction::pathViewFilter(), { this, &CViewBaseNonTemplate::ps_removeFilter }); + if (m_filterWidget) + { + const bool dialog = qobject_cast(m_filterWidget); + if (dialog) ma.addAction(CIcons::filter16(), "Show filter", CMenuAction::pathViewFilter(), { this, &CViewBaseNonTemplate::ps_displayFilterDialog }, CShortcut::keyDisplayFilter()); + ma.addAction(CIcons::filter16(), "Remove Filter", CMenuAction::pathViewFilter(), { this, &CViewBaseNonTemplate::ps_removeFilter }); + } break; } case MenuMaterializeFilter: { ma.addAction(CIcons::tableRelationship16(), "Materialize filtered data", CMenuAction::pathViewFilter(), { this, &CViewBaseNonTemplate::materializeFilter }); break; } case MenuLoad: { ma.addAction(CIcons::disk16(), "Load from file", CMenuAction::pathViewLoadSave(), { this, &CViewBaseNonTemplate::ps_loadJsonAction }); break; } case MenuSave: { ma.addAction(CIcons::disk16(), "Save data in file", CMenuAction::pathViewLoadSave(), { this, &CViewBaseNonTemplate::ps_saveJsonAction }, CShortcut::keySaveViews()); break; } + case MenuCut: + { + if (!QApplication::clipboard()) break; + ma.addAction(CIcons::cut16(), "Cut", CMenuAction::pathViewCutPaste(), { this, &CViewBaseNonTemplate::ps_cut }, QKeySequence(QKeySequence::Paste)); + break; + } + case MenuPaste: + { + if (!QApplication::clipboard()) break; + ma.addAction(CIcons::paste16(), "Paste", CMenuAction::pathViewCutPaste(), { this, &CViewBaseNonTemplate::ps_paste }, QKeySequence(QKeySequence::Paste)); + break; + } + case MenuCopy: + { + if (!QApplication::clipboard()) break; + ma.addAction(CIcons::copy16(), "Copy", CMenuAction::pathViewCutPaste(), { this, &CViewBaseNonTemplate::ps_copy }, QKeySequence(QKeySequence::Copy)); + break; + } default: break; } @@ -321,7 +345,12 @@ namespace BlackGui menuActions.addActions(this->initMenuActions(MenuRemoveSelectedRows)); } } - if (this->m_menus.testFlag(MenuFilter)) + + if (this->m_menus.testFlag(MenuCopy)) { menuActions.addActions(this->initMenuActions(MenuCopy)); } + if (this->m_menus.testFlag(MenuCut)) { menuActions.addActions(this->initMenuActions(MenuCut)); } + if (this->m_menus.testFlag(MenuPaste)) { menuActions.addActions(this->initMenuActions(MenuPaste)); } + + if (this->m_menus.testFlag(MenuFilter) && m_filterWidget) { menuActions.addActions(this->initMenuActions(MenuFilter)); if (this->m_menus.testFlag(MenuMaterializeFilter)) @@ -1417,6 +1446,49 @@ namespace BlackGui } } + template + void CViewBase::ps_copy() + { + QClipboard *clipboard = QApplication::clipboard(); + if (!clipboard) { return; } + if (!this->hasSelection()) { return; } + const ContainerType selection = this->selectedObjects(); + if (selection.isEmpty()) { return; } + const QString json = selection.toJsonString(); + clipboard->setText(json); + } + + template + void CViewBase::ps_cut() + { + if (!QApplication::clipboard()) { return; } + this->ps_copy(); + this->removeSelectedRows(); + } + + template + void CViewBase::ps_paste() + { + const QClipboard *clipboard = QApplication::clipboard(); + if (!clipboard) { return; } + const QString json = clipboard->text(); + if (json.isEmpty()) { return; } + if (!Json::looksLikeSwiftJson(json)) { return; } // no JSON + try + { + ContainerType objects; + objects.convertFromJson(json); + if (!objects.isEmpty()) + { + this->insert(objects); + } + } + catch (const CJsonException &ex) + { + Q_UNUSED(ex); + } + } + template bool CViewBase::ps_filterDialogFinished(int status) { diff --git a/src/blackgui/views/viewbase.h b/src/blackgui/views/viewbase.h index 66b9a50b9..3eef2b717 100644 --- a/src/blackgui/views/viewbase.h +++ b/src/blackgui/views/viewbase.h @@ -112,6 +112,9 @@ namespace BlackGui MenuLoad = 1 << 8, //!< load from JSON MenuToggleSelectionMode = 1 << 9, //!< allow to toggle selection mode MenuOrderable = 1 << 10, //!< items can be ordered (if container is BlackMisc::IOrderableList + MenuCopy = 1 << 11, //!< copy (for copy/paste) + MenuPaste = 1 << 12, //!< paste (for copy/paste) + MenuCut = 1 << 13, //!< cut (for copy/paste) MenuStandard = MenuClear | MenuRemoveSelectedRows | MenuRefresh | MenuBackend | MenuDisplayAutomatically | MenuFilter | MenuSave | MenuLoad | MenuToggleSelectionMode, MenuLoadAndSave = MenuLoad | MenuSave, @@ -120,8 +123,8 @@ namespace BlackGui MenuDefaultDbViews = MenuToggleSelectionMode | MenuBackend, // special menus, should be in derived classes, but enums cannot be inherited // maybe shifted in the future to elsewhere - MenuHighlightStashed = 1 << 11, //!< highlight stashed models - MenuCanStashModels = 1 << 12, //!< stash models + MenuHighlightStashed = 1 << 14, //!< highlight stashed models + MenuCanStashModels = 1 << 15, //!< stash models MenuStashing = MenuHighlightStashed | MenuCanStashModels, }; Q_DECLARE_FLAGS(Menu, MenuFlag) @@ -469,6 +472,15 @@ namespace BlackGui //! Hide load indicator (no parameters) void ps_hideLoadIndicator(); + //! Copy + virtual void ps_copy() = 0; + + //! Cut + virtual void ps_cut() = 0; + + //! Paste + virtual void ps_paste() = 0; + // ------------ slots of CViewDbObjects ---------------- // need to be declared here and overridden, as this is the only part with valid Q_OBJECT @@ -685,6 +697,9 @@ namespace BlackGui virtual void ps_rowSelected(const QModelIndex &index) override; virtual BlackMisc::CStatusMessage ps_loadJson() override; virtual BlackMisc::CStatusMessage ps_saveJson() const override; + virtual void ps_copy() override; + virtual void ps_cut() override; + virtual void ps_paste() override; //! @} }; } // namespace