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.

507 lines
18KB

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