From 392549353907a0622705a22431d6b4562c92d917 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 14 Apr 2017 18:08:02 -0700 Subject: [PATCH] add a simple results window to show bake results --- libraries/model-baking/src/FBXBaker.cpp | 6 +- libraries/model-baking/src/FBXBaker.h | 1 + tools/oven/src/Oven.h | 7 +++ tools/oven/src/ui/ModelBakeWidget.cpp | 35 ++++++++++- tools/oven/src/ui/ModelBakeWidget.h | 4 +- tools/oven/src/ui/OvenMainWindow.cpp | 22 ++++++- tools/oven/src/ui/OvenMainWindow.h | 11 ++++ tools/oven/src/ui/ResultsWindow.cpp | 79 +++++++++++++++++++++++++ tools/oven/src/ui/ResultsWindow.h | 34 +++++++++++ 9 files changed, 191 insertions(+), 8 deletions(-) create mode 100644 tools/oven/src/ui/ResultsWindow.cpp create mode 100644 tools/oven/src/ui/ResultsWindow.h diff --git a/libraries/model-baking/src/FBXBaker.cpp b/libraries/model-baking/src/FBXBaker.cpp index 5b5a8b7c0a..0cc484ce5c 100644 --- a/libraries/model-baking/src/FBXBaker.cpp +++ b/libraries/model-baking/src/FBXBaker.cpp @@ -51,8 +51,8 @@ QString FBXBaker::pathToCopyOfOriginal() const { } void FBXBaker::handleError(const QString& error) { - qCCritical(model_baking) << error; - _errorList << error; + qCCritical(model_baking).noquote() << error; + _errorList.append(error); emit finished(); } @@ -200,7 +200,7 @@ void FBXBaker::importScene() { if (!importStatus) { // failed to initialize importer, print an error and return - handleError("Failed to import FBX file at" + _fbxURL.toString() + " - error:" + importer->GetStatus().GetErrorString()); + handleError("Failed to import " + _fbxURL.toString() + " - " + importer->GetStatus().GetErrorString()); return; } else { qCDebug(model_baking) << "Imported" << _fbxURL << "to FbxScene"; diff --git a/libraries/model-baking/src/FBXBaker.h b/libraries/model-baking/src/FBXBaker.h index 10c8a5c359..a6dd6ad55a 100644 --- a/libraries/model-baking/src/FBXBaker.h +++ b/libraries/model-baking/src/FBXBaker.h @@ -56,6 +56,7 @@ public: Q_INVOKABLE void bake(); bool hasErrors() const { return !_errorList.isEmpty(); } + QStringList getErrors() const { return _errorList; } QUrl getFBXUrl() const { return _fbxURL; } QString getBakedFBXRelativePath() const { return _bakedFBXRelativePath; } diff --git a/tools/oven/src/Oven.h b/tools/oven/src/Oven.h index 7ec9bdbd3b..3fc9a4c0f6 100644 --- a/tools/oven/src/Oven.h +++ b/tools/oven/src/Oven.h @@ -14,6 +14,11 @@ #include +#if defined(qApp) +#undef qApp +#endif +#define qApp (static_cast(QCoreApplication::instance())) + class OvenMainWindow; class Oven : public QApplication { @@ -22,6 +27,8 @@ class Oven : public QApplication { public: Oven(int argc, char* argv[]); + OvenMainWindow* getMainWindow() const { return _mainWindow; } + private: OvenMainWindow* _mainWindow; }; diff --git a/tools/oven/src/ui/ModelBakeWidget.cpp b/tools/oven/src/ui/ModelBakeWidget.cpp index 3b28bb77fa..cf21483255 100644 --- a/tools/oven/src/ui/ModelBakeWidget.cpp +++ b/tools/oven/src/ui/ModelBakeWidget.cpp @@ -20,6 +20,9 @@ #include #include +#include "../Oven.h" +#include "OvenMainWindow.h" + #include "ModelBakeWidget.h" static const QString EXPORT_DIR_SETTING_KEY = "model_export_directory"; @@ -180,7 +183,7 @@ void ModelBakeWidget::bakeButtonClicked() { } // everything seems to be in place, kick off a bake for this model now - auto baker = new FBXBaker(modelToBakeURL, outputDirectory.absolutePath(), false); + auto baker = QSharedPointer { new FBXBaker(modelToBakeURL, outputDirectory.absolutePath(), false) }; // move the baker to the baker thread baker->moveToThread(_bakerThread); @@ -191,10 +194,36 @@ void ModelBakeWidget::bakeButtonClicked() { } // invoke the bake method on the baker thread - QMetaObject::invokeMethod(baker, "bake"); + QMetaObject::invokeMethod(baker.data(), "bake"); + + // make sure we hear about the results of this baker when it is done + connect(baker.data(), &FBXBaker::finished, this, &ModelBakeWidget::handleFinishedBaker); + + // add a pending row to the results window to show that this bake is in process + auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + auto resultsRow = resultsWindow->addPendingResultRow(modelToBakeURL.fileName()); // keep a unique_ptr to this baker - _bakers.emplace_back(baker); + // and remember the row that represents it in the results table + _bakers.insert(baker, resultsRow); + } +} + +void ModelBakeWidget::handleFinishedBaker() { + if (auto baker = qobject_cast(sender())) { + // turn this baker into a shared pointer + auto sharedBaker = QSharedPointer(baker); + + // add the results of this bake to the results window + auto resultRow = _bakers.value(sharedBaker); + + auto resultsWindow = qApp->getMainWindow()->showResultsWindow(); + + if (sharedBaker->hasErrors()) { + resultsWindow->changeStatusForRow(resultRow, baker->getErrors().join("\n")); + } else { + resultsWindow->changeStatusForRow(resultRow, "Success"); + } } } diff --git a/tools/oven/src/ui/ModelBakeWidget.h b/tools/oven/src/ui/ModelBakeWidget.h index f277d91938..3d76ec0d4d 100644 --- a/tools/oven/src/ui/ModelBakeWidget.h +++ b/tools/oven/src/ui/ModelBakeWidget.h @@ -36,10 +36,12 @@ private slots: void outputDirectoryChanged(const QString& newDirectory); + void handleFinishedBaker(); + private: void setupUI(); - std::list> _bakers; + QHash, int> _bakers; QLineEdit* _modelLineEdit; QLineEdit* _outputDirLineEdit; diff --git a/tools/oven/src/ui/OvenMainWindow.cpp b/tools/oven/src/ui/OvenMainWindow.cpp index 9c25fb5c72..1cf2986d17 100644 --- a/tools/oven/src/ui/OvenMainWindow.cpp +++ b/tools/oven/src/ui/OvenMainWindow.cpp @@ -21,7 +21,6 @@ OvenMainWindow::OvenMainWindow(QWidget *parent, Qt::WindowFlags flags) : setWindowTitle("High Fidelity Oven"); // give the window a fixed width that will never change - const int FIXED_WINDOW_WIDTH = 640; setFixedWidth(FIXED_WINDOW_WIDTH); // setup a stacked layout for the main "modes" menu and subseq @@ -30,3 +29,24 @@ OvenMainWindow::OvenMainWindow(QWidget *parent, Qt::WindowFlags flags) : setCentralWidget(stackedWidget); } + +OvenMainWindow::~OvenMainWindow() { + if (_resultsWindow) { + _resultsWindow->close(); + _resultsWindow->deleteLater(); + } +} + +ResultsWindow* OvenMainWindow::showResultsWindow() { + if (!_resultsWindow) { + // we don't have a results window right now, so make a new one + _resultsWindow = new ResultsWindow; + } + + // show the results window, place it right below our window + _resultsWindow->show(); + _resultsWindow->move(_resultsWindow->x(), this->frameGeometry().bottom()); + + // return a pointer to the results window the caller can use + return _resultsWindow; +} diff --git a/tools/oven/src/ui/OvenMainWindow.h b/tools/oven/src/ui/OvenMainWindow.h index 0941be543b..2d5d2aec99 100644 --- a/tools/oven/src/ui/OvenMainWindow.h +++ b/tools/oven/src/ui/OvenMainWindow.h @@ -12,12 +12,23 @@ #ifndef hifi_OvenMainWindow_h #define hifi_OvenMainWindow_h +#include #include +#include "ResultsWindow.h" + +const int FIXED_WINDOW_WIDTH = 640; + class OvenMainWindow : public QMainWindow { Q_OBJECT public: OvenMainWindow(QWidget *parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags()); + ~OvenMainWindow(); + + ResultsWindow* showResultsWindow(); + +private: + QPointer _resultsWindow; }; #endif // hifi_OvenMainWindow_h diff --git a/tools/oven/src/ui/ResultsWindow.cpp b/tools/oven/src/ui/ResultsWindow.cpp new file mode 100644 index 0000000000..99389f363c --- /dev/null +++ b/tools/oven/src/ui/ResultsWindow.cpp @@ -0,0 +1,79 @@ +// +// ResultsWindow.cpp +// tools/oven/src/ui +// +// Created by Stephen Birarda on 4/14/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include + +#include "OvenMainWindow.h" + +#include "ResultsWindow.h" + +ResultsWindow::ResultsWindow(QWidget* parent) : + QWidget(parent) +{ + // add a title to this window to identify it + setWindowTitle("High Fidelity Oven - Bake Results"); + + // give this dialog the same starting width as the main application window + resize(FIXED_WINDOW_WIDTH, size().height()); + + // have the window delete itself when closed + setAttribute(Qt::WA_DeleteOnClose); + + setupUI(); +} + +void ResultsWindow::setupUI() { + QVBoxLayout* resultsLayout = new QVBoxLayout(this); + + // add a results table to the widget + _resultsTable = new QTableWidget(0, 2, this); + + // add the header to the table widget + _resultsTable->setHorizontalHeaderLabels({"File", "Status"}); + + // add that table widget to the vertical box layout, so we can make it stretch to the size of the parent + resultsLayout->insertWidget(0, _resultsTable); + + // make the filename column hold 25% of the total width + // strech the last column of the table (that holds the results) to fill up the remaining available size + _resultsTable->horizontalHeader()->resizeSection(0, 0.25 * FIXED_WINDOW_WIDTH); + _resultsTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents); + + // set the layout of this widget to the created layout + setLayout(resultsLayout); +} + + +int ResultsWindow::addPendingResultRow(const QString& fileName) { + int rowIndex = _resultsTable->rowCount(); + + _resultsTable->insertRow(rowIndex); + + // add a new item for the filename, make it non-editable + auto fileNameItem = new QTableWidgetItem(fileName); + fileNameItem->setFlags(fileNameItem->flags() & ~Qt::ItemIsEditable); + _resultsTable->setItem(rowIndex, 0, fileNameItem); + + auto statusItem = new QTableWidgetItem("Baking..."); + statusItem->setFlags(statusItem->flags() & ~Qt::ItemIsEditable); + _resultsTable->setItem(rowIndex, 1, statusItem); + + return rowIndex; +} + +void ResultsWindow::changeStatusForRow(int rowIndex, const QString& result) { + auto statusItem = new QTableWidgetItem(result); + statusItem->setFlags(statusItem->flags() & ~Qt::ItemIsEditable); + _resultsTable->setItem(rowIndex, 1, statusItem); +} diff --git a/tools/oven/src/ui/ResultsWindow.h b/tools/oven/src/ui/ResultsWindow.h new file mode 100644 index 0000000000..b7e380a631 --- /dev/null +++ b/tools/oven/src/ui/ResultsWindow.h @@ -0,0 +1,34 @@ +// +// ResultsWindow.h +// tools/oven/src/ui +// +// Created by Stephen Birarda on 4/14/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ResultsWindow_h +#define hifi_ResultsWindow_h + +#include + +class QTableWidget; + +class ResultsWindow : public QWidget { + Q_OBJECT + +public: + ResultsWindow(QWidget* parent = nullptr); + + void setupUI(); + + int addPendingResultRow(const QString& fileName); + void changeStatusForRow(int rowIndex, const QString& result); + +private: + QTableWidget* _resultsTable { nullptr }; +}; + +#endif // hifi_ResultsWindow_h