@@ -701,6 +701,10 @@ private: | |||||
{ | { | ||||
mouseDownCompUID = underMouse->getComponentUID(); | mouseDownCompUID = underMouse->getComponentUID(); | ||||
mouseDownResult = canvas.getSelection().addToSelectionOnMouseDown (mouseDownCompUID, e.mods); | mouseDownResult = canvas.getSelection().addToSelectionOnMouseDown (mouseDownCompUID, e.mods); | ||||
updateSelectedComponentResizeFrames(); | |||||
hideSizeGuides(); | |||||
showSizeGuides(); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -17620,19 +17620,23 @@ namespace PropertyFileConstants | |||||
static const char* const valueAttribute = "val"; | static const char* const valueAttribute = "val"; | ||||
} | } | ||||
PropertiesFile::PropertiesFile (const File& f, const int millisecondsBeforeSaving, const int options_) | |||||
PropertiesFile::PropertiesFile (const File& f, const int millisecondsBeforeSaving, | |||||
const int options_, InterProcessLock* const processLock_) | |||||
: PropertySet (ignoreCaseOfKeyNames), | : PropertySet (ignoreCaseOfKeyNames), | ||||
file (f), | file (f), | ||||
timerInterval (millisecondsBeforeSaving), | timerInterval (millisecondsBeforeSaving), | ||||
options (options_), | options (options_), | ||||
loadedOk (false), | loadedOk (false), | ||||
needsWriting (false) | |||||
needsWriting (false), | |||||
processLock (processLock_) | |||||
{ | { | ||||
// You need to correctly specify just one storage format for the file | // You need to correctly specify just one storage format for the file | ||||
jassert ((options_ & (storeAsBinary | storeAsCompressedBinary | storeAsXML)) == storeAsBinary | jassert ((options_ & (storeAsBinary | storeAsCompressedBinary | storeAsXML)) == storeAsBinary | ||||
|| (options_ & (storeAsBinary | storeAsCompressedBinary | storeAsXML)) == storeAsCompressedBinary | || (options_ & (storeAsBinary | storeAsCompressedBinary | storeAsXML)) == storeAsCompressedBinary | ||||
|| (options_ & (storeAsBinary | storeAsCompressedBinary | storeAsXML)) == storeAsXML); | || (options_ & (storeAsBinary | storeAsCompressedBinary | storeAsXML)) == storeAsXML); | ||||
ProcessScopedLock pl (getProcessLock()); | |||||
ScopedPointer<InputStream> fileStream (f.createInputStream()); | ScopedPointer<InputStream> fileStream (f.createInputStream()); | ||||
if (fileStream != 0) | if (fileStream != 0) | ||||
@@ -17693,8 +17697,10 @@ PropertiesFile::PropertiesFile (const File& f, const int millisecondsBeforeSavin | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
// must be a pretty broken XML file we're trying to parse here! | |||||
jassertfalse | |||||
// must be a pretty broken XML file we're trying to parse here, | |||||
// or a sign that this object needs an InterProcessLock, | |||||
// or just a failure reading the file. This last reason is why | |||||
// we don't jassertfalse here. | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -17711,6 +17717,11 @@ PropertiesFile::~PropertiesFile() | |||||
jassertfalse; | jassertfalse; | ||||
} | } | ||||
PropertiesFile::ProcessScopedLock PropertiesFile::getProcessLock() const | |||||
{ | |||||
return ProcessScopedLock (processLock != 0 ? new InterProcessLock::ScopedLockType (*processLock) : 0); | |||||
} | |||||
bool PropertiesFile::saveIfNeeded() | bool PropertiesFile::saveIfNeeded() | ||||
{ | { | ||||
const ScopedLock sl (getLock()); | const ScopedLock sl (getLock()); | ||||
@@ -17760,6 +17771,8 @@ bool PropertiesFile::save() | |||||
getAllProperties().getAllValues() [i]); | getAllProperties().getAllValues() [i]); | ||||
} | } | ||||
ProcessScopedLock pl (getProcessLock()); | |||||
if (doc.writeToFile (file, String::empty)) | if (doc.writeToFile (file, String::empty)) | ||||
{ | { | ||||
needsWriting = false; | needsWriting = false; | ||||
@@ -17768,6 +17781,8 @@ bool PropertiesFile::save() | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
ProcessScopedLock pl (getProcessLock()); | |||||
TemporaryFile tempFile (file); | TemporaryFile tempFile (file); | ||||
ScopedPointer <OutputStream> out (tempFile.getFile().createOutputStream()); | ScopedPointer <OutputStream> out (tempFile.getFile().createOutputStream()); | ||||
@@ -17871,7 +17886,8 @@ PropertiesFile* PropertiesFile::createDefaultAppPropertiesFile (const String& ap | |||||
const String& folderName, | const String& folderName, | ||||
const bool commonToAllUsers, | const bool commonToAllUsers, | ||||
const int millisecondsBeforeSaving, | const int millisecondsBeforeSaving, | ||||
const int propertiesFileOptions) | |||||
const int propertiesFileOptions, | |||||
InterProcessLock *processLock_) | |||||
{ | { | ||||
const File file (getDefaultAppSettingsFile (applicationName, | const File file (getDefaultAppSettingsFile (applicationName, | ||||
fileNameSuffix, | fileNameSuffix, | ||||
@@ -17883,7 +17899,7 @@ PropertiesFile* PropertiesFile::createDefaultAppPropertiesFile (const String& ap | |||||
if (file == File::nonexistent) | if (file == File::nonexistent) | ||||
return 0; | return 0; | ||||
return new PropertiesFile (file, millisecondsBeforeSaving, propertiesFileOptions); | |||||
return new PropertiesFile (file, millisecondsBeforeSaving, propertiesFileOptions,processLock_); | |||||
} | } | ||||
END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
@@ -13457,7 +13457,8 @@ public: | |||||
PropertiesFile (const File& file, | PropertiesFile (const File& file, | ||||
int millisecondsBeforeSaving, | int millisecondsBeforeSaving, | ||||
int optionFlags); | |||||
int optionFlags, | |||||
InterProcessLock* processLock = 0); | |||||
~PropertiesFile(); | ~PropertiesFile(); | ||||
@@ -13478,7 +13479,8 @@ public: | |||||
const String& folderName, | const String& folderName, | ||||
bool commonToAllUsers, | bool commonToAllUsers, | ||||
int millisecondsBeforeSaving, | int millisecondsBeforeSaving, | ||||
int propertiesFileOptions); | |||||
int propertiesFileOptions, | |||||
InterProcessLock *ipl = NULL); | |||||
static const File getDefaultAppSettingsFile (const String& applicationName, | static const File getDefaultAppSettingsFile (const String& applicationName, | ||||
const String& fileNameSuffix, | const String& fileNameSuffix, | ||||
@@ -13497,6 +13499,10 @@ private: | |||||
const int options; | const int options; | ||||
bool loadedOk, needsWriting; | bool loadedOk, needsWriting; | ||||
InterProcessLock* processLock; | |||||
typedef ScopedPointer<InterProcessLock::ScopedLockType> ProcessScopedLock; | |||||
ProcessScopedLock getProcessLock() const; | |||||
void timerCallback(); | void timerCallback(); | ||||
PropertiesFile (const PropertiesFile&); | PropertiesFile (const PropertiesFile&); | ||||
@@ -35,7 +35,9 @@ BEGIN_JUCE_NAMESPACE | |||||
#include "../io/streams/juce_SubregionStream.h" | #include "../io/streams/juce_SubregionStream.h" | ||||
#include "../io/streams/juce_GZIPDecompressorInputStream.h" | #include "../io/streams/juce_GZIPDecompressorInputStream.h" | ||||
#include "../io/streams/juce_GZIPCompressorOutputStream.h" | #include "../io/streams/juce_GZIPCompressorOutputStream.h" | ||||
#include "../containers/juce_ScopedPointer.h" | |||||
#include "../core/juce_SystemStats.h" | #include "../core/juce_SystemStats.h" | ||||
#include "../threads/juce_InterProcessLock.h" | |||||
#include "../text/juce_XmlDocument.h" | #include "../text/juce_XmlDocument.h" | ||||
@@ -52,19 +54,23 @@ namespace PropertyFileConstants | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
PropertiesFile::PropertiesFile (const File& f, const int millisecondsBeforeSaving, const int options_) | |||||
PropertiesFile::PropertiesFile (const File& f, const int millisecondsBeforeSaving, | |||||
const int options_, InterProcessLock* const processLock_) | |||||
: PropertySet (ignoreCaseOfKeyNames), | : PropertySet (ignoreCaseOfKeyNames), | ||||
file (f), | file (f), | ||||
timerInterval (millisecondsBeforeSaving), | timerInterval (millisecondsBeforeSaving), | ||||
options (options_), | options (options_), | ||||
loadedOk (false), | loadedOk (false), | ||||
needsWriting (false) | |||||
needsWriting (false), | |||||
processLock (processLock_) | |||||
{ | { | ||||
// You need to correctly specify just one storage format for the file | // You need to correctly specify just one storage format for the file | ||||
jassert ((options_ & (storeAsBinary | storeAsCompressedBinary | storeAsXML)) == storeAsBinary | jassert ((options_ & (storeAsBinary | storeAsCompressedBinary | storeAsXML)) == storeAsBinary | ||||
|| (options_ & (storeAsBinary | storeAsCompressedBinary | storeAsXML)) == storeAsCompressedBinary | || (options_ & (storeAsBinary | storeAsCompressedBinary | storeAsXML)) == storeAsCompressedBinary | ||||
|| (options_ & (storeAsBinary | storeAsCompressedBinary | storeAsXML)) == storeAsXML); | || (options_ & (storeAsBinary | storeAsCompressedBinary | storeAsXML)) == storeAsXML); | ||||
ProcessScopedLock pl (getProcessLock()); | |||||
ScopedPointer<InputStream> fileStream (f.createInputStream()); | ScopedPointer<InputStream> fileStream (f.createInputStream()); | ||||
if (fileStream != 0) | if (fileStream != 0) | ||||
@@ -125,8 +131,10 @@ PropertiesFile::PropertiesFile (const File& f, const int millisecondsBeforeSavin | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
// must be a pretty broken XML file we're trying to parse here! | |||||
jassertfalse | |||||
// must be a pretty broken XML file we're trying to parse here, | |||||
// or a sign that this object needs an InterProcessLock, | |||||
// or just a failure reading the file. This last reason is why | |||||
// we don't jassertfalse here. | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -143,6 +151,11 @@ PropertiesFile::~PropertiesFile() | |||||
jassertfalse; | jassertfalse; | ||||
} | } | ||||
PropertiesFile::ProcessScopedLock PropertiesFile::getProcessLock() const | |||||
{ | |||||
return ProcessScopedLock (processLock != 0 ? new InterProcessLock::ScopedLockType (*processLock) : 0); | |||||
} | |||||
bool PropertiesFile::saveIfNeeded() | bool PropertiesFile::saveIfNeeded() | ||||
{ | { | ||||
const ScopedLock sl (getLock()); | const ScopedLock sl (getLock()); | ||||
@@ -192,6 +205,8 @@ bool PropertiesFile::save() | |||||
getAllProperties().getAllValues() [i]); | getAllProperties().getAllValues() [i]); | ||||
} | } | ||||
ProcessScopedLock pl (getProcessLock()); | |||||
if (doc.writeToFile (file, String::empty)) | if (doc.writeToFile (file, String::empty)) | ||||
{ | { | ||||
needsWriting = false; | needsWriting = false; | ||||
@@ -200,6 +215,8 @@ bool PropertiesFile::save() | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
ProcessScopedLock pl (getProcessLock()); | |||||
TemporaryFile tempFile (file); | TemporaryFile tempFile (file); | ||||
ScopedPointer <OutputStream> out (tempFile.getFile().createOutputStream()); | ScopedPointer <OutputStream> out (tempFile.getFile().createOutputStream()); | ||||
@@ -304,7 +321,8 @@ PropertiesFile* PropertiesFile::createDefaultAppPropertiesFile (const String& ap | |||||
const String& folderName, | const String& folderName, | ||||
const bool commonToAllUsers, | const bool commonToAllUsers, | ||||
const int millisecondsBeforeSaving, | const int millisecondsBeforeSaving, | ||||
const int propertiesFileOptions) | |||||
const int propertiesFileOptions, | |||||
InterProcessLock *processLock_) | |||||
{ | { | ||||
const File file (getDefaultAppSettingsFile (applicationName, | const File file (getDefaultAppSettingsFile (applicationName, | ||||
fileNameSuffix, | fileNameSuffix, | ||||
@@ -316,7 +334,7 @@ PropertiesFile* PropertiesFile::createDefaultAppPropertiesFile (const String& ap | |||||
if (file == File::nonexistent) | if (file == File::nonexistent) | ||||
return 0; | return 0; | ||||
return new PropertiesFile (file, millisecondsBeforeSaving, propertiesFileOptions); | |||||
return new PropertiesFile (file, millisecondsBeforeSaving, propertiesFileOptions,processLock_); | |||||
} | } | ||||
@@ -30,6 +30,7 @@ | |||||
#include "../containers/juce_PropertySet.h" | #include "../containers/juce_PropertySet.h" | ||||
#include "../events/juce_Timer.h" | #include "../events/juce_Timer.h" | ||||
#include "../events/juce_ChangeBroadcaster.h" | #include "../events/juce_ChangeBroadcaster.h" | ||||
#include "../threads/juce_InterProcessLock.h" | |||||
//============================================================================== | //============================================================================== | ||||
@@ -76,10 +77,17 @@ public: | |||||
@param optionFlags a combination of the flags in the FileFormatOptions | @param optionFlags a combination of the flags in the FileFormatOptions | ||||
enum, which specify the type of file to save, and other | enum, which specify the type of file to save, and other | ||||
options. | options. | ||||
@param processLock an optional InterprocessLock object that will be used to | |||||
prevent multiple threads or processes from writing to the file | |||||
at the same time. The PropertiesFile will keep a pointer to | |||||
this object but will not take ownership of it - the caller is | |||||
responsible for making sure that the lock doesn't get deleted | |||||
before the PropertiesFile has been deleted. | |||||
*/ | */ | ||||
PropertiesFile (const File& file, | PropertiesFile (const File& file, | ||||
int millisecondsBeforeSaving, | int millisecondsBeforeSaving, | ||||
int optionFlags); | |||||
int optionFlags, | |||||
InterProcessLock* processLock = 0); | |||||
/** Destructor. | /** Destructor. | ||||
@@ -146,7 +154,8 @@ public: | |||||
const String& folderName, | const String& folderName, | ||||
bool commonToAllUsers, | bool commonToAllUsers, | ||||
int millisecondsBeforeSaving, | int millisecondsBeforeSaving, | ||||
int propertiesFileOptions); | |||||
int propertiesFileOptions, | |||||
InterProcessLock *ipl = NULL); | |||||
/** Handy utility to choose a file in the standard OS-dependent location for application | /** Handy utility to choose a file in the standard OS-dependent location for application | ||||
settings files. | settings files. | ||||
@@ -187,6 +196,10 @@ private: | |||||
const int options; | const int options; | ||||
bool loadedOk, needsWriting; | bool loadedOk, needsWriting; | ||||
InterProcessLock* processLock; | |||||
typedef ScopedPointer<InterProcessLock::ScopedLockType> ProcessScopedLock; | |||||
ProcessScopedLock getProcessLock() const; | |||||
void timerCallback(); | void timerCallback(); | ||||
PropertiesFile (const PropertiesFile&); | PropertiesFile (const PropertiesFile&); | ||||