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.

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