From 62a5c9061622fdce7dbaf799c65c90137153f94f Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 22 Aug 2021 18:02:22 -0500 Subject: [PATCH] moving document related code from AtomToolsMainWindow to AtomToolsDocumentMainWindow adding virtual function stubs to customize actions Signed-off-by: Guthrie Adams --- .../Document/AtomToolsDocumentMainWindow.h | 39 +- .../Window/AtomToolsMainWindow.h | 21 +- .../Document/AtomToolsDocumentMainWindow.cpp | 447 ++++++++++++------ .../Source/Window/AtomToolsMainWindow.cpp | 144 +----- 4 files changed, 332 insertions(+), 319 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h index 1c8f9a1f55..6beae2a69c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h @@ -12,6 +12,7 @@ #include #include #include +#include #endif namespace AtomToolsFramework @@ -30,7 +31,35 @@ namespace AtomToolsFramework AtomToolsDocumentMainWindow(QWidget* parent = 0); ~AtomToolsDocumentMainWindow(); - private: + protected: + void AddDocumentMenus(); + void AddDocumentTabBar(); + + QString GetDocumentPath(const AZ::Uuid& documentId) const; + + AZ::Uuid GetDocumentIdFromTab(const int tabIndex) const; + + void AddTabForDocumentId( + const AZ::Uuid& documentId, + const AZStd::string& label, + const AZStd::string& toolTip); + + void RemoveTabForDocumentId(const AZ::Uuid& documentId); + + void UpdateTabForDocumentId( + const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified); + + void SelectPreviousTab(); + + void SelectNextTab(); + + virtual void OpenTabContextMenu() const; + virtual bool GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath) const; + virtual bool GetOpenFileInfo(AZStd::string& openPath) const; + virtual QWidget* CreateViewForDocumemt(const AZ::Uuid& documentId) const; + virtual void OpenSettings() const; + virtual void OpenHelp() const; + virtual void OpenAbout() const; // AtomToolsDocumentNotificationBus::Handler overrides... void OnDocumentOpened(const AZ::Uuid& documentId) override; @@ -39,13 +68,6 @@ namespace AtomToolsFramework void OnDocumentUndoStateChanged(const AZ::Uuid& documentId) override; void OnDocumentSaved(const AZ::Uuid& documentId) override; - void CreateMenu() override; - void CreateTabBar() override; - - QString GetDocumentPath(const AZ::Uuid& documentId) const; - - void OpenTabContextMenu() override; - void closeEvent(QCloseEvent* closeEvent) override; QMenu* m_menuFile = {}; @@ -73,5 +95,6 @@ namespace AtomToolsFramework QMenu* m_menuHelp = {}; QAction* m_actionHelp = {}; QAction* m_actionAbout = {}; + AzQtComponents::TabWidget* m_tabWidget = {}; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h index 2a304c9a8c..c5b47fe7a4 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h @@ -7,18 +7,14 @@ */ #pragma once + #include - #include - #include #include #include -#include #include -#include -#include namespace AtomToolsFramework { @@ -38,26 +34,11 @@ namespace AtomToolsFramework bool IsDockWidgetVisible(const AZStd::string& name) const override; AZStd::vector GetDockWidgetNames() const override; - virtual void CreateMenu(); - virtual void CreateTabBar(); - - virtual void AddTabForDocumentId( - const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, AZStd::function widgetCreator); - virtual void RemoveTabForDocumentId(const AZ::Uuid& documentId); - virtual void UpdateTabForDocumentId( - const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified); - virtual AZ::Uuid GetDocumentIdFromTab(const int tabIndex) const; - - virtual void OpenTabContextMenu(); - virtual void SelectPreviousTab(); - virtual void SelectNextTab(); - void SetStatusMessage(const QString& message); void SetStatusWarning(const QString& message); void SetStatusError(const QString& message); AzQtComponents::FancyDocking* m_advancedDockManager = nullptr; - AzQtComponents::TabWidget* m_tabWidget = nullptr; QLabel* m_statusMessage = nullptr; AZStd::unordered_map m_dockWidgets; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp index 502f861f0a..a35b65461a 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp @@ -21,6 +21,9 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnin #include #include #include +#include +#include +#include #include AZ_POP_DISABLE_WARNING @@ -30,7 +33,8 @@ namespace AtomToolsFramework : AtomToolsMainWindow(parent) { setObjectName("AtomToolsDocumentMainWindow"); - + AddDocumentMenus(); + AddDocumentTabBar(); AtomToolsDocumentNotificationBus::Handler::BusConnect(); } @@ -39,157 +43,27 @@ namespace AtomToolsFramework AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); } - void AtomToolsDocumentMainWindow::closeEvent(QCloseEvent* closeEvent) + void AtomToolsDocumentMainWindow::AddDocumentMenus() { - bool didClose = true; - AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); - if (!didClose) - { - closeEvent->ignore(); - return; - } - - AtomToolsMainWindowNotificationBus::Broadcast(&AtomToolsMainWindowNotifications::OnMainWindowClosing); - } - - void AtomToolsDocumentMainWindow::OnDocumentOpened(const AZ::Uuid& documentId) - { - bool isOpen = false; - AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsDocumentRequestBus::Events::IsOpen); - bool isSavable = false; - AtomToolsDocumentRequestBus::EventResult(isSavable, documentId, &AtomToolsDocumentRequestBus::Events::IsSavable); - bool isModified = false; - AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); - bool canUndo = false; - AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); - bool canRedo = false; - AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsDocumentRequestBus::Events::CanRedo); - AZStd::string absolutePath; - AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - AZStd::string filename; - AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - - // Update UI to display the new document - if (!documentId.IsNull() && isOpen) - { - // Create a new tab for the document ID and assign it's label to the file name of the document. - AddTabForDocumentId(documentId, filename, absolutePath, [this]{ - // The tab widget requires a dummy page per tab - auto contentWidget = new QWidget(centralWidget()); - contentWidget->setContentsMargins(0, 0, 0, 0); - contentWidget->setFixedSize(0, 0); - return contentWidget; - }); - - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - } - - const bool hasTabs = m_tabWidget->count() > 0; - - // Update menu options - m_actionNew->setEnabled(true); - m_actionOpen->setEnabled(true); - m_actionOpenRecent->setEnabled(false); - m_actionClose->setEnabled(hasTabs); - m_actionCloseAll->setEnabled(hasTabs); - m_actionCloseOthers->setEnabled(hasTabs); - - m_actionSave->setEnabled(isOpen && isSavable); - m_actionSaveAsCopy->setEnabled(isOpen && isSavable); - m_actionSaveAsChild->setEnabled(isOpen); - m_actionSaveAll->setEnabled(hasTabs); - - m_actionExit->setEnabled(true); - - m_actionUndo->setEnabled(canUndo); - m_actionRedo->setEnabled(canRedo); - m_actionSettings->setEnabled(true); - - m_actionPreviousTab->setEnabled(m_tabWidget->count() > 1); - m_actionNextTab->setEnabled(m_tabWidget->count() > 1); - - m_actionAbout->setEnabled(false); - - activateWindow(); - raise(); - - const QString documentPath = GetDocumentPath(documentId); - if (!documentPath.isEmpty()) - { - SetStatusMessage(tr("Document opened: %1").arg(documentPath)); - } - } - - void AtomToolsDocumentMainWindow::OnDocumentClosed(const AZ::Uuid& documentId) - { - RemoveTabForDocumentId(documentId); - SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); - } - - void AtomToolsDocumentMainWindow::OnDocumentModified(const AZ::Uuid& documentId) - { - bool isModified = false; - AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); - AZStd::string absolutePath; - AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - AZStd::string filename; - AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - } - - void AtomToolsDocumentMainWindow::OnDocumentUndoStateChanged(const AZ::Uuid& documentId) - { - if (documentId == GetDocumentIdFromTab(m_tabWidget->currentIndex())) - { - bool canUndo = false; - AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); - bool canRedo = false; - AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsDocumentRequestBus::Events::CanRedo); - m_actionUndo->setEnabled(canUndo); - m_actionRedo->setEnabled(canRedo); - } - } - - void AtomToolsDocumentMainWindow::OnDocumentSaved(const AZ::Uuid& documentId) - { - bool isModified = false; - AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); - AZStd::string absolutePath; - AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - AZStd::string filename; - AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); - } - - void AtomToolsDocumentMainWindow::CreateMenu() - { - Base::CreateMenu(); - // Generating the main menu manually because it's easier and we will have some dynamic or data driven entries m_menuFile = menuBar()->addMenu("&File"); m_actionNew = m_menuFile->addAction("&New...", [this]() { - //CreateMaterialDialog createDialog(this); - //createDialog.adjustSize(); - - //if (createDialog.exec() == QDialog::Accepted && - // !createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() && - // !createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty()) - //{ - // AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, - // createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(), - // createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData()); - //} + AZStd::string openPath; + AZStd::string savePath; + if (GetCreateFileInfo(openPath, savePath)) + { + AtomToolsDocumentSystemRequestBus::Broadcast( + &AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, openPath, savePath); + } }, QKeySequence::New); m_actionOpen = m_menuFile->addAction("&Open...", [this]() { - //const AZStd::vector assetTypes = { azrtti_typeid() }; - //const AZStd::string filePath = GetOpenFileInfo(assetTypes).absoluteFilePath().toUtf8().constData(); - //if (!filePath.empty()) - //{ - // AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::OpenDocument, filePath); - //} + AZStd::string openPath; + if (GetOpenFileInfo(openPath)) + { + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::OpenDocument, openPath); + } }, QKeySequence::Open); m_actionOpenRecent = m_menuFile->addAction("Open &Recent"); @@ -298,10 +172,8 @@ namespace AtomToolsFramework m_menuEdit->addSeparator(); m_actionSettings = m_menuEdit->addAction("&Settings...", [this]() { - //SettingsDialog dialog(this); - //dialog.exec(); + OpenSettings(); }, QKeySequence::Preferences); - m_actionSettings->setEnabled(true); m_menuView = menuBar()->addMenu("&View"); @@ -318,17 +190,27 @@ namespace AtomToolsFramework m_menuHelp = menuBar()->addMenu("&Help"); m_actionHelp = m_menuHelp->addAction("&Help...", [this]() { - //HelpDialog dialog(this); - //dialog.exec(); + OpenHelp(); }); m_actionAbout = m_menuHelp->addAction("&About...", [this]() { + OpenAbout(); }); } - void AtomToolsDocumentMainWindow::CreateTabBar() + void AtomToolsDocumentMainWindow::AddDocumentTabBar() { - Base::CreateTabBar(); + m_tabWidget = new AzQtComponents::TabWidget(centralWidget()); + m_tabWidget->setObjectName("TabWidget"); + m_tabWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); + m_tabWidget->setContentsMargins(0, 0, 0, 0); + + // The tab bar should only be visible if it has active documents + m_tabWidget->setVisible(false); + m_tabWidget->setTabBarAutoHide(false); + m_tabWidget->setMovable(true); + m_tabWidget->setTabsClosable(true); + m_tabWidget->setUsesScrollButtons(true); // This signal will be triggered whenever a tab is added, removed, selected, clicked, dragged // When the last tab is removed tabIndex will be -1 and the document ID will be null @@ -342,6 +224,14 @@ namespace AtomToolsFramework const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); }); + + // Add context menu for right-clicking on tabs + m_tabWidget->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu); + connect(m_tabWidget, &QWidget::customContextMenuRequested, this, [this]() { + OpenTabContextMenu(); + }); + + centralWidget()->layout()->addWidget(m_tabWidget); } QString AtomToolsDocumentMainWindow::GetDocumentPath(const AZ::Uuid& documentId) const @@ -351,7 +241,109 @@ namespace AtomToolsFramework return absolutePath.c_str(); } - void AtomToolsDocumentMainWindow::OpenTabContextMenu() + AZ::Uuid AtomToolsDocumentMainWindow::GetDocumentIdFromTab(const int tabIndex) const + { + const QVariant tabData = m_tabWidget->tabBar()->tabData(tabIndex); + if (!tabData.isNull()) + { + // We need to be able to convert between a UUID and a string to store and retrieve a document ID from the tab bar + const QString documentIdString = tabData.toString(); + const QByteArray documentIdBytes = documentIdString.toUtf8(); + const AZ::Uuid documentId(documentIdBytes.data(), documentIdBytes.size()); + return documentId; + } + return AZ::Uuid::CreateNull(); + } + + void AtomToolsDocumentMainWindow::AddTabForDocumentId( + const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip) + { + // Blocking signals from the tab bar so the currentChanged signal is not sent while a document is already being opened. + // This prevents the OnDocumentOpened notification from being sent recursively. + const QSignalBlocker blocker(m_tabWidget); + + // If a tab for this document already exists then select it instead of creating a new one + for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) + { + if (documentId == GetDocumentIdFromTab(tabIndex)) + { + m_tabWidget->setCurrentIndex(tabIndex); + m_tabWidget->repaint(); + return; + } + } + + const int tabIndex = m_tabWidget->addTab(CreateViewForDocumemt(documentId), label.c_str()); + + // The user can manually reorder tabs which will invalidate any association by index. + // We need to store the document ID with the tab using the tab instead of a separate mapping. + m_tabWidget->tabBar()->setTabData(tabIndex, QVariant(documentId.ToString())); + m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); + m_tabWidget->setCurrentIndex(tabIndex); + m_tabWidget->setVisible(true); + m_tabWidget->repaint(); + } + + void AtomToolsDocumentMainWindow::RemoveTabForDocumentId(const AZ::Uuid& documentId) + { + // We are not blocking signals here because we want closing tabs to close the associated document + // and automatically select the next document. + for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) + { + if (documentId == GetDocumentIdFromTab(tabIndex)) + { + m_tabWidget->removeTab(tabIndex); + m_tabWidget->setVisible(m_tabWidget->count() > 0); + m_tabWidget->repaint(); + break; + } + } + } + + void AtomToolsDocumentMainWindow::UpdateTabForDocumentId( + const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified) + { + // Whenever a document is opened, saved, or modified we need to update the tab label + if (!documentId.IsNull()) + { + // Because tab order and indexes can change from user interactions, we cannot store a map + // between a tab index and document ID. + // We must iterate over all of the tabs to find the one associated with this document. + for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) + { + if (documentId == GetDocumentIdFromTab(tabIndex)) + { + // We use an asterisk prepended to the file name to denote modified document + // Appending is standard and preferred but the tabs elide from the + // end (instead of middle) and cut it off + const AZStd::string modifiedLabel = isModified ? "* " + label : label; + m_tabWidget->setTabText(tabIndex, modifiedLabel.c_str()); + m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); + m_tabWidget->repaint(); + break; + } + } + } + } + + void AtomToolsDocumentMainWindow::SelectPreviousTab() + { + if (m_tabWidget->count() > 1) + { + // Adding count to wrap around when index <= 0 + m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + m_tabWidget->count() - 1) % m_tabWidget->count()); + } + } + + void AtomToolsDocumentMainWindow::SelectNextTab() + { + if (m_tabWidget->count() > 1) + { + m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + 1) % m_tabWidget->count()); + } + } + + void AtomToolsDocumentMainWindow::OpenTabContextMenu() const { const QTabBar* tabBar = m_tabWidget->tabBar(); const QPoint position = tabBar->mapFromGlobal(QCursor::pos()); @@ -377,6 +369,157 @@ namespace AtomToolsFramework tabMenu.exec(QCursor::pos()); } } + + inline bool AtomToolsDocumentMainWindow::GetCreateFileInfo(AZStd::string& openPath, AZStd::string& savePath) const + { + AZ_UNUSED(openPath); + AZ_UNUSED(savePath); + return false; + } + + inline bool AtomToolsDocumentMainWindow::GetOpenFileInfo(AZStd::string& openPath) const + { + AZ_UNUSED(openPath); + return false; + } + + inline QWidget* AtomToolsDocumentMainWindow::CreateViewForDocumemt(const AZ::Uuid& documentId) const + { + AZ_UNUSED(documentId); + auto contentWidget = new QWidget(centralWidget()); + contentWidget->setContentsMargins(0, 0, 0, 0); + contentWidget->setFixedSize(0, 0); + return contentWidget; + } + + inline void AtomToolsDocumentMainWindow::OpenSettings() const + { + } + + inline void AtomToolsDocumentMainWindow::OpenHelp() const + { + } + + inline void AtomToolsDocumentMainWindow::OpenAbout() const + { + } + + void AtomToolsDocumentMainWindow::OnDocumentOpened(const AZ::Uuid& documentId) + { + bool isOpen = false; + AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsDocumentRequestBus::Events::IsOpen); + bool isSavable = false; + AtomToolsDocumentRequestBus::EventResult(isSavable, documentId, &AtomToolsDocumentRequestBus::Events::IsSavable); + bool isModified = false; + AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); + bool canUndo = false; + AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); + bool canRedo = false; + AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsDocumentRequestBus::Events::CanRedo); + AZStd::string absolutePath; + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + + // Update UI to display the new document + if (!documentId.IsNull() && isOpen) + { + // Create a new tab for the document ID and assign it's label to the file name of the document. + AddTabForDocumentId(documentId, filename, absolutePath); + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + } + + const bool hasTabs = m_tabWidget->count() > 0; + + // Update menu options + m_actionNew->setEnabled(true); + m_actionOpen->setEnabled(true); + m_actionOpenRecent->setEnabled(false); + m_actionClose->setEnabled(hasTabs); + m_actionCloseAll->setEnabled(hasTabs); + m_actionCloseOthers->setEnabled(hasTabs); + + m_actionSave->setEnabled(isOpen && isSavable); + m_actionSaveAsCopy->setEnabled(isOpen && isSavable); + m_actionSaveAsChild->setEnabled(isOpen); + m_actionSaveAll->setEnabled(hasTabs); + + m_actionExit->setEnabled(true); + + m_actionUndo->setEnabled(canUndo); + m_actionRedo->setEnabled(canRedo); + m_actionSettings->setEnabled(true); + + m_actionPreviousTab->setEnabled(m_tabWidget->count() > 1); + m_actionNextTab->setEnabled(m_tabWidget->count() > 1); + + m_actionAbout->setEnabled(false); + + activateWindow(); + raise(); + + const QString documentPath = GetDocumentPath(documentId); + if (!documentPath.isEmpty()) + { + SetStatusMessage(tr("Document opened: %1").arg(documentPath)); + } + } + + void AtomToolsDocumentMainWindow::OnDocumentClosed(const AZ::Uuid& documentId) + { + RemoveTabForDocumentId(documentId); + SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); + } + + void AtomToolsDocumentMainWindow::OnDocumentModified(const AZ::Uuid& documentId) + { + bool isModified = false; + AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); + AZStd::string absolutePath; + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + } + + void AtomToolsDocumentMainWindow::OnDocumentUndoStateChanged(const AZ::Uuid& documentId) + { + if (documentId == GetDocumentIdFromTab(m_tabWidget->currentIndex())) + { + bool canUndo = false; + AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); + bool canRedo = false; + AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsDocumentRequestBus::Events::CanRedo); + m_actionUndo->setEnabled(canUndo); + m_actionRedo->setEnabled(canRedo); + } + } + + void AtomToolsDocumentMainWindow::OnDocumentSaved(const AZ::Uuid& documentId) + { + bool isModified = false; + AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); + AZStd::string absolutePath; + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); + } + + + void AtomToolsDocumentMainWindow::closeEvent(QCloseEvent* closeEvent) + { + bool didClose = true; + AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); + if (!didClose) + { + closeEvent->ignore(); + return; + } + + AtomToolsMainWindowNotificationBus::Broadcast(&AtomToolsMainWindowNotifications::OnMainWindowClosing); + } } // namespace AtomToolsFramework //#include diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp index cd7d49d8d3..a8ddebfbf0 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include @@ -26,6 +27,10 @@ namespace AtomToolsFramework m_statusMessage = new QLabel(statusBar()); statusBar()->addPermanentWidget(m_statusMessage, 1); + auto menuBar = new QMenuBar(this); + menuBar->setObjectName("MenuBar"); + setMenuBar(menuBar); + auto centralWidget = new QWidget(this); auto centralWidgetLayout = new QVBoxLayout(centralWidget); centralWidgetLayout->setMargin(0); @@ -108,145 +113,6 @@ namespace AtomToolsFramework return names; } - void AtomToolsMainWindow::CreateMenu() - { - auto menuBar = new QMenuBar(this); - menuBar->setObjectName("MenuBar"); - setMenuBar(menuBar); - } - - void AtomToolsMainWindow::CreateTabBar() - { - m_tabWidget = new AzQtComponents::TabWidget(centralWidget()); - m_tabWidget->setObjectName("TabWidget"); - m_tabWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); - m_tabWidget->setContentsMargins(0, 0, 0, 0); - - // The tab bar should only be visible if it has active documents - m_tabWidget->setVisible(false); - m_tabWidget->setTabBarAutoHide(false); - m_tabWidget->setMovable(true); - m_tabWidget->setTabsClosable(true); - m_tabWidget->setUsesScrollButtons(true); - - // Add context menu for right-clicking on tabs - m_tabWidget->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu); - connect( - m_tabWidget, &QWidget::customContextMenuRequested, this, - [this]() - { - OpenTabContextMenu(); - }); - - centralWidget()->layout()->addWidget(m_tabWidget); - } - - void AtomToolsMainWindow::AddTabForDocumentId( - const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, AZStd::function widgetCreator) - { - // Blocking signals from the tab bar so the currentChanged signal is not sent while a document is already being opened. - // This prevents the OnDocumentOpened notification from being sent recursively. - const QSignalBlocker blocker(m_tabWidget); - - // If a tab for this document already exists then select it instead of creating a new one - for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) - { - if (documentId == GetDocumentIdFromTab(tabIndex)) - { - m_tabWidget->setCurrentIndex(tabIndex); - m_tabWidget->repaint(); - return; - } - } - - const int tabIndex = m_tabWidget->addTab(widgetCreator(), label.c_str()); - - // The user can manually reorder tabs which will invalidate any association by index. - // We need to store the document ID with the tab using the tab instead of a separate mapping. - m_tabWidget->tabBar()->setTabData(tabIndex, QVariant(documentId.ToString())); - m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); - m_tabWidget->setCurrentIndex(tabIndex); - m_tabWidget->setVisible(true); - m_tabWidget->repaint(); - } - - void AtomToolsMainWindow::RemoveTabForDocumentId(const AZ::Uuid& documentId) - { - // We are not blocking signals here because we want closing tabs to close the associated document - // and automatically select the next document. - for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) - { - if (documentId == GetDocumentIdFromTab(tabIndex)) - { - m_tabWidget->removeTab(tabIndex); - m_tabWidget->setVisible(m_tabWidget->count() > 0); - m_tabWidget->repaint(); - break; - } - } - } - - void AtomToolsMainWindow::UpdateTabForDocumentId( - const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified) - { - // Whenever a document is opened, saved, or modified we need to update the tab label - if (!documentId.IsNull()) - { - // Because tab order and indexes can change from user interactions, we cannot store a map - // between a tab index and document ID. - // We must iterate over all of the tabs to find the one associated with this document. - for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) - { - if (documentId == GetDocumentIdFromTab(tabIndex)) - { - // We use an asterisk prepended to the file name to denote modified document - // Appending is standard and preferred but the tabs elide from the - // end (instead of middle) and cut it off - const AZStd::string modifiedLabel = isModified ? "* " + label : label; - m_tabWidget->setTabText(tabIndex, modifiedLabel.c_str()); - m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); - m_tabWidget->repaint(); - break; - } - } - } - } - - AZ::Uuid AtomToolsMainWindow::GetDocumentIdFromTab(const int tabIndex) const - { - const QVariant tabData = m_tabWidget->tabBar()->tabData(tabIndex); - if (!tabData.isNull()) - { - // We need to be able to convert between a UUID and a string to store and retrieve a document ID from the tab bar - const QString documentIdString = tabData.toString(); - const QByteArray documentIdBytes = documentIdString.toUtf8(); - const AZ::Uuid documentId(documentIdBytes.data(), documentIdBytes.size()); - return documentId; - } - return AZ::Uuid::CreateNull(); - } - - void AtomToolsMainWindow::OpenTabContextMenu() - { - } - - void AtomToolsMainWindow::SelectPreviousTab() - { - if (m_tabWidget->count() > 1) - { - // Adding count to wrap around when index <= 0 - m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + m_tabWidget->count() - 1) % m_tabWidget->count()); - } - } - - void AtomToolsMainWindow::SelectNextTab() - { - if (m_tabWidget->count() > 1) - { - m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + 1) % m_tabWidget->count()); - } - } - void AtomToolsMainWindow::SetStatusMessage(const QString& message) { m_statusMessage->setText(QString("%1").arg(message));