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.

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