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.

819 lines
27KB

  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. StringArray ProjectContentComponent::getExportersWhichCanLaunch() const
  392. {
  393. StringArray s;
  394. for (Project::ExporterIterator exporter (*project); exporter.next();)
  395. if (exporter->canLaunchProject())
  396. s.add (exporter->getName());
  397. return s;
  398. }
  399. void ProjectContentComponent::openInIDE (const String& exporterName)
  400. {
  401. if (project != nullptr)
  402. for (Project::ExporterIterator exporter (*project); exporter.next();)
  403. if (exporter->getName() == exporterName && exporter->launchProject())
  404. break;
  405. }
  406. static void openIDEMenuCallback (int result, ProjectContentComponent* comp)
  407. {
  408. if (comp != nullptr && result > 0)
  409. comp->openInIDE (comp->getExportersWhichCanLaunch() [result - 1]);
  410. }
  411. void ProjectContentComponent::openInIDE()
  412. {
  413. if (project != nullptr)
  414. {
  415. StringArray possibleExporters = getExportersWhichCanLaunch();
  416. if (possibleExporters.size() > 1)
  417. {
  418. PopupMenu menu;
  419. for (int i = 0; i < possibleExporters.size(); ++i)
  420. menu.addItem (i + 1, possibleExporters[i]);
  421. menu.showMenuAsync (PopupMenu::Options(),
  422. ModalCallbackFunction::forComponent (openIDEMenuCallback, this));
  423. }
  424. else
  425. {
  426. openInIDE (possibleExporters[0]);
  427. }
  428. }
  429. }
  430. void ProjectContentComponent::deleteSelectedTreeItems()
  431. {
  432. if (TreePanelBase* const tree = dynamic_cast<TreePanelBase*> (treeViewTabs.getCurrentContentComponent()))
  433. tree->deleteSelectedItems();
  434. }
  435. void ProjectContentComponent::updateMainWindowTitle()
  436. {
  437. if (MainWindow* mw = findParentComponentOfClass<MainWindow>())
  438. {
  439. String title;
  440. File file;
  441. bool edited = false;
  442. if (currentDocument != nullptr)
  443. {
  444. title = currentDocument->getName();
  445. edited = currentDocument->needsSaving();
  446. file = currentDocument->getFile();
  447. }
  448. if (ComponentPeer* peer = mw->getPeer())
  449. {
  450. if (! peer->setDocumentEditedStatus (edited))
  451. if (edited)
  452. title << "*";
  453. peer->setRepresentedFile (file);
  454. }
  455. mw->updateTitle (title);
  456. }
  457. }
  458. void ProjectContentComponent::showBubbleMessage (const Rectangle<int>& pos, const String& text)
  459. {
  460. addChildComponent (&bubbleMessage);
  461. bubbleMessage.setColour (BubbleComponent::backgroundColourId, Colours::white.withAlpha (0.7f));
  462. bubbleMessage.setColour (BubbleComponent::outlineColourId, Colours::black.withAlpha (0.8f));
  463. bubbleMessage.setAlwaysOnTop (true);
  464. bubbleMessage.showAt (pos, AttributedString (text), 3000, true, false);
  465. }
  466. //==============================================================================
  467. void ProjectContentComponent::showTranslationTool()
  468. {
  469. if (translationTool != nullptr)
  470. {
  471. translationTool->toFront (true);
  472. }
  473. else if (project != nullptr)
  474. {
  475. new FloatingToolWindow ("Translation File Builder",
  476. "transToolWindowPos",
  477. new TranslationToolComponent(),
  478. translationTool,
  479. 600, 700,
  480. 600, 400, 10000, 10000);
  481. }
  482. }
  483. //==============================================================================
  484. ApplicationCommandTarget* ProjectContentComponent::getNextCommandTarget()
  485. {
  486. return findFirstTargetParentComponent();
  487. }
  488. void ProjectContentComponent::getAllCommands (Array <CommandID>& commands)
  489. {
  490. const CommandID ids[] = { CommandIDs::saveDocument,
  491. CommandIDs::saveDocumentAs,
  492. CommandIDs::closeDocument,
  493. CommandIDs::saveProject,
  494. CommandIDs::closeProject,
  495. CommandIDs::openInIDE,
  496. CommandIDs::saveAndOpenInIDE,
  497. CommandIDs::showFilePanel,
  498. CommandIDs::showConfigPanel,
  499. CommandIDs::goToPreviousDoc,
  500. CommandIDs::goToNextDoc,
  501. CommandIDs::goToCounterpart,
  502. CommandIDs::deleteSelectedItem,
  503. CommandIDs::showTranslationTool };
  504. commands.addArray (ids, numElementsInArray (ids));
  505. }
  506. void ProjectContentComponent::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result)
  507. {
  508. String documentName;
  509. if (currentDocument != nullptr)
  510. documentName = " '" + currentDocument->getName().substring (0, 32) + "'";
  511. #if JUCE_MAC
  512. const ModifierKeys cmdCtrl (ModifierKeys::ctrlModifier | ModifierKeys::commandModifier);
  513. #else
  514. const ModifierKeys cmdCtrl (ModifierKeys::ctrlModifier | ModifierKeys::altModifier);
  515. #endif
  516. switch (commandID)
  517. {
  518. case CommandIDs::saveProject:
  519. result.setInfo ("Save Project",
  520. "Saves the current project",
  521. CommandCategories::general, 0);
  522. result.setActive (project != nullptr);
  523. break;
  524. case CommandIDs::closeProject:
  525. result.setInfo ("Close Project",
  526. "Closes the current project",
  527. CommandCategories::general, 0);
  528. result.setActive (project != nullptr);
  529. break;
  530. case CommandIDs::saveDocument:
  531. result.setInfo ("Save" + documentName,
  532. "Saves the current document",
  533. CommandCategories::general, 0);
  534. result.setActive (currentDocument != nullptr || project != nullptr);
  535. result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier, 0));
  536. break;
  537. case CommandIDs::saveDocumentAs:
  538. result.setInfo ("Save As...",
  539. "Saves the current document to a new location",
  540. CommandCategories::general, 0);
  541. result.setActive (currentDocument != nullptr || project != nullptr);
  542. result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0));
  543. break;
  544. case CommandIDs::closeDocument:
  545. result.setInfo ("Close" + documentName,
  546. "Closes the current document",
  547. CommandCategories::general, 0);
  548. result.setActive (contentView != nullptr);
  549. result.defaultKeypresses.add (KeyPress ('w', cmdCtrl, 0));
  550. break;
  551. case CommandIDs::goToPreviousDoc:
  552. result.setInfo ("Previous Document", "Go to previous document", CommandCategories::general, 0);
  553. result.setActive (recentDocumentList.canGoToPrevious());
  554. result.defaultKeypresses.add (KeyPress (KeyPress::leftKey, cmdCtrl, 0));
  555. break;
  556. case CommandIDs::goToNextDoc:
  557. result.setInfo ("Next Document", "Go to next document", CommandCategories::general, 0);
  558. result.setActive (recentDocumentList.canGoToNext());
  559. result.defaultKeypresses.add (KeyPress (KeyPress::rightKey, cmdCtrl, 0));
  560. break;
  561. case CommandIDs::goToCounterpart:
  562. result.setInfo ("Open corresponding header or cpp file", "Open counterpart file", CommandCategories::general, 0);
  563. result.setActive (canGoToCounterpart());
  564. result.defaultKeypresses.add (KeyPress (KeyPress::upKey, cmdCtrl, 0));
  565. break;
  566. case CommandIDs::openInIDE:
  567. #if JUCE_MAC
  568. result.setInfo ("Open in Xcode...",
  569. #elif JUCE_WINDOWS
  570. result.setInfo ("Open in Visual Studio...",
  571. #else
  572. result.setInfo ("Open as a Makefile...",
  573. #endif
  574. "Launches the project in an external IDE",
  575. CommandCategories::general, 0);
  576. result.setActive (ProjectExporter::canProjectBeLaunched (project));
  577. break;
  578. case CommandIDs::saveAndOpenInIDE:
  579. #if JUCE_MAC
  580. result.setInfo ("Save Project and Open in Xcode...",
  581. #elif JUCE_WINDOWS
  582. result.setInfo ("Save Project and Open in Visual Studio...",
  583. #else
  584. result.setInfo ("Save Project and Open as a Makefile...",
  585. #endif
  586. "Saves the project and launches it in an external IDE",
  587. CommandCategories::general, 0);
  588. result.setActive (ProjectExporter::canProjectBeLaunched (project));
  589. result.defaultKeypresses.add (KeyPress ('l', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0));
  590. break;
  591. case CommandIDs::showFilePanel:
  592. result.setInfo ("Show File Panel",
  593. "Shows the tree of files for this project",
  594. CommandCategories::general, 0);
  595. result.setActive (project != nullptr);
  596. result.defaultKeypresses.add (KeyPress ('p', ModifierKeys::commandModifier, 0));
  597. break;
  598. case CommandIDs::showConfigPanel:
  599. result.setInfo ("Show Config Panel",
  600. "Shows the build options for the project",
  601. CommandCategories::general, 0);
  602. result.setActive (project != nullptr);
  603. result.defaultKeypresses.add (KeyPress ('i', ModifierKeys::commandModifier, 0));
  604. break;
  605. case CommandIDs::deleteSelectedItem:
  606. result.setInfo ("Delete Selected File", String::empty, CommandCategories::general, 0);
  607. result.defaultKeypresses.add (KeyPress (KeyPress::deleteKey, 0, 0));
  608. result.defaultKeypresses.add (KeyPress (KeyPress::backspaceKey, 0, 0));
  609. result.setActive (dynamic_cast<TreePanelBase*> (treeViewTabs.getCurrentContentComponent()) != nullptr);
  610. break;
  611. case CommandIDs::showTranslationTool:
  612. result.setInfo ("Translation File Builder", "Shows the translation file helper tool", CommandCategories::general, 0);
  613. break;
  614. default:
  615. break;
  616. }
  617. }
  618. bool ProjectContentComponent::perform (const InvocationInfo& info)
  619. {
  620. switch (info.commandID)
  621. {
  622. case CommandIDs::saveProject:
  623. case CommandIDs::closeProject:
  624. case CommandIDs::saveDocument:
  625. case CommandIDs::saveDocumentAs:
  626. case CommandIDs::closeDocument:
  627. case CommandIDs::goToPreviousDoc:
  628. case CommandIDs::goToNextDoc:
  629. case CommandIDs::goToCounterpart:
  630. case CommandIDs::saveAndOpenInIDE:
  631. if (reinvokeCommandAfterCancellingModalComps (info))
  632. {
  633. grabKeyboardFocus(); // to force any open labels to close their text editors
  634. return true;
  635. }
  636. break;
  637. default:
  638. break;
  639. }
  640. switch (info.commandID)
  641. {
  642. case CommandIDs::saveProject: saveProject(); break;
  643. case CommandIDs::closeProject: closeProject(); break;
  644. case CommandIDs::saveDocument: saveDocument(); break;
  645. case CommandIDs::saveDocumentAs: saveAs(); break;
  646. case CommandIDs::closeDocument: closeDocument(); break;
  647. case CommandIDs::goToPreviousDoc: goToPreviousFile(); break;
  648. case CommandIDs::goToNextDoc: goToNextFile(); break;
  649. case CommandIDs::goToCounterpart: goToCounterpart(); break;
  650. case CommandIDs::showFilePanel: treeViewTabs.setCurrentTabIndex (0); break;
  651. case CommandIDs::showConfigPanel: treeViewTabs.setCurrentTabIndex (1); break;
  652. case CommandIDs::openInIDE: openInIDE(); break;
  653. case CommandIDs::deleteSelectedItem: deleteSelectedTreeItems(); break;
  654. case CommandIDs::saveAndOpenInIDE:
  655. if (saveProject())
  656. openInIDE();
  657. break;
  658. case CommandIDs::showTranslationTool: showTranslationTool(); break;
  659. default:
  660. return false;
  661. }
  662. return true;
  663. }