mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-28 14:59:31 -05:00
Add SceneLicense information to the Scene
Add documentation generator to SceneLicense
This commit is contained in:
@@ -132,6 +132,8 @@ set(OPENSPACE_SOURCE
|
||||
${OPENSPACE_BASE_DIR}/src/scene/scene.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/scene/scene_doc.inl
|
||||
${OPENSPACE_BASE_DIR}/src/scene/scene_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/scene/scenelicense.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/scene/scenelicensewriter.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/scene/sceneloader.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/scene/scenemanager.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode.cpp
|
||||
@@ -286,6 +288,8 @@ set(OPENSPACE_HEADER
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/scene/rotation.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/scene/scale.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/scene/scene.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/scene/scenelicense.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/scene/scenelicensewriter.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/scene/sceneloader.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/scene/scenemanager.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/scene/scenegraphnode.h
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/misc/invariants.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
@@ -158,6 +160,12 @@ std::string escapedJson(const std::string& text) {
|
||||
case '\\':
|
||||
jsonString += "\\\\";
|
||||
break;
|
||||
case '\n':
|
||||
jsonString += "\\\\n";
|
||||
break;
|
||||
case '\r':
|
||||
jsonString += "\\r";
|
||||
break;
|
||||
default:
|
||||
jsonString += c;
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ const string ConfigurationManager::KeyPropertyDocumentation = "PropertyDocumenta
|
||||
const string ConfigurationManager::KeyKeyboardShortcuts = "KeyboardShortcuts";
|
||||
const string ConfigurationManager::KeyDocumentation = "Documentation";
|
||||
const string ConfigurationManager::KeyFactoryDocumentation = "FactoryDocumentation";
|
||||
const string ConfigurationManager::KeySceneLicenseDocumentation = "LicenseDocumentation";
|
||||
const string ConfigurationManager::KeyConfigScene = "Scene";
|
||||
const string ConfigurationManager::KeyConfigTasksRoot = "TasksRoot";
|
||||
|
||||
|
||||
@@ -200,6 +200,14 @@ documentation::Documentation ConfigurationManager::Documentation() {
|
||||
"created in the current application configuration. Any previous file in this "
|
||||
"location will be silently overritten."
|
||||
},
|
||||
{
|
||||
ConfigurationManager::KeySceneLicenseDocumentation,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"The file that will be created on startup containing the scene license "
|
||||
"information. Any previous file in this location will be silently "
|
||||
"overwritten."
|
||||
},
|
||||
{
|
||||
ConfigurationManager::KeyLauncher,
|
||||
new TableVerifier({
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/scene/rotation.h>
|
||||
#include <openspace/scene/scale.h>
|
||||
#include <openspace/scene/scenelicense.h>
|
||||
#include <openspace/scene/translation.h>
|
||||
#include <openspace/scene/scenemanager.h>
|
||||
|
||||
@@ -645,6 +646,15 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) {
|
||||
);
|
||||
}
|
||||
|
||||
if (configurationManager().hasKey(ConfigurationManager::KeySceneLicenseDocumentation))
|
||||
{
|
||||
scene->writeSceneLicenseDocumentation(
|
||||
absPath(configurationManager().value<std::string>(
|
||||
ConfigurationManager::KeySceneLicenseDocumentation
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
// If a PropertyDocumentationFile was specified, generate it now.
|
||||
if (configurationManager().hasKey(ConfigurationManager::KeyPropertyDocumentation)) {
|
||||
scene->writeDocumentation(
|
||||
|
||||
@@ -138,7 +138,7 @@ std::string KeyBindingManager::generateJson() const {
|
||||
}
|
||||
|
||||
return jsonString;
|
||||
}
|
||||
}
|
||||
|
||||
scripting::LuaLibrary KeyBindingManager::luaLibrary() {
|
||||
return {
|
||||
|
||||
@@ -139,6 +139,10 @@ void Scene::removeNode(SceneGraphNode* node, UpdateDependencies updateDeps) {
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::addSceneLicense(SceneLicense license) {
|
||||
_licenses.push_back(std::move(license));
|
||||
}
|
||||
|
||||
void Scene::updateDependencies() {
|
||||
sortTopologically();
|
||||
}
|
||||
@@ -272,6 +276,11 @@ const std::vector<SceneGraphNode*>& Scene::allSceneGraphNodes() const {
|
||||
return _topologicallySortedNodes;
|
||||
}
|
||||
|
||||
void Scene::writeSceneLicenseDocumentation(const std::string& path) const {
|
||||
SceneLicenseWriter writer(_licenses);
|
||||
writer.writeDocumentation(path);
|
||||
}
|
||||
|
||||
std::string Scene::generateJson() const {
|
||||
std::function<std::string(properties::PropertyOwner*)> createJson =
|
||||
[&createJson](properties::PropertyOwner* owner) -> std::string
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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/scene/scenelicense.h>
|
||||
|
||||
#include <openspace/openspace.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace {
|
||||
const char* LicenseKeyName = "Name";
|
||||
const char* LicenseKeyAttribution = "Attribution";
|
||||
const char* LicenseKeyUrl = "URL";
|
||||
const char* LicenseKeyLicenseText = "License";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation SceneLicense::Documentation() {
|
||||
using namespace documentation;
|
||||
|
||||
return {
|
||||
"License Information",
|
||||
"core_license",
|
||||
{
|
||||
{
|
||||
LicenseKeyName,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"A short, descriptive name for the license employed for this node."
|
||||
},
|
||||
{
|
||||
LicenseKeyAttribution,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The organization that shall be attributed to the licensed content."
|
||||
},
|
||||
{
|
||||
LicenseKeyUrl,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"The URL pointing to the original license."
|
||||
},
|
||||
{
|
||||
LicenseKeyLicenseText,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The full text of the license agreements."
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SceneLicense::SceneLicense(const ghoul::Dictionary& dictionary, std::string m)
|
||||
: module(std::move(m))
|
||||
{
|
||||
ghoul_assert(!module.empty(), "Module name must not be empty");
|
||||
|
||||
documentation::testSpecificationAndThrow(Documentation(), dictionary, "SceneLicense");
|
||||
|
||||
name = dictionary.value<std::string>(LicenseKeyName);
|
||||
attribution = dictionary.value<std::string>(LicenseKeyAttribution);
|
||||
dictionary.getValue(LicenseKeyUrl, url);
|
||||
licenseText = dictionary.value<std::string>(LicenseKeyLicenseText);
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
@@ -0,0 +1,82 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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/scene/scenelicensewriter.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace {
|
||||
const char* MainTemplateFilename = "${OPENSPACE_DATA}/web/scenelicense/main.hbs";
|
||||
const char* SceneLicenseTemplateFilename = "${OPENSPACE_DATA}/web/scenelicense/scenelicense.hbs";
|
||||
const char* JsFilename = "${OPENSPACE_DATA}/web/scenelicense/script.js";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
SceneLicenseWriter::SceneLicenseWriter(const std::vector<SceneLicense>& licenses)
|
||||
: DocumentationGenerator(
|
||||
"Documentation",
|
||||
"sceneLicenses",
|
||||
{
|
||||
{ "sceneLicenseTemplate", SceneLicenseTemplateFilename },
|
||||
{ "mainTemplate", MainTemplateFilename }
|
||||
},
|
||||
JsFilename
|
||||
)
|
||||
, _licenses(licenses)
|
||||
{}
|
||||
|
||||
std::string SceneLicenseWriter::generateJson() const {
|
||||
std::stringstream json;
|
||||
json << "[";
|
||||
for (const SceneLicense& license : _licenses) {
|
||||
json << "{";
|
||||
json << "\"module\": \"" << escapedJson(license.module) << "\", ";
|
||||
json << "\"name\": \"" << escapedJson(license.name) << "\", ";
|
||||
json << "\"attribution\": \"" << escapedJson(license.attribution) << "\", ";
|
||||
json << "\"url\": \"" << escapedJson(license.url) << "\", ";
|
||||
json << "\"licenseText\": \"" << escapedJson(license.licenseText) << "\"";
|
||||
json << "}";
|
||||
|
||||
if (&license != &(_licenses.back())) {
|
||||
json << ",";
|
||||
}
|
||||
}
|
||||
|
||||
json << "]";
|
||||
|
||||
|
||||
std::string jsonString = "";
|
||||
for (const char& c : json.str()) {
|
||||
if (c == '\'') {
|
||||
jsonString += "\\'";
|
||||
} else {
|
||||
jsonString += c;
|
||||
}
|
||||
}
|
||||
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
+66
-12
@@ -40,6 +40,7 @@ namespace {
|
||||
const char* KeyPathScene = "ScenePath";
|
||||
const char* KeyModules = "Modules";
|
||||
const char* ModuleExtension = ".mod";
|
||||
const char* LicenseExtension = ".license";
|
||||
//const char* KeyPathModule = "ModulePath";
|
||||
|
||||
//const char* RootNodeName = "Root";
|
||||
@@ -97,6 +98,7 @@ std::unique_ptr<Scene> SceneLoader::loadScene(const std::string& path) {
|
||||
std::vector<std::string> keys = moduleDictionary.keys();
|
||||
|
||||
std::vector<SceneLoader::LoadedNode> allNodes;
|
||||
std::vector<SceneLicense> allLicenses;
|
||||
|
||||
{
|
||||
// Inside loadDirectory the working directory is changed (for now), so we need
|
||||
@@ -112,8 +114,19 @@ std::unique_ptr<Scene> SceneLoader::loadScene(const std::string& path) {
|
||||
std::replace(fullName.begin(), fullName.end(), '/', FileSys.PathSeparator);
|
||||
std::string path = FileSys.pathByAppendingComponent(modulesPath, fullName);
|
||||
|
||||
std::vector<SceneLoader::LoadedNode> nodes = loadDirectory(path, state);
|
||||
std::move(nodes.begin(), nodes.end(), std::back_inserter(allNodes));
|
||||
std::pair<std::vector<SceneLoader::LoadedNode>, std::vector<SceneLicense>>
|
||||
nodes = loadDirectory(path, state);
|
||||
|
||||
std::move(
|
||||
nodes.first.begin(),
|
||||
nodes.first.end(),
|
||||
std::back_inserter(allNodes)
|
||||
);
|
||||
std::move(
|
||||
nodes.second.begin(),
|
||||
nodes.second.end(),
|
||||
std::back_inserter(allLicenses)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +138,10 @@ std::unique_ptr<Scene> SceneLoader::loadScene(const std::string& path) {
|
||||
|
||||
addLoadedNodes(*scene, std::move(allNodes));
|
||||
|
||||
for (SceneLicense& l : allLicenses) {
|
||||
scene->addSceneLicense(std::move(l));
|
||||
}
|
||||
|
||||
ghoul::Dictionary cameraDictionary;
|
||||
sceneDictionary.getValue(KeyCamera, cameraDictionary);
|
||||
LoadedCamera loadedCamera = loadCamera(cameraDictionary);
|
||||
@@ -145,7 +162,8 @@ std::unique_ptr<Scene> SceneLoader::loadScene(const std::string& path) {
|
||||
return scene;
|
||||
}
|
||||
|
||||
std::vector<SceneGraphNode*> SceneLoader::importDirectory(Scene& scene, const std::string& path) {
|
||||
std::pair<std::vector<SceneGraphNode*>, std::vector<SceneLicense>>
|
||||
SceneLoader::importDirectory(Scene& scene, const std::string& path) {
|
||||
lua_State* state = ghoul::lua::createNewLuaState();
|
||||
OnExit(
|
||||
// Delete the Lua state at the end of the scope, no matter what.
|
||||
@@ -156,9 +174,11 @@ std::vector<SceneGraphNode*> SceneLoader::importDirectory(Scene& scene, const st
|
||||
std::string absDirectoryPath = absPath(path);
|
||||
|
||||
ghoul::filesystem::Directory oldDirectory = FileSys.currentDirectory();
|
||||
std::vector<SceneLoader::LoadedNode> nodes = loadDirectory(path, state);
|
||||
std::pair<std::vector<SceneLoader::LoadedNode>, std::vector<SceneLicense>>
|
||||
nodes = loadDirectory(path, state);
|
||||
|
||||
FileSys.setCurrentDirectory(oldDirectory);
|
||||
return addLoadedNodes(scene, std::move(nodes));
|
||||
return { addLoadedNodes(scene, std::move(nodes.first)), nodes.second };
|
||||
}
|
||||
|
||||
SceneGraphNode* SceneLoader::importNodeDictionary(Scene& scene, const ghoul::Dictionary& dict) {
|
||||
@@ -198,14 +218,15 @@ SceneLoader::LoadedCamera SceneLoader::loadCamera(const ghoul::Dictionary& camer
|
||||
}
|
||||
|
||||
|
||||
std::vector<SceneLoader::LoadedNode> SceneLoader::loadDirectory(
|
||||
std::pair<std::vector<SceneLoader::LoadedNode>, std::vector<SceneLicense>>
|
||||
SceneLoader::loadDirectory(
|
||||
const std::string& path,
|
||||
lua_State* luaState)
|
||||
{
|
||||
std::string::size_type pos = path.find_last_of(FileSys.PathSeparator);
|
||||
if (pos == std::string::npos) {
|
||||
LERROR("Error parsing directory name '" << path << "'");
|
||||
return std::vector<SceneLoader::LoadedNode>();
|
||||
return {};
|
||||
}
|
||||
std::string moduleName = path.substr(pos + 1);
|
||||
std::string moduleFile = FileSys.pathByAppendingComponent(path, moduleName) + ModuleExtension;
|
||||
@@ -218,9 +239,18 @@ std::vector<SceneLoader::LoadedNode> SceneLoader::loadDirectory(
|
||||
FileSys.setCurrentDirectory(ghoul::filesystem::Directory(path));
|
||||
|
||||
// We have a module file, so it is a direct include.
|
||||
return loadModule(moduleFile, luaState);
|
||||
std::vector<SceneLoader::LoadedNode> nodes = loadModule(moduleFile, luaState);
|
||||
|
||||
std::vector<SceneLicense> licenses;
|
||||
std::string licenseFile = FileSys.pathByAppendingComponent(path, moduleName) + LicenseExtension;
|
||||
if (FileSys.fileExists(licenseFile)) {
|
||||
licenses = loadLicense(licenseFile, moduleName);
|
||||
}
|
||||
|
||||
return { std::move(nodes), licenses };
|
||||
} else {
|
||||
std::vector<SceneLoader::LoadedNode> allLoadedNodes;
|
||||
std::vector<SceneLicense> allLicenses;
|
||||
// If we do not have a module file, we have to include all subdirectories.
|
||||
using ghoul::filesystem::Directory;
|
||||
using std::string;
|
||||
@@ -230,14 +260,25 @@ std::vector<SceneLoader::LoadedNode> SceneLoader::loadDirectory(
|
||||
|
||||
if (!FileSys.directoryExists(directoryPath)) {
|
||||
LERROR("The directory " << directoryPath << " does not exist.");
|
||||
return std::vector<SceneLoader::LoadedNode>();
|
||||
return {};
|
||||
}
|
||||
|
||||
for (const string& subdirectory : directory.readDirectories()) {
|
||||
std::vector<SceneLoader::LoadedNode> loadedNodes = loadDirectory(subdirectory, luaState);
|
||||
std::move(loadedNodes.begin(), loadedNodes.end(), std::back_inserter(allLoadedNodes));
|
||||
std::pair<std::vector<SceneLoader::LoadedNode>, std::vector<SceneLicense>>
|
||||
loadedNodes = loadDirectory(subdirectory, luaState);
|
||||
|
||||
std::move(
|
||||
loadedNodes.first.begin(),
|
||||
loadedNodes.first.end(),
|
||||
std::back_inserter(allLoadedNodes)
|
||||
);
|
||||
std::move(
|
||||
loadedNodes.second.begin(),
|
||||
loadedNodes.second.end(),
|
||||
std::back_inserter(allLicenses)
|
||||
);
|
||||
}
|
||||
return allLoadedNodes;
|
||||
return { std::move(allLoadedNodes), std::move(allLicenses) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,6 +350,19 @@ std::vector<SceneLoader::LoadedNode> SceneLoader::loadModule(const std::string&
|
||||
return loadedNodes;
|
||||
}
|
||||
|
||||
std::vector<SceneLicense> SceneLoader::loadLicense(const std::string& path, std::string module) {
|
||||
ghoul::Dictionary licenseDictionary;
|
||||
try {
|
||||
ghoul::lua::loadDictionaryFromFile(path, licenseDictionary);
|
||||
} catch (const ghoul::lua::LuaRuntimeException& e) {
|
||||
LERRORC(e.component, e.message);
|
||||
return {};
|
||||
}
|
||||
|
||||
SceneLicense license(licenseDictionary, module);
|
||||
return { license };
|
||||
}
|
||||
|
||||
std::vector<SceneGraphNode*> SceneLoader::addLoadedNodes(Scene& scene, std::vector<SceneLoader::LoadedNode>&& loadedNodes) {
|
||||
std::map<std::string, SceneGraphNode*> existingNodes = scene.nodesByName();
|
||||
std::map<std::string, SceneGraphNode*> addedNodes;
|
||||
|
||||
Reference in New Issue
Block a user