This commit is contained in:
2021-10-14 13:47:35 +02:00
commit 6625a8dfaa
4026 changed files with 844291 additions and 0 deletions
@@ -0,0 +1,138 @@
#pragma once
#include "ovsgCSkeletonGenerator.h"
#include <map>
#include <vector>
namespace OpenViBE {
namespace SkeletonGenerator {
class CBoxAlgorithmSkeletonGenerator final : public CSkeletonGenerator
{
public:
CBoxAlgorithmSkeletonGenerator(Kernel::IKernelContext& ctx, GtkBuilder* builder) : CSkeletonGenerator(ctx, builder) { }
~CBoxAlgorithmSkeletonGenerator() override { }
bool initialize() override;
bool save(const std::string& filename) override;
bool load(const std::string& filename) override;
void getCurrentParameters() override;
// Box Description
std::string m_Name, m_Version, m_ClassName, m_Category, m_ShortDesc, m_DetailedDesc;
std::string m_GtkStockItemName;
int m_GtkStockItemIdx = 0;
struct SIOS
{
std::string name, type, typeID, defaultValue;
};
// Inputs
bool m_CanModifyInputs = false, m_CanAddInputs = false;
std::vector<SIOS> m_Inputs;
// Outputs
bool m_CanModifyOutputs = false, m_CanAddOutputs = false;
std::vector<SIOS> m_Outputs;
// Settings
bool m_CanModifySettings = false, m_CanAddSettings = false;
std::vector<SIOS> m_Settings;
//Algorithms
std::vector<std::string> m_Algorithms; // the algorithm selected by user
// Can be made non-const after '= false' produces working code
static const bool USE_CODEC_TOOLKIT = true; // use or not the codec toolkit for encoder and decoder algorithms
//the map between algorithm and corresponding header declaration (all variables algo/input/output).
std::map<std::string, std::string> m_AlgoDeclaration;
//the map between algorithm and corresponding initialisation
std::map<std::string, std::string> m_AlgoInitialisations;
//the map between algorithm and corresponding initialisation of ref targets
std::map<std::string, std::string> m_AlgoInitialisationReferenceTargets;
//the map between algorithm and corresponding uninitialisation
std::map<std::string, std::string> m_AlgoUninitialisations;
// Box Listener
bool m_UseBoxListener = false;
// input
bool m_HasOnInputAdded = false;
bool m_HasOnInputRemoved = false;
bool m_HasOnInputTypeChanged = false;
bool m_HasOnInputNameChanged = false;
bool m_HasOnInputConnected = false;
bool m_HasOnInputDisconnected = false;
// output
bool m_HasOnOutputAdded = false;
bool m_HasOnOutputRemoved = false;
bool m_HasOnOutputTypeChanged = false;
bool m_HasOnOutputNameChanged = false;
bool m_HasOnOutputConnected = false;
bool m_HasOnOutputDisconnected = false;
// setting
bool m_HasOnSettingAdded = false;
bool m_HasOnSettingRemoved = false;
bool m_HasOnSettingTypeChanged = false;
bool m_HasOnSettingNameChanged = false;
bool m_HasOnSettingDefaultValueChanged = false;
bool m_HasOnSettingValueChanged = false;
bool m_HasProcessInput = false;
bool m_HasProcessClock = false;
bool m_HasProcessMessage = false;
uint32_t m_ClockFrequency = 0;
void buttonCheckCB();
void buttonOkCB();
void toggleListenerCheckbuttonsStateCB(bool state) const;
void buttonTooltipCB(GtkButton* button);
void buttonExitCB();
void buttonAddInputCB() const;
void buttonAddOutputCB() const;
void buttonAddSettingCB() const;
void buttonAddAlgorithmCB() const;
void buttonRemoveGeneric(const char* buttonName) const;
void algorithmSelectedCB(int index);
void setSensitivity(const char* widgetName, bool isActive) const;
private:
Kernel::ILogManager& getLogManager() const override { return m_kernelCtx.getLogManager(); }
Kernel::IErrorManager& getErrorManager() const override { return m_kernelCtx.getErrorManager(); }
static std::string getRandomIdentifierString() { return CIdentifier::random().str(); }
// Sanity checks that a string is not empty or consist of spaces
static bool isStringValid(const std::string& str) { return !str.empty() && str.find_first_not_of(' ') != std::string::npos; }
void clearStore(const char* name) const;
void addDialogButttons(const char* name) const;
void setEntryToConfigValue(const char* name, const char* token) const;
void setActiveFromConf(const char* name, const char* token) const;
void setActiveFromConfTog(const char* name, const char* token) const;
const gchar* getText(const char* name) const;
void addCollectionToTree(const char* treeName, const std::vector<std::string>& collection) const;
void fillCollection(const char* treeName, std::vector<SIOS>& collection) const;
bool isActive(char* name) const;
std::map<GtkButton*, std::string> m_tooltips;
std::vector<std::string> m_typeCorrespondances;
};
class CDummyAlgoProto final : public Kernel::IAlgorithmProto
{
public:
std::map<std::string, Kernel::EParameterType> m_Inputs, m_Outputs;
std::vector<std::string> m_InputTriggers, m_OutputTriggers;
bool addInputParameter(const CIdentifier& id, const CString& name, Kernel::EParameterType typeID,
const CIdentifier& subTypeID = CIdentifier::undefined()) override;
bool addOutputParameter(const CIdentifier& id, const CString& name, Kernel::EParameterType typeID,
const CIdentifier& subTypeID = CIdentifier::undefined()) override;
bool addInputTrigger(const CIdentifier& id, const CString& name) override;
bool addOutputTrigger(const CIdentifier& id, const CString& name) override;
CIdentifier getClassIdentifier() const override { return CIdentifier::undefined(); }
};
} // namespace SkeletonGenerator
} // namespace OpenViBE
@@ -0,0 +1,504 @@
#include "ovsgCDriverSkeletonGenerator.h"
#include <iostream>
#include <sstream>
#include <fstream>
#include <glib/gstdio.h>
#include <cstdio>
#include <boost/regex.hpp>
namespace OpenViBE {
namespace SkeletonGenerator {
//-----------------------------------------------------------------------
static void CheckCB(GtkButton* /*button*/, void* data) { static_cast<CDriverSkeletonGenerator*>(data)->buttonCheckCB(); }
static void TooltipCB(GtkButton* button, void* data) { static_cast<CDriverSkeletonGenerator*>(data)->buttonTooltipCB(button); }
static void OkCB(GtkButton* /*button*/, void* data) { static_cast<CDriverSkeletonGenerator*>(data)->buttonOkCB(); }
static void ExitCB(GtkButton* /*button*/, void* data)
{
static_cast<CDriverSkeletonGenerator*>(data)->buttonExitCB();
gtk_exit(0);
}
//-----------------------------------------------------------------------
void CDriverSkeletonGenerator::buttonExitCB()
{
getCommonParameters();
getCurrentParameters();
if (!cleanConfigurationFile(m_configFile)) { return; }
saveCommonParameters(m_configFile);
save(m_configFile);
getLogManager() << Kernel::LogLevel_Info << "All entries saved in [" << m_configFile << "]. Exiting.\n";
}
void CDriverSkeletonGenerator::buttonCheckCB()
{
//Author and Company
getCommonParameters();
getCurrentParameters();
getLogManager() << Kernel::LogLevel_Info << "Checking values... \n";
bool success = true;
std::stringstream ss;
ss << "----- STATUS -----\n";
//-------------------------------------------------------------------------------------------------------------------------------------------//
//::GtkWidget * driverName = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_driver_name"));
//m_DriverName = gtk_entry_get_text(GTK_ENTRY(driverName));
const boost::regex regExpDriverName("([a-z]|[A-Z]|[0-9])+([a-z]|[A-Z]|[0-9]|[ \t\r\n]|[\\.-_\\(\\)])*", boost::regex::perl);
if (regex_match(std::string(m_DriverName), regExpDriverName) == false)
{
OV_WARNING_K("-- Driver Name: INVALID");
success = false;
ss << "[FAILED] Invalid driver name. Please use only characters (lower or uppercase) and numbers (blanck allowed).\n";
}
else
{
getLogManager() << Kernel::LogLevel_Info << "-- Driver Name: VALID (" << m_DriverName << ")\n";
ss << "[ OK ] Valid driver name.\n";
}
//-------------------------------------------------------------------------------------------------------------------------------------------//
//::GtkWidget * className = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_class_name"));
//m_ClassName = gtk_entry_get_text(GTK_ENTRY(className));
const boost::regex regExpClassName("([a-z]|[A-Z]|[0-9])+", boost::regex::perl);
if (regex_match(std::string(m_ClassName), regExpClassName) == false)
{
OV_WARNING_K("-- Class Name: INVALID");
success = false;
ss << "[FAILED] Invalid class name. Please use only characters (lower or uppercase) and numbers (no blanck allowed).\n";
}
else
{
getLogManager() << Kernel::LogLevel_Info << "-- Class Name: VALID (" << m_ClassName << ")\n";
ss << "[ OK ] Valid class name.\n";
}
//-------------------------------------------------------------------------------------------------------------------------------------------//
GtkWidget* spinMinChannel = GTK_WIDGET(gtk_builder_get_object(m_builder, "spinbutton_min_channel"));
//m_MinChannel = std::to_string(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinMinChannel)))).c_str();
GtkWidget* spinMaxChannel = GTK_WIDGET(gtk_builder_get_object(m_builder, "spinbutton_max_channel"));
//m_MaxChannel = std::to_string(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinMaxChannel)))).c_str();
if (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinMinChannel)) > gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinMaxChannel)))
{
OV_WARNING_K(Kernel::LogLevel_Warning << "-- Channels: INVALID");
success = false;
ss << "[FAILED] Invalid channel count. Be sure that Min <= Max.\n";
}
else
{
getLogManager() << Kernel::LogLevel_Info << "-- Channels: VALID (" << m_MinChannel << "/" << m_MaxChannel << ")\n";
ss << "[ OK ] Valid channel count.\n";
}
//-------------------------------------------------------------------------------------------------------------------------------------------//
/*::GtkWidget * sf = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_sampling_frequencies"));
CString samplings = gtk_entry_get_text(GTK_ENTRY(sf));
*/
const boost::regex regExpSamplings("(([1-9][0-9]*);)*([1-9][0-9]*)", boost::regex::perl);
if (regex_match(m_Samplings, regExpSamplings) == false)
{
OV_WARNING_K("-- Sampling frequencies: INVALID");
success = false;
ss << "[FAILED] Invalid sampling frequencies. Please use only whole numbers separated with ';' (no blanck allowed).\n";
}
else
{
// Maximum 16 frequencies
size_t nSampling = 0;
size_t freq;
std::stringstream tmp(m_Samplings);
m_SamplingSeparate.clear();
while (tmp >> freq && nSampling < 16)
{
m_SamplingSeparate.push_back(std::to_string(freq));
if (tmp.peek() == ';') { tmp.ignore(); }
nSampling++;
}
getLogManager() << Kernel::LogLevel_Info << "-- Sampling frequencies: VALID\n";
for (const auto& s : m_SamplingSeparate) { std::cout << "- " << s << " Hz\n"; }
ss << "[ OK ] " << nSampling << " valid sampling frequencie(s).\n";
}
//-------------------------------------------------------------------------------------------------------------------------------------------//
/*::GtkWidget * fileChooser = GTK_WIDGET(gtk_builder_get_object(m_builder, "filechooserbutton_target_directory"));
char * directory = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fileChooser));
m_directory = CString(directory);
g_free(directory);*/
#ifdef TARGET_OS_Windows
const std::string space("%20");
if (m_directory.rfind(space) != std::string::npos)
{
ss << "[FAILED] Invalid destination folder :" << m_directory << ".\n";
getLogManager() << Kernel::LogLevel_Error << "Invalid destination folder :" << m_directory << ".\n";
success = false;
}
else
#endif
{
getLogManager() << Kernel::LogLevel_Info << "-- Target directory: " << m_directory << "\n";
ss << "[ OK ] Valid target directory: " << m_directory << "\n";
}
//-------------------------------------------------------------------------------------------------------------------------------------------//
GtkWidget* textview = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-tooltips-textview"));
GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
if (success)
{
ss << "----- SUCCESS -----\nPress OK to generate the files. If you want to modify your choice(s), please press the \"Check\" button again.";
GtkWidget* buttonOk = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-ok-button"));
gtk_widget_set_sensitive(buttonOk, true);
}
else
{
ss << "----- PROCESS FAILED -----\nModify your choices and press the \"Check\" button again.";
GtkWidget* buttonOk = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-ok-button"));
gtk_widget_set_sensitive(buttonOk, false);
}
gtk_text_buffer_set_text(buffer, ss.str().c_str(), -1);
}
void CDriverSkeletonGenerator::buttonOkCB()
{
getLogManager() << Kernel::LogLevel_Info << "Generating files... \n";
std::string log = "Generating files...\n";
bool success = true;
const std::string date = getDate();
// we construct the map of substitutions
std::map<std::string, std::string> substitutions;
substitutions["@@AuthorName@@"] = m_author;
substitutions["@@CompanyName@@"] = m_company;
substitutions["@@Date@@"] = date;
substitutions["@@ClassName@@"] = m_ClassName;
substitutions["@@DriverName@@"] = m_DriverName;
substitutions["@@MinChannel@@"] = m_MinChannel;
substitutions["@@MaxChannel@@"] = m_MaxChannel;
substitutions["@@SamplingFrequency@@"] = m_SamplingSeparate[0];
GtkWidget* textview = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-tooltips-textview"));
GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
//-------------------------------------------------------------------------------------------------------------------------------------------//
// driver.h
std::string dst = m_directory + "/ovasCDriver" + m_ClassName + ".h";
std::string tmplate = m_kernelCtx.getConfigurationManager().expand("${Path_Data}/applications/skeleton-generator/driver.h-skeleton").toASCIIString();
if (!this->generate(tmplate, dst, substitutions, log))
{
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
success = false;
}
//-------------------------------------------------------------------------------------------------------------------------------------------//
// driver.cpp
dst = m_directory + "/ovasCDriver" + m_ClassName + ".cpp";
tmplate = m_kernelCtx.getConfigurationManager().expand("${Path_Data}/applications/skeleton-generator/driver.cpp-skeleton").toASCIIString();
if (!this->generate(tmplate, dst, substitutions, log))
{
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
success = false;
}
//-------------------------------------------------------------------------------------------------------------------------------------------//
// config.h
dst = m_directory + "/ovasCConfiguration" + m_ClassName + ".h";
tmplate = m_kernelCtx.getConfigurationManager().expand("${Path_Data}/applications/skeleton-generator/configuration.h-skeleton").toASCIIString();
if (!this->generate(tmplate, dst, substitutions, log))
{
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
success = false;
}
//-------------------------------------------------------------------------------------------------------------------------------------------//
// config.cpp
dst = m_directory + "/ovasCConfiguration" + m_ClassName + ".cpp";
tmplate = m_kernelCtx.getConfigurationManager().expand("${Path_Data}/applications/skeleton-generator/configuration.cpp-skeleton").toASCIIString();
if (!this->generate(tmplate, dst, substitutions, log))
{
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
success = false;
}
//-------------------------------------------------------------------------------------------------------------------------------------------//
// interface.ui
dst = m_directory + "/interface-" + m_ClassName + ".ui";
tmplate = m_kernelCtx.getConfigurationManager().expand("${Path_Data}/applications/skeleton-generator/interface.ui-skeleton").toASCIIString();
if (!this->generate(tmplate, dst, substitutions, log))
{
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
success = false;
}
// the following substitution is done in a .ui file, and not in a cpp file.
// The SED primitive immplemented do not cover that case, and some typo problem happen with the character "
const std::string pattern("@@SamplingFrequencyList@@");
std::string substitute;
for (auto it = m_SamplingSeparate.begin(); it != m_SamplingSeparate.end();)
{
substitute += (*it++);
if (it != m_SamplingSeparate.end()) { substitute += "<\\/col><\\/row><row><col id=\\\"0\\\" translatable=\\\"yes\\\">"; }
}
success &= regexReplace(dst, pattern, substitute, "");
//-------------------------------------------------------------------------------------------------------------------------------------------//
// readme-driver.txt
dst = m_directory + "/README.txt";
tmplate = m_kernelCtx.getConfigurationManager().expand("${Path_Data}/applications/skeleton-generator/readme-driver.txt-skeleton");
if (!this->generate(tmplate, dst, substitutions, log))
{
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
success = false;
}
//-------------------------------------------------------------------------------------------------------------------------------------------//
if (success)
{
success &= cleanConfigurationFile(m_configFile);
success &= saveCommonParameters(m_configFile);
success &= save(m_configFile);
}
if (!success)
{
log += "Generation process did not completly succeed. Some files may have not been produced.\n";
OV_WARNING_K("Generation process did not completly succeed. Some files may have not been produced.");
}
else
{
log += "Generation process successful. All information saved in [" + m_configFile + "]\nPlease read the file [README.txt] !\n";
getLogManager() << Kernel::LogLevel_Info << "Generation process successful. All information saved in [" << m_configFile << "]\n";
}
// Launch the browser to display the produced files
const std::string browser = m_kernelCtx.getConfigurationManager().expand("${Designer_WebBrowserCommand_${OperatingSystem}}").toASCIIString();
#ifdef TARGET_OS_Windows
const std::string browserCmd = browser + " file:///" + m_directory; //otherwise the browser does not find the directory (problem with / and \ char)
#else
const std::string browserCmd = browser + " \"" + m_directory + "\"";
#endif
if (system(browserCmd.c_str())) { }
gtk_text_buffer_set_text(buffer, log.c_str(), -1);
}
void CDriverSkeletonGenerator::buttonTooltipCB(GtkButton* button)
{
const EWidgetName widgetName = m_widgetNames[button];
GtkWidget* textview = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-tooltips-textview"));
GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
if (widgetName == EWidgetName::DriverName)
{
gtk_text_buffer_set_text(buffer,
"Driver Name: \nThis name will be the one displayed in the Acquisition Server selection combobox.\nUsually, the driver is named according to the EEG device (with precisions such as a version number).\n------\nExample: OpenEEG Modular EEG (P2)\n\n\n",
-1);
}
else if (widgetName == EWidgetName::ClassName)
{
gtk_text_buffer_set_text(buffer,
"Class Name: \nThis name will be used to generate all source and GUI files.\nYou should choose a class name close to the device name (no blank allowed !).\n------\nExample: OpenEEGModularEEG will generate\n - ovasCDriverOpenEEGModularEEG.h/.cpp, the driver skeleton \n - ovasCConfigurationOpenEEGModularEEG.h/.cpp, the configuration class skeleton\n - interface-OpenEEG-ModularEEG.ui, the GUI description file",
-1);
}
else if (widgetName == EWidgetName::ChannelCount)
{
gtk_text_buffer_set_text(buffer,
"Channel count: \nEnter in the two fields the minimum and maximum number of channels the device is capable of.\nOf course you can still change it later in the source code.\n------\nExample: Min(1) Max(16)\n\n\n",
-1);
}
else if (widgetName == EWidgetName::Sampling)
{
gtk_text_buffer_set_text(buffer,
"Sampling frequencies: \nEnter in the text field the sampling frequencies your device is capable of.\nYou can specify a list of defined frequencies (value separator ';').\n------\nExample:\n\"128;256;512\" for three defined frequencies.\n\n",
-1);
}
else if (widgetName == EWidgetName::Directory)
{
gtk_text_buffer_set_text(buffer,
"Target directory: \nEnter the destination directory in which all files will be generated. \nAny existing files will be overwritten.\n------\nExample: ~/skeleton-generator/foobar-driver/\n\n\n",
-1);
}
else { }
}
bool CDriverSkeletonGenerator::initialize()
{
GtkWidget* driver = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-window"));
// Buttons and signals
GtkWidget* buttonCheck = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-check-button"));
GtkWidget* buttonOk = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-ok-button"));
g_signal_connect(buttonCheck, "pressed", G_CALLBACK(CheckCB), this);
g_signal_connect(buttonOk, "pressed", G_CALLBACK(OkCB), this);
////target directory
//::GtkWidget * fileChooser = GTK_WIDGET(gtk_builder_get_object(m_builder, "filechooserbutton_target_directory"));
//CString directory = m_kernelContext.getConfigurationManager().expand("${SkeletonGenerator_TargetDirectory}");
//if(!gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fileChooser), directory.c_str()))
//{
// gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fileChooser),"..");
//}
// Tooltips buttons and signal
GtkButton* buttonDriverName = GTK_BUTTON(gtk_builder_get_object(m_builder, "sg-driver-driver-name-tooltip-button"));
GtkButton* buttonClassName = GTK_BUTTON(gtk_builder_get_object(m_builder, "sg-driver-class-name-tooltip-button"));
GtkButton* buttonChannelCount = GTK_BUTTON(gtk_builder_get_object(m_builder, "sg-driver-channel-count-tooltip-button"));
GtkButton* buttonSampling = GTK_BUTTON(gtk_builder_get_object(m_builder, "sg-driver-sampling-frequencies-tooltip-button"));
GtkButton* buttonDirectory = GTK_BUTTON(gtk_builder_get_object(m_builder, "sg-driver-target-directory-tooltip-button"));
m_widgetNames[buttonDriverName] = EWidgetName::DriverName;
m_widgetNames[buttonClassName] = EWidgetName::ClassName;
m_widgetNames[buttonChannelCount] = EWidgetName::ChannelCount;
m_widgetNames[buttonSampling] = EWidgetName::Sampling;
m_widgetNames[buttonDirectory] = EWidgetName::Directory;
g_signal_connect(buttonDriverName, "pressed", G_CALLBACK(TooltipCB), this);
g_signal_connect(buttonClassName, "pressed", G_CALLBACK(TooltipCB), this);
g_signal_connect(buttonChannelCount, "pressed", G_CALLBACK(TooltipCB), this);
g_signal_connect(buttonSampling, "pressed", G_CALLBACK(TooltipCB), this);
g_signal_connect(buttonDirectory, "pressed", G_CALLBACK(TooltipCB), this);
//Close with X and "cancel" button
g_signal_connect(G_OBJECT(driver), "delete_event", G_CALLBACK(gtk_exit), nullptr);
GtkWidget* buttonCancel = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-cancel-button"));
g_signal_connect(buttonCancel, "pressed", G_CALLBACK(ExitCB), this);
//load everything from file
load(m_configFile);
gtk_widget_show_all(driver);
return true;
}
bool CDriverSkeletonGenerator::save(const std::string& filename)
{
std::ofstream file;
file.open(filename, std::ios::app | std::ios::binary);
OV_ERROR_UNLESS_KRF(file.is_open(), "Saving the driver entries in [" << m_configFile << "] failed !", Kernel::ErrorType::BadFileWrite);
file << "# ----------------------DRIVER-------------------------\n";
std::string directory(m_directory);
for (auto it = directory.begin(); it < directory.end(); ++it) { if ((*it) == '\\') { directory.replace(it, it + 1, 1, '/'); } }
file << "SkeletonGenerator_Driver_DriverName = " << m_DriverName << std::endl;
file << "SkeletonGenerator_Driver_ClassName = " << m_ClassName << std::endl;
file << "SkeletonGenerator_Driver_MinChannel = " << m_MinChannel << std::endl;
file << "SkeletonGenerator_Driver_MaxChannel = " << m_MaxChannel << std::endl;
file << "SkeletonGenerator_Driver_SamplingFrequencies = " << m_Samplings << std::endl;
file << "SkeletonGenerator_Driver_TargetDirectory = " << directory << std::endl;
file << "# -----------------------------------------------------" << std::endl;
file.close();
getLogManager() << Kernel::LogLevel_Info << "Driver entries saved in [" << m_configFile << "]\n";
m_configFileLoaded = false;
return true;
}
bool CDriverSkeletonGenerator::load(const std::string& filename)
{
if (!m_configFileLoaded && !m_kernelCtx.getConfigurationManager().addConfigurationFromFile(filename.c_str()))
{
OV_WARNING_K("Driver: Configuration file [" << filename << "] could not be loaded. It will be automatically generated after first use.");
return false;
}
GtkWidget* driverName = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_driver_name"));
gtk_entry_set_text(GTK_ENTRY(driverName), m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_Driver_DriverName}"));
GtkWidget* className = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_class_name"));
gtk_entry_set_text(GTK_ENTRY(className), m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_Driver_ClassName}"));
GtkWidget* minChannel = GTK_WIDGET(gtk_builder_get_object(m_builder, "spinbutton_min_channel"));
gtk_spin_button_set_value(
GTK_SPIN_BUTTON(minChannel), double(m_kernelCtx.getConfigurationManager().expandAsInteger("${SkeletonGenerator_Driver_MinChannel}")));
GtkWidget* maxChannel = GTK_WIDGET(gtk_builder_get_object(m_builder, "spinbutton_max_channel"));
gtk_spin_button_set_value(
GTK_SPIN_BUTTON(maxChannel), double(m_kernelCtx.getConfigurationManager().expandAsInteger("${SkeletonGenerator_Driver_MaxChannel}")));
GtkWidget* sf = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_sampling_frequencies"));
gtk_entry_set_text(GTK_ENTRY(sf), m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_Driver_SamplingFrequencies}"));
GtkWidget* fileChooser = GTK_WIDGET(gtk_builder_get_object(m_builder, "filechooserbutton_target_directory"));
// if the user specified a target directory, it has full priority
std::string directory = m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_TargetDirectory}").toASCIIString();
#ifdef TARGET_OS_Linux
bool needFilePrefix = false;
#endif
if (!directory.empty())
{
getLogManager() << Kernel::LogLevel_Debug << "Target dir user [" << directory << "]\n";
#ifdef TARGET_OS_Linux
needFilePrefix = true;
#endif
}
else
{
//previous entry
directory = m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_Driver_TargetDirectory}");
if (!directory.empty())
{
getLogManager() << Kernel::LogLevel_Debug << "Target previous [" << directory << "]\n";
#ifdef TARGET_OS_Linux
needFilePrefix = true;
#endif
}
else
{
//default path = dist
getLogManager() << Kernel::LogLevel_Debug << "Target default [dist]\n";
#ifdef TARGET_OS_Linux
directory = std::string(gtk_file_chooser_get_current_folder_uri(GTK_FILE_CHOOSER(fileChooser)));
directory = directory + "/..";
#elif defined TARGET_OS_Windows
directory = "..";
#endif
}
}
#ifdef TARGET_OS_Linux
if(needFilePrefix) directory = "file://" + directory;
gtk_file_chooser_set_current_folder_uri(GTK_FILE_CHOOSER(fileChooser), directory.c_str());
#elif defined TARGET_OS_Windows
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fileChooser), directory.c_str());
#endif
getLogManager() << Kernel::LogLevel_Info << "Driver entries from [" << filename << "] loaded.\n";
return true;
}
void CDriverSkeletonGenerator::getCurrentParameters()
{
GtkWidget* driverName = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_driver_name"));
m_DriverName = gtk_entry_get_text(GTK_ENTRY(driverName));
GtkWidget* className = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_class_name"));
m_ClassName = gtk_entry_get_text(GTK_ENTRY(className));
GtkWidget* minChannel = GTK_WIDGET(gtk_builder_get_object(m_builder, "spinbutton_min_channel"));
m_MinChannel = std::to_string(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(minChannel))));
GtkWidget* maxChannel = GTK_WIDGET(gtk_builder_get_object(m_builder, "spinbutton_max_channel"));
m_MaxChannel = std::to_string(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(maxChannel))));
GtkWidget* sf = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_sampling_frequencies"));
m_Samplings = gtk_entry_get_text(GTK_ENTRY(sf));
GtkWidget* fileChooser = GTK_WIDGET(gtk_builder_get_object(m_builder, "filechooserbutton_target_directory"));
char* directory = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fileChooser));
m_directory = CString(directory);
g_free(directory);
}
} // namespace SkeletonGenerator
} // namespace OpenViBE
@@ -0,0 +1,51 @@
#pragma once
#include "ovsgCSkeletonGenerator.h"
#include <vector>
#include <map>
namespace OpenViBE {
namespace SkeletonGenerator {
class CDriverSkeletonGenerator final : public CSkeletonGenerator
{
public:
CDriverSkeletonGenerator(Kernel::IKernelContext& ctx, GtkBuilder* builder) : CSkeletonGenerator(ctx, builder) { }
~CDriverSkeletonGenerator() override { }
bool initialize() override;
bool save(const std::string& filename) override;
bool load(const std::string& filename) override;
void getCurrentParameters() override;
std::string m_DriverName;
std::string m_ClassName;
std::string m_Samplings;
std::vector<std::string> m_SamplingSeparate;
std::string m_MinChannel;
std::string m_MaxChannel;
void buttonCheckCB();
void buttonOkCB();
void buttonTooltipCB(GtkButton* button);
void buttonExitCB();
private:
Kernel::ILogManager& getLogManager() const override { return m_kernelCtx.getLogManager(); }
Kernel::IErrorManager& getErrorManager() const override { return m_kernelCtx.getErrorManager(); }
enum class EWidgetName
{
DriverName,
ClassName,
ChannelCount,
Sampling,
Directory,
};
std::map<GtkButton*, EWidgetName> m_widgetNames;
};
} // namespace SkeletonGenerator
} // namespace OpenViBE
@@ -0,0 +1,249 @@
#include "ovsgCSkeletonGenerator.h"
#include <string>
#include <ctime>
#include <sstream>
#include <fstream>
#include <iostream>
#include <iterator>
#include <boost/regex.hpp>
namespace OpenViBE {
namespace SkeletonGenerator {
CSkeletonGenerator::CSkeletonGenerator(Kernel::IKernelContext& ctx, GtkBuilder* builder)
: m_kernelCtx(ctx), m_builder(builder)
{
m_configFile = m_kernelCtx.getConfigurationManager().expand("${CustomConfigurationApplication}");
m_kernelCtx.getLogManager() << Kernel::LogLevel_Trace << "Configuration file [" << m_configFile << "]\n";
loadCommonParameters(m_configFile);
}
void CSkeletonGenerator::getCommonParameters()
{
//Author and Company
GtkWidget* company = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_company_name"));
m_company = gtk_entry_get_text(GTK_ENTRY(company));
GtkWidget* author = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_author_name"));
m_author = gtk_entry_get_text(GTK_ENTRY(author));
}
bool CSkeletonGenerator::saveCommonParameters(const std::string& filename)
{
// we get the latest values
getCommonParameters();
std::ofstream file;
file.open(filename, std::ios::app | std::ios::binary);
OV_ERROR_UNLESS_KRF(file.is_open(), "Saving the common entries in [" << filename << "] failed !", Kernel::ErrorType::BadFileRead);
// generator selected
std::string active;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_builder, "sg-driver-selection-radio-button")))) { active = "0"; }
else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_builder, "sg-algo-selection-radio-button")))) { active = "1"; }
else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_builder, "sg-box-selection-radio-button")))) { active = "2"; }
file << "SkeletonGenerator_GeneratorSelected = " << active << std::endl;
file << "SkeletonGenerator_Common_Author = " << m_author << std::endl;
file << "SkeletonGenerator_Common_Company = " << m_company << std::endl;
file.close();
getLogManager() << Kernel::LogLevel_Info << "Common entries saved in [" << filename << "]\n";
//we can reload the file, it may have changed
m_configFileLoaded = false;
return true;
}
bool CSkeletonGenerator::cleanConfigurationFile(const std::string& filename) const
{
std::ofstream file;
file.open(filename, std::ios::binary);
OV_ERROR_UNLESS_KRF(file.is_open(), "Failed to clean [" << filename << "]", Kernel::ErrorType::BadFileRead);
getLogManager() << Kernel::LogLevel_Info << "Configuration file [" << filename << "] cleaned.\n";
file.close();
return true;
}
bool CSkeletonGenerator::loadCommonParameters(const std::string& filename)
{
OV_ERROR_UNLESS_KRF(m_configFileLoaded || m_kernelCtx.getConfigurationManager().addConfigurationFromFile(filename.c_str()),
"Common: Configuration file [" << filename << "] could not be loaded. \n", Kernel::ErrorType::BadFileRead);
GtkWidget* widget = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-driver-selection-radio-button"));
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(widget), (m_kernelCtx.getConfigurationManager().expandAsUInteger("${SkeletonGenerator_GeneratorSelected}") == 0));
widget = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-algo-selection-radio-button"));
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(widget), (m_kernelCtx.getConfigurationManager().expandAsUInteger("${SkeletonGenerator_GeneratorSelected}") == 1));
widget = GTK_WIDGET(gtk_builder_get_object(m_builder, "sg-box-selection-radio-button"));
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(widget), (m_kernelCtx.getConfigurationManager().expandAsUInteger("${SkeletonGenerator_GeneratorSelected}") == 2));
GtkWidget* company = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_company_name"));
gtk_entry_set_text(GTK_ENTRY(company), m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_Common_Company}"));
GtkWidget* author = GTK_WIDGET(gtk_builder_get_object(m_builder, "entry_author_name"));
gtk_entry_set_text(GTK_ENTRY(author), m_kernelCtx.getConfigurationManager().expand("${SkeletonGenerator_Common_Author}"));
getLogManager() << Kernel::LogLevel_Info << "Common entries from [" << filename << "] loaded.\n";
m_configFileLoaded = true;
return true;
}
std::string CSkeletonGenerator::ensureSedCompliancy(const std::string& expression)
{
std::string res(expression);
auto it = res.begin();
while (it < res.end())
{
if ((*it) == '\\')
{
it = res.insert(it, '\\');
++it;
it = res.insert(it, '\\');
++it;
it = res.insert(it, '\\');
++it;
#ifdef TARGET_OS_Linux
it = res.insert(it,'\\');
it = res.insert(it,'\\');
it+=2;
it = res.insert(it,'\\');
it = res.insert(it,'\\');
it+=2;
#endif
}
else if ((*it) == '/')
{
it = res.insert(it, '\\');
++it;
}
else if ((*it) == '"')
{
it = res.insert(it, '\\');
++it;
it = res.insert(it, '\\');
++it;
it = res.insert(it, '\\');
++it;
it = res.insert(it, '\\');
++it;
it = res.insert(it, '\\');
++it;
}
else if ((*it) == '\n')
{
it = res.erase(it);
#ifdef TARGET_OS_Linux
it = res.insert(it,'\\');
it = res.insert(it,'\\');
it+=2;
#endif
it = res.insert(it, '\\');
it = res.insert(it, '\\');
it += 2;
it = res.insert(it, 'n');
//++it;
}
++it;
}
return res;
}
bool CSkeletonGenerator::regexReplace(const std::string& src, const std::string& regEx, const std::string& substitute, const std::string& dst) const
{
try
{
// Read file to memory
std::ifstream in(src);
std::string buffer((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
in.close();
// Open output stream and set an iterator to it
std::string realDst((dst.empty() ? src : dst));
std::ofstream out(realDst);
const std::ostream_iterator<char> it(out);
// Do regex magic on the iterator
boost::regex exp;
exp.assign(regEx);
regex_replace(it, buffer.begin(), buffer.end(), exp, substitute, boost::match_default | boost::format_sed);
out.close();
}
catch (...)
{
std::cout << "Error occurred processing " << src << " to " << dst << "\n";
return false;
}
return true;
}
std::string CSkeletonGenerator::getDate()
{
time_t raw;
time(&raw);
struct tm* info = localtime(&raw);
std::string res(asctime(info));
res = res.substr(0, res.size() - 1); // the ascitime ends with a "\n"
return res;
}
bool CSkeletonGenerator::generate(const std::string& src, const std::string& dst, const std::map<std::string, std::string>& substitutions,
std::string& log) const
{
// we check if the template file is in place.
if (! g_file_test(src.c_str(), G_FILE_TEST_EXISTS))
{
log += "[FAILED] the template file '" + src + "' is missing.\n";
OV_ERROR_KRF("The template file '" << src << "' is missing.", Kernel::ErrorType::BadInput);
}
// we check the map
if (substitutions.empty())
{
log += "[WARNING] No substitution provided.\n";
OV_WARNING_K("No substitution provided.");
return false;
}
bool success = true;
log += "[ OK ] -- template file '" + src + "' found.\n";
getLogManager() << Kernel::LogLevel_Info << " -- template file '" << src << "' found.\n";
//we need to create the destination file by copying the template file, then do the first substitution
auto it = substitutions.cbegin();
success &= regexReplace(src, it->first, ensureSedCompliancy(it->second), dst);
++it;
//next substitutions are done on the - incomplete - destination file itself
while (it != substitutions.cend() && success)
{
getLogManager() << Kernel::LogLevel_Trace << "Executing substitution [" << it->first << "] ->[" << it->second << "]\n";
success &= regexReplace(dst, it->first, ensureSedCompliancy(it->second));
++it;
}
if (!success)
{
log += "[FAILED] -- " + dst + " cannot be written.\n";
OV_ERROR_KRF(" -- " << dst << " cannot be written.", Kernel::ErrorType::BadFileWrite);
}
log += "[ OK ] -- " + dst + " written.\n";
getLogManager() << Kernel::LogLevel_Info << " -- " << dst << " written.\n";
return true;
}
} // namespace SkeletonGenerator
} // namespace OpenViBE
@@ -0,0 +1,62 @@
#pragma once
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <openvibe/kernel/ovIKernelObject.h>
//#include <configuration/ovkCConfigurationManager.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <map>
namespace OpenViBE {
namespace SkeletonGenerator {
class CSkeletonGenerator
{
public:
CSkeletonGenerator(Kernel::IKernelContext& ctx, GtkBuilder* builder);
virtual ~CSkeletonGenerator() { }
protected:
Kernel::IKernelContext& m_kernelCtx;
GtkBuilder* m_builder = nullptr;
std::string m_author;
std::string m_company;
std::string m_directory;
std::string m_configFile; // basic application config file
bool m_configFileLoaded = false;
virtual bool initialize() = 0;
void getCommonParameters();
bool saveCommonParameters(const std::string& filename);
bool loadCommonParameters(const std::string& filename);
bool cleanConfigurationFile(const std::string& filename) const;
// returns a sed-compliant expression to be parsed in a substitution command
static std::string ensureSedCompliancy(const std::string& expression);
// executes a regex replace and builds a new file, by replacing the matching expressions by the substitute. If no destination file is provided, the template file is modified.
// Note that the input must be a valid sed format regex pattern, the function does not check.
bool regexReplace(const std::string& src, const std::string& regEx, const std::string& substitute, const std::string& dst = std::string("")) const;
// get the formatted string date
static std::string getDate();
// generate a new file, giving a template file, a destination file, and a map ofsubstitutions (Tag,Substitute)
// return false if an error occurred.
bool generate(const std::string& src, const std::string& dst, const std::map<std::string, std::string>& substitutions, std::string& log) const;
virtual void getCurrentParameters() = 0;
virtual bool save(const std::string& filename) = 0;
virtual bool load(const std::string& filename) = 0;
virtual Kernel::ILogManager& getLogManager() const { return m_kernelCtx.getLogManager(); }
virtual Kernel::IErrorManager& getErrorManager() const { return m_kernelCtx.getErrorManager(); }
};
} // namespace SkeletonGenerator
} // namespace OpenViBE
@@ -0,0 +1,96 @@
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <iostream>
#include <clocale> // std::setlocale
#include "ovsgCDriverSkeletonGenerator.h"
#include "ovsgCBoxAlgorithmSkeletonGenerator.h"
int main(int argc, char** argv)
{
OpenViBE::CKernelLoader loader;
std::cout << "[ INF ] Created kernel loader, trying to load kernel module" << std::endl;
OpenViBE::CString err;
#if defined TARGET_OS_Windows
const OpenViBE::CString file = OpenViBE::Directories::getLibDir() + "/openvibe-kernel.dll";
#else
const OpenViBE::CString file = OpenViBE::Directories::getLibDir() + "/libopenvibe-kernel.so";
#endif
if (!loader.load(file, &err)) { std::cout << "[ FAILED ] Error loading kernel (" << err << ")" << " from [" << file << "]\n"; }
else
{
std::cout << "[ INF ] Kernel module loaded, trying to get kernel descriptor" << std::endl;
OpenViBE::Kernel::IKernelDesc* desc = nullptr;
loader.initialize();
loader.getKernelDesc(desc);
if (!desc) { std::cout << "[ FAILED ] No kernel descriptor" << std::endl; }
else
{
std::cout << "[ INF ] Got kernel descriptor, trying to create kernel" << std::endl;
OpenViBE::Kernel::IKernelContext* ctx = desc->createKernel("skeleton-generator", OpenViBE::Directories::getDataDir() + "/kernel/openvibe.conf");
if (!ctx || !ctx->initialize()) { std::cout << "[ FAILED ] No kernel created by kernel descriptor" << std::endl; }
else
{
ctx->getConfigurationManager().addConfigurationFromFile(OpenViBE::Directories::getDataDir() + "/kernel/openvibe.conf");
ctx->getConfigurationManager().addConfigurationFromFile(
OpenViBE::Directories::getDataDir() + "/applications/skeleton-generator/skeleton-generator.conf");
OpenViBE::Toolkit::initialize(*ctx);
OpenViBE::Kernel::IConfigurationManager& configMgr = ctx->getConfigurationManager();
ctx->getPluginManager().addPluginsFromFiles(configMgr.expand("${Kernel_Plugins}"));
gtk_init(&argc, &argv);
// We rely on this with 64bit/gtk 2.24, to roll back gtk_init() sometimes switching
// the locale to one where ',' is needed instead of '.' for separators of floats,
// causing issues, for example getConfigurationManager.expandAsFloat("0.05") -> 0;
// due to implementation by std::stod().
std::setlocale(LC_ALL, "C");
GtkBuilder* builder = gtk_builder_new();
const OpenViBE::CString filename = OpenViBE::Directories::getDataDir() + "/applications/skeleton-generator/generator-interface.ui";
OV_ERROR_UNLESS(gtk_builder_add_from_file(builder, filename.toASCIIString(), nullptr), "Problem loading [" << filename << "]",
OpenViBE::Kernel::ErrorType::BadFileRead, -1, ctx->getErrorManager(), ctx->getLogManager());
//gtk_builder_connect_signals(builder, nullptr);
GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(builder, "sg-selection-dialog"));
gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);
gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
GtkWidget* radioDriver = GTK_WIDGET(gtk_builder_get_object(builder, "sg-driver-selection-radio-button"));
GtkWidget* radioAlgo = GTK_WIDGET(gtk_builder_get_object(builder, "sg-algo-selection-radio-button"));
GtkWidget* radioBox = GTK_WIDGET(gtk_builder_get_object(builder, "sg-box-selection-radio-button"));
OpenViBE::SkeletonGenerator::CBoxAlgorithmSkeletonGenerator boxGenerator(*ctx, builder);
OpenViBE::SkeletonGenerator::CDriverSkeletonGenerator driverGenerator(*ctx, builder);
const gint resp = gtk_dialog_run(GTK_DIALOG(dialog));
if (resp == GTK_RESPONSE_OK)
{
gtk_widget_hide(GTK_WIDGET(dialog));
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioDriver))) { driverGenerator.initialize(); }
OV_ERROR_UNLESS(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioAlgo)), "NOT YET AVAILABLE.",
OpenViBE::Kernel::ErrorType::Internal, 0, ctx->getErrorManager(), ctx->getLogManager());
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioBox))) { boxGenerator.initialize(); }
gtk_main();
}
else
{
std::cout << "User cancelled. Exit." << std::endl;
return 0;
}
}
}
}
loader.uninitialize();
loader.unload();
return 0;
}