/* ============================================================================== This file is part of the JUCE library. Copyright (c) 2015 - ROLI Ltd. Permission is granted to use this software under the terms of either: a) the GPL v2 (or any later version) b) the Affero GPL v3 Details of these licenses can be found at: www.gnu.org/licenses JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.juce.com for more information. ============================================================================== */ class ModulesPanel : public Component, private TableListBoxModel, private ValueTree::Listener, private Button::Listener { public: ModulesPanel (Project& p) : project (p), modulesValueTree (p.getModules().state), setCopyModeButton ("Set copy-mode for all modules..."), copyPathButton ("Set paths for all modules...") { table.getHeader().addColumn ("Module", nameCol, 180, 100, 400, TableHeaderComponent::notSortable); table.getHeader().addColumn ("Version", versionCol, 100, 100, 100, TableHeaderComponent::notSortable); table.getHeader().addColumn ("Make Local Copy", copyCol, 100, 100, 100, TableHeaderComponent::notSortable); table.getHeader().addColumn ("Paths", pathCol, 250, 100, 600, TableHeaderComponent::notSortable); table.setModel (this); table.setColour (TableListBox::backgroundColourId, Colours::transparentBlack); addAndMakeVisible (table); table.updateContent(); table.setRowHeight (20); table.setMultipleSelectionEnabled (true); addAndMakeVisible (setCopyModeButton); addAndMakeVisible (copyPathButton); setCopyModeButton.addListener (this); setCopyModeButton.setTriggeredOnMouseDown (true); copyPathButton.addListener (this); copyPathButton.setTriggeredOnMouseDown (true); modulesValueTree.addListener (this); lookAndFeelChanged(); } void paint (Graphics& g) override { ProjucerLookAndFeel::fillWithBackgroundTexture (*this, g); } void resized() override { Rectangle r (getLocalBounds().reduced (5, 4)); table.setBounds (r.removeFromTop (table.getRowPosition (getNumRows() - 1, true).getBottom() + 20)); Rectangle buttonRow (r.removeFromTop (32).removeFromBottom (28)); setCopyModeButton.setBounds (buttonRow.removeFromLeft (jmin (260, r.getWidth() / 3))); buttonRow.removeFromLeft (8); copyPathButton.setBounds (buttonRow.removeFromLeft (jmin (260, r.getWidth() / 3))); } int getNumRows() override { return project.getModules().getNumModules(); } void paintRowBackground (Graphics& g, int /*rowNumber*/, int width, int height, bool rowIsSelected) override { g.setColour (rowIsSelected ? Colours::lightblue.withAlpha (0.4f) : Colours::white.withAlpha (0.4f)); g.fillRect (0, 0, width, height - 1); } void paintCell (Graphics& g, int rowNumber, int columnId, int width, int height, bool /*rowIsSelected*/) override { String text; const String moduleID (project.getModules().getModuleID (rowNumber)); if (columnId == nameCol) { text = moduleID; } else if (columnId == versionCol) { text = project.getModules().getModuleInfo (moduleID).getVersion(); if (text.isEmpty()) text = "?"; } else if (columnId == copyCol) { text = project.getModules().shouldCopyModuleFilesLocally (moduleID).getValue() ? "Yes" : "No"; } else if (columnId == pathCol) { StringArray paths; for (Project::ExporterIterator exporter (project); exporter.next();) paths.addIfNotAlreadyThere (exporter->getPathForModuleString (moduleID).trim()); text = paths.joinIntoString (", "); } g.setColour (Colours::black); g.setFont (height * 0.65f); g.drawText (text, Rectangle (width, height).reduced (4, 0), Justification::centredLeft, true); } void cellDoubleClicked (int rowNumber, int, const MouseEvent&) override { const String moduleID (project.getModules().getModuleID (rowNumber)); if (moduleID.isNotEmpty()) if (ProjectContentComponent* pcc = findParentComponentOfClass()) pcc->showModule (moduleID); } void deleteKeyPressed (int row) override { project.getModules().removeModule (project.getModules().getModuleID (row)); } void buttonClicked (Button* b) override { if (b == &setCopyModeButton) showCopyModeMenu(); if (b == ©PathButton) showSetPathsMenu(); } private: enum { nameCol = 1, versionCol, copyCol, pathCol }; Project& project; ValueTree modulesValueTree; TableListBox table; TextButton setCopyModeButton, copyPathButton; std::map modulePathClipboard; void valueTreePropertyChanged (ValueTree&, const Identifier&) override { itemChanged(); } void valueTreeChildAdded (ValueTree&, ValueTree&) override { itemChanged(); } void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override { itemChanged(); } void valueTreeChildOrderChanged (ValueTree&, int, int) override { itemChanged(); } void valueTreeParentChanged (ValueTree&) override { itemChanged(); } void itemChanged() { table.updateContent(); resized(); repaint(); } void showCopyModeMenu() { PopupMenu m; m.addItem (1, "Set all modules to copy locally"); m.addItem (2, "Set all modules to not copy locally"); int res = m.showAt (&setCopyModeButton); if (res != 0) project.getModules().setLocalCopyModeForAllModules (res == 1); } void showSetPathsMenu() { enum { copyPathsToAllModulesID = 1, copyPathsID, pastePathsID }; auto& moduleList = project.getModules(); auto moduleToCopy = moduleList.getModuleID (table.getSelectedRow()); if (moduleToCopy.isNotEmpty()) { PopupMenu m; m.addItem (copyPathsToAllModulesID, "Copy the paths from the module '" + moduleToCopy + "' to all other modules"); m.addItem (copyPathsID, "Copy paths from selected module", table.getNumSelectedRows() == 1); m.addItem (pastePathsID, "Paste paths to selected modules", ! modulePathClipboard.empty()); int res = m.showAt (©PathButton); if (res == copyPathsToAllModulesID) { for (Project::ExporterIterator exporter (project); exporter.next();) { for (int i = 0; i < moduleList.getNumModules(); ++i) { auto modID = moduleList.getModuleID (i); if (modID != moduleToCopy) exporter->getPathForModuleValue (modID) = exporter->getPathForModuleValue (moduleToCopy).getValue(); } } } else if (res == copyPathsID) { modulePathClipboard.clear(); for (Project::ExporterIterator exporter (project); exporter.next();) modulePathClipboard[exporter->getName()] = exporter->getPathForModuleValue (moduleToCopy).getValue(); } else if (res == pastePathsID) { for (int selectionId = 0; selectionId < table.getNumSelectedRows(); ++selectionId) { auto rowNumber = table.getSelectedRow (selectionId); auto modID = moduleList.getModuleID (rowNumber); for (Project::ExporterIterator exporter (project); exporter.next();) exporter->getPathForModuleValue (modID) = modulePathClipboard[exporter->getName()]; } } table.repaint(); } else { PopupMenu m; m.addItem (1, "(Select a module in the list above to use this option)", false); m.showAt (©PathButton); } } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModulesPanel) };