| @@ -28,6 +28,7 @@ | |||
| #include "../jucer_Headers.h" | |||
| #include "jucer_MainWindow.h" | |||
| #include "jucer_CommandLine.h" | |||
| #include "../project/jucer_Module.h" | |||
| #include "jucer_AutoUpdater.h" | |||
| #include "../Code Editor/jucer_SourceCodeEditor.h" | |||
| @@ -109,8 +109,6 @@ public: | |||
| bool isDifferentVersionToCurrent() const | |||
| { | |||
| JUCE_COMPILER_WARNING("testing") | |||
| return true; | |||
| return version != JUCE_STRINGIFY(JUCE_MAJOR_VERSION) | |||
| "." JUCE_STRINGIFY(JUCE_MINOR_VERSION) | |||
| "." JUCE_STRINGIFY(JUCE_BUILDNUMBER) | |||
| @@ -141,23 +139,69 @@ return true; | |||
| } | |||
| else | |||
| { | |||
| JUCE_COMPILER_WARNING("todo") | |||
| if (! AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, | |||
| TRANS("Download JUCE version 123?").replace ("123", info.version), | |||
| TRANS("A new version of JUCE is available - would you like to download it?"))) | |||
| { | |||
| return; | |||
| } | |||
| File targetFolder; | |||
| File targetFolder (findDefaultModulesFolder()); | |||
| // FileChooser f; | |||
| if (isJuceModulesFolder (targetFolder)) | |||
| targetFolder = targetFolder.getParentDirectory(); | |||
| DownloadNewVersionThread::performDownload (info.url, targetFolder); | |||
| 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 Introjucer 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 (info.url, targetFolder); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static bool isZipFolder (const File& f) | |||
| { | |||
| JUCE_COMPILER_WARNING("testing") | |||
| return true; | |||
| return f.getChildFile ("modules").isDirectory() | |||
| && f.getChildFile ("extras").isDirectory() | |||
| && f.getChildFile ("examples").isDirectory() | |||
| @@ -220,7 +264,7 @@ private: | |||
| } | |||
| else | |||
| { | |||
| JUCE_COMPILER_WARNING("todo") | |||
| new RelaunchTimer (targetFolder); | |||
| } | |||
| } | |||
| } | |||
| @@ -252,7 +296,7 @@ JUCE_COMPILER_WARNING("todo") | |||
| if (threadShouldExit()) | |||
| return Result::fail ("cancel"); | |||
| size_t written = mo.writeFromInputStream (*in, 8192); | |||
| int64 written = mo.writeFromInputStream (*in, 8192); | |||
| if (written == 0) | |||
| break; | |||
| @@ -273,7 +317,8 @@ JUCE_COMPILER_WARNING("todo") | |||
| { | |||
| setStatusMessage ("Installing..."); | |||
| File tempUnzipped; | |||
| File unzipTarget; | |||
| bool isUsingTempFolder = false; | |||
| { | |||
| MemoryInputStream input (data, false); | |||
| @@ -282,32 +327,43 @@ JUCE_COMPILER_WARNING("todo") | |||
| if (zip.getNumEntries() == 0) | |||
| return Result::fail ("The downloaded file wasn't a valid JUCE file!"); | |||
| tempUnzipped = targetFolder.getNonexistentSibling(); | |||
| unzipTarget = targetFolder; | |||
| if (! tempUnzipped.createDirectory()) | |||
| return Result::fail ("Couldn't create a folder to unzip the new version!"); | |||
| if (unzipTarget.exists()) | |||
| { | |||
| isUsingTempFolder = true; | |||
| unzipTarget = targetFolder.getNonexistentSibling(); | |||
| Result r (zip.uncompressTo (tempUnzipped)); | |||
| if (! unzipTarget.createDirectory()) | |||
| return Result::fail ("Couldn't create a folder to unzip the new version!"); | |||
| } | |||
| Result r (zip.uncompressTo (unzipTarget)); | |||
| if (r.failed()) | |||
| { | |||
| tempUnzipped.deleteRecursively(); | |||
| if (isUsingTempFolder) | |||
| unzipTarget.deleteRecursively(); | |||
| return r; | |||
| } | |||
| } | |||
| File oldFolder (targetFolder.getSiblingFile (targetFolder.getFileNameWithoutExtension() + "_old").getNonexistentSibling()); | |||
| if (! targetFolder.moveFileTo (targetFolder.getNonexistentSibling())) | |||
| if (isUsingTempFolder) | |||
| { | |||
| tempUnzipped.deleteRecursively(); | |||
| return Result::fail ("Could not remove the existing folder!"); | |||
| } | |||
| File oldFolder (targetFolder.getSiblingFile (targetFolder.getFileNameWithoutExtension() + "_old").getNonexistentSibling()); | |||
| if (! tempUnzipped.moveFileTo (targetFolder)) | |||
| { | |||
| tempUnzipped.deleteRecursively(); | |||
| return Result::fail ("Could not overwrite the existing folder!"); | |||
| 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(); | |||
| @@ -320,6 +376,37 @@ JUCE_COMPILER_WARNING("todo") | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DownloadNewVersionThread) | |||
| }; | |||
| struct RelaunchTimer : private Timer | |||
| { | |||
| RelaunchTimer (const File& f) : parentFolder (f) | |||
| { | |||
| startTimer (1500); | |||
| } | |||
| void timerCallback() override | |||
| { | |||
| stopTimer(); | |||
| File app = parentFolder.getChildFile ( | |||
| #if JUCE_MAC | |||
| "Introjucer.app"); | |||
| #elif JUCE_WINDOWS | |||
| "Introjucer.exe"); | |||
| #elif JUCE_LINUX | |||
| "Introjucer"); | |||
| #endif | |||
| JUCEApplication::quit(); | |||
| if (app.exists()) | |||
| app.startAsProcess(); | |||
| delete this; | |||
| } | |||
| File parentFolder; | |||
| }; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LatestVersionChecker) | |||
| }; | |||
| @@ -543,3 +543,24 @@ Project* MainWindowList::getFrontmostProject() | |||
| return nullptr; | |||
| } | |||
| File findDefaultModulesFolder (bool mustContainJuceCoreModule) | |||
| { | |||
| const MainWindowList& windows = IntrojucerApp::getApp().mainWindowList; | |||
| for (int i = windows.windows.size(); --i >= 0;) | |||
| { | |||
| if (Project* p = windows.windows.getUnchecked (i)->getProject()) | |||
| { | |||
| const File f (EnabledModuleList::findDefaultModulesFolder (*p)); | |||
| if (isJuceModulesFolder (f) || (f.isDirectory() && ! mustContainJuceCoreModule)) | |||
| return f; | |||
| } | |||
| } | |||
| if (mustContainJuceCoreModule) | |||
| return findDefaultModulesFolder (false); | |||
| return File::nonexistent; | |||
| } | |||
| @@ -895,3 +895,13 @@ void EnabledModuleList::addModuleOfferingToCopy (const File& f) | |||
| addModule (m.manifestFile, areMostModulesCopiedLocally()); | |||
| } | |||
| bool isJuceFolder (const File& f) | |||
| { | |||
| return isJuceModulesFolder (f.getChildFile ("modules")); | |||
| } | |||
| bool isJuceModulesFolder (const File& f) | |||
| { | |||
| return f.isDirectory() && f.getChildFile ("juce_core").isDirectory(); | |||
| } | |||
| @@ -30,6 +30,11 @@ | |||
| class ProjectExporter; | |||
| class ProjectSaver; | |||
| //============================================================================== | |||
| File findDefaultModulesFolder (bool mustContainJuceCoreModule = true); | |||
| bool isJuceModulesFolder (const File&); | |||
| bool isJuceFolder (const File&); | |||
| //============================================================================== | |||
| struct ModuleDescription | |||
| { | |||
| @@ -30,7 +30,7 @@ | |||
| #include "../Project Saving/jucer_ProjectExporter.h" | |||
| #include "../Utility/jucer_TranslationTool.h" | |||
| #include "../Utility/jucer_JucerTreeViewBase.h" | |||
| #include "jucer_NewFileWizard.h" | |||
| #include "../Wizards/jucer_NewFileWizard.h" | |||
| #include "jucer_GroupInformationComponent.h" | |||
| //============================================================================== | |||
| @@ -241,7 +241,8 @@ void ProjectContentComponent::resized() | |||
| if (contentView != nullptr) | |||
| contentView->setBounds (r); | |||
| logo->setBounds (r.reduced (r.getWidth() / 4, r.getHeight() / 4)); | |||
| if (logo != nullptr) | |||
| logo->setBounds (r.reduced (r.getWidth() / 4, r.getHeight() / 4)); | |||
| } | |||
| void ProjectContentComponent::lookAndFeelChanged() | |||
| @@ -26,7 +26,7 @@ | |||
| #define __JUCER_NEWFILEWIZARD_JUCEHEADER__ | |||
| #include "../jucer_Headers.h" | |||
| #include "jucer_Project.h" | |||
| #include "../Project/jucer_Project.h" | |||
| //============================================================================== | |||
| @@ -77,33 +77,6 @@ static File& getLastWizardFolder() | |||
| return lastFolder; | |||
| } | |||
| static bool isJuceModulesFolder (const File& f) | |||
| { | |||
| return f.isDirectory() | |||
| && f.getChildFile ("juce_core").isDirectory(); | |||
| } | |||
| static File findDefaultModulesFolder (bool mustContainJuceCoreModule = true) | |||
| { | |||
| const MainWindowList& windows = IntrojucerApp::getApp().mainWindowList; | |||
| for (int i = windows.windows.size(); --i >= 0;) | |||
| { | |||
| if (Project* p = windows.windows.getUnchecked (i)->getProject()) | |||
| { | |||
| const File f (EnabledModuleList::findDefaultModulesFolder (*p)); | |||
| if (isJuceModulesFolder (f) || (f.isDirectory() && ! mustContainJuceCoreModule)) | |||
| return f; | |||
| } | |||
| } | |||
| if (mustContainJuceCoreModule) | |||
| return findDefaultModulesFolder (false); | |||
| return File::nonexistent; | |||
| } | |||
| //============================================================================== | |||
| struct NewProjectWizard | |||
| { | |||
| @@ -24,8 +24,8 @@ | |||
| #include "../jucer_Headers.h" | |||
| #include "jucer_NewProjectWizardClasses.h" | |||
| #include "jucer_ProjectType.h" | |||
| #include "jucer_Module.h" | |||
| #include "../Project/jucer_ProjectType.h" | |||
| #include "../Project/jucer_Module.h" | |||
| #include "../Project Saving/jucer_ProjectExporter.h" | |||
| #include "../Application/jucer_Application.h" | |||
| #include "../Application/jucer_MainWindow.h" | |||
| @@ -154,7 +154,7 @@ public: | |||
| listBox.setOpaque (false); | |||
| listBox.setMultipleSelectionEnabled (true); | |||
| listBox.setClickingTogglesRowSelection (true); | |||
| listBox.setColour (ListBox::ColourIds::backgroundColourId, Colours::white.withAlpha (0.0f)); | |||
| listBox.setColour (ListBox::backgroundColourId, Colours::white.withAlpha (0.0f)); | |||
| addAndMakeVisible (listBox); | |||
| selectDefaultExporterIfNoneSelected(); | |||
| @@ -203,7 +203,7 @@ public: | |||
| if (rowIsSelected) | |||
| g.fillAll (Colour (0x99f29000)); | |||
| Rectangle<float> dotSelect (height, height); | |||
| Rectangle<float> dotSelect ((float) height, (float) height); | |||
| dotSelect.reduce (12, 12); | |||
| g.setColour (Colour (0x33ffffff)); | |||
| @@ -38,13 +38,13 @@ public: | |||
| { | |||
| // svg for thumbnail icon | |||
| ScopedPointer<XmlElement> svg (XmlDocument::parse (thumbSvg)); | |||
| assert (svg != nullptr); | |||
| jassert (svg != nullptr); | |||
| thumb = Drawable::createFromSVG (*svg); | |||
| // svg for thumbnail background highlight | |||
| ScopedPointer<XmlElement> backSvg (XmlDocument::parse (BinaryData::wizard_Highlight_svg)); | |||
| assert (backSvg != nullptr); | |||
| jassert (backSvg != nullptr); | |||
| hoverBackground = Drawable::createFromSVG (*backSvg); | |||
| @@ -60,7 +60,7 @@ public: | |||
| if (isMouseOverButton) | |||
| { | |||
| if (getStyle() == ButtonStyle::ImageFitted) | |||
| if (getStyle() == ImageFitted) | |||
| { | |||
| hoverBackground->drawWithin (g, bounds, RectanglePlacement::centred, 1.0); | |||
| thumb->drawWithin (g, bounds, RectanglePlacement::centred, 1.0); | |||
| @@ -75,7 +75,7 @@ public: | |||
| } | |||
| else | |||
| { | |||
| if (getStyle() == ButtonStyle::ImageFitted) | |||
| if (getStyle() == ImageFitted) | |||
| { | |||
| thumb->drawWithin (g, bounds, RectanglePlacement::centred, 1.0); | |||
| } | |||
| @@ -89,7 +89,7 @@ public: | |||
| Rectangle<float> textTarget; | |||
| // center the text for the text buttons or position the text in the image buttons | |||
| if (getStyle() != ButtonStyle::ImageFitted) | |||
| if (getStyle() != ImageFitted) | |||
| { | |||
| textTarget = getLocalBounds().toFloat(); | |||
| } | |||
| @@ -145,7 +145,7 @@ public: | |||
| ScopedPointer<NewProjectWizard> wizard (createWizardType (i)); | |||
| TemplateOptionButton* b = new TemplateOptionButton (wizard->getName(), | |||
| TemplateOptionButton::ButtonStyle::ImageFitted, | |||
| TemplateOptionButton::ImageFitted, | |||
| wizard->getIcon()); | |||
| optionButtons.add (b); | |||
| addAndMakeVisible (b); | |||
| @@ -156,9 +156,9 @@ public: | |||
| // Handle Open Project button functionality | |||
| ApplicationCommandManager& commandManager = IntrojucerApp::getCommandManager(); | |||
| addAndMakeVisible (blankProjectButton = new TemplateOptionButton ("Create Blank Project", TemplateOptionButton::ButtonStyle::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg)); | |||
| addAndMakeVisible (exampleProjectButton = new TemplateOptionButton ("Open Example Project", TemplateOptionButton::ButtonStyle::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg)); | |||
| addAndMakeVisible (openProjectButton = new TemplateOptionButton ("Open Existing Project", TemplateOptionButton::ButtonStyle::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg)); | |||
| addAndMakeVisible (blankProjectButton = new TemplateOptionButton ("Create Blank Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg)); | |||
| addAndMakeVisible (exampleProjectButton = new TemplateOptionButton ("Open Example Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg)); | |||
| addAndMakeVisible (openProjectButton = new TemplateOptionButton ("Open Existing Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg)); | |||
| blankProjectButton->addListener (this); | |||
| exampleProjectButton->addListener (this); | |||
| @@ -191,7 +191,7 @@ public: | |||
| void resized() override | |||
| { | |||
| Rectangle<int> allOpts = getLocalBounds().reduced (40, 60); | |||
| allOpts.removeFromBottom (allOpts.getHeight() * 0.25); | |||
| allOpts.removeFromBottom (allOpts.getHeight() / 4); | |||
| const int numHorizIcons = 4; | |||
| const int optStep = allOpts.getWidth() / numHorizIcons; | |||
| @@ -41,7 +41,7 @@ | |||
| @code | |||
| XmlDocument myDocument (File ("myfile.xml")); | |||
| XmlElement* mainElement = myDocument.getDocumentElement(); | |||
| ScopedPointer<XmlElement> mainElement (myDocument.getDocumentElement()); | |||
| if (mainElement == nullptr) | |||
| { | |||
| @@ -57,7 +57,7 @@ | |||
| Or you can use the static helper methods for quick parsing.. | |||
| @code | |||
| XmlElement* xml = XmlDocument::parse (myXmlFile); | |||
| ScopedPointer<XmlElement> xml (XmlDocument::parse (myXmlFile)); | |||
| if (xml != nullptr && xml->hasTagName ("foobar")) | |||
| { | |||
| @@ -501,13 +501,20 @@ void Path::addRoundedRectangle (float x, float y, float w, float h, float cs) | |||
| addRoundedRectangle (x, y, w, h, cs, cs); | |||
| } | |||
| void Path::addTriangle (const float x1, const float y1, | |||
| const float x2, const float y2, | |||
| const float x3, const float y3) | |||
| void Path::addTriangle (float x1, float y1, | |||
| float x2, float y2, | |||
| float x3, float y3) | |||
| { | |||
| startNewSubPath (x1, y1); | |||
| lineTo (x2, y2); | |||
| lineTo (x3, y3); | |||
| addTriangle (Point<float> (x1, y1), | |||
| Point<float> (x2, y2), | |||
| Point<float> (x3, y3)); | |||
| } | |||
| void Path::addTriangle (Point<float> p1, Point<float> p2, Point<float> p3) | |||
| { | |||
| startNewSubPath (p1); | |||
| lineTo (p2); | |||
| lineTo (p3); | |||
| closeSubPath(); | |||
| } | |||
| @@ -377,6 +377,18 @@ public: | |||
| float x2, float y2, | |||
| float x3, float y3); | |||
| /** Adds a triangle to the path. | |||
| The triangle is added as a new closed sub-path. (Any currently open paths will be left open). | |||
| Note that whether the vertices are specified in clockwise or anticlockwise | |||
| order will affect how the triangle is filled when it overlaps other | |||
| shapes (the winding order setting will affect this of course). | |||
| */ | |||
| void addTriangle (Point<float> point1, | |||
| Point<float> point2, | |||
| Point<float> point3); | |||
| /** Adds a quadrilateral to the path. | |||
| The quad is added as a new closed sub-path. (Any currently open paths will be left open). | |||
| @@ -102,7 +102,7 @@ public: | |||
| private: | |||
| #if JUCE_CATCH_DEPRECATED_CODE_MISUSE | |||
| // Note that this method has been removed - instead, see LookAndFeel::getTextButtonWidthToFitText() | |||
| // Note that this method has been removed - instead, see LookAndFeel::getTextButtonFont() | |||
| virtual int getFont() { return 0; } | |||
| #endif | |||