diff --git a/examples/Demo/Source/Demos/SystemInfoDemo.cpp b/examples/Demo/Source/Demos/SystemInfoDemo.cpp index f1fa50e639..9810aa7945 100644 --- a/examples/Demo/Source/Demos/SystemInfoDemo.cpp +++ b/examples/Demo/Source/Demos/SystemInfoDemo.cpp @@ -119,7 +119,9 @@ static String getAllSystemInfo() << "User region: " << SystemStats::getUserRegion() << newLine << "User language: " << SystemStats::getUserLanguage() << newLine << "Display language: " << SystemStats::getDisplayLanguage() << newLine - << newLine + << newLine; + + systemInfo << "Number of CPUs: " << SystemStats::getNumCpus() << newLine << "Memory size: " << SystemStats::getMemorySizeInMegabytes() << " MB" << newLine << "CPU vendor: " << SystemStats::getCpuVendor() << newLine @@ -134,12 +136,16 @@ static String getAllSystemInfo() << "CPU has 3DNOW: " << (SystemStats::has3DNow() ? "yes" : "no") << newLine << "CPU has AVX: " << (SystemStats::hasAVX() ? "yes" : "no") << newLine << "CPU has AVX2: " << (SystemStats::hasAVX2() ? "yes" : "no") << newLine - << newLine + << newLine; + + systemInfo << "Current working directory: " << File::getCurrentWorkingDirectory().getFullPathName() << newLine << "Current application file: " << File::getSpecialLocation (File::currentApplicationFile).getFullPathName() << newLine << "Current executable file: " << File::getSpecialLocation (File::currentExecutableFile) .getFullPathName() << newLine << "Invoked executable file: " << File::getSpecialLocation (File::invokedExecutableFile) .getFullPathName() << newLine - << newLine + << newLine; + + systemInfo << "User home folder: " << File::getSpecialLocation (File::userHomeDirectory) .getFullPathName() << newLine << "User desktop folder: " << File::getSpecialLocation (File::userDesktopDirectory) .getFullPathName() << newLine << "User documents folder: " << File::getSpecialLocation (File::userDocumentsDirectory) .getFullPathName() << newLine @@ -150,7 +156,9 @@ static String getAllSystemInfo() << "Common application data folder: " << File::getSpecialLocation (File::commonApplicationDataDirectory).getFullPathName() << newLine << "Common documents folder: " << File::getSpecialLocation (File::commonDocumentsDirectory) .getFullPathName() << newLine << "Local temp folder: " << File::getSpecialLocation (File::tempDirectory) .getFullPathName() << newLine - << newLine + << newLine; + + systemInfo << "File System roots: " << getFileSystemRoots() << newLine << "Free space in home folder: " << File::descriptionOfSizeInBytes (File::getSpecialLocation (File::userHomeDirectory) .getBytesFreeOnVolume()) << newLine diff --git a/extras/Projucer/Source/LiveBuildEngine/projucer_CompileEngineClient.cpp b/extras/Projucer/Source/LiveBuildEngine/projucer_CompileEngineClient.cpp index 6b085b9f23..e8cd610875 100644 --- a/extras/Projucer/Source/LiveBuildEngine/projucer_CompileEngineClient.cpp +++ b/extras/Projucer/Source/LiveBuildEngine/projucer_CompileEngineClient.cpp @@ -89,9 +89,15 @@ namespace ProjectProperties static File getCacheLocation (Project& project) { + String cacheFolderName = project.getProjectFilenameRoot() + "_" + project.getProjectUID(); + + #if JUCE_DEBUG + cacheFolderName += "_debug"; + #endif + return getProjucerTempFolder() .getChildFile ("Intermediate Files") - .getChildFile (project.getProjectFilenameRoot() + "_" + project.getProjectUID()); + .getChildFile (cacheFolderName); } } diff --git a/extras/Projucer/Source/LiveBuildEngine/projucer_CompileEngineServer.cpp b/extras/Projucer/Source/LiveBuildEngine/projucer_CompileEngineServer.cpp index 9cfc99a358..39e459ce71 100644 --- a/extras/Projucer/Source/LiveBuildEngine/projucer_CompileEngineServer.cpp +++ b/extras/Projucer/Source/LiveBuildEngine/projucer_CompileEngineServer.cpp @@ -230,7 +230,7 @@ String createCommandLineForLaunchingServer (const String& pipeName, const String const File exe (File::getSpecialLocation (File::currentExecutableFile).getFullPathName()); - return exe.getFullPathName() + " " + commandPrefix + info.joinIntoString (commandTokenSeparator); + return "\"" + exe.getFullPathName() + "\" " + commandPrefix + info.joinIntoString (commandTokenSeparator); } static ServerIPC* currentServer = nullptr; diff --git a/extras/Projucer/Source/Project/jucer_ProjectContentComponent.cpp b/extras/Projucer/Source/Project/jucer_ProjectContentComponent.cpp index f65729fdfb..42f9d449fc 100644 --- a/extras/Projucer/Source/Project/jucer_ProjectContentComponent.cpp +++ b/extras/Projucer/Source/Project/jucer_ProjectContentComponent.cpp @@ -354,65 +354,95 @@ struct BuildTabComponent : public ConcertinaPanel struct ProjucerDisabledComp : public Component, private Button::Listener { - ProjucerDisabledComp (String message, bool loggedIn, bool canLogin, bool requirePurchase = false, - const String& loginName = String()) - : isLoggedIn (loggedIn), isPurchaseButton (requirePurchase) + ProjucerDisabledComp (String message, bool loggedIn, bool showSubscribeButton, + bool showSignInButton, bool showSwitchAccountButton) + : isLoggedIn (loggedIn) { infoLabel.setColour (Label::textColourId, findColour (mainBackgroundColourId).contrasting (0.7f)); infoLabel.setJustificationType (Justification::centred); infoLabel.setText (message, dontSendNotification); addAndMakeVisible (infoLabel); - if (canLogin) + if (showSubscribeButton) { - addAndMakeVisible (loginButton); - loginButton.addListener (this); + subscribeButton = new TextButton (String ( "Subscribe...")); + addAndMakeVisible (*subscribeButton); + subscribeButton->addListener (this); + } - if (isPurchaseButton) - { - loginButton.setButtonText ("Purchase JUCE Pro..."); - signOutButton = new TextButton (String ("Sign Out ") + loginName); - addAndMakeVisible (*signOutButton); - signOutButton->addListener (this); - } + if (showSignInButton) + { + signInButton = new TextButton (String ( "Sign in...")); + addAndMakeVisible (*signInButton); + signInButton->addListener (this); + } + + if (showSwitchAccountButton) + { + switchAccountButton = new TextButton (String ("Switch account...")); + addAndMakeVisible (*switchAccountButton); + switchAccountButton->addListener (this); } } void resized() override { - infoLabel.centreWithSize (proportionOfWidth (0.9f), 200); - loginButton.setSize (jmin (getWidth() - 10, 150), 22); - loginButton.setCentrePosition (infoLabel.getBounds().getCentreX(), - infoLabel.getBottom() + loginButton.getHeight() * 2); + int infoWidth = proportionOfWidth (0.9f); + int infoHeight = 100; - if (signOutButton != nullptr) + infoLabel.centreWithSize (infoWidth, infoHeight); + + int buttonWidth = jmin (getWidth() - 10, 150); + int buttonHeight = 22; + int itemDistance = 10; + + int buttonCenterX = infoLabel.getBounds().getCentreX(); + int buttonCenterY = infoLabel.getBottom() + itemDistance + buttonHeight / 2; + + if (subscribeButton.get() != nullptr) { - signOutButton->setSize (jmin (getWidth() - 10, 150), 22); - signOutButton->setCentrePosition (infoLabel.getBounds().getCentreX(), - loginButton.getBottom() + 20); + subscribeButton->setSize (buttonWidth, buttonHeight); + subscribeButton->setCentrePosition (buttonCenterX, buttonCenterY); + buttonCenterY += itemDistance + buttonHeight; + } + + if (signInButton.get() != nullptr) + { + signInButton->setSize (buttonWidth, buttonHeight); + signInButton->setCentrePosition (buttonCenterX, buttonCenterY); + buttonCenterY += itemDistance + buttonHeight; + } + + if (switchAccountButton.get() != nullptr) + { + switchAccountButton->setSize (buttonWidth, buttonHeight); + switchAccountButton->setCentrePosition (buttonCenterX, buttonCenterY); } } void buttonClicked (Button* btn) override { - if (btn == &loginButton) + if (btn == subscribeButton.get()) { - if (isPurchaseButton) - URL ("http://www.juce.com").launchInDefaultBrowser(); - else - ProjucerApplication::getApp().showLoginForm(); + URL ("http://www.juce.com/get-juce").launchInDefaultBrowser(); } - else if (btn == signOutButton.get()) + else if (btn == signInButton.get()) { - ProjucerLicenses::getInstance()->logout(); - ProjucerApplication::getApp().updateAllBuildTabs(); + ProjucerApplication::getApp().showLoginForm(); + } + else if (btn == switchAccountButton.get()) + { + ProjucerApplication::getApp().showLoginForm(); } } + bool isLoggedIn; + +private: Label infoLabel { "info", String() }; - TextButton loginButton { "Log-in..." }; - ScopedPointer signOutButton; - bool isLoggedIn, isPurchaseButton; + ScopedPointer subscribeButton; + ScopedPointer signInButton; + ScopedPointer switchAccountButton; }; struct EnableBuildComp : public Component @@ -458,33 +488,30 @@ Component* ProjectContentComponent::createBuildTab (CompileEngineChildProcess* c return new BuildTabComponent (child, new ProjucerAppClasses::ErrorListComp (child->errorList)); } - auto& unlockStatus = *ProjucerLicenses::getInstance(); + jassert (project != nullptr); + const auto& unlockStatus = *ProjucerLicenses::getInstance(); - if (unlockStatus.hasLiveCodingLicence() - && project != nullptr - && LiveBuildProjectSettings::isBuildDisabled (*project)) - return new EnableBuildComp(); + if (unlockStatus.hasLiveCodingLicence()) + { + jassert (unlockStatus.isLoggedIn()); + jassert (unlockStatus.isDLLPresent()); + return new EnableBuildComp(); + } - if (unlockStatus.isLoggedIn()) - return new ProjucerDisabledComp (String ("The Projucer's live-build features are currently disabled!") + newLine - + newLine - + "Your account " + unlockStatus.getLoginName().quoted() - + " does not have an asscociated JUCE Pro license:", - true, true, true, unlockStatus.getLoginName()); - - if (! unlockStatus.isDLLPresent()) - return new ProjucerDisabledComp (String ("The live-building DLL is missing!") + newLine - + newLine - + "To enable the compiler, you'll need to install the missing DLL " - + CompileEngineDLL::getDLLName().quoted() + newLine - + newLine - + "Visit the JUCE website/forum for more help on getting and installing the DLL!", - false, false); - - return new ProjucerDisabledComp ("The Projucer's live-build features are currently disabled!\n\n" - "To enable them, you'll need to log-in with your JUCE account details:", - false, true, false); + return createDisabledBuildTab(unlockStatus.isLoggedIn(), + unlockStatus.isDLLPresent()); #endif +}; + +//============================================================================== +Component* ProjectContentComponent::createDisabledBuildTab(bool loggedIn, bool dllPresent) { + bool showSubscribeButton = true; + bool showSignInButton = dllPresent && ! loggedIn; + bool showSwitchAccountButton = dllPresent && loggedIn; + + return new ProjucerDisabledComp ( + "Subscribe to JUCE Pro or Indie to use the Projucer's live-build features:", + loggedIn, showSubscribeButton, showSignInButton, showSwitchAccountButton); } BuildTabComponent* findBuildTab (const TabbedComponent& tabs) @@ -1499,7 +1526,8 @@ void ProjectContentComponent::handleMissingSystemHeaders() deleteProjectTabs(); createProjectTabs(); - ProjucerDisabledComp* buildTab = new ProjucerDisabledComp (tabMessage, false, false); + bool isLoggedIn = ProjucerLicenses::getInstance()->isLoggedIn(); + ProjucerDisabledComp* buildTab = new ProjucerDisabledComp (tabMessage, isLoggedIn, false, false, false); treeViewTabs.addTab ("Build", Colours::transparentBlack, buildTab, true); showBuildTab(); diff --git a/extras/Projucer/Source/Project/jucer_ProjectContentComponent.h b/extras/Projucer/Source/Project/jucer_ProjectContentComponent.h index f87eab6274..534079f232 100644 --- a/extras/Projucer/Source/Project/jucer_ProjectContentComponent.h +++ b/extras/Projucer/Source/Project/jucer_ProjectContentComponent.h @@ -154,6 +154,8 @@ private: void timerCallback() override; Component* createBuildTab (CompileEngineChildProcess*); + Component* createDisabledBuildTab (bool loggedIn, bool dllPresent); + bool isContinuousRebuildEnabled() { return getAppSettings().getGlobalProperties().getBoolValue ("continuousRebuild", true); } void setContinuousRebuildEnabled (bool b) { getAppSettings().getGlobalProperties().setValue ("continuousRebuild", b); } void rebuildNow(); diff --git a/modules/juce_core/files/juce_File.cpp b/modules/juce_core/files/juce_File.cpp index 1605cacdb6..8f97cff737 100644 --- a/modules/juce_core/files/juce_File.cpp +++ b/modules/juce_core/files/juce_File.cpp @@ -300,6 +300,21 @@ bool File::copyFileTo (const File& newFile) const || (exists() && newFile.deleteFile() && copyInternal (newFile)); } +bool File::replaceFileIn (const File& newFile) const +{ + if (newFile.fullPath == fullPath) + return true; + + if (! newFile.exists()) + return moveFileTo (newFile); + + if (! replaceInternal (newFile)) + return false; + + deleteFile(); + return true; +} + bool File::copyDirectoryTo (const File& newDirectory) const { if (isDirectory() && newDirectory.createDirectory()) diff --git a/modules/juce_core/files/juce_File.h b/modules/juce_core/files/juce_File.h index 9848c13dad..ad15137790 100644 --- a/modules/juce_core/files/juce_File.h +++ b/modules/juce_core/files/juce_File.h @@ -503,6 +503,18 @@ public: */ bool copyFileTo (const File& targetLocation) const; + /** Replaces a file. + + Replace the file in the given location, assuming the replaced files identity. + Depending on the file system this will preserve file attributes such as + creation date, short file name, etc. + + If replacement succeeds the original file is deleted. + + @returns true if the operation succeeds + */ + bool replaceFileIn (const File& targetLocation) const; + /** Copies a directory. Tries to copy an entire directory, recursively. @@ -982,6 +994,7 @@ private: Result createDirectoryInternal (const String&) const; bool copyInternal (const File&) const; bool moveInternal (const File&) const; + bool replaceInternal (const File&) const; bool setFileTimesInternal (int64 m, int64 a, int64 c) const; void getFileTimesInternal (int64& m, int64& a, int64& c) const; bool setFileReadOnlyInternal (bool) const; diff --git a/modules/juce_core/files/juce_TemporaryFile.cpp b/modules/juce_core/files/juce_TemporaryFile.cpp index acb1af0c9a..337f7f3b2e 100644 --- a/modules/juce_core/files/juce_TemporaryFile.cpp +++ b/modules/juce_core/files/juce_TemporaryFile.cpp @@ -86,7 +86,7 @@ bool TemporaryFile::overwriteTargetFileWithTemporary() const // Have a few attempts at overwriting the file before giving up.. for (int i = 5; --i >= 0;) { - if (temporaryFile.moveFileTo (targetFile)) + if (temporaryFile.replaceFileIn (targetFile)) return true; Thread::sleep (100); diff --git a/modules/juce_core/native/juce_posix_SharedCode.h b/modules/juce_core/native/juce_posix_SharedCode.h index 5296c80e18..5dd2888d4f 100644 --- a/modules/juce_core/native/juce_posix_SharedCode.h +++ b/modules/juce_core/native/juce_posix_SharedCode.h @@ -440,6 +440,11 @@ bool File::moveInternal (const File& dest) const return false; } +bool File::replaceInternal (const File& dest) const +{ + return moveInternal (dest); +} + Result File::createDirectoryInternal (const String& fileName) const { return getResultForReturnValue (mkdir (fileName.toUTF8(), 0777)); diff --git a/modules/juce_core/native/juce_win32_Files.cpp b/modules/juce_core/native/juce_win32_Files.cpp index 497dfaae30..9edd8690a6 100644 --- a/modules/juce_core/native/juce_win32_Files.cpp +++ b/modules/juce_core/native/juce_win32_Files.cpp @@ -220,6 +220,15 @@ bool File::moveInternal (const File& dest) const return MoveFile (fullPath.toWideCharPointer(), dest.getFullPathName().toWideCharPointer()) != 0; } +bool File::replaceInternal (const File& dest) const +{ + void* lpExclude = 0; + void* lpReserved = 0; + + return ReplaceFile (dest.getFullPathName().toWideCharPointer(), fullPath.toWideCharPointer(), + 0, REPLACEFILE_IGNORE_MERGE_ERRORS, lpExclude, lpReserved) != 0; +} + Result File::createDirectoryInternal (const String& fileName) const { return CreateDirectory (fileName.toWideCharPointer(), 0) ? Result::ok()