|
- /*
- ==============================================================================
-
- 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&) {}
|