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.

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