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.

443 lines
16KB

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