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.

482 lines
17KB

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