/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-11 by Raw Material Software Ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License (Version 2), as published by the Free Software Foundation. A copy of the license is included in the JUCE distribution, or can be found online 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.rawmaterialsoftware.com/juce for more information. ============================================================================== */ #include "../Project Saving/jucer_ProjectExporter.h" #include "../Application/jucer_Application.h" #include "jucer_ConfigPage.h" #include "jucer_ModulesPanel.h" //============================================================================== void SettingsTreeViewItemBase::showSettingsPage (Component* content) { content->setComponentID (getUniqueName()); ScopedPointer comp (content); ProjectContentComponent* pcc = getProjectContentComponent(); if (pcc != nullptr) pcc->setEditorComponent (new PropertyPanelViewport (comp.release()), nullptr); } void SettingsTreeViewItemBase::closeSettingsPage() { ProjectContentComponent* pcc = getProjectContentComponent(); if (pcc != nullptr) { PropertyPanelViewport* ppv = dynamic_cast (pcc->getEditorComponent()); if (ppv != nullptr && ppv->viewport.getViewedComponent()->getComponentID() == getUniqueName()) pcc->hideEditor(); } } //============================================================================== namespace ProjectSettingsTreeClasses { class ConfigItem : public SettingsTreeViewItemBase { public: ConfigItem (const ProjectExporter::BuildConfiguration::Ptr& config_, const String& exporterName_) : config (config_), exporterName (exporterName_), configTree (config->config) { jassert (config != nullptr); configTree.addListener (this); } bool isMissing() { return false; } bool canBeSelected() const { return true; } bool mightContainSubItems() { return false; } String getUniqueName() const { return "config_" + config->getName(); } String getRenamingName() const { return getDisplayName(); } String getDisplayName() const { return config->getName(); } void setName (const String&) {} Icon getIcon() const { return Icon (getIcons().config, getContrastingColour (Colours::green, 0.5f)); } void showDocument() { showSettingsPage (new SettingsComp (config, exporterName)); } void itemOpennessChanged (bool) {} void deleteItem() { if (AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, "Delete Configuration", "Are you sure you want to delete this configuration?")) { closeSettingsPage(); config->removeFromExporter(); } } void showPopupMenu() { PopupMenu menu; menu.addItem (1, "Create a copy of this configuration"); menu.addSeparator(); menu.addItem (2, "Delete this configuration"); launchPopupMenu (menu); } void handlePopupMenuResult (int resultCode) { if (resultCode == 2) { deleteAllSelectedItems(); } else if (resultCode == 1) { for (Project::ExporterIterator exporter (config->project); exporter.next();) { if (config->config.isAChildOf (exporter.exporter->settings)) { exporter.exporter->addNewConfiguration (config); break; } } } } var getDragSourceDescription() { return getParentItem()->getUniqueName() + "||" + config->getName(); } void valueTreePropertyChanged (ValueTree&, const Identifier&) { repaintItem(); } private: ProjectExporter::BuildConfiguration::Ptr config; String exporterName; ValueTree configTree; //============================================================================== class SettingsComp : public Component { public: SettingsComp (ProjectExporter::BuildConfiguration* config, const String& exporterName) { addAndMakeVisible (&group); PropertyListBuilder props; config->createPropertyEditors (props); group.setProperties (props); group.setName (exporterName + " / " + config->getName()); parentSizeChanged(); } void parentSizeChanged() { updateSize (*this, group); } private: PropertyGroup group; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp); }; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConfigItem); }; //============================================================================== class ExporterItem : public SettingsTreeViewItemBase { public: ExporterItem (Project& project_, ProjectExporter* exporter_, int exporterIndex_) : project (project_), exporter (exporter_), configListTree (exporter->getConfigurations()), exporterIndex (exporterIndex_) { configListTree.addListener (this); jassert (exporter != nullptr); } bool canBeSelected() const { return true; } bool mightContainSubItems() { return exporter->getNumConfigurations() > 0; } String getUniqueName() const { return "exporter_" + String (exporterIndex); } String getRenamingName() const { return getDisplayName(); } String getDisplayName() const { return exporter->getName(); } void setName (const String&) {} bool isMissing() { return false; } Icon getIcon() const { return Icon (getIcons().exporter, getContrastingColour (0.5f)); } void showDocument() { showSettingsPage (new SettingsComp (exporter)); } void deleteItem() { if (AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, "Delete Exporter", "Are you sure you want to delete this export target?")) { closeSettingsPage(); ValueTree parent (exporter->settings.getParent()); parent.removeChild (exporter->settings, project.getUndoManagerFor (parent)); } } void addSubItems() { for (ProjectExporter::ConfigIterator config (*exporter); config.next();) addSubItem (new ConfigItem (config.config, exporter->getName())); } void showPopupMenu() { PopupMenu menu; menu.addItem (1, "Add a new configuration"); menu.addSeparator(); menu.addItem (2, "Delete this exporter"); launchPopupMenu (menu); } void handlePopupMenuResult (int resultCode) { if (resultCode == 2) deleteAllSelectedItems(); else if (resultCode == 1) exporter->addNewConfiguration (nullptr); } var getDragSourceDescription() { return getParentItem()->getUniqueName() + "/" + String (exporterIndex); } bool isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails) { return dragSourceDetails.description.toString().startsWith (getUniqueName()); } void itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex) { const int oldIndex = indexOfConfig (dragSourceDetails.description.toString().fromLastOccurrenceOf ("||", false, false)); if (oldIndex >= 0) configListTree.moveChild (oldIndex, insertIndex, project.getUndoManagerFor (configListTree)); } int indexOfConfig (const String& configName) { int i = 0; for (ProjectExporter::ConfigIterator config (*exporter); config.next(); ++i) if (config->getName() == configName) return i; return -1; } //============================================================================== void valueTreeChildAdded (ValueTree& parentTree, ValueTree&) { refreshIfNeeded (parentTree); } void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&) { refreshIfNeeded (parentTree); } void valueTreeChildOrderChanged (ValueTree& parentTree) { refreshIfNeeded (parentTree); } void refreshIfNeeded (ValueTree& changedTree) { if (changedTree == configListTree) refreshSubItems(); } private: Project& project; ScopedPointer exporter; ValueTree configListTree; int exporterIndex; //============================================================================== class SettingsComp : public Component { public: SettingsComp (ProjectExporter* exporter) { addAndMakeVisible (&group); PropertyListBuilder props; exporter->createPropertyEditors (props); group.setProperties (props); group.setName ("Export target: " + exporter->getName()); parentSizeChanged(); } void parentSizeChanged() { updateSize (*this, group); } private: PropertyGroup group; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp); }; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ExporterItem); }; //============================================================================== class ModulesItem : public SettingsTreeViewItemBase { public: ModulesItem (Project& project_) : project (project_) {} bool canBeSelected() const { return true; } bool mightContainSubItems() { return false; } String getUniqueName() const { return "modules"; } String getRenamingName() const { return getDisplayName(); } String getDisplayName() const { return "Modules"; } void setName (const String&) {} bool isMissing() { return false; } Icon getIcon() const { return Icon (getIcons().graph, getContrastingColour (Colours::red, 0.5f)); } void showDocument() { showSettingsPage (new SettingsComp (project)); } private: Project& project; //============================================================================== class SettingsComp : public Component { public: SettingsComp (Project& project_) : project (project_) { addAndMakeVisible (&group); PropertyListBuilder props; props.add (new ModulesPanel (project)); group.setProperties (props); group.setName ("Modules"); parentSizeChanged(); } void parentSizeChanged() { updateSize (*this, group); } private: Project& project; var lastProjectType; PropertyGroup group; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp); }; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModulesItem); }; //============================================================================== class RootItem : public SettingsTreeViewItemBase { public: RootItem (Project& project_) : project (project_), exportersTree (project_.getExporters()) { exportersTree.addListener (this); } String getRenamingName() const { return getDisplayName(); } String getDisplayName() const { return project.getTitle(); } void setName (const String&) {} bool isMissing() { return false; } Icon getIcon() const { return project.getMainGroup().getIcon().withContrastingColourTo (getBackgroundColour()); } void showDocument() { showSettingsPage (new SettingsComp (project)); } bool canBeSelected() const { return true; } bool mightContainSubItems() { return project.getNumExporters() > 0; } String getUniqueName() const { return "config_root"; } void addSubItems() { addSubItem (new ModulesItem (project)); IntrojucerApp::getApp().addExtraConfigItems (project, *this); int i = 0; for (Project::ExporterIterator exporter (project); exporter.next(); ++i) addSubItem (new ExporterItem (project, exporter.exporter.release(), i)); } void showPopupMenu() { PopupMenu menu; const StringArray exporters (ProjectExporter::getExporterNames()); for (int i = 0; i < exporters.size(); ++i) menu.addItem (i + 1, "Create a new " + exporters[i] + " target"); launchPopupMenu (menu); } void handlePopupMenuResult (int resultCode) { if (resultCode > 0) { String exporterName (ProjectExporter::getExporterNames() [resultCode - 1]); if (exporterName.isNotEmpty()) project.addNewExporter (exporterName); } } bool isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails) { return dragSourceDetails.description.toString().startsWith (getUniqueName()); } void itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex) { int oldIndex = dragSourceDetails.description.toString().getTrailingIntValue(); exportersTree.moveChild (oldIndex, jmax (0, insertIndex - 1), project.getUndoManagerFor (exportersTree)); } //============================================================================== void valueTreeChildAdded (ValueTree& parentTree, ValueTree&) { refreshIfNeeded (parentTree); } void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&) { refreshIfNeeded (parentTree); } void valueTreeChildOrderChanged (ValueTree& parentTree) { refreshIfNeeded (parentTree); } void refreshIfNeeded (ValueTree& changedTree) { if (changedTree == exportersTree) refreshSubItems(); } private: Project& project; ValueTree exportersTree; //============================================================================== class SettingsComp : public Component, private ChangeListener { public: SettingsComp (Project& project_) : project (project_) { addAndMakeVisible (&group); updatePropertyList(); project.addChangeListener (this); } ~SettingsComp() { project.removeChangeListener (this); } void parentSizeChanged() { updateSize (*this, group); } void updatePropertyList() { PropertyListBuilder props; project.createPropertyEditors (props); group.setProperties (props); group.setName ("Project Settings"); lastProjectType = project.getProjectTypeValue().getValue(); parentSizeChanged(); } void changeListenerCallback (ChangeBroadcaster*) { if (lastProjectType != project.getProjectTypeValue().getValue()) updatePropertyList(); } private: Project& project; var lastProjectType; PropertyGroup group; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp); }; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RootItem); }; } JucerTreeViewBase* createProjectConfigTreeViewRoot (Project& project) { return new ProjectSettingsTreeClasses::RootItem (project); }