Newer
Older
------------------------------------------------------------------
This file is part of the Open Ephys GUI
Copyright (C) 2016 Open Ephys
------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <iostream>
// ============================================================================
// ============================================================================
// ============================================================================
struct OpenEphysPluginAppWizard : public NewProjectWizard
{
OpenEphysPluginAppWizard()
{
modulesFolder = File::getCurrentWorkingDirectory()
.getParentDirectory().getParentDirectory().getParentDirectory()
.getChildFile ("JuceLibraryCode").getChildFile ("modules");
String getName() const override { return TRANS("Open-Ephys Plug-In"); }
String getDescription() const override { return TRANS("Creates an Open-Ephys neuro plug-in."); }
const char* getIcon() const override { return BinaryData::wizard_AudioPlugin_svg; }
StringArray getDefaultModules() override
{
//StringArray s (NewProjectWizard::getDefaultModules());
//s.add ("juce_audio_plugin_client");
// TODO <Kirill A>
// Just an empty modules for now
StringArray s;
return s;
}
Result getResultsFromConfigPage (const PluginTemplatesPageComponent* configPage)
{
m_pluginType = configPage->getSelectedPluginType();
m_processorType = configPage->getSelectedProcessorType();
m_shouldUseVisualizerEditor = configPage->shouldUseVisualizerEditor();
m_guiTemplateName = configPage->getSelectedTemplateName();
m_guiVisualizerTemplateName = configPage->getSelectedVisualizerTemplateName();
DBG (String ("GUI Template name: ") + m_guiTemplateName);
DBG (String ("GUI Visualizer template name: ") + m_guiVisualizerTemplateName);
m_contentLookAndFeelClassName = configPage->getSelectedLookAndFeelClassName();
m_shouldChangeContentLookAndFeel = (m_contentLookAndFeelClassName != "DEFAULT");
if (m_shouldChangeContentLookAndFeel)
DBG (String ("Content LookAndFeel name: ") + m_contentLookAndFeelClassName);
return Result::ok();
}
bool initialiseProject (Project& project) override
{
createSourceFolder();
if (auto templatesPage = dynamic_cast<PluginTemplatesPageComponent*>
(ownerWizardComp->findParentComponentOfClass<StartPageComponent>()
->getPluginTemplatesPage()))
{
getResultsFromConfigPage (templatesPage);
}
String pluginProcessorName = CodeHelpers::makeValidIdentifier (appTitle, true, true, false) + "Processor";
pluginProcessorName = pluginProcessorName.substring (0, 1).toUpperCase() + pluginProcessorName.substring (1);
const String pluginEditorName = pluginProcessorName + "Editor";
const String processorType = getProcessorTypeString (m_processorType);
const String pluginFriendlyName = appTitle;
DBG (String ("Processor type: ") + processorType);
const String pluginContentComponentName = pluginProcessorName + "ContentComponent";
project.getProjectTypeValue() = ProjectType_OpenEphysPlugin::getTypeName();
project.setPluginType (m_pluginType);
project.setPluginProcessorType (m_processorType);
Project::Item sourceGroup (createSourceGroup (project));
project.getConfigFlag ("JUCE_QUICKTIME") = Project::configFlagDisabled; // disabled because it interferes with RTAS build on PC
project.shouldBuildVST().setValue (false);
project.shouldBuildVST3().setValue (false);
setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));
//String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), filterCppFile));
generatePluginMakeFile (project, sourceGroup);
generatePluginLibFile (project, sourceGroup, pluginProcessorName, pluginFriendlyName);
generatePluginProcessorFiles (project, sourceGroup, pluginProcessorName, pluginEditorName, pluginFriendlyName);
// No need to generate content component files for any plugins except Processors.
if (m_pluginType != Plugin::PLUGIN_TYPE_PROCESSOR)
generatePluginEditorFiles (project, sourceGroup, pluginProcessorName, pluginEditorName, pluginFriendlyName, pluginContentComponentName);
generatePluginEditorContentComponentFiles (project, sourceGroup, pluginProcessorName, pluginEditorName, pluginContentComponentName);
if (m_shouldUseVisualizerEditor)
{
const String visualizerCanvasName = pluginProcessorName + "Visualizer";
const String visualizerCanvasContentComponentName = visualizerCanvasName + "ContentComponent";
generatePluginVisualizerEditorCanvasFiles (project, sourceGroup,
pluginProcessorName, visualizerCanvasName,
visualizerCanvasName, visualizerCanvasContentComponentName);
generatePluginEditorContentComponentFiles (project, sourceGroup,
pluginProcessorName, visualizerCanvasName,
visualizerCanvasContentComponentName,
true);
}
return true;
}
bool generatePluginLibFile (const Project& project,
Project::Item& sourceGroup,
const String& pluginProcessorName,
const String& pluginFriendlyName)
{
String libPluginType = getLibPluginTypeString (m_pluginType);
String libCreateFunctionName = getLibPluginCreateFunctionString (m_pluginType);
String libPluginInfoType = getLibPluginInfoType (m_pluginType);
const auto newPluginLibFile = getSourceFilesFolder().getChildFile ("OpenEphysLib.cpp");
String libPluginProcessorType = m_pluginType == PLUGIN_TYPE_PROCESSOR
? ("info->processor.type = " + getLibProcessorTypeString (m_processorType) + ";")
: "";
String pluginLibCppFileContent = project.getFileTemplate ("openEphys_OpenEphysLibTemplate_cpp")
.replace ("PROCESSORCLASSNAME", pluginProcessorName, false)
.replace ("PLUGINLIBRARYNAME", pluginFriendlyName + " plugin library", false) // TODO <Kirill A>: set library name variable
.replace ("PLUGINLIBRARYVERSION", "1", false) // TODO <Kirill A>: set library version variable
.replace ("PLUGINGUINAME", pluginFriendlyName, false) // TODO <Kirill A>: set library gui name variable
.replace ("LIBPLUGINTYPE", libPluginType, false)
.replace ("LIBPLUGININFOTYPE", libPluginInfoType, false)
.replace ("LIBPLUGINCREATEFUNCTION", libCreateFunctionName, false)
.replace ("LIBPLUGINPROCESSORTYPE", libPluginProcessorType, false);
bool wasGeneratedSuccessfully = true;
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (newPluginLibFile, pluginLibCppFileContent))
{
failedFiles.add (newPluginLibFile.getFullPathName());
wasGeneratedSuccessfully = false;
}
sourceGroup.addFileAtIndex (newPluginLibFile, -1, true);
return wasGeneratedSuccessfully;
}
bool generatePluginMakeFile (const Project& project, Project::Item& sourceGroup)
String templatePluginMakeFileContent = project.getFileTemplate ("openEphys_PluginMakefile_example");
const auto sourceFolder = getSourceFilesFolder();
auto newPluginMakeFile = sourceFolder.getChildFile ("Makefile");
bool wasGeneratedSuccessfully = true;
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (newPluginMakeFile, templatePluginMakeFileContent))
{
failedFiles.add (newPluginMakeFile.getFullPathName());
wasGeneratedSuccessfully = false;
}
return wasGeneratedSuccessfully;
}
bool generatePluginProcessorFiles (const Project& project,
Project::Item& sourceGroup,
const String& processorName,
const String& editorName,
const String& pluginFriendlyName)
{
const auto sourceFolder = getSourceFilesFolder();
auto newProcessorCppFile = sourceFolder.getChildFile (processorName + ".cpp");
auto newProcessorHFile = sourceFolder.getChildFile (processorName + ".h");
auto newEditorHFile = sourceFolder.getChildFile (editorName + ".h");
String processorFileTemplateName = getTemplateProcessorFileName (m_pluginType);
String processorType = getProcessorTypeString (m_processorType);
String processorHeaders = CodeHelpers::createIncludeStatement (newProcessorHFile, newProcessorCppFile) + newLine;
if (m_pluginType == PLUGIN_TYPE_PROCESSOR)
processorHeaders += CodeHelpers::createIncludeStatement (newEditorHFile, newProcessorCppFile);
String processorCppFileContent = project.getFileTemplate (processorFileTemplateName + "_cpp")
.replace ("PROCESSORHEADERS", processorHeaders, false)
.replace ("PROCESSORCLASSNAME", processorName, false)
.replace ("PLUGINGUINAME", pluginFriendlyName, false)
.replace ("EDITORCLASSNAME", editorName, false)
.replace ("PROCESSORTYPE", processorType, false);
String processorHFileConent = project.getFileTemplate (processorFileTemplateName + "_h")
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
//.replace ("APPHEADERS", appHeaders, false)
.replace ("PROCESSORCLASSNAME", processorName, false)
.replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (newProcessorHFile), false);
bool wasGeneratedSuccessfully = true;
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (newProcessorCppFile, processorCppFileContent))
{
failedFiles.add (newProcessorCppFile.getFullPathName());
wasGeneratedSuccessfully = false;
}
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (newProcessorHFile, processorHFileConent))
{
failedFiles.add (newProcessorHFile.getFullPathName());
wasGeneratedSuccessfully = false;
}
sourceGroup.addFileAtIndex (newProcessorCppFile, -1, true);
sourceGroup.addFileAtIndex (newProcessorHFile, -1, false);
return wasGeneratedSuccessfully;
}
bool generatePluginEditorFiles (const Project& project,
Project::Item& sourceGroup,
const String& processorName,
const String& editorName,
const String& pluginFriendlyName,
const String& contentComponentName)
const auto sourceFolder = getSourceFilesFolder();
auto newEditorCppFile = sourceFolder.getChildFile (editorName + ".cpp");
auto newEditorHFile = sourceFolder.getChildFile (editorName + ".h");
String templateFileNameWithoutExtension = m_shouldUseVisualizerEditor
? "openEphys_ProcessorVisualizerEditorPluginTemplate"
: "openEphys_ProcessorEditorPluginTemplate";
String editorCppFileContent = project.getFileTemplate (templateFileNameWithoutExtension + "_cpp")
//.replace ("EDITORCPPHEADERS", CodeHelpers::createIncludeStatement (filterHFile, filterCppFile)
// + newLine + CodeHelpers::createIncludeStatement (editorHFile, filterCppFile), false)
.replace ("PROCESSORCLASSNAME", processorName, false)
.replace ("EDITORCLASSNAME", editorName, false)
.replace ("PLUGINGUINAME", pluginFriendlyName, false);
String editorHFileContent = project.getFileTemplate (templateFileNameWithoutExtension + "_h")
//.replace ("EDITORHEADERS", appHeaders + newLine + CodeHelpers::createIncludeStatement (filterHFile, filterCppFile), false)
.replace ("PROCESSORCLASSNAME", processorName, false)
.replace ("EDITORCLASSNAME", editorName, false)
.replace ("CONTENTCOMPONENTCLASSNAME", contentComponentName, false)
.replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (newEditorHFile), false);
if (m_shouldUseVisualizerEditor)
{
const String visualizerCanvasClassName = processorName + "Visualizer";
editorCppFileContent = editorCppFileContent
.replace ("EDITORCANVASCLASSNAME", visualizerCanvasClassName, false)
.replace ("GenericEditor", "VisualizerEditor", false);
}
if (m_shouldChangeContentLookAndFeel)
{
const auto lookAndFeelDeclarationCode = "ScopedPointer<LookAndFeel> m_contentLookAndFeel;";
const auto lookAndFeelSetterCode = "content.setLookAndFeel (m_contentLookAndFeel);";
const auto lookAndFeelCreationCode = "m_contentLookAndFeel = new LOOKANDFEELCLASSNAME();";
editorCppFileContent = editorCppFileContent
// Uncomment some pieces of code
.replace (String ("//") + lookAndFeelCreationCode, lookAndFeelCreationCode, false)
.replace (String ("//") + lookAndFeelSetterCode, lookAndFeelSetterCode, false)
// Change LookAndFeel class name
.replace ("LOOKANDFEELCLASSNAME", m_contentLookAndFeelClassName, false);
editorHFileContent = editorHFileContent
// Uncomment some pieces of code
.replace (String ("//") + lookAndFeelDeclarationCode, lookAndFeelDeclarationCode, false);
}
bool wasGeneratedSuccessfully = true;
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (newEditorCppFile, editorCppFileContent))
{
failedFiles.add (newEditorCppFile.getFullPathName());
wasGeneratedSuccessfully = false;
}
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (newEditorHFile, editorHFileContent))
{
failedFiles.add (newEditorHFile.getFullPathName());
wasGeneratedSuccessfully = false;
}
sourceGroup.addFileAtIndex (newEditorCppFile, -1, true);
sourceGroup.addFileAtIndex (newEditorHFile, -1, false);
return wasGeneratedSuccessfully;
bool generatePluginEditorContentComponentFiles (const Project& project,
Project::Item& sourceGroup,
const String& processorName,
const String& editorName,
const String& contentComponentName,
bool useVisualizerEditorTemplates = false)
{
const auto sourceFolder = getSourceFilesFolder();
auto newContentComponentCppFile = sourceFolder.getChildFile (contentComponentName + ".cpp");
auto newContentComponentHFile = sourceFolder.getChildFile (contentComponentName + ".h");
const String guiTemplateName = useVisualizerEditorTemplates
? m_guiVisualizerTemplateName
: m_guiTemplateName;
String contentComponentCppFileContent;
String contentComponentHFileContent;
if (guiTemplateName == "DEFAULT" || (! isExistsGuiTemplate (guiTemplateName)))
{
contentComponentCppFileContent = project.getFileTemplate ("openEphys_ProcessorContentComponentTemplate_cpp")
.replace ("CONTENTCOMPONENTCLASSNAME", contentComponentName, false);
contentComponentHFileContent = project.getFileTemplate ("openEphys_ProcessorContentComponentTemplate_h")
.replace ("CONTENTCOMPONENTCLASSNAME", contentComponentName, false)
.replace ("EDITORCLASSNAME", editorName, false)
.replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (newContentComponentHFile), false);
}
else
{
const auto guiTemplateClassName = getGUITemplateClassName (guiTemplateName);
contentComponentCppFileContent = getGUITemplate (guiTemplateName, false)
.replace (guiTemplateClassName, contentComponentName);
const auto userVariablesMacro = String ("//[UserVariables] -- You can add your own custom variables in this section.") + newLine;
const auto friendClassDefinition = CodeHelpers::indent (String ("friend class ") + editorName, 4, true) + ";" + newLine;
contentComponentHFileContent = getGUITemplate (guiTemplateName, true)
.replace (guiTemplateClassName, contentComponentName)
.replace (userVariablesMacro, userVariablesMacro + friendClassDefinition , false);
}
bool wasGeneratedSuccessfully = true;
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (newContentComponentCppFile, contentComponentCppFileContent))
{
failedFiles.add (newContentComponentCppFile.getFullPathName());
wasGeneratedSuccessfully = false;
}
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (newContentComponentHFile, contentComponentHFileContent))
{
failedFiles.add (newContentComponentHFile.getFullPathName());
wasGeneratedSuccessfully = false;
}
sourceGroup.addFileAtIndex (newContentComponentCppFile, -1, true);
sourceGroup.addFileAtIndex (newContentComponentHFile, -1, false);
return wasGeneratedSuccessfully;
}
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
bool generatePluginVisualizerEditorCanvasFiles (const Project& project,
Project::Item& sourceGroup,
const String& processorName,
const String& editorName,
const String& canvasName,
const String& contentComponentName)
{
const auto sourceFolder = getSourceFilesFolder();
auto newCanvasComponentCppFile = sourceFolder.getChildFile (canvasName + ".cpp");
auto newCanvasComponentHFile = sourceFolder.getChildFile (canvasName + ".h");
String canvasComponentCppFileContent;
String canvasComponentHFileContent;
canvasComponentCppFileContent = project.getFileTemplate ("openEphys_ProcessorVisualizerCanvasTemplate_cpp")
.replace ("PROCESSORCLASSNAME", processorName, false)
.replace ("EDITORCANVASCLASSNAME", editorName, false);
canvasComponentHFileContent = project.getFileTemplate ("openEphys_ProcessorVisualizerCanvasTemplate_h")
.replace ("PROCESSORCLASSNAME", processorName,false)
.replace ("EDITORCANVASCLASSNAME", editorName, false)
.replace ("CONTENTCOMPONENTCLASSNAME", contentComponentName, false)
.replace ("HEADERGUARD", CodeHelpers::makeHeaderGuardName (newCanvasComponentHFile), false);
bool wasGeneratedSuccessfully = true;
if (m_shouldChangeContentLookAndFeel)
{
const auto lookAndFeelDeclarationCode = "ScopedPointer<LookAndFeel> m_contentLookAndFeel;";
const auto lookAndFeelSetterCode = "content.setLookAndFeel (m_contentLookAndFeel);";
const auto lookAndFeelCreationCode = "m_contentLookAndFeel = new LOOKANDFEELCLASSNAME();";
canvasComponentCppFileContent = canvasComponentCppFileContent
// Uncomment some pieces of code
.replace (String ("//") + lookAndFeelCreationCode, lookAndFeelCreationCode, false)
.replace (String ("//") + lookAndFeelSetterCode, lookAndFeelSetterCode, false)
// Change LookAndFeel class name
.replace ("LOOKANDFEELCLASSNAME", m_contentLookAndFeelClassName, false);
canvasComponentHFileContent = canvasComponentHFileContent
// Uncomment some pieces of code
.replace (String ("//") + lookAndFeelDeclarationCode, lookAndFeelDeclarationCode, false);
}
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (newCanvasComponentCppFile, canvasComponentCppFileContent))
{
failedFiles.add (newCanvasComponentCppFile.getFullPathName());
wasGeneratedSuccessfully = false;
}
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (newCanvasComponentHFile, canvasComponentHFileContent))
{
failedFiles.add (newCanvasComponentHFile.getFullPathName());
wasGeneratedSuccessfully = false;
}
sourceGroup.addFileAtIndex (newCanvasComponentCppFile, -1, true);
sourceGroup.addFileAtIndex (newCanvasComponentHFile, -1, false);
return wasGeneratedSuccessfully;
}
const char* COMBOBOX_ID_PLUGIN_TYPE = "pluginTypeComboBox";// { "pluginTypeComboBox" };
const char* COMBOBOX_ID_PROCESSOR_TYPE = "processorTypeComboBox";// { "processorTypeComboBox" };
private:
PluginType m_pluginType { NOT_A_PLUGIN_TYPE } ;
PluginProcessorType m_processorType { PROCESSOR_TYPE_INVALID };
/** The name of the GUI template which is used to create content component for plugin. */
String m_guiTemplateName;
/** The name of the GUI template for VisualizerEditor's Canvas (if used) to create content component for plugin. */
String m_guiVisualizerTemplateName;
/** The class name of the LookAndFeel for contents. If it's equal to "DEFAULT" - this means that user didn't
selected the new lookAndFeel for component and we have no need to change it..*/
String m_contentLookAndFeelClassName;
bool m_shouldUseVisualizerEditor;
bool m_shouldChangeContentLookAndFeel;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenEphysPluginAppWizard)
};