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.

842 lines
28KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. void createGUIEditorMenu (PopupMenu&);
  18. void handleGUIEditorMenuCommand (int);
  19. void registerGUIEditorCommands();
  20. //==============================================================================
  21. struct ProjucerApplication::MainMenuModel : public MenuBarModel
  22. {
  23. MainMenuModel()
  24. {
  25. setApplicationCommandManagerToWatch (&getCommandManager());
  26. }
  27. StringArray getMenuBarNames() override
  28. {
  29. return getApp().getMenuNames();
  30. }
  31. PopupMenu getMenuForIndex (int /*topLevelMenuIndex*/, const String& menuName) override
  32. {
  33. PopupMenu menu;
  34. getApp().createMenu (menu, menuName);
  35. return menu;
  36. }
  37. void menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/) override
  38. {
  39. getApp().handleMainMenuCommand (menuItemID);
  40. }
  41. };
  42. //==============================================================================
  43. ProjucerApplication::ProjucerApplication() : isRunningCommandLine (false)
  44. {
  45. }
  46. void ProjucerApplication::initialise (const String& commandLine)
  47. {
  48. if (commandLine.trimStart().startsWith ("--server"))
  49. {
  50. initialiseLogger ("Compiler_Log_");
  51. LookAndFeel::setDefaultLookAndFeel (&lookAndFeel);
  52. #if JUCE_MAC
  53. Process::setDockIconVisible (false);
  54. #endif
  55. server = createClangServer (commandLine);
  56. }
  57. else
  58. {
  59. initialiseLogger ("IDE_Log_");
  60. Logger::writeToLog (SystemStats::getOperatingSystemName());
  61. Logger::writeToLog ("CPU: " + String (SystemStats::getCpuSpeedInMegaherz())
  62. + "MHz Cores: " + String (SystemStats::getNumCpus())
  63. + " " + String (SystemStats::getMemorySizeInMegabytes()) + "MB");
  64. initialiseBasics();
  65. if (commandLine.isNotEmpty())
  66. {
  67. isRunningCommandLine = true;
  68. const int appReturnCode = performCommandLine (commandLine);
  69. if (appReturnCode != commandLineNotPerformed)
  70. {
  71. setApplicationReturnValue (appReturnCode);
  72. quit();
  73. return;
  74. }
  75. isRunningCommandLine = false;
  76. }
  77. if (sendCommandLineToPreexistingInstance())
  78. {
  79. DBG ("Another instance is running - quitting...");
  80. quit();
  81. return;
  82. }
  83. openDocumentManager.registerType (new ProjucerAppClasses::LiveBuildCodeEditorDocument::Type(), 2);
  84. if (! checkEULA())
  85. {
  86. quit();
  87. return;
  88. }
  89. childProcessCache = new ChildProcessCache();
  90. initCommandManager();
  91. menuModel = new MainMenuModel();
  92. settings->appearance.refreshPresetSchemeList();
  93. // do further initialisation in a moment when the message loop has started
  94. triggerAsyncUpdate();
  95. }
  96. }
  97. void ProjucerApplication::initialiseBasics()
  98. {
  99. LookAndFeel::setDefaultLookAndFeel (&lookAndFeel);
  100. settings = new StoredSettings();
  101. ImageCache::setCacheTimeout (30 * 1000);
  102. icons = new Icons();
  103. }
  104. bool ProjucerApplication::initialiseLogger (const char* filePrefix)
  105. {
  106. if (logger == nullptr)
  107. {
  108. #if JUCE_LINUX
  109. String folder = "~/.config/Projucer/Logs";
  110. #else
  111. String folder = "com.juce.projucer";
  112. #endif
  113. logger = FileLogger::createDateStampedLogger (folder, filePrefix, ".txt",
  114. getApplicationName() + " " + getApplicationVersion()
  115. + " --- Build date: " __DATE__);
  116. Logger::setCurrentLogger (logger);
  117. }
  118. return logger != nullptr;
  119. }
  120. void ProjucerApplication::handleAsyncUpdate()
  121. {
  122. initialiseWindows (getCommandLineParameters());
  123. #if JUCE_MAC
  124. PopupMenu extraAppleMenuItems;
  125. createExtraAppleMenuItems (extraAppleMenuItems);
  126. // workaround broken "Open Recent" submenu: not passing the
  127. // submenu's title here avoids the defect in JuceMainMenuHandler::addMenuItem
  128. MenuBarModel::setMacMainMenu (menuModel, &extraAppleMenuItems); //, "Open Recent");
  129. #endif
  130. versionChecker = new LatestVersionChecker();
  131. showLoginFormAsyncIfNotTriedRecently();
  132. }
  133. void ProjucerApplication::initialiseWindows (const String& commandLine)
  134. {
  135. const String commandLineWithoutNSDebug (commandLine.replace ("-NSDocumentRevisionsDebugMode YES", StringRef()));
  136. if (commandLineWithoutNSDebug.trim().isNotEmpty() && ! commandLineWithoutNSDebug.trim().startsWithChar ('-'))
  137. anotherInstanceStarted (commandLine);
  138. else
  139. mainWindowList.reopenLastProjects();
  140. mainWindowList.createWindowIfNoneAreOpen();
  141. }
  142. void ProjucerApplication::shutdown()
  143. {
  144. if (server != nullptr)
  145. {
  146. destroyClangServer (server);
  147. Logger::writeToLog ("Server shutdown cleanly");
  148. }
  149. versionChecker = nullptr;
  150. appearanceEditorWindow = nullptr;
  151. globalPreferencesWindow = nullptr;
  152. utf8Window = nullptr;
  153. svgPathWindow = nullptr;
  154. mainWindowList.forceCloseAllWindows();
  155. openDocumentManager.clear();
  156. childProcessCache = nullptr;
  157. #if JUCE_MAC
  158. MenuBarModel::setMacMainMenu (nullptr);
  159. #endif
  160. menuModel = nullptr;
  161. commandManager = nullptr;
  162. settings = nullptr;
  163. LookAndFeel::setDefaultLookAndFeel (nullptr);
  164. if (! isRunningCommandLine)
  165. Logger::writeToLog ("Shutdown");
  166. deleteLogger();
  167. }
  168. struct AsyncQuitRetrier : private Timer
  169. {
  170. AsyncQuitRetrier() { startTimer (500); }
  171. void timerCallback() override
  172. {
  173. stopTimer();
  174. delete this;
  175. if (JUCEApplicationBase* app = JUCEApplicationBase::getInstance())
  176. app->systemRequestedQuit();
  177. }
  178. JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier)
  179. };
  180. void ProjucerApplication::systemRequestedQuit()
  181. {
  182. if (server != nullptr)
  183. {
  184. sendQuitMessageToIDE (server);
  185. }
  186. else if (ModalComponentManager::getInstance()->cancelAllModalComponents())
  187. {
  188. new AsyncQuitRetrier();
  189. }
  190. else
  191. {
  192. if (closeAllMainWindows())
  193. quit();
  194. }
  195. }
  196. //==============================================================================
  197. String ProjucerApplication::getVersionDescription() const
  198. {
  199. String s;
  200. const Time buildDate (Time::getCompilationDate());
  201. s << "Projucer " << ProjectInfo::versionString
  202. << newLine
  203. << "Build date: " << buildDate.getDayOfMonth()
  204. << " " << Time::getMonthName (buildDate.getMonth(), true)
  205. << " " << buildDate.getYear();
  206. return s;
  207. }
  208. void ProjucerApplication::anotherInstanceStarted (const String& commandLine)
  209. {
  210. if (server == nullptr && ! commandLine.trim().startsWithChar ('-'))
  211. openFile (File (commandLine.unquoted()));
  212. }
  213. ProjucerApplication& ProjucerApplication::getApp()
  214. {
  215. ProjucerApplication* const app = dynamic_cast<ProjucerApplication*> (JUCEApplication::getInstance());
  216. jassert (app != nullptr);
  217. return *app;
  218. }
  219. ApplicationCommandManager& ProjucerApplication::getCommandManager()
  220. {
  221. ApplicationCommandManager* cm = ProjucerApplication::getApp().commandManager;
  222. jassert (cm != nullptr);
  223. return *cm;
  224. }
  225. //==============================================================================
  226. enum
  227. {
  228. recentProjectsBaseID = 100,
  229. activeDocumentsBaseID = 300,
  230. colourSchemeBaseID = 1000
  231. };
  232. MenuBarModel* ProjucerApplication::getMenuModel()
  233. {
  234. return menuModel.get();
  235. }
  236. StringArray ProjucerApplication::getMenuNames()
  237. {
  238. const char* const names[] = { "File", "Edit", "View", "Build", "Window", "GUI Editor", "Tools", nullptr };
  239. return StringArray (names);
  240. }
  241. void ProjucerApplication::createMenu (PopupMenu& menu, const String& menuName)
  242. {
  243. if (menuName == "File") createFileMenu (menu);
  244. else if (menuName == "Edit") createEditMenu (menu);
  245. else if (menuName == "View") createViewMenu (menu);
  246. else if (menuName == "Build") createBuildMenu (menu);
  247. else if (menuName == "Window") createWindowMenu (menu);
  248. else if (menuName == "Tools") createToolsMenu (menu);
  249. else if (menuName == "GUI Editor") createGUIEditorMenu (menu);
  250. else jassertfalse; // names have changed?
  251. }
  252. void ProjucerApplication::createFileMenu (PopupMenu& menu)
  253. {
  254. menu.addCommandItem (commandManager, CommandIDs::newProject);
  255. menu.addSeparator();
  256. menu.addCommandItem (commandManager, CommandIDs::open);
  257. PopupMenu recentFiles;
  258. settings->recentFiles.createPopupMenuItems (recentFiles, recentProjectsBaseID, true, true);
  259. menu.addSubMenu ("Open Recent", recentFiles);
  260. menu.addSeparator();
  261. menu.addCommandItem (commandManager, CommandIDs::closeDocument);
  262. menu.addCommandItem (commandManager, CommandIDs::saveDocument);
  263. menu.addCommandItem (commandManager, CommandIDs::saveDocumentAs);
  264. menu.addCommandItem (commandManager, CommandIDs::saveAll);
  265. menu.addSeparator();
  266. menu.addCommandItem (commandManager, CommandIDs::closeProject);
  267. menu.addCommandItem (commandManager, CommandIDs::saveProject);
  268. menu.addSeparator();
  269. menu.addCommandItem (commandManager, CommandIDs::openInIDE);
  270. menu.addCommandItem (commandManager, CommandIDs::saveAndOpenInIDE);
  271. menu.addSeparator();
  272. menu.addCommandItem (commandManager, CommandIDs::loginLogout);
  273. #if ! JUCE_MAC
  274. menu.addCommandItem (commandManager, CommandIDs::showGlobalPreferences);
  275. menu.addSeparator();
  276. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit);
  277. #endif
  278. }
  279. void ProjucerApplication::createEditMenu (PopupMenu& menu)
  280. {
  281. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::undo);
  282. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::redo);
  283. menu.addSeparator();
  284. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
  285. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
  286. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);
  287. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
  288. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::selectAll);
  289. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::deselectAll);
  290. menu.addSeparator();
  291. menu.addCommandItem (commandManager, CommandIDs::showFindPanel);
  292. menu.addCommandItem (commandManager, CommandIDs::findSelection);
  293. menu.addCommandItem (commandManager, CommandIDs::findNext);
  294. menu.addCommandItem (commandManager, CommandIDs::findPrevious);
  295. }
  296. void ProjucerApplication::createViewMenu (PopupMenu& menu)
  297. {
  298. menu.addCommandItem (commandManager, CommandIDs::showFilePanel);
  299. menu.addCommandItem (commandManager, CommandIDs::showConfigPanel);
  300. menu.addCommandItem (commandManager, CommandIDs::showBuildTab);
  301. menu.addCommandItem (commandManager, CommandIDs::showProjectSettings);
  302. menu.addCommandItem (commandManager, CommandIDs::showProjectModules);
  303. menu.addSeparator();
  304. createColourSchemeItems (menu);
  305. }
  306. void ProjucerApplication::createBuildMenu (PopupMenu& menu)
  307. {
  308. menu.addCommandItem (commandManager, CommandIDs::enableBuild);
  309. menu.addCommandItem (commandManager, CommandIDs::toggleContinuousBuild);
  310. menu.addCommandItem (commandManager, CommandIDs::buildNow);
  311. menu.addSeparator();
  312. menu.addCommandItem (commandManager, CommandIDs::launchApp);
  313. menu.addCommandItem (commandManager, CommandIDs::killApp);
  314. menu.addCommandItem (commandManager, CommandIDs::cleanAll);
  315. menu.addSeparator();
  316. menu.addCommandItem (commandManager, CommandIDs::reinstantiateComp);
  317. menu.addCommandItem (commandManager, CommandIDs::showWarnings);
  318. menu.addSeparator();
  319. menu.addCommandItem (commandManager, CommandIDs::nextError);
  320. menu.addCommandItem (commandManager, CommandIDs::prevError);
  321. }
  322. void ProjucerApplication::createColourSchemeItems (PopupMenu& menu)
  323. {
  324. const StringArray presetSchemes (settings->appearance.getPresetSchemes());
  325. if (presetSchemes.size() > 0)
  326. {
  327. PopupMenu schemes;
  328. for (int i = 0; i < presetSchemes.size(); ++i)
  329. schemes.addItem (colourSchemeBaseID + i, presetSchemes[i]);
  330. menu.addSubMenu ("Colour Scheme", schemes);
  331. }
  332. }
  333. void ProjucerApplication::createWindowMenu (PopupMenu& menu)
  334. {
  335. menu.addCommandItem (commandManager, CommandIDs::closeWindow);
  336. menu.addSeparator();
  337. menu.addCommandItem (commandManager, CommandIDs::goToPreviousDoc);
  338. menu.addCommandItem (commandManager, CommandIDs::goToNextDoc);
  339. menu.addCommandItem (commandManager, CommandIDs::goToCounterpart);
  340. menu.addSeparator();
  341. const int numDocs = jmin (50, openDocumentManager.getNumOpenDocuments());
  342. for (int i = 0; i < numDocs; ++i)
  343. {
  344. OpenDocumentManager::Document* doc = openDocumentManager.getOpenDocument(i);
  345. menu.addItem (activeDocumentsBaseID + i, doc->getName());
  346. }
  347. menu.addSeparator();
  348. menu.addCommandItem (commandManager, CommandIDs::closeAllDocuments);
  349. }
  350. void ProjucerApplication::createToolsMenu (PopupMenu& menu)
  351. {
  352. menu.addCommandItem (commandManager, CommandIDs::showUTF8Tool);
  353. menu.addCommandItem (commandManager, CommandIDs::showSVGPathTool);
  354. menu.addCommandItem (commandManager, CommandIDs::showTranslationTool);
  355. }
  356. void ProjucerApplication::createExtraAppleMenuItems (PopupMenu& menu)
  357. {
  358. menu.addCommandItem (commandManager, CommandIDs::showGlobalPreferences);
  359. }
  360. void ProjucerApplication::handleMainMenuCommand (int menuItemID)
  361. {
  362. if (menuItemID >= recentProjectsBaseID && menuItemID < recentProjectsBaseID + 100)
  363. {
  364. // open a file from the "recent files" menu
  365. openFile (settings->recentFiles.getFile (menuItemID - recentProjectsBaseID));
  366. }
  367. else if (menuItemID >= activeDocumentsBaseID && menuItemID < activeDocumentsBaseID + 200)
  368. {
  369. if (OpenDocumentManager::Document* doc = openDocumentManager.getOpenDocument (menuItemID - activeDocumentsBaseID))
  370. mainWindowList.openDocument (doc, true);
  371. else
  372. jassertfalse;
  373. }
  374. else if (menuItemID >= colourSchemeBaseID && menuItemID < colourSchemeBaseID + 200)
  375. {
  376. settings->appearance.selectPresetScheme (menuItemID - colourSchemeBaseID);
  377. }
  378. else
  379. {
  380. handleGUIEditorMenuCommand (menuItemID);
  381. }
  382. }
  383. //==============================================================================
  384. void ProjucerApplication::getAllCommands (Array <CommandID>& commands)
  385. {
  386. JUCEApplication::getAllCommands (commands);
  387. const CommandID ids[] = { CommandIDs::newProject,
  388. CommandIDs::open,
  389. CommandIDs::closeAllDocuments,
  390. CommandIDs::saveAll,
  391. CommandIDs::showGlobalPreferences,
  392. CommandIDs::showUTF8Tool,
  393. CommandIDs::showSVGPathTool,
  394. CommandIDs::loginLogout };
  395. commands.addArray (ids, numElementsInArray (ids));
  396. }
  397. void ProjucerApplication::getCommandInfo (CommandID commandID, ApplicationCommandInfo& result)
  398. {
  399. switch (commandID)
  400. {
  401. case CommandIDs::newProject:
  402. result.setInfo ("New Project...", "Creates a new Jucer project", CommandCategories::general, 0);
  403. result.defaultKeypresses.add (KeyPress ('n', ModifierKeys::commandModifier, 0));
  404. break;
  405. case CommandIDs::open:
  406. result.setInfo ("Open...", "Opens a Jucer project", CommandCategories::general, 0);
  407. result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
  408. break;
  409. case CommandIDs::showGlobalPreferences:
  410. result.setInfo ("Preferences...", "Shows the preferences window.", CommandCategories::general, 0);
  411. result.defaultKeypresses.add (KeyPress (',', ModifierKeys::commandModifier, 0));
  412. break;
  413. case CommandIDs::closeAllDocuments:
  414. result.setInfo ("Close All Documents", "Closes all open documents", CommandCategories::general, 0);
  415. result.setActive (openDocumentManager.getNumOpenDocuments() > 0);
  416. break;
  417. case CommandIDs::saveAll:
  418. result.setInfo ("Save All", "Saves all open documents", CommandCategories::general, 0);
  419. result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier | ModifierKeys::altModifier, 0));
  420. break;
  421. case CommandIDs::showUTF8Tool:
  422. result.setInfo ("UTF-8 String-Literal Helper", "Shows the UTF-8 string literal utility", CommandCategories::general, 0);
  423. break;
  424. case CommandIDs::showSVGPathTool:
  425. result.setInfo ("SVG Path Helper", "Shows the SVG->Path data conversion utility", CommandCategories::general, 0);
  426. break;
  427. case CommandIDs::loginLogout:
  428. result.setInfo (ProjucerLicenses::getInstance()->isLoggedIn()
  429. ? String ("Sign out ") + ProjucerLicenses::getInstance()->getLoginName()
  430. : String ("Sign in..."),
  431. "Log out of your JUCE account", CommandCategories::general, 0);
  432. result.setActive (ProjucerLicenses::getInstance()->isDLLPresent());
  433. break;
  434. default:
  435. JUCEApplication::getCommandInfo (commandID, result);
  436. break;
  437. }
  438. }
  439. bool ProjucerApplication::perform (const InvocationInfo& info)
  440. {
  441. switch (info.commandID)
  442. {
  443. case CommandIDs::newProject: createNewProject(); break;
  444. case CommandIDs::open: askUserToOpenFile(); break;
  445. case CommandIDs::saveAll: openDocumentManager.saveAll(); break;
  446. case CommandIDs::closeAllDocuments: closeAllDocuments (true); break;
  447. case CommandIDs::showUTF8Tool: showUTF8ToolWindow(); break;
  448. case CommandIDs::showSVGPathTool: showSVGPathDataToolWindow(); break;
  449. case CommandIDs::showGlobalPreferences: AppearanceSettings::showGlobalPreferences (globalPreferencesWindow); break;
  450. case CommandIDs::loginLogout: loginOrLogout(); break;
  451. default: return JUCEApplication::perform (info);
  452. }
  453. return true;
  454. }
  455. //==============================================================================
  456. void ProjucerApplication::createNewProject()
  457. {
  458. MainWindow* mw = mainWindowList.getOrCreateEmptyWindow();
  459. mw->showNewProjectWizard();
  460. mainWindowList.avoidSuperimposedWindows (mw);
  461. }
  462. void ProjucerApplication::updateNewlyOpenedProject (Project& p)
  463. {
  464. LiveBuildProjectSettings::updateNewlyOpenedProject (p);
  465. }
  466. void ProjucerApplication::askUserToOpenFile()
  467. {
  468. FileChooser fc ("Open File");
  469. if (fc.browseForFileToOpen())
  470. openFile (fc.getResult());
  471. }
  472. bool ProjucerApplication::openFile (const File& file)
  473. {
  474. return mainWindowList.openFile (file);
  475. }
  476. bool ProjucerApplication::closeAllDocuments (bool askUserToSave)
  477. {
  478. return openDocumentManager.closeAll (askUserToSave);
  479. }
  480. bool ProjucerApplication::closeAllMainWindows()
  481. {
  482. return server != nullptr || mainWindowList.askAllWindowsToClose();
  483. }
  484. //==============================================================================
  485. void ProjucerApplication::showUTF8ToolWindow()
  486. {
  487. if (utf8Window != nullptr)
  488. utf8Window->toFront (true);
  489. else
  490. new FloatingToolWindow ("UTF-8 String Literal Converter",
  491. "utf8WindowPos",
  492. new UTF8Component(), utf8Window,
  493. 500, 500, 300, 300, 1000, 1000);
  494. }
  495. void ProjucerApplication::showSVGPathDataToolWindow()
  496. {
  497. if (svgPathWindow != nullptr)
  498. svgPathWindow->toFront (true);
  499. else
  500. new FloatingToolWindow ("SVG Path Converter",
  501. "svgPathWindowPos",
  502. new SVGPathDataComponent(), svgPathWindow,
  503. 500, 500, 300, 300, 1000, 1000);
  504. }
  505. //==============================================================================
  506. struct FileWithTime
  507. {
  508. FileWithTime (const File& f) : file (f), time (f.getLastModificationTime()) {}
  509. FileWithTime() {}
  510. bool operator< (const FileWithTime& other) const { return time < other.time; }
  511. bool operator== (const FileWithTime& other) const { return time == other.time; }
  512. File file;
  513. Time time;
  514. };
  515. void ProjucerApplication::deleteLogger()
  516. {
  517. const int maxNumLogFilesToKeep = 50;
  518. Logger::setCurrentLogger (nullptr);
  519. if (logger != nullptr)
  520. {
  521. Array<File> logFiles;
  522. logger->getLogFile().getParentDirectory().findChildFiles (logFiles, File::findFiles, false);
  523. if (logFiles.size() > maxNumLogFilesToKeep)
  524. {
  525. Array <FileWithTime> files;
  526. for (int i = 0; i < logFiles.size(); ++i)
  527. files.addUsingDefaultSort (logFiles.getReference(i));
  528. for (int i = 0; i < files.size() - maxNumLogFilesToKeep; ++i)
  529. files.getReference(i).file.deleteFile();
  530. }
  531. }
  532. logger = nullptr;
  533. }
  534. struct LiveBuildConfigItem : public ConfigTreeItemTypes::ConfigTreeItemBase
  535. {
  536. LiveBuildConfigItem (Project& p) : project (p) {}
  537. bool isMissing() override { return false; }
  538. bool canBeSelected() const override { return true; }
  539. bool mightContainSubItems() override { return false; }
  540. String getUniqueName() const override { return "live_build_settings"; }
  541. String getRenamingName() const override { return getDisplayName(); }
  542. String getDisplayName() const override { return "Live Build Settings"; }
  543. void setName (const String&) override {}
  544. Icon getIcon() const override { return Icon (getIcons().config, getContrastingColour (Colours::green, 0.5f)); }
  545. void showDocument() override { showSettingsPage (new SettingsComp (project)); }
  546. void itemOpennessChanged (bool) override {}
  547. Project& project;
  548. //==============================================================================
  549. struct SettingsComp : public Component
  550. {
  551. SettingsComp (Project& p)
  552. {
  553. addAndMakeVisible (&group);
  554. PropertyListBuilder props;
  555. LiveBuildProjectSettings::getLiveSettings (p, props);
  556. group.setProperties (props);
  557. group.setName ("Live Build Settings");
  558. parentSizeChanged();
  559. }
  560. void parentSizeChanged() override { updateSize (*this, group); }
  561. ConfigTreeItemTypes::PropertyGroupComponent group;
  562. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp)
  563. };
  564. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LiveBuildConfigItem)
  565. };
  566. void ProjucerApplication::addLiveBuildConfigItem (Project& project, TreeViewItem& parent)
  567. {
  568. parent.addSubItem (new LiveBuildConfigItem (project));
  569. }
  570. PropertiesFile::Options ProjucerApplication::getPropertyFileOptionsFor (const String& filename)
  571. {
  572. PropertiesFile::Options options;
  573. options.applicationName = filename;
  574. options.filenameSuffix = "settings";
  575. options.osxLibrarySubFolder = "Application Support";
  576. #if JUCE_LINUX
  577. options.folderName = "~/.config/Projucer";
  578. #else
  579. options.folderName = "Projucer";
  580. #endif
  581. return options;
  582. }
  583. void ProjucerApplication::hideLoginForm()
  584. {
  585. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  586. loginForm = nullptr;
  587. }
  588. void ProjucerApplication::showLoginForm()
  589. {
  590. if (ProjucerLicenses::getInstance()->isDLLPresent())
  591. {
  592. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  593. if (loginForm != nullptr)
  594. return;
  595. DialogWindow::LaunchOptions lo;
  596. lo.dialogTitle = "Log-in to Projucer";
  597. lo.dialogBackgroundColour = Colour (0xffdddddd);
  598. lo.content.setOwned (loginForm = new LoginForm());
  599. lo.escapeKeyTriggersCloseButton = true;
  600. lo.componentToCentreAround = nullptr;
  601. lo.escapeKeyTriggersCloseButton = true;
  602. lo.resizable = false;
  603. lo.useBottomRightCornerResizer = false;
  604. lo.useNativeTitleBar = true;
  605. lo.launchAsync();
  606. getGlobalProperties().setValue ("lastLoginAttemptTime",
  607. (int) (Time::getCurrentTime().toMilliseconds() / 1000));
  608. }
  609. }
  610. void ProjucerApplication::showLoginFormAsyncIfNotTriedRecently()
  611. {
  612. if (ProjucerLicenses::getInstance()->isDLLPresent())
  613. {
  614. Time lastLoginAttempt (getGlobalProperties().getValue ("lastLoginAttemptTime").getIntValue() * (int64) 1000);
  615. if (Time::getCurrentTime().getDayOfMonth() != lastLoginAttempt.getDayOfMonth())
  616. startTimer (1000);
  617. }
  618. else
  619. {
  620. getGlobalProperties().removeValue ("lastLoginAttemptTime");
  621. }
  622. }
  623. void ProjucerApplication::timerCallback()
  624. {
  625. stopTimer();
  626. if (! ProjucerLicenses::getInstance()->isLoggedIn())
  627. showLoginForm();
  628. }
  629. void ProjucerApplication::updateAllBuildTabs()
  630. {
  631. for (int i = 0; i < mainWindowList.windows.size(); ++i)
  632. if (ProjectContentComponent* p = mainWindowList.windows.getUnchecked(i)->getProjectContentComponent())
  633. p->rebuildProjectTabs();
  634. }
  635. //==============================================================================
  636. void ProjucerApplication::loginOrLogout()
  637. {
  638. ProjucerLicenses& status = *ProjucerLicenses::getInstance();
  639. if (status.isLoggedIn())
  640. status.logout();
  641. else
  642. showLoginForm();
  643. updateAllBuildTabs();
  644. }
  645. bool ProjucerApplication::checkEULA()
  646. {
  647. if (currentEULAHasBeenAcceptedPreviously()
  648. || ! ProjucerLicenses::getInstance()->isDLLPresent())
  649. return true;
  650. ScopedPointer<AlertWindow> eulaDialogue (new EULADialogue());
  651. bool hasBeenAccepted = (eulaDialogue->runModalLoop() == EULADialogue::accepted);
  652. setCurrentEULAAccepted (hasBeenAccepted);
  653. return hasBeenAccepted;
  654. }
  655. bool ProjucerApplication::currentEULAHasBeenAcceptedPreviously() const
  656. {
  657. return getGlobalProperties().getValue (getEULAChecksumProperty()).getIntValue() != 0;
  658. }
  659. String ProjucerApplication::getEULAChecksumProperty() const
  660. {
  661. return "eulaChecksum_" + MD5 (BinaryData::projucer_EULA_txt,
  662. BinaryData::projucer_EULA_txtSize).toHexString();
  663. }
  664. void ProjucerApplication::setCurrentEULAAccepted (bool hasBeenAccepted) const
  665. {
  666. const String checksum (getEULAChecksumProperty());
  667. auto& globals = getGlobalProperties();
  668. if (hasBeenAccepted)
  669. globals.setValue (checksum, 1);
  670. else
  671. globals.removeValue (checksum);
  672. globals.saveIfNeeded();
  673. }
  674. void ProjucerApplication::initCommandManager()
  675. {
  676. commandManager = new ApplicationCommandManager();
  677. commandManager->registerAllCommandsForTarget (this);
  678. {
  679. CodeDocument doc;
  680. CppCodeEditorComponent ed (File(), doc);
  681. commandManager->registerAllCommandsForTarget (&ed);
  682. }
  683. registerGUIEditorCommands();
  684. }