Browse Source

Introjucer: changes to implementation of auto-update and a few editor tweaks.

tags/2021-05-28
jules 10 years ago
parent
commit
c53b00cb21
8 changed files with 240 additions and 118 deletions
  1. +22
    -1
      extras/Introjucer/Source/Application/jucer_Application.h
  2. +134
    -94
      extras/Introjucer/Source/Application/jucer_AutoUpdater.cpp
  3. +20
    -2
      extras/Introjucer/Source/Application/jucer_AutoUpdater.h
  4. +18
    -2
      extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.cpp
  5. +16
    -3
      extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.h
  6. +4
    -11
      extras/Introjucer/Source/Project/jucer_ProjectContentComponent.cpp
  7. +25
    -5
      extras/Introjucer/Source/Utility/jucer_JucerTreeViewBase.h
  8. +1
    -0
      extras/Introjucer/Source/Utility/jucer_PresetIDs.h

+ 22
- 1
extras/Introjucer/Source/Application/jucer_Application.h View File

@@ -85,7 +85,7 @@ public:
MenuBarModel::setMacMainMenu (menuModel, nullptr, "Open Recent");
#endif
versionChecker = new LatestVersionChecker();
versionChecker = createVersionChecker();
}
void initialiseBasics()
@@ -169,6 +169,21 @@ public:
const String getApplicationName() override { return "Introjucer"; }
const String getApplicationVersion() override { return ProjectInfo::versionString; }
virtual String getVersionDescription() const
{
String s;
const Time buildDate (Time::getCompilationDate());
s << "Introjucer " << ProjectInfo::versionString
<< newLine
<< "Build date: " << buildDate.getDayOfMonth()
<< " " << Time::getMonthName (buildDate.getMonth(), true)
<< " " << buildDate.getYear();
return s;
}
bool moreThanOneInstanceAllowed() override
{
return true; // this is handled manually in initialise()
@@ -546,6 +561,12 @@ public:
return new ProjectContentComponent();
}
//==============================================================================
virtual LatestVersionChecker* createVersionChecker() const
{
return new LatestVersionChecker();
}
//==============================================================================
IntrojucerLookAndFeel lookAndFeel;


+ 134
- 94
extras/Introjucer/Source/Application/jucer_AutoUpdater.cpp View File

@@ -26,9 +26,15 @@
#include "jucer_AutoUpdater.h"
LatestVersionChecker::JuceVersionTriple::JuceVersionTriple()
: major (JUCE_MAJOR_VERSION),
minor (JUCE_MINOR_VERSION),
build (JUCE_BUILDNUMBER)
: 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)
@@ -118,16 +124,19 @@ struct RelaunchTimer : private Timer
class DownloadNewVersionThread : public ThreadWithProgressWindow
{
public:
DownloadNewVersionThread (URL u, const String& extraHeaders, File target)
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 (URL u, const String& extraHeaders, File targetFolder)
static void performDownload (LatestVersionChecker& versionChecker, URL u,
const String& extraHeaders, File targetFolder)
{
DownloadNewVersionThread d (u, extraHeaders, targetFolder);
DownloadNewVersionThread d (versionChecker, u, extraHeaders, targetFolder);
if (d.runThread())
{
@@ -152,7 +161,10 @@ public:
result = download (zipData);
if (result.wasOk() && ! threadShouldExit())
result = unzip (zipData);
{
setStatusMessage ("Installing...");
result = owner.performUpdate (zipData, targetFolder);
}
}
Result download (MemoryBlock& dest)
@@ -177,7 +189,7 @@ public:
if (redirectPath.isEmpty())
break;
url = LatestVersionChecker::getLatestVersionURL (headers, redirectPath);
url = owner.getLatestVersionURL (headers, redirectPath);
}
if (in != nullptr && statusCode == 200)
@@ -207,63 +219,7 @@ public:
return Result::fail ("Failed to download from: " + url.toString (false));
}
Result unzip (const MemoryBlock& data)
{
setStatusMessage ("Installing...");
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();
}
LatestVersionChecker& owner;
Result result;
URL url;
String headers;
@@ -278,13 +234,14 @@ class UpdateUserDialog : public Component,
{
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 JUCE version 123?").
replace ("123", version.toString())));
TRANS ("Download \"123\" version 456?").replace ("123", productName)
.replace ("456", version.toString())));
titleLabel->setFont (Font (15.00f, Font::bold));
titleLabel->setJustificationType (Justification::centredLeft);
@@ -293,7 +250,8 @@ public:
titleLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
addAndMakeVisible (contentLabel = new Label ("Content Label",
TRANS("A new version of JUCE is available - would you like to download it?")));
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);
@@ -413,13 +371,16 @@ public:
}
static DialogWindow* launch (const LatestVersionChecker::JuceVersionTriple& version,
const String& productName,
const String& releaseNotes,
const char* overwritePath = nullptr)
{
OptionalScopedPointer<Component> userDialog (new UpdateUserDialog (version, releaseNotes, overwritePath), true);
OptionalScopedPointer<Component> userDialog (new UpdateUserDialog (version, productName,
releaseNotes, overwritePath), true);
DialogWindow::LaunchOptions lo;
lo.dialogTitle = TRANS ("Download JUCE version 123?").replace ("123", version.toString());
lo.dialogTitle = TRANS ("Download \"123\" version 456?").replace ("456", version.toString())
.replace ("123", productName);
lo.dialogBackgroundColour = Colours::lightgrey;
lo.content = userDialog;
lo.componentToCentreAround = nullptr;
@@ -528,12 +489,92 @@ String LatestVersionChecker::getOSString()
else return SystemStats::getOperatingSystemName();
}
URL LatestVersionChecker::getLatestVersionURL (String& headers, const String& path)
const LatestVersionChecker::JuceServerLocationsAndKeys& LatestVersionChecker::getJuceServerURLsAndKeys() const
{
static LatestVersionChecker::JuceServerLocationsAndKeys urlsAndKeys =
{
"https://my.roli.com",
"495fb2d-cce9a8-3c52824-2da2679",
1,
"/software_versions/update_to/Introjucer/"
};
return urlsAndKeys;
}
int LatestVersionChecker::getProductVersionNumber() const
{
static const char* updateSeverHostname = "https://my.roli.com";
static const char* publicAPIKey = "495fb2d-cce9a8-3c52824-2da2679";
static const int apiVersion = 1;
static const char* updatePath = "/software_versions/update_to/Introjucer/";
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://"));
@@ -545,12 +586,12 @@ URL LatestVersionChecker::getLatestVersionURL (String& headers, const String& pa
}
else
{
updateURL << updateSeverHostname
<< (isRedirect ? path : String (updatePath));
updateURL << urlsAndKeys.updateSeverHostname
<< (isRedirect ? path : String (urlsAndKeys.updatePath));
if (! isRedirect)
{
updateURL << JuceVersionTriple().toString() << '/'
updateURL << JuceVersionTriple (getProductVersionNumber()).toString() << '/'
<< getOSString() << "?language=" << SystemStats::getUserLanguage();
}
}
@@ -559,19 +600,19 @@ URL LatestVersionChecker::getLatestVersionURL (String& headers, const String& pa
if (! isAbsolute)
{
headers << "X-API-Key: " << publicAPIKey;
headers << "X-API-Key: " << urlsAndKeys.publicAPIKey;
if (! isRedirect)
{
headers << "\nContent-Type: application/json\n"
<< "Accept: application/json; version=" << apiVersion;
<< "Accept: application/json; version=" << urlsAndKeys.apiVersion;
}
}
return URL (updateURL);
}
URL LatestVersionChecker::getLatestVersionURL (String& headers)
URL LatestVersionChecker::getLatestVersionURL (String& headers) const
{
String emptyString;
return getLatestVersionURL (headers, emptyString);
@@ -656,24 +697,21 @@ void LatestVersionChecker::askUserAboutNewVersion (const LatestVersionChecker::J
URL& newVersionToDownload,
const String& extraHeaders)
{
// Currently we do not show the release notes
ignoreUnused (releaseNotes);
JuceVersionTriple currentVersion;
JuceVersionTriple currentVersion (getProductVersionNumber());
if (version > currentVersion)
{
File appParentFolder (File::getSpecialLocation (File::currentApplicationFile).getParentDirectory());
DialogWindow* modalDialog = nullptr;
if (isZipFolder (appParentFolder))
if (isZipFolder (appParentFolder) && allowCustomLocation())
{
modalDialog = UpdateUserDialog::launch (version, releaseNotes,
modalDialog = UpdateUserDialog::launch (version, getProductName(), releaseNotes,
appParentFolder.getFullPathName().toRawUTF8());
}
else
{
modalDialog = UpdateUserDialog::launch (version, releaseNotes);
modalDialog = UpdateUserDialog::launch (version, getProductName(), releaseNotes);
}
if (modalDialog != nullptr)
@@ -695,11 +733,13 @@ void LatestVersionChecker::modalStateFinished (int result,
const String& extraHeaders,
File appParentFolder)
{
if (result == 1)
DownloadNewVersionThread::performDownload (newVersionToDownload, extraHeaders, appParentFolder);
if (result == 2)
askUserForLocationToDownload (newVersionToDownload, extraHeaders);
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)
@@ -752,7 +792,7 @@ void LatestVersionChecker::askUserForLocationToDownload (URL& newVersionToDownlo
targetFolder = targetFolder.getChildFile ("JUCE").getNonexistentSibling();
}
DownloadNewVersionThread::performDownload (newVersionToDownload, extraHeaders, targetFolder);
DownloadNewVersionThread::performDownload (*this, newVersionToDownload, extraHeaders, targetFolder);
}
}


+ 20
- 2
extras/Introjucer/Source/Application/jucer_AutoUpdater.h View File

@@ -35,6 +35,7 @@ public:
struct JuceVersionTriple
{
JuceVersionTriple();
JuceVersionTriple (int juceVersionNumber);
JuceVersionTriple (int majorInt, int minorInt, int buildNumber);
static bool fromString (const String& versionString, JuceVersionTriple& result);
@@ -45,14 +46,23 @@ public:
int major, minor, build;
};
//==============================================================================
struct JuceServerLocationsAndKeys
{
const char* updateSeverHostname;
const char* publicAPIKey;
const int apiVersion;
const char* updatePath;
};
//==============================================================================
LatestVersionChecker();
~LatestVersionChecker();
static String getOSString();
static URL getLatestVersionURL (String& headers, const String& path);
static URL getLatestVersionURL (String& headers);
URL getLatestVersionURL (String& headers, const String& path) const;
URL getLatestVersionURL (String& headers) const;
void checkForNewVersion();
void processResult (var reply, const String& downloadPath);
@@ -66,6 +76,14 @@ public:
static bool isZipFolder (const File&);
virtual Result performUpdate (const MemoryBlock& data, File& targetFolder);
protected:
virtual const JuceServerLocationsAndKeys& getJuceServerURLsAndKeys() const;
virtual int getProductVersionNumber() const;
virtual const char* getProductName() const;
virtual bool allowCustomLocation() const;
private:
//==============================================================================
friend class UpdaterDialogModalCallback;


+ 18
- 2
extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.cpp View File

@@ -146,7 +146,7 @@ SourceCodeEditor::SourceCodeEditor (OpenDocumentManager::Document* doc, CodeDocu
setEditor (ed);
}
SourceCodeEditor::SourceCodeEditor (OpenDocumentManager::Document* doc, CodeEditorComponent* ed)
SourceCodeEditor::SourceCodeEditor (OpenDocumentManager::Document* doc, GenericCodeEditorComponent* ed)
: DocumentEditorComponent (doc)
{
setEditor (ed);
@@ -163,7 +163,7 @@ SourceCodeEditor::~SourceCodeEditor()
doc->updateLastState (*editor);
}
void SourceCodeEditor::setEditor (CodeEditorComponent* newEditor)
void SourceCodeEditor::setEditor (GenericCodeEditorComponent* newEditor)
{
if (editor != nullptr)
editor->getDocument().removeListener (this);
@@ -322,6 +322,16 @@ bool GenericCodeEditorComponent::perform (const InvocationInfo& info)
return CodeEditorComponent::perform (info);
}
void GenericCodeEditorComponent::addListener (GenericCodeEditorComponent::Listener* listener)
{
listeners.add (listener);
}
void GenericCodeEditorComponent::removeListener (GenericCodeEditorComponent::Listener* listener)
{
listeners.remove (listener);
}
//==============================================================================
class GenericCodeEditorComponent::FindPanel : public Component,
private TextEditor::Listener,
@@ -527,6 +537,12 @@ void GenericCodeEditorComponent::handleEscapeKey()
hideFindPanel();
}
void GenericCodeEditorComponent::editorViewportPositionChanged()
{
CodeEditorComponent::editorViewportPositionChanged();
listeners.call (&Listener::codeEditorViewportMoved, *this);
}
//==============================================================================
static CPlusPlusCodeTokeniser cppTokeniser;


+ 16
- 3
extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.h View File

@@ -136,6 +136,8 @@ protected:
void reloadInternal();
};
class GenericCodeEditorComponent;
//==============================================================================
class SourceCodeEditor : public DocumentEditorComponent,
private ValueTree::Listener,
@@ -143,13 +145,13 @@ class SourceCodeEditor : public DocumentEditorComponent,
{
public:
SourceCodeEditor (OpenDocumentManager::Document*, CodeDocument&);
SourceCodeEditor (OpenDocumentManager::Document*, CodeEditorComponent*);
SourceCodeEditor (OpenDocumentManager::Document*, GenericCodeEditorComponent*);
~SourceCodeEditor();
void scrollToKeepRangeOnScreen (Range<int> range);
void highlight (Range<int> range, bool cursorAtStart);
ScopedPointer<CodeEditorComponent> editor;
ScopedPointer<GenericCodeEditorComponent> editor;
private:
void resized() override;
@@ -164,7 +166,7 @@ private:
void codeDocumentTextInserted (const String&, int) override;
void codeDocumentTextDeleted (int, int) override;
void setEditor (CodeEditorComponent*);
void setEditor (GenericCodeEditorComponent*);
void updateColourScheme();
void checkSaveState();
@@ -191,6 +193,7 @@ public:
void findSelection();
void findNext (bool forwards, bool skipCurrentSelection);
void handleEscapeKey() override;
void editorViewportPositionChanged() override;
void resized() override;
@@ -199,10 +202,20 @@ public:
static bool isCaseSensitiveSearch() { return getAppSettings().getGlobalProperties().getBoolValue ("searchCaseSensitive"); }
static void setCaseSensitiveSearch (bool b) { getAppSettings().getGlobalProperties().setValue ("searchCaseSensitive", b); }
struct Listener
{
virtual ~Listener() {}
virtual void codeEditorViewportMoved (CodeEditorComponent&) = 0;
};
void addListener (Listener* listener);
void removeListener (Listener* listener);
private:
File file;
class FindPanel;
ScopedPointer<FindPanel> findPanel;
ListenerList<Listener> listeners;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GenericCodeEditorComponent)
};


+ 4
- 11
extras/Introjucer/Source/Project/jucer_ProjectContentComponent.cpp View File

@@ -141,7 +141,7 @@ struct LogoComponent : public Component
Rectangle<int> r (getLocalBounds());
g.setFont (15.0f);
g.drawFittedText (getVersionInfo(), r.removeFromBottom (30), Justification::centred, 2);
g.drawFittedText (getVersionInfo(), r.removeFromBottom (50), Justification::centred, 3);
const Path& logo = getIcons().mainJuceLogo;
g.fillPath (logo, RectanglePlacement (RectanglePlacement::centred)
@@ -150,16 +150,9 @@ struct LogoComponent : public Component
static String getVersionInfo()
{
const Time buildDate (Time::getCompilationDate());
String s;
s << SystemStats::getJUCEVersion() << newLine
<< "Introjucer built: " << buildDate.getDayOfMonth()
<< " " << Time::getMonthName (buildDate.getMonth(), true)
<< " " << buildDate.getYear();
return s;
return SystemStats::getJUCEVersion()
+ newLine
+ IntrojucerApp::getApp().getVersionDescription();
}
};


+ 25
- 5
extras/Introjucer/Source/Utility/jucer_JucerTreeViewBase.h View File

@@ -92,14 +92,14 @@ public:
int textX;
protected:
ProjectContentComponent* getProjectContentComponent() const;
virtual void addSubItems() {}
Colour getBackgroundColour() const;
Colour getContrastingColour (float contrast) const;
Colour getContrastingColour (Colour targetColour, float minContrast) const;
protected:
ProjectContentComponent* getProjectContentComponent() const;
virtual void addSubItems() {}
private:
class ItemSelectionTimer;
friend class ItemSelectionTimer;
@@ -195,7 +195,13 @@ public:
{
g.setColour (Colours::black);
paintIcon (g);
item.paintContent (g, Rectangle<int> (item.textX, 0, getWidth() - item.textX, getHeight()));
int rightEdge = getWidth();
if (Component* c = buttons.getFirst())
rightEdge = c->getX();
item.paintContent (g, Rectangle<int> (item.textX, 0, rightEdge - item.textX, getHeight()));
}
void paintIcon (Graphics& g)
@@ -207,9 +213,23 @@ public:
void resized() override
{
item.textX = (int) item.getIconSize() + 8;
Rectangle<int> r (getLocalBounds());
for (int i = buttons.size(); --i >= 0;)
buttons.getUnchecked(i)->setBounds (r.removeFromRight (r.getHeight()));
}
void addRightHandButton (Component* button)
{
buttons.add (button);
addAndMakeVisible (button);
}
JucerTreeViewBase& item;
OwnedArray<Component> buttons;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeItemComponent)
};


+ 1
- 0
extras/Introjucer/Source/Utility/jucer_PresetIDs.h View File

@@ -47,6 +47,7 @@ namespace Ids
DECLARE_ID (source);
DECLARE_ID (width);
DECLARE_ID (height);
DECLARE_ID (bounds);
DECLARE_ID (background);
DECLARE_ID (initialState);
DECLARE_ID (targetFolder);


Loading…
Cancel
Save