mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-27 02:20:05 +00:00
Added method String::containsNonWhitespaceChars(); changed the XML parser to not strip whitespace from around text elements, and also added XmlDocument::setEmptyTextElementsIgnored() to make it optionally keep all whitespace-only text elements. Added methods File::containsSubDirectories(), WebBrowserComponent::refresh(), TreeView::deleteRootItem(). Ironed out a possible bug with buttons crashing when deleted during a keypress callback. Changed pixel ordering to sort out transparent windows on PPC macs. Also fixed a mac AU build problem, and removed a couple of gcc warnings.
This commit is contained in:
parent
db5ab181a8
commit
4c1b6ce430
25 changed files with 3409 additions and 3138 deletions
|
|
@ -90,6 +90,10 @@ void WebBrowserComponent::goForward()
|
|||
|
||||
}
|
||||
|
||||
void WebBrowserComponent::refresh()
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void WebBrowserComponent::paint (Graphics& g)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -543,6 +543,9 @@ private:
|
|||
|
||||
void swapRGBOrder (const int x, const int y, const int w, int h) const
|
||||
{
|
||||
#if JUCE_BIG_ENDIAN
|
||||
jassert (pixelStride == 4);
|
||||
#endif
|
||||
jassert (Rectangle (0, 0, juceImage.getWidth(), juceImage.getHeight())
|
||||
.contains (Rectangle (x, y, w, h)));
|
||||
|
||||
|
|
@ -555,9 +558,18 @@ private:
|
|||
|
||||
for (int i = w; --i >= 0;)
|
||||
{
|
||||
const uint8 temp = p[0];
|
||||
#if JUCE_BIG_ENDIAN
|
||||
const uint8 oldp3 = p[3];
|
||||
const uint8 oldp1 = p[1];
|
||||
p[3] = p[0];
|
||||
p[0] = oldp1;
|
||||
p[1] = p[2];
|
||||
p[2] = oldp3;
|
||||
#else
|
||||
const uint8 oldp0 = p[0];
|
||||
p[0] = p[2];
|
||||
p[2] = temp;
|
||||
p[2] = oldp0;
|
||||
#endif
|
||||
|
||||
p += pixelStride;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,6 +147,11 @@ public:
|
|||
{
|
||||
[webView stopLoading: nil];
|
||||
}
|
||||
|
||||
void refresh()
|
||||
{
|
||||
[webView reload: nil];
|
||||
}
|
||||
|
||||
private:
|
||||
WebView* webView;
|
||||
|
|
@ -206,6 +211,11 @@ void WebBrowserComponent::goForward()
|
|||
browser->goForward();
|
||||
}
|
||||
|
||||
void WebBrowserComponent::refresh()
|
||||
{
|
||||
browser->refresh();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void WebBrowserComponent::paint (Graphics& g)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ static int CALLBACK browseCallbackProc (HWND hWnd, UINT msg, LPARAM lParam, LPAR
|
|||
return 0;
|
||||
}
|
||||
|
||||
void juce_setWindowStyleBit (HWND h, int styleType, int feature, bool bitIsSet);
|
||||
void juce_setWindowStyleBit (HWND h, int styleType, int feature, bool bitIsSet) throw();
|
||||
|
||||
static UINT_PTR CALLBACK openCallback (HWND hdlg, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ bool juce_canWriteToFile (const String& fileName) throw()
|
|||
}
|
||||
|
||||
bool juce_setFileReadOnly (const String& fileName,
|
||||
bool isReadOnly)
|
||||
bool isReadOnly) throw()
|
||||
{
|
||||
DWORD attr = GetFileAttributes (fileName);
|
||||
|
||||
|
|
|
|||
|
|
@ -272,6 +272,12 @@ void WebBrowserComponent::goForward()
|
|||
browser->browser->GoForward();
|
||||
}
|
||||
|
||||
void WebBrowserComponent::refresh()
|
||||
{
|
||||
if (browser->browser != 0)
|
||||
browser->browser->Refresh();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void WebBrowserComponent::paint (Graphics& g)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5351,6 +5351,12 @@ bool juce_findFileNext (void* handle, String& resultFile,
|
|||
|
||||
void juce_findFileClose (void* handle) throw();
|
||||
|
||||
static const String juce_addTrailingSeparator (const String& path) throw()
|
||||
{
|
||||
return path.endsWithChar (File::separator) ? path
|
||||
: path + File::separator;
|
||||
}
|
||||
|
||||
static const String parseAbsolutePath (String path) throw()
|
||||
{
|
||||
if (path.isEmpty())
|
||||
|
|
@ -5742,10 +5748,7 @@ const File File::getChildFile (String relativePath) const throw()
|
|||
}
|
||||
}
|
||||
|
||||
if (! path.endsWithChar (separator))
|
||||
path += separator;
|
||||
|
||||
return File (path + relativePath);
|
||||
return File (juce_addTrailingSeparator (path) + relativePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5902,9 +5905,7 @@ int File::findChildFiles (OwnedArray<File>& results,
|
|||
// find child files or directories in this directory first..
|
||||
if (isDirectory())
|
||||
{
|
||||
String path (fullPath);
|
||||
if (! path.endsWithChar (separator))
|
||||
path += separator;
|
||||
const String path (juce_addTrailingSeparator (fullPath));
|
||||
|
||||
String filename;
|
||||
bool isDirectory, isHidden;
|
||||
|
|
@ -5999,6 +6000,37 @@ int File::getNumberOfChildFiles (const int whatToLookFor,
|
|||
return count;
|
||||
}
|
||||
|
||||
bool File::containsSubDirectories() const throw()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (isDirectory())
|
||||
{
|
||||
String filename;
|
||||
bool isDirectory, isHidden;
|
||||
void* const handle = juce_findFileStart (juce_addTrailingSeparator (fullPath),
|
||||
T("*"), filename,
|
||||
&isDirectory, &isHidden, 0, 0, 0, 0);
|
||||
|
||||
if (handle != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (isDirectory)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (juce_findFileNext (handle, filename, &isDirectory, &isHidden, 0, 0, 0, 0));
|
||||
|
||||
juce_findFileClose (handle);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const File File::getNonexistentChildFile (const String& prefix_,
|
||||
const String& suffix,
|
||||
bool putNumbersInBrackets) const throw()
|
||||
|
|
@ -6272,11 +6304,8 @@ const String File::getRelativePathFrom (const File& dir) const throw()
|
|||
thisPath [len] = 0;
|
||||
}
|
||||
|
||||
String dirPath ((dir.existsAsFile()) ? dir.getParentDirectory().getFullPathName()
|
||||
: dir.fullPath);
|
||||
|
||||
if (! dirPath.endsWithChar (separator))
|
||||
dirPath += separator;
|
||||
String dirPath (juce_addTrailingSeparator ((dir.existsAsFile()) ? dir.getParentDirectory().getFullPathName()
|
||||
: dir.fullPath));
|
||||
|
||||
const int len = jmin (thisPath.length(), dirPath.length());
|
||||
int commonBitLength = 0;
|
||||
|
|
@ -11152,11 +11181,15 @@ bool String::startsWithIgnoreCase (const tchar* const other) const throw()
|
|||
|
||||
bool String::startsWithChar (const tchar character) const throw()
|
||||
{
|
||||
jassert (character != 0); // strings can't contain a null character!
|
||||
|
||||
return text->text[0] == character;
|
||||
}
|
||||
|
||||
bool String::endsWithChar (const tchar character) const throw()
|
||||
{
|
||||
jassert (character != 0); // strings can't contain a null character!
|
||||
|
||||
return text->text[0] != 0
|
||||
&& text->text [length() - 1] == character;
|
||||
}
|
||||
|
|
@ -11502,6 +11535,17 @@ bool String::containsAnyOf (const tchar* const chars) const throw()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool String::containsNonWhitespaceChars() const throw()
|
||||
{
|
||||
const tchar* t = text->text;
|
||||
|
||||
while (*t != 0)
|
||||
if (! CharacterFunctions::isWhitespace (*t++))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int String::getIntValue() const throw()
|
||||
{
|
||||
return CharacterFunctions::getIntValue (text->text);
|
||||
|
|
@ -12096,7 +12140,7 @@ void StringArray::removeEmptyStrings (const bool removeWhitespaceStrings) throw(
|
|||
if (removeWhitespaceStrings)
|
||||
{
|
||||
for (int i = size(); --i >= 0;)
|
||||
if (((const String*) strings.getUnchecked(i))->trim().isEmpty())
|
||||
if (! ((const String*) strings.getUnchecked(i))->containsNonWhitespaceChars())
|
||||
remove (i);
|
||||
}
|
||||
else
|
||||
|
|
@ -12525,6 +12569,7 @@ static bool isXmlIdentifierChar_Slow (const tchar c) throw()
|
|||
|
||||
XmlDocument::XmlDocument (const String& documentText) throw()
|
||||
: originalText (documentText),
|
||||
ignoreEmptyTextElements (true),
|
||||
inputSource (0)
|
||||
{
|
||||
}
|
||||
|
|
@ -12548,6 +12593,11 @@ void XmlDocument::setInputSource (InputSource* const newSource) throw()
|
|||
}
|
||||
}
|
||||
|
||||
void XmlDocument::setEmptyTextElementsIgnored (const bool shouldBeIgnored) throw()
|
||||
{
|
||||
ignoreEmptyTextElements = shouldBeIgnored;
|
||||
}
|
||||
|
||||
XmlElement* XmlDocument::getDocumentElement (const bool onlyReadOuterDocumentElement)
|
||||
{
|
||||
String textToParse (originalText);
|
||||
|
|
@ -13097,9 +13147,8 @@ void XmlDocument::readChildElements (XmlElement* parent) throw()
|
|||
}
|
||||
}
|
||||
|
||||
textElementContent = textElementContent.trim();
|
||||
|
||||
if (textElementContent.isNotEmpty())
|
||||
if (ignoreEmptyTextElements ? textElementContent.containsNonWhitespaceChars()
|
||||
: textElementContent.isNotEmpty())
|
||||
e->setText (textElementContent);
|
||||
}
|
||||
}
|
||||
|
|
@ -13412,7 +13461,7 @@ XmlElement::XmlElement (const String& tagName_) throw()
|
|||
attributes (0)
|
||||
{
|
||||
// the tag name mustn't be empty, or it'll look like a text element!
|
||||
jassert (tagName_.trim().isNotEmpty())
|
||||
jassert (tagName_.containsNonWhitespaceChars())
|
||||
}
|
||||
|
||||
XmlElement::XmlElement (int /*dummy*/) throw()
|
||||
|
|
@ -14684,9 +14733,10 @@ static CriticalSection runningThreadsLock;
|
|||
|
||||
void Thread::threadEntryPoint (Thread* const thread) throw()
|
||||
{
|
||||
runningThreadsLock.enter();
|
||||
runningThreads.add (thread);
|
||||
runningThreadsLock.exit();
|
||||
{
|
||||
const ScopedLock sl (runningThreadsLock);
|
||||
runningThreads.add (thread);
|
||||
}
|
||||
|
||||
JUCE_TRY
|
||||
{
|
||||
|
|
@ -14705,10 +14755,12 @@ void Thread::threadEntryPoint (Thread* const thread) throw()
|
|||
}
|
||||
JUCE_CATCH_ALL_ASSERT
|
||||
|
||||
runningThreadsLock.enter();
|
||||
jassert (runningThreads.contains (thread));
|
||||
runningThreads.removeValue (thread);
|
||||
runningThreadsLock.exit();
|
||||
{
|
||||
const ScopedLock sl (runningThreadsLock);
|
||||
|
||||
jassert (runningThreads.contains (thread));
|
||||
runningThreads.removeValue (thread);
|
||||
}
|
||||
|
||||
#if JUCE_WIN32
|
||||
juce_CloseThreadHandle (thread->threadHandle_);
|
||||
|
|
@ -14872,34 +14924,28 @@ int Thread::getNumRunningThreads() throw()
|
|||
Thread* Thread::getCurrentThread() throw()
|
||||
{
|
||||
const ThreadID thisId = getCurrentThreadId();
|
||||
Thread* result = 0;
|
||||
|
||||
runningThreadsLock.enter();
|
||||
const ScopedLock sl (runningThreadsLock);
|
||||
|
||||
for (int i = runningThreads.size(); --i >= 0;)
|
||||
{
|
||||
Thread* const t = (Thread*) (runningThreads.getUnchecked(i));
|
||||
|
||||
if (t->threadId_ == thisId)
|
||||
{
|
||||
result = t;
|
||||
break;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
runningThreadsLock.exit();
|
||||
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Thread::stopAllThreads (const int timeOutMilliseconds) throw()
|
||||
{
|
||||
runningThreadsLock.enter();
|
||||
{
|
||||
const ScopedLock sl (runningThreadsLock);
|
||||
|
||||
for (int i = runningThreads.size(); --i >= 0;)
|
||||
((Thread*) runningThreads.getUnchecked(i))->signalThreadShouldExit();
|
||||
|
||||
runningThreadsLock.exit();
|
||||
for (int i = runningThreads.size(); --i >= 0;)
|
||||
((Thread*) runningThreads.getUnchecked(i))->signalThreadShouldExit();
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
|
@ -27173,7 +27219,7 @@ void KnownPluginList::addToMenu (PopupMenu& menu, const SortMethod sortMethod) c
|
|||
String thisSubMenuName (sortMethod == sortByCategory ? pd->category
|
||||
: pd->manufacturerName);
|
||||
|
||||
if (thisSubMenuName.trim().isEmpty())
|
||||
if (! thisSubMenuName.containsNonWhitespaceChars())
|
||||
thisSubMenuName = T("Other");
|
||||
|
||||
if (thisSubMenuName != lastSubMenuName)
|
||||
|
|
@ -41632,9 +41678,14 @@ bool Button::keyStateChanged (Component*)
|
|||
updateState (0);
|
||||
|
||||
if (isEnabled() && wasDown && ! isKeyDown)
|
||||
{
|
||||
internalClickCallback (ModifierKeys::getCurrentModifiers());
|
||||
|
||||
return isKeyDown || wasDown;
|
||||
// (return immediately - this button may now have been deleted)
|
||||
return true;
|
||||
}
|
||||
|
||||
return wasDown || isKeyDown;
|
||||
}
|
||||
|
||||
bool Button::keyPressed (const KeyPress&, Component*)
|
||||
|
|
@ -51504,6 +51555,13 @@ void TreeView::setRootItem (TreeViewItem* const newRootItem)
|
|||
}
|
||||
}
|
||||
|
||||
void TreeView::deleteRootItem()
|
||||
{
|
||||
TreeViewItem* const oldItem = rootItem;
|
||||
setRootItem (0);
|
||||
delete oldItem;
|
||||
}
|
||||
|
||||
void TreeView::setRootItemVisible (const bool shouldBeVisible)
|
||||
{
|
||||
rootItemVisible = shouldBeVisible;
|
||||
|
|
@ -53286,7 +53344,7 @@ FileChooser::FileChooser (const String& chooserBoxTitle,
|
|||
useNativeDialogBox = false;
|
||||
#endif
|
||||
|
||||
if (fileFilters.trim().isEmpty())
|
||||
if (! fileFilters.containsNonWhitespaceChars())
|
||||
filters = T("*");
|
||||
}
|
||||
|
||||
|
|
@ -239911,7 +239969,7 @@ bool juce_canWriteToFile (const String& fileName) throw()
|
|||
}
|
||||
|
||||
bool juce_setFileReadOnly (const String& fileName,
|
||||
bool isReadOnly)
|
||||
bool isReadOnly) throw()
|
||||
{
|
||||
DWORD attr = GetFileAttributes (fileName);
|
||||
|
||||
|
|
@ -245012,7 +245070,7 @@ static int CALLBACK browseCallbackProc (HWND hWnd, UINT msg, LPARAM lParam, LPAR
|
|||
return 0;
|
||||
}
|
||||
|
||||
void juce_setWindowStyleBit (HWND h, int styleType, int feature, bool bitIsSet);
|
||||
void juce_setWindowStyleBit (HWND h, int styleType, int feature, bool bitIsSet) throw();
|
||||
|
||||
static UINT_PTR CALLBACK openCallback (HWND hdlg, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam)
|
||||
{
|
||||
|
|
@ -246576,6 +246634,12 @@ void WebBrowserComponent::goForward()
|
|||
browser->browser->GoForward();
|
||||
}
|
||||
|
||||
void WebBrowserComponent::refresh()
|
||||
{
|
||||
if (browser->browser != 0)
|
||||
browser->browser->Refresh();
|
||||
}
|
||||
|
||||
void WebBrowserComponent::paint (Graphics& g)
|
||||
{
|
||||
if (browser->browser == 0)
|
||||
|
|
@ -259370,6 +259434,10 @@ void WebBrowserComponent::goForward()
|
|||
|
||||
}
|
||||
|
||||
void WebBrowserComponent::refresh()
|
||||
{
|
||||
}
|
||||
|
||||
void WebBrowserComponent::paint (Graphics& g)
|
||||
{
|
||||
g.fillAll (Colours::white);
|
||||
|
|
@ -265555,6 +265623,9 @@ private:
|
|||
|
||||
void swapRGBOrder (const int x, const int y, const int w, int h) const
|
||||
{
|
||||
#if JUCE_BIG_ENDIAN
|
||||
jassert (pixelStride == 4);
|
||||
#endif
|
||||
jassert (Rectangle (0, 0, juceImage.getWidth(), juceImage.getHeight())
|
||||
.contains (Rectangle (x, y, w, h)));
|
||||
|
||||
|
|
@ -265567,9 +265638,18 @@ private:
|
|||
|
||||
for (int i = w; --i >= 0;)
|
||||
{
|
||||
const uint8 temp = p[0];
|
||||
#if JUCE_BIG_ENDIAN
|
||||
const uint8 oldp3 = p[3];
|
||||
const uint8 oldp1 = p[1];
|
||||
p[3] = p[0];
|
||||
p[0] = oldp1;
|
||||
p[1] = p[2];
|
||||
p[2] = oldp3;
|
||||
#else
|
||||
const uint8 oldp0 = p[0];
|
||||
p[0] = p[2];
|
||||
p[2] = temp;
|
||||
p[2] = oldp0;
|
||||
#endif
|
||||
|
||||
p += pixelStride;
|
||||
}
|
||||
|
|
@ -269370,6 +269450,11 @@ public:
|
|||
[webView stopLoading: nil];
|
||||
}
|
||||
|
||||
void refresh()
|
||||
{
|
||||
[webView reload: nil];
|
||||
}
|
||||
|
||||
private:
|
||||
WebView* webView;
|
||||
DownloadClickDetector* clickListener;
|
||||
|
|
@ -269426,6 +269511,11 @@ void WebBrowserComponent::goForward()
|
|||
browser->goForward();
|
||||
}
|
||||
|
||||
void WebBrowserComponent::refresh()
|
||||
{
|
||||
browser->refresh();
|
||||
}
|
||||
|
||||
void WebBrowserComponent::paint (Graphics& g)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1535,12 +1535,16 @@ public:
|
|||
/** Returns true if the string contains no characters.
|
||||
|
||||
Note that there's also an isNotEmpty() method to help write readable code.
|
||||
|
||||
@see containsNonWhitespaceChars()
|
||||
*/
|
||||
inline bool isEmpty() const throw() { return text->text[0] == 0; }
|
||||
|
||||
/** Returns true if the string contains at least one character.
|
||||
|
||||
Note that there's also an isEmpty() method to help write readable code.
|
||||
|
||||
@see containsNonWhitespaceChars()
|
||||
*/
|
||||
inline bool isNotEmpty() const throw() { return text->text[0] != 0; }
|
||||
|
||||
|
|
@ -1700,6 +1704,15 @@ public:
|
|||
*/
|
||||
bool containsOnly (const tchar* const charactersItMightContain) const throw();
|
||||
|
||||
/** Returns true if this string contains any non-whitespace characters.
|
||||
|
||||
This will return false if the string contains only whitespace characters, or
|
||||
if it's empty.
|
||||
|
||||
It is equivalent to calling "myString.trim().isNotEmpty()".
|
||||
*/
|
||||
bool containsNonWhitespaceChars() const throw();
|
||||
|
||||
/** Returns true if the string matches this simple wildcard expression.
|
||||
|
||||
So for example String ("abcdef").matchesWildcard ("*DEF", true) would return true.
|
||||
|
|
@ -6534,6 +6547,11 @@ public:
|
|||
int getNumberOfChildFiles (const int whatToLookFor,
|
||||
const String& wildCardPattern = JUCE_T("*")) const throw();
|
||||
|
||||
/** Returns true if this file is a directory that contains one or more subdirectories.
|
||||
@see isDirectory, findChildFiles
|
||||
*/
|
||||
bool File::containsSubDirectories() const throw();
|
||||
|
||||
/** Creates a stream to read from this file.
|
||||
|
||||
@returns a stream that will read from this file (initially positioned at the
|
||||
|
|
@ -11812,7 +11830,14 @@ public:
|
|||
/** Creates a checksum for a block of binary data. */
|
||||
MD5 (const char* data, const int numBytes);
|
||||
|
||||
/** Creates a checksum for a string. */
|
||||
/** Creates a checksum for a string.
|
||||
|
||||
Note that this operates on the string as a block of unicode characters, so the
|
||||
result you get will differ from the value you'd get if the string was treated
|
||||
as a block of utf8 or ascii. Bear this in mind if you're comparing the result
|
||||
of this method with a checksum created by a different framework, which may have
|
||||
used a different encoding.
|
||||
*/
|
||||
MD5 (const String& text);
|
||||
|
||||
/** Creates a checksum for the input from a stream.
|
||||
|
|
@ -13751,6 +13776,15 @@ public:
|
|||
*/
|
||||
void setInputSource (InputSource* const newSource) throw();
|
||||
|
||||
/** Sets a flag to change the treatment of empty text elements.
|
||||
|
||||
If this is true (the default state), then any text elements that contain only
|
||||
whitespace characters will be ingored during parsing. If you need to catch
|
||||
whitespace-only text, then you should set this to false before calling the
|
||||
getDocumentElement() method.
|
||||
*/
|
||||
void setEmptyTextElementsIgnored (const bool shouldBeIgnored) throw();
|
||||
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
|
|
@ -13761,7 +13795,7 @@ private:
|
|||
bool identifierLookupTable [128];
|
||||
String lastError, dtdText;
|
||||
StringArray tokenisedDTD;
|
||||
bool needToLoadDTD;
|
||||
bool needToLoadDTD, ignoreEmptyTextElements;
|
||||
InputSource* inputSource;
|
||||
|
||||
void setLastError (const String& desc, const bool carryOn) throw();
|
||||
|
|
@ -43179,7 +43213,8 @@ public:
|
|||
The object passed in will not be deleted by the treeview, it's up to the caller
|
||||
to delete it when no longer needed. BUT make absolutely sure that you don't delete
|
||||
this item until you've removed it from the tree, either by calling setRootItem (0),
|
||||
or by deleting the tree first.
|
||||
or by deleting the tree first. You can also use deleteRootItem() as a quick way
|
||||
to delete it.
|
||||
*/
|
||||
void setRootItem (TreeViewItem* const newRootItem);
|
||||
|
||||
|
|
@ -43189,6 +43224,12 @@ public:
|
|||
*/
|
||||
TreeViewItem* getRootItem() const throw() { return rootItem; }
|
||||
|
||||
/** This will remove and delete the current root item.
|
||||
|
||||
It's a convenient way of deleting the item and calling setRootItem (0).
|
||||
*/
|
||||
void deleteRootItem();
|
||||
|
||||
/** Changes whether the tree's root item is shown or not.
|
||||
|
||||
If the root item is hidden, only its sub-items will be shown in the treeview - this
|
||||
|
|
@ -52820,6 +52861,10 @@ public:
|
|||
*/
|
||||
void goForward();
|
||||
|
||||
/** Refreshes the browser.
|
||||
*/
|
||||
void refresh();
|
||||
|
||||
/** This callback is called when the browser is about to navigate
|
||||
to a new location.
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -416,7 +416,7 @@ void KnownPluginList::addToMenu (PopupMenu& menu, const SortMethod sortMethod) c
|
|||
String thisSubMenuName (sortMethod == sortByCategory ? pd->category
|
||||
: pd->manufacturerName);
|
||||
|
||||
if (thisSubMenuName.trim().isEmpty())
|
||||
if (! thisSubMenuName.containsNonWhitespaceChars())
|
||||
thisSubMenuName = T("Other");
|
||||
|
||||
if (thisSubMenuName != lastSubMenuName)
|
||||
|
|
|
|||
|
|
@ -613,9 +613,14 @@ bool Button::keyStateChanged (Component*)
|
|||
updateState (0);
|
||||
|
||||
if (isEnabled() && wasDown && ! isKeyDown)
|
||||
{
|
||||
internalClickCallback (ModifierKeys::getCurrentModifiers());
|
||||
|
||||
return isKeyDown || wasDown;
|
||||
// (return immediately - this button may now have been deleted)
|
||||
return true;
|
||||
}
|
||||
|
||||
return wasDown || isKeyDown;
|
||||
}
|
||||
|
||||
bool Button::keyPressed (const KeyPress&, Component*)
|
||||
|
|
|
|||
|
|
@ -435,6 +435,14 @@ void TreeView::setRootItem (TreeViewItem* const newRootItem)
|
|||
}
|
||||
}
|
||||
|
||||
void TreeView::deleteRootItem()
|
||||
{
|
||||
TreeViewItem* const oldItem = rootItem;
|
||||
setRootItem (0);
|
||||
delete oldItem;
|
||||
}
|
||||
|
||||
|
||||
void TreeView::setRootItemVisible (const bool shouldBeVisible)
|
||||
{
|
||||
rootItemVisible = shouldBeVisible;
|
||||
|
|
|
|||
|
|
@ -414,7 +414,8 @@ public:
|
|||
The object passed in will not be deleted by the treeview, it's up to the caller
|
||||
to delete it when no longer needed. BUT make absolutely sure that you don't delete
|
||||
this item until you've removed it from the tree, either by calling setRootItem (0),
|
||||
or by deleting the tree first.
|
||||
or by deleting the tree first. You can also use deleteRootItem() as a quick way
|
||||
to delete it.
|
||||
*/
|
||||
void setRootItem (TreeViewItem* const newRootItem);
|
||||
|
||||
|
|
@ -424,6 +425,12 @@ public:
|
|||
*/
|
||||
TreeViewItem* getRootItem() const throw() { return rootItem; }
|
||||
|
||||
/** This will remove and delete the current root item.
|
||||
|
||||
It's a convenient way of deleting the item and calling setRootItem (0).
|
||||
*/
|
||||
void deleteRootItem();
|
||||
|
||||
/** Changes whether the tree's root item is shown or not.
|
||||
|
||||
If the root item is hidden, only its sub-items will be shown in the treeview - this
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ FileChooser::FileChooser (const String& chooserBoxTitle,
|
|||
useNativeDialogBox = false;
|
||||
#endif
|
||||
|
||||
if (fileFilters.trim().isEmpty())
|
||||
if (! fileFilters.containsNonWhitespaceChars())
|
||||
filters = T("*");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,9 @@ public:
|
|||
*/
|
||||
void goForward();
|
||||
|
||||
/** Refreshes the browser.
|
||||
*/
|
||||
void refresh();
|
||||
|
||||
//==============================================================================
|
||||
/** This callback is called when the browser is about to navigate
|
||||
|
|
|
|||
|
|
@ -66,7 +66,14 @@ public:
|
|||
/** Creates a checksum for a block of binary data. */
|
||||
MD5 (const char* data, const int numBytes);
|
||||
|
||||
/** Creates a checksum for a string. */
|
||||
/** Creates a checksum for a string.
|
||||
|
||||
Note that this operates on the string as a block of unicode characters, so the
|
||||
result you get will differ from the value you'd get if the string was treated
|
||||
as a block of utf8 or ascii. Bear this in mind if you're comparing the result
|
||||
of this method with a checksum created by a different framework, which may have
|
||||
used a different encoding.
|
||||
*/
|
||||
MD5 (const String& text);
|
||||
|
||||
/** Creates a checksum for the input from a stream.
|
||||
|
|
|
|||
|
|
@ -96,6 +96,12 @@ bool juce_findFileNext (void* handle, String& resultFile,
|
|||
|
||||
void juce_findFileClose (void* handle) throw();
|
||||
|
||||
//==============================================================================
|
||||
static const String juce_addTrailingSeparator (const String& path) throw()
|
||||
{
|
||||
return path.endsWithChar (File::separator) ? path
|
||||
: path + File::separator;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static const String parseAbsolutePath (String path) throw()
|
||||
|
|
@ -498,10 +504,7 @@ const File File::getChildFile (String relativePath) const throw()
|
|||
}
|
||||
}
|
||||
|
||||
if (! path.endsWithChar (separator))
|
||||
path += separator;
|
||||
|
||||
return File (path + relativePath);
|
||||
return File (juce_addTrailingSeparator (path) + relativePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -663,9 +666,7 @@ int File::findChildFiles (OwnedArray<File>& results,
|
|||
// find child files or directories in this directory first..
|
||||
if (isDirectory())
|
||||
{
|
||||
String path (fullPath);
|
||||
if (! path.endsWithChar (separator))
|
||||
path += separator;
|
||||
const String path (juce_addTrailingSeparator (fullPath));
|
||||
|
||||
String filename;
|
||||
bool isDirectory, isHidden;
|
||||
|
|
@ -760,6 +761,37 @@ int File::getNumberOfChildFiles (const int whatToLookFor,
|
|||
return count;
|
||||
}
|
||||
|
||||
bool File::containsSubDirectories() const throw()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (isDirectory())
|
||||
{
|
||||
String filename;
|
||||
bool isDirectory, isHidden;
|
||||
void* const handle = juce_findFileStart (juce_addTrailingSeparator (fullPath),
|
||||
T("*"), filename,
|
||||
&isDirectory, &isHidden, 0, 0, 0, 0);
|
||||
|
||||
if (handle != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (isDirectory)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (juce_findFileNext (handle, filename, &isDirectory, &isHidden, 0, 0, 0, 0));
|
||||
|
||||
juce_findFileClose (handle);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const File File::getNonexistentChildFile (const String& prefix_,
|
||||
const String& suffix,
|
||||
|
|
@ -1040,11 +1072,8 @@ const String File::getRelativePathFrom (const File& dir) const throw()
|
|||
thisPath [len] = 0;
|
||||
}
|
||||
|
||||
String dirPath ((dir.existsAsFile()) ? dir.getParentDirectory().getFullPathName()
|
||||
: dir.fullPath);
|
||||
|
||||
if (! dirPath.endsWithChar (separator))
|
||||
dirPath += separator;
|
||||
String dirPath (juce_addTrailingSeparator ((dir.existsAsFile()) ? dir.getParentDirectory().getFullPathName()
|
||||
: dir.fullPath));
|
||||
|
||||
const int len = jmin (thisPath.length(), dirPath.length());
|
||||
int commonBitLength = 0;
|
||||
|
|
|
|||
|
|
@ -548,6 +548,11 @@ public:
|
|||
int getNumberOfChildFiles (const int whatToLookFor,
|
||||
const String& wildCardPattern = JUCE_T("*")) const throw();
|
||||
|
||||
/** Returns true if this file is a directory that contains one or more subdirectories.
|
||||
@see isDirectory, findChildFiles
|
||||
*/
|
||||
bool File::containsSubDirectories() const throw();
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a stream to read from this file.
|
||||
|
||||
|
|
|
|||
|
|
@ -1483,11 +1483,15 @@ bool String::startsWithIgnoreCase (const tchar* const other) const throw()
|
|||
|
||||
bool String::startsWithChar (const tchar character) const throw()
|
||||
{
|
||||
jassert (character != 0); // strings can't contain a null character!
|
||||
|
||||
return text->text[0] == character;
|
||||
}
|
||||
|
||||
bool String::endsWithChar (const tchar character) const throw()
|
||||
{
|
||||
jassert (character != 0); // strings can't contain a null character!
|
||||
|
||||
return text->text[0] != 0
|
||||
&& text->text [length() - 1] == character;
|
||||
}
|
||||
|
|
@ -1838,6 +1842,18 @@ bool String::containsAnyOf (const tchar* const chars) const throw()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool String::containsNonWhitespaceChars() const throw()
|
||||
{
|
||||
const tchar* t = text->text;
|
||||
|
||||
while (*t != 0)
|
||||
if (! CharacterFunctions::isWhitespace (*t++))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
int String::getIntValue() const throw()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -176,12 +176,16 @@ public:
|
|||
/** Returns true if the string contains no characters.
|
||||
|
||||
Note that there's also an isNotEmpty() method to help write readable code.
|
||||
|
||||
@see containsNonWhitespaceChars()
|
||||
*/
|
||||
inline bool isEmpty() const throw() { return text->text[0] == 0; }
|
||||
|
||||
/** Returns true if the string contains at least one character.
|
||||
|
||||
Note that there's also an isEmpty() method to help write readable code.
|
||||
|
||||
@see containsNonWhitespaceChars()
|
||||
*/
|
||||
inline bool isNotEmpty() const throw() { return text->text[0] != 0; }
|
||||
|
||||
|
|
@ -341,6 +345,15 @@ public:
|
|||
*/
|
||||
bool containsOnly (const tchar* const charactersItMightContain) const throw();
|
||||
|
||||
/** Returns true if this string contains any non-whitespace characters.
|
||||
|
||||
This will return false if the string contains only whitespace characters, or
|
||||
if it's empty.
|
||||
|
||||
It is equivalent to calling "myString.trim().isNotEmpty()".
|
||||
*/
|
||||
bool containsNonWhitespaceChars() const throw();
|
||||
|
||||
/** Returns true if the string matches this simple wildcard expression.
|
||||
|
||||
So for example String ("abcdef").matchesWildcard ("*DEF", true) would return true.
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ void StringArray::removeEmptyStrings (const bool removeWhitespaceStrings) throw(
|
|||
if (removeWhitespaceStrings)
|
||||
{
|
||||
for (int i = size(); --i >= 0;)
|
||||
if (((const String*) strings.getUnchecked(i))->trim().isEmpty())
|
||||
if (! ((const String*) strings.getUnchecked(i))->containsNonWhitespaceChars())
|
||||
remove (i);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ static bool isXmlIdentifierChar_Slow (const tchar c) throw()
|
|||
//==============================================================================
|
||||
XmlDocument::XmlDocument (const String& documentText) throw()
|
||||
: originalText (documentText),
|
||||
ignoreEmptyTextElements (true),
|
||||
inputSource (0)
|
||||
{
|
||||
}
|
||||
|
|
@ -77,6 +78,11 @@ void XmlDocument::setInputSource (InputSource* const newSource) throw()
|
|||
}
|
||||
}
|
||||
|
||||
void XmlDocument::setEmptyTextElementsIgnored (const bool shouldBeIgnored) throw()
|
||||
{
|
||||
ignoreEmptyTextElements = shouldBeIgnored;
|
||||
}
|
||||
|
||||
XmlElement* XmlDocument::getDocumentElement (const bool onlyReadOuterDocumentElement)
|
||||
{
|
||||
String textToParse (originalText);
|
||||
|
|
@ -626,9 +632,8 @@ void XmlDocument::readChildElements (XmlElement* parent) throw()
|
|||
}
|
||||
}
|
||||
|
||||
textElementContent = textElementContent.trim();
|
||||
|
||||
if (textElementContent.isNotEmpty())
|
||||
if (ignoreEmptyTextElements ? textElementContent.containsNonWhitespaceChars()
|
||||
: textElementContent.isNotEmpty())
|
||||
e->setText (textElementContent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,14 @@ public:
|
|||
*/
|
||||
void setInputSource (InputSource* const newSource) throw();
|
||||
|
||||
/** Sets a flag to change the treatment of empty text elements.
|
||||
|
||||
If this is true (the default state), then any text elements that contain only
|
||||
whitespace characters will be ingored during parsing. If you need to catch
|
||||
whitespace-only text, then you should set this to false before calling the
|
||||
getDocumentElement() method.
|
||||
*/
|
||||
void setEmptyTextElementsIgnored (const bool shouldBeIgnored) throw();
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
|
@ -134,7 +142,7 @@ private:
|
|||
bool identifierLookupTable [128];
|
||||
String lastError, dtdText;
|
||||
StringArray tokenisedDTD;
|
||||
bool needToLoadDTD;
|
||||
bool needToLoadDTD, ignoreEmptyTextElements;
|
||||
InputSource* inputSource;
|
||||
|
||||
void setLastError (const String& desc, const bool carryOn) throw();
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ XmlElement::XmlElement (const String& tagName_) throw()
|
|||
attributes (0)
|
||||
{
|
||||
// the tag name mustn't be empty, or it'll look like a text element!
|
||||
jassert (tagName_.trim().isNotEmpty())
|
||||
jassert (tagName_.containsNonWhitespaceChars())
|
||||
}
|
||||
|
||||
XmlElement::XmlElement (int /*dummy*/) throw()
|
||||
|
|
|
|||
|
|
@ -55,9 +55,10 @@ static CriticalSection runningThreadsLock;
|
|||
//==============================================================================
|
||||
void Thread::threadEntryPoint (Thread* const thread) throw()
|
||||
{
|
||||
runningThreadsLock.enter();
|
||||
runningThreads.add (thread);
|
||||
runningThreadsLock.exit();
|
||||
{
|
||||
const ScopedLock sl (runningThreadsLock);
|
||||
runningThreads.add (thread);
|
||||
}
|
||||
|
||||
JUCE_TRY
|
||||
{
|
||||
|
|
@ -76,10 +77,12 @@ void Thread::threadEntryPoint (Thread* const thread) throw()
|
|||
}
|
||||
JUCE_CATCH_ALL_ASSERT
|
||||
|
||||
runningThreadsLock.enter();
|
||||
jassert (runningThreads.contains (thread));
|
||||
runningThreads.removeValue (thread);
|
||||
runningThreadsLock.exit();
|
||||
{
|
||||
const ScopedLock sl (runningThreadsLock);
|
||||
|
||||
jassert (runningThreads.contains (thread));
|
||||
runningThreads.removeValue (thread);
|
||||
}
|
||||
|
||||
#if JUCE_WIN32
|
||||
juce_CloseThreadHandle (thread->threadHandle_);
|
||||
|
|
@ -250,34 +253,28 @@ int Thread::getNumRunningThreads() throw()
|
|||
Thread* Thread::getCurrentThread() throw()
|
||||
{
|
||||
const ThreadID thisId = getCurrentThreadId();
|
||||
Thread* result = 0;
|
||||
|
||||
runningThreadsLock.enter();
|
||||
const ScopedLock sl (runningThreadsLock);
|
||||
|
||||
for (int i = runningThreads.size(); --i >= 0;)
|
||||
{
|
||||
Thread* const t = (Thread*) (runningThreads.getUnchecked(i));
|
||||
|
||||
if (t->threadId_ == thisId)
|
||||
{
|
||||
result = t;
|
||||
break;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
runningThreadsLock.exit();
|
||||
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Thread::stopAllThreads (const int timeOutMilliseconds) throw()
|
||||
{
|
||||
runningThreadsLock.enter();
|
||||
{
|
||||
const ScopedLock sl (runningThreadsLock);
|
||||
|
||||
for (int i = runningThreads.size(); --i >= 0;)
|
||||
((Thread*) runningThreads.getUnchecked(i))->signalThreadShouldExit();
|
||||
|
||||
runningThreadsLock.exit();
|
||||
for (int i = runningThreads.size(); --i >= 0;)
|
||||
((Thread*) runningThreads.getUnchecked(i))->signalThreadShouldExit();
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue