1522 lines
53 KiB
C++
1522 lines
53 KiB
C++
|
/*
|
||
|
==============================================================================
|
||
|
|
||
|
This file is part of the JUCE library.
|
||
|
Copyright (c) 2020 - Raw Material Software Limited
|
||
|
|
||
|
JUCE is an open source library subject to commercial or open-source
|
||
|
licensing.
|
||
|
|
||
|
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||
|
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||
|
|
||
|
End User License Agreement: www.juce.com/juce-6-licence
|
||
|
Privacy Policy: www.juce.com/juce-privacy-policy
|
||
|
|
||
|
Or: You may also use this code under the terms of the GPL v3 (see
|
||
|
www.gnu.org/licenses).
|
||
|
|
||
|
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||
|
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||
|
DISCLAIMED.
|
||
|
|
||
|
==============================================================================
|
||
|
*/
|
||
|
|
||
|
PopupMenu createGUIEditorMenu();
|
||
|
void handleGUIEditorMenuCommand (int);
|
||
|
void registerGUIEditorCommands();
|
||
|
|
||
|
|
||
|
//==============================================================================
|
||
|
struct ProjucerApplication::MainMenuModel : public MenuBarModel
|
||
|
{
|
||
|
MainMenuModel()
|
||
|
{
|
||
|
setApplicationCommandManagerToWatch (&getCommandManager());
|
||
|
}
|
||
|
|
||
|
StringArray getMenuBarNames() override
|
||
|
{
|
||
|
return getApp().getMenuNames();
|
||
|
}
|
||
|
|
||
|
PopupMenu getMenuForIndex (int /*topLevelMenuIndex*/, const String& menuName) override
|
||
|
{
|
||
|
return getApp().createMenu (menuName);
|
||
|
}
|
||
|
|
||
|
void menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/) override
|
||
|
{
|
||
|
getApp().handleMainMenuCommand (menuItemID);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//==============================================================================
|
||
|
void ProjucerApplication::initialise (const String& commandLine)
|
||
|
{
|
||
|
initialiseLogger ("IDE_Log_");
|
||
|
Logger::writeToLog (SystemStats::getOperatingSystemName());
|
||
|
Logger::writeToLog ("CPU: " + String (SystemStats::getCpuSpeedInMegahertz())
|
||
|
+ "MHz Cores: " + String (SystemStats::getNumCpus())
|
||
|
+ " " + String (SystemStats::getMemorySizeInMegabytes()) + "MB");
|
||
|
|
||
|
isRunningCommandLine = commandLine.isNotEmpty()
|
||
|
&& ! commandLine.startsWith ("-NSDocumentRevisionsDebugMode");
|
||
|
|
||
|
settings = std::make_unique<StoredSettings>();
|
||
|
|
||
|
if (isRunningCommandLine)
|
||
|
{
|
||
|
auto appReturnCode = performCommandLine (ArgumentList ("Projucer", commandLine));
|
||
|
|
||
|
if (appReturnCode != commandLineNotPerformed)
|
||
|
{
|
||
|
setApplicationReturnValue (appReturnCode);
|
||
|
quit();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
isRunningCommandLine = false;
|
||
|
}
|
||
|
|
||
|
if (sendCommandLineToPreexistingInstance())
|
||
|
{
|
||
|
DBG ("Another instance is running - quitting...");
|
||
|
quit();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
doBasicApplicationSetup();
|
||
|
|
||
|
// do further initialisation in a moment when the message loop has started
|
||
|
triggerAsyncUpdate();
|
||
|
}
|
||
|
|
||
|
bool ProjucerApplication::initialiseLogger (const char* filePrefix)
|
||
|
{
|
||
|
if (logger == nullptr)
|
||
|
{
|
||
|
#if JUCE_LINUX || JUCE_BSD
|
||
|
String folder = "~/.config/Projucer/Logs";
|
||
|
#else
|
||
|
String folder = "com.juce.projucer";
|
||
|
#endif
|
||
|
|
||
|
logger.reset (FileLogger::createDateStampedLogger (folder, filePrefix, ".txt",
|
||
|
getApplicationName() + " " + getApplicationVersion()
|
||
|
+ " --- Build date: " __DATE__));
|
||
|
Logger::setCurrentLogger (logger.get());
|
||
|
}
|
||
|
|
||
|
return logger != nullptr;
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::initialiseWindows (const String& commandLine)
|
||
|
{
|
||
|
const String commandLineWithoutNSDebug (commandLine.replace ("-NSDocumentRevisionsDebugMode YES", StringRef()));
|
||
|
|
||
|
if (commandLineWithoutNSDebug.trim().isNotEmpty() && ! commandLineWithoutNSDebug.trim().startsWithChar ('-'))
|
||
|
anotherInstanceStarted (commandLine);
|
||
|
else if (mainWindowList.windows.size() == 0)
|
||
|
mainWindowList.reopenLastProjects();
|
||
|
|
||
|
mainWindowList.createWindowIfNoneAreOpen();
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::handleAsyncUpdate()
|
||
|
{
|
||
|
rescanJUCEPathModules();
|
||
|
rescanUserPathModules();
|
||
|
|
||
|
menuModel.reset (new MainMenuModel());
|
||
|
|
||
|
#if JUCE_MAC
|
||
|
rebuildAppleMenu();
|
||
|
appleMenuRebuildListener = std::make_unique<AppleMenuRebuildListener>();
|
||
|
#endif
|
||
|
|
||
|
settings->appearance.refreshPresetSchemeList();
|
||
|
setColourScheme (getGlobalProperties().getIntValue ("COLOUR SCHEME"), false);
|
||
|
setEditorColourScheme (getGlobalProperties().getIntValue ("EDITOR COLOUR SCHEME"), false);
|
||
|
updateEditorColourSchemeIfNeeded();
|
||
|
|
||
|
ImageCache::setCacheTimeout (30 * 1000);
|
||
|
tooltipWindow = std::make_unique<TooltipWindow> (nullptr, 1200);
|
||
|
|
||
|
if (isAutomaticVersionCheckingEnabled())
|
||
|
LatestVersionCheckerAndUpdater::getInstance()->checkForNewVersion (true);
|
||
|
|
||
|
initialiseWindows (getCommandLineParameters());
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::doBasicApplicationSetup()
|
||
|
{
|
||
|
licenseController = std::make_unique<LicenseController>();
|
||
|
LookAndFeel::setDefaultLookAndFeel (&lookAndFeel);
|
||
|
initCommandManager();
|
||
|
icons = std::make_unique<Icons>();
|
||
|
}
|
||
|
|
||
|
static void deleteTemporaryFiles()
|
||
|
{
|
||
|
auto tempDirectory = File::getSpecialLocation (File::SpecialLocationType::tempDirectory).getChildFile ("PIPs");
|
||
|
|
||
|
if (tempDirectory.exists())
|
||
|
tempDirectory.deleteRecursively();
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::shutdown()
|
||
|
{
|
||
|
utf8Window.reset();
|
||
|
svgPathWindow.reset();
|
||
|
aboutWindow.reset();
|
||
|
pathsWindow.reset();
|
||
|
editorColourSchemeWindow.reset();
|
||
|
pipCreatorWindow.reset();
|
||
|
|
||
|
mainWindowList.forceCloseAllWindows();
|
||
|
openDocumentManager.clear();
|
||
|
|
||
|
#if JUCE_MAC
|
||
|
MenuBarModel::setMacMainMenu (nullptr);
|
||
|
#endif
|
||
|
|
||
|
menuModel.reset();
|
||
|
commandManager.reset();
|
||
|
settings.reset();
|
||
|
|
||
|
if (! isRunningCommandLine)
|
||
|
LookAndFeel::setDefaultLookAndFeel (nullptr);
|
||
|
|
||
|
// clean up after ourselves and delete any temp project files that may have
|
||
|
// been created from PIPs
|
||
|
deleteTemporaryFiles();
|
||
|
|
||
|
if (! isRunningCommandLine)
|
||
|
Logger::writeToLog ("Shutdown");
|
||
|
|
||
|
deleteLogger();
|
||
|
}
|
||
|
|
||
|
struct AsyncQuitRetrier : private Timer
|
||
|
{
|
||
|
AsyncQuitRetrier() { startTimer (500); }
|
||
|
|
||
|
void timerCallback() override
|
||
|
{
|
||
|
stopTimer();
|
||
|
delete this;
|
||
|
|
||
|
if (auto* app = JUCEApplicationBase::getInstance())
|
||
|
app->systemRequestedQuit();
|
||
|
}
|
||
|
|
||
|
JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier)
|
||
|
};
|
||
|
|
||
|
void ProjucerApplication::systemRequestedQuit()
|
||
|
{
|
||
|
if (ModalComponentManager::getInstance()->cancelAllModalComponents())
|
||
|
{
|
||
|
new AsyncQuitRetrier();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
closeAllMainWindows ([] (bool closedSuccessfully)
|
||
|
{
|
||
|
if (closedSuccessfully)
|
||
|
ProjucerApplication::quit();
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//==============================================================================
|
||
|
String ProjucerApplication::getVersionDescription() const
|
||
|
{
|
||
|
String s;
|
||
|
|
||
|
const Time buildDate (Time::getCompilationDate());
|
||
|
|
||
|
s << "Projucer " << ProjectInfo::versionString
|
||
|
<< newLine
|
||
|
<< "Build date: " << buildDate.getDayOfMonth()
|
||
|
<< " " << Time::getMonthName (buildDate.getMonth(), true)
|
||
|
<< " " << buildDate.getYear();
|
||
|
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::anotherInstanceStarted (const String& commandLine)
|
||
|
{
|
||
|
if (! commandLine.trim().startsWithChar ('-'))
|
||
|
{
|
||
|
ArgumentList list ({}, commandLine);
|
||
|
|
||
|
for (auto& arg : list.arguments)
|
||
|
openFile (arg.resolveAsFile(), nullptr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ProjucerApplication& ProjucerApplication::getApp()
|
||
|
{
|
||
|
ProjucerApplication* const app = dynamic_cast<ProjucerApplication*> (JUCEApplication::getInstance());
|
||
|
jassert (app != nullptr);
|
||
|
return *app;
|
||
|
}
|
||
|
|
||
|
ApplicationCommandManager& ProjucerApplication::getCommandManager()
|
||
|
{
|
||
|
auto* cm = ProjucerApplication::getApp().commandManager.get();
|
||
|
jassert (cm != nullptr);
|
||
|
return *cm;
|
||
|
}
|
||
|
|
||
|
|
||
|
//==============================================================================
|
||
|
enum
|
||
|
{
|
||
|
recentProjectsBaseID = 100,
|
||
|
openWindowsBaseID = 300,
|
||
|
activeDocumentsBaseID = 400,
|
||
|
showPathsID = 1999,
|
||
|
examplesBaseID = 2000
|
||
|
};
|
||
|
|
||
|
MenuBarModel* ProjucerApplication::getMenuModel()
|
||
|
{
|
||
|
return menuModel.get();
|
||
|
}
|
||
|
|
||
|
StringArray ProjucerApplication::getMenuNames()
|
||
|
{
|
||
|
StringArray currentMenuNames { "File", "Edit", "View", "Window", "Document", "GUI Editor", "Tools", "Help" };
|
||
|
|
||
|
if (! isGUIEditorEnabled()) currentMenuNames.removeString ("GUI Editor");
|
||
|
|
||
|
return currentMenuNames;
|
||
|
}
|
||
|
|
||
|
PopupMenu ProjucerApplication::createMenu (const String& menuName)
|
||
|
{
|
||
|
if (menuName == "File")
|
||
|
return createFileMenu();
|
||
|
|
||
|
if (menuName == "Edit")
|
||
|
return createEditMenu();
|
||
|
|
||
|
if (menuName == "View")
|
||
|
return createViewMenu();
|
||
|
|
||
|
if (menuName == "Window")
|
||
|
return createWindowMenu();
|
||
|
|
||
|
if (menuName == "Document")
|
||
|
return createDocumentMenu();
|
||
|
|
||
|
if (menuName == "Tools")
|
||
|
return createToolsMenu();
|
||
|
|
||
|
if (menuName == "Help")
|
||
|
return createHelpMenu();
|
||
|
|
||
|
if (menuName == "GUI Editor")
|
||
|
if (isGUIEditorEnabled())
|
||
|
return createGUIEditorMenu();
|
||
|
|
||
|
jassertfalse; // names have changed?
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
PopupMenu ProjucerApplication::createFileMenu()
|
||
|
{
|
||
|
PopupMenu menu;
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::newProject);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::newProjectFromClipboard);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::newPIP);
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::open);
|
||
|
|
||
|
{
|
||
|
PopupMenu recentFiles;
|
||
|
|
||
|
settings->recentFiles.createPopupMenuItems (recentFiles, recentProjectsBaseID, true, true);
|
||
|
|
||
|
if (recentFiles.getNumItems() > 0)
|
||
|
{
|
||
|
recentFiles.addSeparator();
|
||
|
recentFiles.addCommandItem (commandManager.get(), CommandIDs::clearRecentFiles);
|
||
|
}
|
||
|
|
||
|
menu.addSubMenu ("Open Recent", recentFiles);
|
||
|
}
|
||
|
|
||
|
menu.addSubMenu ("Open Example", createExamplesPopupMenu());
|
||
|
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::closeDocument);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::saveDocument);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::saveDocumentAs);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::saveAll);
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::closeProject);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::saveProject);
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::openInIDE);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::saveAndOpenInIDE);
|
||
|
menu.addSeparator();
|
||
|
|
||
|
#if ! JUCER_ENABLE_GPL_MODE
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::loginLogout);
|
||
|
#endif
|
||
|
|
||
|
#if ! JUCE_MAC
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showAboutWindow);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::checkForNewVersion);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::enableNewVersionCheck);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showGlobalPathsWindow);
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::quit);
|
||
|
#endif
|
||
|
|
||
|
return menu;
|
||
|
}
|
||
|
|
||
|
PopupMenu ProjucerApplication::createEditMenu()
|
||
|
{
|
||
|
PopupMenu menu;
|
||
|
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::undo);
|
||
|
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::redo);
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::cut);
|
||
|
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::copy);
|
||
|
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::paste);
|
||
|
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::del);
|
||
|
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::selectAll);
|
||
|
menu.addCommandItem (commandManager.get(), StandardApplicationCommandIDs::deselectAll);
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showFindPanel);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::findSelection);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::findNext);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::findPrevious);
|
||
|
return menu;
|
||
|
}
|
||
|
|
||
|
PopupMenu ProjucerApplication::createViewMenu()
|
||
|
{
|
||
|
PopupMenu menu;
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showProjectSettings);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showFileExplorerPanel);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showModulesPanel);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showExportersPanel);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showExporterSettings);
|
||
|
|
||
|
menu.addSeparator();
|
||
|
createColourSchemeItems (menu);
|
||
|
|
||
|
return menu;
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::createColourSchemeItems (PopupMenu& menu)
|
||
|
{
|
||
|
{
|
||
|
PopupMenu colourSchemeMenu;
|
||
|
|
||
|
colourSchemeMenu.addItem (PopupMenu::Item ("Dark")
|
||
|
.setTicked (selectedColourSchemeIndex == 0)
|
||
|
.setAction ([this] { setColourScheme (0, true); updateEditorColourSchemeIfNeeded(); }));
|
||
|
|
||
|
colourSchemeMenu.addItem (PopupMenu::Item ("Grey")
|
||
|
.setTicked (selectedColourSchemeIndex == 1)
|
||
|
.setAction ([this] { setColourScheme (1, true); updateEditorColourSchemeIfNeeded(); }));
|
||
|
|
||
|
colourSchemeMenu.addItem (PopupMenu::Item ("Light")
|
||
|
.setTicked (selectedColourSchemeIndex == 2)
|
||
|
.setAction ([this] { setColourScheme (2, true); updateEditorColourSchemeIfNeeded(); }));
|
||
|
|
||
|
menu.addSubMenu ("Colour Scheme", colourSchemeMenu);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
PopupMenu editorColourSchemeMenu;
|
||
|
|
||
|
auto& appearanceSettings = getAppSettings().appearance;
|
||
|
|
||
|
appearanceSettings.refreshPresetSchemeList();
|
||
|
auto schemes = appearanceSettings.getPresetSchemes();
|
||
|
|
||
|
auto i = 0;
|
||
|
|
||
|
for (auto& s : schemes)
|
||
|
{
|
||
|
editorColourSchemeMenu.addItem (PopupMenu::Item (s)
|
||
|
.setEnabled (editorColourSchemeWindow == nullptr)
|
||
|
.setTicked (selectedEditorColourSchemeIndex == i)
|
||
|
.setAction ([this, i] { setEditorColourScheme (i, true); }));
|
||
|
++i;
|
||
|
}
|
||
|
|
||
|
editorColourSchemeMenu.addSeparator();
|
||
|
editorColourSchemeMenu.addItem (PopupMenu::Item ("Create...")
|
||
|
.setEnabled (editorColourSchemeWindow == nullptr)
|
||
|
.setAction ([this] { showEditorColourSchemeWindow(); }));
|
||
|
|
||
|
menu.addSubMenu ("Editor Colour Scheme", editorColourSchemeMenu);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PopupMenu ProjucerApplication::createWindowMenu()
|
||
|
{
|
||
|
PopupMenu menu;
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::goToPreviousWindow);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::goToNextWindow);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::closeWindow);
|
||
|
menu.addSeparator();
|
||
|
|
||
|
int counter = 0;
|
||
|
|
||
|
for (auto* window : mainWindowList.windows)
|
||
|
{
|
||
|
if (window != nullptr)
|
||
|
{
|
||
|
if (auto* project = window->getProject())
|
||
|
menu.addItem (openWindowsBaseID + counter++, project->getProjectNameString());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::closeAllWindows);
|
||
|
return menu;
|
||
|
}
|
||
|
|
||
|
PopupMenu ProjucerApplication::createDocumentMenu()
|
||
|
{
|
||
|
PopupMenu menu;
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::goToPreviousDoc);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::goToNextDoc);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::goToCounterpart);
|
||
|
menu.addSeparator();
|
||
|
|
||
|
auto numDocs = jmin (50, openDocumentManager.getNumOpenDocuments());
|
||
|
|
||
|
for (int i = 0; i < numDocs; ++i)
|
||
|
{
|
||
|
OpenDocumentManager::Document* doc = openDocumentManager.getOpenDocument(i);
|
||
|
menu.addItem (activeDocumentsBaseID + i, doc->getName());
|
||
|
}
|
||
|
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::closeAllDocuments);
|
||
|
return menu;
|
||
|
}
|
||
|
|
||
|
PopupMenu ProjucerApplication::createToolsMenu()
|
||
|
{
|
||
|
PopupMenu menu;
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showUTF8Tool);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showSVGPathTool);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showTranslationTool);
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::enableGUIEditor);
|
||
|
return menu;
|
||
|
}
|
||
|
|
||
|
PopupMenu ProjucerApplication::createHelpMenu()
|
||
|
{
|
||
|
PopupMenu menu;
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showForum);
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showAPIModules);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showAPIClasses);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showTutorials);
|
||
|
return menu;
|
||
|
}
|
||
|
|
||
|
PopupMenu ProjucerApplication::createExtraAppleMenuItems()
|
||
|
{
|
||
|
PopupMenu menu;
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showAboutWindow);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::checkForNewVersion);
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::enableNewVersionCheck);
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::showGlobalPathsWindow);
|
||
|
return menu;
|
||
|
}
|
||
|
|
||
|
PopupMenu ProjucerApplication::createExamplesPopupMenu() noexcept
|
||
|
{
|
||
|
PopupMenu menu;
|
||
|
numExamples = 0;
|
||
|
for (auto& dir : getSortedExampleDirectories())
|
||
|
{
|
||
|
PopupMenu m;
|
||
|
for (auto& f : getSortedExampleFilesInDirectory (dir))
|
||
|
{
|
||
|
m.addItem (examplesBaseID + numExamples, f.getFileNameWithoutExtension());
|
||
|
++numExamples;
|
||
|
}
|
||
|
|
||
|
menu.addSubMenu (dir.getFileName(), m);
|
||
|
}
|
||
|
|
||
|
if (numExamples == 0)
|
||
|
{
|
||
|
menu.addItem (showPathsID, "Set path to JUCE...");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
menu.addSeparator();
|
||
|
menu.addCommandItem (commandManager.get(), CommandIDs::launchDemoRunner);
|
||
|
}
|
||
|
|
||
|
return menu;
|
||
|
}
|
||
|
|
||
|
#if JUCE_MAC
|
||
|
void ProjucerApplication::rebuildAppleMenu()
|
||
|
{
|
||
|
auto extraAppleMenuItems = createExtraAppleMenuItems();
|
||
|
|
||
|
// workaround broken "Open Recent" submenu: not passing the
|
||
|
// submenu's title here avoids the defect in JuceMainMenuHandler::addMenuItem
|
||
|
MenuBarModel::setMacMainMenu (menuModel.get(), &extraAppleMenuItems); //, "Open Recent");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//==============================================================================
|
||
|
File ProjucerApplication::getJUCEExamplesDirectoryPathFromGlobal() noexcept
|
||
|
{
|
||
|
auto globalPath = File::createFileWithoutCheckingPath (getAppSettings().getStoredPath (Ids::jucePath, TargetOS::getThisOS()).get().toString()
|
||
|
.replace ("~", File::getSpecialLocation (File::userHomeDirectory).getFullPathName()));
|
||
|
|
||
|
if (globalPath.exists())
|
||
|
return File (globalPath).getChildFile ("examples");
|
||
|
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
Array<File> ProjucerApplication::getSortedExampleDirectories() noexcept
|
||
|
{
|
||
|
Array<File> exampleDirectories;
|
||
|
|
||
|
auto examplesPath = getJUCEExamplesDirectoryPathFromGlobal();
|
||
|
|
||
|
if (! isValidJUCEExamplesDirectory (examplesPath))
|
||
|
return {};
|
||
|
|
||
|
for (const auto& iter : RangedDirectoryIterator (examplesPath, false, "*", File::findDirectories))
|
||
|
{
|
||
|
auto exampleDirectory = iter.getFile();
|
||
|
|
||
|
if (exampleDirectory.getNumberOfChildFiles (File::findFiles | File::ignoreHiddenFiles) > 0
|
||
|
&& exampleDirectory.getFileName() != "DemoRunner"
|
||
|
&& exampleDirectory.getFileName() != "Assets"
|
||
|
&& exampleDirectory.getFileName() != "CMake")
|
||
|
{
|
||
|
exampleDirectories.add (exampleDirectory);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
exampleDirectories.sort();
|
||
|
|
||
|
return exampleDirectories;
|
||
|
}
|
||
|
|
||
|
Array<File> ProjucerApplication::getSortedExampleFilesInDirectory (const File& directory) noexcept
|
||
|
{
|
||
|
Array<File> exampleFiles;
|
||
|
|
||
|
for (const auto& iter : RangedDirectoryIterator (directory, false, "*.h", File::findFiles))
|
||
|
exampleFiles.add (iter.getFile());
|
||
|
|
||
|
exampleFiles.sort();
|
||
|
|
||
|
return exampleFiles;
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::findAndLaunchExample (int selectedIndex)
|
||
|
{
|
||
|
File example;
|
||
|
|
||
|
for (auto& dir : getSortedExampleDirectories())
|
||
|
{
|
||
|
auto exampleFiles = getSortedExampleFilesInDirectory (dir);
|
||
|
|
||
|
if (selectedIndex < exampleFiles.size())
|
||
|
{
|
||
|
example = exampleFiles.getUnchecked (selectedIndex);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
selectedIndex -= exampleFiles.size();
|
||
|
}
|
||
|
|
||
|
// example doesn't exist?
|
||
|
jassert (example != File());
|
||
|
|
||
|
openFile (example, nullptr);
|
||
|
}
|
||
|
|
||
|
//==============================================================================
|
||
|
static String getPlatformSpecificFileExtension()
|
||
|
{
|
||
|
#if JUCE_MAC
|
||
|
return ".app";
|
||
|
#elif JUCE_WINDOWS
|
||
|
return ".exe";
|
||
|
#elif JUCE_LINUX || JUCE_BSD
|
||
|
return {};
|
||
|
#else
|
||
|
jassertfalse;
|
||
|
return {};
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static File getPlatformSpecificProjectFolder()
|
||
|
{
|
||
|
auto examplesDir = ProjucerApplication::getJUCEExamplesDirectoryPathFromGlobal();
|
||
|
|
||
|
if (examplesDir == File())
|
||
|
return {};
|
||
|
|
||
|
auto buildsFolder = examplesDir.getChildFile ("DemoRunner").getChildFile ("Builds");
|
||
|
|
||
|
#if JUCE_MAC
|
||
|
return buildsFolder.getChildFile ("MacOSX");
|
||
|
#elif JUCE_WINDOWS
|
||
|
return buildsFolder.getChildFile ("VisualStudio2017");
|
||
|
#elif JUCE_LINUX || JUCE_BSD
|
||
|
return buildsFolder.getChildFile ("LinuxMakefile");
|
||
|
#else
|
||
|
jassertfalse;
|
||
|
return {};
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static File tryToFindDemoRunnerExecutableInBuilds()
|
||
|
{
|
||
|
auto projectFolder = getPlatformSpecificProjectFolder();
|
||
|
|
||
|
if (projectFolder == File())
|
||
|
return {};
|
||
|
|
||
|
#if JUCE_MAC
|
||
|
projectFolder = projectFolder.getChildFile ("build");
|
||
|
auto demoRunnerExecutable = projectFolder.getChildFile ("Release").getChildFile ("DemoRunner.app");
|
||
|
|
||
|
if (demoRunnerExecutable.exists())
|
||
|
return demoRunnerExecutable;
|
||
|
|
||
|
demoRunnerExecutable = projectFolder.getChildFile ("Debug").getChildFile ("DemoRunner.app");
|
||
|
|
||
|
if (demoRunnerExecutable.exists())
|
||
|
return demoRunnerExecutable;
|
||
|
#elif JUCE_WINDOWS
|
||
|
projectFolder = projectFolder.getChildFile ("x64");
|
||
|
auto demoRunnerExecutable = projectFolder.getChildFile ("Release").getChildFile ("App").getChildFile ("DemoRunner.exe");
|
||
|
|
||
|
if (demoRunnerExecutable.existsAsFile())
|
||
|
return demoRunnerExecutable;
|
||
|
|
||
|
demoRunnerExecutable = projectFolder.getChildFile ("Debug").getChildFile ("App").getChildFile ("DemoRunner.exe");
|
||
|
|
||
|
if (demoRunnerExecutable.existsAsFile())
|
||
|
return demoRunnerExecutable;
|
||
|
#elif JUCE_LINUX || JUCE_BSD
|
||
|
projectFolder = projectFolder.getChildFile ("build");
|
||
|
auto demoRunnerExecutable = projectFolder.getChildFile ("DemoRunner");
|
||
|
|
||
|
if (demoRunnerExecutable.existsAsFile())
|
||
|
return demoRunnerExecutable;
|
||
|
#endif
|
||
|
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
static File tryToFindPrebuiltDemoRunnerExecutable()
|
||
|
{
|
||
|
auto prebuiltFile = File (getAppSettings().getStoredPath (Ids::jucePath, TargetOS::getThisOS()).get().toString())
|
||
|
.getChildFile ("DemoRunner" + getPlatformSpecificFileExtension());
|
||
|
|
||
|
#if JUCE_MAC
|
||
|
if (prebuiltFile.exists())
|
||
|
#else
|
||
|
if (prebuiltFile.existsAsFile())
|
||
|
#endif
|
||
|
return prebuiltFile;
|
||
|
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::checkIfGlobalJUCEPathHasChanged()
|
||
|
{
|
||
|
auto globalJUCEPath = File (getAppSettings().getStoredPath (Ids::jucePath, TargetOS::getThisOS()).get());
|
||
|
|
||
|
if (lastJUCEPath != globalJUCEPath)
|
||
|
{
|
||
|
hasScannedForDemoRunnerProject = false;
|
||
|
hasScannedForDemoRunnerExecutable = false;
|
||
|
|
||
|
lastJUCEPath = globalJUCEPath;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
File ProjucerApplication::tryToFindDemoRunnerExecutable()
|
||
|
{
|
||
|
checkIfGlobalJUCEPathHasChanged();
|
||
|
|
||
|
if (hasScannedForDemoRunnerExecutable)
|
||
|
return lastDemoRunnerExectuableFile;
|
||
|
|
||
|
hasScannedForDemoRunnerExecutable = true;
|
||
|
|
||
|
auto demoRunnerExecutable = tryToFindDemoRunnerExecutableInBuilds();
|
||
|
|
||
|
if (demoRunnerExecutable == File())
|
||
|
demoRunnerExecutable = tryToFindPrebuiltDemoRunnerExecutable();
|
||
|
|
||
|
lastDemoRunnerExectuableFile = demoRunnerExecutable;
|
||
|
|
||
|
return demoRunnerExecutable;
|
||
|
}
|
||
|
|
||
|
File ProjucerApplication::tryToFindDemoRunnerProject()
|
||
|
{
|
||
|
checkIfGlobalJUCEPathHasChanged();
|
||
|
|
||
|
if (hasScannedForDemoRunnerProject)
|
||
|
return lastDemoRunnerProjectFile;
|
||
|
|
||
|
hasScannedForDemoRunnerProject = true;
|
||
|
|
||
|
auto projectFolder = getPlatformSpecificProjectFolder();
|
||
|
|
||
|
if (projectFolder == File())
|
||
|
{
|
||
|
lastDemoRunnerProjectFile = File();
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
#if JUCE_MAC
|
||
|
auto demoRunnerProjectFile = projectFolder.getChildFile ("DemoRunner.xcodeproj");
|
||
|
#elif JUCE_WINDOWS
|
||
|
auto demoRunnerProjectFile = projectFolder.getChildFile ("DemoRunner.sln");
|
||
|
#elif JUCE_LINUX || JUCE_BSD
|
||
|
auto demoRunnerProjectFile = projectFolder.getChildFile ("Makefile");
|
||
|
#endif
|
||
|
|
||
|
#if JUCE_MAC
|
||
|
if (! demoRunnerProjectFile.exists())
|
||
|
#else
|
||
|
if (! demoRunnerProjectFile.existsAsFile())
|
||
|
#endif
|
||
|
demoRunnerProjectFile = File();
|
||
|
|
||
|
lastDemoRunnerProjectFile = demoRunnerProjectFile;
|
||
|
|
||
|
return demoRunnerProjectFile;
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::launchDemoRunner()
|
||
|
{
|
||
|
auto demoRunnerFile = tryToFindDemoRunnerExecutable();
|
||
|
|
||
|
if (demoRunnerFile != File() && demoRunnerFile.startAsProcess())
|
||
|
return;
|
||
|
|
||
|
demoRunnerFile = tryToFindDemoRunnerProject();
|
||
|
|
||
|
if (demoRunnerFile != File())
|
||
|
{
|
||
|
auto& lf = Desktop::getInstance().getDefaultLookAndFeel();
|
||
|
|
||
|
#if JUCE_LINUX || JUCE_BSD
|
||
|
demoRunnerAlert.reset (lf.createAlertWindow ("Open Project",
|
||
|
"Couldn't find a compiled version of the Demo Runner."
|
||
|
" Please compile the Demo Runner project in the JUCE examples directory.",
|
||
|
"OK", {}, {},
|
||
|
MessageBoxIconType::WarningIcon, 1,
|
||
|
mainWindowList.getFrontmostWindow (false)));
|
||
|
demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this] (int)
|
||
|
{
|
||
|
demoRunnerAlert.reset (nullptr);
|
||
|
}), false);
|
||
|
|
||
|
#else
|
||
|
demoRunnerAlert.reset (lf.createAlertWindow ("Open Project",
|
||
|
"Couldn't find a compiled version of the Demo Runner."
|
||
|
" Do you want to open the project?",
|
||
|
"Open project", "Cancel", {},
|
||
|
MessageBoxIconType::QuestionIcon, 2,
|
||
|
mainWindowList.getFrontmostWindow (false)));
|
||
|
demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this, demoRunnerFile] (int retVal)
|
||
|
{
|
||
|
demoRunnerAlert.reset (nullptr);
|
||
|
|
||
|
if (retVal == 1)
|
||
|
demoRunnerFile.startAsProcess();
|
||
|
}), false);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//==============================================================================
|
||
|
void ProjucerApplication::handleMainMenuCommand (int menuItemID)
|
||
|
{
|
||
|
if (menuItemID >= recentProjectsBaseID && menuItemID < (recentProjectsBaseID + 100))
|
||
|
{
|
||
|
// open a file from the "recent files" menu
|
||
|
openFile (settings->recentFiles.getFile (menuItemID - recentProjectsBaseID), nullptr);
|
||
|
}
|
||
|
else if (menuItemID >= openWindowsBaseID && menuItemID < (openWindowsBaseID + 100))
|
||
|
{
|
||
|
if (auto* window = mainWindowList.windows.getUnchecked (menuItemID - openWindowsBaseID))
|
||
|
window->toFront (true);
|
||
|
}
|
||
|
else if (menuItemID >= activeDocumentsBaseID && menuItemID < (activeDocumentsBaseID + 200))
|
||
|
{
|
||
|
if (auto* doc = openDocumentManager.getOpenDocument (menuItemID - activeDocumentsBaseID))
|
||
|
mainWindowList.openDocument (doc, true);
|
||
|
else
|
||
|
jassertfalse;
|
||
|
}
|
||
|
else if (menuItemID == showPathsID)
|
||
|
{
|
||
|
showPathsWindow (true);
|
||
|
}
|
||
|
else if (menuItemID >= examplesBaseID && menuItemID < (examplesBaseID + numExamples))
|
||
|
{
|
||
|
findAndLaunchExample (menuItemID - examplesBaseID);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
handleGUIEditorMenuCommand (menuItemID);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//==============================================================================
|
||
|
void ProjucerApplication::getAllCommands (Array <CommandID>& commands)
|
||
|
{
|
||
|
JUCEApplication::getAllCommands (commands);
|
||
|
|
||
|
const CommandID ids[] = { CommandIDs::newProject,
|
||
|
CommandIDs::newProjectFromClipboard,
|
||
|
CommandIDs::newPIP,
|
||
|
CommandIDs::open,
|
||
|
CommandIDs::launchDemoRunner,
|
||
|
CommandIDs::closeAllWindows,
|
||
|
CommandIDs::closeAllDocuments,
|
||
|
CommandIDs::clearRecentFiles,
|
||
|
CommandIDs::saveAll,
|
||
|
CommandIDs::showGlobalPathsWindow,
|
||
|
CommandIDs::showUTF8Tool,
|
||
|
CommandIDs::showSVGPathTool,
|
||
|
CommandIDs::enableGUIEditor,
|
||
|
CommandIDs::showAboutWindow,
|
||
|
CommandIDs::checkForNewVersion,
|
||
|
CommandIDs::enableNewVersionCheck,
|
||
|
CommandIDs::showForum,
|
||
|
CommandIDs::showAPIModules,
|
||
|
CommandIDs::showAPIClasses,
|
||
|
CommandIDs::showTutorials,
|
||
|
CommandIDs::loginLogout };
|
||
|
|
||
|
commands.addArray (ids, numElementsInArray (ids));
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::getCommandInfo (CommandID commandID, ApplicationCommandInfo& result)
|
||
|
{
|
||
|
switch (commandID)
|
||
|
{
|
||
|
case CommandIDs::newProject:
|
||
|
result.setInfo ("New Project...", "Creates a new JUCE project", CommandCategories::general, 0);
|
||
|
result.defaultKeypresses.add (KeyPress ('n', ModifierKeys::commandModifier, 0));
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::newProjectFromClipboard:
|
||
|
result.setInfo ("New Project From Clipboard...", "Creates a new JUCE project from the clipboard contents", CommandCategories::general, 0);
|
||
|
result.defaultKeypresses.add (KeyPress ('n', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0));
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::newPIP:
|
||
|
result.setInfo ("New PIP...", "Opens the PIP Creator utility for creating a new PIP", CommandCategories::general, 0);
|
||
|
result.defaultKeypresses.add (KeyPress ('p', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0));
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::launchDemoRunner:
|
||
|
result.setInfo ("Launch Demo Runner", "Launches the JUCE demo runner application, or the project if it can't be found", CommandCategories::general, 0);
|
||
|
result.setActive (tryToFindDemoRunnerExecutable() != File() || tryToFindDemoRunnerProject() != File());
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::open:
|
||
|
result.setInfo ("Open...", "Opens a JUCE project", CommandCategories::general, 0);
|
||
|
result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::showGlobalPathsWindow:
|
||
|
result.setInfo ("Global Paths...",
|
||
|
"Shows the window to change the stored global paths.",
|
||
|
CommandCategories::general, 0);
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::closeAllWindows:
|
||
|
result.setInfo ("Close All Windows", "Closes all open windows", CommandCategories::general, 0);
|
||
|
result.setActive (mainWindowList.windows.size() > 0);
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::closeAllDocuments:
|
||
|
result.setInfo ("Close All Documents", "Closes all open documents", CommandCategories::general, 0);
|
||
|
result.setActive (openDocumentManager.getNumOpenDocuments() > 0);
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::clearRecentFiles:
|
||
|
result.setInfo ("Clear Recent Files", "Clears all recent files from the menu", CommandCategories::general, 0);
|
||
|
result.setActive (settings->recentFiles.getNumFiles() > 0);
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::saveAll:
|
||
|
result.setInfo ("Save All", "Saves all open documents", CommandCategories::general, 0);
|
||
|
result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier | ModifierKeys::altModifier, 0));
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::showUTF8Tool:
|
||
|
result.setInfo ("UTF-8 String-Literal Helper", "Shows the UTF-8 string literal utility", CommandCategories::general, 0);
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::showSVGPathTool:
|
||
|
result.setInfo ("SVG Path Converter", "Shows the SVG->Path data conversion utility", CommandCategories::general, 0);
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::enableGUIEditor:
|
||
|
result.setInfo ("GUI Editor Enabled",
|
||
|
"Enables or disables the GUI editor functionality",
|
||
|
CommandCategories::general,
|
||
|
(isGUIEditorEnabled() ? ApplicationCommandInfo::isTicked : 0));
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::showAboutWindow:
|
||
|
result.setInfo ("About Projucer", "Shows the Projucer's 'About' page.", CommandCategories::general, 0);
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::checkForNewVersion:
|
||
|
result.setInfo ("Check for New Version...", "Checks the web server for a new version of JUCE", CommandCategories::general, 0);
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::enableNewVersionCheck:
|
||
|
result.setInfo ("Automatically Check for New Versions",
|
||
|
"Enables automatic background checking for new versions of JUCE.",
|
||
|
CommandCategories::general,
|
||
|
(isAutomaticVersionCheckingEnabled() ? ApplicationCommandInfo::isTicked : 0));
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::showForum:
|
||
|
result.setInfo ("JUCE Community Forum", "Shows the JUCE community forum in a browser", CommandCategories::general, 0);
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::showAPIModules:
|
||
|
result.setInfo ("API Modules", "Shows the API modules documentation in a browser", CommandCategories::general, 0);
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::showAPIClasses:
|
||
|
result.setInfo ("API Classes", "Shows the API classes documentation in a browser", CommandCategories::general, 0);
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::showTutorials:
|
||
|
result.setInfo ("JUCE Tutorials", "Shows the JUCE tutorials in a browser", CommandCategories::general, 0);
|
||
|
break;
|
||
|
|
||
|
case CommandIDs::loginLogout:
|
||
|
{
|
||
|
auto licenseState = licenseController->getCurrentState();
|
||
|
|
||
|
if (licenseState.isGPL())
|
||
|
result.setInfo ("Disable GPL mode", "Disables GPL mode", CommandCategories::general, 0);
|
||
|
else
|
||
|
result.setInfo (licenseState.isSignedIn() ? String ("Sign out ") + licenseState.username + "..." : String ("Sign in..."),
|
||
|
"Sign out of your JUCE account",
|
||
|
CommandCategories::general, 0);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
JUCEApplication::getCommandInfo (commandID, result);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ProjucerApplication::perform (const InvocationInfo& info)
|
||
|
{
|
||
|
switch (info.commandID)
|
||
|
{
|
||
|
case CommandIDs::newProject: createNewProject(); break;
|
||
|
case CommandIDs::newProjectFromClipboard: createNewProjectFromClipboard(); break;
|
||
|
case CommandIDs::newPIP: createNewPIP(); break;
|
||
|
case CommandIDs::open: askUserToOpenFile(); break;
|
||
|
case CommandIDs::launchDemoRunner: launchDemoRunner(); break;
|
||
|
case CommandIDs::saveAll: saveAllDocuments(); break;
|
||
|
case CommandIDs::closeAllWindows: closeAllMainWindowsAndQuitIfNeeded(); break;
|
||
|
case CommandIDs::closeAllDocuments: closeAllDocuments (OpenDocumentManager::SaveIfNeeded::yes); break;
|
||
|
case CommandIDs::clearRecentFiles: clearRecentFiles(); break;
|
||
|
case CommandIDs::showUTF8Tool: showUTF8ToolWindow(); break;
|
||
|
case CommandIDs::showSVGPathTool: showSVGPathDataToolWindow(); break;
|
||
|
case CommandIDs::enableGUIEditor: enableOrDisableGUIEditor(); break;
|
||
|
case CommandIDs::showGlobalPathsWindow: showPathsWindow (false); break;
|
||
|
case CommandIDs::showAboutWindow: showAboutWindow(); break;
|
||
|
case CommandIDs::checkForNewVersion: LatestVersionCheckerAndUpdater::getInstance()->checkForNewVersion (false); break;
|
||
|
case CommandIDs::enableNewVersionCheck: setAutomaticVersionCheckingEnabled (! isAutomaticVersionCheckingEnabled()); break;
|
||
|
case CommandIDs::showForum: launchForumBrowser(); break;
|
||
|
case CommandIDs::showAPIModules: launchModulesBrowser(); break;
|
||
|
case CommandIDs::showAPIClasses: launchClassesBrowser(); break;
|
||
|
case CommandIDs::showTutorials: launchTutorialsBrowser(); break;
|
||
|
case CommandIDs::loginLogout: doLoginOrLogout(); break;
|
||
|
default: return JUCEApplication::perform (info);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//==============================================================================
|
||
|
void ProjucerApplication::createNewProject()
|
||
|
{
|
||
|
auto* mw = mainWindowList.getOrCreateEmptyWindow();
|
||
|
jassert (mw != nullptr);
|
||
|
|
||
|
mw->showStartPage();
|
||
|
|
||
|
mainWindowList.checkWindowBounds (*mw);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::createNewProjectFromClipboard()
|
||
|
{
|
||
|
auto tempFile = File::getSpecialLocation (File::SpecialLocationType::tempDirectory).getChildFile ("PIPs").getChildFile ("Clipboard")
|
||
|
.getChildFile ("PIPFile_" + String (std::abs (Random::getSystemRandom().nextInt())) + ".h")
|
||
|
.getNonexistentSibling();
|
||
|
|
||
|
if (tempFile.existsAsFile())
|
||
|
tempFile.deleteFile();
|
||
|
|
||
|
tempFile.create();
|
||
|
tempFile.appendText (SystemClipboard::getTextFromClipboard());
|
||
|
|
||
|
auto cleanup = [tempFile] (String errorString)
|
||
|
{
|
||
|
if (errorString.isNotEmpty())
|
||
|
{
|
||
|
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Error", errorString);
|
||
|
tempFile.deleteFile();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
if (! isPIPFile (tempFile))
|
||
|
{
|
||
|
cleanup ("Clipboard does not contain a valid PIP.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
openFile (tempFile, [parent = WeakReference<ProjucerApplication> { this }, cleanup] (bool openedSuccessfully)
|
||
|
{
|
||
|
if (parent == nullptr)
|
||
|
return;
|
||
|
|
||
|
if (! openedSuccessfully)
|
||
|
{
|
||
|
cleanup ("Couldn't create project from clipboard contents.");
|
||
|
parent->mainWindowList.closeWindow (parent->mainWindowList.windows.getLast());
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::createNewPIP()
|
||
|
{
|
||
|
showPIPCreatorWindow();
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::askUserToOpenFile()
|
||
|
{
|
||
|
chooser = std::make_unique<FileChooser> ("Open File");
|
||
|
auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles;
|
||
|
|
||
|
chooser->launchAsync (flags, [this] (const FileChooser& fc)
|
||
|
{
|
||
|
const auto result = fc.getResult();
|
||
|
|
||
|
if (result != File{})
|
||
|
openFile (result, nullptr);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::openFile (const File& file, std::function<void (bool)> callback)
|
||
|
{
|
||
|
mainWindowList.openFile (file, std::move (callback));
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::saveAllDocuments()
|
||
|
{
|
||
|
openDocumentManager.saveAllSyncWithoutAsking();
|
||
|
|
||
|
for (int i = 0; i < mainWindowList.windows.size(); ++i)
|
||
|
if (auto* pcc = mainWindowList.windows.getUnchecked(i)->getProjectContentComponent())
|
||
|
pcc->refreshProjectTreeFileStatuses();
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::closeAllDocuments (OpenDocumentManager::SaveIfNeeded askUserToSave)
|
||
|
{
|
||
|
openDocumentManager.closeAllAsync (askUserToSave, nullptr);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::closeAllMainWindows (std::function<void (bool)> callback)
|
||
|
{
|
||
|
mainWindowList.askAllWindowsToClose (std::move (callback));
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::closeAllMainWindowsAndQuitIfNeeded()
|
||
|
{
|
||
|
closeAllMainWindows ([parent = WeakReference<ProjucerApplication> { this }] (bool closedSuccessfully)
|
||
|
{
|
||
|
#if JUCE_MAC
|
||
|
ignoreUnused (parent, closedSuccessfully);
|
||
|
#else
|
||
|
if (parent == nullptr)
|
||
|
return;
|
||
|
|
||
|
if (closedSuccessfully && parent->mainWindowList.windows.size() == 0)
|
||
|
parent->systemRequestedQuit();
|
||
|
#endif
|
||
|
});
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::clearRecentFiles()
|
||
|
{
|
||
|
settings->recentFiles.clear();
|
||
|
settings->recentFiles.clearRecentFilesNatively();
|
||
|
settings->flush();
|
||
|
menuModel->menuItemsChanged();
|
||
|
}
|
||
|
|
||
|
//==============================================================================
|
||
|
void ProjucerApplication::showUTF8ToolWindow()
|
||
|
{
|
||
|
if (utf8Window != nullptr)
|
||
|
utf8Window->toFront (true);
|
||
|
else
|
||
|
new FloatingToolWindow ("UTF-8 String Literal Converter", "utf8WindowPos",
|
||
|
new UTF8Component(), utf8Window, true,
|
||
|
500, 500, 300, 300, 1000, 1000);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::showSVGPathDataToolWindow()
|
||
|
{
|
||
|
if (svgPathWindow != nullptr)
|
||
|
svgPathWindow->toFront (true);
|
||
|
else
|
||
|
new FloatingToolWindow ("SVG Path Converter", "svgPathWindowPos",
|
||
|
new SVGPathDataComponent(), svgPathWindow, true,
|
||
|
500, 500, 300, 300, 1000, 1000);
|
||
|
}
|
||
|
|
||
|
bool ProjucerApplication::isGUIEditorEnabled() const
|
||
|
{
|
||
|
return getGlobalProperties().getBoolValue (Ids::guiEditorEnabled);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::enableOrDisableGUIEditor()
|
||
|
{
|
||
|
getGlobalProperties().setValue (Ids::guiEditorEnabled, ! isGUIEditorEnabled());
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::showAboutWindow()
|
||
|
{
|
||
|
if (aboutWindow != nullptr)
|
||
|
aboutWindow->toFront (true);
|
||
|
else
|
||
|
new FloatingToolWindow ({}, {}, new AboutWindowComponent(),
|
||
|
aboutWindow, false,
|
||
|
500, 300, 500, 300, 500, 300);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::showPathsWindow (bool highlightJUCEPath)
|
||
|
{
|
||
|
if (pathsWindow != nullptr)
|
||
|
pathsWindow->toFront (true);
|
||
|
else
|
||
|
new FloatingToolWindow ("Global Paths", "pathsWindowPos",
|
||
|
new GlobalPathsWindowComponent(), pathsWindow, false,
|
||
|
600, 700, 600, 700, 600, 700);
|
||
|
|
||
|
if (highlightJUCEPath)
|
||
|
if (auto* pathsComp = dynamic_cast<GlobalPathsWindowComponent*> (pathsWindow->getChildComponent (0)))
|
||
|
pathsComp->highlightJUCEPath();
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::showEditorColourSchemeWindow()
|
||
|
{
|
||
|
if (editorColourSchemeWindow != nullptr)
|
||
|
editorColourSchemeWindow->toFront (true);
|
||
|
else
|
||
|
new FloatingToolWindow ("Editor Colour Scheme", "editorColourSchemeWindowPos",
|
||
|
new EditorColourSchemeWindowComponent(), editorColourSchemeWindow, false,
|
||
|
500, 500, 500, 500, 500, 500);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::showPIPCreatorWindow()
|
||
|
{
|
||
|
if (pipCreatorWindow != nullptr)
|
||
|
pipCreatorWindow->toFront (true);
|
||
|
else
|
||
|
new FloatingToolWindow ("PIP Creator", "pipCreatorWindowPos",
|
||
|
new PIPCreatorWindowComponent(), pipCreatorWindow, false,
|
||
|
600, 750, 600, 750, 600, 750);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::launchForumBrowser()
|
||
|
{
|
||
|
URL forumLink ("https://forum.juce.com/");
|
||
|
|
||
|
if (forumLink.isWellFormed())
|
||
|
forumLink.launchInDefaultBrowser();
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::launchModulesBrowser()
|
||
|
{
|
||
|
URL modulesLink ("https://docs.juce.com/master/modules.html");
|
||
|
|
||
|
if (modulesLink.isWellFormed())
|
||
|
modulesLink.launchInDefaultBrowser();
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::launchClassesBrowser()
|
||
|
{
|
||
|
URL classesLink ("https://docs.juce.com/master/classes.html");
|
||
|
|
||
|
if (classesLink.isWellFormed())
|
||
|
classesLink.launchInDefaultBrowser();
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::launchTutorialsBrowser()
|
||
|
{
|
||
|
URL tutorialsLink ("https://juce.com/learn/tutorials");
|
||
|
|
||
|
if (tutorialsLink.isWellFormed())
|
||
|
tutorialsLink.launchInDefaultBrowser();
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::doLoginOrLogout()
|
||
|
{
|
||
|
if (licenseController->getCurrentState().isSignedIn())
|
||
|
{
|
||
|
licenseController->resetState();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (auto* window = mainWindowList.getMainWindowWithLoginFormOpen())
|
||
|
{
|
||
|
window->toFront (true);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mainWindowList.createWindowIfNoneAreOpen();
|
||
|
mainWindowList.getFrontmostWindow()->showLoginFormOverlay();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//==============================================================================
|
||
|
struct FileWithTime
|
||
|
{
|
||
|
FileWithTime (const File& f) : file (f), time (f.getLastModificationTime()) {}
|
||
|
FileWithTime() {}
|
||
|
|
||
|
bool operator< (const FileWithTime& other) const { return time < other.time; }
|
||
|
bool operator== (const FileWithTime& other) const { return time == other.time; }
|
||
|
|
||
|
File file;
|
||
|
Time time;
|
||
|
};
|
||
|
|
||
|
void ProjucerApplication::deleteLogger()
|
||
|
{
|
||
|
const int maxNumLogFilesToKeep = 50;
|
||
|
|
||
|
Logger::setCurrentLogger (nullptr);
|
||
|
|
||
|
if (logger != nullptr)
|
||
|
{
|
||
|
auto logFiles = logger->getLogFile().getParentDirectory().findChildFiles (File::findFiles, false);
|
||
|
|
||
|
if (logFiles.size() > maxNumLogFilesToKeep)
|
||
|
{
|
||
|
Array<FileWithTime> files;
|
||
|
|
||
|
for (auto& f : logFiles)
|
||
|
files.addUsingDefaultSort (f);
|
||
|
|
||
|
for (int i = 0; i < files.size() - maxNumLogFilesToKeep; ++i)
|
||
|
files.getReference(i).file.deleteFile();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
logger.reset();
|
||
|
}
|
||
|
|
||
|
PropertiesFile::Options ProjucerApplication::getPropertyFileOptionsFor (const String& filename, bool isProjectSettings)
|
||
|
{
|
||
|
PropertiesFile::Options options;
|
||
|
options.applicationName = filename;
|
||
|
options.filenameSuffix = "settings";
|
||
|
options.osxLibrarySubFolder = "Application Support";
|
||
|
#if JUCE_LINUX || JUCE_BSD
|
||
|
options.folderName = "~/.config/Projucer";
|
||
|
#else
|
||
|
options.folderName = "Projucer";
|
||
|
#endif
|
||
|
|
||
|
if (isProjectSettings)
|
||
|
options.folderName += "/ProjectSettings";
|
||
|
|
||
|
return options;
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::initCommandManager()
|
||
|
{
|
||
|
commandManager.reset (new ApplicationCommandManager());
|
||
|
commandManager->registerAllCommandsForTarget (this);
|
||
|
|
||
|
{
|
||
|
CodeDocument doc;
|
||
|
CppCodeEditorComponent ed (File(), doc);
|
||
|
commandManager->registerAllCommandsForTarget (&ed);
|
||
|
}
|
||
|
|
||
|
registerGUIEditorCommands();
|
||
|
}
|
||
|
|
||
|
static void rescanModules (AvailableModulesList& list, const Array<File>& paths, bool async)
|
||
|
{
|
||
|
if (async)
|
||
|
list.scanPathsAsync (paths);
|
||
|
else
|
||
|
list.scanPaths (paths);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::rescanJUCEPathModules()
|
||
|
{
|
||
|
rescanModules (jucePathModulesList, { getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()).get().toString() }, ! isRunningCommandLine);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::rescanUserPathModules()
|
||
|
{
|
||
|
rescanModules (userPathsModulesList, { getAppSettings().getStoredPath (Ids::defaultUserModulePath, TargetOS::getThisOS()).get().toString() }, ! isRunningCommandLine);
|
||
|
}
|
||
|
|
||
|
bool ProjucerApplication::isAutomaticVersionCheckingEnabled() const
|
||
|
{
|
||
|
return ! getGlobalProperties().getBoolValue (Ids::dontQueryForUpdate);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::setAutomaticVersionCheckingEnabled (bool enabled)
|
||
|
{
|
||
|
getGlobalProperties().setValue (Ids::dontQueryForUpdate, ! enabled);
|
||
|
}
|
||
|
|
||
|
bool ProjucerApplication::shouldPromptUserAboutIncorrectJUCEPath() const
|
||
|
{
|
||
|
return ! getGlobalProperties().getBoolValue (Ids::dontAskAboutJUCEPath);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::setShouldPromptUserAboutIncorrectJUCEPath (bool shouldPrompt)
|
||
|
{
|
||
|
getGlobalProperties().setValue (Ids::dontAskAboutJUCEPath, ! shouldPrompt);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::selectEditorColourSchemeWithName (const String& schemeName)
|
||
|
{
|
||
|
auto& appearanceSettings = getAppSettings().appearance;
|
||
|
auto schemes = appearanceSettings.getPresetSchemes();
|
||
|
|
||
|
auto schemeIndex = schemes.indexOf (schemeName);
|
||
|
|
||
|
if (schemeIndex >= 0)
|
||
|
setEditorColourScheme (schemeIndex, true);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::setColourScheme (int index, bool saveSetting)
|
||
|
{
|
||
|
switch (index)
|
||
|
{
|
||
|
case 0: lookAndFeel.setColourScheme (LookAndFeel_V4::getDarkColourScheme()); break;
|
||
|
case 1: lookAndFeel.setColourScheme (LookAndFeel_V4::getGreyColourScheme()); break;
|
||
|
case 2: lookAndFeel.setColourScheme (LookAndFeel_V4::getLightColourScheme()); break;
|
||
|
default: break;
|
||
|
}
|
||
|
|
||
|
lookAndFeel.setupColours();
|
||
|
mainWindowList.sendLookAndFeelChange();
|
||
|
|
||
|
if (utf8Window != nullptr) utf8Window->sendLookAndFeelChange();
|
||
|
if (svgPathWindow != nullptr) svgPathWindow->sendLookAndFeelChange();
|
||
|
if (aboutWindow != nullptr) aboutWindow->sendLookAndFeelChange();
|
||
|
if (pathsWindow != nullptr) pathsWindow->sendLookAndFeelChange();
|
||
|
if (editorColourSchemeWindow != nullptr) editorColourSchemeWindow->sendLookAndFeelChange();
|
||
|
if (pipCreatorWindow != nullptr) pipCreatorWindow->sendLookAndFeelChange();
|
||
|
|
||
|
auto* mcm = ModalComponentManager::getInstance();
|
||
|
for (auto i = 0; i < mcm->getNumModalComponents(); ++i)
|
||
|
mcm->getModalComponent (i)->sendLookAndFeelChange();
|
||
|
|
||
|
if (saveSetting)
|
||
|
{
|
||
|
auto& properties = getGlobalProperties();
|
||
|
properties.setValue ("COLOUR SCHEME", index);
|
||
|
}
|
||
|
|
||
|
selectedColourSchemeIndex = index;
|
||
|
|
||
|
getCommandManager().commandStatusChanged();
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::setEditorColourScheme (int index, bool saveSetting)
|
||
|
{
|
||
|
auto& appearanceSettings = getAppSettings().appearance;
|
||
|
auto schemes = appearanceSettings.getPresetSchemes();
|
||
|
|
||
|
index = jmin (index, schemes.size() - 1);
|
||
|
|
||
|
appearanceSettings.selectPresetScheme (index);
|
||
|
|
||
|
if (saveSetting)
|
||
|
{
|
||
|
auto& properties = getGlobalProperties();
|
||
|
properties.setValue ("EDITOR COLOUR SCHEME", index);
|
||
|
}
|
||
|
|
||
|
selectedEditorColourSchemeIndex = index;
|
||
|
|
||
|
getCommandManager().commandStatusChanged();
|
||
|
}
|
||
|
|
||
|
static bool isEditorColourSchemeADefaultScheme (const StringArray& schemes, int editorColourSchemeIndex)
|
||
|
{
|
||
|
auto& schemeName = schemes[editorColourSchemeIndex];
|
||
|
return (schemeName == "Default (Dark)" || schemeName == "Default (Light)");
|
||
|
}
|
||
|
|
||
|
static int getEditorColourSchemeForGUIColourScheme (const StringArray& schemes, int guiColourSchemeIndex)
|
||
|
{
|
||
|
auto defaultDarkEditorIndex = schemes.indexOf ("Default (Dark)");
|
||
|
auto defaultLightEditorIndex = schemes.indexOf ("Default (Light)");
|
||
|
|
||
|
// Can't find default code editor colour schemes!
|
||
|
jassert (defaultDarkEditorIndex != -1 && defaultLightEditorIndex != -1);
|
||
|
|
||
|
return (guiColourSchemeIndex == 2 ? defaultLightEditorIndex : defaultDarkEditorIndex);
|
||
|
}
|
||
|
|
||
|
void ProjucerApplication::updateEditorColourSchemeIfNeeded()
|
||
|
{
|
||
|
auto& appearanceSettings = getAppSettings().appearance;
|
||
|
auto schemes = appearanceSettings.getPresetSchemes();
|
||
|
|
||
|
if (isEditorColourSchemeADefaultScheme (schemes, selectedEditorColourSchemeIndex))
|
||
|
setEditorColourScheme (getEditorColourSchemeForGUIColourScheme (schemes, selectedColourSchemeIndex), true);
|
||
|
}
|