| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2017 - ROLI Ltd.
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    By using JUCE, you agree to the terms of both the JUCE 5 End-User License
 -    Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
 -    27th April 2017).
 - 
 -    End User License Agreement: www.juce.com/juce-5-licence
 -    Privacy Policy: www.juce.com/juce-5-privacy-policy
 - 
 -    Or: You may also use this code under the terms of the GPL v3 (see
 -    www.gnu.org/licenses).
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - #include "../jucer_Headers.h"
 - #include "jucer_Application.h"
 - #include "jucer_AutoUpdater.h"
 - 
 - LatestVersionChecker::JuceVersionTriple::JuceVersionTriple()
 -   :  major ((ProjectInfo::versionNumber & 0xff0000) >> 16),
 -      minor ((ProjectInfo::versionNumber & 0x00ff00) >> 8),
 -      build ((ProjectInfo::versionNumber & 0x0000ff) >> 0)
 - {}
 - 
 - LatestVersionChecker::JuceVersionTriple::JuceVersionTriple (int juceVersionNumber)
 -   :  major ((juceVersionNumber & 0xff0000) >> 16),
 -      minor ((juceVersionNumber & 0x00ff00) >> 8),
 -      build ((juceVersionNumber & 0x0000ff) >> 0)
 - {}
 - 
 - LatestVersionChecker::JuceVersionTriple::JuceVersionTriple (int majorInt, int minorInt, int buildNumber)
 -     : major (majorInt),
 -       minor (minorInt),
 -       build (buildNumber)
 - {}
 - 
 - bool LatestVersionChecker::JuceVersionTriple::fromString (const String& versionString,
 -                                                           LatestVersionChecker::JuceVersionTriple& result)
 - {
 -     StringArray tokenizedString = StringArray::fromTokens (versionString, ".", StringRef());
 - 
 -     if (tokenizedString.size() != 3)
 -         return false;
 - 
 -     result.major = tokenizedString [0].getIntValue();
 -     result.minor = tokenizedString [1].getIntValue();
 -     result.build = tokenizedString [2].getIntValue();
 - 
 -     return true;
 - }
 - 
 - String LatestVersionChecker::JuceVersionTriple::toString() const
 - {
 -     String retval;
 -     retval << major << '.' << minor << '.' << build;
 -     return retval;
 - }
 - 
 - bool LatestVersionChecker::JuceVersionTriple::operator> (const LatestVersionChecker::JuceVersionTriple& b) const noexcept
 - {
 -     if (major == b.major)
 -     {
 -         if (minor == b.minor)
 -             return build > b.build;
 - 
 -         return minor > b.minor;
 -     }
 - 
 -     return major > b.major;
 - }
 - 
 - //==============================================================================
 - struct RelaunchTimer  : private Timer
 - {
 -     RelaunchTimer (const File& f)  : parentFolder (f)
 -     {
 -         startTimer (1500);
 -     }
 - 
 -     void timerCallback() override
 -     {
 -         stopTimer();
 - 
 -         File app = parentFolder.getChildFile (
 -                       #if JUCE_MAC
 -                        "Projucer.app");
 -                       #elif JUCE_WINDOWS
 -                        "Projucer.exe");
 -                       #elif JUCE_LINUX
 -                        "Projucer");
 -                       #endif
 - 
 -         JUCEApplication::quit();
 - 
 -         if (app.exists())
 -         {
 -             app.setExecutePermission (true);
 - 
 -            #if JUCE_MAC
 -             app.getChildFile ("Contents")
 -                .getChildFile ("MacOS")
 -                .getChildFile ("Projucer").setExecutePermission (true);
 -            #endif
 - 
 -                 app.startAsProcess();
 -         }
 - 
 -         delete this;
 -     }
 - 
 -     File parentFolder;
 - };
 - 
 - //==============================================================================
 - class DownloadNewVersionThread   : public ThreadWithProgressWindow
 - {
 - public:
 -     DownloadNewVersionThread (LatestVersionChecker& versionChecker,URL u,
 -                               const String& extraHeaders, File target)
 -         : ThreadWithProgressWindow ("Downloading New Version", true, true),
 -           owner (versionChecker),
 -           result (Result::ok()),
 -           url (u), headers (extraHeaders), targetFolder (target)
 -     {
 -     }
 - 
 -     static void performDownload (LatestVersionChecker& versionChecker, URL u,
 -                                  const String& extraHeaders, File targetFolder)
 -     {
 -         DownloadNewVersionThread d (versionChecker, u, extraHeaders, targetFolder);
 - 
 -         if (d.runThread())
 -         {
 -             if (d.result.failed())
 -             {
 -                 AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
 -                                                   "Installation Failed",
 -                                                   d.result.getErrorMessage());
 -             }
 -             else
 -             {
 -                 new RelaunchTimer (targetFolder);
 -             }
 -         }
 -     }
 - 
 -     void run() override
 -     {
 -         setProgress (-1.0);
 - 
 -         MemoryBlock zipData;
 -         result = download (zipData);
 - 
 -         if (result.wasOk() && ! threadShouldExit())
 -         {
 -             setStatusMessage ("Installing...");
 -             result = owner.performUpdate (zipData, targetFolder);
 -         }
 -     }
 - 
 -     Result download (MemoryBlock& dest)
 -     {
 -         setStatusMessage ("Downloading...");
 - 
 -         int statusCode = 302;
 -         const int maxRedirects = 5;
 - 
 -         // we need to do the redirecting manually due to inconsistencies on the way headers are handled on redirects
 -         ScopedPointer<InputStream> in;
 - 
 -         for (int redirect = 0; redirect < maxRedirects; ++redirect)
 -         {
 -             StringPairArray responseHeaders;
 - 
 -             in = url.createInputStream (false, nullptr, nullptr, headers, 10000, &responseHeaders, &statusCode, 0);
 -             if (in == nullptr || statusCode != 302)
 -                 break;
 - 
 -             String redirectPath = responseHeaders ["Location"];
 -             if (redirectPath.isEmpty())
 -                 break;
 - 
 -             url = owner.getLatestVersionURL (headers, redirectPath);
 -         }
 - 
 -         if (in != nullptr && statusCode == 200)
 -         {
 -             int64 total = 0;
 -             MemoryOutputStream mo (dest, true);
 - 
 -             for (;;)
 -             {
 -                 if (threadShouldExit())
 -                     return Result::fail ("cancel");
 - 
 -                 int64 written = mo.writeFromInputStream (*in, 8192);
 - 
 -                 if (written == 0)
 -                     break;
 - 
 -                 total += written;
 - 
 -                 setStatusMessage (String (TRANS ("Downloading...  (123)"))
 -                                   .replace ("123", File::descriptionOfSizeInBytes (total)));
 -             }
 - 
 -             return Result::ok();
 -         }
 - 
 -         return Result::fail ("Failed to download from: " + url.toString (false));
 -     }
 - 
 -     LatestVersionChecker& owner;
 -     Result result;
 -     URL url;
 -     String headers;
 -     File targetFolder;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DownloadNewVersionThread)
 - };
 - 
 - //==============================================================================
 - class UpdateUserDialog   : public Component,
 -                            public ButtonListener
 - {
 - public:
 -     UpdateUserDialog (const LatestVersionChecker::JuceVersionTriple& version,
 -                       const String& productName,
 -                       const String& releaseNotes,
 -                       const char* overwriteFolderPath)
 -         : hasOverwriteButton (overwriteFolderPath != nullptr)
 -     {
 -         addAndMakeVisible (titleLabel = new Label ("Title Label",
 -                                                    TRANS ("Download \"123\" version 456?").replace ("123", productName)
 -                                                                                           .replace ("456", version.toString())));
 - 
 -         titleLabel->setFont (Font (15.00f, Font::bold));
 -         titleLabel->setJustificationType (Justification::centredLeft);
 -         titleLabel->setEditable (false, false, false);
 - 
 -         addAndMakeVisible (contentLabel = new Label ("Content Label",
 -                                                      TRANS ("A new version of \"123\" is available - would you like to download it?")
 -                                                         .replace ("123", productName)));
 -         contentLabel->setFont (Font (15.00f, Font::plain));
 -         contentLabel->setJustificationType (Justification::topLeft);
 -         contentLabel->setEditable (false, false, false);
 - 
 -         addAndMakeVisible (okButton = new TextButton ("OK Button"));
 -         okButton->setButtonText (TRANS(hasOverwriteButton ? "Choose Another Folder..." : "OK"));
 -         okButton->addListener (this);
 - 
 -         addAndMakeVisible (cancelButton = new TextButton ("Cancel Button"));
 -         cancelButton->setButtonText (TRANS("Cancel"));
 -         cancelButton->addListener (this);
 - 
 -         addAndMakeVisible (changeLogLabel = new Label ("Change Log Label",
 -                                                        TRANS("Release Notes:")));
 -         changeLogLabel->setFont (Font (15.00f, Font::plain));
 -         changeLogLabel->setJustificationType (Justification::topLeft);
 -         changeLogLabel->setEditable (false, false, false);
 - 
 -         addAndMakeVisible (changeLog = new TextEditor ("Change Log"));
 -         changeLog->setMultiLine (true);
 -         changeLog->setReturnKeyStartsNewLine (true);
 -         changeLog->setReadOnly (true);
 -         changeLog->setScrollbarsShown (true);
 -         changeLog->setCaretVisible (false);
 -         changeLog->setPopupMenuEnabled (false);
 -         changeLog->setText (releaseNotes);
 - 
 -         if (hasOverwriteButton)
 -         {
 -             addAndMakeVisible (overwriteLabel = new Label ("Overwrite Label",
 -                                                            TRANS("Updating will overwrite everything in the following folder:")));
 -             overwriteLabel->setFont (Font (15.00f, Font::plain));
 -             overwriteLabel->setJustificationType (Justification::topLeft);
 -             overwriteLabel->setEditable (false, false, false);
 - 
 -             addAndMakeVisible (overwritePath = new Label ("Overwrite Path", overwriteFolderPath));
 -             overwritePath->setFont (Font (15.00f, Font::bold));
 -             overwritePath->setJustificationType (Justification::topLeft);
 -             overwritePath->setEditable (false, false, false);
 - 
 -             addAndMakeVisible (overwriteButton = new TextButton ("Overwrite Button"));
 -             overwriteButton->setButtonText (TRANS("Overwrite"));
 -             overwriteButton->addListener (this);
 -         }
 - 
 -         juceIcon = Drawable::createFromImageData (BinaryData::juce_icon_png,
 -                                                   BinaryData::juce_icon_pngSize);
 - 
 -         setSize (518, overwritePath ? 345 : 269);
 - 
 -         lookAndFeelChanged();
 -     }
 - 
 -     ~UpdateUserDialog()
 -     {
 -         titleLabel = nullptr;
 -         contentLabel = nullptr;
 -         okButton = nullptr;
 -         cancelButton = nullptr;
 -         changeLogLabel = nullptr;
 -         changeLog = nullptr;
 -         overwriteLabel = nullptr;
 -         overwritePath = nullptr;
 -         overwriteButton = nullptr;
 -         juceIcon = nullptr;
 -     }
 - 
 -     void paint (Graphics& g) override
 -     {
 -         g.fillAll (findColour (backgroundColourId));
 -         g.setColour (findColour (defaultTextColourId));
 - 
 -         if (juceIcon != nullptr)
 -             juceIcon->drawWithin (g, Rectangle<float> (20, 17, 64, 64),
 -                                   RectanglePlacement::stretchToFit, 1.000f);
 -     }
 - 
 -     void resized() override
 -     {
 -         titleLabel->setBounds (88, 10, 397, 24);
 -         contentLabel->setBounds (88, 40, 397, 51);
 -         changeLogLabel->setBounds (22, 92, 341, 24);
 -         changeLog->setBounds (24, 112, 476, 102);
 - 
 -         if (hasOverwriteButton)
 -         {
 -             okButton->setBounds (getWidth() - 24 - 174, getHeight() - 37, 174, 28);
 -             overwriteButton->setBounds ((getWidth() - 24 - 174) + -14 - 86, getHeight() - 37, 86, 28);
 -             cancelButton->setBounds (24, getHeight() - 37, 70, 28);
 - 
 -             overwriteLabel->setBounds (24, 238, 472, 16);
 -             overwritePath->setBounds (24, 262, 472, 40);
 -         }
 -         else
 -         {
 -             okButton->setBounds (getWidth() - 24 - 47, getHeight() - 37, 47, 28);
 -             cancelButton->setBounds ((getWidth() - 24 - 47) + -14 - 70, getHeight() - 37, 70, 28);
 -         }
 -     }
 - 
 -     void buttonClicked (Button* clickedButton) override
 -     {
 -         if (DialogWindow* parentDialog = findParentComponentOfClass<DialogWindow>())
 -         {
 -             if      (clickedButton == overwriteButton) parentDialog->exitModalState (1);
 -             else if (clickedButton == okButton)        parentDialog->exitModalState (2);
 -             else if (clickedButton == cancelButton)    parentDialog->exitModalState (-1);
 -         }
 -         else
 -             jassertfalse;
 -     }
 - 
 -     static DialogWindow* launch (const LatestVersionChecker::JuceVersionTriple& version,
 -                                  const String& productName,
 -                                  const String& releaseNotes,
 -                                  const char* overwritePath = nullptr)
 -     {
 -         OptionalScopedPointer<Component> userDialog (new UpdateUserDialog (version, productName,
 -                                                                            releaseNotes, overwritePath), true);
 - 
 -         DialogWindow::LaunchOptions lo;
 -         lo.dialogTitle = TRANS ("Download \"123\" version 456?").replace ("456", version.toString())
 -                                                                 .replace ("123", productName);
 -         lo.dialogBackgroundColour = userDialog->findColour (backgroundColourId);
 -         lo.content = userDialog;
 -         lo.componentToCentreAround = nullptr;
 -         lo.escapeKeyTriggersCloseButton = true;
 -         lo.useNativeTitleBar = true;
 -         lo.resizable = false;
 -         lo.useBottomRightCornerResizer = false;
 - 
 -         return lo.launchAsync();
 -     }
 - 
 - private:
 -     bool hasOverwriteButton;
 -     ScopedPointer<Label> titleLabel, contentLabel, changeLogLabel, overwriteLabel, overwritePath;
 -     ScopedPointer<TextButton> okButton, cancelButton;
 -     ScopedPointer<TextEditor> changeLog;
 -     ScopedPointer<TextButton> overwriteButton;
 -     ScopedPointer<Drawable> juceIcon;
 - 
 -     void lookAndFeelChanged() override
 -     {
 -         cancelButton->setColour (TextButton::buttonColourId,
 -                                  findColour (secondaryButtonBackgroundColourId));
 -         changeLog->applyFontToAllText (changeLog->getFont());
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UpdateUserDialog)
 - };
 - 
 - //==============================================================================
 - class UpdaterDialogModalCallback : public ModalComponentManager::Callback
 - {
 - public:
 -     struct DelayedCallback  : private Timer
 -     {
 -         DelayedCallback (LatestVersionChecker& versionChecker,
 -                          URL& newVersionToDownload,
 -                          const String& extraHeaders,
 -                          const File& appParentFolder,
 -                          int returnValue)
 -             : parent (versionChecker), download (newVersionToDownload),
 -               headers (extraHeaders), folder (appParentFolder), result (returnValue)
 -         {
 -             startTimer (200);
 -         }
 - 
 -     private:
 -         void timerCallback() override
 -         {
 -             stopTimer();
 -             parent.modalStateFinished (result, download, headers, folder);
 - 
 -             delete this;
 -         }
 - 
 -         LatestVersionChecker& parent;
 -         URL download;
 -         String headers;
 -         File folder;
 -         int result;
 - 
 -         JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DelayedCallback)
 -     };
 - 
 -     UpdaterDialogModalCallback (LatestVersionChecker& versionChecker,
 -                                 URL& newVersionToDownload,
 -                                 const String& extraHeaders,
 -                                 const File& appParentFolder)
 -         : parent (versionChecker), download (newVersionToDownload),
 -           headers (extraHeaders), folder (appParentFolder)
 -     {}
 - 
 -     void modalStateFinished (int returnValue) override
 -     {
 -         // the dialog window is only closed after this function exits
 -         // so we need a deferred callback to the parent. Unfortunately
 -         // our instance is also deleted after this function is used
 -         // so we can't use our own instance for a timer callback
 -         // we must allocate a new one.
 -         new DelayedCallback (parent, download, headers, folder, returnValue);
 -     }
 - 
 - private:
 -     LatestVersionChecker& parent;
 -     URL download;
 -     String headers;
 -     File folder;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UpdaterDialogModalCallback)
 - };
 - 
 - 
 - //==============================================================================
 - LatestVersionChecker::LatestVersionChecker()  : Thread ("Updater"),
 -                                                 statusCode (-1),
 -                                                 hasAttemptedToReadWebsite (false)
 - {
 -     startTimer (2000);
 - }
 - 
 - LatestVersionChecker::~LatestVersionChecker()
 - {
 -     stopThread (20000);
 - }
 - 
 - String LatestVersionChecker::getOSString()
 - {
 -     SystemStats::OperatingSystemType osType = SystemStats::getOperatingSystemType();
 - 
 -     if      ((osType & SystemStats::MacOSX)  != 0) return "OSX";
 -     else if ((osType & SystemStats::Windows) != 0) return "Windows";
 -     else if ((osType & SystemStats::Linux)   != 0) return "Linux";
 -     else return SystemStats::getOperatingSystemName();
 - }
 - 
 - const LatestVersionChecker::JuceServerLocationsAndKeys& LatestVersionChecker::getJuceServerURLsAndKeys() const
 - {
 -     static LatestVersionChecker::JuceServerLocationsAndKeys urlsAndKeys =
 -     {
 -         "https://my.roli.com",
 -         "265441b-343403c-20f6932-76361d",
 -         1,
 -         "/software_versions/update_to/Projucer/"
 -     };
 - 
 -     return urlsAndKeys;
 - }
 - 
 - int LatestVersionChecker::getProductVersionNumber() const   { return ProjectInfo::versionNumber; }
 - const char* LatestVersionChecker::getProductName() const    { return ProjectInfo::projectName; }
 - bool LatestVersionChecker::allowCustomLocation() const      { return true; }
 - 
 - Result LatestVersionChecker::performUpdate (const MemoryBlock& data, File& targetFolder)
 - {
 -     File unzipTarget;
 -     bool isUsingTempFolder = false;
 - 
 -     {
 -         MemoryInputStream input (data, false);
 -         ZipFile zip (input);
 - 
 -         if (zip.getNumEntries() == 0)
 -             return Result::fail ("The downloaded file wasn't a valid JUCE file!");
 - 
 -         unzipTarget = targetFolder;
 - 
 -         if (unzipTarget.exists())
 -         {
 -             isUsingTempFolder = true;
 -             unzipTarget = targetFolder.getNonexistentSibling();
 - 
 -             if (! unzipTarget.createDirectory())
 -                 return Result::fail ("Couldn't create a folder to unzip the new version!");
 -         }
 - 
 -         Result r (zip.uncompressTo (unzipTarget));
 - 
 -         if (r.failed())
 -         {
 -             if (isUsingTempFolder)
 -                 unzipTarget.deleteRecursively();
 - 
 -             return r;
 -         }
 -     }
 - 
 -     if (isUsingTempFolder)
 -     {
 -         File oldFolder (targetFolder.getSiblingFile (targetFolder.getFileNameWithoutExtension() + "_old")
 -                         .getNonexistentSibling());
 - 
 -         if (! targetFolder.moveFileTo (oldFolder))
 -         {
 -             unzipTarget.deleteRecursively();
 -             return Result::fail ("Could not remove the existing folder!");
 -         }
 - 
 -         if (! unzipTarget.moveFileTo (targetFolder))
 -         {
 -             unzipTarget.deleteRecursively();
 -             return Result::fail ("Could not overwrite the existing folder!");
 -         }
 -     }
 - 
 -     return Result::ok();
 - }
 - 
 - URL LatestVersionChecker::getLatestVersionURL (String& headers, const String& path) const
 - {
 -     const LatestVersionChecker::JuceServerLocationsAndKeys& urlsAndKeys = getJuceServerURLsAndKeys();
 - 
 -     String updateURL;
 -     bool isAbsolute = (path.startsWith ("http://") || path.startsWith ("https://"));
 -     bool isRedirect = path.isNotEmpty();
 - 
 -     if (isAbsolute)
 -     {
 -         updateURL = path;
 -     }
 -     else
 -     {
 -         updateURL << urlsAndKeys.updateSeverHostname
 -                   << (isRedirect ? path : String (urlsAndKeys.updatePath));
 - 
 -         if (! isRedirect)
 -         {
 -             updateURL << JuceVersionTriple (getProductVersionNumber()).toString() << '/'
 -                       << getOSString() << "?language=" << SystemStats::getUserLanguage();
 -         }
 -     }
 - 
 -     headers.clear();
 - 
 -     if (! isAbsolute)
 -     {
 -         headers << "X-API-Key: " << urlsAndKeys.publicAPIKey;
 - 
 -         if (! isRedirect)
 -         {
 -             headers << "\nContent-Type: application/json\n"
 -                     << "Accept: application/json; version=" << urlsAndKeys.apiVersion;
 -         }
 -     }
 - 
 -     return URL (updateURL);
 - }
 - 
 - URL LatestVersionChecker::getLatestVersionURL (String& headers) const
 - {
 -     String emptyString;
 -     return getLatestVersionURL (headers, emptyString);
 - }
 - 
 - void LatestVersionChecker::checkForNewVersion()
 - {
 -     hasAttemptedToReadWebsite = true;
 - 
 -     {
 -         String extraHeaders;
 -         URL updateURL (getLatestVersionURL (extraHeaders));
 -         StringPairArray responseHeaders;
 - 
 -         const int numRedirects = 0;
 - 
 -         const ScopedPointer<InputStream> in (updateURL.createInputStream (false, nullptr, nullptr,
 -                                                                           extraHeaders, 0, &responseHeaders,
 -                                                                           &statusCode, numRedirects));
 - 
 -         if (threadShouldExit())
 -             return;  // can't connect: fail silently.
 - 
 -         if (in != nullptr && (statusCode == 303 || statusCode == 400))
 -         {
 -             // if this doesn't fail then there is a new version available.
 -             // By leaving the scope of this function we will abort the download
 -             // to give the user a chance to cancel an update
 -             if (statusCode == 303)
 -                 newRelativeDownloadPath = responseHeaders ["Location"];
 - 
 -             jsonReply = JSON::parse (in->readEntireStreamAsString());
 -         }
 -     }
 - 
 -     if (! threadShouldExit())
 -         startTimer (100);
 - }
 - 
 -  bool LatestVersionChecker::processResult (var reply, const String& downloadPath)
 -  {
 -      if (statusCode == 303)
 -      {
 -          String versionString = reply.getProperty ("version", var()).toString();
 -          String releaseNotes = reply.getProperty ("notes", var()).toString();
 -          JuceVersionTriple version;
 - 
 -          if (versionString.isNotEmpty() && releaseNotes.isNotEmpty())
 -          {
 -              if (JuceVersionTriple::fromString (versionString, version))
 -              {
 -                  String extraHeaders;
 - 
 -                  URL newVersionToDownload = getLatestVersionURL (extraHeaders, downloadPath);
 -                  return askUserAboutNewVersion (version, releaseNotes, newVersionToDownload, extraHeaders);
 -              }
 -          }
 -      }
 -      else if (statusCode == 400)
 -      {
 -          // In the far-distant future, this may be contacting a defunct
 -          // URL, so hopefully the website will contain a helpful message
 -          // for the user..
 -          var errorObj = reply.getDynamicObject()->getProperty ("error");
 - 
 -          if (errorObj.isObject())
 -          {
 -              String message = errorObj.getProperty ("message", var()).toString();
 - 
 -              if (message.isNotEmpty())
 -              {
 -                  AlertWindow::showMessageBox (AlertWindow::WarningIcon,
 -                                               TRANS("JUCE Updater"),
 -                                               message);
 - 
 -                  return false;
 -              }
 -          }
 -      }
 - 
 -      // try again
 -      return true;
 - }
 - 
 - bool LatestVersionChecker::askUserAboutNewVersion (const LatestVersionChecker::JuceVersionTriple& version,
 -                                                    const String& releaseNotes,
 -                                                    URL& newVersionToDownload,
 -                                                    const String& extraHeaders)
 - {
 -     JuceVersionTriple currentVersion (getProductVersionNumber());
 - 
 -     if (version > currentVersion)
 -     {
 -         File appParentFolder (File::getSpecialLocation (File::currentApplicationFile).getParentDirectory());
 -         DialogWindow* modalDialog = nullptr;
 - 
 -         if (isZipFolder (appParentFolder) && allowCustomLocation())
 -         {
 -             modalDialog = UpdateUserDialog::launch (version, getProductName(), releaseNotes,
 -                                                     appParentFolder.getFullPathName().toRawUTF8());
 -         }
 -         else
 -         {
 -             modalDialog = UpdateUserDialog::launch (version, getProductName(), releaseNotes);
 -         }
 - 
 -         if (modalDialog != nullptr)
 -         {
 -             UpdaterDialogModalCallback* callback = new UpdaterDialogModalCallback (*this,
 -                                                                                    newVersionToDownload,
 -                                                                                    extraHeaders,
 -                                                                                    appParentFolder);
 - 
 -             // attachCallback will delete callback
 -             if (ModalComponentManager* mm = ModalComponentManager::getInstance())
 -                 mm->attachCallback (modalDialog, callback);
 -         }
 - 
 -         return false;
 -     }
 - 
 -     return true;
 - }
 - 
 - void LatestVersionChecker::modalStateFinished (int result,
 -                                                URL& newVersionToDownload,
 -                                                const String& extraHeaders,
 -                                                File appParentFolder)
 - {
 - 
 -     if (result == 1 || result == 2)
 -     {
 -         if (result == 1 || ! allowCustomLocation())
 -             DownloadNewVersionThread::performDownload (*this, newVersionToDownload, extraHeaders, appParentFolder);
 -         else
 -             askUserForLocationToDownload (newVersionToDownload, extraHeaders);
 -     }
 - }
 - 
 - void LatestVersionChecker::askUserForLocationToDownload (URL& newVersionToDownload, const String& extraHeaders)
 - {
 -     File targetFolder (EnabledModuleList::findGlobalModulesFolder());
 - 
 -     if (isJuceModulesFolder (targetFolder))
 -         targetFolder = targetFolder.getParentDirectory();
 - 
 -     FileChooser chooser (TRANS("Please select the location into which you'd like to install the new version"),
 -         targetFolder);
 - 
 -     if (chooser.browseForDirectory())
 -     {
 -         targetFolder = chooser.getResult();
 - 
 -         if (isJuceModulesFolder (targetFolder))
 -             targetFolder = targetFolder.getParentDirectory();
 - 
 -         if (targetFolder.getChildFile ("JUCE").isDirectory())
 -             targetFolder = targetFolder.getChildFile ("JUCE");
 - 
 -         if (targetFolder.getChildFile (".git").isDirectory())
 -         {
 -             AlertWindow::showMessageBox (AlertWindow::WarningIcon,
 -                                          TRANS ("Downloading new JUCE version"),
 -                                          TRANS ("This folder is a GIT repository!\n\n"
 -                                                 "You should use a \"git pull\" to update it to the latest version. "
 -                                                 "Or to use the Projucer to get an update, you should select an empty "
 -                                                 "folder into which you'd like to download the new code."));
 - 
 -             return;
 -         }
 - 
 -         if (isJuceFolder (targetFolder))
 -         {
 -             if (! AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
 -                                                 TRANS("Overwrite existing JUCE folder?"),
 -                                                 TRANS("Do you want to overwrite the folder:\n\n"
 -                                                       "xfldrx\n\n"
 -                                                       " ..with the latest version from juce.com?\n\n"
 -                                                       "(Please note that this will overwrite everything in that folder!)")
 -                                                 .replace ("xfldrx", targetFolder.getFullPathName())))
 -             {
 -                 return;
 -             }
 -         }
 -         else
 -         {
 -             targetFolder = targetFolder.getChildFile ("JUCE").getNonexistentSibling();
 -         }
 - 
 -         DownloadNewVersionThread::performDownload (*this, newVersionToDownload, extraHeaders, targetFolder);
 -     }
 - }
 - 
 - bool LatestVersionChecker::isZipFolder (const File& f)
 - {
 -     return f.getChildFile ("modules").isDirectory()
 -         && f.getChildFile ("extras").isDirectory()
 -         && f.getChildFile ("examples").isDirectory()
 -         && ! f.getChildFile (".git").isDirectory();
 - }
 - 
 - void LatestVersionChecker::timerCallback()
 - {
 -     stopTimer();
 - 
 -     if (hasAttemptedToReadWebsite)
 -     {
 -         bool restartTimer = true;
 -         if (jsonReply.isObject())
 -             restartTimer = processResult (jsonReply, newRelativeDownloadPath);
 - 
 -         hasAttemptedToReadWebsite = false;
 - 
 -         if (restartTimer)
 -             startTimer (7200000);
 -     }
 -     else
 -     {
 -         startThread (3);
 -     }
 - }
 - 
 - void LatestVersionChecker::run()
 - {
 -     checkForNewVersion();
 - }
 
 
  |