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.

506 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::openProjectInIDE);
  153. #if ! JUCE_MAC
  154. menu.addSeparator();
  155. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit);
  156. #endif
  157. }
  158. else if (topLevelMenuIndex == 1) // "Edit" menu
  159. {
  160. menu.addCommandItem (commandManager, CommandIDs::undo);
  161. menu.addCommandItem (commandManager, CommandIDs::redo);
  162. menu.addSeparator();
  163. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
  164. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
  165. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);
  166. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
  167. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::selectAll);
  168. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::deselectAll);
  169. menu.addSeparator();
  170. menu.addCommandItem (commandManager, CommandIDs::toFront);
  171. menu.addCommandItem (commandManager, CommandIDs::toBack);
  172. menu.addSeparator();
  173. menu.addCommandItem (commandManager, CommandIDs::group);
  174. menu.addCommandItem (commandManager, CommandIDs::ungroup);
  175. menu.addSeparator();
  176. menu.addCommandItem (commandManager, CommandIDs::bringBackLostItems);
  177. }
  178. else if (topLevelMenuIndex == 2) // "View" menu
  179. {
  180. menu.addCommandItem (commandManager, CommandIDs::showProjectSettings);
  181. menu.addSeparator();
  182. menu.addCommandItem (commandManager, CommandIDs::test);
  183. menu.addSeparator();
  184. menu.addCommandItem (commandManager, CommandIDs::showGrid);
  185. menu.addCommandItem (commandManager, CommandIDs::enableSnapToGrid);
  186. menu.addSeparator();
  187. menu.addCommandItem (commandManager, CommandIDs::zoomIn);
  188. menu.addCommandItem (commandManager, CommandIDs::zoomOut);
  189. menu.addCommandItem (commandManager, CommandIDs::zoomNormal);
  190. menu.addSeparator();
  191. menu.addCommandItem (commandManager, CommandIDs::useTabbedWindows);
  192. }
  193. else if (topLevelMenuIndex == 3) // "Window" menu
  194. {
  195. menu.addCommandItem (commandManager, CommandIDs::closeWindow);
  196. menu.addSeparator();
  197. const int numDocs = jmin (50, OpenDocumentManager::getInstance()->getNumOpenDocuments());
  198. for (int i = 0; i < numDocs; ++i)
  199. {
  200. OpenDocumentManager::Document* doc = OpenDocumentManager::getInstance()->getOpenDocument(i);
  201. menu.addItem (300 + i, doc->getName());
  202. }
  203. menu.addSeparator();
  204. menu.addCommandItem (commandManager, CommandIDs::closeAllDocuments);
  205. }
  206. else if (topLevelMenuIndex == 4) // "Juce" menu
  207. {
  208. menu.addCommandItem (commandManager, CommandIDs::showJuceVersion);
  209. }
  210. return menu;
  211. }
  212. void menuItemSelected (int menuItemID, int topLevelMenuIndex)
  213. {
  214. if (menuItemID >= 100 && menuItemID < 200)
  215. {
  216. // open a file from the "recent files" menu
  217. const File file (StoredSettings::getInstance()->recentFiles.getFile (menuItemID - 100));
  218. getApp()->openFile (file);
  219. }
  220. else if (menuItemID >= 300 && menuItemID < 400)
  221. {
  222. OpenDocumentManager::Document* doc = OpenDocumentManager::getInstance()->getOpenDocument (menuItemID - 300);
  223. getApp()->getOrCreateFrontmostWindow (true)->getProjectContentComponent()->showDocument (doc);
  224. }
  225. }
  226. private:
  227. JucerApplication* getApp() const
  228. {
  229. return static_cast<JucerApplication*> (JUCEApplication::getInstance());
  230. }
  231. };
  232. //==============================================================================
  233. void getAllCommands (Array <CommandID>& commands)
  234. {
  235. JUCEApplication::getAllCommands (commands);
  236. const CommandID ids[] = { CommandIDs::newProject,
  237. CommandIDs::open,
  238. CommandIDs::showPrefs,
  239. CommandIDs::closeAllDocuments,
  240. CommandIDs::saveAll,
  241. CommandIDs::showJuceVersion };
  242. commands.addArray (ids, numElementsInArray (ids));
  243. }
  244. void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result)
  245. {
  246. switch (commandID)
  247. {
  248. case CommandIDs::newProject:
  249. result.setInfo ("New Project...", "Creates a new Jucer project", CommandCategories::general, 0);
  250. result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
  251. break;
  252. case CommandIDs::open:
  253. result.setInfo ("Open...", "Opens a Jucer project", CommandCategories::general, 0);
  254. result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
  255. break;
  256. case CommandIDs::showPrefs:
  257. result.setInfo ("Preferences...", "Shows the preferences panel.", CommandCategories::general, 0);
  258. result.defaultKeypresses.add (KeyPress (',', ModifierKeys::commandModifier, 0));
  259. break;
  260. case CommandIDs::closeAllDocuments:
  261. result.setInfo ("Close All Documents", "Closes all open documents", CommandCategories::general, 0);
  262. result.setActive (OpenDocumentManager::getInstance()->getNumOpenDocuments() > 0);
  263. break;
  264. case CommandIDs::saveAll:
  265. result.setInfo ("Save All", "Saves all open documents", CommandCategories::general, 0);
  266. result.setActive (OpenDocumentManager::getInstance()->anyFilesNeedSaving());
  267. break;
  268. case CommandIDs::showJuceVersion:
  269. result.setInfo ("Download the latest JUCE version", "Checks online for any Juce updates", CommandCategories::general, 0);
  270. break;
  271. default:
  272. JUCEApplication::getCommandInfo (commandID, result);
  273. break;
  274. }
  275. }
  276. bool perform (const InvocationInfo& info)
  277. {
  278. switch (info.commandID)
  279. {
  280. case CommandIDs::newProject: createNewProject(); break;
  281. case CommandIDs::open: askUserToOpenFile(); break;
  282. case CommandIDs::showPrefs: showPrefsPanel(); break;
  283. case CommandIDs::saveAll: OpenDocumentManager::getInstance()->saveAll(); break;
  284. case CommandIDs::closeAllDocuments: closeAllDocuments (true); break;
  285. case CommandIDs::showJuceVersion: JuceUpdater::show (mainWindows[0]); break;
  286. default: return JUCEApplication::perform (info);
  287. }
  288. return true;
  289. }
  290. //==============================================================================
  291. void showPrefsPanel()
  292. {
  293. jassertfalse;
  294. }
  295. void createNewProject()
  296. {
  297. MainWindow* mw = createNewMainWindow (false);
  298. ScopedPointer <Project> newProj (NewProjectWizard::runNewProjectWizard (mw));
  299. if (newProj != 0)
  300. {
  301. mw->setProject (newProj.release());
  302. mw->setVisible (true);
  303. }
  304. else
  305. {
  306. closeWindow (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. for (int j = mainWindows.size(); --j >= 0;)
  318. {
  319. if (mainWindows.getUnchecked(j)->getProject() != 0
  320. && mainWindows.getUnchecked(j)->getProject()->getFile() == file)
  321. {
  322. mainWindows.getUnchecked(j)->toFront (true);
  323. return true;
  324. }
  325. }
  326. if (file.hasFileExtension (Project::projectFileExtension))
  327. {
  328. ScopedPointer <Project> newDoc (new Project (file));
  329. if (file == File::nonexistent ? newDoc->loadFromUserSpecifiedFile (true)
  330. : newDoc->loadFrom (file, true))
  331. {
  332. MainWindow* w = getOrCreateEmptyWindow (false);
  333. w->setProject (newDoc.release());
  334. w->restoreWindowPosition();
  335. w->setVisible (true);
  336. return true;
  337. }
  338. }
  339. else if (file.exists())
  340. {
  341. return getOrCreateFrontmostWindow (true)->openFile (file);
  342. }
  343. return false;
  344. }
  345. bool closeAllDocuments (bool askUserToSave)
  346. {
  347. for (int i = OpenDocumentManager::getInstance()->getNumOpenDocuments(); --i >= 0;)
  348. {
  349. OpenDocumentManager::Document* doc = OpenDocumentManager::getInstance()->getOpenDocument (i);
  350. for (int j = mainWindows.size(); --j >= 0;)
  351. mainWindows.getUnchecked(j)->getProjectContentComponent()->hideDocument (doc);
  352. if (! OpenDocumentManager::getInstance()->closeDocument (i, askUserToSave))
  353. return false;
  354. }
  355. return true;
  356. }
  357. void updateRecentProjectList()
  358. {
  359. Array<File> projects;
  360. for (int i = 0; i < mainWindows.size(); ++i)
  361. {
  362. MainWindow* mw = mainWindows[i];
  363. if (mw != 0 && mw->getProject() != 0)
  364. projects.add (mw->getProject()->getFile());
  365. }
  366. StoredSettings::getInstance()->setLastProjects (projects);
  367. }
  368. ScopedPointer<MainMenuModel> menuModel;
  369. private:
  370. OwnedArray <MainWindow> mainWindows;
  371. MainWindow* createNewMainWindow (bool makeVisible)
  372. {
  373. MainWindow* mw = new MainWindow();
  374. for (int i = mainWindows.size(); --i >= 0;)
  375. if (mw->getBounds() == mainWindows.getUnchecked(i)->getBounds())
  376. mw->setBounds (mw->getBounds().translated (20, 20));
  377. mainWindows.add (mw);
  378. if (makeVisible)
  379. mw->setVisible (true);
  380. mw->restoreWindowPosition();
  381. return mw;
  382. }
  383. MainWindow* getOrCreateFrontmostWindow (bool makeVisible)
  384. {
  385. if (mainWindows.size() == 0)
  386. return createNewMainWindow (makeVisible);
  387. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
  388. {
  389. MainWindow* mw = dynamic_cast <MainWindow*> (Desktop::getInstance().getComponent (i));
  390. if (mainWindows.contains (mw))
  391. return mw;
  392. }
  393. return mainWindows.getLast();
  394. }
  395. MainWindow* getOrCreateEmptyWindow (bool makeVisible)
  396. {
  397. if (mainWindows.size() == 0)
  398. return createNewMainWindow (makeVisible);
  399. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
  400. {
  401. MainWindow* mw = dynamic_cast <MainWindow*> (Desktop::getInstance().getComponent (i));
  402. if (mainWindows.contains (mw) && mw->getProject() == 0)
  403. return mw;
  404. }
  405. return createNewMainWindow (makeVisible);
  406. }
  407. };
  408. #endif // __JUCER_APPLICATION_H_6595C2A8__