summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Studio/Application/StudioApp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Authoring/Studio/Application/StudioApp.cpp')
-rw-r--r--src/Authoring/Studio/Application/StudioApp.cpp2239
1 files changed, 0 insertions, 2239 deletions
diff --git a/src/Authoring/Studio/Application/StudioApp.cpp b/src/Authoring/Studio/Application/StudioApp.cpp
deleted file mode 100644
index f3594c94..00000000
--- a/src/Authoring/Studio/Application/StudioApp.cpp
+++ /dev/null
@@ -1,2239 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 1999-2002 NVIDIA Corporation.
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt 3D Studio.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "Qt3DSCommonPrecompile.h"
-
-#ifdef _WIN32
-#pragma warning(disable : 4100) // unreferenced formal parameter
-#endif
-#include "StudioApp.h"
-#include "PlayerWnd.h"
-#include "DataInputDlg.h"
-#include "qtsingleapplication.h"
-#include "qtlocalpeer.h"
-#include "TimelineWidget.h"
-#include "SlideView.h"
-#include "IKeyframesManager.h"
-#include "PresentationFile.h"
-#include "EditPresentationIdDlg.h"
-
-#include <QtGui/qsurfaceformat.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qurl.h>
-#include <QtCore/qsavefile.h>
-#include <QtGui/qopenglcontext.h>
-#include <QtWidgets/qaction.h>
-#include <QtCore/qstandardpaths.h>
-#include <QtCore/qcommandlineparser.h>
-#include <QtXml/qdom.h>
-#include <QtQml/qqmlapplicationengine.h>
-#include <QtQuick/qquickitem.h>
-
-#ifdef ENABLE_QT_BREAKPAD
-#include <qtsystemexceptionhandler.h>
-#endif
-
-#ifdef QT3DSTUDIO_REVISION
-#define STRINGIFY_INTERNAL(x) #x
-#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
-const char *const QT3DSTUDIO_REVISION_STR = STRINGIFY(QT3DSTUDIO_REVISION);
-#endif
-
-const QString activePresentationQuery = QStringLiteral("activePresentation:");
-
-int main(int argc, char *argv[])
-{
- bool isOpenGLES = false;
-
- // init runtime static resources
- Q_INIT_RESOURCE(res);
-
- QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
- QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
-#if !defined(Q_OS_MACOS)
- QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
-#endif
- SharedTools::QtSingleApplication guiApp(QStringLiteral("Qt3DStudio"), argc, argv);
-
- // Fix for uia and uip file attribute random ordering (see QTBUG-8158)
- qSetGlobalQHashSeed(1720419);
-
-#if defined(Q_OS_MACOS)
- QSurfaceFormat openGL33Format;
- openGL33Format.setRenderableType(QSurfaceFormat::OpenGL);
- openGL33Format.setProfile(QSurfaceFormat::CoreProfile);
- openGL33Format.setMajorVersion(3);
- openGL33Format.setMinorVersion(3);
- openGL33Format.setStencilBufferSize(8);
- QSurfaceFormat::setDefaultFormat(openGL33Format);
-#else
- QSurfaceFormat format;
- format.setDepthBufferSize(24);
- format.setStencilBufferSize(8);
- QScopedPointer<QOpenGLContext> context(new QOpenGLContext());
- context->setFormat(format);
- context->create();
- isOpenGLES = context->isOpenGLES();
-#endif
-
-#ifdef ENABLE_QT_BREAKPAD
- const QString libexecPath = QCoreApplication::applicationDirPath() + QStringLiteral("/.");
- QtSystemExceptionHandler systemExceptionHandler(libexecPath);
- systemExceptionHandler.setBuildVersion(QT3DSTUDIO_REVISION_STR);
-#endif
-
- // Parse the command line so we know what's up
- QCommandLineParser parser;
- parser.addHelpOption();
- parser.addPositionalArgument("file",
- QObject::tr("The presentation file."),
- QObject::tr("[file]"));
- parser.addPositionalArgument("folder",
- QObject::tr("The folder in which to create the new\n"
- "presentation."),
- QObject::tr("[folder]"));
- parser.addOption({"create",
- QObject::tr("Creates a new presentation.\n"
- "The file argument must be specified.\n"
- "The folder argument is optional. In\n"
- "case it is omitted, the new presentation\n"
- "is created in the executable folder.")});
- parser.addOption({"silent",
- QObject::tr("Allows creating a project silently.\n"
- "Only has effect with create.")});
- parser.addOption({"add",
- QObject::tr("Add a presentation to an existing project.\n"
- "Omit to create a new project. Only has effect with create.")});
- parser.process(guiApp);
-
- const QStringList files = parser.positionalArguments();
- if (files.count() > 1 && !parser.isSet("create")) {
- qWarning() << "Only one presentation file can be given.";
- parser.showHelp(-1);
- } else if (files.count() > 2 && parser.isSet("create")) {
- qWarning() << "Only one presentation file and a target folder can be given.";
- parser.showHelp(-1);
- } else if (files.count() == 0 && parser.isSet("create")) {
- qWarning() << "A presentation file is required.";
- parser.showHelp(-1);
- }
-
- QObject::connect(&guiApp, &SharedTools::QtSingleApplication::messageReceived,
- &g_StudioApp, &CStudioApp::handleMessageReceived);
-
-#if (defined Q_OS_MACOS)
- QObject::connect(&guiApp, &SharedTools::QtSingleApplication::fileOpenRequest,
- &g_StudioApp, &CStudioApp::openApplication);
-#endif
-
- // Load and apply stylesheet for the application
- QFile styleFile(":/style.qss");
- styleFile.open(QFile::ReadOnly);
- guiApp.setStyleSheet(styleFile.readAll());
- g_StudioApp.initInstance(parser, isOpenGLES);
- return g_StudioApp.run(parser);
-}
-
-//==============================================================================
-// Includes
-//==============================================================================
-#include "Exceptions.h"
-#include "IOLibraryException.h"
-#include "MainFrm.h"
-#include "AboutDlg.h"
-#include "Views.h"
-#include "Doc.h"
-#include "Dialogs.h"
-#include "Dispatch.h"
-#include "StartupDlg.h"
-#include "RecentItems.h"
-#include "StudioPreferences.h"
-#include "MsgRouter.h"
-#include "Views.h"
-#include "Qt3DSFile.h"
-#include "Qt3DSFileTools.h"
-#include "ITickTock.h"
-#include "IStudioRenderer.h"
-#include "IDocumentEditor.h"
-#include "StudioUtils.h"
-
-#include "ClientDataModelBridge.h"
-#include "CommonConstants.h"
-#include "IOLibraryException.h"
-
-#include "Qt3DSDMErrors.h"
-
-#include <iostream>
-#include <fstream>
-#include <stdio.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include <QtWidgets/qapplication.h>
-#include <QtCore/qsettings.h>
-
-#include "Core.h"
-#include "HotKeys.h"
-#include "StudioTutorialWidget.h"
-#include "Qt3DSDMStudioSystem.h"
-#include "Qt3DSDMInspectable.h"
-#include "Qt3DSDMSlides.h"
-#include "Qt3DSDMMaterialInspectable.h"
-#include "Qt3DSDMAnimation.h"
-#include "Qt3DSDMDataCore.h"
-#include "IDirectoryWatchingSystem.h"
-#include "ITickTock.h"
-#include "foundation/Qt3DSLogging.h"
-
-CStudioApp g_StudioApp;
-
-using namespace Q3DStudio;
-
-namespace qt3ds
-{
-void Qt3DSAssert(const char *exp, const char *file, int line, bool *ignore)
-{
- Q_UNUSED(ignore)
- g_StudioApp.GetDialogs()->DestroyProgressScreen();
- g_StudioApp.GetDialogs()->DisplayKnownErrorDialog(exp);
- qFatal("Assertion thrown %s(%d): %s", file, line, exp);
-}
-}
-
-//=============================================================================
-/**
- * Constructor
- */
-CStudioApp::CStudioApp()
- : m_core(nullptr)
- , m_isSilent(false)
- , m_views(nullptr)
- , m_toolMode(STUDIO_TOOLMODE_MOVE)
- , m_manipulationMode(StudioManipulationModes::Local)
- , m_selectMode(STUDIO_SELECTMODE_GROUP)
- , m_dialogs(nullptr)
- , m_playbackTime(0)
- , m_authorZoom(false)
- , m_welcomeShownThisSession(false)
- , m_goStraightToWelcomeFileDialog(false)
- , m_tutorialPage(0)
- , m_autosaveTimer(new QTimer(this))
-{
- connect(m_autosaveTimer, &QTimer::timeout, this, [=](){ OnSave(true); });
-}
-
-//=============================================================================
-/**
- * Destructor
- */
-CStudioApp::~CStudioApp()
-{
- delete m_views;
- m_views = nullptr;
- delete m_dialogs;
- m_dialogs = nullptr;
- delete m_core;
- m_core = nullptr;
-}
-
-void CStudioApp::performShutdown()
-{
- // Dispatch un-registration
- if (m_core) {
- m_core->GetDispatch()->RemoveAppStatusListener(this);
- m_core->GetDispatch()->RemoveCoreAsynchronousEventListener(this);
-
- // close transactions before we call destructors
- if (m_core->GetDoc()->isTransactionOpened())
- m_core->GetDoc()->closeTransaction();
-
- qCInfo(qt3ds::TRACE_INFO) << "Studio exiting successfully";
- }
-
- if (m_renderer) {
- if (m_views->getMainFrame())
- m_views->getMainFrame()->GetPlayerWnd()->makeCurrent();
- m_renderer->Close();
- m_renderer = std::shared_ptr<Q3DStudio::IStudioRenderer>();
- if (m_views->getMainFrame())
- m_views->getMainFrame()->GetPlayerWnd()->doneCurrent();
- }
-
- delete m_views;
- m_views = nullptr;
- delete m_dialogs;
- m_dialogs = nullptr;
- delete m_core;
- m_core = nullptr;
-
- // Get rid of the temp files
- Qt3DSFile::ClearCurrentTempCache();
-
- CMsgRouter::GetInstance()->blockMessages();
-
- qApp->exit();
-}
-
-//=============================================================================
-/**
- * Entry location for the creation of this application.
- * This creates the all the views, then returns if everything
- * was successful.
- */
-bool CStudioApp::initInstance(const QCommandLineParser &parser, bool isOpenGLES)
-{
- QApplication::setOrganizationName("The Qt Company");
- QApplication::setOrganizationDomain("qt.io");
- QApplication::setApplicationName("Qt 3D Studio");
- QApplication::setApplicationVersion(CStudioPreferences::GetVersionString());
-
- qCInfo(qt3ds::TRACE_INFO) << "Studio: " << QApplication::applicationFilePath();
- qCInfo(qt3ds::TRACE_INFO) << "Version: " << CStudioPreferences::GetVersionString();
-
- // Silent is ignored for everything but create
- m_isSilent = parser.isSet("silent") && parser.isSet("create");
-
- // Initialize help file paths
- m_helpFilePath = Qt3DSFile::GetApplicationDirectory()
- + QStringLiteral("/../doc/qt3dstudio/qt3dstudio-index.html");
- m_gettingStartedFilePath = Qt3DSFile::GetApplicationDirectory()
- + QStringLiteral("/../doc/qt3dstudio/getting-started.html");
-
- QString thePreferencesPath = CFilePath::GetUserApplicationDirectory()
- + QStringLiteral("/Qt3DStudio/Preferences.setting");
- CStudioPreferences::loadPreferences(thePreferencesPath);
-
- m_dialogs = new CDialogs(!m_isSilent);
-
- if (isOpenGLES) {
- m_dialogs->DisplayKnownErrorDialog(
- tr("Qt 3D Studio cannot be started.\n"
- "OpenGL ES is not supported for Qt 3D Studio Editor.\n"
- "Make sure you are not using a software renderer or\n"
- "wrapper like MESA or Angle before trying again."));
- exit(0);
- }
-
- m_views = new CViews();
-
- m_core = new CCore();
- getRenderer();
- m_core->GetDoc()->SetSceneGraph(m_renderer);
-
- // Dispatch registration
- m_core->GetDispatch()->AddAppStatusListener(this);
- m_core->GetDispatch()->AddCoreAsynchronousEventListener(this);
- m_core->GetDispatch()->AddFailListener(this);
-
- // Initialize autosave
- m_autosaveTimer->setInterval(CStudioPreferences::GetAutoSaveDelay() * 1000);
- if (CStudioPreferences::GetAutoSavePreference())
- m_autosaveTimer->start();
-
- return true;
-}
-
-//=============================================================================
-/**
- * Command handler to display the about dialog.
- */
-void CStudioApp::onAppAbout()
-{
- CAboutDlg aboutDlg;
- aboutDlg.exec();
-}
-
-//=============================================================================
-/**
- * Main application execution loop.
- * The application's main thread stays in this until the app exits.
- * @return true on success; false on failure
- */
-bool CStudioApp::run(const QCommandLineParser &parser)
-{
- bool theRetVal = false;
- try {
- if (parser.isSet("create")) {
- // true: add a presentation to a project, false: create a new project
- bool isAdd = parser.isSet("add");
- // Create, requires file and folder
- if (parser.positionalArguments().count() > 1) {
- theRetVal = createAndRunApplication(parser.positionalArguments().at(0),
- parser.positionalArguments().at(1), !isAdd);
- } else {
- theRetVal = createAndRunApplication(parser.positionalArguments().at(0),
- QString(), !isAdd);
- }
- } else if (parser.positionalArguments().count() > 0) {
- // Start given file
- theRetVal = openAndRunApplication(parser.positionalArguments().at(0));
- } else {
- // No arguments, normal start
- theRetVal = blankRunApplication();
- }
-
- if (!theRetVal)
- qWarning("Problem starting application");
-
- performShutdown();
- } catch (qt3dsdm::Qt3DSDMError &uicdmError) {
- Q_UNUSED(uicdmError);
- exit(1);
- } catch (...) {
- throw;
- }
-
- return theRetVal;
-}
-
-bool CStudioApp::handleWelcomeRes(int res, bool recursive)
-{
- bool theReturn = true;
- bool canceled = false;
- switch (res) {
- case StudioTutorialWidget::createNewResult: {
- if (PerformSavePrompt()) {
- QString theFile(m_dialogs->GetNewDocumentChoice(getMostRecentProjectParentDir()));
- if (!theFile.isEmpty()) {
- if (!m_core->OnNewDocument(theFile, true)) {
- // Invalid filename, show a message box and the startup dialog
- showInvalidFilenameWarning();
- theReturn = showStartupDialog();
- } else {
- theReturn = true;
- m_welcomeShownThisSession = true;
- }
- } else {
- canceled = true;
- }
- } else {
- canceled = true;
- }
- } break;
-
- case StudioTutorialWidget::openSampleResult: {
- if (PerformSavePrompt()) {
- // Try three options:
- // - open a specific example .uia
- // - failing that, show the main example root dir
- // - failing all previous, show default Documents dir
- QFileInfo filePath;
- QString theFile(QStringLiteral("."));
-
-#ifndef Q_OS_MACOS
- filePath.setFile(Qt3DSFile::GetApplicationDirectory() +
- QStringLiteral("/../examples/studio3d/SampleProject"));
-
- if (!filePath.exists()) {
- filePath.setFile(Qt3DSFile::GetApplicationDirectory()
- + QStringLiteral("/../examples/studio3d"));
-#else
- filePath.setFile(Qt3DSFile::GetApplicationDirectory()
- + QStringLiteral("/../../../../examples/studio3d/SampleProject"));
-
- if (!filePath.exists()) {
- filePath.setFile(Qt3DSFile::GetApplicationDirectory()
- + QStringLiteral("/../../../../examples/studio3d"));
-#endif
- if (!filePath.exists()) {
- filePath.setFile(QStandardPaths::writableLocation(
- QStandardPaths::DocumentsLocation));
- }
- theFile = m_dialogs->GetFileOpenChoice(filePath.absoluteFilePath());
- } else {
- theFile = filePath.absoluteFilePath() + QStringLiteral("/SampleProject.uia");
- }
-
- if (!theFile.isEmpty()) {
- OnLoadDocument(theFile);
- theReturn = true;
- m_welcomeShownThisSession = true;
- } else {
- canceled = true;
- }
- } else {
- canceled = true;
- }
- } break;
- default:
- // Welcome screen was simply closed
- theReturn = false;
- break;
- }
-
- if (canceled) {
- // User Cancels the dialog. Show the welcome screen.
- if (recursive) {
- m_welcomeShownThisSession = false;
- m_goStraightToWelcomeFileDialog = true;
- theReturn = showStartupDialog();
- } else {
- theReturn = false;
- }
- }
- return theReturn;
-}
-
-QString CStudioApp::resolvePresentationFile(const QString &inFile)
-{
- QFileInfo inFileInfo(inFile);
- // a uip file, just return it
- if (inFileInfo.suffix().compare(QStringLiteral("uip"), Qt::CaseInsensitive) == 0)
- return inFile;
-
- // If opening a .uia file, open the initial presentation
- if (inFileInfo.suffix().compare(QStringLiteral("uia"), Qt::CaseInsensitive) == 0
- && inFileInfo.exists()) {
- QString uiaPath = inFileInfo.absoluteFilePath();
- QString initialPresentation = m_core->getProjectFile().getInitialPresentationSrc(uiaPath);
-
- if (!initialPresentation.isEmpty())
- return inFileInfo.path() + QStringLiteral("/") + initialPresentation;
- }
-
- // couldn't find a uip file
- return {};
-}
-
-//=============================================================================
-/**
- * Show startup dialog and perform necessary action such as create new doc or load doc.
- * Return false if user requests to exit
- */
-bool CStudioApp::showStartupDialog()
-{
-#if (defined Q_OS_MACOS)
- if (m_fileOpenEvent)
- return true;
-#endif
-
- int welcomeRes = QDialog::Rejected;
- bool theReturn = true;
-
- if (!m_welcomeShownThisSession){
- m_welcomeShownThisSession = true;
-
- bool show = false;
- QSettings settings;
-
- if (!settings.contains("showWelcomeScreen")) {
- settings.setValue("showWelcomeScreen", 1);
- show = true;
- } else {
- // if we are returning to welcome dialog page after canceling
- // file dialog, do not care about settings but always show
- // welcome
- show = settings.value("showWelcomeScreen").toBool()
- || m_goStraightToWelcomeFileDialog;
- }
-
- if (show) {
- StudioTutorialWidget tutorial(m_pMainWnd);
- welcomeRes = tutorial.exec();
- }
- }
-
- // show the usual startup dialog only if user rejected tutorial
- // ( = did not open samples or create new project)
- if (welcomeRes == QDialog::Rejected) {
- CStartupDlg theStartupDlg(m_pMainWnd);
-
- // Populate recent items
- if (m_pMainWnd) {
- CRecentItems *theRecentItems = m_pMainWnd->GetRecentItems();
- for (long theIndex = 0; theIndex < theRecentItems->GetItemCount(); ++theIndex)
- theStartupDlg.AddRecentItem(theRecentItems->GetItem(theIndex));
- }
-
- theStartupDlg.exec();
- CStartupDlg::EStartupChoice theChoice = theStartupDlg.GetChoice();
-
- switch (theChoice) {
- case CStartupDlg::EStartupChoice_Exit:
- theReturn = true;
- break;
-
- case CStartupDlg::EStartupChoice_NewDoc: {
- QString theFile = m_dialogs->GetNewDocumentChoice(getMostRecentProjectParentDir());
- if (!theFile.isEmpty()) {
- if (!m_core->OnNewDocument(theFile, true)) {
- // Invalid filename, show a message box and the dialog again
- showInvalidFilenameWarning();
- theReturn = showStartupDialog();
- }
- } else {
- // User Cancels the dialog. Show startup dialog again.
- theReturn = showStartupDialog();
- }
- } break;
-
- case CStartupDlg::EStartupChoice_OpenDoc: {
- QString theFile = m_dialogs->GetFileOpenChoice(getMostRecentDirectory());
- if (!theFile.isEmpty()) {
- OnLoadDocument(theFile);
- theReturn = true;
- } else {
- // User Cancels the dialog. Show startup dialog again.
- theReturn = showStartupDialog();
- }
- } break;
-
- case CStartupDlg::EStartupChoice_OpenRecent: {
- QString theFile = theStartupDlg.GetRecentDoc();
- if (!theFile.isEmpty()) {
- OnLoadDocument(theFile);
- theReturn = true;
- } else {
- // User Cancels the dialog. Show startup dialog again.
- theReturn = showStartupDialog();
- }
- } break;
-
- default:
- QT3DS_ASSERT(false); // Should not reach this block.
- theReturn = false;
- break;
- }
- } else { // open sample or create new
- theReturn = handleWelcomeRes(welcomeRes, true);
- }
- return theReturn;
-}
-
-#if (defined Q_OS_MACOS)
-void CStudioApp::openApplication(const QString &inFilename)
-{
- m_fileOpenEvent = true;
- QString loadFile = resolvePresentationFile(inFilename);
- OnLoadDocument(loadFile, true);
-}
-#endif
-
-//=============================================================================
-/**
- * Start the app.
- */
-bool CStudioApp::blankRunApplication()
-{
- initCore();
- // Event loop must be running before we launch startup dialog, or possible error message boxes
- // will cause a silent crash.
-#if (defined Q_OS_MACOS)
- // Give a bit of time for Finder file open, in case that's how we were started
- QTimer::singleShot(250, this, &CStudioApp::showStartupDialog);
-#else
- QTimer::singleShot(0, this, &CStudioApp::showStartupDialog);
-#endif
- return runApplication();
-}
-
-//=============================================================================
-/**
- * Open the specified file and run the application.
- * This will load the file then go into the standard app loop.
- * On load with the -silent flag, this would force the application to exit on
- * load failures.
- * @return true on success; false on failure
- */
-bool CStudioApp::openAndRunApplication(const QString &inFilename)
-{
- // Need to resolve the actual file we want to load already to be able to check for it
- QString loadFile = resolvePresentationFile(inFilename);
-
- // First check if the desired presentation is already open on another instance
- SharedTools::QtSingleApplication *app =
- static_cast<SharedTools::QtSingleApplication *>(QCoreApplication::instance());
- const auto pids = app->runningInstances();
- for (const auto pid : pids) {
- app->setBlock(true);
- QString query = activePresentationQuery + loadFile;
- if (app->sendMessage(query, true, 5000, pid))
- return true;
- }
-
- bool theSuccess = false;
- initCore();
- // Load document. Upon failure, don't show startup dialog but exit immediately.
- if (OnLoadDocument(loadFile, false))
- theSuccess = runApplication();
- return theSuccess;
-}
-
-bool CStudioApp::createAndRunApplication(const QString &filename, const QString &folder,
- bool isNewProject)
-{
- bool theSuccess = false;
- initCore();
- // Append .uip if it is not included in the filename
- QString actualFilename = filename;
- if (!actualFilename.endsWith(QLatin1String(".uip")))
- actualFilename.append(QLatin1String(".uip"));
-
- QString actualFolder = folder;
- if (!actualFolder.endsWith(QLatin1String("/")))
- actualFilename.append(QLatin1String("/"));
-
- // Create presentation
- QString filePath = actualFolder + actualFilename;
- if (!filePath.isEmpty()) {
- theSuccess = m_core->OnNewDocument(filePath, isNewProject, m_isSilent);
- if (!theSuccess)
- return false;
-
- theSuccess = m_isSilent || runApplication();
- }
- return theSuccess;
-}
-
-//=============================================================================
-/**
- * This is the app execution loop, the main thread loops here until the app exits.
- * @return true on success; false on failure
- */
-bool CStudioApp::runApplication()
-{
- return qApp->exec() == 0;
-}
-
-//=============================================================================
-/**
- * Initialize the core and all the views.
- */
-void CStudioApp::initCore()
-{
- // Initialize and cache the RenderSelector values for the first time,
- // this way, subsequent attempts to instantiate a RenderSelector would circumvent the need
- // for any extra (unneccesary) creation of render contexts which inadvertently cause exceptions
- // to be thrown.
-
- m_core->Initialize();
-
- if (m_views) {
- m_views->createViews(m_isSilent);
- m_pMainWnd = m_views->getMainFrame();
- m_pMainWnd->initializeGeometryAndState();
- }
-
- RegisterGlobalKeyboardShortcuts(m_core->GetHotKeys(), m_pMainWnd);
- m_core->GetDispatch()->AddPresentationChangeListener(this);
-}
-
-struct SIImportFailedHandler : public Q3DStudio::IImportFailedHandler
-{
- CDialogs &m_Dialogs;
- SIImportFailedHandler(CDialogs &dialogs)
- : m_Dialogs(dialogs)
- {
- }
- void DisplayImportFailed(const QString &inDocumentPath, const QString &inDescription,
- bool inWarningsOnly) override
- {
- m_Dialogs.DisplayImportFailed(QUrl(inDocumentPath), inDescription, inWarningsOnly);
- }
-};
-
-struct SIDeletingReferencedObjectHandler : public Q3DStudio::IDeletingReferencedObjectHandler
-{
- CDialogs &m_Dialogs;
-
- SIDeletingReferencedObjectHandler(CDialogs &dialogs)
- : m_Dialogs(dialogs)
- {
- }
-
- void DisplayMessageBox(const QString &inDescription) override
- {
- QString theTitle = QObject::tr("Warning");
- QString theMessage = QObject::tr("The following objects have action(s) that reference this "
- "object and/or its descendants:\n%1\nPlease fix the "
- "action(s) accordingly.").arg(inDescription);
-
- m_Dialogs.DisplayMessageBox(theTitle, theMessage, Qt3DSMessageBox::ICON_WARNING, false);
- }
-};
-
-struct SIMoveRenameHandler : public Q3DStudio::IMoveRenameHandler
-{
- CDialogs &m_dialogs;
-
- SIMoveRenameHandler(CDialogs &dialogs)
- : m_dialogs(dialogs)
- {
- }
-
- void displayMessageBox(const QString &origName, const QString &newName) override
- {
- g_StudioApp.GetDialogs()->DisplayObjectRenamed(origName, newName);
- }
-};
-
-void CStudioApp::setupTimer(long inMessageId, QWidget *inWnd)
-{
- m_tickTock = ITickTock::CreateTickTock(inMessageId, inWnd);
- getDirectoryWatchingSystem();
- m_core->GetDoc()->SetDirectoryWatchingSystem(m_directoryWatchingSystem);
- m_core->GetDoc()->SetImportFailedHandler(
- std::make_shared<SIImportFailedHandler>(std::ref(*GetDialogs())));
- m_core->GetDoc()->SetDocMessageBoxHandler(
- std::make_shared<SIDeletingReferencedObjectHandler>(std::ref(*GetDialogs())));
- m_core->GetDoc()->setMoveRenameHandler(
- std::make_shared<SIMoveRenameHandler>(std::ref(*GetDialogs())));
-}
-
-ITickTock &CStudioApp::getTickTock()
-{
- if (m_tickTock == nullptr)
- throw std::runtime_error("Uninitialized TickTock");
- return *m_tickTock;
-}
-
-Q3DStudio::IStudioRenderer &CStudioApp::getRenderer()
-{
- if (!m_renderer)
- m_renderer = Q3DStudio::IStudioRenderer::CreateStudioRenderer();
- return *m_renderer;
-}
-
-void CStudioApp::clearGuides()
-{
- SCOPED_DOCUMENT_EDITOR(*m_core->GetDoc(), QObject::tr("Clear Guides"))->ClearGuides();
-}
-
-void CStudioApp::handleMessageReceived(const QString &message, QObject *socket)
-{
- if (message.startsWith(activePresentationQuery)) {
- QLocalSocket *lsocket = qobject_cast<QLocalSocket *>(socket);
- if (lsocket) {
- // Another studio instance wants to know if specified presentation is open on this one
- QString checkPath(message.mid(activePresentationQuery.size()));
- QFileInfo checkFile(checkPath);
- QString docPath;
- if (m_core)
- docPath = m_core->GetDoc()->GetDocumentPath();
- QFileInfo openFile(docPath);
- if (!checkPath.isEmpty() && checkFile == openFile) {
- lsocket->write(SharedTools::QtLocalPeer::acceptReply(),
- SharedTools::QtLocalPeer::acceptReply().size());
- // Since we accept active presentation query, it means the querying instance will
- // shut down and this instance must be made active window.
- if (m_pMainWnd) {
- m_pMainWnd->setWindowState(m_pMainWnd->windowState() & ~Qt::WindowMinimized);
- m_pMainWnd->raise();
- m_pMainWnd->activateWindow();
- }
- } else {
- lsocket->write(SharedTools::QtLocalPeer::denyReply(),
- SharedTools::QtLocalPeer::denyReply().size());
- }
- lsocket->waitForBytesWritten(1000);
- }
- }
- if (socket)
- delete socket;
-}
-
-void SendAsyncCommand(CDispatch &inDispatch, Q3DStudio::TCallbackFunc inFunc)
-{
- inDispatch.FireOnAsynchronousCommand(inFunc);
-}
-
-IDirectoryWatchingSystem &CStudioApp::getDirectoryWatchingSystem()
-{
- if (m_directoryWatchingSystem == nullptr) {
- Q3DStudio::TCallbackCaller theCaller =
- std::bind(SendAsyncCommand, std::ref(*m_core->GetDispatch()),
- std::placeholders::_1);
- m_directoryWatchingSystem =
- IDirectoryWatchingSystem::CreateThreadedDirectoryWatchingSystem(theCaller);
- }
- return *m_directoryWatchingSystem;
-}
-
-CCore *CStudioApp::GetCore()
-{
- return m_core;
-}
-
-//=============================================================================
-/**
- * Get the view manager for this core to communicate to the views.
- */
-CViews *CStudioApp::GetViews()
-{
- return m_views;
-}
-
-//=============================================================================
-/**
- * Get the dialog manager for this core for displaying dialogs.
- */
-CDialogs *CStudioApp::GetDialogs()
-{
- return m_dialogs;
-}
-
-long CStudioApp::GetToolMode()
-{
- return m_toolMode;
-}
-
-void CStudioApp::SetToolMode(long inToolMode)
-{
- if (m_toolMode != inToolMode) {
- m_toolMode = inToolMode;
- m_core->GetDispatch()->FireOnToolbarChange();
- }
-}
-
-long CStudioApp::GetSelectMode()
-{
- return m_selectMode;
-}
-
-void CStudioApp::SetSelectMode(long inSelectMode)
-{
- if (m_selectMode != inSelectMode) {
- m_selectMode = inSelectMode;
- m_core->GetDispatch()->FireOnToolbarChange();
- }
-}
-
-StudioManipulationModes::Enum CStudioApp::GetManipulationMode() const
-{
- return m_manipulationMode;
-}
-void CStudioApp::SetManipulationMode(StudioManipulationModes::Enum inManipulationMode)
-{
- if (m_manipulationMode != inManipulationMode) {
- m_manipulationMode = inManipulationMode;
- m_core->GetDispatch()->FireOnToolbarChange();
- }
-}
-
-//=============================================================================
-/**
- * return true if undo is possible
- */
-bool CStudioApp::CanUndo()
-{
- return m_core->GetCmdStack()->CanUndo()
- && !m_views->getMainFrame()->getTimelineWidget()->dndActive();
-}
-
-//=============================================================================
-/**
- * return true if redo is possible
- */
-bool CStudioApp::CanRedo()
-{
- return m_core->GetCmdStack()->CanRedo();
-}
-
-void CStudioApp::OnCopy()
-{
- m_core->GetDoc()->HandleCopy();
-}
-
-bool CStudioApp::CanCopy()
-{
- return m_core->GetDoc()->canCopy();
-}
-
-//=============================================================================
-/**
- * Get a string describing the type of the copy operation that can be done.
- * Precedence of copying is 1) Actions; 2) Keyframes; 3) Objects
- */
-QString CStudioApp::GetCopyType()
-{
- QString theCopyType;
-
- CDoc *theDoc = m_core->GetDoc();
- if (theDoc->canCopySelectedActions())
- theCopyType = tr("Action");
- else if (theDoc->canCopySelectedKeyframes())
- theCopyType = tr("Keyframes");
- else
- theCopyType = tr("Object");
-
- return theCopyType;
-}
-
-QString CStudioApp::getDuplicateType() const
-{
- const bool slide = qobject_cast<SlideView *>(m_lastActiveView) != nullptr;
- CDoc *doc = m_core->GetDoc();
- if (slide) {
- qt3dsdm::Qt3DSDMSlideHandle handle = doc->GetActiveSlide();
- if (handle != doc->GetStudioSystem()->GetSlideSystem()->GetMasterSlide(handle))
- return tr("Slide");
- } else {
- qt3dsdm::Qt3DSDMInstanceHandle selectedInstance = doc->GetSelectedInstance();
- CClientDataModelBridge *bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
- if (bridge->IsDuplicateable(selectedInstance))
- return tr("Object");
- }
- return {};
-}
-
-QString CStudioApp::getDeleteType() const
-{
- // Delete priority: keyframes, slides, objects
- const bool slide = qobject_cast<SlideView *>(m_lastActiveView) != nullptr;
- CDoc *doc = m_core->GetDoc();
- if (m_pMainWnd->getTimelineWidget()->hasSelectedKeyframes()) {
- return tr("Keyframes");
- } else if (slide) {
- // Check if the slide is the last one or the master
- qt3dsdm::Qt3DSDMSlideHandle slideHandle = doc->GetActiveSlide();
- qt3dsdm::ISlideSystem *slideSys = doc->GetStudioSystem()->GetSlideSystem();
- qt3dsdm::Qt3DSDMSlideHandle masterSlideHandle = slideSys->GetMasterSlide(slideHandle);
- size_t slideCount = slideSys->GetSlideCount(masterSlideHandle);
- if (slideHandle != masterSlideHandle && slideCount > 2)
- return tr("Slide");
- } else {
- qt3dsdm::TInstanceHandleList selected = doc->GetSelectedValue().GetSelectedInstances();
- CClientDataModelBridge *bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
- int deletableCount = 0;
- for (size_t idx = 0, end = selected.size(); idx < end; ++idx) {
- if (bridge->CanDelete(selected[idx]))
- deletableCount++;
- }
- if (deletableCount && deletableCount == selected.size())
- return tr("Object");
- }
- return {};
-}
-
-bool CStudioApp::canGroupSelectedObjects() const
-{
- // Grouping is allowed for single and for multiple selected items.
- qt3dsdm::TInstanceHandleList selected = m_core->GetDoc()
- ->GetSelectedValue().GetSelectedInstances();
- if (selected.size() >= 1) {
- // Scene objects, any direct children of scene objects (layers and behaviors), effects,
- // root components, images, and materials are not groupable. Anything that can be
- // multiselected can be grouped, so its enough to check the first selected object's type.
- // Behavior that is not direct child of scene could technically be grouped, but since it
- // cannot be multiselected, we treat it as ungroupable.
- qt3dsdm::Qt3DSDMInstanceHandle first = selected[0];
- if (first.Valid()) {
- auto bridge = m_core->GetDoc()->GetStudioSystem()->GetClientDataModelBridge();
- EStudioObjectType type = bridge->GetObjectType(first);
-
- if (type & OBJTYPE_IS_UNGROUPABLE)
- return false;
-
- // Components can't be grouped if they are the root of currently active time context
- if (type == OBJTYPE_COMPONENT && bridge->IsActiveComponent(first))
- return false;
-
- // All items must either be on master slide or not be on master slide
- bool isMaster = bridge->IsMaster(first);
- for (size_t i = 1, end = selected.size(); i < end; ++i) {
- if (isMaster != bridge->IsMaster(selected[i]))
- return false;
- }
-
- return true;
- }
- }
- return false;
-}
-
-bool CStudioApp::canUngroupSelectedObjects() const
-{
- qt3dsdm::TInstanceHandleList selected = m_core->GetDoc()
- ->GetSelectedValue().GetSelectedInstances();
- if (selected.size() == 1) {
- qt3dsdm::Qt3DSDMInstanceHandle first = selected[0];
- return (first.Valid() && m_core->GetDoc()->GetStudioSystem()->GetClientDataModelBridge()
- ->GetObjectType(first) == OBJTYPE_GROUP);
- }
- return false;
-}
-
-bool CStudioApp::groupSelectedObjects() const
-{
- if (canGroupSelectedObjects()) {
- qt3dsdm::TInstanceHandleList selected = m_core->GetDoc()
- ->GetSelectedValue().GetSelectedInstances();
- SCOPED_DOCUMENT_EDITOR(*m_core->GetDoc(),
- QObject::tr("Group objects"))->groupObjects(selected);
- return true;
- }
- return false;
-}
-
-bool CStudioApp::ungroupSelectedObjects() const
-{
- if (canUngroupSelectedObjects()) {
- qt3dsdm::TInstanceHandleList selected = m_core->GetDoc()
- ->GetSelectedValue().GetSelectedInstances();
- SCOPED_DOCUMENT_EDITOR(*m_core->GetDoc(),
- QObject::tr("Ungroup objects"))->ungroupObjects(selected);
- return true;
- }
- return false;
-}
-
-//=============================================================================
-/**
- * Cuts the selected object or keys
- */
-void CStudioApp::OnCut()
-{
- m_core->GetDoc()->HandleCut();
-}
-
-bool CStudioApp::CanCut()
-{
- return m_core->GetDoc()->canCut();
-}
-
-//=============================================================================
-/**
- * Paste keys from the copied list yo
- */
-void CStudioApp::OnPaste()
-{
- m_core->GetDoc()->HandlePaste();
-}
-
-bool CStudioApp::CanPaste()
-{
- return m_core->GetDoc()->canPaste();
-}
-
-//=============================================================================
-/**
- * Get a string describing the type of the paste operation that can be done.
- * Precedence of paste is 1) Actions; 2) Object ; 3) Keyframes
- */
-QString CStudioApp::GetPasteType()
-{
- QString thePasteType;
-
- CDoc *theDoc = m_core->GetDoc();
- if (theDoc->canPasteActions())
- thePasteType = tr("Action");
- else if (theDoc->canPasteObjects())
- thePasteType = tr("Object");
- else
- thePasteType = tr("Keyframes");
-
- return thePasteType;
-}
-
-bool CStudioApp::CanChangeTimebarColor()
-{
- bool theRetVal = true;
- qt3dsdm::Qt3DSDMInstanceHandle theSelectedInstance = m_core->GetDoc()->GetSelectedInstance();
- if (!theSelectedInstance.Valid()
- || m_core->GetDoc()->GetStudioSystem()->GetClientDataModelBridge()->IsSceneInstance(
- theSelectedInstance)) {
- theRetVal = false;
- }
-
- return theRetVal;
-}
-
-//=============================================================================
-/**
- * Sets any changed keyframes on the selected object
- */
-void CStudioApp::HandleSetChangedKeys()
-{
- m_core->GetDoc()->SetChangedKeyframes();
-}
-
-//=============================================================================
-/**
- * Deletes all selected keys
- */
-void CStudioApp::DeleteSelectedKeys()
-{
- m_core->GetDoc()->deleteSelectedKeyframes();
-}
-
-//=============================================================================
-/**
- * Deletes selected object or keyframes
- */
-void CStudioApp::DeleteSelectedObject()
-{
- const bool slide = qobject_cast<SlideView *>(m_lastActiveView) != nullptr;
- m_core->GetDoc()->DeleteSelectedItems(slide);
-}
-
-/**
- * Handles the duplicate object command
- */
-void CStudioApp::HandleDuplicateCommand()
-{
- const bool slide = qobject_cast<SlideView *>(m_lastActiveView) != nullptr;
- m_core->GetDoc()->HandleDuplicateCommand(slide);
-}
-
-/**
- * Toggles the state of autoset keyframes.
- */
-void CStudioApp::OnToggleAutosetKeyframes()
-{
- SetAutosetKeyframes(!CStudioPreferences::IsAutosetKeyframesOn());
-
- m_core->GetDispatch()->FireOnToolbarChange();
-}
-
-//==============================================================================
-/**
- * Updates the preferences, and AnimationSystem.
- */
-void CStudioApp::SetAutosetKeyframes(bool inFlag)
-{
- CStudioPreferences::SetAutosetKeyframesOn(inFlag);
-
- m_core->GetDoc()->GetStudioSystem()->GetAnimationSystem()->SetAutoKeyframe(inFlag);
-}
-
-//==============================================================================
-/**
- * If the presentation is not currently playing, this function will make it
- * start playing from the current position. The starting point of the playhead
- * is saved so that it can be restored later.
- */
-void CStudioApp::PlaybackPlay()
-{
- // Do not start playback if user is currently interacting with scene
- if (getRenderer().isMouseDown())
- return;
-
- CDoc *theDoc = m_core->GetDoc();
- if (!theDoc->IsPlaying()) {
- m_playbackTime = theDoc->GetCurrentViewTime();
- m_playbackOriginalSlide = theDoc->GetActiveSlide();
- theDoc->SetPlayMode(PLAYMODE_PLAY);
- }
-}
-
-//==============================================================================
-/**
- * If the presentation is currently playing, it is stopped. The playhead is
- * left wherever it was stopped at (hence it's not restored).
- */
-void CStudioApp::PlaybackStopNoRestore()
-{
- m_core->GetDoc()->SetPlayMode(PLAYMODE_STOP);
-}
-
-//==============================================================================
-/**
- * Moves the playhead back to time zero.
- */
-void CStudioApp::PlaybackRewind()
-{
- CDoc *theDoc = m_core->GetDoc();
- if (theDoc->IsPlaying()) {
- theDoc->SetPlayMode(PLAYMODE_STOP, 0);
- theDoc->SetPlayMode(PLAYMODE_PLAY);
- } else {
- m_core->GetDoc()->NotifyTimeChanged(0);
- }
-}
-
-bool CStudioApp::IsPlaying()
-{
- return m_core->GetDoc()->IsPlaying();
-}
-
-//=============================================================================
-/**
- * Performs a file revert.
- * This will revert the doc to the last saved version.
- */
-void CStudioApp::OnRevert()
-{
- if (!m_core->GetDoc()->isModified() || m_dialogs->ConfirmRevert()) {
- QString theCurrentDoc = m_core->GetDoc()->GetDocumentPath();
- OnLoadDocument(theCurrentDoc);
- }
-}
-
-//=============================================================================
-/**
- * Check to see if it is possible to perform a revert.
- */
-bool CStudioApp::CanRevert() const
-{
- return m_core->GetDoc()->isModified() && m_core->GetDoc()->isValid();
-}
-
-//==============================================================================
-/**
- * Handles the recent list.
- */
-void CStudioApp::OnFileOpenRecent(const QString &inDocument)
-{
- if (PerformSavePrompt())
- OnLoadDocument(inDocument);
-}
-
-//==============================================================================
-/**
- * Called when closing the current doc, this prompts the user to save the doc.
- * This will only prompt if the doc is modified, and if the user selects save
- * then this will perform the save operation.
- * @return true if the operation should continue, false if not.
- */
-bool CStudioApp::PerformSavePrompt()
-{
- if (m_core->GetDoc()->isModified()) {
- CDialogs::ESavePromptResult theResult = m_dialogs->PromptForSave();
- if (theResult == CDialogs::SAVE_FIRST) {
- bool onSaveResult = OnSave();
- if (onSaveResult)
- return true;
- } else if (theResult == CDialogs::CONTINUE_NO_SAVE) {
- return true;
- }
-
- return false;
- }
- return true;
-}
-
-//==============================================================================
-/**
- * If the presentation is currently playing, it is stopped. The playhead is
- * restored to the position found in m_PlaybackTime.
- */
-void CStudioApp::PlaybackStop()
-{
- CDoc *theDoc = m_core->GetDoc();
- // change it back to the original slide first before restoring the original time
- if (m_playbackOriginalSlide.Valid()) {
- if (m_playbackOriginalSlide != theDoc->GetActiveSlide())
- theDoc->NotifyActiveSlideChanged(m_playbackOriginalSlide);
- theDoc->SetPlayMode(PLAYMODE_STOP, m_playbackTime);
- }
- // Invalidate the playback original slide so we don't inadvertently trigger this code later.
- m_playbackOriginalSlide = 0;
-}
-
-//=============================================================================
-/**
- * Used for track wheel to do smooth tracking on mac, just scrolls the playhead.
- */
-void CStudioApp::AdvanceTime()
-{
- long theDeltaTime = CStudioPreferences::GetTimeAdvanceAmount();
- long theTime =
- (m_core->GetDoc()->GetCurrentViewTime() + theDeltaTime) / theDeltaTime * theDeltaTime;
- m_core->GetDoc()->NotifyTimeChanged(theTime);
-}
-
-//=============================================================================
-/**
- * Used for track wheel to do smooth tracking on mac, just scrolls the playhead.
- */
-void CStudioApp::ReduceTime()
-{
- long theDeltaTime = CStudioPreferences::GetTimeAdvanceAmount();
- long theTime = (m_core->GetDoc()->GetCurrentViewTime() - 1) / theDeltaTime * theDeltaTime;
- m_core->GetDoc()->NotifyTimeChanged(theTime);
-}
-
-//=============================================================================
-/**
- * Used for track wheel to do smooth tracking on mac, just scrolls the playhead.
- */
-void CStudioApp::AdvanceUltraBigTime()
-{
- long theDeltaTime = CStudioPreferences::GetBigTimeAdvanceAmount();
- long theTime =
- (m_core->GetDoc()->GetCurrentViewTime() + theDeltaTime) / theDeltaTime * theDeltaTime;
- m_core->GetDoc()->NotifyTimeChanged(theTime);
-}
-
-//=============================================================================
-/**
- * Used for track wheel to do smooth tracking on mac, just scrolls the playhead.
- */
-void CStudioApp::ReduceUltraBigTime()
-{
- long theDeltaTime = CStudioPreferences::GetBigTimeAdvanceAmount();
- long theTime = (m_core->GetDoc()->GetCurrentViewTime() - 1) / theDeltaTime * theDeltaTime;
- m_core->GetDoc()->NotifyTimeChanged(theTime);
-}
-
-//==============================================================================
-/**
- * If the presentation is currently playing, it is stopped. Otherwise, the
- * presetation starts playing from its current position. Called when the user
- * presses the Enter key.
- */
-void CStudioApp::PlaybackToggle()
-{
- // If the presentation is playing, stop it and leave the playhead where it is
- if (m_core->GetDoc()->IsPlaying())
- PlaybackStopNoRestore();
- // Otherwise, the presentation is stopped, so start it playing
- else
- PlaybackPlay();
-}
-
-// TODO: move to more appropriate place (InspectorControlModel.cpp)
-CInspectableBase *CStudioApp::getInspectableFromInstance(qt3dsdm::Qt3DSDMInstanceHandle inInstance)
-{
- CInspectableBase *inspectableBase = nullptr;
- CDoc *doc = m_core->GetDoc();
-
- if (doc->GetDocumentReader().IsInstance(inInstance)) {
- CClientDataModelBridge *theBridge = doc->GetStudioSystem()->GetClientDataModelBridge();
- qt3dsdm::Qt3DSDMSlideHandle activeSlide = doc->GetActiveSlide();
-
- // Slide, scene or component
- if (inInstance == theBridge->GetOwningComponentInstance(activeSlide)) {
- Qt3DSDMInstanceHandle activeSlideInstance = doc->GetStudioSystem()->GetSlideSystem()
- ->GetSlideInstance(activeSlide);
-
- inspectableBase = new Qt3DSDMInspectable(inInstance, activeSlideInstance);
- }
- if (!inspectableBase) {
- if (theBridge->IsMaterialBaseInstance(inInstance))
- inspectableBase = new Qt3DSDMMaterialInspectable(inInstance);
- else
- inspectableBase = new Qt3DSDMInspectable(inInstance);
- }
- }
-
- return inspectableBase;
-}
-
-void CStudioApp::RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler,
- QWidget *actionParent)
-{
- m_core->RegisterGlobalKeyboardShortcuts(inShortcutHandler, actionParent);
-
- ADD_GLOBAL_SHORTCUT(actionParent,
- QKeySequence(Qt::Key_Period),
- CStudioApp::AdvanceTime);
- ADD_GLOBAL_SHORTCUT(actionParent,
- QKeySequence(Qt::Key_Comma),
- CStudioApp::ReduceTime);
- ADD_GLOBAL_SHORTCUT(actionParent,
- QKeySequence(Qt::ShiftModifier | Qt::Key_Period),
- CStudioApp::AdvanceUltraBigTime);
- ADD_GLOBAL_SHORTCUT(actionParent,
- QKeySequence(Qt::ShiftModifier | Qt::Key_Comma),
- CStudioApp::ReduceUltraBigTime);
- ADD_GLOBAL_SHORTCUT(actionParent,
- QKeySequence(Qt::Key_Return),
- CStudioApp::PlaybackToggle);
-
- inShortcutHandler->RegisterKeyUpEvent(
- new CDynHotKeyConsumer<CStudioApp>(this, &CStudioApp::playbackPreviewEnd), 0,
- Qt::Key_Space);
- inShortcutHandler->RegisterKeyDownEvent(
- new CDynHotKeyConsumer<CStudioApp>(this, &CStudioApp::playbackPreviewStart), 0,
- Qt::Key_Space);
-
- if (m_views)
- m_views->registerGlobalKeyboardShortcuts(inShortcutHandler, actionParent);
-}
-
-void CStudioApp::playbackPreviewStart()
-{
- if (!m_playbackPreviewOn) {
- m_playbackPreviewOn = true;
- m_core->GetDoc()->setPlayBackPreviewState(true);
- PlaybackPlay();
- }
-}
-
-void CStudioApp::playbackPreviewEnd()
-{
- m_core->GetDoc()->setPlayBackPreviewState(false);
- m_playbackPreviewOn = false;
- PlaybackStop();
-}
-
-bool CStudioApp::isPlaybackPreviewOn() const
-{
- return m_playbackPreviewOn;
-}
-
-/**
- * Handles the Save command
- * This will save the file, if the file has not been saved before this will
- * do a save as operation.
- * @param autosave set true if triggering an autosave.
- * @return true if the file was successfully saved.
- */
-bool CStudioApp::OnSave(bool autosave)
-{
- Qt3DSFile theCurrentDoc = m_core->GetDoc()->GetDocumentPath();
- if (!theCurrentDoc.IsFile()) {
- return false;
- } else if (!theCurrentDoc.CanWrite()) {
- m_dialogs->DisplaySavingPresentationFailed();
- return false;
- } else {
- // Compose autosave filename (insert _autosave before extension)
- QString autosaveFile = theCurrentDoc.GetPath().toQString();
- int insertionPoint = autosaveFile.lastIndexOf(QLatin1String(".uip"));
- autosaveFile.insert(insertionPoint, QStringLiteral("_autosave"));
-
- if (autosave) {
- // Set the copy flag to avoid changing actual document name & history
- m_core->OnSaveDocument(autosaveFile, true);
- } else {
- m_core->OnSaveDocument(theCurrentDoc.GetAbsolutePath().toQString());
- // Delete previous autosave file
- QFile::remove(autosaveFile);
- }
-
- return true;
- }
-}
-
-/**
- * This will prompt the user for a location and name to save a copy of the project folder.
- * Saving under the current project is not possible.
- */
-void CStudioApp::onProjectSaveAs()
-{
- if (PerformSavePrompt()) {
- const QString newProj = m_dialogs->GetSaveAsChoice(QObject::tr("Save Project As"),
- true, true);
- if (!newProj.isEmpty()) {
- // Copy the project
- const QString currentProj = GetCore()->getProjectFile().getProjectPath();
- if (CFilePath::copyFolder(currentProj, newProj)) {
- // Prompt whether to open the new project
- QMessageBox box(m_pMainWnd);
- box.setWindowTitle(QObject::tr("Project copy saved successfully"));
- box.setText(QObject::tr("Continue working with the original project?"));
- box.setIcon(QMessageBox::Question);
- box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
- box.setButtonText(QMessageBox::No, QObject::tr("No, open the one I just saved"));
- box.setDefaultButton(QMessageBox::Yes);
- int choice = box.exec();
- if (choice == QMessageBox::No) {
- const QString newProjDoc = newProj
- + QDir::cleanPath(GetCore()->GetDoc()->GetDocumentPath()).mid(
- currentProj.length());
- QTimer::singleShot(0, [this, newProjDoc]() {
- OnLoadDocument(newProjDoc);
- });
- }
- } else {
- const QString title(QObject::tr("Project save failed"));
- const QString warning = QObject::tr("Failed to save the project as %1.")
- .arg(newProj);
- QMessageBox::warning(m_pMainWnd, title, warning);
- }
- }
- }
-}
-
-void CStudioApp::SetAutosaveEnabled(bool enabled)
-{
- if (enabled)
- m_autosaveTimer->start();
- else
- m_autosaveTimer->stop();
-}
-
-void CStudioApp::SetAutosaveInterval(int interval)
-{
- m_autosaveTimer->setInterval(interval * 1000);
-}
-
-//=============================================================================
-/**
- * Call to load a new document.
- * There should not be a currently active document when this is called.
- * @param inDocument the path to the UIP file to be loaded.
- * @param inShowStartupDialogOnError true to show startup dialog if loading document is error
- * @return true if loading was successful
- */
-bool CStudioApp::OnLoadDocument(const QString &inDocument, bool inShowStartupDialogOnError)
-{
- bool theLoadResult = false;
- QString theLoadErrorParameter;
- QString theErrorText;
- QString loadFile = resolvePresentationFile(inDocument);
- QFileInfo loadFileInfo(loadFile);
-
- m_core->GetDispatch()->FireOnProgressBegin(QObject::tr("Loading "), loadFileInfo.fileName());
-
- // Make sure scene is visible
- if (m_views)
- m_views->getMainFrame()->showScene();
-
- try {
- m_core->getProjectFile().initProjectFile(loadFile);
- OnLoadDocumentCatcher(loadFile);
- m_core->GetDispatch()->FireOnOpenDocument(loadFile, true);
- // Loading was successful
- theLoadResult = true;
- } catch (ProjectFileNotFoundException &) {
- theErrorText = tr("Project file was not found");
- // No project file (.uia) was found
- } catch (CUnsupportedFileFormatException &) {
- theErrorText = tr("The file could not be opened. It is either invalid or was made with an "
- "old version of Studio.");
- // We've encountered a file format that is older than the current, OR
- // corrupt files, unsupported file formats and illegal types.
- } catch (CInvalidFileFormatException &) {
- theErrorText = tr("The file could not be opened. The file format is invalid.");
- } catch (CLoadReferencedFileException &inError) {
- // referenced files (e.g. Data Files) failed to load
- theErrorText = tr("%1 failed to load due to invalid referenced file: %2.").arg(
- loadFileInfo.completeBaseName(), inError.GetFilePath());
- const QString theDesc = inError.GetDescription();
- if (!theDesc.isEmpty()) {
- // append any description is provided
- theErrorText += QStringLiteral("\n") + inError.GetDescription();
- }
- } catch (CIOException &) { // provide specific error message if possible
- if (!loadFileInfo.exists())
- theLoadErrorParameter = tr(" does not exist.");
- qCCritical(qt3ds::INTERNAL_ERROR)
- << "Failed to load document, IO error (file may be unreadable or nonexistent)";
- } catch (...) {
- qCCritical(qt3ds::INTERNAL_ERROR) << "Failed to load document, unknown error";
- // We don't know exactly what went wrong during a load, but let studio 'fail gracefully'.
- }
-
- if (!theErrorText.isEmpty()) {
- qCCritical(qt3ds::INTERNAL_ERROR) << "Failed to load document: "
- << theErrorText;
- }
-
- m_core->GetDispatch()->FireOnProgressEnd();
-
- // load fail
- if (!theLoadResult) {
-#if (defined Q_OS_MACOS)
- m_fileOpenEvent = false;
-#endif
- if (!theErrorText.isEmpty()) {
- m_dialogs->DisplayKnownErrorDialog(theErrorText);
- } else {
- m_dialogs->DisplayLoadingPresentationFailed(loadFileInfo, inDocument,
- theLoadErrorParameter);
- }
-
- m_core->GetDispatch()->FireOnOpenDocument(loadFile, false);
-
- // Show startup dialog
- if (inShowStartupDialogOnError) {
- if (!showStartupDialog())
- qApp->quit();
- }
- } else {
- m_dialogs->ResetSettings(loadFile);
- m_core->getProjectFile().updateDocPresentationId();
- m_core->getProjectFile().loadSubpresentationsAndDatainputs(m_subpresentations,
- m_dataInputDialogItems);
- m_core->getProjectFile().loadVariants();
- GetViews()->getMainFrame()->getSlideView()->refreshVariants();
- getRenderer().RegisterSubpresentations(m_subpresentations);
-
- m_authorZoom = false;
-
- m_core->GetDispatch()->FireAuthorZoomChanged();
- verifyDatainputBindings();
- checkDeletedDatainputs();
- }
-
- return theLoadResult;
-}
-
-void CStudioApp::saveDataInputsToProjectFile()
-{
- m_core->getProjectFile().ensureProjectFile();
-
- QDomDocument doc;
- QSaveFile file(m_core->getProjectFile().getProjectFilePath());
- if (!StudioUtils::openDomDocumentSave(file, doc))
- return;
-
- QDomElement assetsNode = doc.documentElement().firstChildElement(QStringLiteral("assets"));
-
- if (!assetsNode.isNull()) {
- // remove old dataInput nodes
- for (int i = assetsNode.childNodes().count() - 1; i >= 0; --i) {
- QDomNode node_i = assetsNode.childNodes().at(i);
- if (node_i.nodeName() == QLatin1String("dataInput"))
- assetsNode.removeChild(node_i);
- }
-
- // add the new dataInputs
- for (CDataInputDialogItem *item : qAsConst(m_dataInputDialogItems)) {
- QDomElement diNode = doc.createElement(QStringLiteral("dataInput"));
- diNode.setAttribute(QStringLiteral("name"), item->name);
-
- if (item->type == EDataType::DataTypeRangedNumber) {
- diNode.setAttribute(QStringLiteral("type"), QStringLiteral("Ranged Number"));
- diNode.setAttribute(QStringLiteral("min"), item->minValue);
- diNode.setAttribute(QStringLiteral("max"), item->maxValue);
- } else if (item->type == EDataType::DataTypeString) {
- diNode.setAttribute(QStringLiteral("type"), QStringLiteral("String"));
- } else if (item->type == EDataType::DataTypeFloat) {
- diNode.setAttribute(QStringLiteral("type"), QStringLiteral("Float"));
- } else if (item->type == EDataType::DataTypeBoolean) {
- diNode.setAttribute(QStringLiteral("type"), QStringLiteral("Boolean"));
- } else if (item->type == EDataType::DataTypeVector4) {
- diNode.setAttribute(QStringLiteral("type"), QStringLiteral("Vector4"));
- } else if (item->type == EDataType::DataTypeVector3) {
- diNode.setAttribute(QStringLiteral("type"), QStringLiteral("Vector3"));
- } else if (item->type == EDataType::DataTypeVector2) {
- diNode.setAttribute(QStringLiteral("type"), QStringLiteral("Vector2"));
- } else if (item->type == EDataType::DataTypeVariant) {
- diNode.setAttribute(QStringLiteral("type"), QStringLiteral("Variant"));
- }
-#ifdef DATAINPUT_EVALUATOR_ENABLED
- else if (item->type == EDataType::DataTypeEvaluator) {
- diNode.setAttribute(QStringLiteral("type"), QStringLiteral("Evaluator"));
- diNode.setAttribute(QStringLiteral("evaluator"), item->valueString);
- }
-#endif
-
- QHashIterator<QString, QString> it(item->metadata);
- QString metadataStr;
- while (it.hasNext()) {
- it.next();
- metadataStr.append(it.key() + QLatin1Char('$') + it.value() + QLatin1Char('$'));
- }
- metadataStr.chop(1);
-
- diNode.setAttribute(QStringLiteral("metadata"), metadataStr.trimmed());
-
- assetsNode.appendChild(diNode);
- }
- StudioUtils::commitDomDocumentSave(file, doc);
- }
-}
-
-QString CStudioApp::getMostRecentDirectory() const
-{
- QFileInfo mostRecentDirectory = QFileInfo(QStringLiteral("."));
- if (m_views) {
- CRecentItems *recentItems = m_views->getMainFrame()->GetRecentItems();
- if (recentItems->GetItemCount() > 0) {
- mostRecentDirectory
- = QFileInfo(recentItems->GetItem(0)).path();
- }
- }
- return mostRecentDirectory.absoluteFilePath();
-}
-
-QString CStudioApp::getMostRecentProjectParentDir() const
-{
- QString parentDirectory(QStringLiteral("."));
- if (m_views) {
- CRecentItems *recentItems = m_views->getMainFrame()->GetRecentItems();
- if (recentItems->GetItemCount() > 0) {
- QString mostRecentPresentation = recentItems->GetItem(0);
- QFileInfo projectFile(PresentationFile::findProjectFile(mostRecentPresentation));
- if (!projectFile.exists())
- projectFile.setFile(mostRecentPresentation);
- if (!projectFile.exists()) {
- parentDirectory = QStandardPaths::writableLocation(
- QStandardPaths::DocumentsLocation);
- } else {
- QDir dir = projectFile.absoluteDir();
- dir.cdUp();
- parentDirectory = dir.absolutePath();
- }
- }
- }
- return parentDirectory;
-}
-
-bool CStudioApp::isQmlStream(const QString &fileName)
-{
- bool retval = false;
- if (m_qmlStreamMap.contains(fileName)) {
- retval = m_qmlStreamMap[fileName];
- } else {
- if (!fileName.endsWith(QLatin1String(".qml")) || !QFileInfo(fileName).exists()) {
- return false; // Don't pollute the map with non-qml or nonexistent files
- } else {
- QQmlApplicationEngine qmlEngine(fileName);
- if (qmlEngine.rootObjects().size() > 0) {
- const char *rootClassName = qmlEngine.rootObjects().at(0)
- ->metaObject()->superClass()->className();
- retval = strcmp(rootClassName, "Q3DStudio::Q3DSQmlBehavior") != 0;
- }
- }
- m_qmlStreamMap.insert(fileName, retval);
- }
- return retval;
-}
-
-/**
- * Called by OnLoadDocument, to allow the error reporting to be inserted.
- * Because of the nature of the error reporting, OnLoadDocument has to have
- * a certain structure that limits it (C type variables, no object destructors).
- */
-void CStudioApp::OnLoadDocumentCatcher(const QString &inDocument)
-{
- {
- CDispatchDataModelNotificationScope __scope(*m_core->GetDispatch());
-
- // CloseDocument() clears all the OpenGL buffers so it needs the correct context
- getRenderer().MakeContextCurrent();
- m_core->GetDoc()->CloseDocument();
- getRenderer().ReleaseContext();
-
- m_core->GetDoc()->LoadDocument(inDocument);
- }
-
- // Make sure the client scene is resized properly
- if (m_views)
- m_views->recheckMainframeSizingMode();
-}
-
-void CStudioApp::OnFileOpen()
-{
- if (PerformSavePrompt()) {
- QString theFile = m_dialogs->GetFileOpenChoice(getMostRecentDirectory());
- if (!theFile.isEmpty())
- OnLoadDocument(theFile);
- }
-}
-
-/**
- * Create a new project
- * this creates the project file (.uia), asset folders, and a default .uip file
- */
-QString CStudioApp::OnProjectNew()
-{
- if (PerformSavePrompt()) {
- QString theFile = m_dialogs->GetNewDocumentChoice(getMostRecentProjectParentDir(), true);
- if (!theFile.isEmpty()) {
- if (!m_core->OnNewDocument(theFile, true))
- showInvalidFilenameWarning();
- }
- }
- return {};
-}
-
-/**
- * Create a new presentation
- * this creates a .uip file
- */
-void CStudioApp::OnFileNew()
-{
- if (PerformSavePrompt()) {
- QString theFile = m_dialogs->GetNewDocumentChoice(getMostRecentDirectory(), false);
- if (!theFile.isEmpty() && !m_core->OnNewDocument(theFile, false))
- showInvalidFilenameWarning();
- }
-}
-
-bool CStudioApp::IsAuthorZoom() const
-{
- return m_authorZoom;
-}
-
-bool CStudioApp::isOnProgress() const
-{
- return m_isOnProgress;
-}
-
-void CStudioApp::SetAuthorZoom(bool inZoom)
-{
- if (m_authorZoom != inZoom) {
- m_authorZoom = inZoom;
- m_core->GetDispatch()->FireAuthorZoomChanged();
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// These commands come over the dispatch from inside the core. The core doesn't
-// have access to the CMsgRouter at the moment, so this relays the message.
-void CStudioApp::OnAsynchronousCommand(CCmd *inCmd)
-{
- CMsgRouter::GetInstance()->SendCommand(inCmd, m_core);
-}
-
-void CStudioApp::OnDisplayAppStatus(const QString &inStatusMsg)
-{
- // Do nothing, it was used to show this in the status bar
-}
-
-void CStudioApp::OnProgressBegin(const QString &inActionText,
- const QString &inAdditionalText)
-{
- m_isOnProgress = true;
- m_dialogs->DisplayProgressScreen(inActionText, inAdditionalText);
-}
-
-void CStudioApp::OnProgressEnd()
-{
- m_dialogs->DestroyProgressScreen();
- QTimer::singleShot(0, [this]() {
- m_isOnProgress = false;
- });
-}
-
-void CStudioApp::OnAssetDeleteFail()
-{
- m_dialogs->DisplayAssetDeleteFailed();
-}
-
-void CStudioApp::OnPasteFail()
-{
- m_dialogs->DisplayPasteFailed();
-}
-
-void CStudioApp::OnBuildconfigurationFileParseFail(const QString &inMessage)
-{
- m_dialogs->DisplayMessageBox(tr("Build Configurations Error"), inMessage,
- Qt3DSMessageBox::ICON_ERROR, false);
-}
-
-void CStudioApp::OnSaveFail(bool inKnownError)
-{
- qCCritical(qt3ds::INTERNAL_ERROR) << "Failed to save project: "
- << (inKnownError ? "KnownError" : "UnknownError");
- if (inKnownError)
- m_dialogs->DisplaySavingPresentationFailed();
- else
- m_dialogs->DisplayKnownErrorDialog(tr("Unknown error encountered while saving."));
-}
-
-void CStudioApp::OnErrorFail(const QString &inText)
-{
- qCCritical(qt3ds::INTERNAL_ERROR) << inText;
- m_dialogs->DisplayMessageBox(tr("Qt 3D Studio"), inText, Qt3DSMessageBox::ICON_ERROR, false);
-}
-
-void CStudioApp::OnRefreshResourceFail(const QString &inResourceName, const QString &inDescription)
-{
- qCCritical(qt3ds::INTERNAL_ERROR) << "Failed to refresh resource: "
- << inResourceName;
- qCCritical(qt3ds::INTERNAL_ERROR) << inDescription;
- m_dialogs->DisplayRefreshResourceFailed(inResourceName, inDescription);
-}
-
-void CStudioApp::OnNewPresentation()
-{
- m_core->GetDoc()->GetStudioSystem()->GetAnimationSystem()->SetAutoKeyframe(
- CStudioPreferences::IsAutosetKeyframesOn());
- qCInfo(qt3ds::TRACE_INFO) << "New Presentation: "
- << m_core->GetDoc()->GetDocumentPath();
-}
-
-void CStudioApp::OnPresentationModifiedExternally()
-{
- int theUserChoice = m_dialogs->DisplayChoiceBox(
- tr("Warning!"),
- tr("This project has changed on disk. Do you want to reload it?"),
- Qt3DSMessageBox::ICON_WARNING);
- if (theUserChoice == IDYES) {
- QString theCurrentDoc = m_core->GetDoc()->GetDocumentPath();
- OnLoadDocument(theCurrentDoc);
- }
-}
-
-// Converts a renderable path to the format used in the SubPresentationRecord struct
-// filePath can be absolute or relative to either presentation or project
-QString CStudioApp::getRenderablePath(const QString &filePath) const
-{
- QString renderablePath;
- QDir projectDir(m_core->getProjectFile().getProjectPath());
- const QString projectPath = QDir::cleanPath(projectDir.absolutePath());
- int index = projectPath.length() + 1;
- QFileInfo fi(filePath);
- if (fi.isAbsolute()) {
- renderablePath = filePath.mid(index);
- } else {
- QFileInfo presFile(m_core->GetDoc()->GetDocumentPath());
- QDir presDir(presFile.absoluteDir());
- QString checkFile = QDir::cleanPath(presDir.absoluteFilePath(filePath));
- if (!QFileInfo(checkFile).exists()) {
- checkFile = QDir::cleanPath(projectDir.absoluteFilePath(filePath));
- if (!QFileInfo(checkFile).exists())
- return {};
- }
- renderablePath = checkFile.mid(index);
- }
- return renderablePath;
-}
-
-// Get the presentation id, returns an empty string for qml streams
-// filePath can be absolute or relative to either presentation or project
-QString CStudioApp::getPresentationId(const QString &filePath) const
-{
- QString renderablePath = getRenderablePath(filePath);
- for (SubPresentationRecord r : qAsConst(m_subpresentations)) {
- if (r.m_type == QLatin1String("presentation") && r.m_argsOrSrc == renderablePath)
- return r.m_id;
- }
- return {};
-}
-
-// Get the qml stream id, returns an empty string for presentations
-// filePath can be absolute or relative to either presentation or project
-QString CStudioApp::getQmlId(const QString &filePath) const
-{
- QString renderablePath = getRenderablePath(filePath);
- for (SubPresentationRecord r : qAsConst(m_subpresentations)) {
- if (r.m_type == QLatin1String("presentation-qml") && r.m_argsOrSrc == renderablePath)
- return r.m_id;
- }
- return {};
-}
-
-// Get the renderable id for a file path.
-// filePath can be absolute or relative to either presentation or project
-QString CStudioApp::getRenderableId(const QString &filePath) const
-{
- QString renderablePath = getRenderablePath(filePath);
- for (SubPresentationRecord r : qAsConst(m_subpresentations)) {
- if (r.m_argsOrSrc == renderablePath)
- return r.m_id;
- }
- return {};
-}
-
-QString CStudioApp::getRenderableAbsolutePath(const QString &renderableId) const
-{
- for (SubPresentationRecord r : qAsConst(m_subpresentations)) {
- if (r.m_id == renderableId) {
- QDir projectDir(m_core->getProjectFile().getProjectPath());
- return QDir::cleanPath(projectDir.absoluteFilePath(r.m_argsOrSrc));
- }
- }
- return {};
-}
-
-// Returns renderable size in pixels.
-QSize CStudioApp::getRenderableSize(const QString &renderableId)
-{
- for (int i = 0; i < m_subpresentations.size(); ++i) {
- SubPresentationRecord &r = m_subpresentations[i];
- if (r.m_id == renderableId) {
- if (!r.m_size.isValid()) {
- QDir projectDir(m_core->getProjectFile().getProjectPath());
- QString path = QDir::cleanPath(projectDir.absoluteFilePath(r.m_argsOrSrc));
- QString type = r.m_type;
- if (type == QLatin1String("presentation")) {
- r.m_size = PresentationFile::readSize(path);
- } else { // QML stream
- QQmlApplicationEngine qmlEngine(path);
- if (qmlEngine.rootObjects().size() > 0) {
- QQuickItem *item = qobject_cast<QQuickItem *>(qmlEngine.rootObjects().at(0));
- if (item)
- r.m_size = QSize(qRound(item->width()), qRound(item->height()));
- }
- }
- }
- return r.m_size;
- }
- }
- return {};
-}
-
-void CStudioApp::OnUndefinedDatainputsFail(
- const QMultiMap<QString, QPair<qt3dsdm::Qt3DSDMInstanceHandle,
- qt3dsdm::Qt3DSDMPropertyHandle>> *map)
-{
- bool res = m_dialogs->DisplayUndefinedDatainputDlg(map);
-
- // Delete invalid datainput bindings if user prompted so.
- if (res) {
- m_core->GetDoc()->RemoveDatainputBindings(map);
- // clear commands as we do not want to create undo point
- // for automatic datainput deletion
- m_core->GetCmdStack()->Clear();
- }
-}
-
-void CStudioApp::toggleEyeball()
-{
- CDoc *doc = m_core->GetDoc();
- if (doc->getSelectedInstancesCount() > 0) {
- qt3dsdm::Qt3DSDMPropertyHandle property
- = doc->GetStudioSystem()->GetClientDataModelBridge()->GetSceneAsset().m_Eyeball;
- SCOPED_DOCUMENT_EDITOR(*doc, tr("Visibility Toggle"))
- ->toggleBoolPropertyOnSelected(property);
- }
-}
-
-void CStudioApp::toggleShy()
-{
- CDoc *doc = m_core->GetDoc();
- if (doc->getSelectedInstancesCount() > 0) {
- qt3dsdm::Qt3DSDMPropertyHandle property
- = doc->GetStudioSystem()->GetClientDataModelBridge()->GetSceneAsset().m_Shy;
- SCOPED_DOCUMENT_EDITOR(*doc, tr("Shy Toggle"))
- ->toggleBoolPropertyOnSelected(property);
- }
-}
-
-void CStudioApp::toggleLocked()
-{
- CDoc *doc = m_core->GetDoc();
- if (doc->getSelectedInstancesCount() > 0) {
- qt3dsdm::Qt3DSDMPropertyHandle property
- = doc->GetStudioSystem()->GetClientDataModelBridge()->GetSceneAsset().m_Locked;
- SCOPED_DOCUMENT_EDITOR(*doc, tr("Locked Toggle"))
- ->toggleBoolPropertyOnSelected(property);
-
- // Since you are not supposed to be able to select locked objects,
- // we just assume anything toggled was actually locked and deselect everything
- doc->DeselectAllItems();
- }
-}
-
-void CStudioApp::showPresentationIdUniqueWarning()
-{
- m_dialogs->DisplayMessageBox(tr("Warning"),
- tr("Presentation Id must be unique."),
- Qt3DSMessageBox::ICON_WARNING, false);
-}
-
-void CStudioApp::showPresentationIdEmptyWarning()
-{
- m_dialogs->DisplayMessageBox(tr("Warning"),
- tr("Presentation Id must not be empty."),
- Qt3DSMessageBox::ICON_WARNING, false);
-}
-
-void CStudioApp::showInvalidFilenameWarning()
-{
- m_dialogs->DisplayMessageBox(tr("Invalid filename"),
- tr("The filename given was invalid."),
- Qt3DSMessageBox::ICON_WARNING, false);
-}
-
-void CStudioApp::checkDeletedDatainputs()
-{
- QMultiMap<QString, QPair<qt3dsdm::Qt3DSDMInstanceHandle, qt3dsdm::Qt3DSDMPropertyHandle>> *map;
- map = new QMultiMap<QString, QPair<qt3dsdm::Qt3DSDMInstanceHandle,
- qt3dsdm::Qt3DSDMPropertyHandle>>;
- auto doc = m_core->GetDoc();
- // Update datainputs for the currently open presentation
- doc->UpdateDatainputMap(map);
-
- if (!map->empty())
- m_core->GetDispatch()->FireOnUndefinedDatainputsFail(map);
-
- // Update allowed property types for datainput-controlled properties
- // in subpresentations. It is ok to do this once
- // at the project opening, as the assumption is that subpresentation files
- // do not change while we are editing currently open presentation.
-
- // Clear the old subpresentation binding info only.
- for (auto it : qAsConst(m_dataInputDialogItems))
- it->externalPresBoundTypes.clear();
-
- const QMultiMap<QString, QPair<QString, QString>> spDatainputs
- = GetCore()->getProjectFile().getDiBindingtypesFromSubpresentations();
-
- // For datainput bindings in subpresentations we do not have specific
- // instance and/or property handles. Get the datatype for property using
- // the generic name string and leave instance/property handle empty.
- for (auto sp = spDatainputs.cbegin(); sp != spDatainputs.cend(); ++sp) {
- const QString propName = sp->second;
- CDataInputDialogItem *item = m_dataInputDialogItems.find(sp->first).value();
- QPair<qt3dsdm::DataModelDataType::Value, bool> spEntry;
- if (propName == QLatin1String("@timeline")) {
- spEntry.first = qt3dsdm::DataModelDataType::Value::RangedNumber;
- spEntry.second = true;
- } else if (propName == QLatin1String("@slide")) {
- spEntry.first = qt3dsdm::DataModelDataType::Value::String;
- spEntry.second = true;
- } else {
- qt3dsimp::SImportComposerTypes theTypes;
- qt3dsimp::SImportAsset &theAsset(theTypes.GetImportAssetForType(
- qt3dsdm::ComposerObjectTypes::ControllableObject));
- qt3dsdm::DataModelDataType::Value theType(
- theAsset.GetPropertyDataType(propName.toStdWString().c_str()));
- spEntry.first = theType;
- spEntry.second = false;
- }
-
- item->externalPresBoundTypes.insert(sp.key(), spEntry);
- }
-}
-
-void CStudioApp::verifyDatainputBindings()
-{
- m_core->GetDoc()->getSceneEditor()->BeginAggregateOperation();
- bool res = m_core->GetDoc()->VerifyControlledProperties(
- m_core->GetDoc()->GetActiveRootInstance());
- m_core->GetDoc()->getSceneEditor()->EndAggregateOperation();
-
- if (!res) {
- // we remove invalid control bindings directly without transaction, so
- // we need to explicitly fire notification in order to update UI
- m_core->GetDispatch()->FireEndDataModelNotifications();
- m_core->GetDoc()->SetModifiedFlag(true);
- m_dialogs->DisplayMessageBox(tr("Invalid datainput usage in UIP file"),
- tr("Some objects had invalid datainput control bindings."
- " Invalid entries have been removed."),
- Qt3DSMessageBox::ICON_WARNING, false);
- }
-}
-
-/**
-* This will prompt the user for a new name for the duplicated presentation and copy the current
-* presentation with that name in the same folder as the original. The new presentation is added
-* to the project and gets autogenerated id. The new presentation is made current.
-*/
-void CStudioApp::duplicatePresentation(const QString &presFile)
-{
- QString thePresFile = presFile;
- bool qmlStream = presFile.endsWith(QLatin1String(".qml"));
- if (presFile.isEmpty())
- thePresFile = GetCore()->GetDoc()->GetDocumentPath();
-
- if (qmlStream || PerformSavePrompt()) {
- QFileInfo fi(thePresFile);
- QString relativePresPath = QDir(GetCore()->getProjectFile().getProjectPath())
- .relativeFilePath(fi.absoluteFilePath());
-
- EditPresentationIdDlg dlg(relativePresPath,
- qmlStream ? EditPresentationIdDlg::DuplicateQmlStream
- : EditPresentationIdDlg::DuplicatePresentation,
- m_pMainWnd);
- dlg.exec();
- const QString newPres = dlg.getDuplicateFile();
- if (!qmlStream && !newPres.isEmpty())
- OnLoadDocument(newPres);
- }
-}