The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

970 lines
34KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. void createGUIEditorMenu (PopupMenu&);
  20. void handleGUIEditorMenuCommand (int);
  21. void registerGUIEditorCommands();
  22. void attachCallback (Button& button, std::function<void()> callback)
  23. {
  24. struct ButtonCallback : public Button::Listener,
  25. private ComponentListener
  26. {
  27. ButtonCallback (Button& b, std::function<void()> f) : target (b), fn (f)
  28. {
  29. target.addListener (this);
  30. target.addComponentListener (this);
  31. }
  32. ~ButtonCallback()
  33. {
  34. target.removeListener (this);
  35. }
  36. void componentBeingDeleted (Component&) override { delete this; }
  37. void buttonClicked (Button*) override { fn(); }
  38. Button& target;
  39. std::function<void()> fn;
  40. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonCallback)
  41. };
  42. new ButtonCallback (button, callback);
  43. }
  44. //==============================================================================
  45. struct ProjucerApplication::MainMenuModel : public MenuBarModel
  46. {
  47. MainMenuModel()
  48. {
  49. setApplicationCommandManagerToWatch (&getCommandManager());
  50. }
  51. StringArray getMenuBarNames() override
  52. {
  53. return getApp().getMenuNames();
  54. }
  55. PopupMenu getMenuForIndex (int /*topLevelMenuIndex*/, const String& menuName) override
  56. {
  57. PopupMenu menu;
  58. getApp().createMenu (menu, menuName);
  59. return menu;
  60. }
  61. void menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/) override
  62. {
  63. getApp().handleMainMenuCommand (menuItemID);
  64. }
  65. };
  66. //==============================================================================
  67. ProjucerApplication::ProjucerApplication() : isRunningCommandLine (false)
  68. {
  69. }
  70. void ProjucerApplication::initialise (const String& commandLine)
  71. {
  72. if (commandLine.trimStart().startsWith ("--server"))
  73. {
  74. initialiseLogger ("Compiler_Log_");
  75. LookAndFeel::setDefaultLookAndFeel (&lookAndFeel);
  76. #if JUCE_MAC
  77. Process::setDockIconVisible (false);
  78. #endif
  79. server = createClangServer (commandLine);
  80. }
  81. else
  82. {
  83. initialiseLogger ("IDE_Log_");
  84. Logger::writeToLog (SystemStats::getOperatingSystemName());
  85. Logger::writeToLog ("CPU: " + String (SystemStats::getCpuSpeedInMegaherz())
  86. + "MHz Cores: " + String (SystemStats::getNumCpus())
  87. + " " + String (SystemStats::getMemorySizeInMegabytes()) + "MB");
  88. initialiseBasics();
  89. isRunningCommandLine = commandLine.isNotEmpty();
  90. licenseController = new LicenseController;
  91. licenseController->addLicenseStatusChangedCallback (this);
  92. if (isRunningCommandLine)
  93. {
  94. const int appReturnCode = performCommandLine (commandLine);
  95. if (appReturnCode != commandLineNotPerformed)
  96. {
  97. setApplicationReturnValue (appReturnCode);
  98. quit();
  99. return;
  100. }
  101. isRunningCommandLine = false;
  102. }
  103. if (sendCommandLineToPreexistingInstance())
  104. {
  105. DBG ("Another instance is running - quitting...");
  106. quit();
  107. return;
  108. }
  109. openDocumentManager.registerType (new ProjucerAppClasses::LiveBuildCodeEditorDocument::Type(), 2);
  110. childProcessCache = new ChildProcessCache();
  111. initCommandManager();
  112. menuModel = new MainMenuModel();
  113. settings->appearance.refreshPresetSchemeList();
  114. setColourScheme (settings->getGlobalProperties().getIntValue ("COLOUR SCHEME"), false);
  115. setEditorColourScheme (settings->getGlobalProperties().getIntValue ("EDITOR COLOUR SCHEME"), false);
  116. updateEditorColourSchemeIfNeeded();
  117. // do further initialisation in a moment when the message loop has started
  118. triggerAsyncUpdate();
  119. }
  120. }
  121. void ProjucerApplication::initialiseBasics()
  122. {
  123. LookAndFeel::setDefaultLookAndFeel (&lookAndFeel);
  124. settings = new StoredSettings();
  125. ImageCache::setCacheTimeout (30 * 1000);
  126. icons = new Icons();
  127. tooltipWindow.setMillisecondsBeforeTipAppears (1200);
  128. }
  129. bool ProjucerApplication::initialiseLogger (const char* filePrefix)
  130. {
  131. if (logger == nullptr)
  132. {
  133. #if JUCE_LINUX
  134. String folder = "~/.config/Projucer/Logs";
  135. #else
  136. String folder = "com.juce.projucer";
  137. #endif
  138. logger = FileLogger::createDateStampedLogger (folder, filePrefix, ".txt",
  139. getApplicationName() + " " + getApplicationVersion()
  140. + " --- Build date: " __DATE__);
  141. Logger::setCurrentLogger (logger);
  142. }
  143. return logger != nullptr;
  144. }
  145. void ProjucerApplication::handleAsyncUpdate()
  146. {
  147. if (licenseController != nullptr)
  148. licenseController->startWebviewIfNeeded();
  149. #if JUCE_MAC
  150. PopupMenu extraAppleMenuItems;
  151. createExtraAppleMenuItems (extraAppleMenuItems);
  152. // workaround broken "Open Recent" submenu: not passing the
  153. // submenu's title here avoids the defect in JuceMainMenuHandler::addMenuItem
  154. MenuBarModel::setMacMainMenu (menuModel, &extraAppleMenuItems); //, "Open Recent");
  155. #endif
  156. versionChecker = new LatestVersionChecker();
  157. }
  158. void ProjucerApplication::initialiseWindows (const String& commandLine)
  159. {
  160. const String commandLineWithoutNSDebug (commandLine.replace ("-NSDocumentRevisionsDebugMode YES", StringRef()));
  161. if (commandLineWithoutNSDebug.trim().isNotEmpty() && ! commandLineWithoutNSDebug.trim().startsWithChar ('-'))
  162. anotherInstanceStarted (commandLine);
  163. else
  164. mainWindowList.reopenLastProjects();
  165. mainWindowList.createWindowIfNoneAreOpen();
  166. if (licenseController->getState().applicationUsageDataState == LicenseState::ApplicationUsageData::notChosenYet)
  167. showApplicationUsageDataAgreementPopup();
  168. }
  169. void ProjucerApplication::shutdown()
  170. {
  171. if (server != nullptr)
  172. {
  173. destroyClangServer (server);
  174. Logger::writeToLog ("Server shutdown cleanly");
  175. }
  176. versionChecker.reset();
  177. utf8Window.reset();
  178. svgPathWindow.reset();
  179. aboutWindow.reset();
  180. pathsWindow.reset();
  181. editorColourSchemeWindow.reset();
  182. if (licenseController != nullptr)
  183. {
  184. licenseController->removeLicenseStatusChangedCallback (this);
  185. licenseController.reset();
  186. }
  187. mainWindowList.forceCloseAllWindows();
  188. openDocumentManager.clear();
  189. childProcessCache.reset();
  190. #if JUCE_MAC
  191. MenuBarModel::setMacMainMenu (nullptr);
  192. #endif
  193. menuModel.reset();
  194. commandManager.reset();
  195. settings.reset();
  196. LookAndFeel::setDefaultLookAndFeel (nullptr);
  197. if (! isRunningCommandLine)
  198. Logger::writeToLog ("Shutdown");
  199. deleteLogger();
  200. }
  201. struct AsyncQuitRetrier : private Timer
  202. {
  203. AsyncQuitRetrier() { startTimer (500); }
  204. void timerCallback() override
  205. {
  206. stopTimer();
  207. delete this;
  208. if (auto* app = JUCEApplicationBase::getInstance())
  209. app->systemRequestedQuit();
  210. }
  211. JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier)
  212. };
  213. void ProjucerApplication::systemRequestedQuit()
  214. {
  215. if (server != nullptr)
  216. {
  217. sendQuitMessageToIDE (server);
  218. }
  219. else if (ModalComponentManager::getInstance()->cancelAllModalComponents())
  220. {
  221. new AsyncQuitRetrier();
  222. }
  223. else
  224. {
  225. if (closeAllMainWindows())
  226. quit();
  227. }
  228. }
  229. //==============================================================================
  230. void ProjucerApplication::licenseStateChanged (const LicenseState& state)
  231. {
  232. #if ! JUCER_ENABLE_GPL_MODE
  233. if (state.type != LicenseState::Type::notLoggedIn
  234. && state.type != LicenseState::Type::noLicenseChosenYet)
  235. #else
  236. ignoreUnused (state);
  237. #endif
  238. {
  239. initialiseWindows (getCommandLineParameters());
  240. }
  241. }
  242. void ProjucerApplication::doLogout()
  243. {
  244. if (licenseController != nullptr)
  245. {
  246. const LicenseState& state = licenseController->getState();
  247. if (state.type != LicenseState::Type::notLoggedIn && closeAllMainWindows())
  248. licenseController->logout();
  249. }
  250. }
  251. //==============================================================================
  252. String ProjucerApplication::getVersionDescription() const
  253. {
  254. String s;
  255. const Time buildDate (Time::getCompilationDate());
  256. s << "Projucer " << ProjectInfo::versionString
  257. << newLine
  258. << "Build date: " << buildDate.getDayOfMonth()
  259. << " " << Time::getMonthName (buildDate.getMonth(), true)
  260. << " " << buildDate.getYear();
  261. return s;
  262. }
  263. void ProjucerApplication::anotherInstanceStarted (const String& commandLine)
  264. {
  265. if (server == nullptr && ! commandLine.trim().startsWithChar ('-'))
  266. openFile (File (commandLine.unquoted()));
  267. }
  268. ProjucerApplication& ProjucerApplication::getApp()
  269. {
  270. ProjucerApplication* const app = dynamic_cast<ProjucerApplication*> (JUCEApplication::getInstance());
  271. jassert (app != nullptr);
  272. return *app;
  273. }
  274. ApplicationCommandManager& ProjucerApplication::getCommandManager()
  275. {
  276. ApplicationCommandManager* cm = ProjucerApplication::getApp().commandManager;
  277. jassert (cm != nullptr);
  278. return *cm;
  279. }
  280. //==============================================================================
  281. enum
  282. {
  283. recentProjectsBaseID = 100,
  284. activeDocumentsBaseID = 300,
  285. colourSchemeBaseID = 1000,
  286. codeEditorColourSchemeBaseID = 2000,
  287. };
  288. MenuBarModel* ProjucerApplication::getMenuModel()
  289. {
  290. return menuModel.get();
  291. }
  292. StringArray ProjucerApplication::getMenuNames()
  293. {
  294. return { "File", "Edit", "View", "Build", "Window", "GUI Editor", "Tools" };
  295. }
  296. void ProjucerApplication::createMenu (PopupMenu& menu, const String& menuName)
  297. {
  298. if (menuName == "File") createFileMenu (menu);
  299. else if (menuName == "Edit") createEditMenu (menu);
  300. else if (menuName == "View") createViewMenu (menu);
  301. else if (menuName == "Build") createBuildMenu (menu);
  302. else if (menuName == "Window") createWindowMenu (menu);
  303. else if (menuName == "Tools") createToolsMenu (menu);
  304. else if (menuName == "GUI Editor") createGUIEditorMenu (menu);
  305. else jassertfalse; // names have changed?
  306. }
  307. void ProjucerApplication::createFileMenu (PopupMenu& menu)
  308. {
  309. menu.addCommandItem (commandManager, CommandIDs::newProject);
  310. menu.addSeparator();
  311. menu.addCommandItem (commandManager, CommandIDs::open);
  312. PopupMenu recentFiles;
  313. settings->recentFiles.createPopupMenuItems (recentFiles, recentProjectsBaseID, true, true);
  314. menu.addSubMenu ("Open Recent", recentFiles);
  315. menu.addSeparator();
  316. menu.addCommandItem (commandManager, CommandIDs::closeDocument);
  317. menu.addCommandItem (commandManager, CommandIDs::saveDocument);
  318. menu.addCommandItem (commandManager, CommandIDs::saveDocumentAs);
  319. menu.addCommandItem (commandManager, CommandIDs::saveAll);
  320. menu.addSeparator();
  321. menu.addCommandItem (commandManager, CommandIDs::closeProject);
  322. menu.addCommandItem (commandManager, CommandIDs::saveProject);
  323. menu.addSeparator();
  324. menu.addCommandItem (commandManager, CommandIDs::openInIDE);
  325. menu.addCommandItem (commandManager, CommandIDs::saveAndOpenInIDE);
  326. menu.addSeparator();
  327. #if ! JUCER_ENABLE_GPL_MODE
  328. menu.addCommandItem (commandManager, CommandIDs::loginLogout);
  329. #endif
  330. #if ! JUCE_MAC
  331. menu.addCommandItem (commandManager, CommandIDs::showAboutWindow);
  332. menu.addCommandItem (commandManager, CommandIDs::showAppUsageWindow);
  333. menu.addCommandItem (commandManager, CommandIDs::showGlobalPathsWindow);
  334. menu.addSeparator();
  335. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit);
  336. #endif
  337. }
  338. void ProjucerApplication::createEditMenu (PopupMenu& menu)
  339. {
  340. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::undo);
  341. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::redo);
  342. menu.addSeparator();
  343. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
  344. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
  345. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);
  346. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
  347. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::selectAll);
  348. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::deselectAll);
  349. menu.addSeparator();
  350. menu.addCommandItem (commandManager, CommandIDs::showFindPanel);
  351. menu.addCommandItem (commandManager, CommandIDs::findSelection);
  352. menu.addCommandItem (commandManager, CommandIDs::findNext);
  353. menu.addCommandItem (commandManager, CommandIDs::findPrevious);
  354. }
  355. void ProjucerApplication::createViewMenu (PopupMenu& menu)
  356. {
  357. menu.addCommandItem (commandManager, CommandIDs::showProjectSettings);
  358. menu.addCommandItem (commandManager, CommandIDs::showProjectTab);
  359. menu.addCommandItem (commandManager, CommandIDs::showBuildTab);
  360. menu.addCommandItem (commandManager, CommandIDs::showFileExplorerPanel);
  361. menu.addCommandItem (commandManager, CommandIDs::showModulesPanel);
  362. menu.addCommandItem (commandManager, CommandIDs::showExportersPanel);
  363. menu.addCommandItem (commandManager, CommandIDs::showExporterSettings);
  364. menu.addSeparator();
  365. createColourSchemeItems (menu);
  366. }
  367. void ProjucerApplication::createBuildMenu (PopupMenu& menu)
  368. {
  369. menu.addCommandItem (commandManager, CommandIDs::toggleBuildEnabled);
  370. menu.addCommandItem (commandManager, CommandIDs::buildNow);
  371. menu.addCommandItem (commandManager, CommandIDs::toggleContinuousBuild);
  372. menu.addSeparator();
  373. menu.addCommandItem (commandManager, CommandIDs::launchApp);
  374. menu.addCommandItem (commandManager, CommandIDs::killApp);
  375. menu.addCommandItem (commandManager, CommandIDs::cleanAll);
  376. menu.addSeparator();
  377. menu.addCommandItem (commandManager, CommandIDs::reinstantiateComp);
  378. menu.addCommandItem (commandManager, CommandIDs::showWarnings);
  379. menu.addSeparator();
  380. menu.addCommandItem (commandManager, CommandIDs::nextError);
  381. menu.addCommandItem (commandManager, CommandIDs::prevError);
  382. }
  383. void ProjucerApplication::createColourSchemeItems (PopupMenu& menu)
  384. {
  385. PopupMenu colourSchemes;
  386. colourSchemes.addItem (colourSchemeBaseID + 0, "Dark", true, selectedColourSchemeIndex == 0);
  387. colourSchemes.addItem (colourSchemeBaseID + 1, "Grey", true, selectedColourSchemeIndex == 1);
  388. colourSchemes.addItem (colourSchemeBaseID + 2, "Light", true, selectedColourSchemeIndex == 2);
  389. menu.addSubMenu ("Colour Scheme", colourSchemes);
  390. //==========================================================================
  391. PopupMenu editorColourSchemes;
  392. auto& appearanceSettings = getAppSettings().appearance;
  393. appearanceSettings.refreshPresetSchemeList();
  394. auto schemes = appearanceSettings.getPresetSchemes();
  395. auto i = 0;
  396. for (auto s : schemes)
  397. {
  398. editorColourSchemes.addItem (codeEditorColourSchemeBaseID + i, s,
  399. editorColourSchemeWindow == nullptr,
  400. selectedEditorColourSchemeIndex == i);
  401. ++i;
  402. }
  403. numEditorColourSchemes = i;
  404. editorColourSchemes.addSeparator();
  405. editorColourSchemes.addItem (codeEditorColourSchemeBaseID + numEditorColourSchemes,
  406. "Create...", editorColourSchemeWindow == nullptr);
  407. menu.addSubMenu ("Editor Colour Scheme", editorColourSchemes);
  408. }
  409. void ProjucerApplication::createWindowMenu (PopupMenu& menu)
  410. {
  411. menu.addCommandItem (commandManager, CommandIDs::closeWindow);
  412. menu.addSeparator();
  413. menu.addCommandItem (commandManager, CommandIDs::goToPreviousDoc);
  414. menu.addCommandItem (commandManager, CommandIDs::goToNextDoc);
  415. menu.addCommandItem (commandManager, CommandIDs::goToCounterpart);
  416. menu.addSeparator();
  417. const int numDocs = jmin (50, openDocumentManager.getNumOpenDocuments());
  418. for (int i = 0; i < numDocs; ++i)
  419. {
  420. OpenDocumentManager::Document* doc = openDocumentManager.getOpenDocument(i);
  421. menu.addItem (activeDocumentsBaseID + i, doc->getName());
  422. }
  423. menu.addSeparator();
  424. menu.addCommandItem (commandManager, CommandIDs::closeAllDocuments);
  425. }
  426. void ProjucerApplication::createToolsMenu (PopupMenu& menu)
  427. {
  428. menu.addCommandItem (commandManager, CommandIDs::showUTF8Tool);
  429. menu.addCommandItem (commandManager, CommandIDs::showSVGPathTool);
  430. menu.addCommandItem (commandManager, CommandIDs::showTranslationTool);
  431. }
  432. void ProjucerApplication::createExtraAppleMenuItems (PopupMenu& menu)
  433. {
  434. menu.addCommandItem (commandManager, CommandIDs::showAboutWindow);
  435. menu.addCommandItem (commandManager, CommandIDs::showAppUsageWindow);
  436. menu.addSeparator();
  437. menu.addCommandItem (commandManager, CommandIDs::showGlobalPathsWindow);
  438. }
  439. void ProjucerApplication::handleMainMenuCommand (int menuItemID)
  440. {
  441. if (menuItemID >= recentProjectsBaseID && menuItemID < (recentProjectsBaseID + 100))
  442. {
  443. // open a file from the "recent files" menu
  444. openFile (settings->recentFiles.getFile (menuItemID - recentProjectsBaseID));
  445. }
  446. else if (menuItemID >= activeDocumentsBaseID && menuItemID < (activeDocumentsBaseID + 200))
  447. {
  448. if (OpenDocumentManager::Document* doc = openDocumentManager.getOpenDocument (menuItemID - activeDocumentsBaseID))
  449. mainWindowList.openDocument (doc, true);
  450. else
  451. jassertfalse;
  452. }
  453. else if (menuItemID >= colourSchemeBaseID && menuItemID < (colourSchemeBaseID + 3))
  454. {
  455. setColourScheme (menuItemID - colourSchemeBaseID, true);
  456. updateEditorColourSchemeIfNeeded();
  457. }
  458. else if (menuItemID >= codeEditorColourSchemeBaseID && menuItemID < (codeEditorColourSchemeBaseID + numEditorColourSchemes))
  459. {
  460. setEditorColourScheme (menuItemID - codeEditorColourSchemeBaseID, true);
  461. }
  462. else if (menuItemID == (codeEditorColourSchemeBaseID + numEditorColourSchemes))
  463. {
  464. showEditorColourSchemeWindow();
  465. }
  466. else
  467. {
  468. handleGUIEditorMenuCommand (menuItemID);
  469. }
  470. }
  471. //==============================================================================
  472. void ProjucerApplication::getAllCommands (Array <CommandID>& commands)
  473. {
  474. JUCEApplication::getAllCommands (commands);
  475. const CommandID ids[] = { CommandIDs::newProject,
  476. CommandIDs::open,
  477. CommandIDs::closeAllDocuments,
  478. CommandIDs::saveAll,
  479. CommandIDs::showGlobalPathsWindow,
  480. CommandIDs::showUTF8Tool,
  481. CommandIDs::showSVGPathTool,
  482. CommandIDs::showAboutWindow,
  483. CommandIDs::showAppUsageWindow,
  484. CommandIDs::loginLogout };
  485. commands.addArray (ids, numElementsInArray (ids));
  486. }
  487. void ProjucerApplication::getCommandInfo (CommandID commandID, ApplicationCommandInfo& result)
  488. {
  489. switch (commandID)
  490. {
  491. case CommandIDs::newProject:
  492. result.setInfo ("New Project...", "Creates a new Jucer project", CommandCategories::general, 0);
  493. result.defaultKeypresses.add (KeyPress ('n', ModifierKeys::commandModifier, 0));
  494. break;
  495. case CommandIDs::open:
  496. result.setInfo ("Open...", "Opens a Jucer project", CommandCategories::general, 0);
  497. result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
  498. break;
  499. case CommandIDs::showGlobalPathsWindow:
  500. result.setInfo ("Global Search Paths...",
  501. "Shows the window to change the global search paths.",
  502. CommandCategories::general, 0);
  503. break;
  504. case CommandIDs::closeAllDocuments:
  505. result.setInfo ("Close All Documents", "Closes all open documents", CommandCategories::general, 0);
  506. result.setActive (openDocumentManager.getNumOpenDocuments() > 0);
  507. break;
  508. case CommandIDs::saveAll:
  509. result.setInfo ("Save All", "Saves all open documents", CommandCategories::general, 0);
  510. result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier | ModifierKeys::altModifier, 0));
  511. break;
  512. case CommandIDs::showUTF8Tool:
  513. result.setInfo ("UTF-8 String-Literal Helper", "Shows the UTF-8 string literal utility", CommandCategories::general, 0);
  514. break;
  515. case CommandIDs::showSVGPathTool:
  516. result.setInfo ("SVG Path Converter", "Shows the SVG->Path data conversion utility", CommandCategories::general, 0);
  517. break;
  518. case CommandIDs::showAboutWindow:
  519. result.setInfo ("About Projucer", "Shows the Projucer's 'About' page.", CommandCategories::general, 0);
  520. break;
  521. case CommandIDs::showAppUsageWindow:
  522. result.setInfo ("Application Usage Data", "Shows the application usage data agreement window", CommandCategories::general, 0);
  523. break;
  524. case CommandIDs::loginLogout:
  525. {
  526. bool isLoggedIn = false;
  527. String username;
  528. if (licenseController != nullptr)
  529. {
  530. const LicenseState state = licenseController->getState();
  531. isLoggedIn = (state.type != LicenseState::Type::notLoggedIn && state.type != LicenseState::Type::GPL);
  532. username = state.username;
  533. }
  534. result.setInfo (isLoggedIn
  535. ? String ("Sign out ") + username + "..."
  536. : String ("Sign in..."),
  537. "Log out of your JUCE account", CommandCategories::general, 0);
  538. }
  539. break;
  540. default:
  541. JUCEApplication::getCommandInfo (commandID, result);
  542. break;
  543. }
  544. }
  545. bool ProjucerApplication::perform (const InvocationInfo& info)
  546. {
  547. switch (info.commandID)
  548. {
  549. case CommandIDs::newProject: createNewProject(); break;
  550. case CommandIDs::open: askUserToOpenFile(); break;
  551. case CommandIDs::saveAll: openDocumentManager.saveAll(); break;
  552. case CommandIDs::closeAllDocuments: closeAllDocuments (true); break;
  553. case CommandIDs::showUTF8Tool: showUTF8ToolWindow(); break;
  554. case CommandIDs::showSVGPathTool: showSVGPathDataToolWindow(); break;
  555. case CommandIDs::showGlobalPathsWindow: showPathsWindow(); break;
  556. case CommandIDs::showAboutWindow: showAboutWindow(); break;
  557. case CommandIDs::showAppUsageWindow: showApplicationUsageDataAgreementPopup(); break;
  558. case CommandIDs::loginLogout: doLogout(); break;
  559. default: return JUCEApplication::perform (info);
  560. }
  561. return true;
  562. }
  563. //==============================================================================
  564. void ProjucerApplication::createNewProject()
  565. {
  566. MainWindow* mw = mainWindowList.getOrCreateEmptyWindow();
  567. mw->showNewProjectWizard();
  568. mainWindowList.avoidSuperimposedWindows (mw);
  569. }
  570. void ProjucerApplication::updateNewlyOpenedProject (Project& p)
  571. {
  572. LiveBuildProjectSettings::updateNewlyOpenedProject (p);
  573. }
  574. void ProjucerApplication::askUserToOpenFile()
  575. {
  576. FileChooser fc ("Open File");
  577. if (fc.browseForFileToOpen())
  578. openFile (fc.getResult());
  579. }
  580. bool ProjucerApplication::openFile (const File& file)
  581. {
  582. return mainWindowList.openFile (file);
  583. }
  584. bool ProjucerApplication::closeAllDocuments (bool askUserToSave)
  585. {
  586. return openDocumentManager.closeAll (askUserToSave);
  587. }
  588. bool ProjucerApplication::closeAllMainWindows()
  589. {
  590. return server != nullptr || mainWindowList.askAllWindowsToClose();
  591. }
  592. //==============================================================================
  593. void ProjucerApplication::showUTF8ToolWindow()
  594. {
  595. if (utf8Window != nullptr)
  596. utf8Window->toFront (true);
  597. else
  598. new FloatingToolWindow ("UTF-8 String Literal Converter",
  599. "utf8WindowPos",
  600. new UTF8Component(), utf8Window, true,
  601. 500, 500, 300, 300, 1000, 1000);
  602. }
  603. void ProjucerApplication::showSVGPathDataToolWindow()
  604. {
  605. if (svgPathWindow != nullptr)
  606. svgPathWindow->toFront (true);
  607. else
  608. new FloatingToolWindow ("SVG Path Converter",
  609. "svgPathWindowPos",
  610. new SVGPathDataComponent(), svgPathWindow, true,
  611. 500, 500, 300, 300, 1000, 1000);
  612. }
  613. void ProjucerApplication::showAboutWindow()
  614. {
  615. if (aboutWindow != nullptr)
  616. aboutWindow->toFront (true);
  617. else
  618. new FloatingToolWindow ({}, {}, new AboutWindowComponent(),
  619. aboutWindow, false,
  620. 500, 300, 500, 300, 500, 300);
  621. }
  622. void ProjucerApplication::showApplicationUsageDataAgreementPopup()
  623. {
  624. if (applicationUsageDataWindow != nullptr)
  625. applicationUsageDataWindow->toFront (true);
  626. else
  627. new FloatingToolWindow ("Application Usage Analytics",
  628. {}, new ApplicationUsageDataWindowComponent (isPaidOrGPL()),
  629. applicationUsageDataWindow, false,
  630. 400, 300, 400, 300, 400, 300);
  631. }
  632. void ProjucerApplication::dismissApplicationUsageDataAgreementPopup()
  633. {
  634. if (applicationUsageDataWindow != nullptr)
  635. applicationUsageDataWindow.reset();
  636. }
  637. void ProjucerApplication::showPathsWindow()
  638. {
  639. if (pathsWindow != nullptr)
  640. pathsWindow->toFront (true);
  641. else
  642. new FloatingToolWindow ("Global Search Paths",
  643. "pathsWindowPos",
  644. new GlobalSearchPathsWindowComponent(), pathsWindow, false,
  645. 600, 500, 600, 500, 600, 500);
  646. }
  647. void ProjucerApplication::showEditorColourSchemeWindow()
  648. {
  649. if (editorColourSchemeWindow != nullptr)
  650. editorColourSchemeWindow->toFront (true);
  651. else
  652. {
  653. new FloatingToolWindow ("Editor Colour Scheme",
  654. "editorColourSchemeWindowPos",
  655. new EditorColourSchemeWindowComponent(),
  656. editorColourSchemeWindow,
  657. false,
  658. 500, 500, 500, 500, 500, 500);
  659. }
  660. }
  661. //==============================================================================
  662. struct FileWithTime
  663. {
  664. FileWithTime (const File& f) : file (f), time (f.getLastModificationTime()) {}
  665. FileWithTime() {}
  666. bool operator< (const FileWithTime& other) const { return time < other.time; }
  667. bool operator== (const FileWithTime& other) const { return time == other.time; }
  668. File file;
  669. Time time;
  670. };
  671. void ProjucerApplication::deleteLogger()
  672. {
  673. const int maxNumLogFilesToKeep = 50;
  674. Logger::setCurrentLogger (nullptr);
  675. if (logger != nullptr)
  676. {
  677. Array<File> logFiles;
  678. logger->getLogFile().getParentDirectory().findChildFiles (logFiles, File::findFiles, false);
  679. if (logFiles.size() > maxNumLogFilesToKeep)
  680. {
  681. Array <FileWithTime> files;
  682. for (int i = 0; i < logFiles.size(); ++i)
  683. files.addUsingDefaultSort (logFiles.getReference(i));
  684. for (int i = 0; i < files.size() - maxNumLogFilesToKeep; ++i)
  685. files.getReference(i).file.deleteFile();
  686. }
  687. }
  688. logger.reset();
  689. }
  690. PropertiesFile::Options ProjucerApplication::getPropertyFileOptionsFor (const String& filename, bool isProjectSettings)
  691. {
  692. PropertiesFile::Options options;
  693. options.applicationName = filename;
  694. options.filenameSuffix = "settings";
  695. options.osxLibrarySubFolder = "Application Support";
  696. #if JUCE_LINUX
  697. options.folderName = "~/.config/Projucer";
  698. #else
  699. options.folderName = "Projucer";
  700. #endif
  701. if (isProjectSettings)
  702. options.folderName += "/ProjectSettings";
  703. return options;
  704. }
  705. void ProjucerApplication::updateAllBuildTabs()
  706. {
  707. for (int i = 0; i < mainWindowList.windows.size(); ++i)
  708. if (ProjectContentComponent* p = mainWindowList.windows.getUnchecked(i)->getProjectContentComponent())
  709. p->rebuildProjectTabs();
  710. }
  711. void ProjucerApplication::initCommandManager()
  712. {
  713. commandManager = new ApplicationCommandManager();
  714. commandManager->registerAllCommandsForTarget (this);
  715. {
  716. CodeDocument doc;
  717. CppCodeEditorComponent ed (File(), doc);
  718. commandManager->registerAllCommandsForTarget (&ed);
  719. }
  720. registerGUIEditorCommands();
  721. }
  722. void ProjucerApplication::selectEditorColourSchemeWithName (const String& schemeName)
  723. {
  724. auto& appearanceSettings = getAppSettings().appearance;
  725. auto schemes = appearanceSettings.getPresetSchemes();
  726. auto schemeIndex = schemes.indexOf (schemeName);
  727. if (schemeIndex >= 0)
  728. setEditorColourScheme (schemeIndex, true);
  729. }
  730. void ProjucerApplication::setColourScheme (int index, bool saveSetting)
  731. {
  732. switch (index)
  733. {
  734. case 0: lookAndFeel.setColourScheme (LookAndFeel_V4::getDarkColourScheme()); break;
  735. case 1: lookAndFeel.setColourScheme (LookAndFeel_V4::getGreyColourScheme()); break;
  736. case 2: lookAndFeel.setColourScheme (LookAndFeel_V4::getLightColourScheme()); break;
  737. default: break;
  738. }
  739. lookAndFeel.setupColours();
  740. mainWindowList.sendLookAndFeelChange();
  741. if (utf8Window != nullptr) utf8Window->sendLookAndFeelChange();
  742. if (svgPathWindow != nullptr) svgPathWindow->sendLookAndFeelChange();
  743. if (aboutWindow != nullptr) aboutWindow->sendLookAndFeelChange();
  744. if (applicationUsageDataWindow != nullptr) applicationUsageDataWindow->sendLookAndFeelChange();
  745. if (pathsWindow != nullptr) pathsWindow->sendLookAndFeelChange();
  746. if (editorColourSchemeWindow != nullptr) editorColourSchemeWindow->sendLookAndFeelChange();
  747. auto* mcm = ModalComponentManager::getInstance();
  748. for (auto i = 0; i < mcm->getNumModalComponents(); ++i)
  749. mcm->getModalComponent (i)->sendLookAndFeelChange();
  750. if (saveSetting)
  751. {
  752. auto& properties = settings->getGlobalProperties();
  753. properties.setValue ("COLOUR SCHEME", index);
  754. }
  755. selectedColourSchemeIndex = index;
  756. getCommandManager().commandStatusChanged();
  757. }
  758. void ProjucerApplication::setEditorColourScheme (int index, bool saveSetting)
  759. {
  760. auto& appearanceSettings = getAppSettings().appearance;
  761. auto schemes = appearanceSettings.getPresetSchemes();
  762. index = jmin (index, schemes.size() - 1);
  763. appearanceSettings.selectPresetScheme (index);
  764. if (saveSetting)
  765. {
  766. auto& properties = settings->getGlobalProperties();
  767. properties.setValue ("EDITOR COLOUR SCHEME", index);
  768. }
  769. selectedEditorColourSchemeIndex = index;
  770. getCommandManager().commandStatusChanged();
  771. }
  772. bool ProjucerApplication::isEditorColourSchemeADefaultScheme (const StringArray& schemes, int editorColourSchemeIndex)
  773. {
  774. auto& schemeName = schemes[editorColourSchemeIndex];
  775. return (schemeName == "Default (Dark)" || schemeName == "Default (Light)");
  776. }
  777. int ProjucerApplication::getEditorColourSchemeForGUIColourScheme (const StringArray& schemes, int guiColourSchemeIndex)
  778. {
  779. auto defaultDarkEditorIndex = schemes.indexOf ("Default (Dark)");
  780. auto defaultLightEditorIndex = schemes.indexOf ("Default (Light)");
  781. // Can't find default code editor colour schemes!
  782. jassert (defaultDarkEditorIndex != -1 && defaultLightEditorIndex != -1);
  783. return (guiColourSchemeIndex == 2 ? defaultLightEditorIndex : defaultDarkEditorIndex);
  784. }
  785. void ProjucerApplication::updateEditorColourSchemeIfNeeded()
  786. {
  787. auto& appearanceSettings = getAppSettings().appearance;
  788. auto schemes = appearanceSettings.getPresetSchemes();
  789. if (isEditorColourSchemeADefaultScheme (schemes, selectedEditorColourSchemeIndex))
  790. setEditorColourScheme (getEditorColourSchemeForGUIColourScheme (schemes, selectedColourSchemeIndex), true);
  791. }