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.

510 lines
18KB

  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 "../Project/jucer_NewProjectWizard.h"
  24. #include "jucer_CommandLine.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. {
  52. anotherInstanceStarted (commandLine);
  53. }
  54. else
  55. {
  56. Array<File> projects (StoredSettings::getInstance()->getLastProjects());
  57. for (int i = 0; i < projects.size(); ++ i)
  58. openFile (projects.getReference(i));
  59. }
  60. if (mainWindows.size() == 0)
  61. createNewMainWindow()->makeVisible();
  62. #if JUCE_MAC
  63. MenuBarModel::setMacMainMenu (menuModel);
  64. #endif
  65. }
  66. void shutdown()
  67. {
  68. #if JUCE_MAC
  69. MenuBarModel::setMacMainMenu (nullptr);
  70. #endif
  71. menuModel = nullptr;
  72. StoredSettings::deleteInstance();
  73. mainWindows.clear();
  74. OpenDocumentManager::deleteInstance();
  75. deleteAndZero (commandManager);
  76. }
  77. //==============================================================================
  78. void systemRequestedQuit()
  79. {
  80. while (mainWindows.size() > 0)
  81. {
  82. if (! mainWindows[0]->closeCurrentProject())
  83. return;
  84. mainWindows.remove (0);
  85. }
  86. quit();
  87. }
  88. void closeWindow (MainWindow* w)
  89. {
  90. jassert (mainWindows.contains (w));
  91. mainWindows.removeObject (w);
  92. #if ! JUCE_MAC
  93. if (mainWindows.size() == 0)
  94. systemRequestedQuit();
  95. #endif
  96. updateRecentProjectList();
  97. }
  98. //==============================================================================
  99. const String getApplicationName()
  100. {
  101. return String (ProjectInfo::projectName) + " " + getApplicationVersion();
  102. }
  103. const String getApplicationVersion()
  104. {
  105. return ProjectInfo::versionString;
  106. }
  107. bool moreThanOneInstanceAllowed()
  108. {
  109. #ifndef JUCE_LINUX
  110. return false;
  111. #else
  112. return true; //xxx should be false but doesn't work on linux..
  113. #endif
  114. }
  115. void anotherInstanceStarted (const String& commandLine)
  116. {
  117. openFile (commandLine.unquoted());
  118. }
  119. virtual void doExtraInitialisation() {}
  120. //==============================================================================
  121. class MainMenuModel : public MenuBarModel
  122. {
  123. public:
  124. MainMenuModel()
  125. {
  126. setApplicationCommandManagerToWatch (commandManager);
  127. }
  128. const StringArray getMenuBarNames()
  129. {
  130. const char* const names[] = { "File", "Edit", "View", "Window", "Update", 0 };
  131. return StringArray ((const char**) names);
  132. }
  133. const PopupMenu getMenuForIndex (int topLevelMenuIndex, const String& menuName)
  134. {
  135. PopupMenu menu;
  136. if (topLevelMenuIndex == 0) // "File" menu
  137. {
  138. menu.addCommandItem (commandManager, CommandIDs::newProject);
  139. menu.addSeparator();
  140. menu.addCommandItem (commandManager, CommandIDs::open);
  141. PopupMenu recentFiles;
  142. StoredSettings::getInstance()->recentFiles.createPopupMenuItems (recentFiles, 100, true, true);
  143. menu.addSubMenu ("Open recent file", recentFiles);
  144. menu.addSeparator();
  145. menu.addCommandItem (commandManager, CommandIDs::closeDocument);
  146. menu.addCommandItem (commandManager, CommandIDs::saveDocument);
  147. menu.addCommandItem (commandManager, CommandIDs::saveDocumentAs);
  148. menu.addSeparator();
  149. menu.addCommandItem (commandManager, CommandIDs::closeProject);
  150. menu.addCommandItem (commandManager, CommandIDs::saveProject);
  151. menu.addCommandItem (commandManager, CommandIDs::saveProjectAs);
  152. menu.addSeparator();
  153. menu.addCommandItem (commandManager, CommandIDs::openInIDE);
  154. menu.addCommandItem (commandManager, CommandIDs::saveAndOpenInIDE);
  155. #if ! JUCE_MAC
  156. menu.addSeparator();
  157. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit);
  158. #endif
  159. }
  160. else if (topLevelMenuIndex == 1) // "Edit" menu
  161. {
  162. menu.addCommandItem (commandManager, CommandIDs::undo);
  163. menu.addCommandItem (commandManager, CommandIDs::redo);
  164. menu.addSeparator();
  165. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
  166. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
  167. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);
  168. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
  169. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::selectAll);
  170. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::deselectAll);
  171. menu.addSeparator();
  172. menu.addCommandItem (commandManager, CommandIDs::toFront);
  173. menu.addCommandItem (commandManager, CommandIDs::toBack);
  174. menu.addSeparator();
  175. menu.addCommandItem (commandManager, CommandIDs::group);
  176. menu.addCommandItem (commandManager, CommandIDs::ungroup);
  177. menu.addSeparator();
  178. menu.addCommandItem (commandManager, CommandIDs::bringBackLostItems);
  179. }
  180. else if (topLevelMenuIndex == 2) // "View" menu
  181. {
  182. menu.addCommandItem (commandManager, CommandIDs::showProjectSettings);
  183. menu.addSeparator();
  184. menu.addCommandItem (commandManager, CommandIDs::test);
  185. menu.addSeparator();
  186. menu.addCommandItem (commandManager, CommandIDs::showGrid);
  187. menu.addCommandItem (commandManager, CommandIDs::enableSnapToGrid);
  188. menu.addSeparator();
  189. menu.addCommandItem (commandManager, CommandIDs::zoomIn);
  190. menu.addCommandItem (commandManager, CommandIDs::zoomOut);
  191. menu.addCommandItem (commandManager, CommandIDs::zoomNormal);
  192. menu.addSeparator();
  193. menu.addCommandItem (commandManager, CommandIDs::useTabbedWindows);
  194. }
  195. else if (topLevelMenuIndex == 3) // "Window" menu
  196. {
  197. menu.addCommandItem (commandManager, CommandIDs::closeWindow);
  198. menu.addSeparator();
  199. const int numDocs = jmin (50, OpenDocumentManager::getInstance()->getNumOpenDocuments());
  200. for (int i = 0; i < numDocs; ++i)
  201. {
  202. OpenDocumentManager::Document* doc = OpenDocumentManager::getInstance()->getOpenDocument(i);
  203. menu.addItem (300 + i, doc->getName());
  204. }
  205. menu.addSeparator();
  206. menu.addCommandItem (commandManager, CommandIDs::closeAllDocuments);
  207. }
  208. else if (topLevelMenuIndex == 4) // "Juce" menu
  209. {
  210. menu.addCommandItem (commandManager, CommandIDs::showJuceVersion);
  211. }
  212. return menu;
  213. }
  214. void menuItemSelected (int menuItemID, int topLevelMenuIndex)
  215. {
  216. if (menuItemID >= 100 && menuItemID < 200)
  217. {
  218. // open a file from the "recent files" menu
  219. const File file (StoredSettings::getInstance()->recentFiles.getFile (menuItemID - 100));
  220. getApp()->openFile (file);
  221. }
  222. else if (menuItemID >= 300 && menuItemID < 400)
  223. {
  224. OpenDocumentManager::Document* doc = OpenDocumentManager::getInstance()->getOpenDocument (menuItemID - 300);
  225. MainWindow* w = getApp()->getOrCreateFrontmostWindow();
  226. w->makeVisible();
  227. w->getProjectContentComponent()->showDocument (doc);
  228. }
  229. }
  230. private:
  231. JucerApplication* getApp() const
  232. {
  233. return static_cast<JucerApplication*> (JUCEApplication::getInstance());
  234. }
  235. };
  236. //==============================================================================
  237. void getAllCommands (Array <CommandID>& commands)
  238. {
  239. JUCEApplication::getAllCommands (commands);
  240. const CommandID ids[] = { CommandIDs::newProject,
  241. CommandIDs::open,
  242. CommandIDs::showPrefs,
  243. CommandIDs::closeAllDocuments,
  244. CommandIDs::saveAll,
  245. CommandIDs::showJuceVersion };
  246. commands.addArray (ids, numElementsInArray (ids));
  247. }
  248. void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result)
  249. {
  250. switch (commandID)
  251. {
  252. case CommandIDs::newProject:
  253. result.setInfo ("New Project...", "Creates a new Jucer project", CommandCategories::general, 0);
  254. result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
  255. break;
  256. case CommandIDs::open:
  257. result.setInfo ("Open...", "Opens a Jucer project", CommandCategories::general, 0);
  258. result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
  259. break;
  260. case CommandIDs::showPrefs:
  261. result.setInfo ("Preferences...", "Shows the preferences panel.", CommandCategories::general, 0);
  262. result.defaultKeypresses.add (KeyPress (',', ModifierKeys::commandModifier, 0));
  263. break;
  264. case CommandIDs::closeAllDocuments:
  265. result.setInfo ("Close All Documents", "Closes all open documents", CommandCategories::general, 0);
  266. result.setActive (OpenDocumentManager::getInstance()->getNumOpenDocuments() > 0);
  267. break;
  268. case CommandIDs::saveAll:
  269. result.setInfo ("Save All", "Saves all open documents", CommandCategories::general, 0);
  270. result.setActive (OpenDocumentManager::getInstance()->anyFilesNeedSaving());
  271. break;
  272. case CommandIDs::showJuceVersion:
  273. result.setInfo ("Download the latest JUCE version", "Checks online for any Juce updates", CommandCategories::general, 0);
  274. break;
  275. default:
  276. JUCEApplication::getCommandInfo (commandID, result);
  277. break;
  278. }
  279. }
  280. bool perform (const InvocationInfo& info)
  281. {
  282. switch (info.commandID)
  283. {
  284. case CommandIDs::newProject: createNewProject(); break;
  285. case CommandIDs::open: askUserToOpenFile(); break;
  286. case CommandIDs::showPrefs: showPrefsPanel(); break;
  287. case CommandIDs::saveAll: OpenDocumentManager::getInstance()->saveAll(); break;
  288. case CommandIDs::closeAllDocuments: closeAllDocuments (true); break;
  289. case CommandIDs::showJuceVersion: JuceUpdater::show (mainWindows[0]); break;
  290. default: return JUCEApplication::perform (info);
  291. }
  292. return true;
  293. }
  294. //==============================================================================
  295. void showPrefsPanel()
  296. {
  297. jassertfalse;
  298. }
  299. void createNewProject()
  300. {
  301. MainWindow* mw = createNewMainWindow();
  302. ScopedPointer <Project> newProj (NewProjectWizard::runNewProjectWizard (mw));
  303. if (newProj != nullptr)
  304. {
  305. mw->setProject (newProj.release());
  306. mw->makeVisible();
  307. }
  308. else
  309. {
  310. closeWindow (mw);
  311. }
  312. }
  313. void askUserToOpenFile()
  314. {
  315. FileChooser fc ("Open File");
  316. if (fc.browseForFileToOpen())
  317. openFile (fc.getResult());
  318. }
  319. bool openFile (const File& file)
  320. {
  321. for (int j = mainWindows.size(); --j >= 0;)
  322. {
  323. if (mainWindows.getUnchecked(j)->getProject() != nullptr
  324. && mainWindows.getUnchecked(j)->getProject()->getFile() == file)
  325. {
  326. mainWindows.getUnchecked(j)->toFront (true);
  327. return true;
  328. }
  329. }
  330. if (file.hasFileExtension (Project::projectFileExtension))
  331. {
  332. ScopedPointer <Project> newDoc (new Project (file));
  333. if (newDoc->loadFrom (file, true))
  334. {
  335. MainWindow* w = getOrCreateEmptyWindow();
  336. w->setProject (newDoc.release());
  337. w->makeVisible();
  338. return true;
  339. }
  340. }
  341. else if (file.exists())
  342. {
  343. MainWindow* w = getOrCreateFrontmostWindow();
  344. const bool ok = w->openFile (file);
  345. w->makeVisible();
  346. return ok;
  347. }
  348. return false;
  349. }
  350. bool closeAllDocuments (bool askUserToSave)
  351. {
  352. for (int i = OpenDocumentManager::getInstance()->getNumOpenDocuments(); --i >= 0;)
  353. {
  354. OpenDocumentManager::Document* doc = OpenDocumentManager::getInstance()->getOpenDocument (i);
  355. for (int j = mainWindows.size(); --j >= 0;)
  356. mainWindows.getUnchecked(j)->getProjectContentComponent()->hideDocument (doc);
  357. if (! OpenDocumentManager::getInstance()->closeDocument (i, askUserToSave))
  358. return false;
  359. }
  360. return true;
  361. }
  362. void updateRecentProjectList()
  363. {
  364. Array<File> projects;
  365. for (int i = 0; i < mainWindows.size(); ++i)
  366. {
  367. MainWindow* mw = mainWindows[i];
  368. if (mw != nullptr && mw->getProject() != nullptr)
  369. projects.add (mw->getProject()->getFile());
  370. }
  371. StoredSettings::getInstance()->setLastProjects (projects);
  372. }
  373. ScopedPointer<MainMenuModel> menuModel;
  374. private:
  375. OwnedArray <MainWindow> mainWindows;
  376. MainWindow* createNewMainWindow()
  377. {
  378. MainWindow* mw = new MainWindow();
  379. for (int i = mainWindows.size(); --i >= 0;)
  380. if (mw->getBounds() == mainWindows.getUnchecked(i)->getBounds())
  381. mw->setBounds (mw->getBounds().translated (20, 20));
  382. mainWindows.add (mw);
  383. mw->restoreWindowPosition();
  384. return mw;
  385. }
  386. MainWindow* getOrCreateFrontmostWindow()
  387. {
  388. if (mainWindows.size() == 0)
  389. return createNewMainWindow();
  390. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
  391. {
  392. MainWindow* mw = dynamic_cast <MainWindow*> (Desktop::getInstance().getComponent (i));
  393. if (mainWindows.contains (mw))
  394. return mw;
  395. }
  396. return mainWindows.getLast();
  397. }
  398. MainWindow* getOrCreateEmptyWindow()
  399. {
  400. if (mainWindows.size() == 0)
  401. return createNewMainWindow();
  402. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
  403. {
  404. MainWindow* mw = dynamic_cast <MainWindow*> (Desktop::getInstance().getComponent (i));
  405. if (mainWindows.contains (mw) && mw->getProject() == nullptr)
  406. return mw;
  407. }
  408. return createNewMainWindow();
  409. }
  410. };
  411. #endif // __JUCER_APPLICATION_JUCEHEADER__