| @@ -20,6 +20,8 @@ Changelist for version 1.44 | |||||
| - added MultiDocumentPanel::createNewDocumentWindow() method to allow creation of custom document windows in a MultiDocumentPanel | - added MultiDocumentPanel::createNewDocumentWindow() method to allow creation of custom document windows in a MultiDocumentPanel | ||||
| - added a Thread::getCurrentThread() method | - added a Thread::getCurrentThread() method | ||||
| - added an option to MessageManagerLock that can check for thread termination, to avoid deadlocks. | - added an option to MessageManagerLock that can check for thread termination, to avoid deadlocks. | ||||
| - new method: PropertySet::setFallbackPropertySet() | |||||
| - some simplifications to ApplicationProperties, because of problems it was causing when there were read-only common property files. | |||||
| ============================================================================== | ============================================================================== | ||||
| Changelist for version 1.43 | Changelist for version 1.43 | ||||
| @@ -47,7 +47,8 @@ ApplicationProperties::ApplicationProperties() throw() | |||||
| : userProps (0), | : userProps (0), | ||||
| commonProps (0), | commonProps (0), | ||||
| msBeforeSaving (3000), | msBeforeSaving (3000), | ||||
| options (PropertiesFile::storeAsBinary) | |||||
| options (PropertiesFile::storeAsBinary), | |||||
| commonSettingsAreReadOnly (0) | |||||
| { | { | ||||
| } | } | ||||
| @@ -75,9 +76,8 @@ bool ApplicationProperties::testWriteAccess (const bool testUserSettings, | |||||
| const bool testCommonSettings, | const bool testCommonSettings, | ||||
| const bool showWarningDialogOnFailure) | const bool showWarningDialogOnFailure) | ||||
| { | { | ||||
| const bool userOk = (! testUserSettings) || getUserSettings()->save(); | |||||
| const bool commonOk = (! testCommonSettings) | |||||
| || (userProps != getCommonSettings() && getCommonSettings()->save()); | |||||
| const bool userOk = (! testUserSettings) || getUserSettings()->save(); | |||||
| const bool commonOk = (! testCommonSettings) || getCommonSettings (false)->save(); | |||||
| if (! (userOk && commonOk)) | if (! (userOk && commonOk)) | ||||
| { | { | ||||
| @@ -85,26 +85,16 @@ bool ApplicationProperties::testWriteAccess (const bool testUserSettings, | |||||
| { | { | ||||
| String filenames; | String filenames; | ||||
| if (! userOk) | |||||
| filenames << "\n" << getUserSettings()->getFile().getFullPathName(); | |||||
| if (userProps != 0 && ! userOk) | |||||
| filenames << '\n' << userProps->getFile().getFullPathName(); | |||||
| if (! commonOk) | |||||
| { | |||||
| PropertiesFile* const realCommonProps | |||||
| = PropertiesFile::createDefaultAppPropertiesFile (appName, fileSuffix, folderName, | |||||
| true, msBeforeSaving, options); | |||||
| if (realCommonProps != 0) | |||||
| { | |||||
| filenames << "\n" << realCommonProps->getFile().getFullPathName(); | |||||
| delete realCommonProps; | |||||
| } | |||||
| } | |||||
| if (commonProps != 0 && ! commonOk) | |||||
| filenames << '\n' << commonProps->getFile().getFullPathName(); | |||||
| AlertWindow::showMessageBox (AlertWindow::WarningIcon, | AlertWindow::showMessageBox (AlertWindow::WarningIcon, | ||||
| appName + TRANS(" - Unable to save settings"), | appName + TRANS(" - Unable to save settings"), | ||||
| TRANS("An error occurred when trying to save the application's settings file...\n\nIn order to save and restore its settings, ") | TRANS("An error occurred when trying to save the application's settings file...\n\nIn order to save and restore its settings, ") | ||||
| + appName + TRANS(" needs to be able to write to the following files:\n") | |||||
| + appName + TRANS(" needs to be able to write to the following files:\n") | |||||
| + filenames | + filenames | ||||
| + TRANS("\n\nMake sure that these files aren't read-only, and that the disk isn't full.")); | + TRANS("\n\nMake sure that these files aren't read-only, and that the disk isn't full.")); | ||||
| } | } | ||||
| @@ -116,45 +106,46 @@ bool ApplicationProperties::testWriteAccess (const bool testUserSettings, | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| PropertiesFile* ApplicationProperties::getUserSettings() throw() | |||||
| void ApplicationProperties::openFiles() throw() | |||||
| { | { | ||||
| if (userProps == 0) | |||||
| { | |||||
| // You need to call setStorageParameters() before trying to get hold of the | |||||
| // properties! | |||||
| jassert (appName.isNotEmpty()); | |||||
| // You need to call setStorageParameters() before trying to get hold of the | |||||
| // properties! | |||||
| jassert (appName.isNotEmpty()); | |||||
| if (appName.isNotEmpty()) | |||||
| if (appName.isNotEmpty()) | |||||
| { | |||||
| if (userProps == 0) | |||||
| userProps = PropertiesFile::createDefaultAppPropertiesFile (appName, fileSuffix, folderName, | userProps = PropertiesFile::createDefaultAppPropertiesFile (appName, fileSuffix, folderName, | ||||
| false, msBeforeSaving, options); | false, msBeforeSaving, options); | ||||
| if (userProps == 0) | |||||
| { | |||||
| // create an emergency properties object to avoid returning a null pointer.. | |||||
| userProps = new PropertiesFile (File::nonexistent, msBeforeSaving, options); | |||||
| } | |||||
| if (commonProps == 0) | |||||
| commonProps = PropertiesFile::createDefaultAppPropertiesFile (appName, fileSuffix, folderName, | |||||
| true, msBeforeSaving, options); | |||||
| userProps->setFallbackPropertySet (commonProps); | |||||
| } | } | ||||
| } | |||||
| PropertiesFile* ApplicationProperties::getUserSettings() throw() | |||||
| { | |||||
| if (userProps == 0) | |||||
| openFiles(); | |||||
| return userProps; | return userProps; | ||||
| } | } | ||||
| PropertiesFile* ApplicationProperties::getCommonSettings() throw() | |||||
| PropertiesFile* ApplicationProperties::getCommonSettings (const bool returnUserPropsIfReadOnly) throw() | |||||
| { | { | ||||
| if (commonProps == 0) | if (commonProps == 0) | ||||
| { | |||||
| // You need to call setStorageParameters() before trying to get hold of the | |||||
| // properties! | |||||
| jassert (appName.isNotEmpty()); | |||||
| openFiles(); | |||||
| if (appName.isNotEmpty()) | |||||
| commonProps = PropertiesFile::createDefaultAppPropertiesFile (appName, fileSuffix, folderName, | |||||
| true, msBeforeSaving, options); | |||||
| if (commonProps == 0 || ! commonProps->save()) | |||||
| { | |||||
| delete commonProps; | |||||
| commonProps = getUserSettings(); | |||||
| } | |||||
| if (returnUserPropsIfReadOnly) | |||||
| { | |||||
| if (commonSettingsAreReadOnly == 0) | |||||
| commonSettingsAreReadOnly = commonProps->save() ? -1 : 1; | |||||
| if (commonSettingsAreReadOnly > 0) | |||||
| return userProps; | |||||
| } | } | ||||
| return commonProps; | return commonProps; | ||||
| @@ -163,17 +154,13 @@ PropertiesFile* ApplicationProperties::getCommonSettings() throw() | |||||
| bool ApplicationProperties::saveIfNeeded() | bool ApplicationProperties::saveIfNeeded() | ||||
| { | { | ||||
| return (userProps == 0 || userProps->saveIfNeeded()) | return (userProps == 0 || userProps->saveIfNeeded()) | ||||
| && (commonProps == 0 || commonProps == userProps || commonProps->saveIfNeeded()); | |||||
| && (commonProps == 0 || commonProps->saveIfNeeded()); | |||||
| } | } | ||||
| void ApplicationProperties::closeFiles() | void ApplicationProperties::closeFiles() | ||||
| { | { | ||||
| delete userProps; | |||||
| if (commonProps != userProps) | |||||
| delete commonProps; | |||||
| userProps = commonProps = 0; | |||||
| deleteAndZero (userProps); | |||||
| deleteAndZero (commonProps); | |||||
| } | } | ||||
| @@ -106,7 +106,12 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Returns the user settings file. | /** Returns the user settings file. | ||||
| The first time this is called, it will create and load the file. | |||||
| The first time this is called, it will create and load the properties file. | |||||
| Note that when you search the user PropertiesFile for a value that it doesn't contain, | |||||
| the common settings are used as a second-chance place to look. This is done via the | |||||
| PropertySet::setFallbackPropertySet() method - by default the common settings are set | |||||
| to the fallback for the user settings. | |||||
| @see getCommonSettings | @see getCommonSettings | ||||
| */ | */ | ||||
| @@ -114,14 +119,19 @@ public: | |||||
| /** Returns the common settings file. | /** Returns the common settings file. | ||||
| The first time this is called, it will create and load the file. | |||||
| If the common settings file doesn't have write access but the user one does, | |||||
| then this may return the same PropertiesFile object as getUserSettings(). | |||||
| The first time this is called, it will create and load the properties file. | |||||
| @param returnUserPropsIfReadOnly if this is true, and the common properties file is | |||||
| read-only (e.g. because the user doesn't have permission to write | |||||
| to shared files), then this will return the user settings instead, | |||||
| (like getUserSettings() would do). This is handy if you'd like to | |||||
| write a value to the common settings, but if that's no possible, | |||||
| then you'd rather write to the user settings than none at all. | |||||
| If returnUserPropsIfReadOnly is false, this method will always return | |||||
| the common settings, even if any changes to them can't be saved. | |||||
| @see getUserSettings | @see getUserSettings | ||||
| */ | */ | ||||
| PropertiesFile* getCommonSettings() throw(); | |||||
| PropertiesFile* getCommonSettings (const bool returnUserPropsIfReadOnly) throw(); | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Saves both files if they need to be saved. | /** Saves both files if they need to be saved. | ||||
| @@ -138,6 +148,7 @@ public: | |||||
| */ | */ | ||||
| void closeFiles(); | void closeFiles(); | ||||
| //============================================================================== | //============================================================================== | ||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| @@ -148,9 +159,12 @@ private: | |||||
| String appName, fileSuffix, folderName; | String appName, fileSuffix, folderName; | ||||
| int msBeforeSaving, options; | int msBeforeSaving, options; | ||||
| int commonSettingsAreReadOnly; | |||||
| ApplicationProperties (const ApplicationProperties&); | ApplicationProperties (const ApplicationProperties&); | ||||
| const ApplicationProperties& operator= (const ApplicationProperties&); | const ApplicationProperties& operator= (const ApplicationProperties&); | ||||
| void openFiles() throw(); | |||||
| }; | }; | ||||
| @@ -144,13 +144,23 @@ bool PropertiesFile::saveIfNeeded() | |||||
| return (! needsWriting) || save(); | return (! needsWriting) || save(); | ||||
| } | } | ||||
| bool PropertiesFile::needsToBeSaved() const throw() | |||||
| { | |||||
| const ScopedLock sl (getLock()); | |||||
| return needsWriting; | |||||
| } | |||||
| bool PropertiesFile::save() | bool PropertiesFile::save() | ||||
| { | { | ||||
| const ScopedLock sl (getLock()); | const ScopedLock sl (getLock()); | ||||
| stopTimer(); | stopTimer(); | ||||
| if (file == File::nonexistent || file.isDirectory()) | |||||
| if (file == File::nonexistent | |||||
| || file.isDirectory() | |||||
| || ! file.getParentDirectory().createDirectory()) | |||||
| return false; | return false; | ||||
| if ((options & storeAsXML) != 0) | if ((options & storeAsXML) != 0) | ||||
| @@ -292,7 +302,9 @@ PropertiesFile* PropertiesFile::createDefaultAppPropertiesFile (const String& ap | |||||
| folderName, | folderName, | ||||
| commonToAllUsers)); | commonToAllUsers)); | ||||
| if (file == File::nonexistent || ! file.getParentDirectory().createDirectory()) | |||||
| jassert (file != File::nonexistent); | |||||
| if (file == File::nonexistent) | |||||
| return 0; | return 0; | ||||
| return new PropertiesFile (file, millisecondsBeforeSaving, propertiesFileOptions); | return new PropertiesFile (file, millisecondsBeforeSaving, propertiesFileOptions); | ||||
| @@ -114,6 +114,11 @@ public: | |||||
| */ | */ | ||||
| bool save(); | bool save(); | ||||
| /** Returns true if the properties have been altered since the last time they were | |||||
| saved. | |||||
| */ | |||||
| bool needsToBeSaved() const throw(); | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Returns the file that's being used. */ | /** Returns the file that's being used. */ | ||||
| const File getFile() const throw(); | const File getFile() const throw(); | ||||
| @@ -225,12 +225,16 @@ public: | |||||
| If generateTooltip is true, then the button's tooltip will be automatically | If generateTooltip is true, then the button's tooltip will be automatically | ||||
| generated based on the name of this command and its current shortcut key. | generated based on the name of this command and its current shortcut key. | ||||
| @see addShortcut | |||||
| @see addShortcut, getCommandID | |||||
| */ | */ | ||||
| void setCommandToTrigger (ApplicationCommandManager* commandManagerToUse, | void setCommandToTrigger (ApplicationCommandManager* commandManagerToUse, | ||||
| const int commandID, | const int commandID, | ||||
| const bool generateTooltip); | const bool generateTooltip); | ||||
| /** Returns the command ID that was set by setCommandToTrigger(). | |||||
| */ | |||||
| int getCommandID() const throw() { return commandID; } | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Assigns a shortcut key to trigger the button. | /** Assigns a shortcut key to trigger the button. | ||||
| @@ -45,24 +45,6 @@ static const int titleH = 24; | |||||
| static const int iconWidth = 80; | static const int iconWidth = 80; | ||||
| //============================================================================== | |||||
| class AlertWindowTextButton : public TextButton | |||||
| { | |||||
| public: | |||||
| AlertWindowTextButton (const String& text) | |||||
| : TextButton (text, String::empty) | |||||
| { | |||||
| setWantsKeyboardFocus (true); | |||||
| setMouseClickGrabsKeyboardFocus (false); | |||||
| } | |||||
| int returnValue; | |||||
| private: | |||||
| AlertWindowTextButton (const AlertWindowTextButton&); | |||||
| const AlertWindowTextButton& operator= (const AlertWindowTextButton&); | |||||
| }; | |||||
| //============================================================================== | //============================================================================== | ||||
| class AlertWindowTextEditor : public TextEditor | class AlertWindowTextEditor : public TextEditor | ||||
| { | { | ||||
| @@ -89,13 +71,13 @@ public: | |||||
| void returnPressed() | void returnPressed() | ||||
| { | { | ||||
| // pass these up the component hierarchy to be trigger the buttons | // pass these up the component hierarchy to be trigger the buttons | ||||
| Component::keyPressed (KeyPress (KeyPress::returnKey, 0, T('\n'))); | |||||
| getParentComponent()->keyPressed (KeyPress (KeyPress::returnKey, 0, T('\n'))); | |||||
| } | } | ||||
| void escapePressed() | void escapePressed() | ||||
| { | { | ||||
| // pass these up the component hierarchy to be trigger the buttons | // pass these up the component hierarchy to be trigger the buttons | ||||
| Component::keyPressed (KeyPress (KeyPress::escapeKey, 0, 0)); | |||||
| getParentComponent()->keyPressed (KeyPress (KeyPress::escapeKey, 0, 0)); | |||||
| } | } | ||||
| private: | private: | ||||
| @@ -134,8 +116,6 @@ AlertWindow::AlertWindow (const String& title, | |||||
| lookAndFeelChanged(); | lookAndFeelChanged(); | ||||
| constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000); | constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000); | ||||
| setWantsKeyboardFocus (getNumChildComponents() == 0); | |||||
| } | } | ||||
| AlertWindow::~AlertWindow() | AlertWindow::~AlertWindow() | ||||
| @@ -172,12 +152,12 @@ void AlertWindow::buttonClicked (Button* button) | |||||
| { | { | ||||
| for (int i = 0; i < buttons.size(); i++) | for (int i = 0; i < buttons.size(); i++) | ||||
| { | { | ||||
| AlertWindowTextButton* const c = (AlertWindowTextButton*) buttons[i]; | |||||
| TextButton* const c = (TextButton*) buttons[i]; | |||||
| if (button->getName() == c->getName()) | if (button->getName() == c->getName()) | ||||
| { | { | ||||
| if (c->getParentComponent() != 0) | if (c->getParentComponent() != 0) | ||||
| c->getParentComponent()->exitModalState (c->returnValue); | |||||
| c->getParentComponent()->exitModalState (c->getCommandID()); | |||||
| break; | break; | ||||
| } | } | ||||
| @@ -190,9 +170,11 @@ void AlertWindow::addButton (const String& name, | |||||
| const KeyPress& shortcutKey1, | const KeyPress& shortcutKey1, | ||||
| const KeyPress& shortcutKey2) | const KeyPress& shortcutKey2) | ||||
| { | { | ||||
| AlertWindowTextButton* const b = new AlertWindowTextButton (name); | |||||
| TextButton* const b = new TextButton (name, String::empty); | |||||
| b->returnValue = returnValue; | |||||
| b->setWantsKeyboardFocus (true); | |||||
| b->setMouseClickGrabsKeyboardFocus (false); | |||||
| b->setCommandToTrigger (0, returnValue, false); | |||||
| b->addShortcut (shortcutKey1); | b->addShortcut (shortcutKey1); | ||||
| b->addShortcut (shortcutKey2); | b->addShortcut (shortcutKey2); | ||||
| b->addButtonListener (this); | b->addButtonListener (this); | ||||
| @@ -286,6 +268,7 @@ public: | |||||
| setCaretVisible (false); | setCaretVisible (false); | ||||
| setScrollbarsShown (true); | setScrollbarsShown (true); | ||||
| lookAndFeelChanged(); | lookAndFeelChanged(); | ||||
| setWantsKeyboardFocus (false); | |||||
| setFont (font); | setFont (font); | ||||
| setText (message, false); | setText (message, false); | ||||
| @@ -441,14 +424,14 @@ void AlertWindow::updateLayout (const bool onlyIncreaseSize) | |||||
| int buttonW = 40; | int buttonW = 40; | ||||
| int i; | int i; | ||||
| for (i = 0; i < buttons.size(); ++i) | for (i = 0; i < buttons.size(); ++i) | ||||
| buttonW += 16 + ((const AlertWindowTextButton*) buttons[i])->getWidth(); | |||||
| buttonW += 16 + ((const TextButton*) buttons[i])->getWidth(); | |||||
| w = jmax (buttonW, w); | w = jmax (buttonW, w); | ||||
| h += (textBoxes.size() + comboBoxes.size() + progressBars.size()) * 50; | h += (textBoxes.size() + comboBoxes.size() + progressBars.size()) * 50; | ||||
| if (buttons.size() > 0) | if (buttons.size() > 0) | ||||
| h += 20 + ((AlertWindowTextButton*) buttons[0])->getHeight(); | |||||
| h += 20 + ((TextButton*) buttons[0])->getHeight(); | |||||
| for (i = customComps.size(); --i >= 0;) | for (i = customComps.size(); --i >= 0;) | ||||
| { | { | ||||
| @@ -499,14 +482,14 @@ void AlertWindow::updateLayout (const bool onlyIncreaseSize) | |||||
| int totalWidth = -spacer; | int totalWidth = -spacer; | ||||
| for (i = buttons.size(); --i >= 0;) | for (i = buttons.size(); --i >= 0;) | ||||
| totalWidth += ((AlertWindowTextButton*) buttons[i])->getWidth() + spacer; | |||||
| totalWidth += ((TextButton*) buttons[i])->getWidth() + spacer; | |||||
| int x = (w - totalWidth) / 2; | int x = (w - totalWidth) / 2; | ||||
| int y = (int) (getHeight() * 0.95f); | int y = (int) (getHeight() * 0.95f); | ||||
| for (i = 0; i < buttons.size(); ++i) | for (i = 0; i < buttons.size(); ++i) | ||||
| { | { | ||||
| AlertWindowTextButton* const c = (AlertWindowTextButton*) buttons[i]; | |||||
| TextButton* const c = (TextButton*) buttons[i]; | |||||
| int ny = proportionOfHeight (0.95f) - c->getHeight(); | int ny = proportionOfHeight (0.95f) - c->getHeight(); | ||||
| c->setTopLeftPosition (x, ny); | c->setTopLeftPosition (x, ny); | ||||
| if (ny < y) | if (ny < y) | ||||
| @@ -544,6 +527,8 @@ void AlertWindow::updateLayout (const bool onlyIncreaseSize) | |||||
| y += h + 10; | y += h + 10; | ||||
| } | } | ||||
| } | } | ||||
| setWantsKeyboardFocus (getNumChildComponents() == 0); | |||||
| } | } | ||||
| bool AlertWindow::containsAnyExtraComponents() const | bool AlertWindow::containsAnyExtraComponents() const | ||||
| @@ -569,7 +554,7 @@ bool AlertWindow::keyPressed (const KeyPress& key) | |||||
| { | { | ||||
| for (int i = buttons.size(); --i >= 0;) | for (int i = buttons.size(); --i >= 0;) | ||||
| { | { | ||||
| AlertWindowTextButton* const b = (AlertWindowTextButton*) buttons[i]; | |||||
| TextButton* const b = (TextButton*) buttons[i]; | |||||
| if (b->isRegisteredForShortcut (key)) | if (b->isRegisteredForShortcut (key)) | ||||
| { | { | ||||
| @@ -585,7 +570,7 @@ bool AlertWindow::keyPressed (const KeyPress& key) | |||||
| } | } | ||||
| else if (key.isKeyCode (KeyPress::returnKey) && buttons.size() == 1) | else if (key.isKeyCode (KeyPress::returnKey) && buttons.size() == 1) | ||||
| { | { | ||||
| ((AlertWindowTextButton*) buttons.getFirst())->triggerClick(); | |||||
| ((TextButton*) buttons.getFirst())->triggerClick(); | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -42,6 +42,7 @@ BEGIN_JUCE_NAMESPACE | |||||
| //============================================================================== | //============================================================================== | ||||
| PropertySet::PropertySet (const bool ignoreCaseOfKeyNames) throw() | PropertySet::PropertySet (const bool ignoreCaseOfKeyNames) throw() | ||||
| : properties (ignoreCaseOfKeyNames), | : properties (ignoreCaseOfKeyNames), | ||||
| fallbackProperties (0), | |||||
| ignoreCaseOfKeys (ignoreCaseOfKeyNames) | ignoreCaseOfKeys (ignoreCaseOfKeyNames) | ||||
| { | { | ||||
| } | } | ||||
| @@ -51,11 +52,17 @@ PropertySet::~PropertySet() | |||||
| } | } | ||||
| const String PropertySet::getValue (const String& keyName, | const String PropertySet::getValue (const String& keyName, | ||||
| const String& defaultReturnValue) const throw() | |||||
| const String& defaultValue) const throw() | |||||
| { | { | ||||
| const ScopedLock sl (lock); | const ScopedLock sl (lock); | ||||
| return properties.getValue (keyName, defaultReturnValue); | |||||
| const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); | |||||
| if (index >= 0) | |||||
| return properties.getAllValues() [index]; | |||||
| return fallbackProperties != 0 ? fallbackProperties->getValue (keyName, defaultValue) | |||||
| : defaultValue; | |||||
| } | } | ||||
| int PropertySet::getIntValue (const String& keyName, | int PropertySet::getIntValue (const String& keyName, | ||||
| @@ -67,7 +74,8 @@ int PropertySet::getIntValue (const String& keyName, | |||||
| if (index >= 0) | if (index >= 0) | ||||
| return properties.getAllValues() [index].getIntValue(); | return properties.getAllValues() [index].getIntValue(); | ||||
| return defaultValue; | |||||
| return fallbackProperties != 0 ? fallbackProperties->getIntValue (keyName, defaultValue) | |||||
| : defaultValue; | |||||
| } | } | ||||
| double PropertySet::getDoubleValue (const String& keyName, | double PropertySet::getDoubleValue (const String& keyName, | ||||
| @@ -79,7 +87,8 @@ double PropertySet::getDoubleValue (const String& keyName, | |||||
| if (index >= 0) | if (index >= 0) | ||||
| return properties.getAllValues()[index].getDoubleValue(); | return properties.getAllValues()[index].getDoubleValue(); | ||||
| return defaultValue; | |||||
| return fallbackProperties != 0 ? fallbackProperties->getDoubleValue (keyName, defaultValue) | |||||
| : defaultValue; | |||||
| } | } | ||||
| bool PropertySet::getBoolValue (const String& keyName, | bool PropertySet::getBoolValue (const String& keyName, | ||||
| @@ -91,7 +100,8 @@ bool PropertySet::getBoolValue (const String& keyName, | |||||
| if (index >= 0) | if (index >= 0) | ||||
| return properties.getAllValues() [index].getIntValue() != 0; | return properties.getAllValues() [index].getIntValue() != 0; | ||||
| return defaultValue; | |||||
| return fallbackProperties != 0 ? fallbackProperties->getBoolValue (keyName, defaultValue) | |||||
| : defaultValue; | |||||
| } | } | ||||
| XmlElement* PropertySet::getXmlValue (const String& keyName) const | XmlElement* PropertySet::getXmlValue (const String& keyName) const | ||||
| @@ -162,6 +172,12 @@ bool PropertySet::containsKey (const String& keyName) const throw() | |||||
| return properties.getAllKeys().contains (keyName, ignoreCaseOfKeys); | return properties.getAllKeys().contains (keyName, ignoreCaseOfKeys); | ||||
| } | } | ||||
| void PropertySet::setFallbackPropertySet (PropertySet* fallbackProperties_) throw() | |||||
| { | |||||
| const ScopedLock sl (lock); | |||||
| fallbackProperties = fallbackProperties_; | |||||
| } | |||||
| void PropertySet::propertyChanged() | void PropertySet::propertyChanged() | ||||
| { | { | ||||
| } | } | ||||
| @@ -63,6 +63,10 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Returns one of the properties as a string. | /** Returns one of the properties as a string. | ||||
| If the value isn't found in this set, then this will look for it in a fallback | |||||
| property set (if you've specified one with the setFallbackPropertySet() method), | |||||
| and if it can't find one there, it'll return the default value passed-in. | |||||
| @param keyName the name of the property to retrieve | @param keyName the name of the property to retrieve | ||||
| @param defaultReturnValue a value to return if the named property doesn't actually exist | @param defaultReturnValue a value to return if the named property doesn't actually exist | ||||
| */ | */ | ||||
| @@ -71,6 +75,10 @@ public: | |||||
| /** Returns one of the properties as an integer. | /** Returns one of the properties as an integer. | ||||
| If the value isn't found in this set, then this will look for it in a fallback | |||||
| property set (if you've specified one with the setFallbackPropertySet() method), | |||||
| and if it can't find one there, it'll return the default value passed-in. | |||||
| @param keyName the name of the property to retrieve | @param keyName the name of the property to retrieve | ||||
| @param defaultReturnValue a value to return if the named property doesn't actually exist | @param defaultReturnValue a value to return if the named property doesn't actually exist | ||||
| */ | */ | ||||
| @@ -79,6 +87,10 @@ public: | |||||
| /** Returns one of the properties as an double. | /** Returns one of the properties as an double. | ||||
| If the value isn't found in this set, then this will look for it in a fallback | |||||
| property set (if you've specified one with the setFallbackPropertySet() method), | |||||
| and if it can't find one there, it'll return the default value passed-in. | |||||
| @param keyName the name of the property to retrieve | @param keyName the name of the property to retrieve | ||||
| @param defaultReturnValue a value to return if the named property doesn't actually exist | @param defaultReturnValue a value to return if the named property doesn't actually exist | ||||
| */ | */ | ||||
| @@ -90,6 +102,10 @@ public: | |||||
| The result will be true if the string found for this key name can be parsed as a non-zero | The result will be true if the string found for this key name can be parsed as a non-zero | ||||
| integer. | integer. | ||||
| If the value isn't found in this set, then this will look for it in a fallback | |||||
| property set (if you've specified one with the setFallbackPropertySet() method), | |||||
| and if it can't find one there, it'll return the default value passed-in. | |||||
| @param keyName the name of the property to retrieve | @param keyName the name of the property to retrieve | ||||
| @param defaultReturnValue a value to return if the named property doesn't actually exist | @param defaultReturnValue a value to return if the named property doesn't actually exist | ||||
| */ | */ | ||||
| @@ -101,6 +117,10 @@ public: | |||||
| The result will a new XMLElement object that the caller must delete. If may return 0 if the | The result will a new XMLElement object that the caller must delete. If may return 0 if the | ||||
| key isn't found, or if the entry contains an string that isn't valid XML. | key isn't found, or if the entry contains an string that isn't valid XML. | ||||
| If the value isn't found in this set, then this will look for it in a fallback | |||||
| property set (if you've specified one with the setFallbackPropertySet() method), | |||||
| and if it can't find one there, it'll return the default value passed-in. | |||||
| @param keyName the name of the property to retrieve | @param keyName the name of the property to retrieve | ||||
| */ | */ | ||||
| XmlElement* getXmlValue (const String& keyName) const; | XmlElement* getXmlValue (const String& keyName) const; | ||||
| @@ -167,6 +187,25 @@ public: | |||||
| /** Returns the lock used when reading or writing to this set */ | /** Returns the lock used when reading or writing to this set */ | ||||
| const CriticalSection& getLock() const throw() { return lock; } | const CriticalSection& getLock() const throw() { return lock; } | ||||
| //============================================================================== | |||||
| /** Sets up a second PopertySet that will be used to look up any values that aren't | |||||
| set in this one. | |||||
| If you set this up to be a pointer to a second property set, then whenever one | |||||
| of the getValue() methods fails to find an entry in this set, it will look up that | |||||
| value in the fallback set, and if it finds it, it will return that. | |||||
| Make sure that you don't delete the fallback set while it's still being used by | |||||
| another set! To remove the fallback set, just call this method with a null pointer. | |||||
| @see getFallbackPropertySet | |||||
| */ | |||||
| void setFallbackPropertySet (PropertySet* fallbackProperties) throw(); | |||||
| /** Returns the fallback property set. | |||||
| @see setFallbackPropertySet | |||||
| */ | |||||
| PropertySet* getFallbackPropertySet() const throw() { return fallbackProperties; } | |||||
| //============================================================================== | //============================================================================== | ||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| @@ -182,8 +221,9 @@ protected: | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| StringPairArray properties; | StringPairArray properties; | ||||
| bool ignoreCaseOfKeys; | |||||
| PropertySet* fallbackProperties; | |||||
| CriticalSection lock; | CriticalSection lock; | ||||
| bool ignoreCaseOfKeys; | |||||
| PropertySet (const PropertySet&); | PropertySet (const PropertySet&); | ||||
| const PropertySet& operator= (const PropertySet&); | const PropertySet& operator= (const PropertySet&); | ||||