mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Introjucer update to provide downloading of new modules directly from the website.
This commit is contained in:
parent
65902c0b99
commit
2d56bedab5
18 changed files with 606 additions and 400 deletions
|
|
@ -38,7 +38,10 @@ class JucerApplication : public JUCEApplication
|
|||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
JucerApplication() {}
|
||||
JucerApplication()
|
||||
{
|
||||
}
|
||||
|
||||
~JucerApplication() {}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -96,12 +99,18 @@ public:
|
|||
mainWindows.clear();
|
||||
|
||||
OpenDocumentManager::deleteInstance();
|
||||
deleteAndZero (commandManager);
|
||||
commandManager = nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void systemRequestedQuit()
|
||||
{
|
||||
if (cancelAnyModalComponents())
|
||||
{
|
||||
new AsyncQuitRetrier();
|
||||
return;
|
||||
}
|
||||
|
||||
while (mainWindows.size() > 0)
|
||||
{
|
||||
if (! mainWindows[0]->closeCurrentProject())
|
||||
|
|
@ -139,11 +148,11 @@ public:
|
|||
|
||||
bool moreThanOneInstanceAllowed()
|
||||
{
|
||||
#ifndef JUCE_LINUX
|
||||
#ifndef JUCE_LINUX
|
||||
return false;
|
||||
#else
|
||||
#else
|
||||
return true; //xxx should be false but doesn't work on linux..
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void anotherInstanceStarted (const String& commandLine)
|
||||
|
|
@ -352,7 +361,12 @@ public:
|
|||
case CommandIDs::showPrefs: showPrefsPanel(); break;
|
||||
case CommandIDs::saveAll: OpenDocumentManager::getInstance()->saveAll(); break;
|
||||
case CommandIDs::closeAllDocuments: closeAllDocuments (true); break;
|
||||
case CommandIDs::showJuceVersion: JuceUpdater::show (mainWindows[0]); break;
|
||||
case CommandIDs::showJuceVersion:
|
||||
{
|
||||
ModuleList list (ModuleList::getDefaultModulesFolder (nullptr));
|
||||
JuceUpdater::show (list, mainWindows[0]);
|
||||
break;
|
||||
}
|
||||
default: return JUCEApplication::perform (info);
|
||||
}
|
||||
|
||||
|
|
@ -503,6 +517,35 @@ private:
|
|||
|
||||
return createNewMainWindow();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static bool cancelAnyModalComponents()
|
||||
{
|
||||
const int numModal = ModalComponentManager::getInstance()->getNumModalComponents();
|
||||
|
||||
for (int i = numModal; --i >= 0;)
|
||||
if (ModalComponentManager::getInstance()->getModalComponent(i) != nullptr)
|
||||
ModalComponentManager::getInstance()->getModalComponent(i)->exitModalState (0);
|
||||
|
||||
return numModal > 0;
|
||||
}
|
||||
|
||||
class AsyncQuitRetrier : public Timer
|
||||
{
|
||||
public:
|
||||
AsyncQuitRetrier() { startTimer (500); }
|
||||
|
||||
void timerCallback()
|
||||
{
|
||||
stopTimer();
|
||||
delete this;
|
||||
|
||||
if (JUCEApplication::getInstance() != nullptr)
|
||||
JUCEApplication::getInstance()->systemRequestedQuit();
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ namespace
|
|||
int listModules()
|
||||
{
|
||||
std::cout << "Downloading list of available modules..." << std::endl;
|
||||
ModuleList list;
|
||||
ModuleList list (File::nonexistent);
|
||||
list.loadFromWebsite();
|
||||
|
||||
for (int i = 0; i < list.modules.size(); ++i)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
#include "jucer_CommandIDs.h"
|
||||
|
||||
//==============================================================================
|
||||
extern ApplicationCommandManager* commandManager;
|
||||
extern ScopedPointer<ApplicationCommandManager> commandManager;
|
||||
|
||||
//==============================================================================
|
||||
const char* const projectItemDragType = "Project Items";
|
||||
|
|
|
|||
|
|
@ -25,30 +25,45 @@
|
|||
|
||||
#include "../jucer_Headers.h"
|
||||
#include "jucer_JuceUpdater.h"
|
||||
#include "../Project/jucer_Module.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
JuceUpdater::JuceUpdater()
|
||||
: filenameComp ("Juce Folder", StoredSettings::getInstance()->getLastKnownJuceFolder(),
|
||||
JuceUpdater::JuceUpdater (ModuleList& moduleList_)
|
||||
: moduleList (moduleList_),
|
||||
latestList (File::nonexistent),
|
||||
filenameComp ("Juce Folder", ModuleList::getLocalModulesFolder (nullptr),
|
||||
true, true, false, "*", String::empty, "Select your Juce folder"),
|
||||
checkNowButton ("Check Online for Available Updates...",
|
||||
"Contacts the website to see if this version is up-to-date")
|
||||
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")
|
||||
{
|
||||
addAndMakeVisible (&label);
|
||||
addAndMakeVisible (¤tVersionLabel);
|
||||
addAndMakeVisible (&filenameComp);
|
||||
addAndMakeVisible (&checkNowButton);
|
||||
addAndMakeVisible (¤tVersionLabel);
|
||||
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 ("Destination folder:", false);
|
||||
label.setText ("Local modules folder:", false);
|
||||
|
||||
addAndMakeVisible (&availableVersionsList);
|
||||
availableVersionsList.setModel (this);
|
||||
|
||||
setSize (600, 300);
|
||||
updateInstallButtonStatus();
|
||||
versionsToDownload = ValueTree ("modules");
|
||||
versionsToDownload.addListener (this);
|
||||
|
||||
setSize (600, 500);
|
||||
|
||||
checkNow();
|
||||
}
|
||||
|
||||
JuceUpdater::~JuceUpdater()
|
||||
|
|
@ -57,12 +72,32 @@ JuceUpdater::~JuceUpdater()
|
|||
filenameComp.removeListener (this);
|
||||
}
|
||||
|
||||
void JuceUpdater::show (Component* mainWindow)
|
||||
//==============================================================================
|
||||
class UpdateDialogWindow : public DialogWindow
|
||||
{
|
||||
JuceUpdater updater;
|
||||
DialogWindow::showModalDialog ("Juce Update...", &updater, mainWindow,
|
||||
Colours::lightgrey,
|
||||
true, false, false);
|
||||
public:
|
||||
UpdateDialogWindow (JuceUpdater* updater, Component* componentToCentreAround)
|
||||
: DialogWindow ("JUCE Module Updater",
|
||||
Colours::lightgrey, true, 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)
|
||||
{
|
||||
UpdateDialogWindow w (new JuceUpdater (moduleList), mainWindow);
|
||||
w.runModalLoop();
|
||||
}
|
||||
|
||||
void JuceUpdater::resized()
|
||||
|
|
@ -70,9 +105,16 @@ void JuceUpdater::resized()
|
|||
filenameComp.setBounds (20, 40, getWidth() - 40, 22);
|
||||
label.setBounds (filenameComp.getX(), filenameComp.getY() - 18, filenameComp.getWidth(), 18);
|
||||
currentVersionLabel.setBounds (filenameComp.getX(), filenameComp.getBottom(), filenameComp.getWidth(), 25);
|
||||
checkNowButton.changeWidthToFitText (20);
|
||||
checkNowButton.setCentrePosition (getWidth() / 2, filenameComp.getBottom() + 40);
|
||||
availableVersionsList.setBounds (filenameComp.getX(), checkNowButton.getBottom() + 20, filenameComp.getWidth(), getHeight() - (checkNowButton.getBottom() + 20));
|
||||
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)
|
||||
|
|
@ -80,247 +122,134 @@ void JuceUpdater::paint (Graphics& g)
|
|||
g.fillAll (Colours::white);
|
||||
}
|
||||
|
||||
String findVersionNum (const String& file, const String& token)
|
||||
void JuceUpdater::buttonClicked (Button* b)
|
||||
{
|
||||
return file.fromFirstOccurrenceOf (token, false, false)
|
||||
.upToFirstOccurrenceOf ("\n", false, false)
|
||||
.trim();
|
||||
if (b == &installButton)
|
||||
install();
|
||||
else if (b == &selectAllButton)
|
||||
selectAll();
|
||||
else
|
||||
checkNow();
|
||||
}
|
||||
|
||||
String JuceUpdater::getCurrentVersion()
|
||||
void JuceUpdater::refresh()
|
||||
{
|
||||
const String header (filenameComp.getCurrentFile()
|
||||
.getChildFile ("src/core/juce_StandardHeader.h").loadFileAsString());
|
||||
|
||||
const String v1 (findVersionNum (header, "JUCE_MAJOR_VERSION"));
|
||||
const String v2 (findVersionNum (header, "JUCE_MINOR_VERSION"));
|
||||
const String v3 (findVersionNum (header, "JUCE_BUILDNUMBER"));
|
||||
|
||||
if ((v1 + v2 + v3).isEmpty())
|
||||
return String::empty;
|
||||
|
||||
return v1 + "." + v2 + "." + v3;
|
||||
}
|
||||
|
||||
XmlElement* JuceUpdater::downloadVersionList()
|
||||
{
|
||||
return URL ("http://www.rawmaterialsoftware.com/juce/downloads/juce_versions.php").readEntireXmlStream();
|
||||
}
|
||||
|
||||
void JuceUpdater::updateVersions (const XmlElement& xml)
|
||||
{
|
||||
availableVersions.clear();
|
||||
|
||||
forEachXmlChildElementWithTagName (xml, v, "VERSION")
|
||||
{
|
||||
VersionInfo* vi = new VersionInfo();
|
||||
vi->url = URL (v->getStringAttribute ("url"));
|
||||
vi->desc = v->getStringAttribute ("desc");
|
||||
vi->version = v->getStringAttribute ("version");
|
||||
vi->date = v->getStringAttribute ("date");
|
||||
availableVersions.add (vi);
|
||||
}
|
||||
|
||||
availableVersionsList.updateContent();
|
||||
availableVersionsList.repaint();
|
||||
}
|
||||
|
||||
void JuceUpdater::buttonClicked (Button*)
|
||||
{
|
||||
ScopedPointer<XmlElement> xml (downloadVersionList());
|
||||
|
||||
if (xml == nullptr || xml->hasTagName ("html"))
|
||||
{
|
||||
AlertWindow::showMessageBox (AlertWindow::WarningIcon, "Connection Problems...",
|
||||
"Couldn't connect to the Raw Material Software website!");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (! xml->hasTagName ("JUCEVERSIONS"))
|
||||
{
|
||||
AlertWindow::showMessageBox (AlertWindow::WarningIcon, "Update Problems...",
|
||||
"This version of the Introjucer may be too old to receive automatic updates!\n\n"
|
||||
"Please visit www.rawmaterialsoftware.com and get the latest version manually!");
|
||||
return;
|
||||
}
|
||||
|
||||
const String currentVersion (getCurrentVersion());
|
||||
|
||||
OwnedArray<VersionInfo> versions;
|
||||
updateVersions (*xml);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class NewVersionDownloader : public ThreadWithProgressWindow
|
||||
class WebsiteContacterThread : public Thread,
|
||||
private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
NewVersionDownloader (const String& title, const URL& url_, const File& target_)
|
||||
: ThreadWithProgressWindow (title, true, true),
|
||||
url (url_), target (target_)
|
||||
WebsiteContacterThread (JuceUpdater& owner_, const ModuleList& latestList)
|
||||
: Thread ("Module updater"),
|
||||
owner (owner_),
|
||||
downloaded (latestList)
|
||||
{
|
||||
startThread();
|
||||
}
|
||||
|
||||
~WebsiteContacterThread()
|
||||
{
|
||||
stopThread (10000);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
setStatusMessage ("Contacting website...");
|
||||
|
||||
ScopedPointer<InputStream> input (url.createInputStream (false));
|
||||
|
||||
if (input == nullptr)
|
||||
{
|
||||
error = "Couldn't connect to the website...";
|
||||
return;
|
||||
}
|
||||
|
||||
if (! target.deleteFile())
|
||||
{
|
||||
error = "Couldn't delete the destination file...";
|
||||
return;
|
||||
}
|
||||
|
||||
ScopedPointer<OutputStream> output (target.createOutputStream (32768));
|
||||
|
||||
if (output == nullptr)
|
||||
{
|
||||
error = "Couldn't write to the destination file...";
|
||||
return;
|
||||
}
|
||||
|
||||
setStatusMessage ("Downloading...");
|
||||
|
||||
int totalBytes = (int) input->getTotalLength();
|
||||
int bytesSoFar = 0;
|
||||
|
||||
while (! (input->isExhausted() || threadShouldExit()))
|
||||
{
|
||||
HeapBlock<char> buffer (8192);
|
||||
const int num = input->read (buffer, 8192);
|
||||
|
||||
if (num == 0)
|
||||
break;
|
||||
|
||||
output->write (buffer, num);
|
||||
bytesSoFar += num;
|
||||
|
||||
setProgress (totalBytes > 0 ? bytesSoFar / (double) totalBytes : -1.0);
|
||||
}
|
||||
if (downloaded.loadFromWebsite())
|
||||
triggerAsyncUpdate();
|
||||
else
|
||||
AlertWindow::showMessageBox (AlertWindow::InfoIcon,
|
||||
"Module Update",
|
||||
"Couldn't connect to the website!");
|
||||
}
|
||||
|
||||
String error;
|
||||
void handleAsyncUpdate()
|
||||
{
|
||||
owner.backgroundUpdateComplete (downloaded);
|
||||
}
|
||||
|
||||
private:
|
||||
URL url;
|
||||
File target;
|
||||
JuceUpdater& owner;
|
||||
ModuleList downloaded;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class Unzipper : public ThreadWithProgressWindow
|
||||
void JuceUpdater::checkNow()
|
||||
{
|
||||
public:
|
||||
Unzipper (ZipFile& zipFile_, const File& targetDir_)
|
||||
: ThreadWithProgressWindow ("Unzipping...", true, true),
|
||||
worked (true), zipFile (zipFile_), targetDir (targetDir_)
|
||||
{
|
||||
}
|
||||
websiteContacterThread = nullptr;
|
||||
websiteContacterThread = new WebsiteContacterThread (*this, latestList);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
for (int i = 0; i < zipFile.getNumEntries(); ++i)
|
||||
{
|
||||
if (threadShouldExit())
|
||||
break;
|
||||
|
||||
const ZipFile::ZipEntry* e = zipFile.getEntry (i);
|
||||
setStatusMessage ("Unzipping " + e->filename + "...");
|
||||
setProgress (i / (double) zipFile.getNumEntries());
|
||||
|
||||
worked = zipFile.uncompressEntry (i, targetDir, true) && worked;
|
||||
}
|
||||
}
|
||||
|
||||
bool worked;
|
||||
|
||||
private:
|
||||
ZipFile& zipFile;
|
||||
File targetDir;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void JuceUpdater::applyVersion (VersionInfo* version)
|
||||
void JuceUpdater::backgroundUpdateComplete (const ModuleList& newList)
|
||||
{
|
||||
File destDir (filenameComp.getCurrentFile());
|
||||
latestList = newList;
|
||||
websiteContacterThread = nullptr;
|
||||
|
||||
const bool destDirExisted = destDir.isDirectory();
|
||||
if (latestList == moduleList)
|
||||
AlertWindow::showMessageBox (AlertWindow::InfoIcon,
|
||||
"Module Update",
|
||||
"No new modules are available");
|
||||
refresh();
|
||||
}
|
||||
|
||||
if (destDirExisted && destDir.getNumberOfChildFiles (File::findFilesAndDirectories, "*") > 0)
|
||||
{
|
||||
int r = AlertWindow::showYesNoCancelBox (AlertWindow::WarningIcon, "Folder already exists",
|
||||
"The folder " + destDir.getFullPathName() + "\nalready contains some files...\n\n"
|
||||
"Do you want to delete everything in the folder and replace it entirely, or just merge the new files into the existing folder?",
|
||||
"Delete and replace entire folder",
|
||||
"Add and overwrite existing files",
|
||||
"Cancel");
|
||||
int JuceUpdater::getNumCheckedModules() const
|
||||
{
|
||||
int numChecked = 0;
|
||||
|
||||
if (r == 0)
|
||||
return;
|
||||
for (int i = latestList.modules.size(); --i >= 0;)
|
||||
if (versionsToDownload [latestList.modules.getUnchecked(i)->uid])
|
||||
++numChecked;
|
||||
|
||||
if (r == 1)
|
||||
{
|
||||
if (! destDir.deleteRecursively())
|
||||
{
|
||||
AlertWindow::showMessageBox (AlertWindow::WarningIcon, "Problems...",
|
||||
"Couldn't delete the existing folder!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return numChecked;
|
||||
}
|
||||
|
||||
if (! (destDir.isDirectory() || destDir.createDirectory()))
|
||||
{
|
||||
AlertWindow::showMessageBox (AlertWindow::WarningIcon, "Problems...",
|
||||
"Couldn't create that target folder..");
|
||||
return;
|
||||
}
|
||||
bool JuceUpdater::isLatestVersion (const String& moduleID) const
|
||||
{
|
||||
const ModuleList::Module* m1 = moduleList.findModuleInfo (moduleID);
|
||||
const ModuleList::Module* m2 = latestList.findModuleInfo (moduleID);
|
||||
|
||||
File zipFile (destDir.getNonexistentChildFile ("juce_download", ".tar.gz", false));
|
||||
return m1 != nullptr && m2 != nullptr && m1->version == m2->version;
|
||||
}
|
||||
|
||||
bool worked = false;
|
||||
|
||||
{
|
||||
NewVersionDownloader downloader ("Downloading Version " + version->version + "...",
|
||||
version->url, zipFile);
|
||||
worked = downloader.runThread();
|
||||
}
|
||||
|
||||
if (worked)
|
||||
{
|
||||
ZipFile zip (zipFile);
|
||||
Unzipper unzipper (zip, destDir);
|
||||
worked = unzipper.runThread() && unzipper.worked;
|
||||
}
|
||||
|
||||
zipFile.deleteFile();
|
||||
|
||||
if ((! destDirExisted) && (destDir.getNumberOfChildFiles (File::findFilesAndDirectories, "*") == 0 || ! worked))
|
||||
destDir.deleteRecursively();
|
||||
|
||||
filenameComponentChanged (&filenameComp);
|
||||
void JuceUpdater::updateInstallButtonStatus()
|
||||
{
|
||||
const int numChecked = getNumCheckedModules();
|
||||
installButton.setEnabled (numChecked > 0);
|
||||
selectAllButton.setToggleState (numChecked > latestList.modules.size() / 2, false);
|
||||
}
|
||||
|
||||
void JuceUpdater::filenameComponentChanged (FilenameComponent*)
|
||||
{
|
||||
const String version (getCurrentVersion());
|
||||
moduleList.rescan (filenameComp.getCurrentFile());
|
||||
filenameComp.setCurrentFile (moduleList.getModulesFolder(), true, false);
|
||||
|
||||
if (version.isEmpty())
|
||||
if (! FileHelpers::isModulesFolder (moduleList.getModulesFolder()))
|
||||
currentVersionLabel.setText ("(Not a Juce folder)", false);
|
||||
else
|
||||
currentVersionLabel.setText ("(Current version in this folder: " + version + ")", false);
|
||||
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 availableVersions.size();
|
||||
return latestList.modules.size();
|
||||
}
|
||||
|
||||
void JuceUpdater::paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected)
|
||||
|
|
@ -331,74 +260,192 @@ void JuceUpdater::paintListBoxItem (int rowNumber, Graphics& g, int width, int h
|
|||
|
||||
Component* JuceUpdater::refreshComponentForRow (int rowNumber, bool isRowSelected, Component* existingComponentToUpdate)
|
||||
{
|
||||
class UpdateListComponent : public Component,
|
||||
public ButtonListener
|
||||
class UpdateListComponent : public Component
|
||||
{
|
||||
public:
|
||||
UpdateListComponent (JuceUpdater& updater_)
|
||||
: updater (updater_),
|
||||
version (nullptr),
|
||||
applyButton ("Install this version...")
|
||||
: updater (updater_)
|
||||
{
|
||||
addAndMakeVisible (&applyButton);
|
||||
applyButton.addListener (this);
|
||||
addChildComponent (&toggle);
|
||||
toggle.setBounds ("2, 2, parent.height - 2, parent.height - 2");
|
||||
toggle.setWantsKeyboardFocus (false);
|
||||
setInterceptsMouseClicks (false, true);
|
||||
}
|
||||
|
||||
~UpdateListComponent()
|
||||
void setModule (const ModuleList::Module* newModule,
|
||||
const ModuleList::Module* existingModule,
|
||||
const Value& value)
|
||||
{
|
||||
applyButton.removeListener (this);
|
||||
}
|
||||
|
||||
void setVersion (VersionInfo* v)
|
||||
{
|
||||
if (version != v)
|
||||
if (newModule != nullptr)
|
||||
{
|
||||
version = v;
|
||||
repaint();
|
||||
resized();
|
||||
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)";
|
||||
toggle.setEnabled (false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name = status = String::empty;
|
||||
toggle.setVisible (false);
|
||||
}
|
||||
}
|
||||
|
||||
void paint (Graphics& g)
|
||||
{
|
||||
if (version != nullptr)
|
||||
{
|
||||
g.setColour (Colours::green.withAlpha (0.12f));
|
||||
g.setColour (Colours::green.withAlpha (0.12f));
|
||||
|
||||
g.fillRect (0, 1, getWidth(), getHeight() - 2);
|
||||
g.setColour (Colours::black);
|
||||
g.setFont (getHeight() * 0.7f);
|
||||
g.fillRect (0, 1, getWidth(), getHeight() - 2);
|
||||
g.setColour (Colours::black);
|
||||
g.setFont (getHeight() * 0.7f);
|
||||
|
||||
String s;
|
||||
s << "Version " << version->version << " - " << version->desc << " - " << version->date;
|
||||
g.drawText (name, toggle.getRight() + 4, 0, getWidth() / 2 - toggle.getRight() - 4, getHeight(),
|
||||
Justification::centredLeft, true);
|
||||
|
||||
g.drawText (s, 4, 0, applyButton.getX() - 4, getHeight(), Justification::centredLeft, true);
|
||||
}
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
applyButton.changeWidthToFitText (getHeight() - 4);
|
||||
applyButton.setTopRightPosition (getWidth(), 2);
|
||||
applyButton.setVisible (version != nullptr);
|
||||
}
|
||||
|
||||
void buttonClicked (Button*)
|
||||
{
|
||||
updater.applyVersion (version);
|
||||
g.drawText (status, getWidth() / 2, 0, getWidth() / 2, getHeight(),
|
||||
Justification::centredLeft, true);
|
||||
}
|
||||
|
||||
private:
|
||||
JuceUpdater& updater;
|
||||
VersionInfo* version;
|
||||
TextButton applyButton;
|
||||
ToggleButton toggle;
|
||||
String name, status;
|
||||
};
|
||||
|
||||
UpdateListComponent* c = dynamic_cast <UpdateListComponent*> (existingComponentToUpdate);
|
||||
if (c == nullptr)
|
||||
c = new UpdateListComponent (*this);
|
||||
|
||||
c->setVersion (availableVersions [rowNumber]);
|
||||
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&) {}
|
||||
|
|
|
|||
|
|
@ -26,18 +26,21 @@
|
|||
#ifndef __JUCER_JUCEUPDATER_JUCEHEADER__
|
||||
#define __JUCER_JUCEUPDATER_JUCEHEADER__
|
||||
|
||||
#include "../Project/jucer_Module.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class JuceUpdater : public Component,
|
||||
public ButtonListener,
|
||||
public FilenameComponentListener,
|
||||
public ListBoxModel
|
||||
private ButtonListener,
|
||||
private FilenameComponentListener,
|
||||
private ListBoxModel,
|
||||
private ValueTree::Listener
|
||||
{
|
||||
public:
|
||||
JuceUpdater();
|
||||
JuceUpdater (ModuleList& moduleList);
|
||||
~JuceUpdater();
|
||||
|
||||
static void show (Component* mainWindow);
|
||||
static void show (ModuleList& moduleList, Component* mainWindow);
|
||||
|
||||
//==============================================================================
|
||||
void resized();
|
||||
|
|
@ -49,29 +52,36 @@ public:
|
|||
void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected);
|
||||
Component* refreshComponentForRow (int rowNumber, bool isRowSelected, Component* existingComponentToUpdate);
|
||||
|
||||
void backgroundUpdateComplete (const ModuleList& newList);
|
||||
|
||||
private:
|
||||
ModuleList& moduleList;
|
||||
ModuleList latestList;
|
||||
|
||||
Label label, currentVersionLabel;
|
||||
FilenameComponent filenameComp;
|
||||
TextButton checkNowButton;
|
||||
ListBox availableVersionsList;
|
||||
ValueTree versionsToDownload;
|
||||
TextButton installButton;
|
||||
ToggleButton selectAllButton;
|
||||
ScopedPointer<Thread> websiteContacterThread;
|
||||
|
||||
XmlElement* downloadVersionList();
|
||||
String getCurrentVersion();
|
||||
bool isAlreadyUpToDate();
|
||||
void checkNow();
|
||||
void install();
|
||||
void updateInstallButtonStatus();
|
||||
void refresh();
|
||||
void selectAll();
|
||||
int getNumCheckedModules() const;
|
||||
bool isLatestVersion (const String& moduleID) const;
|
||||
|
||||
struct VersionInfo
|
||||
{
|
||||
URL url;
|
||||
String desc;
|
||||
String version;
|
||||
String date;
|
||||
};
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier&);
|
||||
void valueTreeChildAdded (ValueTree&, ValueTree&);
|
||||
void valueTreeChildRemoved (ValueTree&, ValueTree&);
|
||||
void valueTreeChildOrderChanged (ValueTree&);
|
||||
void valueTreeParentChanged (ValueTree&);
|
||||
|
||||
OwnedArray<VersionInfo> availableVersions;
|
||||
|
||||
void updateVersions (const XmlElement& xml);
|
||||
void applyVersion (VersionInfo* version);
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceUpdater);
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCER_JUCEUPDATER_JUCEHEADER__
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
#include "../Code Editor/jucer_SourceCodeEditor.h"
|
||||
#include "../Project/jucer_NewProjectWizard.h"
|
||||
|
||||
ApplicationCommandManager* commandManager = nullptr;
|
||||
ScopedPointer<ApplicationCommandManager> commandManager;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -66,18 +66,18 @@ ProjectExporter* ProjectExporter::createNewExporter (Project& project, const int
|
|||
|
||||
switch (index)
|
||||
{
|
||||
case 0: exp = new XCodeProjectExporter (project, ValueTree (XCodeProjectExporter::getValueTreeTypeName (false)), false); break;
|
||||
case 1: exp = new XCodeProjectExporter (project, ValueTree (XCodeProjectExporter::getValueTreeTypeName (true)), true); break;
|
||||
case 2: exp = new MSVCProjectExporterVC6 (project, ValueTree (MSVCProjectExporterVC6::getValueTreeTypeName())); break;
|
||||
case 0: exp = new XCodeProjectExporter (project, ValueTree (XCodeProjectExporter ::getValueTreeTypeName (false)), false); break;
|
||||
case 1: exp = new XCodeProjectExporter (project, ValueTree (XCodeProjectExporter ::getValueTreeTypeName (true)), true); break;
|
||||
case 2: exp = new MSVCProjectExporterVC6 (project, ValueTree (MSVCProjectExporterVC6 ::getValueTreeTypeName())); break;
|
||||
case 3: exp = new MSVCProjectExporterVC2005 (project, ValueTree (MSVCProjectExporterVC2005::getValueTreeTypeName())); break;
|
||||
case 4: exp = new MSVCProjectExporterVC2008 (project, ValueTree (MSVCProjectExporterVC2008::getValueTreeTypeName())); break;
|
||||
case 5: exp = new MSVCProjectExporterVC2010 (project, ValueTree (MSVCProjectExporterVC2010::getValueTreeTypeName())); break;
|
||||
case 6: exp = new MakefileProjectExporter (project, ValueTree (MakefileProjectExporter::getValueTreeTypeName())); break;
|
||||
case 7: exp = new AndroidProjectExporter (project, ValueTree (AndroidProjectExporter::getValueTreeTypeName())); break;
|
||||
case 6: exp = new MakefileProjectExporter (project, ValueTree (MakefileProjectExporter ::getValueTreeTypeName())); break;
|
||||
case 7: exp = new AndroidProjectExporter (project, ValueTree (AndroidProjectExporter ::getValueTreeTypeName())); break;
|
||||
default: jassertfalse; return 0;
|
||||
}
|
||||
|
||||
File juceFolder (StoredSettings::getInstance()->getLastKnownJuceFolder());
|
||||
File juceFolder (ModuleList::getLocalModulesFolder (&project));
|
||||
File target (exp->getTargetFolder());
|
||||
|
||||
if (FileHelpers::shouldPathsBeRelative (juceFolder.getFullPathName(), project.getFile().getFullPathName()))
|
||||
|
|
@ -95,13 +95,13 @@ ProjectExporter* ProjectExporter::createNewExporter (Project& project, const Str
|
|||
|
||||
ProjectExporter* ProjectExporter::createExporter (Project& project, const ValueTree& settings)
|
||||
{
|
||||
ProjectExporter* exp = MSVCProjectExporterVC6::createForSettings (project, settings);
|
||||
ProjectExporter* exp = MSVCProjectExporterVC6 ::createForSettings (project, settings);
|
||||
if (exp == nullptr) exp = MSVCProjectExporterVC2005::createForSettings (project, settings);
|
||||
if (exp == nullptr) exp = MSVCProjectExporterVC2008::createForSettings (project, settings);
|
||||
if (exp == nullptr) exp = MSVCProjectExporterVC2010::createForSettings (project, settings);
|
||||
if (exp == nullptr) exp = XCodeProjectExporter::createForSettings (project, settings);
|
||||
if (exp == nullptr) exp = MakefileProjectExporter::createForSettings (project, settings);
|
||||
if (exp == nullptr) exp = AndroidProjectExporter::createForSettings (project, settings);
|
||||
if (exp == nullptr) exp = XCodeProjectExporter ::createForSettings (project, settings);
|
||||
if (exp == nullptr) exp = MakefileProjectExporter ::createForSettings (project, settings);
|
||||
if (exp == nullptr) exp = AndroidProjectExporter ::createForSettings (project, settings);
|
||||
|
||||
jassert (exp != nullptr);
|
||||
return exp;
|
||||
|
|
@ -115,7 +115,6 @@ ProjectExporter* ProjectExporter::createPlatformDefaultExporter (Project& projec
|
|||
for (int i = 0; i < project.getNumExporters(); ++i)
|
||||
{
|
||||
ScopedPointer <ProjectExporter> exp (project.createExporter (i));
|
||||
|
||||
const int pref = exp->getLaunchPreferenceOrderForCurrentOS();
|
||||
|
||||
if (pref > bestPref)
|
||||
|
|
@ -210,7 +209,7 @@ void ProjectExporter::createPropertyEditors (Array <PropertyComponent*>& props)
|
|||
props.getLast()->setTooltip ("The location of the Juce library folder that the " + name + " project will use to when compiling. This can be an absolute path, or relative to the jucer project folder, but it must be valid on the filesystem of the machine you use to actually do the compiling.");
|
||||
|
||||
OwnedArray<LibraryModule> modules;
|
||||
ModuleList moduleList;
|
||||
ModuleList moduleList (ModuleList::getDefaultModulesFolder (&project));
|
||||
project.createRequiredModules (moduleList, modules);
|
||||
for (int i = 0; i < modules.size(); ++i)
|
||||
modules.getUnchecked(i)->createPropertyEditors (*this, props);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public:
|
|||
OwnedArray<LibraryModule> modules;
|
||||
|
||||
{
|
||||
ModuleList moduleList;
|
||||
ModuleList moduleList (ModuleList::getDefaultModulesFolder (&project));
|
||||
project.createRequiredModules (moduleList, modules);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,9 +31,94 @@
|
|||
|
||||
|
||||
//==============================================================================
|
||||
ModuleList::ModuleList()
|
||||
ModuleList::ModuleList (const File& modulesFolder_)
|
||||
{
|
||||
rescan();
|
||||
rescan (modulesFolder_);
|
||||
}
|
||||
|
||||
ModuleList::ModuleList (const ModuleList& other)
|
||||
: moduleFolder (other.moduleFolder)
|
||||
{
|
||||
modules.addCopiesOf (other.modules);
|
||||
}
|
||||
|
||||
ModuleList& ModuleList::operator= (const ModuleList& other)
|
||||
{
|
||||
moduleFolder = other.moduleFolder;
|
||||
modules.clear();
|
||||
modules.addCopiesOf (other.modules);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool ModuleList::operator== (const ModuleList& other) const
|
||||
{
|
||||
if (modules.size() != other.modules.size())
|
||||
return false;
|
||||
|
||||
for (int i = modules.size(); --i >= 0;)
|
||||
{
|
||||
const Module* m1 = modules.getUnchecked(i);
|
||||
const Module* m2 = other.findModuleInfo (m1->uid);
|
||||
|
||||
if (m2 == nullptr || *m1 != *m2)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
File ModuleList::getModulesFolderForJuceOrModulesFolder (const File& f)
|
||||
{
|
||||
if (f.getFileName() != "modules" && f.isDirectory() && f.getChildFile ("modules").isDirectory())
|
||||
return f.getChildFile ("modules");
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
File ModuleList::getDefaultModulesFolder (Project* project)
|
||||
{
|
||||
if (project != nullptr)
|
||||
{
|
||||
ScopedPointer <ProjectExporter> exp (ProjectExporter::createPlatformDefaultExporter (*project));
|
||||
|
||||
if (exp != nullptr)
|
||||
{
|
||||
File f (project->resolveFilename (exp->getJuceFolder().toString()));
|
||||
f = getModulesFolderForJuceOrModulesFolder (f);
|
||||
|
||||
if (FileHelpers::isModulesFolder (f))
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return File::getSpecialLocation (File::userHomeDirectory)
|
||||
.getChildFile ("juce")
|
||||
.getChildFile ("modules");
|
||||
}
|
||||
|
||||
File ModuleList::getLocalModulesFolder (Project* project)
|
||||
{
|
||||
File defaultJuceFolder (getDefaultModulesFolder (project));
|
||||
|
||||
File f (StoredSettings::getInstance()->getProps().getValue ("lastJuceFolder", defaultJuceFolder.getFullPathName()));
|
||||
f = getModulesFolderForJuceOrModulesFolder (f);
|
||||
|
||||
if ((! FileHelpers::isModulesFolder (f)) && FileHelpers::isModulesFolder (defaultJuceFolder))
|
||||
f = defaultJuceFolder;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
File ModuleList::getModuleFolder (const String& uid) const
|
||||
{
|
||||
return getModulesFolder().getChildFile (uid);
|
||||
}
|
||||
|
||||
void ModuleList::setLocalModulesFolder (const File& file)
|
||||
{
|
||||
//jassert (FileHelpers::isJuceFolder (file));
|
||||
StoredSettings::getInstance()->getProps().setValue ("lastJuceFolder", file.getFullPathName());
|
||||
}
|
||||
|
||||
struct ModuleSorter
|
||||
|
|
@ -51,31 +136,39 @@ void ModuleList::sort()
|
|||
}
|
||||
|
||||
void ModuleList::rescan()
|
||||
{
|
||||
rescan (moduleFolder);
|
||||
}
|
||||
|
||||
void ModuleList::rescan (const File& newModulesFolder)
|
||||
{
|
||||
modules.clear();
|
||||
moduleFolder = StoredSettings::getInstance()->getLastKnownJuceFolder().getChildFile ("modules");
|
||||
moduleFolder = getModulesFolderForJuceOrModulesFolder (newModulesFolder);
|
||||
|
||||
DirectoryIterator iter (moduleFolder, false, "*", File::findDirectories);
|
||||
|
||||
while (iter.next())
|
||||
if (moduleFolder.isDirectory())
|
||||
{
|
||||
const File moduleDef (iter.getFile().getChildFile (LibraryModule::getInfoFileName()));
|
||||
DirectoryIterator iter (moduleFolder, false, "*", File::findDirectories);
|
||||
|
||||
if (moduleDef.exists())
|
||||
while (iter.next())
|
||||
{
|
||||
LibraryModule m (moduleDef);
|
||||
jassert (m.isValid());
|
||||
const File moduleDef (iter.getFile().getChildFile (LibraryModule::getInfoFileName()));
|
||||
|
||||
if (m.isValid())
|
||||
if (moduleDef.exists())
|
||||
{
|
||||
Module* info = new Module();
|
||||
modules.add (info);
|
||||
LibraryModule m (moduleDef);
|
||||
jassert (m.isValid());
|
||||
|
||||
info->uid = m.getID();
|
||||
info->version = m.getVersion();
|
||||
info->name = m.moduleInfo ["name"];
|
||||
info->description = m.moduleInfo ["description"];
|
||||
info->file = moduleDef;
|
||||
if (m.isValid())
|
||||
{
|
||||
Module* info = new Module();
|
||||
modules.add (info);
|
||||
|
||||
info->uid = m.getID();
|
||||
info->version = m.getVersion();
|
||||
info->name = m.moduleInfo ["name"];
|
||||
info->description = m.moduleInfo ["description"];
|
||||
info->file = moduleDef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -83,7 +176,7 @@ void ModuleList::rescan()
|
|||
sort();
|
||||
}
|
||||
|
||||
void ModuleList::loadFromWebsite()
|
||||
bool ModuleList::loadFromWebsite()
|
||||
{
|
||||
modules.clear();
|
||||
|
||||
|
|
@ -122,6 +215,7 @@ void ModuleList::loadFromWebsite()
|
|||
}
|
||||
|
||||
sort();
|
||||
return infoList.isArray();
|
||||
}
|
||||
|
||||
LibraryModule* ModuleList::Module::create() const
|
||||
|
|
@ -129,6 +223,21 @@ LibraryModule* ModuleList::Module::create() const
|
|||
return new LibraryModule (file);
|
||||
}
|
||||
|
||||
bool ModuleList::Module::operator== (const Module& other) const
|
||||
{
|
||||
return uid == other.uid
|
||||
&& version == other.version
|
||||
&& name == other.name
|
||||
&& description == other.description
|
||||
&& file == other.file
|
||||
&& url == other.url;
|
||||
}
|
||||
|
||||
bool ModuleList::Module::operator!= (const Module& other) const
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
LibraryModule* ModuleList::loadModule (const String& uid) const
|
||||
{
|
||||
const Module* const m = findModuleInfo (uid);
|
||||
|
|
|
|||
|
|
@ -86,11 +86,17 @@ private:
|
|||
class ModuleList
|
||||
{
|
||||
public:
|
||||
ModuleList();
|
||||
ModuleList (const File& modulesFolder);
|
||||
ModuleList (const ModuleList&);
|
||||
ModuleList& operator= (const ModuleList&);
|
||||
|
||||
//==============================================================================
|
||||
void rescan (const File& newModulesFolder);
|
||||
void rescan();
|
||||
void loadFromWebsite();
|
||||
File getModulesFolder() const { return moduleFolder; }
|
||||
File getModuleFolder (const String& uid) const;
|
||||
|
||||
bool loadFromWebsite();
|
||||
|
||||
LibraryModule* loadModule (const String& uid) const;
|
||||
|
||||
|
|
@ -105,10 +111,24 @@ public:
|
|||
String uid, version, name, description;
|
||||
File file;
|
||||
URL url;
|
||||
|
||||
bool operator== (const Module&) const;
|
||||
bool operator!= (const Module&) const;
|
||||
};
|
||||
|
||||
const Module* findModuleInfo (const String& uid) const;
|
||||
|
||||
bool operator== (const ModuleList&) const;
|
||||
|
||||
//==============================================================================
|
||||
static File getDefaultModulesFolder (Project* project);
|
||||
|
||||
static File getLocalModulesFolder (Project* project);
|
||||
static void setLocalModulesFolder (const File& newFile);
|
||||
|
||||
static File getModulesFolderForJuceOrModulesFolder (const File& f);
|
||||
|
||||
//==============================================================================
|
||||
OwnedArray<Module> modules;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "jucer_NewProjectWizard.h"
|
||||
#include "jucer_ProjectType.h"
|
||||
#include "jucer_Module.h"
|
||||
|
||||
//==============================================================================
|
||||
class GUIAppWizard : public NewProjectWizard
|
||||
|
|
@ -451,7 +452,7 @@ Project* NewProjectWizard::runNewProjectWizard (Component* ownerWindow)
|
|||
|
||||
aw.addComboBox ("type", getWizards(), "Project Type");
|
||||
|
||||
FilenameComponent juceFolderSelector ("Juce Library Location", StoredSettings::getInstance()->getLastKnownJuceFolder(),
|
||||
FilenameComponent juceFolderSelector ("Juce Library Location", ModuleList::getLocalModulesFolder (nullptr),
|
||||
true, true, false, "*", String::empty, "(Please select the folder containing Juce!)");
|
||||
juceFolderSelector.setSize (350, 22);
|
||||
|
||||
|
|
|
|||
|
|
@ -177,18 +177,6 @@ const String Project::saveDocument (const File& file)
|
|||
updateProjectSettings();
|
||||
sanitiseConfigFlags();
|
||||
|
||||
{
|
||||
ScopedPointer <ProjectExporter> exp (ProjectExporter::createPlatformDefaultExporter (*this));
|
||||
|
||||
if (exp != nullptr)
|
||||
{
|
||||
File f (resolveFilename (exp->getJuceFolder().toString()));
|
||||
|
||||
if (FileHelpers::isJuceFolder (f))
|
||||
StoredSettings::getInstance()->setLastKnownJuceFolder (f.getFullPathName());
|
||||
}
|
||||
}
|
||||
|
||||
StoredSettings::getInstance()->recentFiles.addFile (file);
|
||||
|
||||
ProjectSaver saver (*this, file);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
//[CppHeaders] You can add your own extra header files here...
|
||||
#include "../Project Saving/jucer_ProjectExporter.h"
|
||||
#include "jucer_Module.h"
|
||||
#include "../Application/jucer_JuceUpdater.h"
|
||||
//[/CppHeaders]
|
||||
|
||||
#include "jucer_ProjectInformationComponent.h"
|
||||
|
|
@ -126,7 +127,7 @@ public:
|
|||
ModuleSettingsPanel (Project& project_, ModuleList& moduleList_, const String& moduleID_)
|
||||
: PanelBase (project_), moduleList (moduleList_), moduleID (moduleID_)
|
||||
{
|
||||
setBounds ("parent.width / 2 + 1, 3, parent.width - 3, parent.height - 3");
|
||||
setBounds ("parent.width / 2 + 1, 31, parent.width - 3, parent.height - 3");
|
||||
}
|
||||
|
||||
void rebuildProperties (Array <PropertyComponent*>& props)
|
||||
|
|
@ -207,7 +208,7 @@ private:
|
|||
if (module != nullptr)
|
||||
{
|
||||
String text;
|
||||
text << module->name << newLine << newLine
|
||||
text << module->name << newLine << "Version: " << module->version << newLine << newLine
|
||||
<< module->description;
|
||||
|
||||
GlyphArrangement ga;
|
||||
|
|
@ -279,16 +280,34 @@ private:
|
|||
|
||||
//==============================================================================
|
||||
class ModulesPanel : public Component,
|
||||
public ListBoxModel
|
||||
public ListBoxModel,
|
||||
public FilenameComponentListener,
|
||||
public ButtonListener
|
||||
{
|
||||
public:
|
||||
ModulesPanel (Project& project_)
|
||||
: project (project_)
|
||||
: project (project_),
|
||||
moduleList (ModuleList::getLocalModulesFolder (&project)),
|
||||
modulesLocation ("modules", moduleList.getModulesFolder(),
|
||||
true, true, false, "*", String::empty,
|
||||
"Select a folder containing your JUCE modules..."),
|
||||
modulesLabel (String::empty, "Module source folder:"),
|
||||
updateModulesButton ("Check for module updates...")
|
||||
{
|
||||
addAndMakeVisible (&modulesLocation);
|
||||
modulesLocation.setBounds ("150, 3, parent.width - 180, 28");
|
||||
modulesLocation.addListener (this);
|
||||
|
||||
modulesLabel.attachToComponent (&modulesLocation, true);
|
||||
|
||||
addAndMakeVisible (&updateModulesButton);
|
||||
updateModulesButton.setBounds ("parent.width - 175, 3, parent.width - 4, 28");
|
||||
updateModulesButton.addListener (this);
|
||||
|
||||
modulesList.setModel (this);
|
||||
modulesList.setColour (ListBox::backgroundColourId, Colours::white.withAlpha (0.4f));
|
||||
addAndMakeVisible (&modulesList);
|
||||
modulesList.setBounds ("4, 3, parent.width / 2 - 4, parent.height - 3");
|
||||
modulesList.setBounds ("4, 31, parent.width / 2 - 4, parent.height - 3");
|
||||
}
|
||||
|
||||
int getNumRows()
|
||||
|
|
@ -330,36 +349,29 @@ public:
|
|||
if (m != nullptr)
|
||||
{
|
||||
if (project.isModuleEnabled (m->uid))
|
||||
{
|
||||
project.removeModule (m->uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
const StringArray extraDepsNeeded (getExtraDependenciesNeeded (project, moduleList, *m));
|
||||
|
||||
/* if (extraDepsNeeded.size() > 0)
|
||||
{
|
||||
if (AlertWindow::showOkCancelBox (AlertWindow::NoIcon,
|
||||
"Module Dependencies",
|
||||
"The '" + m->uid + "' module requires the following dependencies:\n"
|
||||
+ extraDepsNeeded.joinIntoString (", ") + "\n\nDo you want to add all these to your project?"))
|
||||
{
|
||||
project.addModule (m->uid);
|
||||
|
||||
for (int i = extraDepsNeeded.size(); --i >= 0;)
|
||||
project.addModule (extraDepsNeeded[i]);
|
||||
}
|
||||
}
|
||||
else*/
|
||||
{
|
||||
project.addModule (m->uid);
|
||||
}
|
||||
}
|
||||
project.addModule (m->uid);
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void filenameComponentChanged (FilenameComponent*)
|
||||
{
|
||||
moduleList.rescan (modulesLocation.getCurrentFile());
|
||||
modulesLocation.setCurrentFile (moduleList.getModulesFolder(), false, false);
|
||||
ModuleList::setLocalModulesFolder (moduleList.getModulesFolder());
|
||||
modulesList.updateContent();
|
||||
}
|
||||
|
||||
void buttonClicked (Button*)
|
||||
{
|
||||
JuceUpdater::show (moduleList, getTopLevelComponent());
|
||||
|
||||
filenameComponentChanged (nullptr);
|
||||
}
|
||||
|
||||
void listBoxItemClicked (int row, const MouseEvent& e)
|
||||
{
|
||||
if (e.x < modulesList.getRowHeight())
|
||||
|
|
@ -397,6 +409,9 @@ public:
|
|||
private:
|
||||
Project& project;
|
||||
ModuleList moduleList;
|
||||
FilenameComponent modulesLocation;
|
||||
Label modulesLabel;
|
||||
TextButton updateModulesButton;
|
||||
ListBox modulesList;
|
||||
ScopedPointer<ModuleSettingsPanel> settings;
|
||||
};
|
||||
|
|
@ -440,16 +455,16 @@ ProjectInformationComponent::ProjectInformationComponent (Project& project_)
|
|||
//[UserPreSize]
|
||||
rebuildConfigTabs();
|
||||
|
||||
#if JUCE_MAC || JUCE_WINDOWS
|
||||
#if JUCE_MAC || JUCE_WINDOWS
|
||||
openProjectButton.setCommandToTrigger (commandManager, CommandIDs::openInIDE, true);
|
||||
openProjectButton.setButtonText (commandManager->getNameOfCommand (CommandIDs::openInIDE));
|
||||
|
||||
saveAndOpenButton.setCommandToTrigger (commandManager, CommandIDs::saveAndOpenInIDE, true);
|
||||
saveAndOpenButton.setButtonText (commandManager->getNameOfCommand (CommandIDs::saveAndOpenInIDE));
|
||||
#else
|
||||
#else
|
||||
openProjectButton.setVisible (false);
|
||||
saveAndOpenButton.setVisible (false);
|
||||
#endif
|
||||
#endif
|
||||
//[/UserPreSize]
|
||||
|
||||
setSize (836, 427);
|
||||
|
|
|
|||
|
|
@ -150,10 +150,16 @@ namespace FileHelpers
|
|||
bool isJuceFolder (const File& folder)
|
||||
{
|
||||
return folder.getFileName().containsIgnoreCase ("juce")
|
||||
&& folder.getChildFile ("modules").isDirectory();
|
||||
&& isModulesFolder (folder.getChildFile ("modules"));
|
||||
}
|
||||
|
||||
static File lookInFolderForJuceFolder (const File& folder)
|
||||
bool isModulesFolder (const File& folder)
|
||||
{
|
||||
return folder.getFileName().equalsIgnoreCase ("modules")
|
||||
&& folder.isDirectory();
|
||||
}
|
||||
|
||||
File lookInFolderForJuceFolder (const File& folder)
|
||||
{
|
||||
for (DirectoryIterator di (folder, false, "*juce*", File::findDirectories); di.next();)
|
||||
{
|
||||
|
|
@ -182,17 +188,4 @@ namespace FileHelpers
|
|||
|
||||
return File::nonexistent;
|
||||
}
|
||||
|
||||
File findDefaultJuceFolder()
|
||||
{
|
||||
File f = findParentJuceFolder (File::getSpecialLocation (File::currentApplicationFile));
|
||||
|
||||
if (! f.exists())
|
||||
f = lookInFolderForJuceFolder (File::getSpecialLocation (File::userHomeDirectory));
|
||||
|
||||
if (! f.exists())
|
||||
f = lookInFolderForJuceFolder (File::getSpecialLocation (File::userDocumentsDirectory));
|
||||
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,8 +46,9 @@ namespace FileHelpers
|
|||
|
||||
//==============================================================================
|
||||
bool isJuceFolder (const File& folder);
|
||||
bool isModulesFolder (const File& folder);
|
||||
File findParentJuceFolder (const File& file);
|
||||
File findDefaultJuceFolder();
|
||||
File lookInFolderForJuceFolder (const File& folder);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -143,23 +143,6 @@ void StoredSettings::setLastProjects (const Array<File>& files)
|
|||
props->setValue ("lastProjects", s.joinIntoString ("|"));
|
||||
}
|
||||
|
||||
File StoredSettings::getLastKnownJuceFolder() const
|
||||
{
|
||||
File defaultJuceFolder (FileHelpers::findDefaultJuceFolder());
|
||||
File f (props->getValue ("lastJuceFolder", defaultJuceFolder.getFullPathName()));
|
||||
|
||||
if ((! FileHelpers::isJuceFolder (f)) && FileHelpers::isJuceFolder (defaultJuceFolder))
|
||||
f = defaultJuceFolder;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void StoredSettings::setLastKnownJuceFolder (const File& file)
|
||||
{
|
||||
jassert (FileHelpers::isJuceFolder (file));
|
||||
props->setValue ("lastJuceFolder", file.getFullPathName());
|
||||
}
|
||||
|
||||
const StringArray& StoredSettings::getFontNames()
|
||||
{
|
||||
if (fontNames.size() == 0)
|
||||
|
|
|
|||
|
|
@ -50,9 +50,6 @@ public:
|
|||
Array<File> getLastProjects() const;
|
||||
void setLastProjects (const Array<File>& files);
|
||||
|
||||
File getLastKnownJuceFolder() const;
|
||||
void setLastKnownJuceFolder (const File& file);
|
||||
|
||||
const StringArray& getFontNames();
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
*/
|
||||
#define JUCE_MAJOR_VERSION 2
|
||||
#define JUCE_MINOR_VERSION 0
|
||||
#define JUCE_BUILDNUMBER 4
|
||||
#define JUCE_BUILDNUMBER 5
|
||||
|
||||
/** Current Juce version number.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue