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.

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