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.

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