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.

914 lines
30KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "jucer_ProjectContentComponent.h"
  18. #include "jucer_Module.h"
  19. #include "../Application/jucer_MainWindow.h"
  20. #include "../Application/jucer_Application.h"
  21. #include "../Code Editor/jucer_SourceCodeEditor.h"
  22. #include "../Project Saving/jucer_ProjectExporter.h"
  23. #include "../Utility/jucer_TranslationTool.h"
  24. #include "../Utility/jucer_JucerTreeViewBase.h"
  25. #include "jucer_NewFileWizard.h"
  26. #include "jucer_GroupInformationComponent.h"
  27. //==============================================================================
  28. class FileTreePanel : public TreePanelBase
  29. {
  30. public:
  31. FileTreePanel (Project& p)
  32. : TreePanelBase (&p, "fileTreeState")
  33. {
  34. tree.setMultiSelectEnabled (true);
  35. setRoot (new GroupItem (p.getMainGroup()));
  36. }
  37. void updateMissingFileStatuses()
  38. {
  39. if (ProjectTreeItemBase* p = dynamic_cast<ProjectTreeItemBase*> (rootItem.get()))
  40. p->checkFileStatus();
  41. }
  42. private:
  43. #include "jucer_ProjectTree_Base.h"
  44. #include "jucer_ProjectTree_Group.h"
  45. #include "jucer_ProjectTree_File.h"
  46. };
  47. //==============================================================================
  48. class ConfigTreePanel : public TreePanelBase
  49. {
  50. public:
  51. ConfigTreePanel (Project& p)
  52. : TreePanelBase (&p, "settingsTreeState")
  53. {
  54. tree.setMultiSelectEnabled (false);
  55. setRoot (new RootItem (p));
  56. if (tree.getNumSelectedItems() == 0)
  57. tree.getRootItem()->setSelected (true, true);
  58. #if JUCE_MAC || JUCE_WINDOWS
  59. ApplicationCommandManager& commandManager = IntrojucerApp::getCommandManager();
  60. addAndMakeVisible (&openProjectButton);
  61. openProjectButton.setCommandToTrigger (&commandManager, CommandIDs::openInIDE, true);
  62. openProjectButton.setButtonText (commandManager.getNameOfCommand (CommandIDs::openInIDE));
  63. openProjectButton.setColour (TextButton::buttonColourId, Colours::white.withAlpha (0.5f));
  64. addAndMakeVisible (&saveAndOpenButton);
  65. saveAndOpenButton.setCommandToTrigger (&commandManager, CommandIDs::saveAndOpenInIDE, true);
  66. saveAndOpenButton.setButtonText (commandManager.getNameOfCommand (CommandIDs::saveAndOpenInIDE));
  67. saveAndOpenButton.setColour (TextButton::buttonColourId, Colours::white.withAlpha (0.5f));
  68. #endif
  69. }
  70. void resized()
  71. {
  72. Rectangle<int> r (getAvailableBounds());
  73. r.removeFromBottom (6);
  74. if (saveAndOpenButton.isVisible())
  75. saveAndOpenButton.setBounds (r.removeFromBottom (30).reduced (16, 4));
  76. if (openProjectButton.isVisible())
  77. openProjectButton.setBounds (r.removeFromBottom (30).reduced (16, 4));
  78. tree.setBounds (r);
  79. }
  80. void showProjectSettings()
  81. {
  82. if (ConfigTreeItemBase* root = dynamic_cast<ConfigTreeItemBase*> (rootItem.get()))
  83. if (root->isProjectSettings())
  84. root->setSelected (true, true);
  85. }
  86. void showModules()
  87. {
  88. if (ConfigTreeItemBase* mods = getModulesItem())
  89. mods->setSelected (true, true);
  90. }
  91. void showModule (const String& moduleID)
  92. {
  93. if (ConfigTreeItemBase* mods = getModulesItem())
  94. {
  95. mods->setOpen (true);
  96. for (int i = mods->getNumSubItems(); --i >= 0;)
  97. if (ModuleItem* m = dynamic_cast<ModuleItem*> (mods->getSubItem (i)))
  98. if (m->moduleID == moduleID)
  99. m->setSelected (true, true);
  100. }
  101. }
  102. TextButton openProjectButton, saveAndOpenButton;
  103. private:
  104. #include "jucer_ConfigTree_Base.h"
  105. #include "jucer_ConfigTree_Modules.h"
  106. #include "jucer_ConfigTree_Exporter.h"
  107. #include "jucer_ModulesPanel.h"
  108. ConfigTreeItemBase* getModulesItem()
  109. {
  110. if (ConfigTreeItemBase* root = dynamic_cast<ConfigTreeItemBase*> (rootItem.get()))
  111. if (root->isProjectSettings())
  112. if (ConfigTreeItemBase* mods = dynamic_cast<ConfigTreeItemBase*> (root->getSubItem (0)))
  113. if (mods->isModulesList())
  114. return mods;
  115. return nullptr;
  116. }
  117. };
  118. //==============================================================================
  119. class LogoComponent : public Component
  120. {
  121. public:
  122. LogoComponent() {}
  123. void paint (Graphics& g)
  124. {
  125. const Path& logo = getIcons().mainJuceLogo;
  126. const AffineTransform trans (RectanglePlacement (RectanglePlacement::centred)
  127. .getTransformToFit (logo.getBounds(),
  128. getLocalBounds().toFloat()));
  129. g.setColour (findColour (mainBackgroundColourId).contrasting (0.3f));
  130. g.fillPath (logo, trans);
  131. }
  132. };
  133. //==============================================================================
  134. ProjectContentComponent::ProjectContentComponent()
  135. : project (nullptr),
  136. currentDocument (nullptr),
  137. treeViewTabs (TabbedButtonBar::TabsAtTop)
  138. {
  139. setOpaque (true);
  140. setWantsKeyboardFocus (true);
  141. addAndMakeVisible (logo = new LogoComponent());
  142. treeSizeConstrainer.setMinimumWidth (200);
  143. treeSizeConstrainer.setMaximumWidth (500);
  144. treeViewTabs.setOutline (0);
  145. treeViewTabs.getTabbedButtonBar().setMinimumTabScaleFactor (0.3);
  146. IntrojucerApp::getApp().openDocumentManager.addListener (this);
  147. }
  148. ProjectContentComponent::~ProjectContentComponent()
  149. {
  150. IntrojucerApp::getApp().openDocumentManager.removeListener (this);
  151. logo = nullptr;
  152. setProject (nullptr);
  153. contentView = nullptr;
  154. removeChildComponent (&bubbleMessage);
  155. jassert (getNumChildComponents() <= 1);
  156. }
  157. void ProjectContentComponent::paint (Graphics& g)
  158. {
  159. IntrojucerLookAndFeel::fillWithBackgroundTexture (*this, g);
  160. }
  161. void ProjectContentComponent::paintOverChildren (Graphics& g)
  162. {
  163. if (resizerBar != nullptr)
  164. {
  165. const int shadowSize = 15;
  166. const int x = resizerBar->getX();
  167. ColourGradient cg (Colours::black.withAlpha (0.25f), (float) x, 0,
  168. Colours::transparentBlack, (float) (x - shadowSize), 0, false);
  169. cg.addColour (0.4, Colours::black.withAlpha (0.07f));
  170. cg.addColour (0.6, Colours::black.withAlpha (0.02f));
  171. g.setGradientFill (cg);
  172. g.fillRect (x - shadowSize, 0, shadowSize, getHeight());
  173. }
  174. }
  175. void ProjectContentComponent::resized()
  176. {
  177. Rectangle<int> r (getLocalBounds());
  178. if (treeViewTabs.isVisible())
  179. treeViewTabs.setBounds (r.removeFromLeft (treeViewTabs.getWidth()));
  180. if (resizerBar != nullptr)
  181. resizerBar->setBounds (r.withWidth (4));
  182. if (contentView != nullptr)
  183. contentView->setBounds (r);
  184. logo->setBounds (r.reduced (r.getWidth() / 4, r.getHeight() / 4));
  185. }
  186. void ProjectContentComponent::lookAndFeelChanged()
  187. {
  188. repaint();
  189. }
  190. void ProjectContentComponent::childBoundsChanged (Component* child)
  191. {
  192. if (child == &treeViewTabs)
  193. resized();
  194. }
  195. void ProjectContentComponent::setProject (Project* newProject)
  196. {
  197. if (project != newProject)
  198. {
  199. if (project != nullptr)
  200. project->removeChangeListener (this);
  201. contentView = nullptr;
  202. resizerBar = nullptr;
  203. deleteProjectTabs();
  204. project = newProject;
  205. rebuildProjectTabs();
  206. }
  207. }
  208. void ProjectContentComponent::rebuildProjectTabs()
  209. {
  210. deleteProjectTabs();
  211. if (project != nullptr)
  212. {
  213. addAndMakeVisible (&treeViewTabs);
  214. createProjectTabs();
  215. PropertiesFile& settings = project->getStoredProperties();
  216. const String lastTabName (settings.getValue ("lastTab"));
  217. int lastTabIndex = treeViewTabs.getTabNames().indexOf (lastTabName);
  218. if (lastTabIndex < 0 || lastTabIndex > treeViewTabs.getNumTabs())
  219. lastTabIndex = 1;
  220. treeViewTabs.setCurrentTabIndex (lastTabIndex);
  221. int lastTreeWidth = settings.getValue ("projectPanelWidth").getIntValue();
  222. if (lastTreeWidth < 150)
  223. lastTreeWidth = 240;
  224. treeViewTabs.setBounds (0, 0, lastTreeWidth, getHeight());
  225. addAndMakeVisible (resizerBar = new ResizableEdgeComponent (&treeViewTabs, &treeSizeConstrainer,
  226. ResizableEdgeComponent::rightEdge));
  227. resizerBar->setAlwaysOnTop (true);
  228. project->addChangeListener (this);
  229. updateMissingFileStatuses();
  230. }
  231. else
  232. {
  233. treeViewTabs.setVisible (false);
  234. }
  235. resized();
  236. }
  237. void ProjectContentComponent::createProjectTabs()
  238. {
  239. jassert (project != nullptr);
  240. const Colour tabColour (Colours::transparentBlack);
  241. treeViewTabs.addTab ("Files", tabColour, new FileTreePanel (*project), true);
  242. treeViewTabs.addTab ("Config", tabColour, new ConfigTreePanel (*project), true);
  243. }
  244. void ProjectContentComponent::deleteProjectTabs()
  245. {
  246. if (project != nullptr && treeViewTabs.isShowing())
  247. {
  248. PropertiesFile& settings = project->getStoredProperties();
  249. if (treeViewTabs.getWidth() > 0)
  250. settings.setValue ("projectPanelWidth", treeViewTabs.getWidth());
  251. if (treeViewTabs.getNumTabs() > 0)
  252. settings.setValue ("lastTab", treeViewTabs.getCurrentTabName());
  253. }
  254. treeViewTabs.clearTabs();
  255. }
  256. void ProjectContentComponent::saveTreeViewState()
  257. {
  258. for (int i = treeViewTabs.getNumTabs(); --i >= 0;)
  259. if (TreePanelBase* t = dynamic_cast<TreePanelBase*> (treeViewTabs.getTabContentComponent (i)))
  260. t->saveOpenness();
  261. }
  262. void ProjectContentComponent::saveOpenDocumentList()
  263. {
  264. if (project != nullptr)
  265. {
  266. ScopedPointer<XmlElement> xml (recentDocumentList.createXML());
  267. if (xml != nullptr)
  268. project->getStoredProperties().setValue ("lastDocs", xml);
  269. }
  270. }
  271. void ProjectContentComponent::reloadLastOpenDocuments()
  272. {
  273. if (project != nullptr)
  274. {
  275. ScopedPointer<XmlElement> xml (project->getStoredProperties().getXmlValue ("lastDocs"));
  276. if (xml != nullptr)
  277. {
  278. recentDocumentList.restoreFromXML (*project, *xml);
  279. showDocument (recentDocumentList.getCurrentDocument(), true);
  280. }
  281. }
  282. }
  283. bool ProjectContentComponent::documentAboutToClose (OpenDocumentManager::Document* document)
  284. {
  285. hideDocument (document);
  286. return true;
  287. }
  288. void ProjectContentComponent::changeListenerCallback (ChangeBroadcaster*)
  289. {
  290. updateMissingFileStatuses();
  291. }
  292. void ProjectContentComponent::updateMissingFileStatuses()
  293. {
  294. if (FileTreePanel* tree = dynamic_cast<FileTreePanel*> (treeViewTabs.getTabContentComponent (0)))
  295. tree->updateMissingFileStatuses();
  296. }
  297. bool ProjectContentComponent::showEditorForFile (const File& f, bool grabFocus)
  298. {
  299. return getCurrentFile() == f
  300. || showDocument (IntrojucerApp::getApp().openDocumentManager.openFile (project, f), grabFocus);
  301. }
  302. File ProjectContentComponent::getCurrentFile() const
  303. {
  304. return currentDocument != nullptr ? currentDocument->getFile()
  305. : File::nonexistent;
  306. }
  307. bool ProjectContentComponent::showDocument (OpenDocumentManager::Document* doc, bool grabFocus)
  308. {
  309. if (doc == nullptr)
  310. return false;
  311. if (doc->hasFileBeenModifiedExternally())
  312. doc->reloadFromFile();
  313. if (doc == getCurrentDocument() && contentView != nullptr)
  314. {
  315. if (grabFocus)
  316. contentView->grabKeyboardFocus();
  317. return true;
  318. }
  319. recentDocumentList.newDocumentOpened (doc);
  320. bool opened = setEditorComponent (doc->createEditor(), doc);
  321. if (opened && grabFocus)
  322. contentView->grabKeyboardFocus();
  323. return opened;
  324. }
  325. void ProjectContentComponent::hideEditor()
  326. {
  327. currentDocument = nullptr;
  328. contentView = nullptr;
  329. updateMainWindowTitle();
  330. IntrojucerApp::getCommandManager().commandStatusChanged();
  331. resized();
  332. }
  333. void ProjectContentComponent::hideDocument (OpenDocumentManager::Document* doc)
  334. {
  335. if (doc == currentDocument)
  336. {
  337. if (OpenDocumentManager::Document* replacement = recentDocumentList.getClosestPreviousDocOtherThan (doc))
  338. showDocument (replacement, true);
  339. else
  340. hideEditor();
  341. }
  342. }
  343. bool ProjectContentComponent::setEditorComponent (Component* editor,
  344. OpenDocumentManager::Document* doc)
  345. {
  346. if (editor != nullptr)
  347. {
  348. contentView = nullptr;
  349. contentView = editor;
  350. currentDocument = doc;
  351. addAndMakeVisible (editor);
  352. resized();
  353. updateMainWindowTitle();
  354. IntrojucerApp::getCommandManager().commandStatusChanged();
  355. return true;
  356. }
  357. updateMainWindowTitle();
  358. return false;
  359. }
  360. void ProjectContentComponent::closeDocument()
  361. {
  362. if (currentDocument != nullptr)
  363. IntrojucerApp::getApp().openDocumentManager.closeDocument (currentDocument, true);
  364. else if (contentView != nullptr)
  365. if (! goToPreviousFile())
  366. hideEditor();
  367. }
  368. static void showSaveWarning (OpenDocumentManager::Document* currentDocument)
  369. {
  370. AlertWindow::showMessageBox (AlertWindow::WarningIcon,
  371. TRANS("Save failed!"),
  372. TRANS("Couldn't save the file:")
  373. + "\n" + currentDocument->getFile().getFullPathName());
  374. }
  375. void ProjectContentComponent::saveDocument()
  376. {
  377. if (currentDocument != nullptr)
  378. {
  379. if (! currentDocument->save())
  380. showSaveWarning (currentDocument);
  381. }
  382. else
  383. saveProject();
  384. updateMainWindowTitle();
  385. }
  386. void ProjectContentComponent::saveAs()
  387. {
  388. if (currentDocument != nullptr && ! currentDocument->saveAs())
  389. showSaveWarning (currentDocument);
  390. }
  391. bool ProjectContentComponent::goToPreviousFile()
  392. {
  393. OpenDocumentManager::Document* doc = recentDocumentList.getCurrentDocument();
  394. if (doc == nullptr || doc == getCurrentDocument())
  395. doc = recentDocumentList.getPrevious();
  396. return showDocument (doc, true);
  397. }
  398. bool ProjectContentComponent::goToNextFile()
  399. {
  400. return showDocument (recentDocumentList.getNext(), true);
  401. }
  402. bool ProjectContentComponent::canGoToCounterpart() const
  403. {
  404. return currentDocument != nullptr
  405. && currentDocument->getCounterpartFile().exists();
  406. }
  407. bool ProjectContentComponent::goToCounterpart()
  408. {
  409. if (currentDocument != nullptr)
  410. {
  411. const File file (currentDocument->getCounterpartFile());
  412. if (file.exists())
  413. return showEditorForFile (file, true);
  414. }
  415. return false;
  416. }
  417. bool ProjectContentComponent::saveProject()
  418. {
  419. return project != nullptr
  420. && project->save (true, true) == FileBasedDocument::savedOk;
  421. }
  422. void ProjectContentComponent::closeProject()
  423. {
  424. if (MainWindow* const mw = findParentComponentOfClass<MainWindow>())
  425. mw->closeCurrentProject();
  426. }
  427. void ProjectContentComponent::showFilesTab()
  428. {
  429. treeViewTabs.setCurrentTabIndex (0);
  430. }
  431. void ProjectContentComponent::showConfigTab()
  432. {
  433. treeViewTabs.setCurrentTabIndex (1);
  434. }
  435. void ProjectContentComponent::showProjectSettings()
  436. {
  437. showConfigTab();
  438. if (ConfigTreePanel* const tree = dynamic_cast<ConfigTreePanel*> (treeViewTabs.getCurrentContentComponent()))
  439. tree->showProjectSettings();
  440. }
  441. void ProjectContentComponent::showModules()
  442. {
  443. showConfigTab();
  444. if (ConfigTreePanel* const tree = dynamic_cast<ConfigTreePanel*> (treeViewTabs.getCurrentContentComponent()))
  445. tree->showModules();
  446. }
  447. void ProjectContentComponent::showModule (const String& moduleID)
  448. {
  449. showConfigTab();
  450. if (ConfigTreePanel* const tree = dynamic_cast<ConfigTreePanel*> (treeViewTabs.getCurrentContentComponent()))
  451. tree->showModule (moduleID);
  452. }
  453. StringArray ProjectContentComponent::getExportersWhichCanLaunch() const
  454. {
  455. StringArray s;
  456. for (Project::ExporterIterator exporter (*project); exporter.next();)
  457. if (exporter->canLaunchProject())
  458. s.add (exporter->getName());
  459. return s;
  460. }
  461. void ProjectContentComponent::openInIDE (const String& exporterName)
  462. {
  463. if (project != nullptr)
  464. for (Project::ExporterIterator exporter (*project); exporter.next();)
  465. if (exporter->getName() == exporterName && exporter->launchProject())
  466. break;
  467. }
  468. static void openIDEMenuCallback (int result, ProjectContentComponent* comp)
  469. {
  470. if (comp != nullptr && result > 0)
  471. comp->openInIDE (comp->getExportersWhichCanLaunch() [result - 1]);
  472. }
  473. void ProjectContentComponent::openInIDE()
  474. {
  475. if (project != nullptr)
  476. {
  477. StringArray possibleExporters = getExportersWhichCanLaunch();
  478. if (possibleExporters.size() > 1)
  479. {
  480. PopupMenu menu;
  481. for (int i = 0; i < possibleExporters.size(); ++i)
  482. menu.addItem (i + 1, possibleExporters[i]);
  483. menu.showMenuAsync (PopupMenu::Options(),
  484. ModalCallbackFunction::forComponent (openIDEMenuCallback, this));
  485. }
  486. else
  487. {
  488. openInIDE (possibleExporters[0]);
  489. }
  490. }
  491. }
  492. void ProjectContentComponent::deleteSelectedTreeItems()
  493. {
  494. if (TreePanelBase* const tree = dynamic_cast<TreePanelBase*> (treeViewTabs.getCurrentContentComponent()))
  495. tree->deleteSelectedItems();
  496. }
  497. void ProjectContentComponent::updateMainWindowTitle()
  498. {
  499. if (MainWindow* mw = findParentComponentOfClass<MainWindow>())
  500. {
  501. String title;
  502. File file;
  503. bool edited = false;
  504. if (currentDocument != nullptr)
  505. {
  506. title = currentDocument->getName();
  507. edited = currentDocument->needsSaving();
  508. file = currentDocument->getFile();
  509. }
  510. if (ComponentPeer* peer = mw->getPeer())
  511. {
  512. if (! peer->setDocumentEditedStatus (edited))
  513. if (edited)
  514. title << "*";
  515. peer->setRepresentedFile (file);
  516. }
  517. mw->updateTitle (title);
  518. }
  519. }
  520. void ProjectContentComponent::showBubbleMessage (const Rectangle<int>& pos, const String& text)
  521. {
  522. addChildComponent (&bubbleMessage);
  523. bubbleMessage.setColour (BubbleComponent::backgroundColourId, Colours::white.withAlpha (0.7f));
  524. bubbleMessage.setColour (BubbleComponent::outlineColourId, Colours::black.withAlpha (0.8f));
  525. bubbleMessage.setAlwaysOnTop (true);
  526. bubbleMessage.showAt (pos, AttributedString (text), 3000, true, false);
  527. }
  528. //==============================================================================
  529. void ProjectContentComponent::showTranslationTool()
  530. {
  531. if (translationTool != nullptr)
  532. {
  533. translationTool->toFront (true);
  534. }
  535. else if (project != nullptr)
  536. {
  537. new FloatingToolWindow ("Translation File Builder",
  538. "transToolWindowPos",
  539. new TranslationToolComponent(),
  540. translationTool,
  541. 600, 700,
  542. 600, 400, 10000, 10000);
  543. }
  544. }
  545. //==============================================================================
  546. ApplicationCommandTarget* ProjectContentComponent::getNextCommandTarget()
  547. {
  548. return findFirstTargetParentComponent();
  549. }
  550. void ProjectContentComponent::getAllCommands (Array <CommandID>& commands)
  551. {
  552. const CommandID ids[] = { CommandIDs::saveDocument,
  553. CommandIDs::saveDocumentAs,
  554. CommandIDs::closeDocument,
  555. CommandIDs::saveProject,
  556. CommandIDs::closeProject,
  557. CommandIDs::openInIDE,
  558. CommandIDs::saveAndOpenInIDE,
  559. CommandIDs::showFilePanel,
  560. CommandIDs::showConfigPanel,
  561. CommandIDs::showProjectSettings,
  562. CommandIDs::showProjectModules,
  563. CommandIDs::goToPreviousDoc,
  564. CommandIDs::goToNextDoc,
  565. CommandIDs::goToCounterpart,
  566. CommandIDs::deleteSelectedItem,
  567. CommandIDs::showTranslationTool };
  568. commands.addArray (ids, numElementsInArray (ids));
  569. }
  570. void ProjectContentComponent::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result)
  571. {
  572. String documentName;
  573. if (currentDocument != nullptr)
  574. documentName = " '" + currentDocument->getName().substring (0, 32) + "'";
  575. #if JUCE_MAC
  576. const ModifierKeys cmdCtrl (ModifierKeys::ctrlModifier | ModifierKeys::commandModifier);
  577. #else
  578. const ModifierKeys cmdCtrl (ModifierKeys::ctrlModifier | ModifierKeys::altModifier);
  579. #endif
  580. switch (commandID)
  581. {
  582. case CommandIDs::saveProject:
  583. result.setInfo ("Save Project",
  584. "Saves the current project",
  585. CommandCategories::general, 0);
  586. result.setActive (project != nullptr);
  587. break;
  588. case CommandIDs::closeProject:
  589. result.setInfo ("Close Project",
  590. "Closes the current project",
  591. CommandCategories::general, 0);
  592. result.setActive (project != nullptr);
  593. break;
  594. case CommandIDs::saveDocument:
  595. result.setInfo ("Save" + documentName,
  596. "Saves the current document",
  597. CommandCategories::general, 0);
  598. result.setActive (currentDocument != nullptr || project != nullptr);
  599. result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier, 0));
  600. break;
  601. case CommandIDs::saveDocumentAs:
  602. result.setInfo ("Save As...",
  603. "Saves the current document to a new location",
  604. CommandCategories::general, 0);
  605. result.setActive (currentDocument != nullptr || project != nullptr);
  606. result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0));
  607. break;
  608. case CommandIDs::closeDocument:
  609. result.setInfo ("Close" + documentName,
  610. "Closes the current document",
  611. CommandCategories::general, 0);
  612. result.setActive (contentView != nullptr);
  613. result.defaultKeypresses.add (KeyPress ('w', cmdCtrl, 0));
  614. break;
  615. case CommandIDs::goToPreviousDoc:
  616. result.setInfo ("Previous Document", "Go to previous document", CommandCategories::general, 0);
  617. result.setActive (recentDocumentList.canGoToPrevious());
  618. result.defaultKeypresses.add (KeyPress (KeyPress::leftKey, cmdCtrl, 0));
  619. break;
  620. case CommandIDs::goToNextDoc:
  621. result.setInfo ("Next Document", "Go to next document", CommandCategories::general, 0);
  622. result.setActive (recentDocumentList.canGoToNext());
  623. result.defaultKeypresses.add (KeyPress (KeyPress::rightKey, cmdCtrl, 0));
  624. break;
  625. case CommandIDs::goToCounterpart:
  626. result.setInfo ("Open corresponding header or cpp file", "Open counterpart file", CommandCategories::general, 0);
  627. result.setActive (canGoToCounterpart());
  628. result.defaultKeypresses.add (KeyPress (KeyPress::upKey, cmdCtrl, 0));
  629. break;
  630. case CommandIDs::openInIDE:
  631. #if JUCE_MAC
  632. result.setInfo ("Open in Xcode...",
  633. #elif JUCE_WINDOWS
  634. result.setInfo ("Open in Visual Studio...",
  635. #else
  636. result.setInfo ("Open as a Makefile...",
  637. #endif
  638. "Launches the project in an external IDE",
  639. CommandCategories::general, 0);
  640. result.setActive (ProjectExporter::canProjectBeLaunched (project));
  641. break;
  642. case CommandIDs::saveAndOpenInIDE:
  643. #if JUCE_MAC
  644. result.setInfo ("Save Project and Open in Xcode...",
  645. #elif JUCE_WINDOWS
  646. result.setInfo ("Save Project and Open in Visual Studio...",
  647. #else
  648. result.setInfo ("Save Project and Open as a Makefile...",
  649. #endif
  650. "Saves the project and launches it in an external IDE",
  651. CommandCategories::general, 0);
  652. result.setActive (ProjectExporter::canProjectBeLaunched (project));
  653. result.defaultKeypresses.add (KeyPress ('l', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0));
  654. break;
  655. case CommandIDs::showFilePanel:
  656. result.setInfo ("Show File Panel",
  657. "Shows the tree of files for this project",
  658. CommandCategories::general, 0);
  659. result.setActive (project != nullptr);
  660. result.defaultKeypresses.add (KeyPress ('p', ModifierKeys::commandModifier, 0));
  661. break;
  662. case CommandIDs::showConfigPanel:
  663. result.setInfo ("Show Config Panel",
  664. "Shows the build options for the project",
  665. CommandCategories::general, 0);
  666. result.setActive (project != nullptr);
  667. result.defaultKeypresses.add (KeyPress ('i', ModifierKeys::commandModifier, 0));
  668. break;
  669. case CommandIDs::showProjectSettings:
  670. result.setInfo ("Show Project Settings",
  671. "Shows the main project options page",
  672. CommandCategories::general, 0);
  673. result.setActive (project != nullptr);
  674. result.defaultKeypresses.add (KeyPress ('i', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0));
  675. break;
  676. case CommandIDs::showProjectModules:
  677. result.setInfo ("Show Project Modules",
  678. "Shows the project's list of modules",
  679. CommandCategories::general, 0);
  680. result.setActive (project != nullptr);
  681. result.defaultKeypresses.add (KeyPress ('m', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0));
  682. break;
  683. case CommandIDs::deleteSelectedItem:
  684. result.setInfo ("Delete Selected File", String::empty, CommandCategories::general, 0);
  685. result.defaultKeypresses.add (KeyPress (KeyPress::deleteKey, 0, 0));
  686. result.defaultKeypresses.add (KeyPress (KeyPress::backspaceKey, 0, 0));
  687. result.setActive (dynamic_cast<TreePanelBase*> (treeViewTabs.getCurrentContentComponent()) != nullptr);
  688. break;
  689. case CommandIDs::showTranslationTool:
  690. result.setInfo ("Translation File Builder", "Shows the translation file helper tool", CommandCategories::general, 0);
  691. break;
  692. default:
  693. break;
  694. }
  695. }
  696. bool ProjectContentComponent::perform (const InvocationInfo& info)
  697. {
  698. switch (info.commandID)
  699. {
  700. case CommandIDs::saveProject:
  701. case CommandIDs::closeProject:
  702. case CommandIDs::saveDocument:
  703. case CommandIDs::saveDocumentAs:
  704. case CommandIDs::closeDocument:
  705. case CommandIDs::goToPreviousDoc:
  706. case CommandIDs::goToNextDoc:
  707. case CommandIDs::goToCounterpart:
  708. case CommandIDs::saveAndOpenInIDE:
  709. if (reinvokeCommandAfterCancellingModalComps (info))
  710. {
  711. grabKeyboardFocus(); // to force any open labels to close their text editors
  712. return true;
  713. }
  714. break;
  715. default:
  716. break;
  717. }
  718. switch (info.commandID)
  719. {
  720. case CommandIDs::saveProject: saveProject(); break;
  721. case CommandIDs::closeProject: closeProject(); break;
  722. case CommandIDs::saveDocument: saveDocument(); break;
  723. case CommandIDs::saveDocumentAs: saveAs(); break;
  724. case CommandIDs::closeDocument: closeDocument(); break;
  725. case CommandIDs::goToPreviousDoc: goToPreviousFile(); break;
  726. case CommandIDs::goToNextDoc: goToNextFile(); break;
  727. case CommandIDs::goToCounterpart: goToCounterpart(); break;
  728. case CommandIDs::showFilePanel: showFilesTab(); break;
  729. case CommandIDs::showConfigPanel: showConfigTab(); break;
  730. case CommandIDs::showProjectSettings: showProjectSettings(); break;
  731. case CommandIDs::showProjectModules: showModules(); break;
  732. case CommandIDs::openInIDE: openInIDE(); break;
  733. case CommandIDs::deleteSelectedItem: deleteSelectedTreeItems(); break;
  734. case CommandIDs::saveAndOpenInIDE:
  735. if (saveProject())
  736. openInIDE();
  737. break;
  738. case CommandIDs::showTranslationTool: showTranslationTool(); break;
  739. default:
  740. return false;
  741. }
  742. return true;
  743. }