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.

508 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. //==============================================================================
  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. 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 (mainWindows.size() == 0)
  60. createNewMainWindow()->makeVisible();
  61. #if JUCE_MAC
  62. MenuBarModel::setMacMainMenu (menuModel);
  63. #endif
  64. }
  65. void shutdown()
  66. {
  67. #if JUCE_MAC
  68. MenuBarModel::setMacMainMenu (nullptr);
  69. #endif
  70. menuModel = nullptr;
  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 String (ProjectInfo::projectName) + " " + 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. MainWindow* w = getApp()->getOrCreateFrontmostWindow();
  225. w->makeVisible();
  226. w->getProjectContentComponent()->showDocument (doc);
  227. }
  228. }
  229. private:
  230. JucerApplication* getApp() const
  231. {
  232. return static_cast<JucerApplication*> (JUCEApplication::getInstance());
  233. }
  234. };
  235. //==============================================================================
  236. void getAllCommands (Array <CommandID>& commands)
  237. {
  238. JUCEApplication::getAllCommands (commands);
  239. const CommandID ids[] = { CommandIDs::newProject,
  240. CommandIDs::open,
  241. CommandIDs::showPrefs,
  242. CommandIDs::closeAllDocuments,
  243. CommandIDs::saveAll,
  244. CommandIDs::showJuceVersion };
  245. commands.addArray (ids, numElementsInArray (ids));
  246. }
  247. void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result)
  248. {
  249. switch (commandID)
  250. {
  251. case CommandIDs::newProject:
  252. result.setInfo ("New Project...", "Creates a new Jucer project", CommandCategories::general, 0);
  253. result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
  254. break;
  255. case CommandIDs::open:
  256. result.setInfo ("Open...", "Opens a Jucer project", CommandCategories::general, 0);
  257. result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
  258. break;
  259. case CommandIDs::showPrefs:
  260. result.setInfo ("Preferences...", "Shows the preferences panel.", CommandCategories::general, 0);
  261. result.defaultKeypresses.add (KeyPress (',', ModifierKeys::commandModifier, 0));
  262. break;
  263. case CommandIDs::closeAllDocuments:
  264. result.setInfo ("Close All Documents", "Closes all open documents", CommandCategories::general, 0);
  265. result.setActive (OpenDocumentManager::getInstance()->getNumOpenDocuments() > 0);
  266. break;
  267. case CommandIDs::saveAll:
  268. result.setInfo ("Save All", "Saves all open documents", CommandCategories::general, 0);
  269. result.setActive (OpenDocumentManager::getInstance()->anyFilesNeedSaving());
  270. break;
  271. case CommandIDs::showJuceVersion:
  272. result.setInfo ("Download the latest JUCE version", "Checks online for any Juce updates", CommandCategories::general, 0);
  273. break;
  274. default:
  275. JUCEApplication::getCommandInfo (commandID, result);
  276. break;
  277. }
  278. }
  279. bool perform (const InvocationInfo& info)
  280. {
  281. switch (info.commandID)
  282. {
  283. case CommandIDs::newProject: createNewProject(); break;
  284. case CommandIDs::open: askUserToOpenFile(); break;
  285. case CommandIDs::showPrefs: showPrefsPanel(); break;
  286. case CommandIDs::saveAll: OpenDocumentManager::getInstance()->saveAll(); break;
  287. case CommandIDs::closeAllDocuments: closeAllDocuments (true); break;
  288. case CommandIDs::showJuceVersion: JuceUpdater::show (mainWindows[0]); break;
  289. default: return JUCEApplication::perform (info);
  290. }
  291. return true;
  292. }
  293. //==============================================================================
  294. void showPrefsPanel()
  295. {
  296. jassertfalse;
  297. }
  298. void createNewProject()
  299. {
  300. MainWindow* mw = createNewMainWindow();
  301. ScopedPointer <Project> newProj (NewProjectWizard::runNewProjectWizard (mw));
  302. if (newProj != nullptr)
  303. {
  304. mw->setProject (newProj.release());
  305. mw->makeVisible();
  306. }
  307. else
  308. {
  309. closeWindow (mw);
  310. }
  311. }
  312. void askUserToOpenFile()
  313. {
  314. FileChooser fc ("Open File");
  315. if (fc.browseForFileToOpen())
  316. openFile (fc.getResult());
  317. }
  318. bool openFile (const File& file)
  319. {
  320. for (int j = mainWindows.size(); --j >= 0;)
  321. {
  322. if (mainWindows.getUnchecked(j)->getProject() != nullptr
  323. && mainWindows.getUnchecked(j)->getProject()->getFile() == file)
  324. {
  325. mainWindows.getUnchecked(j)->toFront (true);
  326. return true;
  327. }
  328. }
  329. if (file.hasFileExtension (Project::projectFileExtension))
  330. {
  331. ScopedPointer <Project> newDoc (new Project (file));
  332. if (newDoc->loadFrom (file, true))
  333. {
  334. MainWindow* w = getOrCreateEmptyWindow();
  335. w->setProject (newDoc.release());
  336. w->makeVisible();
  337. return true;
  338. }
  339. }
  340. else if (file.exists())
  341. {
  342. MainWindow* w = getOrCreateFrontmostWindow();
  343. const bool ok = w->openFile (file);
  344. w->makeVisible();
  345. return ok;
  346. }
  347. return false;
  348. }
  349. bool closeAllDocuments (bool askUserToSave)
  350. {
  351. for (int i = OpenDocumentManager::getInstance()->getNumOpenDocuments(); --i >= 0;)
  352. {
  353. OpenDocumentManager::Document* doc = OpenDocumentManager::getInstance()->getOpenDocument (i);
  354. for (int j = mainWindows.size(); --j >= 0;)
  355. mainWindows.getUnchecked(j)->getProjectContentComponent()->hideDocument (doc);
  356. if (! OpenDocumentManager::getInstance()->closeDocument (i, askUserToSave))
  357. return false;
  358. }
  359. return true;
  360. }
  361. void updateRecentProjectList()
  362. {
  363. Array<File> projects;
  364. for (int i = 0; i < mainWindows.size(); ++i)
  365. {
  366. MainWindow* mw = mainWindows[i];
  367. if (mw != nullptr && mw->getProject() != nullptr)
  368. projects.add (mw->getProject()->getFile());
  369. }
  370. StoredSettings::getInstance()->setLastProjects (projects);
  371. }
  372. ScopedPointer<MainMenuModel> menuModel;
  373. private:
  374. OwnedArray <MainWindow> mainWindows;
  375. MainWindow* createNewMainWindow()
  376. {
  377. MainWindow* mw = new MainWindow();
  378. for (int i = mainWindows.size(); --i >= 0;)
  379. if (mw->getBounds() == mainWindows.getUnchecked(i)->getBounds())
  380. mw->setBounds (mw->getBounds().translated (20, 20));
  381. mainWindows.add (mw);
  382. mw->restoreWindowPosition();
  383. return mw;
  384. }
  385. MainWindow* getOrCreateFrontmostWindow()
  386. {
  387. if (mainWindows.size() == 0)
  388. return createNewMainWindow();
  389. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
  390. {
  391. MainWindow* mw = dynamic_cast <MainWindow*> (Desktop::getInstance().getComponent (i));
  392. if (mainWindows.contains (mw))
  393. return mw;
  394. }
  395. return mainWindows.getLast();
  396. }
  397. MainWindow* getOrCreateEmptyWindow()
  398. {
  399. if (mainWindows.size() == 0)
  400. return createNewMainWindow();
  401. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
  402. {
  403. MainWindow* mw = dynamic_cast <MainWindow*> (Desktop::getInstance().getComponent (i));
  404. if (mainWindows.contains (mw) && mw->getProject() == nullptr)
  405. return mw;
  406. }
  407. return createNewMainWindow();
  408. }
  409. };
  410. #endif // __JUCER_APPLICATION_JUCEHEADER__