| 
							- /*
 -   ==============================================================================
 - 
 -    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 "../jucer_Headers.h"
 - #include "jucer_JuceUpdater.h"
 - #include "../Project/jucer_Module.h"
 - 
 - 
 - //==============================================================================
 - JuceUpdater::JuceUpdater (ModuleList& moduleList_, const String& message)
 -     : moduleList (moduleList_),
 -       messageLabel (String::empty, message),
 -       filenameComp ("Juce Folder", ModuleList::getLocalModulesFolder (nullptr),
 -                     true, true, false, "*", String::empty, "Select your Juce folder"),
 -       checkNowButton ("Check for available updates on the JUCE website...",
 -                       "Contacts the website to see if new modules are available"),
 -       installButton ("Download and install selected modules..."),
 -       selectAllButton ("Select/Deselect All")
 - {
 -     messageLabel.setJustificationType (Justification::centred);
 -     addAndMakeVisible (&messageLabel);
 - 
 -     addAndMakeVisible (&label);
 -     addAndMakeVisible (¤tVersionLabel);
 -     addAndMakeVisible (&filenameComp);
 -     addAndMakeVisible (&checkNowButton);
 -     addAndMakeVisible (&installButton);
 -     addAndMakeVisible (&selectAllButton);
 -     checkNowButton.addListener (this);
 -     installButton.addListener (this);
 -     selectAllButton.addListener (this);
 -     filenameComp.addListener (this);
 - 
 -     currentVersionLabel.setFont (Font (14.0f, Font::italic));
 -     label.setFont (Font (12.0f));
 -     label.setText ("Local modules folder:", false);
 - 
 -     addAndMakeVisible (&availableVersionsList);
 -     availableVersionsList.setModel (this);
 - 
 -     updateInstallButtonStatus();
 -     versionsToDownload = ValueTree ("modules");
 -     versionsToDownload.addListener (this);
 - 
 -     setSize (600, 500);
 - 
 -     checkNow();
 - }
 - 
 - JuceUpdater::~JuceUpdater()
 - {
 -     checkNowButton.removeListener (this);
 -     filenameComp.removeListener (this);
 - }
 - 
 - //==============================================================================
 - class UpdateDialogWindow : public DialogWindow
 - {
 - public:
 -     UpdateDialogWindow (JuceUpdater* updater, Component* componentToCentreAround)
 -         : DialogWindow ("JUCE Module Updater",
 -                         Colours::lightgrey, true, true)
 -     {
 -         setUsingNativeTitleBar (true);
 -         setContentOwned (updater, true);
 -         centreAroundComponent (componentToCentreAround, getWidth(), getHeight());
 -         setResizable (true, true);
 -     }
 - 
 -     void closeButtonPressed()
 -     {
 -         setVisible (false);
 -     }
 - 
 - private:
 -     JUCE_DECLARE_NON_COPYABLE (UpdateDialogWindow);
 - };
 - 
 - void JuceUpdater::show (ModuleList& moduleList, Component* mainWindow, const String& message)
 - {
 -     UpdateDialogWindow w (new JuceUpdater (moduleList, message), mainWindow);
 -     w.runModalLoop();
 - }
 - 
 - void JuceUpdater::resized()
 - {
 -     messageLabel.setBounds (20, 10, getWidth() - 40, messageLabel.getText().isEmpty() ? 0 : 30);
 - 
 -     filenameComp.setBounds (20, messageLabel.getBottom() + 20, getWidth() - 40, 22);
 -     label.setBounds (filenameComp.getX(), filenameComp.getY() - 18, filenameComp.getWidth(), 18);
 -     currentVersionLabel.setBounds (filenameComp.getX(), filenameComp.getBottom(), filenameComp.getWidth(), 25);
 -     checkNowButton.changeWidthToFitText (22);
 -     checkNowButton.setCentrePosition (getWidth() / 2, filenameComp.getBottom() + 20);
 -     availableVersionsList.setBounds (filenameComp.getX(), checkNowButton.getBottom() + 20,
 -                                      filenameComp.getWidth(),
 -                                      getHeight() - 30 - (checkNowButton.getBottom() + 20));
 -     installButton.changeWidthToFitText (22);
 -     installButton.setTopRightPosition (availableVersionsList.getRight(), getHeight() - 28);
 -     selectAllButton.setBounds (availableVersionsList.getX(),
 -                                availableVersionsList.getBottom() + 4,
 -                                installButton.getX() - availableVersionsList.getX() - 20, 22);
 - }
 - 
 - void JuceUpdater::paint (Graphics& g)
 - {
 -     g.fillAll (Colours::white);
 - }
 - 
 - void JuceUpdater::buttonClicked (Button* b)
 - {
 -     if (b == &installButton)
 -         install();
 -     else if (b == &selectAllButton)
 -         selectAll();
 -     else
 -         checkNow();
 - }
 - 
 - void JuceUpdater::refresh()
 - {
 -     availableVersionsList.updateContent();
 -     availableVersionsList.repaint();
 - }
 - 
 - class WebsiteContacterThread  : public Thread,
 -                                 private AsyncUpdater
 - {
 - public:
 -     WebsiteContacterThread (JuceUpdater& owner_, const ModuleList& latestList)
 -         : Thread ("Module updater"),
 -           owner (owner_),
 -           downloaded (latestList)
 -     {
 -         startThread();
 -     }
 - 
 -     ~WebsiteContacterThread()
 -     {
 -         stopThread (10000);
 -     }
 - 
 -     void run()
 -     {
 -         if (downloaded.loadFromWebsite())
 -             triggerAsyncUpdate();
 -         else
 -             AlertWindow::showMessageBox (AlertWindow::InfoIcon,
 -                                          "Module Update",
 -                                          "Couldn't connect to the JUCE webserver!");
 -     }
 - 
 -     void handleAsyncUpdate()
 -     {
 -         owner.backgroundUpdateComplete (downloaded);
 -     }
 - 
 - private:
 -     JuceUpdater& owner;
 -     ModuleList downloaded;
 - };
 - 
 - void JuceUpdater::checkNow()
 - {
 -     websiteContacterThread = nullptr;
 -     websiteContacterThread = new WebsiteContacterThread (*this, latestList);
 - }
 - 
 - void JuceUpdater::backgroundUpdateComplete (const ModuleList& newList)
 - {
 -     latestList = newList;
 -     websiteContacterThread = nullptr;
 - 
 -     if (latestList == moduleList)
 -         AlertWindow::showMessageBox (AlertWindow::InfoIcon,
 -                                      "Module Update",
 -                                      "No new modules are available");
 -     refresh();
 - }
 - 
 - int JuceUpdater::getNumCheckedModules() const
 - {
 -     int numChecked = 0;
 - 
 -     for (int i = latestList.modules.size(); --i >= 0;)
 -         if (versionsToDownload [latestList.modules.getUnchecked(i)->uid])
 -             ++numChecked;
 - 
 -     return numChecked;
 - }
 - 
 - bool JuceUpdater::isLatestVersion (const String& moduleID) const
 - {
 -     const ModuleList::Module* m1 = moduleList.findModuleInfo (moduleID);
 -     const ModuleList::Module* m2 = latestList.findModuleInfo (moduleID);
 - 
 -     return m1 != nullptr && m2 != nullptr && m1->version == m2->version;
 - }
 - 
 - void JuceUpdater::updateInstallButtonStatus()
 - {
 -     const int numChecked = getNumCheckedModules();
 -     installButton.setEnabled (numChecked > 0);
 -     selectAllButton.setToggleState (numChecked > latestList.modules.size() / 2, false);
 - }
 - 
 - void JuceUpdater::filenameComponentChanged (FilenameComponent*)
 - {
 -     moduleList.rescan (filenameComp.getCurrentFile());
 -     filenameComp.setCurrentFile (moduleList.getModulesFolder(), true, false);
 - 
 -     if (! ModuleList::isModulesFolder (moduleList.getModulesFolder()))
 -         currentVersionLabel.setText ("(Not a Juce folder)", false);
 -     else
 -         currentVersionLabel.setText (String::empty, false);
 - 
 -     refresh();
 - }
 - 
 - void JuceUpdater::selectAll()
 - {
 -     bool enable = getNumCheckedModules() < latestList.modules.size() / 2;
 - 
 -     versionsToDownload.removeAllProperties (nullptr);
 - 
 -     if (enable)
 -     {
 -         for (int i = latestList.modules.size(); --i >= 0;)
 -             if (! isLatestVersion (latestList.modules.getUnchecked(i)->uid))
 -                 versionsToDownload.setProperty (latestList.modules.getUnchecked(i)->uid, true, nullptr);
 -     }
 - }
 - 
 - //==============================================================================
 - int JuceUpdater::getNumRows()
 - {
 -     return latestList.modules.size();
 - }
 - 
 - void JuceUpdater::paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected)
 - {
 -     if (rowIsSelected)
 -         g.fillAll (findColour (TextEditor::highlightColourId));
 - }
 - 
 - Component* JuceUpdater::refreshComponentForRow (int rowNumber, bool isRowSelected, Component* existingComponentToUpdate)
 - {
 -     class UpdateListComponent  : public Component
 -     {
 -     public:
 -         UpdateListComponent (JuceUpdater& updater_)
 -             : updater (updater_)
 -         {
 -             addChildComponent (&toggle);
 -             toggle.setBounds ("2, 2, parent.height - 2, parent.height - 2");
 -             toggle.setWantsKeyboardFocus (false);
 -             setInterceptsMouseClicks (false, true);
 -         }
 - 
 -         void setModule (const ModuleList::Module* newModule,
 -                         const ModuleList::Module* existingModule,
 -                         const Value& value)
 -         {
 -             if (newModule != nullptr)
 -             {
 -                 toggle.getToggleStateValue().referTo (value);
 -                 toggle.setVisible (true);
 -                 toggle.setEnabled (true);
 - 
 -                 name = newModule->uid;
 -                 status = String::empty;
 - 
 -                 if (existingModule == nullptr)
 -                 {
 -                     status << " (not currently installed)";
 -                 }
 -                 else if (existingModule->version != newModule->version)
 -                 {
 -                     status << " installed: " << existingModule->version
 -                            << ", available: " << newModule->version;
 -                 }
 -                 else
 -                 {
 -                     status << " (latest version already installed: " << existingModule->version << ")";
 -                     toggle.setEnabled (false);
 -                 }
 -             }
 -             else
 -             {
 -                 name = status = String::empty;
 -                 toggle.setVisible (false);
 -             }
 -         }
 - 
 -         void paint (Graphics& g)
 -         {
 -             g.setColour (Colours::green.withAlpha (0.12f));
 - 
 -             g.fillRect (0, 1, getWidth(), getHeight() - 2);
 -             g.setColour (Colours::black);
 -             g.setFont (getHeight() * 0.7f);
 - 
 -             g.drawText (name, toggle.getRight() + 4, 0, getWidth() / 2 - toggle.getRight() - 4, getHeight(),
 -                         Justification::centredLeft, true);
 - 
 -             g.drawText (status, getWidth() / 2, 0, getWidth() / 2, getHeight(),
 -                         Justification::centredLeft, true);
 -         }
 - 
 -     private:
 -         JuceUpdater& updater;
 -         ToggleButton toggle;
 -         String name, status;
 -     };
 - 
 -     UpdateListComponent* c = dynamic_cast <UpdateListComponent*> (existingComponentToUpdate);
 -     if (c == nullptr)
 -         c = new UpdateListComponent (*this);
 - 
 -     ModuleList::Module* m = latestList.modules [rowNumber];
 - 
 -     if (m != nullptr)
 -         c->setModule (m,
 -                       moduleList.findModuleInfo (m->uid),
 -                       versionsToDownload.getPropertyAsValue (m->uid, nullptr));
 -     else
 -         c->setModule (nullptr, nullptr, Value());
 - 
 -     return c;
 - }
 - 
 - //==============================================================================
 - class InstallThread   : public ThreadWithProgressWindow
 - {
 - public:
 -     InstallThread (const ModuleList& targetList_,
 -                    const ModuleList& list_, const StringArray& itemsToInstall_)
 -         : ThreadWithProgressWindow ("Installing New Modules", true, true),
 -           result (Result::ok()),
 -           targetList (targetList_),
 -           list (list_),
 -           itemsToInstall (itemsToInstall_)
 -     {
 -     }
 - 
 -     void run()
 -     {
 -         for (int i = 0; i < itemsToInstall.size(); ++i)
 -         {
 -             const ModuleList::Module* m = list.findModuleInfo (itemsToInstall[i]);
 - 
 -             jassert (m != nullptr);
 -             if (m != nullptr)
 -             {
 -                 setProgress (i / (double) itemsToInstall.size());
 - 
 -                 MemoryBlock downloaded;
 -                 result = download (*m, downloaded);
 - 
 -                 if (result.failed())
 -                     break;
 - 
 -                 if (threadShouldExit())
 -                     break;
 - 
 -                 result = unzip (*m, downloaded);
 - 
 -                 if (result.failed())
 -                     break;
 -             }
 - 
 -             if (threadShouldExit())
 -                 break;
 -         }
 -     }
 - 
 -     Result download (const ModuleList::Module& m, MemoryBlock& dest)
 -     {
 -         setStatusMessage ("Downloading " + m.uid + "...");
 - 
 -         if (m.url.readEntireBinaryStream (dest, false))
 -             return Result::ok();
 - 
 -         return Result::fail ("Failed to download from: " + m.url.toString (false));
 -     }
 - 
 -     Result unzip (const ModuleList::Module& m, const MemoryBlock& data)
 -     {
 -         setStatusMessage ("Installing " + m.uid + "...");
 - 
 -         MemoryInputStream input (data, false);
 -         ZipFile zip (input);
 - 
 -         if (zip.getNumEntries() == 0)
 -             return Result::fail ("The downloaded file wasn't a valid module file!");
 - 
 -         return zip.uncompressTo (targetList.getModulesFolder(), true);
 -     }
 - 
 -     Result result;
 - 
 - private:
 -     ModuleList targetList, list;
 -     StringArray itemsToInstall;
 - };
 - 
 - void JuceUpdater::install()
 - {
 -     if (! moduleList.getModulesFolder().createDirectory())
 -     {
 -         AlertWindow::showMessageBox (AlertWindow::WarningIcon,
 -                                      "Module Update",
 -                                      "Couldn't create the target folder!");
 -         return;
 -     }
 - 
 -     StringArray itemsWanted;
 - 
 -     for (int i = latestList.modules.size(); --i >= 0;)
 -         if (versionsToDownload [latestList.modules.getUnchecked(i)->uid])
 -             itemsWanted.add (latestList.modules.getUnchecked(i)->uid);
 - 
 -     {
 -         InstallThread thread (moduleList, latestList, itemsWanted);
 -         thread.runThread();
 -     }
 - 
 -     moduleList.rescan();
 -     refresh();
 - }
 - 
 - void JuceUpdater::valueTreePropertyChanged (ValueTree&, const Identifier&) { updateInstallButtonStatus(); }
 - void JuceUpdater::valueTreeChildAdded (ValueTree&, ValueTree&) {}
 - void JuceUpdater::valueTreeChildRemoved (ValueTree&, ValueTree&) {}
 - void JuceUpdater::valueTreeChildOrderChanged (ValueTree&) {}
 - void JuceUpdater::valueTreeParentChanged (ValueTree&) {}
 
 
  |