Add abstract class to handle Handlebar-based documentation file generation

Apply Documented class to the InteractionHandler
Update Ghoul
This commit is contained in:
Alexander Bock
2017-05-09 18:06:14 +01:00
parent fa7cee729c
commit ddc9ef1bc5
7 changed files with 368 additions and 131 deletions

View File

@@ -31,6 +31,7 @@
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <openspace/util/documented.h>
#include <openspace/util/mouse.h>
#include <openspace/util/keys.h>
@@ -48,8 +49,7 @@ class SceneGraphNode;
namespace interaction {
class InteractionHandler : public properties::PropertyOwner
{
class InteractionHandler : public properties::PropertyOwner, public Documented {
public:
InteractionHandler();
~InteractionHandler();
@@ -121,7 +121,7 @@ public:
void saveCameraStateToFile(const std::string& filepath);
void restoreCameraStateFromFile(const std::string& filepath);
void writeKeyboardDocumentation(const std::string& type, const std::string& file);
// void writeKeyboardDocumentation(const std::string& type, const std::string& file);
private:
using Synchronized = ghoul::Boolean;
@@ -131,6 +131,8 @@ private:
Synchronized synchronization;
std::string documentation;
};
std::string generateJson() const override;
void setInteractionMode(std::shared_ptr<InteractionMode> interactionMode);

View File

@@ -0,0 +1,57 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___DOCUMENTED___H__
#define __OPENSPACE_CORE___DOCUMENTED___H__
#include <string>
#include <vector>
namespace openspace {
class Documented {
public:
struct HandlebarTemplate {
std::string name;
std::string filename;
};
Documented(std::string name, std::string jsonName, std::vector<HandlebarTemplate> handlebarTemplates,
std::string javascriptFilename);
void writeDocumentation(const std::string& filename);
protected:
virtual std::string generateJson() const = 0;
private:
const std::string _name;
const std::string _jsonName;
const std::vector<HandlebarTemplate> _handlebarTemplates;
const std::string _javascriptFile;
};
} // namespace openspace
#endif // __OPENSPACE_CORE___DOCUMENTED___H__

View File

@@ -138,6 +138,7 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/util/blockplaneintersectiongeometry.cpp
${OPENSPACE_BASE_DIR}/src/util/boxgeometry.cpp
${OPENSPACE_BASE_DIR}/src/util/camera.cpp
${OPENSPACE_BASE_DIR}/src/util/documented.cpp
${OPENSPACE_BASE_DIR}/src/util/factorymanager.cpp
${OPENSPACE_BASE_DIR}/src/util/keys.cpp
${OPENSPACE_BASE_DIR}/src/util/openspacemodule.cpp
@@ -281,6 +282,7 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/util/blockplaneintersectiongeometry.h
${OPENSPACE_BASE_DIR}/include/openspace/util/boxgeometry.h
${OPENSPACE_BASE_DIR}/include/openspace/util/camera.h
${OPENSPACE_BASE_DIR}/include/openspace/util/documented.h
${OPENSPACE_BASE_DIR}/include/openspace/util/factorymanager.h
${OPENSPACE_BASE_DIR}/include/openspace/util/factorymanager.inl
${OPENSPACE_BASE_DIR}/include/openspace/util/keys.h

View File

@@ -604,7 +604,8 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) {
if (hasType && hasFile) {
file = absPath(file);
interactionHandler().writeKeyboardDocumentation(type, file);
interactionHandler().writeDocumentation(file);
// interactionHandler().writeKeyboardDocumentation(type, file);
}
}

View File

@@ -59,10 +59,10 @@ namespace {
const char* MainTemplateFilename = "${OPENSPACE_DATA}/web/keybindings/main.hbs";
const char* KeybindingTemplateFilename = "${OPENSPACE_DATA}/web/keybindings/keybinding.hbs";
const char* HandlebarsFilename = "${OPENSPACE_DATA}/web/common/handlebars-v4.0.5.js";
// const char* HandlebarsFilename = "${OPENSPACE_DATA}/web/common/handlebars-v4.0.5.js";
const char* JsFilename = "${OPENSPACE_DATA}/web/keybindings/script.js";
const char* BootstrapFilename = "${OPENSPACE_DATA}/web/common/bootstrap.min.css";
const char* CssFilename = "${OPENSPACE_DATA}/web/common/style.css";
// const char* BootstrapFilename = "${OPENSPACE_DATA}/web/common/bootstrap.min.css";
// const char* CssFilename = "${OPENSPACE_DATA}/web/common/style.css";
} // namespace
#include "interactionhandler_lua.inl"
@@ -73,6 +73,15 @@ namespace interaction {
// InteractionHandler
InteractionHandler::InteractionHandler()
: properties::PropertyOwner("Interaction")
, Documented(
"Documentation",
"keybindings",
{
{ "keybindingTemplate", KeybindingTemplateFilename },
{ "mainTemplate", MainTemplateFilename }
},
JsFilename
)
, _origin("origin", "Origin", "")
, _rotationalFriction("rotationalFriction", "Rotational Friction", true)
, _horizontalFriction("horizontalFriction", "Horizontal Friction", true)
@@ -433,133 +442,163 @@ void InteractionHandler::bindKey(Key key, KeyModifier modifier,
}
void InteractionHandler::writeKeyboardDocumentation(const std::string& type,
const std::string& file)
{
if (type == "text") {
std::ofstream f;
f.exceptions(~std::ofstream::goodbit);
f.open(absPath(file));
for (const auto& p : _keyLua) {
std::string remoteScriptingInfo;
bool remoteScripting = p.second.synchronization;
if (!remoteScripting) {
remoteScriptingInfo = " (LOCAL)";
}
f << std::to_string(p.first) << ": "
<< p.second.command << remoteScriptingInfo << '\n'
<< p.second.documentation << '\n';
std::string InteractionHandler::generateJson() const {
std::stringstream json;
json << "[";
bool first = true;
for (const auto& p : _keyLua) {
if (!first) {
json << ",";
}
first = false;
json << "{";
json << "\"key\": \"" << std::to_string(p.first) << "\",";
json << "\"script\": \"" << p.second.command << "\",";
json << "\"remoteScripting\": " << (p.second.synchronization ? "true," : "false,");
json << "\"documentation\": \"" << p.second.documentation << "\"";
json << "}";
}
json << "]";
std::string jsonString = "";
for (const char& c : json.str()) {
if (c == '\'') {
jsonString += "\\'";
} else {
jsonString += c;
}
}
else if (type == "html") {
std::ofstream f;
f.exceptions(~std::ofstream::goodbit);
f.open(absPath(file));
std::ifstream handlebarsInput(absPath(HandlebarsFilename));
std::ifstream jsInput(absPath(JsFilename));
std::string jsContent;
std::back_insert_iterator<std::string> jsInserter(jsContent);
std::copy(std::istreambuf_iterator<char>{handlebarsInput}, std::istreambuf_iterator<char>(), jsInserter);
std::copy(std::istreambuf_iterator<char>{jsInput}, std::istreambuf_iterator<char>(), jsInserter);
std::ifstream bootstrapInput(absPath(BootstrapFilename));
std::ifstream cssInput(absPath(CssFilename));
std::string cssContent;
std::back_insert_iterator<std::string> cssInserter(cssContent);
std::copy(std::istreambuf_iterator<char>{bootstrapInput}, std::istreambuf_iterator<char>(), cssInserter);
std::copy(std::istreambuf_iterator<char>{cssInput}, std::istreambuf_iterator<char>(), cssInserter);
std::ifstream mainTemplateInput(absPath(MainTemplateFilename));
std::string mainTemplateContent{ std::istreambuf_iterator<char>{mainTemplateInput},
std::istreambuf_iterator<char>{} };
std::ifstream keybindingTemplateInput(absPath(KeybindingTemplateFilename));
std::string keybindingTemplateContent{ std::istreambuf_iterator<char>{keybindingTemplateInput},
std::istreambuf_iterator<char>{} };
std::stringstream json;
json << "[";
bool first = true;
for (const auto& p : _keyLua) {
if (!first) {
json << ",";
}
first = false;
json << "{";
json << "\"key\": \"" << std::to_string(p.first) << "\",";
json << "\"script\": \"" << p.second.command << "\",";
json << "\"remoteScripting\": " << (p.second.synchronization ? "true," : "false,");
json << "\"documentation\": \"" << p.second.documentation << "\"";
json << "}";
}
json << "]";
std::string jsonString = "";
for (const char& c : json.str()) {
if (c == '\'') {
jsonString += "\\'";
} else {
jsonString += c;
}
}
std::string generationTime;
try {
generationTime = Time::now().ISO8601();
}
catch (...) {}
std::stringstream html;
html << "<!DOCTYPE html>\n"
<< "<html>\n"
<< "\t<head>\n"
<< "\t\t<script id=\"mainTemplate\" type=\"text/x-handlebars-template\">\n"
<< mainTemplateContent << "\n"
<< "\t\t</script>\n"
<< "\t\t<script id=\"keybindingTemplate\" type=\"text/x-handlebars-template\">\n"
<< keybindingTemplateContent << "\n"
<< "\t\t</script>\n"
<< "\t<script>\n"
<< "var keybindings = JSON.parse('" << jsonString << "');\n"
<< "var version = [" << OPENSPACE_VERSION_MAJOR << ", " << OPENSPACE_VERSION_MINOR << ", " << OPENSPACE_VERSION_PATCH << "];\n"
<< "var generationTime = '" << generationTime << "';\n"
<< jsContent << "\n"
<< "\t</script>\n"
<< "\t<style type=\"text/css\">\n"
<< cssContent << "\n"
<< "\t</style>\n"
<< "\t\t<title>Documentation</title>\n"
<< "\t</head>\n"
<< "\t<body>\n"
<< "\t<body>\n"
<< "</html>\n";
f << html.str();
/*
for (const auto& p : _keyLua) {
html << "\t\t<tr>\n"
<< "\t\t\t<td>" << std::to_string(p.first) << "</td>\n"
<< "\t\t\t<td>" << p.second.first << "</td>\n"
<< "\t\t\t<td>" << (p.second.second ? "Yes" : "No") << "</td>\n"
<< "\t\t</tr>\n";
}*/
}
else {
throw ghoul::RuntimeError(
"Unsupported keyboard documentation type '" + type + "'",
"InteractionHandler"
);
}
return jsonString;
}
//void InteractionHandler::writeKeyboardDocumentation(const std::string& type,
// const std::string& file)
//{
// if (type == "text") {
// std::ofstream f;
// f.exceptions(~std::ofstream::goodbit);
// f.open(absPath(file));
//
// for (const auto& p : _keyLua) {
// std::string remoteScriptingInfo;
// bool remoteScripting = p.second.synchronization;
//
// if (!remoteScripting) {
// remoteScriptingInfo = " (LOCAL)";
// }
// f << std::to_string(p.first) << ": "
// << p.second.command << remoteScriptingInfo << '\n'
// << p.second.documentation << '\n';
// }
// }
// else if (type == "html") {
// std::ofstream f;
// f.exceptions(~std::ofstream::goodbit);
// f.open(absPath(file));
//
// std::ifstream handlebarsInput(absPath(HandlebarsFilename));
// std::ifstream jsInput(absPath(JsFilename));
//
// std::string jsContent;
// std::back_insert_iterator<std::string> jsInserter(jsContent);
//
// std::copy(std::istreambuf_iterator<char>{handlebarsInput}, std::istreambuf_iterator<char>(), jsInserter);
// std::copy(std::istreambuf_iterator<char>{jsInput}, std::istreambuf_iterator<char>(), jsInserter);
//
// std::ifstream bootstrapInput(absPath(BootstrapFilename));
// std::ifstream cssInput(absPath(CssFilename));
//
// std::string cssContent;
// std::back_insert_iterator<std::string> cssInserter(cssContent);
//
// std::copy(std::istreambuf_iterator<char>{bootstrapInput}, std::istreambuf_iterator<char>(), cssInserter);
// std::copy(std::istreambuf_iterator<char>{cssInput}, std::istreambuf_iterator<char>(), cssInserter);
//
// std::ifstream mainTemplateInput(absPath(MainTemplateFilename));
// std::string mainTemplateContent{ std::istreambuf_iterator<char>{mainTemplateInput},
// std::istreambuf_iterator<char>{} };
//
// std::ifstream keybindingTemplateInput(absPath(KeybindingTemplateFilename));
// std::string keybindingTemplateContent{ std::istreambuf_iterator<char>{keybindingTemplateInput},
// std::istreambuf_iterator<char>{} };
//
// std::stringstream json;
// json << "[";
// bool first = true;
// for (const auto& p : _keyLua) {
// if (!first) {
// json << ",";
// }
// first = false;
// json << "{";
// json << "\"key\": \"" << std::to_string(p.first) << "\",";
// json << "\"script\": \"" << p.second.command << "\",";
// json << "\"remoteScripting\": " << (p.second.synchronization ? "true," : "false,");
// json << "\"documentation\": \"" << p.second.documentation << "\"";
// json << "}";
// }
// json << "]";
//
// std::string jsonString = "";
// for (const char& c : json.str()) {
// if (c == '\'') {
// jsonString += "\\'";
// } else {
// jsonString += c;
// }
// }
//
// std::string generationTime;
// try {
// generationTime = Time::now().ISO8601();
// }
// catch (...) {}
//
// std::stringstream html;
// html << "<!DOCTYPE html>\n"
// << "<html>\n"
// << "\t<head>\n"
// << "\t\t<script id=\"mainTemplate\" type=\"text/x-handlebars-template\">\n"
// << mainTemplateContent << "\n"
// << "\t\t</script>\n"
// << "\t\t<script id=\"keybindingTemplate\" type=\"text/x-handlebars-template\">\n"
// << keybindingTemplateContent << "\n"
// << "\t\t</script>\n"
// << "\t<script>\n"
// << "var keybindings = JSON.parse('" << jsonString << "');\n"
// << "var version = [" << OPENSPACE_VERSION_MAJOR << ", " << OPENSPACE_VERSION_MINOR << ", " << OPENSPACE_VERSION_PATCH << "];\n"
// << "var generationTime = '" << generationTime << "';\n"
// << jsContent << "\n"
// << "\t</script>\n"
// << "\t<style type=\"text/css\">\n"
// << cssContent << "\n"
// << "\t</style>\n"
// << "\t\t<title>Documentation</title>\n"
// << "\t</head>\n"
// << "\t<body>\n"
// << "\t<body>\n"
// << "</html>\n";
//
// f << html.str();
//
//
// /*
// for (const auto& p : _keyLua) {
// html << "\t\t<tr>\n"
// << "\t\t\t<td>" << std::to_string(p.first) << "</td>\n"
// << "\t\t\t<td>" << p.second.first << "</td>\n"
// << "\t\t\t<td>" << (p.second.second ? "Yes" : "No") << "</td>\n"
// << "\t\t</tr>\n";
// }*/
// }
// else {
// throw ghoul::RuntimeError(
// "Unsupported keyboard documentation type '" + type + "'",
// "InteractionHandler"
// );
// }
//}
scripting::LuaLibrary InteractionHandler::luaLibrary() {
return{

136
src/util/documented.cpp Normal file
View File

@@ -0,0 +1,136 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/util/documented.h>
#include <openspace/openspace.h>
#include <openspace/util/time.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/invariants.h>
#include <fstream>
namespace {
const char* HandlebarsFilename = "${OPENSPACE_DATA}/web/common/handlebars-v4.0.5.js";
const char* BootstrapFilename = "${OPENSPACE_DATA}/web/common/bootstrap.min.css";
const char* CssFilename = "${OPENSPACE_DATA}/web/common/style.css";
} // namespace
namespace openspace {
Documented::Documented(std::string name,
std::string jsonName,
std::vector<HandlebarTemplate> handlebarTemplates,
std::string javascriptFilename)
: _name(std::move(name))
, _jsonName(std::move(jsonName))
, _handlebarTemplates(std::move(handlebarTemplates))
, _javascriptFile(std::move(javascriptFilename))
{
ghoul_precondition(!_name.empty(), "name must not be empty");
ghoul_precondition(!_jsonName.empty(), "jsonName must not be empty");
ghoul_precondition(
!_handlebarTemplates.empty(),
"handlebarTemplates must not be empty"
);
ghoul_precondition(!_javascriptFile.empty(), "javascriptFilename must not be empty");
}
void Documented::writeDocumentation(const std::string& filename) {
std::ifstream handlebarsInput(absPath(HandlebarsFilename));
std::ifstream jsInput(absPath(_javascriptFile));
std::string jsContent;
std::back_insert_iterator<std::string> jsInserter(jsContent);
std::copy(std::istreambuf_iterator<char>{handlebarsInput}, std::istreambuf_iterator<char>(), jsInserter);
std::copy(std::istreambuf_iterator<char>{jsInput}, std::istreambuf_iterator<char>(), jsInserter);
std::ifstream bootstrapInput(absPath(BootstrapFilename));
std::ifstream cssInput(absPath(CssFilename));
std::string cssContent;
std::back_insert_iterator<std::string> cssInserter(cssContent);
std::copy(std::istreambuf_iterator<char>{bootstrapInput}, std::istreambuf_iterator<char>(), cssInserter);
std::copy(std::istreambuf_iterator<char>{cssInput}, std::istreambuf_iterator<char>(), cssInserter);
std::ofstream file;
file.exceptions(~std::ofstream::goodbit);
file.open(filename);
std::string json = generateJson();
// We probably should escape backslashes here?
file << "<!DOCTYPE html>" << '\n'
<< "<html>" << '\n'
<< "\t" << "<head>" << '\n';
for (const HandlebarTemplate& t : _handlebarTemplates) {
const char* Type = "text/x-handlebars-template";
file << "\t\t"
<< "<script id=\"" << t.name << "\" type=\"" << Type << "\">" << '\n';
std::ifstream templateFilename(absPath(t.filename));
std::string templateContent(
std::istreambuf_iterator<char>{templateFilename},
std::istreambuf_iterator<char>{}
);
file << templateContent << '\n';
file << "\t"
<< "</script>" << '\n';
}
const std::string Version =
"[" +
std::to_string(OPENSPACE_VERSION_MAJOR) + "," +
std::to_string(OPENSPACE_VERSION_MINOR) + "," +
std::to_string(OPENSPACE_VERSION_PATCH) +
"]";
std::string generationTime;
try {
generationTime = Time::now().ISO8601();
}
catch (...) {}
file
<< "\t" << "<script>" << '\n'
<< "\t\t" << "var " << _jsonName << " = JSON.parse('" << json << "');" << '\n'
<< "\t\t" << "var version = " << Version << ";" << '\n'
<< "\t\t" << "var generationTime = '" << generationTime << "';" << '\n'
<< "\t\t" << jsContent << '\n'
<< "\t" << "</script>" << '\n'
<< "\t" << "<style type=\"text/css\">" << '\n'
<< "\t\t" << cssContent << '\n'
<< "\t" << "</style>" << '\n'
<< "\t\t" << "<title>" << _name << "</title>" << '\n'
<< "\t" << "</head>" << '\n'
<< "\t" << "<body>" << '\n'
<< "\t" << "</body>" << '\n'
<< "</html>" << '\n';
}
} // namespace openspace