| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2013 - Raw Material Software 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),
 -           addWebModuleButton ("Download and add a module..."),
 -           updateModuleButton ("Install updates to modules..."),
 -           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 ("Installed Version", versionCol, 100, 100, 100, TableHeaderComponent::notSortable);
 -         table.getHeader().addColumn ("Available Version", updateCol, 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);
 - 
 -         addAndMakeVisible (addWebModuleButton);
 -         addAndMakeVisible (updateModuleButton);
 -         addAndMakeVisible (setCopyModeButton);
 -         addAndMakeVisible (copyPathButton);
 -         addWebModuleButton.addListener (this);
 -         updateModuleButton.addListener (this);
 -         updateModuleButton.setEnabled (false);
 -         setCopyModeButton.addListener (this);
 -         setCopyModeButton.setTriggeredOnMouseDown (true);
 -         copyPathButton.addListener (this);
 -         copyPathButton.setTriggeredOnMouseDown (true);
 - 
 -         modulesValueTree.addListener (this);
 -         lookAndFeelChanged();
 -     }
 - 
 -     void paint (Graphics& g) override
 -     {
 -         if (webUpdateThread == nullptr)
 -             webUpdateThread = new WebsiteUpdateFetchThread (*this);
 - 
 -         IntrojucerLookAndFeel::fillWithBackgroundTexture (*this, g);
 -     }
 - 
 -     void resized() override
 -     {
 -         Rectangle<int> r (getLocalBounds().reduced (5, 4));
 - 
 -         table.setBounds (r.removeFromTop (table.getRowPosition (getNumRows() - 1, true).getBottom() + 20));
 - 
 -         Rectangle<int> buttonRow (r.removeFromTop (32).removeFromBottom (28));
 -         addWebModuleButton.setBounds (buttonRow.removeFromLeft (jmin (260, r.getWidth() / 3)));
 -         buttonRow.removeFromLeft (8);
 -         updateModuleButton.setBounds (buttonRow.removeFromLeft (jmin (260, r.getWidth() / 3)));
 -         buttonRow.removeFromLeft (8);
 - 
 -         buttonRow = r.removeFromTop (34).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 == updateCol)
 -         {
 -             if (listFromWebsite != nullptr)
 -             {
 -                 if (const ModuleDescription* m = listFromWebsite->getModuleWithID (moduleID))
 -                 {
 -                     if (m->getVersion() != project.getModules().getModuleInfo (moduleID).getVersion())
 -                         text = m->getVersion() +  " available";
 -                     else
 -                         text = "Up-to-date";
 -                 }
 -                 else
 -                     text = "?";
 -             }
 -             else
 -             {
 -                 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<int> (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<ProjectContentComponent>())
 -                 pcc->showModule (moduleID);
 -     }
 - 
 -     void deleteKeyPressed (int row) override
 -     {
 -         project.getModules().removeModule (project.getModules().getModuleID (row));
 -     }
 - 
 -     void webUpdateFinished (const ModuleList& newList)
 -     {
 -         listFromWebsite = new ModuleList (newList);
 - 
 -         table.updateContent();
 -         table.repaint();
 - 
 -         updateModuleButton.setEnabled (getUpdatableModules().size() != 0);
 -     }
 - 
 -     void buttonClicked (Button* b)
 -     {
 -         if (b == &addWebModuleButton)       showAddModuleMenu();
 -         else if (b == &updateModuleButton)  showUpdateModulesMenu();
 -         else if (b == &setCopyModeButton)   showCopyModeMenu();
 -         else if (b == ©PathButton)      showSetPathsMenu();
 -     }
 - 
 - private:
 -     enum
 -     {
 -         nameCol = 1,
 -         versionCol,
 -         updateCol,
 -         copyCol,
 -         pathCol
 -     };
 - 
 -     Project& project;
 -     ValueTree modulesValueTree;
 -     TableListBox table;
 -     TextButton addWebModuleButton, updateModuleButton, setCopyModeButton, copyPathButton;
 -     ScopedPointer<ModuleList> listFromWebsite;
 - 
 -     void valueTreePropertyChanged (ValueTree&, const Identifier&) override    { itemChanged(); }
 -     void valueTreeChildAdded (ValueTree&, ValueTree&) override                { itemChanged(); }
 -     void valueTreeChildRemoved (ValueTree&, ValueTree&) override              { itemChanged(); }
 -     void valueTreeChildOrderChanged (ValueTree&) override                     { itemChanged(); }
 -     void valueTreeParentChanged (ValueTree&) override                         { itemChanged(); }
 - 
 -     void itemChanged()
 -     {
 -         table.updateContent();
 -         resized();
 -         repaint();
 -     }
 - 
 -     StringArray getUpdatableModules() const
 -     {
 -         StringArray result;
 - 
 -         if (listFromWebsite != nullptr)
 -         {
 -             for (int i = 0; i < listFromWebsite->modules.size(); ++i)
 -             {
 -                 const ModuleDescription* m = listFromWebsite->modules.getUnchecked(i);
 -                 const String v1 (m->getVersion());
 -                 const String v2 (project.getModules().getModuleInfo (m->getID()).getVersion());
 - 
 -                 if (v1 != v2 && v1.isNotEmpty() && v2.isNotEmpty())
 -                     result.add (m->getID());
 -             }
 -         }
 - 
 -         return result;
 -     }
 - 
 -     StringArray getAddableModules() const
 -     {
 -         StringArray result;
 - 
 -         if (listFromWebsite != nullptr)
 -         {
 -             for (int i = 0; i < listFromWebsite->modules.size(); ++i)
 -             {
 -                 const ModuleDescription* m = listFromWebsite->modules.getUnchecked(i);
 - 
 -                 if (! project.getModules().isModuleEnabled (m->getID()))
 -                     result.add (m->getID());
 -             }
 -         }
 - 
 -         return result;
 -     }
 - 
 -     void showUpdateModulesMenu()
 -     {
 -         StringArray mods (getUpdatableModules());
 - 
 -         PopupMenu m;
 -         m.addItem (1000, "Update all modules");
 -         m.addSeparator();
 - 
 -         for (int i = 0; i < mods.size(); ++i)
 -             m.addItem (1 + i, "Update " + mods[i]);
 - 
 -         int res = m.showAt (&updateModuleButton);
 - 
 -         if (res > 0 && listFromWebsite != nullptr)
 -         {
 -             if (res != 1000)
 -                 mods = StringArray (mods[res - 1]);
 - 
 -             Array<ModuleDescription> modsToUpdate;
 - 
 -             for (int i = 0; i < mods.size(); ++i)
 -             {
 -                 if (const ModuleDescription* md = listFromWebsite->getModuleWithID (mods[i]))
 -                 {
 -                     ModuleDescription modToUpdate (*md);
 -                     modToUpdate.manifestFile = project.getModules().getModuleInfo (modToUpdate.getID()).manifestFile;
 -                     modsToUpdate.add (modToUpdate);
 -                 }
 -             }
 - 
 -             DownloadAndInstallThread::updateModulesFromWeb (project, modsToUpdate);
 -         }
 -     }
 - 
 -     void showAddModuleMenu()
 -     {
 -         if (listFromWebsite == nullptr)
 -         {
 -             AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
 -                                               "Couldn't contact the website!",
 -                                               "Failed to get the latest module list from juce.com - "
 -                                               "maybe network or server problems - try again soon!");
 -             return;
 -         }
 - 
 -         StringArray mods (getAddableModules());
 - 
 -         if (mods.size() == 0)
 -         {
 -             AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
 -                                               "No modules to add!",
 -                                               "Couldn't find any new modules that aren't already in your project!");
 -             return;
 -         }
 - 
 -         PopupMenu m;
 - 
 -         for (int i = 0; i < mods.size(); ++i)
 -             m.addItem (i + 1, "Install " + mods[i]);
 - 
 -         int res = m.showAt (&addWebModuleButton);
 - 
 -         if (res > 0 && listFromWebsite != nullptr)
 -             if (const ModuleDescription* md = listFromWebsite->getModuleWithID (mods[res - 1]))
 -                 DownloadAndInstallThread::addModuleFromWebsite (project, *md);
 -     }
 - 
 -     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()
 -     {
 -         EnabledModuleList& moduleList = project.getModules();
 - 
 -         const String moduleToCopy (moduleList.getModuleID (table.getSelectedRow()));
 - 
 -         if (moduleToCopy.isNotEmpty())
 -         {
 -             PopupMenu m;
 -             m.addItem (1, "Copy the paths from the module '" + moduleToCopy + "' to all other modules");
 - 
 -             int res = m.showAt (©PathButton);
 - 
 -             if (res != 0)
 -             {
 -                 for (Project::ExporterIterator exporter (project); exporter.next();)
 -                 {
 -                     for (int i = 0; i < moduleList.getNumModules(); ++i)
 -                     {
 -                         String modID = moduleList.getModuleID (i);
 - 
 -                         if (modID != moduleToCopy)
 -                             exporter->getPathForModuleValue (modID) = exporter->getPathForModuleValue (moduleToCopy).getValue();
 -                     }
 -                 }
 -             }
 - 
 -             table.repaint();
 -         }
 -         else
 -         {
 -             PopupMenu m;
 -             m.addItem (1, "Copy the paths from the selected module to all other modules", false);
 - 
 -             m.showAt (©PathButton);
 -         }
 -     }
 - 
 -     struct WebsiteUpdateFetchThread  : private Thread,
 -                                        private AsyncUpdater
 -     {
 -         WebsiteUpdateFetchThread (ModulesPanel& p)  : Thread ("Web Updater"), panel (p)
 -         {
 -             startThread (3);
 -         }
 - 
 -         ~WebsiteUpdateFetchThread()
 -         {
 -             stopThread (15000);
 -         }
 - 
 -         void run() override
 -         {
 -             static Time lastDownloadTime;
 -             static ModuleList lastList;
 - 
 -             if (Time::getCurrentTime() < lastDownloadTime + RelativeTime::minutes (2.0))
 -             {
 -                 list = lastList;
 -                 triggerAsyncUpdate();
 -             }
 -             else
 -             {
 -                 if (list.loadFromWebsite() && ! threadShouldExit())
 -                 {
 -                     lastList = list;
 -                     lastDownloadTime = Time::getCurrentTime();
 -                     triggerAsyncUpdate();
 -                 }
 -             }
 -         }
 - 
 -         void handleAsyncUpdate() override
 -         {
 -             panel.webUpdateFinished (list);
 -         }
 - 
 -     private:
 -         ModuleList list;
 -         ModulesPanel& panel;
 -     };
 - 
 -     ScopedPointer<WebsiteUpdateFetchThread> webUpdateThread;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModulesPanel)
 - };
 - 
 - //==============================================================================
 - class DownloadAndInstallThread   : public ThreadWithProgressWindow
 - {
 - public:
 -     DownloadAndInstallThread (const Array<ModuleDescription>& modulesToInstall)
 -         : ThreadWithProgressWindow ("Installing New Modules", true, true),
 -           result (Result::ok()),
 -           modules (modulesToInstall)
 -     {
 -     }
 - 
 -     static void updateModulesFromWeb (Project& project, const Array<ModuleDescription>& mods)
 -     {
 -         DownloadAndInstallThread d (mods);
 - 
 -         if (d.runThread())
 -         {
 -             if (d.result.failed())
 -             {
 -                 AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
 -                                                   "Module Install Failed",
 -                                                   d.result.getErrorMessage());
 -             }
 -             else
 -             {
 -                 for (int i = 0; i < d.modules.size(); ++i)
 -                     project.getModules().addModule (d.modules.getReference(i).manifestFile,
 -                                                     project.getModules().areMostModulesCopiedLocally());
 -             }
 -         }
 -     }
 - 
 -     static void addModuleFromWebsite (Project& project, const ModuleDescription& module)
 -     {
 -         Array<ModuleDescription> mods;
 -         mods.add (module);
 - 
 -         static File lastLocation (EnabledModuleList::findDefaultModulesFolder (project));
 - 
 -         FileChooser fc ("Select the parent folder for the new module...", lastLocation, String::empty, false);
 - 
 -         if (fc.browseForDirectory())
 -         {
 -             lastLocation = fc.getResult();
 - 
 -             if (lastLocation.getChildFile (ModuleDescription::getManifestFileName()).exists())
 -             {
 -                 AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
 -                                                   "Adding Module",
 -                                                   "You chose a folder that appears to be a module.\n\n"
 -                                                   "You need to select the *parent* folder inside which the new modules will be created.");
 -                 return;
 -             }
 - 
 -             for (int i = 0; i < mods.size(); ++i)
 -                 mods.getReference(i).manifestFile = lastLocation.getChildFile (mods.getReference(i).getID())
 -                                                                 .getChildFile (ModuleDescription::getManifestFileName());
 - 
 -             updateModulesFromWeb (project, mods);
 -         }
 -     }
 - 
 -     void run() override
 -     {
 -         for (int i = 0; i < modules.size(); ++i)
 -         {
 -             const ModuleDescription& m = modules.getReference(i);
 - 
 -             setProgress (i / (double) modules.size());
 - 
 -             MemoryBlock downloaded;
 -             result = download (m, downloaded);
 - 
 -             if (result.failed() || threadShouldExit())
 -                 break;
 - 
 -             result = unzip (m, downloaded);
 - 
 -             if (result.failed() || threadShouldExit())
 -                 break;
 -         }
 -     }
 - 
 -     Result download (const ModuleDescription& m, MemoryBlock& dest)
 -     {
 -         setStatusMessage ("Downloading " + m.getID() + "...");
 - 
 -         const ScopedPointer<InputStream> in (m.url.createInputStream (false, nullptr, nullptr, String::empty, 10000));
 - 
 -         if (in != nullptr && in->readIntoMemoryBlock (dest))
 -             return Result::ok();
 - 
 -         return Result::fail ("Failed to download from: " + m.url.toString (false));
 -     }
 - 
 -     Result unzip (const ModuleDescription& m, const MemoryBlock& data)
 -     {
 -         setStatusMessage ("Installing " + m.getID() + "...");
 - 
 -         MemoryInputStream input (data, false);
 -         ZipFile zip (input);
 - 
 -         if (zip.getNumEntries() == 0)
 -             return Result::fail ("The downloaded file wasn't a valid module file!");
 - 
 -         if (! m.getFolder().deleteRecursively())
 -             return Result::fail ("Couldn't delete the existing folder:\n" + m.getFolder().getFullPathName());
 - 
 -         return zip.uncompressTo (m.getFolder().getParentDirectory(), true);
 -     }
 - 
 -     Result result;
 -     Array<ModuleDescription> modules;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DownloadAndInstallThread)
 - };
 
 
  |