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.

490 lines
16KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 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. #include "../jucer_Headers.h"
  19. #include "jucer_MainWindow.h"
  20. #include "jucer_OpenDocumentManager.h"
  21. #include "jucer_SourceCodeEditor.h"
  22. #include "../model/jucer_ProjectWizard.h"
  23. //==============================================================================
  24. MainWindow::MainWindow()
  25. : DocumentWindow (JUCEApplication::getInstance()->getApplicationName(),
  26. Colour::greyLevel (0.6f),
  27. DocumentWindow::allButtons)
  28. {
  29. setUsingNativeTitleBar (true);
  30. setContentComponent (new ProjectContentComponent());
  31. setApplicationCommandManagerToWatch (commandManager);
  32. #if JUCE_MAC
  33. setMacMainMenu (this);
  34. #else
  35. setMenuBar (this);
  36. #endif
  37. setResizable (true, false);
  38. centreWithSize (700, 600);
  39. // restore the last size and position from our settings file..
  40. restoreWindowStateFromString (StoredSettings::getInstance()->getProps()
  41. .getValue ("lastMainWindowPos"));
  42. // Register all the app commands..
  43. {
  44. commandManager->registerAllCommandsForTarget (JUCEApplication::getInstance());
  45. commandManager->registerAllCommandsForTarget (this);
  46. // use a temporary one of these to harvest its commands..
  47. ProjectContentComponent pcc;
  48. commandManager->registerAllCommandsForTarget (&pcc);
  49. DocumentEditorComponent dec (0);
  50. commandManager->registerAllCommandsForTarget (&dec);
  51. ComponentEditor compEd (0, 0, 0);
  52. commandManager->registerAllCommandsForTarget (&compEd);
  53. }
  54. commandManager->getKeyMappings()->resetToDefaultMappings();
  55. ScopedPointer <XmlElement> keys (StoredSettings::getInstance()->getProps().getXmlValue ("keyMappings"));
  56. if (keys != 0)
  57. commandManager->getKeyMappings()->restoreFromXml (*keys);
  58. addKeyListener (commandManager->getKeyMappings());
  59. // don't want the window to take focus when the title-bar is clicked..
  60. setWantsKeyboardFocus (false);
  61. //getPeer()->setCurrentRenderingEngine (0);
  62. }
  63. MainWindow::~MainWindow()
  64. {
  65. #if JUCE_MAC
  66. setMacMainMenu (0);
  67. #else
  68. setMenuBar (0);
  69. #endif
  70. removeKeyListener (commandManager->getKeyMappings());
  71. // save the current size and position to our settings file..
  72. StoredSettings::getInstance()->getProps()
  73. .setValue ("lastMainWindowPos", getWindowStateAsString());
  74. setContentComponent (0);
  75. currentProject = 0;
  76. }
  77. ProjectContentComponent* MainWindow::getProjectContentComponent() const
  78. {
  79. return dynamic_cast <ProjectContentComponent*> (getContentComponent());
  80. }
  81. void MainWindow::closeButtonPressed()
  82. {
  83. JUCEApplication::getInstance()->systemRequestedQuit();
  84. }
  85. bool MainWindow::closeProject (Project* project)
  86. {
  87. jassert (project == currentProject && project != 0);
  88. if (project == 0)
  89. return true;
  90. if (! OpenDocumentManager::getInstance()->closeAllDocumentsUsingProject (*project, true))
  91. return false;
  92. FileBasedDocument::SaveResult r = project->saveIfNeededAndUserAgrees();
  93. if (r == FileBasedDocument::savedOk)
  94. {
  95. setProject (0);
  96. return true;
  97. }
  98. return false;
  99. }
  100. bool MainWindow::closeCurrentProject()
  101. {
  102. return currentProject == 0 || closeProject (currentProject);
  103. }
  104. bool MainWindow::closeAllDocuments (bool askUserToSave)
  105. {
  106. for (int i = OpenDocumentManager::getInstance()->getNumOpenDocuments(); --i >= 0;)
  107. {
  108. OpenDocumentManager::Document* doc = OpenDocumentManager::getInstance()->getOpenDocument (i);
  109. getProjectContentComponent()->hideDocument (doc);
  110. if (! OpenDocumentManager::getInstance()->closeDocument (i, askUserToSave))
  111. return false;
  112. }
  113. return true;
  114. }
  115. void MainWindow::setProject (Project* newProject)
  116. {
  117. if (newProject != 0)
  118. StoredSettings::getInstance()->setLastProject (newProject->getFile());
  119. getProjectContentComponent()->setProject (newProject);
  120. currentProject = newProject;
  121. commandManager->commandStatusChanged();
  122. }
  123. void MainWindow::reloadLastProject()
  124. {
  125. openFile (StoredSettings::getInstance()->getLastProject());
  126. }
  127. void MainWindow::askUserToOpenFile()
  128. {
  129. FileChooser fc ("Open File");
  130. if (fc.browseForFileToOpen())
  131. openFile (fc.getResult());
  132. }
  133. bool MainWindow::canOpenFile (const File& file) const
  134. {
  135. return file.hasFileExtension (Project::projectFileExtension)
  136. || OpenDocumentManager::getInstance()->canOpenFile (file);
  137. }
  138. bool MainWindow::openFile (const File& file)
  139. {
  140. if (file.hasFileExtension (Project::projectFileExtension))
  141. {
  142. ScopedPointer <Project> newDoc (new Project (file));
  143. if (file == File::nonexistent ? newDoc->loadFromUserSpecifiedFile (true)
  144. : newDoc->loadFrom (file, true))
  145. {
  146. if (closeCurrentProject())
  147. {
  148. setProject (newDoc.release());
  149. return true;
  150. }
  151. }
  152. }
  153. else if (file.exists())
  154. {
  155. return getProjectContentComponent()->showEditorForFile (file);
  156. }
  157. return false;
  158. }
  159. void MainWindow::createNewProject()
  160. {
  161. ScopedPointer <Project> newProj (ProjectWizard::runNewProjectWizard (this));
  162. if (newProj != 0 && closeCurrentProject())
  163. setProject (newProj.release());
  164. }
  165. bool MainWindow::isInterestedInFileDrag (const StringArray& filenames)
  166. {
  167. for (int i = filenames.size(); --i >= 0;)
  168. if (canOpenFile (filenames[i]))
  169. return true;
  170. return false;
  171. }
  172. void MainWindow::filesDropped (const StringArray& filenames, int mouseX, int mouseY)
  173. {
  174. for (int i = filenames.size(); --i >= 0;)
  175. {
  176. const File f (filenames[i]);
  177. if (canOpenFile (f) && openFile (f))
  178. break;
  179. }
  180. }
  181. void MainWindow::activeWindowStatusChanged()
  182. {
  183. DocumentWindow::activeWindowStatusChanged();
  184. if (getProjectContentComponent() != 0)
  185. getProjectContentComponent()->updateMissingFileStatuses();
  186. OpenDocumentManager::getInstance()->reloadModifiedFiles();
  187. }
  188. void MainWindow::updateTitle (const String& documentName)
  189. {
  190. String name (JUCEApplication::getInstance()->getApplicationName());
  191. if (documentName.isNotEmpty())
  192. name = documentName + " - " + name;
  193. setName (name);
  194. }
  195. //==============================================================================
  196. const StringArray MainWindow::getMenuBarNames()
  197. {
  198. const char* const names[] = { "File", "Edit", "View", "Window", 0 };
  199. return StringArray ((const char**) names);
  200. }
  201. const PopupMenu MainWindow::getMenuForIndex (int topLevelMenuIndex,
  202. const String& menuName)
  203. {
  204. PopupMenu menu;
  205. if (topLevelMenuIndex == 0)
  206. {
  207. // "File" menu
  208. menu.addCommandItem (commandManager, CommandIDs::newProject);
  209. menu.addSeparator();
  210. menu.addCommandItem (commandManager, CommandIDs::open);
  211. PopupMenu recentFiles;
  212. StoredSettings::getInstance()->recentFiles.createPopupMenuItems (recentFiles, 100, true, true);
  213. menu.addSubMenu ("Open recent file", recentFiles);
  214. menu.addSeparator();
  215. menu.addCommandItem (commandManager, CommandIDs::closeDocument);
  216. menu.addCommandItem (commandManager, CommandIDs::saveDocument);
  217. menu.addCommandItem (commandManager, CommandIDs::saveDocumentAs);
  218. menu.addSeparator();
  219. menu.addCommandItem (commandManager, CommandIDs::closeProject);
  220. menu.addCommandItem (commandManager, CommandIDs::saveProject);
  221. menu.addCommandItem (commandManager, CommandIDs::saveProjectAs);
  222. menu.addSeparator();
  223. menu.addCommandItem (commandManager, CommandIDs::openProjectInIDE);
  224. #if ! JUCE_MAC
  225. menu.addSeparator();
  226. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit);
  227. #endif
  228. }
  229. else if (topLevelMenuIndex == 1)
  230. {
  231. // "Edit" menu
  232. menu.addCommandItem (commandManager, CommandIDs::undo);
  233. menu.addCommandItem (commandManager, CommandIDs::redo);
  234. menu.addSeparator();
  235. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
  236. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
  237. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);
  238. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
  239. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::selectAll);
  240. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::deselectAll);
  241. menu.addSeparator();
  242. menu.addCommandItem (commandManager, CommandIDs::toFront);
  243. menu.addCommandItem (commandManager, CommandIDs::toBack);
  244. menu.addSeparator();
  245. menu.addCommandItem (commandManager, CommandIDs::group);
  246. menu.addCommandItem (commandManager, CommandIDs::ungroup);
  247. menu.addSeparator();
  248. menu.addCommandItem (commandManager, CommandIDs::bringBackLostItems);
  249. }
  250. else if (topLevelMenuIndex == 2)
  251. {
  252. // "View" menu
  253. menu.addCommandItem (commandManager, CommandIDs::showProjectSettings);
  254. //menu.addCommandItem (commandManager, CommandIDs::test);
  255. menu.addSeparator();
  256. menu.addCommandItem (commandManager, CommandIDs::showGrid);
  257. menu.addCommandItem (commandManager, CommandIDs::enableSnapToGrid);
  258. /* const int currentSnapSize = getActiveDocument() != 0 ? getActiveDocument()->getSnappingGridSize() : 0;
  259. PopupMenu m;
  260. for (int i = 0; i < numElementsInArray (snapSizes); ++i)
  261. m.addItem (300 + i, String (snapSizes[i]) + " pixels", true, snapSizes[i] == currentSnapSize);
  262. menu.addSubMenu ("Grid size", m, getActiveDocument() != 0);*/
  263. menu.addSeparator();
  264. menu.addCommandItem (commandManager, CommandIDs::zoomIn);
  265. menu.addCommandItem (commandManager, CommandIDs::zoomOut);
  266. menu.addCommandItem (commandManager, CommandIDs::zoomNormal);
  267. /* menu.addSeparator();
  268. PopupMenu overlays;
  269. overlays.addCommandItem (commandManager, CommandIDs::compOverlay0);
  270. overlays.addCommandItem (commandManager, CommandIDs::compOverlay33);
  271. overlays.addCommandItem (commandManager, CommandIDs::compOverlay66);
  272. overlays.addCommandItem (commandManager, CommandIDs::compOverlay100);
  273. menu.addSubMenu ("Component Overlay", overlays,
  274. getActiveDocument() != 0 && getActiveDocument()->getComponentLayout() != 0);*/
  275. menu.addSeparator();
  276. menu.addCommandItem (commandManager, CommandIDs::useTabbedWindows);
  277. //menu.addSeparator();
  278. //menu.addCommandItem (commandManager, CommandIDs::showPrefs);
  279. }
  280. else if (topLevelMenuIndex == 3)
  281. {
  282. // "Window" menu
  283. const int numDocs = jmin (50, OpenDocumentManager::getInstance()->getNumOpenDocuments());
  284. for (int i = 0; i < numDocs; ++i)
  285. {
  286. OpenDocumentManager::Document* doc = OpenDocumentManager::getInstance()->getOpenDocument(i);
  287. menu.addItem (300 + i, doc->getName());
  288. }
  289. menu.addSeparator();
  290. menu.addCommandItem (commandManager, CommandIDs::closeAllDocuments);
  291. }
  292. return menu;
  293. }
  294. void MainWindow::menuItemSelected (int menuItemID,
  295. int topLevelMenuIndex)
  296. {
  297. if (menuItemID >= 100 && menuItemID < 200)
  298. {
  299. // open a file from the "recent files" menu
  300. const File file (StoredSettings::getInstance()->recentFiles.getFile (menuItemID - 100));
  301. openFile (file);
  302. }
  303. else if (menuItemID == 201)
  304. {
  305. LookAndFeel::setDefaultLookAndFeel (0);
  306. }
  307. else if (menuItemID >= 300 && menuItemID < 400)
  308. {
  309. OpenDocumentManager::Document* doc = OpenDocumentManager::getInstance()->getOpenDocument (menuItemID - 300);
  310. getProjectContentComponent()->showDocument (doc);
  311. }
  312. }
  313. //==============================================================================
  314. ApplicationCommandTarget* MainWindow::getNextCommandTarget()
  315. {
  316. return 0;
  317. }
  318. void MainWindow::getAllCommands (Array <CommandID>& commands)
  319. {
  320. const CommandID ids[] = { CommandIDs::newProject,
  321. CommandIDs::open,
  322. CommandIDs::showPrefs,
  323. CommandIDs::closeAllDocuments,
  324. CommandIDs::saveAll };
  325. commands.addArray (ids, numElementsInArray (ids));
  326. }
  327. void MainWindow::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result)
  328. {
  329. switch (commandID)
  330. {
  331. case CommandIDs::newProject:
  332. result.setInfo ("New Project...",
  333. "Creates a new Jucer project",
  334. CommandCategories::general, 0);
  335. result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
  336. break;
  337. case CommandIDs::open:
  338. result.setInfo ("Open...",
  339. "Opens a Jucer project",
  340. CommandCategories::general, 0);
  341. result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
  342. break;
  343. case CommandIDs::showPrefs:
  344. result.setInfo ("Preferences...",
  345. "Shows the preferences panel.",
  346. CommandCategories::general, 0);
  347. result.defaultKeypresses.add (KeyPress (',', ModifierKeys::commandModifier, 0));
  348. break;
  349. case CommandIDs::closeAllDocuments:
  350. result.setInfo ("Close All Documents",
  351. "Closes all open documents",
  352. CommandCategories::general, 0);
  353. result.setActive (OpenDocumentManager::getInstance()->getNumOpenDocuments() > 0);
  354. break;
  355. case CommandIDs::saveAll:
  356. result.setInfo ("Save All",
  357. "Saves all open documents",
  358. CommandCategories::general, 0);
  359. result.setActive (OpenDocumentManager::getInstance()->anyFilesNeedSaving());
  360. break;
  361. default:
  362. break;
  363. }
  364. }
  365. bool MainWindow::perform (const InvocationInfo& info)
  366. {
  367. switch (info.commandID)
  368. {
  369. case CommandIDs::newProject:
  370. createNewProject();
  371. break;
  372. case CommandIDs::open:
  373. askUserToOpenFile();
  374. break;
  375. case CommandIDs::showPrefs:
  376. // PrefsPanel::show();
  377. break;
  378. case CommandIDs::saveAll:
  379. OpenDocumentManager::getInstance()->saveAll();
  380. break;
  381. case CommandIDs::closeAllDocuments:
  382. closeAllDocuments (true);
  383. break;
  384. default:
  385. return false;
  386. }
  387. return true;
  388. }