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.

840 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. MenuBarModel::setMacMainMenu (menuModel, &extraAppleMenuItems, "Open Recent");
  127. #endif
  128. versionChecker = new LatestVersionChecker();
  129. showLoginFormAsyncIfNotTriedRecently();
  130. }
  131. void ProjucerApplication::initialiseWindows (const String& commandLine)
  132. {
  133. const String commandLineWithoutNSDebug (commandLine.replace ("-NSDocumentRevisionsDebugMode YES", StringRef()));
  134. if (commandLineWithoutNSDebug.trim().isNotEmpty() && ! commandLineWithoutNSDebug.trim().startsWithChar ('-'))
  135. anotherInstanceStarted (commandLine);
  136. else
  137. mainWindowList.reopenLastProjects();
  138. mainWindowList.createWindowIfNoneAreOpen();
  139. }
  140. void ProjucerApplication::shutdown()
  141. {
  142. if (server != nullptr)
  143. {
  144. destroyClangServer (server);
  145. Logger::writeToLog ("Server shutdown cleanly");
  146. }
  147. versionChecker = nullptr;
  148. appearanceEditorWindow = nullptr;
  149. globalPreferencesWindow = nullptr;
  150. utf8Window = nullptr;
  151. svgPathWindow = nullptr;
  152. mainWindowList.forceCloseAllWindows();
  153. openDocumentManager.clear();
  154. childProcessCache = nullptr;
  155. #if JUCE_MAC
  156. MenuBarModel::setMacMainMenu (nullptr);
  157. #endif
  158. menuModel = nullptr;
  159. commandManager = nullptr;
  160. settings = nullptr;
  161. LookAndFeel::setDefaultLookAndFeel (nullptr);
  162. if (! isRunningCommandLine)
  163. Logger::writeToLog ("Shutdown");
  164. deleteLogger();
  165. }
  166. struct AsyncQuitRetrier : private Timer
  167. {
  168. AsyncQuitRetrier() { startTimer (500); }
  169. void timerCallback() override
  170. {
  171. stopTimer();
  172. delete this;
  173. if (JUCEApplicationBase* app = JUCEApplicationBase::getInstance())
  174. app->systemRequestedQuit();
  175. }
  176. JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier)
  177. };
  178. void ProjucerApplication::systemRequestedQuit()
  179. {
  180. if (server != nullptr)
  181. {
  182. sendQuitMessageToIDE (server);
  183. }
  184. else if (ModalComponentManager::getInstance()->cancelAllModalComponents())
  185. {
  186. new AsyncQuitRetrier();
  187. }
  188. else
  189. {
  190. if (closeAllMainWindows())
  191. quit();
  192. }
  193. }
  194. //==============================================================================
  195. String ProjucerApplication::getVersionDescription() const
  196. {
  197. String s;
  198. const Time buildDate (Time::getCompilationDate());
  199. s << "Projucer " << ProjectInfo::versionString
  200. << newLine
  201. << "Build date: " << buildDate.getDayOfMonth()
  202. << " " << Time::getMonthName (buildDate.getMonth(), true)
  203. << " " << buildDate.getYear();
  204. return s;
  205. }
  206. void ProjucerApplication::anotherInstanceStarted (const String& commandLine)
  207. {
  208. if (server == nullptr && ! commandLine.trim().startsWithChar ('-'))
  209. openFile (File (commandLine.unquoted()));
  210. }
  211. ProjucerApplication& ProjucerApplication::getApp()
  212. {
  213. ProjucerApplication* const app = dynamic_cast<ProjucerApplication*> (JUCEApplication::getInstance());
  214. jassert (app != nullptr);
  215. return *app;
  216. }
  217. ApplicationCommandManager& ProjucerApplication::getCommandManager()
  218. {
  219. ApplicationCommandManager* cm = ProjucerApplication::getApp().commandManager;
  220. jassert (cm != nullptr);
  221. return *cm;
  222. }
  223. //==============================================================================
  224. enum
  225. {
  226. recentProjectsBaseID = 100,
  227. activeDocumentsBaseID = 300,
  228. colourSchemeBaseID = 1000
  229. };
  230. MenuBarModel* ProjucerApplication::getMenuModel()
  231. {
  232. return menuModel.get();
  233. }
  234. StringArray ProjucerApplication::getMenuNames()
  235. {
  236. const char* const names[] = { "File", "Edit", "View", "Build", "Window", "GUI Editor", "Tools", nullptr };
  237. return StringArray (names);
  238. }
  239. void ProjucerApplication::createMenu (PopupMenu& menu, const String& menuName)
  240. {
  241. if (menuName == "File") createFileMenu (menu);
  242. else if (menuName == "Edit") createEditMenu (menu);
  243. else if (menuName == "View") createViewMenu (menu);
  244. else if (menuName == "Build") createBuildMenu (menu);
  245. else if (menuName == "Window") createWindowMenu (menu);
  246. else if (menuName == "Tools") createToolsMenu (menu);
  247. else if (menuName == "GUI Editor") createGUIEditorMenu (menu);
  248. else jassertfalse; // names have changed?
  249. }
  250. void ProjucerApplication::createFileMenu (PopupMenu& menu)
  251. {
  252. menu.addCommandItem (commandManager, CommandIDs::newProject);
  253. menu.addSeparator();
  254. menu.addCommandItem (commandManager, CommandIDs::open);
  255. PopupMenu recentFiles;
  256. settings->recentFiles.createPopupMenuItems (recentFiles, recentProjectsBaseID, true, true);
  257. menu.addSubMenu ("Open Recent", recentFiles);
  258. menu.addSeparator();
  259. menu.addCommandItem (commandManager, CommandIDs::closeDocument);
  260. menu.addCommandItem (commandManager, CommandIDs::saveDocument);
  261. menu.addCommandItem (commandManager, CommandIDs::saveDocumentAs);
  262. menu.addCommandItem (commandManager, CommandIDs::saveAll);
  263. menu.addSeparator();
  264. menu.addCommandItem (commandManager, CommandIDs::closeProject);
  265. menu.addCommandItem (commandManager, CommandIDs::saveProject);
  266. menu.addSeparator();
  267. menu.addCommandItem (commandManager, CommandIDs::openInIDE);
  268. menu.addCommandItem (commandManager, CommandIDs::saveAndOpenInIDE);
  269. menu.addSeparator();
  270. menu.addCommandItem (commandManager, CommandIDs::loginLogout);
  271. #if ! JUCE_MAC
  272. menu.addCommandItem (commandManager, CommandIDs::showGlobalPreferences);
  273. menu.addSeparator();
  274. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit);
  275. #endif
  276. }
  277. void ProjucerApplication::createEditMenu (PopupMenu& menu)
  278. {
  279. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::undo);
  280. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::redo);
  281. menu.addSeparator();
  282. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
  283. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
  284. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);
  285. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
  286. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::selectAll);
  287. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::deselectAll);
  288. menu.addSeparator();
  289. menu.addCommandItem (commandManager, CommandIDs::showFindPanel);
  290. menu.addCommandItem (commandManager, CommandIDs::findSelection);
  291. menu.addCommandItem (commandManager, CommandIDs::findNext);
  292. menu.addCommandItem (commandManager, CommandIDs::findPrevious);
  293. }
  294. void ProjucerApplication::createViewMenu (PopupMenu& menu)
  295. {
  296. menu.addCommandItem (commandManager, CommandIDs::showFilePanel);
  297. menu.addCommandItem (commandManager, CommandIDs::showConfigPanel);
  298. menu.addCommandItem (commandManager, CommandIDs::showBuildTab);
  299. menu.addCommandItem (commandManager, CommandIDs::showProjectSettings);
  300. menu.addCommandItem (commandManager, CommandIDs::showProjectModules);
  301. menu.addSeparator();
  302. createColourSchemeItems (menu);
  303. }
  304. void ProjucerApplication::createBuildMenu (PopupMenu& menu)
  305. {
  306. menu.addCommandItem (commandManager, CommandIDs::enableBuild);
  307. menu.addCommandItem (commandManager, CommandIDs::toggleContinuousBuild);
  308. menu.addCommandItem (commandManager, CommandIDs::buildNow);
  309. menu.addSeparator();
  310. menu.addCommandItem (commandManager, CommandIDs::launchApp);
  311. menu.addCommandItem (commandManager, CommandIDs::killApp);
  312. menu.addCommandItem (commandManager, CommandIDs::cleanAll);
  313. menu.addSeparator();
  314. menu.addCommandItem (commandManager, CommandIDs::reinstantiateComp);
  315. menu.addCommandItem (commandManager, CommandIDs::showWarnings);
  316. menu.addSeparator();
  317. menu.addCommandItem (commandManager, CommandIDs::nextError);
  318. menu.addCommandItem (commandManager, CommandIDs::prevError);
  319. }
  320. void ProjucerApplication::createColourSchemeItems (PopupMenu& menu)
  321. {
  322. const StringArray presetSchemes (settings->appearance.getPresetSchemes());
  323. if (presetSchemes.size() > 0)
  324. {
  325. PopupMenu schemes;
  326. for (int i = 0; i < presetSchemes.size(); ++i)
  327. schemes.addItem (colourSchemeBaseID + i, presetSchemes[i]);
  328. menu.addSubMenu ("Colour Scheme", schemes);
  329. }
  330. }
  331. void ProjucerApplication::createWindowMenu (PopupMenu& menu)
  332. {
  333. menu.addCommandItem (commandManager, CommandIDs::closeWindow);
  334. menu.addSeparator();
  335. menu.addCommandItem (commandManager, CommandIDs::goToPreviousDoc);
  336. menu.addCommandItem (commandManager, CommandIDs::goToNextDoc);
  337. menu.addCommandItem (commandManager, CommandIDs::goToCounterpart);
  338. menu.addSeparator();
  339. const int numDocs = jmin (50, openDocumentManager.getNumOpenDocuments());
  340. for (int i = 0; i < numDocs; ++i)
  341. {
  342. OpenDocumentManager::Document* doc = openDocumentManager.getOpenDocument(i);
  343. menu.addItem (activeDocumentsBaseID + i, doc->getName());
  344. }
  345. menu.addSeparator();
  346. menu.addCommandItem (commandManager, CommandIDs::closeAllDocuments);
  347. }
  348. void ProjucerApplication::createToolsMenu (PopupMenu& menu)
  349. {
  350. menu.addCommandItem (commandManager, CommandIDs::showUTF8Tool);
  351. menu.addCommandItem (commandManager, CommandIDs::showSVGPathTool);
  352. menu.addCommandItem (commandManager, CommandIDs::showTranslationTool);
  353. }
  354. void ProjucerApplication::createExtraAppleMenuItems (PopupMenu& menu)
  355. {
  356. menu.addCommandItem (commandManager, CommandIDs::showGlobalPreferences);
  357. }
  358. void ProjucerApplication::handleMainMenuCommand (int menuItemID)
  359. {
  360. if (menuItemID >= recentProjectsBaseID && menuItemID < recentProjectsBaseID + 100)
  361. {
  362. // open a file from the "recent files" menu
  363. openFile (settings->recentFiles.getFile (menuItemID - recentProjectsBaseID));
  364. }
  365. else if (menuItemID >= activeDocumentsBaseID && menuItemID < activeDocumentsBaseID + 200)
  366. {
  367. if (OpenDocumentManager::Document* doc = openDocumentManager.getOpenDocument (menuItemID - activeDocumentsBaseID))
  368. mainWindowList.openDocument (doc, true);
  369. else
  370. jassertfalse;
  371. }
  372. else if (menuItemID >= colourSchemeBaseID && menuItemID < colourSchemeBaseID + 200)
  373. {
  374. settings->appearance.selectPresetScheme (menuItemID - colourSchemeBaseID);
  375. }
  376. else
  377. {
  378. handleGUIEditorMenuCommand (menuItemID);
  379. }
  380. }
  381. //==============================================================================
  382. void ProjucerApplication::getAllCommands (Array <CommandID>& commands)
  383. {
  384. JUCEApplication::getAllCommands (commands);
  385. const CommandID ids[] = { CommandIDs::newProject,
  386. CommandIDs::open,
  387. CommandIDs::closeAllDocuments,
  388. CommandIDs::saveAll,
  389. CommandIDs::showGlobalPreferences,
  390. CommandIDs::showUTF8Tool,
  391. CommandIDs::showSVGPathTool,
  392. CommandIDs::loginLogout };
  393. commands.addArray (ids, numElementsInArray (ids));
  394. }
  395. void ProjucerApplication::getCommandInfo (CommandID commandID, ApplicationCommandInfo& result)
  396. {
  397. switch (commandID)
  398. {
  399. case CommandIDs::newProject:
  400. result.setInfo ("New Project...", "Creates a new Jucer project", CommandCategories::general, 0);
  401. result.defaultKeypresses.add (KeyPress ('n', ModifierKeys::commandModifier, 0));
  402. break;
  403. case CommandIDs::open:
  404. result.setInfo ("Open...", "Opens a Jucer project", CommandCategories::general, 0);
  405. result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
  406. break;
  407. case CommandIDs::showGlobalPreferences:
  408. result.setInfo ("Preferences...", "Shows the preferences window.", CommandCategories::general, 0);
  409. result.defaultKeypresses.add (KeyPress (',', ModifierKeys::commandModifier, 0));
  410. break;
  411. case CommandIDs::closeAllDocuments:
  412. result.setInfo ("Close All Documents", "Closes all open documents", CommandCategories::general, 0);
  413. result.setActive (openDocumentManager.getNumOpenDocuments() > 0);
  414. break;
  415. case CommandIDs::saveAll:
  416. result.setInfo ("Save All", "Saves all open documents", CommandCategories::general, 0);
  417. result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier | ModifierKeys::altModifier, 0));
  418. break;
  419. case CommandIDs::showUTF8Tool:
  420. result.setInfo ("UTF-8 String-Literal Helper", "Shows the UTF-8 string literal utility", CommandCategories::general, 0);
  421. break;
  422. case CommandIDs::showSVGPathTool:
  423. result.setInfo ("SVG Path Helper", "Shows the SVG->Path data conversion utility", CommandCategories::general, 0);
  424. break;
  425. case CommandIDs::loginLogout:
  426. result.setInfo (ProjucerLicenses::getInstance()->isLoggedIn()
  427. ? String ("Sign out ") + ProjucerLicenses::getInstance()->getLoginName()
  428. : String ("Sign in..."),
  429. "Log out of your JUCE account", CommandCategories::general, 0);
  430. result.setActive (ProjucerLicenses::getInstance()->isDLLPresent());
  431. break;
  432. default:
  433. JUCEApplication::getCommandInfo (commandID, result);
  434. break;
  435. }
  436. }
  437. bool ProjucerApplication::perform (const InvocationInfo& info)
  438. {
  439. switch (info.commandID)
  440. {
  441. case CommandIDs::newProject: createNewProject(); break;
  442. case CommandIDs::open: askUserToOpenFile(); break;
  443. case CommandIDs::saveAll: openDocumentManager.saveAll(); break;
  444. case CommandIDs::closeAllDocuments: closeAllDocuments (true); break;
  445. case CommandIDs::showUTF8Tool: showUTF8ToolWindow(); break;
  446. case CommandIDs::showSVGPathTool: showSVGPathDataToolWindow(); break;
  447. case CommandIDs::showGlobalPreferences: AppearanceSettings::showGlobalPreferences (globalPreferencesWindow); break;
  448. case CommandIDs::loginLogout: loginOrLogout(); break;
  449. default: return JUCEApplication::perform (info);
  450. }
  451. return true;
  452. }
  453. //==============================================================================
  454. void ProjucerApplication::createNewProject()
  455. {
  456. MainWindow* mw = mainWindowList.getOrCreateEmptyWindow();
  457. mw->showNewProjectWizard();
  458. mainWindowList.avoidSuperimposedWindows (mw);
  459. }
  460. void ProjucerApplication::updateNewlyOpenedProject (Project& p)
  461. {
  462. LiveBuildProjectSettings::updateNewlyOpenedProject (p);
  463. }
  464. void ProjucerApplication::askUserToOpenFile()
  465. {
  466. FileChooser fc ("Open File");
  467. if (fc.browseForFileToOpen())
  468. openFile (fc.getResult());
  469. }
  470. bool ProjucerApplication::openFile (const File& file)
  471. {
  472. return mainWindowList.openFile (file);
  473. }
  474. bool ProjucerApplication::closeAllDocuments (bool askUserToSave)
  475. {
  476. return openDocumentManager.closeAll (askUserToSave);
  477. }
  478. bool ProjucerApplication::closeAllMainWindows()
  479. {
  480. return server != nullptr || mainWindowList.askAllWindowsToClose();
  481. }
  482. //==============================================================================
  483. void ProjucerApplication::showUTF8ToolWindow()
  484. {
  485. if (utf8Window != nullptr)
  486. utf8Window->toFront (true);
  487. else
  488. new FloatingToolWindow ("UTF-8 String Literal Converter",
  489. "utf8WindowPos",
  490. new UTF8Component(), utf8Window,
  491. 500, 500, 300, 300, 1000, 1000);
  492. }
  493. void ProjucerApplication::showSVGPathDataToolWindow()
  494. {
  495. if (svgPathWindow != nullptr)
  496. svgPathWindow->toFront (true);
  497. else
  498. new FloatingToolWindow ("SVG Path Converter",
  499. "svgPathWindowPos",
  500. new SVGPathDataComponent(), svgPathWindow,
  501. 500, 500, 300, 300, 1000, 1000);
  502. }
  503. //==============================================================================
  504. struct FileWithTime
  505. {
  506. FileWithTime (const File& f) : file (f), time (f.getLastModificationTime()) {}
  507. FileWithTime() {}
  508. bool operator< (const FileWithTime& other) const { return time < other.time; }
  509. bool operator== (const FileWithTime& other) const { return time == other.time; }
  510. File file;
  511. Time time;
  512. };
  513. void ProjucerApplication::deleteLogger()
  514. {
  515. const int maxNumLogFilesToKeep = 50;
  516. Logger::setCurrentLogger (nullptr);
  517. if (logger != nullptr)
  518. {
  519. Array<File> logFiles;
  520. logger->getLogFile().getParentDirectory().findChildFiles (logFiles, File::findFiles, false);
  521. if (logFiles.size() > maxNumLogFilesToKeep)
  522. {
  523. Array <FileWithTime> files;
  524. for (int i = 0; i < logFiles.size(); ++i)
  525. files.addUsingDefaultSort (logFiles.getReference(i));
  526. for (int i = 0; i < files.size() - maxNumLogFilesToKeep; ++i)
  527. files.getReference(i).file.deleteFile();
  528. }
  529. }
  530. logger = nullptr;
  531. }
  532. struct LiveBuildConfigItem : public ConfigTreeItemTypes::ConfigTreeItemBase
  533. {
  534. LiveBuildConfigItem (Project& p) : project (p) {}
  535. bool isMissing() override { return false; }
  536. bool canBeSelected() const override { return true; }
  537. bool mightContainSubItems() override { return false; }
  538. String getUniqueName() const override { return "live_build_settings"; }
  539. String getRenamingName() const override { return getDisplayName(); }
  540. String getDisplayName() const override { return "Live Build Settings"; }
  541. void setName (const String&) override {}
  542. Icon getIcon() const override { return Icon (getIcons().config, getContrastingColour (Colours::green, 0.5f)); }
  543. void showDocument() override { showSettingsPage (new SettingsComp (project)); }
  544. void itemOpennessChanged (bool) override {}
  545. Project& project;
  546. //==============================================================================
  547. struct SettingsComp : public Component
  548. {
  549. SettingsComp (Project& p)
  550. {
  551. addAndMakeVisible (&group);
  552. PropertyListBuilder props;
  553. LiveBuildProjectSettings::getLiveSettings (p, props);
  554. group.setProperties (props);
  555. group.setName ("Live Build Settings");
  556. parentSizeChanged();
  557. }
  558. void parentSizeChanged() override { updateSize (*this, group); }
  559. ConfigTreeItemTypes::PropertyGroupComponent group;
  560. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp)
  561. };
  562. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LiveBuildConfigItem)
  563. };
  564. void ProjucerApplication::addLiveBuildConfigItem (Project& project, TreeViewItem& parent)
  565. {
  566. parent.addSubItem (new LiveBuildConfigItem (project));
  567. }
  568. PropertiesFile::Options ProjucerApplication::getPropertyFileOptionsFor (const String& filename)
  569. {
  570. PropertiesFile::Options options;
  571. options.applicationName = filename;
  572. options.filenameSuffix = "settings";
  573. options.osxLibrarySubFolder = "Application Support";
  574. #if JUCE_LINUX
  575. options.folderName = "~/.config/Projucer";
  576. #else
  577. options.folderName = "Projucer";
  578. #endif
  579. return options;
  580. }
  581. void ProjucerApplication::hideLoginForm()
  582. {
  583. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  584. loginForm = nullptr;
  585. }
  586. void ProjucerApplication::showLoginForm()
  587. {
  588. if (ProjucerLicenses::getInstance()->isDLLPresent())
  589. {
  590. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  591. if (loginForm != nullptr)
  592. return;
  593. DialogWindow::LaunchOptions lo;
  594. lo.dialogTitle = "Log-in to Projucer";
  595. lo.dialogBackgroundColour = Colour (0xffdddddd);
  596. lo.content.setOwned (loginForm = new LoginForm());
  597. lo.escapeKeyTriggersCloseButton = true;
  598. lo.componentToCentreAround = nullptr;
  599. lo.escapeKeyTriggersCloseButton = true;
  600. lo.resizable = false;
  601. lo.useBottomRightCornerResizer = false;
  602. lo.useNativeTitleBar = true;
  603. lo.launchAsync();
  604. getGlobalProperties().setValue ("lastLoginAttemptTime",
  605. (int) (Time::getCurrentTime().toMilliseconds() / 1000));
  606. }
  607. }
  608. void ProjucerApplication::showLoginFormAsyncIfNotTriedRecently()
  609. {
  610. if (ProjucerLicenses::getInstance()->isDLLPresent())
  611. {
  612. Time lastLoginAttempt (getGlobalProperties().getValue ("lastLoginAttemptTime").getIntValue() * (int64) 1000);
  613. if (Time::getCurrentTime().getDayOfMonth() != lastLoginAttempt.getDayOfMonth())
  614. startTimer (1000);
  615. }
  616. else
  617. {
  618. getGlobalProperties().removeValue ("lastLoginAttemptTime");
  619. }
  620. }
  621. void ProjucerApplication::timerCallback()
  622. {
  623. stopTimer();
  624. if (! ProjucerLicenses::getInstance()->isLoggedIn())
  625. showLoginForm();
  626. }
  627. void ProjucerApplication::updateAllBuildTabs()
  628. {
  629. for (int i = 0; i < mainWindowList.windows.size(); ++i)
  630. if (ProjectContentComponent* p = mainWindowList.windows.getUnchecked(i)->getProjectContentComponent())
  631. p->rebuildProjectTabs();
  632. }
  633. //==============================================================================
  634. void ProjucerApplication::loginOrLogout()
  635. {
  636. ProjucerLicenses& status = *ProjucerLicenses::getInstance();
  637. if (status.isLoggedIn())
  638. status.logout();
  639. else
  640. showLoginForm();
  641. updateAllBuildTabs();
  642. }
  643. bool ProjucerApplication::checkEULA()
  644. {
  645. if (currentEULAHasBeenAcceptedPreviously()
  646. || ! ProjucerLicenses::getInstance()->isDLLPresent())
  647. return true;
  648. ScopedPointer<AlertWindow> eulaDialogue (new EULADialogue());
  649. bool hasBeenAccepted = (eulaDialogue->runModalLoop() == EULADialogue::accepted);
  650. setCurrentEULAAccepted (hasBeenAccepted);
  651. return hasBeenAccepted;
  652. }
  653. bool ProjucerApplication::currentEULAHasBeenAcceptedPreviously() const
  654. {
  655. return getGlobalProperties().getValue (getEULAChecksumProperty()).getIntValue() != 0;
  656. }
  657. String ProjucerApplication::getEULAChecksumProperty() const
  658. {
  659. return "eulaChecksum_" + MD5 (BinaryData::projucer_EULA_txt,
  660. BinaryData::projucer_EULA_txtSize).toHexString();
  661. }
  662. void ProjucerApplication::setCurrentEULAAccepted (bool hasBeenAccepted) const
  663. {
  664. const String checksum (getEULAChecksumProperty());
  665. auto& globals = getGlobalProperties();
  666. if (hasBeenAccepted)
  667. globals.setValue (checksum, 1);
  668. else
  669. globals.removeValue (checksum);
  670. globals.saveIfNeeded();
  671. }
  672. void ProjucerApplication::initCommandManager()
  673. {
  674. commandManager = new ApplicationCommandManager();
  675. commandManager->registerAllCommandsForTarget (this);
  676. {
  677. CodeDocument doc;
  678. CppCodeEditorComponent ed (File(), doc);
  679. commandManager->registerAllCommandsForTarget (&ed);
  680. }
  681. registerGUIEditorCommands();
  682. }