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.

923 lines
30KB

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