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.

883 lines
29KB

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