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.

920 lines
30KB

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