From bd409f2de48d833f8f9ab8f61615acddc8baca70 Mon Sep 17 00:00:00 2001 From: Bennett Goble Date: Sun, 3 Aug 2014 14:01:37 -0400 Subject: [PATCH] importVoxels() JS override: specify file and location --- interface/interface_en.ts | 12 +- interface/src/Application.cpp | 21 +-- interface/src/Application.h | 5 +- .../scripting/ClipboardScriptingInterface.cpp | 31 ++++ .../scripting/ClipboardScriptingInterface.h | 3 + ...ImportDialog.cpp => VoxelImportDialog.cpp} | 133 +++++++++++++----- .../{ImportDialog.h => VoxelImportDialog.h} | 36 +++-- interface/src/voxels/VoxelImporter.cpp | 115 +++++---------- interface/src/voxels/VoxelImporter.h | 23 +-- 9 files changed, 217 insertions(+), 162 deletions(-) rename interface/src/ui/{ImportDialog.cpp => VoxelImportDialog.cpp} (77%) rename interface/src/ui/{ImportDialog.h => VoxelImportDialog.h} (74%) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 6c4426b2c6..b85628b104 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -245,28 +245,28 @@ QObject - - + + Import Voxels - + Loading ... - + Place voxels - + <b>Import</b> %1 as voxels - + Cancel diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 51f6076e7a..3caf9b2f5f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -137,7 +137,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _frameCount(0), _fps(60.0f), _justStarted(true), - _voxelImporter(NULL), + _voxelImportDialog(NULL), + _voxelImporter(), _importSucceded(false), _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard), _wantToKillLocalVoxels(false), @@ -428,7 +429,7 @@ Application::~Application() { delete idleTimer; _sharedVoxelSystem.changeTree(new VoxelTree); - delete _voxelImporter; + delete _voxelImportDialog; // let the avatar mixer know we're out MyAvatar::sendKillAvatar(); @@ -463,8 +464,8 @@ void Application::saveSettings() { Menu::getInstance()->saveSettings(); _rearMirrorTools->saveSettings(_settings); - if (_voxelImporter) { - _voxelImporter->saveSettings(_settings); + if (_voxelImportDialog) { + _voxelImportDialog->saveSettings(_settings); } _settings->sync(); _numChangedSettings = 0; @@ -1568,17 +1569,17 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) { void Application::importVoxels() { _importSucceded = false; - if (!_voxelImporter) { - _voxelImporter = new VoxelImporter(_window); - _voxelImporter->loadSettings(_settings); + if (!_voxelImportDialog) { + _voxelImportDialog = new VoxelImportDialog(_window); + _voxelImportDialog->loadSettings(_settings); } - if (!_voxelImporter->exec()) { + if (!_voxelImportDialog->exec()) { qDebug() << "Import succeeded." << endl; _importSucceded = true; } else { qDebug() << "Import failed." << endl; - if (_sharedVoxelSystem.getTree() == _voxelImporter->getVoxelTree()) { + if (_sharedVoxelSystem.getTree() == _voxelImporter.getVoxelTree()) { _sharedVoxelSystem.killLocalVoxels(); _sharedVoxelSystem.changeTree(&_clipboard); } @@ -1680,7 +1681,7 @@ void Application::init() { // Cleanup of the original shared tree _sharedVoxelSystem.init(); - _voxelImporter = new VoxelImporter(_window); + _voxelImportDialog = new VoxelImportDialog(_window); _environment.init(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 54fb25839a..8c0a999370 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -86,6 +86,7 @@ #include "ui/overlays/Overlays.h" #include "ui/ApplicationOverlay.h" #include "ui/RunningScriptsWidget.h" +#include "ui/VoxelImportDialog.h" #include "voxels/VoxelFade.h" #include "voxels/VoxelHideShowThread.h" #include "voxels/VoxelImporter.h" @@ -192,6 +193,7 @@ public: Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; } + VoxelImporter* getVoxelImporter() { return &_voxelImporter; } VoxelSystem* getVoxels() { return &_voxels; } VoxelTree* getVoxelTree() { return _voxels.getTree(); } const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; } @@ -453,7 +455,8 @@ private: VoxelSystem _voxels; VoxelTree _clipboard; // if I copy/paste - VoxelImporter* _voxelImporter; + VoxelImportDialog* _voxelImportDialog; + VoxelImporter _voxelImporter; bool _importSucceded; VoxelSystem _sharedVoxelSystem; ViewFrustum _sharedVoxelSystemViewFrustum; diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index e8fb545343..0e63a386ed 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -87,6 +87,37 @@ bool ClipboardScriptingInterface::importVoxels() { return Application::getInstance()->getImportSucceded(); } +bool ClipboardScriptingInterface::importVoxels(const QString& filename) { + qDebug() << "Importing ... "; + + VoxelImporter* importer = Application::getInstance()->getVoxelImporter(); + + if (!importer->validImportFile(filename)) { + return false; + } + + QEventLoop loop; + connect(importer, SIGNAL(importDone()), &loop, SLOT(quit())); + importer->import(filename); + loop.exec(); + + return true; +} + +bool ClipboardScriptingInterface::importVoxels(const QString& filename, float x, float y, float z, float s) { + bool success = importVoxels(filename); + + if (success) { + pasteVoxel(x, y, z, s); + } + + return success; +} + +bool ClipboardScriptingInterface::importVoxels(const QString& filename, const VoxelDetail& destinationVoxel) { + return importVoxels(filename, destinationVoxel.x, destinationVoxel.y, destinationVoxel.z, destinationVoxel.s); +} + void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) { nudgeVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s, nudgeVec); } diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index f0258b0cc7..b7b1d85625 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -39,6 +39,9 @@ public slots: void exportVoxel(float x, float y, float z, float s); bool importVoxels(); + bool importVoxels(const QString& filename); + bool importVoxels(const QString& filename, float x, float y, float z, float s); + bool importVoxels(const QString& filename, const VoxelDetail& destinationVoxel); void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec); void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec); diff --git a/interface/src/ui/ImportDialog.cpp b/interface/src/ui/VoxelImportDialog.cpp similarity index 77% rename from interface/src/ui/ImportDialog.cpp rename to interface/src/ui/VoxelImportDialog.cpp index 67b89773fb..2d1b71ba7f 100644 --- a/interface/src/ui/ImportDialog.cpp +++ b/interface/src/ui/VoxelImportDialog.cpp @@ -1,5 +1,5 @@ // -// ImportDialog.cpp +// VoxelImportDialog.cpp // interface/src/ui // // Created by Clement Brisset on 8/12/13. @@ -20,7 +20,11 @@ #include "Application.h" -#include "ImportDialog.h" +#include "VoxelImportDialog.h" +#include "voxels/VoxelImporter.h" + +const QString SETTINGS_GROUP_NAME = "VoxelImport"; +const QString IMPORT_DIALOG_SETTINGS_KEY = "VoxelImportDialogSettings"; const QString WINDOW_NAME = QObject::tr("Import Voxels"); const QString IMPORT_BUTTON_NAME = QObject::tr("Import Voxels"); @@ -97,12 +101,14 @@ QString HiFiIconProvider::type(const QFileInfo &info) const { return QFileIconProvider::type(info); } -ImportDialog::ImportDialog(QWidget* parent) : +VoxelImportDialog::VoxelImportDialog(QWidget* parent) : QFileDialog(parent, WINDOW_NAME, DOWNLOAD_LOCATION, NULL), - _progressBar(this), - _importButton(IMPORT_BUTTON_NAME, this), _cancelButton(CANCEL_BUTTON_NAME, this), - _mode(importMode) { + _importButton(IMPORT_BUTTON_NAME, this), + _importer(Application::getInstance()->getVoxelImporter()), + _mode(importMode), + _progressBar(this), + _didImport(false) { setOption(QFileDialog::DontUseNativeDialog, true); setFileMode(QFileDialog::ExistingFile); @@ -113,41 +119,54 @@ ImportDialog::ImportDialog(QWidget* parent) : _progressBar.setRange(0, 100); - connect(&_importButton, SIGNAL(pressed()), SLOT(accept())); - connect(&_cancelButton, SIGNAL(pressed()), SIGNAL(canceled())); + connect(&_importButton, SIGNAL(pressed()), this, SLOT(accept())); + connect(&_cancelButton, SIGNAL(pressed()), this, SLOT(cancel())); connect(this, SIGNAL(currentChanged(QString)), SLOT(saveCurrentFile(QString))); } -void ImportDialog::reset() { - setMode(importMode); - _progressBar.setValue(0); +void VoxelImportDialog::cancel() { + switch (getMode()) { + case importMode: + _importer->cancel(); + close(); + break; + default: + _importer->reset(); + setMode(importMode); + break; + } + emit canceled(); } -void ImportDialog::setMode(dialogMode mode) { +void VoxelImportDialog::saveSettings(QSettings* settings) { + settings->beginGroup(SETTINGS_GROUP_NAME); + settings->setValue(IMPORT_DIALOG_SETTINGS_KEY, saveState()); + settings->endGroup(); +} + +void VoxelImportDialog::loadSettings(QSettings* settings) { + settings->beginGroup(SETTINGS_GROUP_NAME); + restoreState(settings->value(IMPORT_DIALOG_SETTINGS_KEY).toByteArray()); + settings->endGroup(); +} + +bool VoxelImportDialog::prompt() { + reset(); + exec(); + return _didImport; +} + +void VoxelImportDialog::reset() { + setMode(importMode); + _didImport = false; +} + +void VoxelImportDialog::setMode(dialogMode mode) { + dialogMode previousMode = _mode; _mode = mode; switch (_mode) { - case loadingMode: - _importButton.setEnabled(false); - _importButton.setText(LOADING_BUTTON_NAME); - findChild("sidebar")->setEnabled(false); - findChild("treeView")->setEnabled(false); - findChild("backButton")->setEnabled(false); - findChild("forwardButton")->setEnabled(false); - findChild("toParentButton")->setEnabled(false); - break; - case placeMode: - _progressBar.setValue(100); - _importButton.setEnabled(true); - _importButton.setText(PLACE_BUTTON_NAME); - findChild("sidebar")->setEnabled(false); - findChild("treeView")->setEnabled(false); - findChild("backButton")->setEnabled(false); - findChild("forwardButton")->setEnabled(false); - findChild("toParentButton")->setEnabled(false); - break; case importMode: - default: _progressBar.setValue(0); _importButton.setEnabled(true); _importButton.setText(IMPORT_BUTTON_NAME); @@ -157,22 +176,60 @@ void ImportDialog::setMode(dialogMode mode) { findChild("forwardButton")->setEnabled(true); findChild("toParentButton")->setEnabled(true); break; + case loadingMode: + // Connect to VoxelImporter signals + connect(_importer, SIGNAL(importProgress(int)), this, SLOT(updateProgressBar(int))); + connect(_importer, SIGNAL(importDone()), this, SLOT(afterImport())); + + _importButton.setEnabled(false); + _importButton.setText(LOADING_BUTTON_NAME); + findChild("sidebar")->setEnabled(false); + findChild("treeView")->setEnabled(false); + findChild("backButton")->setEnabled(false); + findChild("forwardButton")->setEnabled(false); + findChild("toParentButton")->setEnabled(false); + break; + case finishedMode: + if (previousMode == loadingMode) { + // Disconnect from VoxelImporter signals + disconnect(_importer, SIGNAL(importProgress(int)), this, SLOT(setProgressBarValue(int))); + disconnect(_importer, SIGNAL(importDone()), this, SLOT(afterImport())); + } + setMode(importMode); + break; } } -void ImportDialog::setProgressBarValue(int value) { +void VoxelImportDialog::setProgressBarValue(int value) { _progressBar.setValue(value); } -void ImportDialog::accept() { - emit accepted(); +void VoxelImportDialog::accept() { + if (getMode() == importMode) { + QString filename = getCurrentFile(); + + // If file is invalid we ignore the call + if (!_importer->validImportFile(filename)) { + return; + } + // Let's prepare the dialog window for import + setMode(loadingMode); + + _importer->import(filename); + } } -void ImportDialog::saveCurrentFile(QString filename) { +void VoxelImportDialog::afterImport() { + setMode(finishedMode); + _didImport = true; + close(); +} + +void VoxelImportDialog::saveCurrentFile(QString filename) { _currentFile = QFileInfo(filename).isFile() ? filename : ""; } -void ImportDialog::setLayout() { +void VoxelImportDialog::setLayout() { QGridLayout* gridLayout = (QGridLayout*) layout(); gridLayout->addWidget(&_progressBar, 2, 0, 2, 1); gridLayout->addWidget(&_cancelButton, 2, 1, 2, 1); @@ -258,7 +315,7 @@ void ImportDialog::setLayout() { } -void ImportDialog::setImportTypes() { +void VoxelImportDialog::setImportTypes() { QFile config(Application::resourcesPath() + "config/config.json"); config.open(QFile::ReadOnly | QFile::Text); QJsonDocument document = QJsonDocument::fromJson(config.readAll()); diff --git a/interface/src/ui/ImportDialog.h b/interface/src/ui/VoxelImportDialog.h similarity index 74% rename from interface/src/ui/ImportDialog.h rename to interface/src/ui/VoxelImportDialog.h index 88cfda7a7c..54faf7449a 100644 --- a/interface/src/ui/ImportDialog.h +++ b/interface/src/ui/VoxelImportDialog.h @@ -1,5 +1,5 @@ // -// ImportDialog.h +// VoxelImportDialog.h // interface/src/ui // // Created by Clement Brisset on 8/12/13. @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_ImportDialog_h -#define hifi_ImportDialog_h +#ifndef hifi_VoxelImportDialog_h +#define hifi_VoxelImportDialog_h #include "InterfaceConfig.h" @@ -23,6 +23,8 @@ #include +#include "voxels/VoxelImporter.h" + class HiFiIconProvider : public QFileIconProvider { public: HiFiIconProvider(const QHash map) { iconsMap = map; }; @@ -35,39 +37,45 @@ public: enum dialogMode { importMode, loadingMode, - placeMode + finishedMode }; -class ImportDialog : public QFileDialog { +class VoxelImportDialog : public QFileDialog { Q_OBJECT public: - ImportDialog(QWidget* parent = NULL); - void reset(); + VoxelImportDialog(QWidget* parent = NULL); QString getCurrentFile() const { return _currentFile; } dialogMode getMode() const { return _mode; } + void setMode(dialogMode mode); + void reset(); + bool prompt(); + void loadSettings(QSettings* settings); + void saveSettings(QSettings* settings); signals: void canceled(); - -public slots: - void setProgressBarValue(int value); private slots: + void setProgressBarValue(int value); void accept(); + void cancel(); void saveCurrentFile(QString filename); + void afterImport(); private: - QString _currentFile; - QProgressBar _progressBar; - QPushButton _importButton; QPushButton _cancelButton; + QString _currentFile; + QPushButton _importButton; + VoxelImporter* _importer; dialogMode _mode; + QProgressBar _progressBar; + bool _didImport; void setLayout(); void setImportTypes(); }; -#endif // hifi_ImportDialog_h +#endif // hifi_VoxelImportDialog_h diff --git a/interface/src/voxels/VoxelImporter.cpp b/interface/src/voxels/VoxelImporter.cpp index f7d5562c06..b713813fb0 100644 --- a/interface/src/voxels/VoxelImporter.cpp +++ b/interface/src/voxels/VoxelImporter.cpp @@ -20,8 +20,7 @@ #include "voxels/VoxelImporter.h" -const QString SETTINGS_GROUP_NAME = "VoxelImport"; -const QString IMPORT_DIALOG_SETTINGS_KEY = "ImportDialogSettings"; +const QStringList SUPPORTED_EXTENSIONS = QStringList() << "png" << "svo" << "schematic"; class ImportTask : public QObject, public QRunnable { public: @@ -32,104 +31,46 @@ private: QString _filename; }; -VoxelImporter::VoxelImporter(QWidget* parent) : - QObject(parent), +VoxelImporter::VoxelImporter() : _voxelTree(true), - _importDialog(parent), - _task(NULL), - _didImport(false) + _task(NULL) { LocalVoxelsList::getInstance()->addPersistantTree(IMPORT_TREE_NAME, &_voxelTree); - connect(&_voxelTree, SIGNAL(importProgress(int)), &_importDialog, SLOT(setProgressBarValue(int))); - connect(&_importDialog, SIGNAL(canceled()), this, SLOT(cancel())); - connect(&_importDialog, SIGNAL(accepted()), this, SLOT(import())); -} - -void VoxelImporter::saveSettings(QSettings* settings) { - settings->beginGroup(SETTINGS_GROUP_NAME); - settings->setValue(IMPORT_DIALOG_SETTINGS_KEY, _importDialog.saveState()); - settings->endGroup(); -} - -void VoxelImporter::loadSettings(QSettings* settings) { - settings->beginGroup(SETTINGS_GROUP_NAME); - _importDialog.restoreState(settings->value(IMPORT_DIALOG_SETTINGS_KEY).toByteArray()); - settings->endGroup(); + connect(&_voxelTree, SIGNAL(importProgress(int)), this, SIGNAL(importProgress(int))); } VoxelImporter::~VoxelImporter() { cleanupTask(); } +void VoxelImporter::cancel() { + if (_task) { + disconnect(_task, 0, 0, 0); + } + reset(); +} + void VoxelImporter::reset() { _voxelTree.eraseAllOctreeElements(); - _importDialog.reset(); - cleanupTask(); } -int VoxelImporter::exec() { - reset(); - _importDialog.exec(); - - if (!_didImport) { - // if the import is rejected, we make sure to cleanup before leaving +void VoxelImporter::import(const QString& filename) { + // If present, abort existing import + if (_task) { cleanupTask(); - return 1; - } else { - _didImport = false; - return 0; } -} -void VoxelImporter::import() { - switch (_importDialog.getMode()) { - case loadingMode: - _importDialog.setMode(placeMode); - return; - case placeMode: - // Means the user chose to import - _didImport = true; - _importDialog.close(); - return; - case importMode: - default: - QString filename = _importDialog.getCurrentFile(); - // if it's not a file, we ignore the call - if (!QFileInfo(filename).isFile()) { - return; - } - - // Let's prepare the dialog window for import - _importDialog.setMode(loadingMode); - - // If not already done, we switch to the local tree - if (Application::getInstance()->getSharedVoxelSystem()->getTree() != &_voxelTree) { - Application::getInstance()->getSharedVoxelSystem()->changeTree(&_voxelTree); - } - - // Creation and launch of the import task on the thread pool - _task = new ImportTask(filename); - connect(_task, SIGNAL(destroyed()), SLOT(import())); - QThreadPool::globalInstance()->start(_task); - break; + // If not already done, we switch to the local tree + if (Application::getInstance()->getSharedVoxelSystem()->getTree() != &_voxelTree) { + Application::getInstance()->getSharedVoxelSystem()->changeTree(&_voxelTree); } -} -void VoxelImporter::cancel() { - switch (_importDialog.getMode()) { - case loadingMode: - disconnect(_task, 0, 0, 0); - cleanupTask(); - case placeMode: - _importDialog.setMode(importMode); - break; - case importMode: - default: - _importDialog.close(); - break; - } + // Creation and launch of the import task on the thread pool + _task = new ImportTask(filename); + connect(_task, SIGNAL(destroyed()), SLOT(finishImport())); + QThreadPool::globalInstance()->start(_task); } void VoxelImporter::cleanupTask() { @@ -140,6 +81,16 @@ void VoxelImporter::cleanupTask() { } } +void VoxelImporter::finishImport() { + cleanupTask(); + emit importDone(); +} + +bool VoxelImporter::validImportFile(const QString& filename) { + QFileInfo fileInfo = QFileInfo(filename); + return fileInfo.isFile() && SUPPORTED_EXTENSIONS.indexOf(fileInfo.suffix().toLower()) != -1; +} + ImportTask::ImportTask(const QString &filename) : _filename(filename) { @@ -151,7 +102,7 @@ void ImportTask::run() { // We start by cleaning up the shared voxel system just in case voxelSystem->killLocalVoxels(); - // Then we call the righ method for the job + // Then we call the right method for the job if (_filename.endsWith(".png", Qt::CaseInsensitive)) { voxelSystem->getTree()->readFromSquareARGB32Pixels(_filename.toLocal8Bit().data()); } else if (_filename.endsWith(".svo", Qt::CaseInsensitive)) { @@ -163,6 +114,6 @@ void ImportTask::run() { qDebug() << "[ERROR] Invalid file extension." << endl; } - // Here we reaverage the tree so that he is ready for preview + // Here we reaverage the tree so that it is ready for preview voxelSystem->getTree()->reaverageOctreeElements(); } diff --git a/interface/src/voxels/VoxelImporter.h b/interface/src/voxels/VoxelImporter.h index 7da89c5a11..21ebbeea2e 100644 --- a/interface/src/voxels/VoxelImporter.h +++ b/interface/src/voxels/VoxelImporter.h @@ -14,8 +14,8 @@ #include #include +#include -#include "ui/ImportDialog.h" #include "voxels/VoxelSystem.h" class ImportTask; @@ -23,28 +23,29 @@ class ImportTask; class VoxelImporter : public QObject { Q_OBJECT public: - VoxelImporter(QWidget* parent = NULL); + VoxelImporter(); ~VoxelImporter(); void reset(); - void loadSettings(QSettings* settings); - void saveSettings(QSettings* settings); - + void cancel(); VoxelTree* getVoxelTree() { return &_voxelTree; } + bool validImportFile(const QString& filename); public slots: - int exec(); - void import(); - void cancel(); + void import(const QString& filename); + +signals: + void importDone(); + void importProgress(int); private: VoxelTree _voxelTree; - ImportDialog _importDialog; - ImportTask* _task; - bool _didImport; void cleanupTask(); + +private slots: + void finishImport(); }; #endif // hifi_VoxelImporter_h