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.

482 lines
17KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #ifndef __JUCER_APPLICATION_JUCEHEADER__
  19. #define __JUCER_APPLICATION_JUCEHEADER__
  20. #include "../jucer_Headers.h"
  21. #include "jucer_MainWindow.h"
  22. #include "jucer_JuceUpdater.h"
  23. #include "jucer_CommandLine.h"
  24. #include "../Code Editor/jucer_SourceCodeEditor.h"
  25. //==============================================================================
  26. class JucerApplication : public JUCEApplication
  27. {
  28. public:
  29. //==============================================================================
  30. JucerApplication() {}
  31. ~JucerApplication() {}
  32. //==============================================================================
  33. void initialise (const String& commandLine)
  34. {
  35. LookAndFeel::setDefaultLookAndFeel (&lookAndFeel);
  36. settings.initialise();
  37. if (commandLine.isNotEmpty())
  38. {
  39. const int appReturnCode = performCommandLine (commandLine);
  40. if (appReturnCode != commandLineNotPerformed)
  41. {
  42. setApplicationReturnValue (appReturnCode);
  43. quit();
  44. return;
  45. }
  46. }
  47. commandManager = new ApplicationCommandManager();
  48. commandManager->registerAllCommandsForTarget (this);
  49. menuModel = new MainMenuModel();
  50. doExtraInitialisation();
  51. ImageCache::setCacheTimeout (30 * 1000);
  52. if (commandLine.trim().isNotEmpty() && ! commandLine.trim().startsWithChar ('-'))
  53. anotherInstanceStarted (commandLine);
  54. else
  55. mainWindowList.reopenLastProjects();
  56. makeSureUserHasSelectedModuleFolder();
  57. mainWindowList.createWindowIfNoneAreOpen();
  58. #if JUCE_MAC
  59. MenuBarModel::setMacMainMenu (menuModel);
  60. #endif
  61. }
  62. void shutdown()
  63. {
  64. appearanceEditorWindow = nullptr;
  65. #if JUCE_MAC
  66. MenuBarModel::setMacMainMenu (nullptr);
  67. #endif
  68. menuModel = nullptr;
  69. mainWindowList.forceCloseAllWindows();
  70. openDocumentManager.clear();
  71. commandManager = nullptr;
  72. settings.flush();
  73. LookAndFeel::setDefaultLookAndFeel (nullptr);
  74. }
  75. //==============================================================================
  76. void systemRequestedQuit()
  77. {
  78. if (cancelAnyModalComponents())
  79. {
  80. new AsyncQuitRetrier();
  81. return;
  82. }
  83. if (mainWindowList.askAllWindowsToClose())
  84. quit();
  85. }
  86. //==============================================================================
  87. const String getApplicationName()
  88. {
  89. return String (ProjectInfo::projectName) + " " + getApplicationVersion();
  90. }
  91. const String getApplicationVersion()
  92. {
  93. return ProjectInfo::versionString;
  94. }
  95. bool moreThanOneInstanceAllowed()
  96. {
  97. #ifndef JUCE_LINUX
  98. return false;
  99. #else
  100. return true; //xxx should be false but doesn't work on linux..
  101. #endif
  102. }
  103. void anotherInstanceStarted (const String& commandLine)
  104. {
  105. openFile (commandLine.unquoted());
  106. }
  107. static JucerApplication& getApp()
  108. {
  109. JucerApplication* const app = dynamic_cast<JucerApplication*> (JUCEApplication::getInstance());
  110. jassert (app != nullptr);
  111. return *app;
  112. }
  113. //==============================================================================
  114. class MainMenuModel : public MenuBarModel
  115. {
  116. public:
  117. MainMenuModel()
  118. {
  119. setApplicationCommandManagerToWatch (commandManager);
  120. }
  121. StringArray getMenuBarNames()
  122. {
  123. return getApp().getMenuNames();
  124. }
  125. PopupMenu getMenuForIndex (int /*topLevelMenuIndex*/, const String& menuName)
  126. {
  127. PopupMenu menu;
  128. getApp().createMenu (menu, menuName);
  129. return menu;
  130. }
  131. void menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/)
  132. {
  133. if (menuItemID >= 100 && menuItemID < 200)
  134. {
  135. // open a file from the "recent files" menu
  136. getApp().openFile (getAppSettings().recentFiles.getFile (menuItemID - 100));
  137. }
  138. else if (menuItemID >= 300 && menuItemID < 400)
  139. {
  140. OpenDocumentManager::Document* doc = getApp().openDocumentManager.getOpenDocument (menuItemID - 300);
  141. jassert (doc != nullptr);
  142. getApp().mainWindowList.openDocument (doc);
  143. }
  144. }
  145. };
  146. virtual StringArray getMenuNames()
  147. {
  148. const char* const names[] = { "File", "Edit", "View", "Window", "Tools", nullptr };
  149. return StringArray (names);
  150. }
  151. virtual void createMenu (PopupMenu& menu, const String& menuName)
  152. {
  153. if (menuName == "File") createFileMenu (menu);
  154. else if (menuName == "Edit") createEditMenu (menu);
  155. else if (menuName == "View") createViewMenu (menu);
  156. else if (menuName == "Window") createWindowMenu (menu);
  157. else if (menuName == "Tools") createToolsMenu (menu);
  158. else jassertfalse; // names have changed?
  159. }
  160. virtual void createFileMenu (PopupMenu& menu)
  161. {
  162. menu.addCommandItem (commandManager, CommandIDs::newProject);
  163. menu.addSeparator();
  164. menu.addCommandItem (commandManager, CommandIDs::open);
  165. PopupMenu recentFiles;
  166. getAppSettings().recentFiles.createPopupMenuItems (recentFiles, 100, true, true);
  167. menu.addSubMenu ("Open recent file", recentFiles);
  168. menu.addSeparator();
  169. menu.addCommandItem (commandManager, CommandIDs::closeDocument);
  170. menu.addCommandItem (commandManager, CommandIDs::saveDocument);
  171. menu.addSeparator();
  172. menu.addCommandItem (commandManager, CommandIDs::closeProject);
  173. menu.addCommandItem (commandManager, CommandIDs::saveProject);
  174. menu.addSeparator();
  175. menu.addCommandItem (commandManager, CommandIDs::openInIDE);
  176. menu.addCommandItem (commandManager, CommandIDs::saveAndOpenInIDE);
  177. #if ! JUCE_MAC
  178. menu.addSeparator();
  179. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit);
  180. #endif
  181. }
  182. virtual void createEditMenu (PopupMenu& menu)
  183. {
  184. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::undo);
  185. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::redo);
  186. menu.addSeparator();
  187. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
  188. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
  189. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);
  190. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
  191. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::selectAll);
  192. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::deselectAll);
  193. menu.addSeparator();
  194. menu.addCommandItem (commandManager, CommandIDs::toFront);
  195. menu.addCommandItem (commandManager, CommandIDs::toBack);
  196. menu.addSeparator();
  197. menu.addCommandItem (commandManager, CommandIDs::group);
  198. menu.addCommandItem (commandManager, CommandIDs::ungroup);
  199. menu.addSeparator();
  200. menu.addCommandItem (commandManager, CommandIDs::bringBackLostItems);
  201. }
  202. virtual void createViewMenu (PopupMenu& menu)
  203. {
  204. menu.addCommandItem (commandManager, CommandIDs::showFilePanel);
  205. menu.addCommandItem (commandManager, CommandIDs::showConfigPanel);
  206. menu.addSeparator();
  207. menu.addCommandItem (commandManager, CommandIDs::showAppearanceSettings);
  208. }
  209. virtual void createWindowMenu (PopupMenu& menu)
  210. {
  211. menu.addCommandItem (commandManager, CommandIDs::closeWindow);
  212. menu.addSeparator();
  213. menu.addCommandItem (commandManager, CommandIDs::goToPreviousDoc);
  214. menu.addCommandItem (commandManager, CommandIDs::goToNextDoc);
  215. menu.addSeparator();
  216. const int numDocs = jmin (50, getApp().openDocumentManager.getNumOpenDocuments());
  217. for (int i = 0; i < numDocs; ++i)
  218. {
  219. OpenDocumentManager::Document* doc = getApp().openDocumentManager.getOpenDocument(i);
  220. menu.addItem (300 + i, doc->getName());
  221. }
  222. menu.addSeparator();
  223. menu.addCommandItem (commandManager, CommandIDs::closeAllDocuments);
  224. }
  225. virtual void createToolsMenu (PopupMenu& menu)
  226. {
  227. menu.addCommandItem (commandManager, CommandIDs::updateModules);
  228. menu.addCommandItem (commandManager, CommandIDs::showUTF8Tool);
  229. }
  230. //==============================================================================
  231. void getAllCommands (Array <CommandID>& commands)
  232. {
  233. JUCEApplication::getAllCommands (commands);
  234. const CommandID ids[] = { CommandIDs::newProject,
  235. CommandIDs::open,
  236. CommandIDs::showPrefs,
  237. CommandIDs::closeAllDocuments,
  238. CommandIDs::saveAll,
  239. CommandIDs::updateModules,
  240. CommandIDs::showAppearanceSettings,
  241. CommandIDs::showUTF8Tool };
  242. commands.addArray (ids, numElementsInArray (ids));
  243. }
  244. void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result)
  245. {
  246. switch (commandID)
  247. {
  248. case CommandIDs::newProject:
  249. result.setInfo ("New Project...", "Creates a new Jucer project", CommandCategories::general, 0);
  250. result.defaultKeypresses.add (KeyPress ('n', ModifierKeys::commandModifier, 0));
  251. break;
  252. case CommandIDs::open:
  253. result.setInfo ("Open...", "Opens a Jucer project", CommandCategories::general, 0);
  254. result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
  255. break;
  256. case CommandIDs::showPrefs:
  257. result.setInfo ("Preferences...", "Shows the preferences panel.", CommandCategories::general, 0);
  258. result.defaultKeypresses.add (KeyPress (',', ModifierKeys::commandModifier, 0));
  259. break;
  260. case CommandIDs::showAppearanceSettings:
  261. result.setInfo ("Fonts and Colours...", "Shows the appearance settings window.", CommandCategories::general, 0);
  262. break;
  263. case CommandIDs::closeAllDocuments:
  264. result.setInfo ("Close All Documents", "Closes all open documents", CommandCategories::general, 0);
  265. result.setActive (openDocumentManager.getNumOpenDocuments() > 0);
  266. break;
  267. case CommandIDs::saveAll:
  268. result.setInfo ("Save All", "Saves all open documents", CommandCategories::general, 0);
  269. result.setActive (openDocumentManager.anyFilesNeedSaving());
  270. break;
  271. case CommandIDs::updateModules:
  272. result.setInfo ("Download the latest JUCE modules", "Checks online for any JUCE modules updates and installs them", CommandCategories::general, 0);
  273. break;
  274. case CommandIDs::showUTF8Tool:
  275. result.setInfo ("UTF-8 String-Literal Helper", "Shows the UTF-8 string literal utility", CommandCategories::general, 0);
  276. break;
  277. default:
  278. JUCEApplication::getCommandInfo (commandID, result);
  279. break;
  280. }
  281. }
  282. bool perform (const InvocationInfo& info)
  283. {
  284. switch (info.commandID)
  285. {
  286. case CommandIDs::newProject: createNewProject(); break;
  287. case CommandIDs::open: askUserToOpenFile(); break;
  288. case CommandIDs::showPrefs: showPrefsPanel(); break;
  289. case CommandIDs::saveAll: openDocumentManager.saveAll(); break;
  290. case CommandIDs::closeAllDocuments: closeAllDocuments (true); break;
  291. case CommandIDs::showUTF8Tool: showUTF8ToolWindow(); break;
  292. case CommandIDs::showAppearanceSettings: showAppearanceEditorWindow(); break;
  293. case CommandIDs::updateModules: runModuleUpdate (String::empty); break;
  294. default: return JUCEApplication::perform (info);
  295. }
  296. return true;
  297. }
  298. //==============================================================================
  299. void showPrefsPanel()
  300. {
  301. jassertfalse;
  302. }
  303. void createNewProject()
  304. {
  305. if (makeSureUserHasSelectedModuleFolder())
  306. {
  307. MainWindow* mw = mainWindowList.getOrCreateEmptyWindow();
  308. mw->showNewProjectWizard();
  309. mainWindowList.avoidSuperimposedWindows (mw);
  310. }
  311. }
  312. void askUserToOpenFile()
  313. {
  314. FileChooser fc ("Open File");
  315. if (fc.browseForFileToOpen())
  316. openFile (fc.getResult());
  317. }
  318. bool openFile (const File& file)
  319. {
  320. return mainWindowList.openFile (file);
  321. }
  322. bool closeAllDocuments (bool askUserToSave)
  323. {
  324. return openDocumentManager.closeAll (askUserToSave);
  325. }
  326. bool makeSureUserHasSelectedModuleFolder()
  327. {
  328. if (! ModuleList::isLocalModulesFolderValid())
  329. {
  330. if (! runModuleUpdate ("Please select a location to store your local set of JUCE modules,\n"
  331. "and download the ones that you'd like to use!"))
  332. {
  333. AlertWindow::showMessageBox (AlertWindow::WarningIcon,
  334. "Introjucer",
  335. "Unless you create a local JUCE folder containing some modules, you'll be unable to save any projects correctly!\n\n"
  336. "Use the option on the 'Tools' menu to set this up!");
  337. return false;
  338. }
  339. }
  340. return true;
  341. }
  342. bool runModuleUpdate (const String& message)
  343. {
  344. ModuleList list;
  345. list.rescan (ModuleList::getDefaultModulesFolder (nullptr));
  346. JuceUpdater::show (list, mainWindowList.windows[0], message);
  347. ModuleList::setLocalModulesFolder (list.getModulesFolder());
  348. return ModuleList::isJuceOrModulesFolder (list.getModulesFolder());
  349. }
  350. void showAppearanceEditorWindow()
  351. {
  352. if (appearanceEditorWindow == nullptr)
  353. appearanceEditorWindow = AppearanceSettings::createEditorWindow();
  354. appearanceEditorWindow->toFront (true);
  355. }
  356. //==============================================================================
  357. virtual void doExtraInitialisation() {}
  358. virtual void addExtraConfigItems (Project&, TreeViewItem&) {}
  359. virtual Component* createProjectContentComponent() const
  360. {
  361. return new ProjectContentComponent();
  362. }
  363. //==============================================================================
  364. IntrojucerLookAndFeel lookAndFeel;
  365. StoredSettings settings;
  366. Icons icons;
  367. ScopedPointer<MainMenuModel> menuModel;
  368. MainWindowList mainWindowList;
  369. OpenDocumentManager openDocumentManager;
  370. ScopedPointer<Component> appearanceEditorWindow;
  371. private:
  372. class AsyncQuitRetrier : public Timer
  373. {
  374. public:
  375. AsyncQuitRetrier() { startTimer (500); }
  376. void timerCallback()
  377. {
  378. stopTimer();
  379. delete this;
  380. JUCEApplication* app = JUCEApplication::getInstance();
  381. if (app != nullptr)
  382. app->systemRequestedQuit();
  383. }
  384. JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier);
  385. };
  386. };
  387. #endif // __JUCER_APPLICATION_JUCEHEADER__