Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions interface/src/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <QtCore/QMimeData>
#include <QtCore/QThreadPool>
#include <QtCore/QFileSelector>
#include <QtCore/QSaveFile>
#include <QtConcurrent/QtConcurrentRun>

#include <QtGui/QClipboard>
Expand All @@ -51,7 +52,7 @@
#include <QFontDatabase>
#include <QProcessEnvironment>
#include <QTemporaryDir>

#include <QTextStream>

#include <gl/QOpenGLContextWrapper.h>
#include <gl/GLWindow.h>
Expand Down Expand Up @@ -5388,6 +5389,36 @@ ivec2 Application::getMouse() const {
return getApplicationCompositor().getReticlePosition();
}

void Application::setInterfaceScriptDataPath(const QString& dataPath) {
interfaceScriptDataPath = dataPath;
}

bool Application::exportData(const QString& dataString) {
qCDebug(interfaceapp, "Saving data to file %s...", interfaceScriptDataPath);

QSaveFile persistFile(interfaceScriptDataPath);
bool success = false;
if (persistFile.open(QIODevice::WriteOnly)) {
if (persistFile.write(dataString.toUtf8()) != -1) {
success = persistFile.commit();
if (!success) {
qCritical() << "Failed to commit to text save file:" << persistFile.errorString();
}
} else {
qCritical("Failed to write to text file.");
}
} else {
qCritical("Failed to open text file for writing.");
}

if (success) {
// restore the main window's active state
_window->activateWindow();
}

return success;
}

bool Application::exportEntities(const QString& filename,
const QVector<QUuid>& entityIDs,
const glm::vec3* givenOffset) {
Expand Down Expand Up @@ -8712,7 +8743,7 @@ void Application::notifyPacketVersionMismatch() {
}

void Application::checkSkeleton() const {
if (getMyAvatar()->getSkeletonModel()->isLoaded() && !getMyAvatar()->getSkeletonModel()->hasSkeleton()) {
if (getMyAvatar()->getSkeletonModel()->isActive() && !getMyAvatar()->getSkeletonModel()->hasSkeleton()) {
qCDebug(interfaceapp) << "MyAvatar model has no skeleton";

QString message = "Your selected avatar body has no skeleton.\n\nThe default body will be loaded...";
Expand Down
5 changes: 5 additions & 0 deletions interface/src/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ class Application : public QApplication,

void setActiveDisplayPlugin(const QString& pluginName);

void setInterfaceScriptDataPath(const QString& dataPath);

#ifndef Q_OS_ANDROID
FileLogger* getLogger() const { return _logger; }
#endif
Expand Down Expand Up @@ -377,6 +379,7 @@ class Application : public QApplication,

public slots:
QVector<EntityItemID> pasteEntities(const QString& entityHostType, float x, float y, float z);
bool exportData(const QString& dataString);
bool exportEntities(const QString& filename, const QVector<QUuid>& entityIDs, const glm::vec3* givenOffset = nullptr);
bool exportEntities(const QString& filename, float x, float y, float z, float scale);
bool importEntities(const QString& url, const bool isObservable = true, const qint64 callerId = -1);
Expand Down Expand Up @@ -708,6 +711,8 @@ private slots:

bool _notifiedPacketVersionMismatchThisDomain;

QString interfaceScriptDataPath;

ConditionalGuard _settingsGuard;

GLCanvas* _glWidget{ nullptr };
Expand Down
9 changes: 9 additions & 0 deletions interface/src/scripting/ClipboardScriptingInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// interface/src/scripting
//
// Copyright 2014 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
Expand All @@ -25,6 +26,14 @@ float ClipboardScriptingInterface::getClipboardContentsLargestDimension() {
return qApp->getEntityClipboard()->getContentsLargestDimension();
}

bool ClipboardScriptingInterface::exportData(const QString& dataString) {
bool retVal;
BLOCKING_INVOKE_METHOD(qApp, "exportData",
Q_RETURN_ARG(bool, retVal),
Q_ARG(const QString&, dataString));
return retVal;
}

bool ClipboardScriptingInterface::exportEntities(const QString& filename, const QVector<QUuid>& entityIDs) {
bool retVal;
BLOCKING_INVOKE_METHOD(qApp, "exportEntities",
Expand Down
10 changes: 10 additions & 0 deletions interface/src/scripting/ClipboardScriptingInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// interface/src/scripting
//
// Copyright 2014 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
Expand Down Expand Up @@ -112,6 +113,15 @@ class ClipboardScriptingInterface : public QObject {
* @returns {boolean} <code>true</code> if entities were found and the file was written, otherwise <code>false</code>.
*/
Q_INVOKABLE bool exportEntities(const QString& filename, float x, float y, float z, float scale);

/**jsdoc
* Export a string of data to a file path previously set by Window.setInterfaceD
* @function Clipboard.exportData
* @variation 0
* @param {string} data - The string of data to export. (If exporting JSON, use JSON.stringify() first.)
* @returns {boolean} <code>true</code> if the file was written, otherwise <code>false</code>.
*/
Q_INVOKABLE bool exportData(const QString& dataString);

/**jsdoc
* Pastes the contents of the clipboard into the domain.
Expand Down
15 changes: 14 additions & 1 deletion interface/src/scripting/WindowScriptingInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,19 @@ QScriptValue WindowScriptingInterface::save(const QString& title, const QString&
return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
}

/// Display a save file dialog. If `directory` is an invalid file or directory the browser will start at the current
/// working directory.
/// \param const QString& title title of the window
/// \param const QString& directory directory to start the file browser at
/// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog`
/// \return QScriptValue file path as a string if one was selected, otherwise `QScriptValue::NullValue`
QScriptValue WindowScriptingInterface::setInterfaceScriptDataPath(const QString& title, const QString& directory, const QString& nameFilter) {
QScriptValue result = WindowScriptingInterface::save(title, directory, nameFilter);
QString resultString = result.toString();
qApp->setInterfaceScriptDataPath(resultString);
return resultString.isEmpty() ? QScriptValue::NullValue : result;
}

/// Display a save file dialog. If `directory` is an invalid file or directory the browser will start at the current
/// working directory.
/// \param const QString& title title of the window
Expand Down Expand Up @@ -467,7 +480,7 @@ void WindowScriptingInterface::copyToClipboard(const QString& text) {


bool WindowScriptingInterface::setDisplayTexture(const QString& name) {
return qApp->getActiveDisplayPlugin()->setDisplayTexture(name); // Plugins that don't know how, answer false.
return qApp->getActiveDisplayPlugin()->setDisplayTexture(name); // Plugins that don't know how, answer false.
}

void WindowScriptingInterface::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio, const QString& filename) {
Expand Down
18 changes: 18 additions & 0 deletions interface/src/scripting/WindowScriptingInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,24 @@ public slots:
*/
QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");

/**jsdoc
* Prompts the user to specify the path and name of a file to use as the script data path. Displays a modal dialog that navigates the directory
* tree and allows the user to type in a file name.
* @function Window.setInterfaceScriptDataPath
* @param {string} [title=""] - The title to display at the top of the dialog.
* @param {string} [directory=""] - The initial directory to start browsing at.
* @param {string} [nameFilter=""] - The types of files to display. Examples: <code>"*.json"</code> and
* <code>"Images (*.png *.jpg *.svg)"</code>. All files are displayed if a filter isn't specified.
* @returns {string} The path and name of the file if one is specified, otherwise <code>null</code>. If a single file type
* is specified in the nameFilter, that file type extension is automatically appended to the result when appropriate.
* @example <caption>Ask the user to specify a file to save to.</caption>
* var filename = Window.setInterfaceScriptDataPath("Save to JSON file", Paths.resources, "*.json");
* print("File: " + filename);
*/
QScriptValue setInterfaceScriptDataPath(const QString& title = "",
const QString& directory = "",
const QString& nameFilter = "");

/**jsdoc
* Prompts the user to specify the path and name of a file to save to. Displays a non-modal dialog that navigates the
* directory tree and allows the user to type in a file name. A {@link Window.saveFileChanged|saveFileChanged} signal is
Expand Down