From 60fd818a784319a4aa385f2138ff3081b0615b48 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Wed, 13 Jul 2005 18:01:43 +0000
Subject: [PATCH] added wxXmlResource::Unload() (replaces patch 1178853)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@34839 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/changes.txt         |   4 ++
 docs/latex/wx/xmlres.tex |  33 ++++++++++++
 include/wx/xrc/xmlres.h  |  14 +++++
 src/xrc/xmlres.cpp       | 107 ++++++++++++++++++++++++++++++---------
 4 files changed, 135 insertions(+), 23 deletions(-)

diff --git a/docs/changes.txt b/docs/changes.txt
index a03e675209..7fa0b5e370 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -10,6 +10,10 @@ All:
 - Fixed wxScopeGuard to work with VC++, documented it.
 - Fixed proxy handling in wxURL.
 
+All (GUI):
+
+- Added wxXmlResource::Unload()
+
 wxMSW:
 
 - Fixed multiline tooltips handling.
diff --git a/docs/latex/wx/xmlres.tex b/docs/latex/wx/xmlres.tex
index 95e99a8e20..7ef4cf75df 100644
--- a/docs/latex/wx/xmlres.tex
+++ b/docs/latex/wx/xmlres.tex
@@ -32,6 +32,7 @@ enum wxXmlResourceFlags
 
 \latexignore{\rtfignore{\wxheading{Members}}}
 
+
 \membersection{wxXmlResource::wxXmlResource}\label{wxxmlresourcector}
 
 \func{}{wxXmlResource}{\param{const wxString\& }{filemask}, \param{int }{flags = wxXRC\_USE\_LOCALE}}
@@ -55,12 +56,14 @@ wxXRC\_NO\_SUBCLASSING: subclass property of object nodes will be ignored
 XRC files from being reloaded from disk in case they have been modified there
 since being last loaded (may slightly speed up loading them).}
 
+
 \membersection{wxXmlResource::\destruct{wxXmlResource}}\label{wxxmlresourcedtor}
 
 \func{}{\destruct{wxXmlResource}}{\void}
 
 Destructor.
 
+
 \membersection{wxXmlResource::AddHandler}\label{wxxmlresourceaddhandler}
 
 \func{void}{AddHandler}{\param{wxXmlResourceHandler* }{handler}}
@@ -71,6 +74,7 @@ wxTextCtrlXmlHandler, wxHtmlWindowXmlHandler. The XML resource compiler
 (wxxrc) can create include file that contains initialization code for
 all controls used within the resource.
 
+
 \membersection{wxXmlResource::AttachUnknownControl}\label{wxxmlresourceattachunknowncontrol}
 
 \func{bool}{AttachUnknownControl}{\param{const wxString\& }{name}, \param{wxWindow* }{control}, \param{wxWindow* }{parent = NULL}}
@@ -78,12 +82,14 @@ all controls used within the resource.
 Attaches an unknown control to the given panel/window/dialog.
 Unknown controls are used in conjunction with <object class="unknown">.
 
+
 \membersection{wxXmlResource::ClearHandlers}\label{wxxmlresourceclearhandlers}
 
 \func{void}{ClearHandlers}{\void}
 
 Removes all handlers.
 
+
 \membersection{wxXmlResource::CompareVersion}\label{wxxmlresourcecompareversion}
 
 \constfunc{int}{CompareVersion}{\param{int }{major}, \param{int }{minor}, \param{int }{release}, \param{int }{revision}}
@@ -91,24 +97,28 @@ Removes all handlers.
 Compares the XRC version to the argument. Returns -1 if the XRC version
 is less than the argument, +1 if greater, and 0 if they equal.
 
+
 \membersection{wxXmlResource::Get}\label{wxxmlresourceget}
 
 \func{wxXmlResource*}{Get}{\void}
 
 Gets the global resources object or creates one if none exists.
 
+
 \membersection{wxXmlResource::GetFlags}\label{wxxmlresourcegetflags}
 
 \func{int}{GetFlags}{\void}
 
 Returns flags, which may be a bitlist of wxXRC\_USE\_LOCALE and wxXRC\_NO\_SUBCLASSING.
 
+
 \membersection{wxXmlResource::GetVersion}\label{wxxmlresourcegetversion}
 
 \constfunc{long}{GetVersion}{\void}
 
 Returns version information (a.b.c.d = d+ 256*c + 256\textasciicircum2*b + 256\textasciitilde3*a).
 
+
 \membersection{wxXmlResource::GetXRCID}\label{wxxmlresourcegetxmlid}
 
 \func{int}{GetXRCID}{\param{const wxChar* }{str\_id}}
@@ -117,6 +127,7 @@ Returns a numeric ID that is equivalent to the string ID used in an XML
 resource. To be used in event tables.
 The macro {\tt XRCID(name)} is provided for convenience.
 
+
 \membersection{wxXmlResource::InitAllHandlers}\label{wxxmlresourceinitallhandlers}
 
 \func{void}{InitAllHandlers}{\void}
@@ -125,6 +136,7 @@ Initializes handlers for all supported controls/windows. This will
 make the executable quite big because it forces linking against
 most of the wxWidgets library.
 
+
 \membersection{wxXmlResource::Load}\label{wxxmlresourceload}
 
 \func{bool}{Load}{\param{const wxString\& }{filemask}}
@@ -132,12 +144,14 @@ most of the wxWidgets library.
 Loads resources from XML files that match given filemask.
 This method understands VFS (see filesys.h).
 
+
 \membersection{wxXmlResource::LoadBitmap}\label{wxxmlresourceloadbitmap}
 
 \func{wxBitmap}{LoadBitmap}{\param{const wxString\& }{name}}
 
 Loads a bitmap resource from a file.
 
+
 \membersection{wxXmlResource::LoadDialog}\label{wxxmlresourceloaddialog}
 
 \func{wxDialog*}{LoadDialog}{\param{wxWindow* }{parent}, \param{const wxString\& }{name}}
@@ -159,24 +173,28 @@ Example:
   dlg->ShowModal();
 \end{verbatim}
 
+
 \membersection{wxXmlResource::LoadFrame}\label{wxxmlresourceloadframe}
 
 \func{bool}{LoadFrame}{\param{wxFrame* }{frame}, \param{wxWindow* }{parent}, \param{const wxString\& }{name}}
 
 Loads a frame.
 
+
 \membersection{wxXmlResource::LoadIcon}\label{wxxmlresourceloadicon}
 
 \func{wxIcon}{LoadIcon}{\param{const wxString\& }{name}}
 
 Loads an icon resource from a file.
 
+
 \membersection{wxXmlResource::LoadMenu}\label{wxxmlresourceloadmenu}
 
 \func{wxMenu*}{LoadMenu}{\param{const wxString\& }{name}}
 
 Loads menu from resource. Returns NULL on failure.
 
+
 \membersection{wxXmlResource::LoadMenuBar}\label{wxxmlresourceloadmenubar}
 
 \func{wxMenuBar*}{LoadMenuBar}{\param{wxWindow* }{parent}, \param{const wxString\& }{name}}
@@ -187,6 +205,7 @@ Loads a menubar from resource. Returns NULL on failure.
 
 Loads a menubar from resource. Returns NULL on failure.
 
+
 \membersection{wxXmlResource::LoadPanel}\label{wxxmlresourceloadpanel}
 
 \func{wxPanel*}{LoadPanel}{\param{wxWindow* }{parent}, \param{const wxString\& }{name}}
@@ -198,21 +217,35 @@ Loads a panel. {\it panel} points to parent window (if any).
 Loads a panel. {\it panel} points to parent window (if any). This form
 is used to finish creation of an already existing instance.
 
+
 \membersection{wxXmlResource::LoadToolBar}\label{wxxmlresourceloadtoolbar}
 
 \func{wxToolBar*}{LoadToolBar}{\param{wxWindow* }{parent}, \param{const wxString\& }{name}}
 
 Loads a toolbar.
 
+
 \membersection{wxXmlResource::Set}\label{wxxmlresourceset}
 
 \func{wxXmlResource*}{Set}{\param{wxXmlResource* }{res}}
 
 Sets the global resources object and returns a pointer to the previous one (may be NULL).
 
+
 \membersection{wxXmlResource::SetFlags}\label{wxxmlresourcesetflags}
 
 \func{void}{SetFlags}{\param{int }{flags}}
 
 Sets flags (bitlist of wxXRC\_USE\_LOCALE and wxXRC\_NO\_SUBCLASSING).
 
+
+\membersection{wxXmlResource::Unload}\label{wxxmlresourceunload}
+
+\func{bool}{Unload}{\param{const wxString\& }{filename}}
+
+This function unloads a resource previously loaded by 
+\helpref{Load()}{wxxmlresourceload}.
+
+Returns \true if the resource was successfully unloaded and \false if it hasn't
+been found in the list of loaded resources.
+
diff --git a/include/wx/xrc/xmlres.h b/include/wx/xrc/xmlres.h
index 1554ce82e0..b90ea18410 100644
--- a/include/wx/xrc/xmlres.h
+++ b/include/wx/xrc/xmlres.h
@@ -124,6 +124,9 @@ public:
     // This method understands VFS (see filesys.h).
     bool Load(const wxString& filemask);
 
+    // Unload resource from the given XML file (wildcards not allowed)
+    bool Unload(const wxString& filename);
+
     // Initialize handlers for all supported controls/windows. This will
     // make the executable quite big because it forces linking against
     // most of the wxWidgets library.
@@ -250,6 +253,17 @@ protected:
                                 wxObject *instance = NULL,
                                 wxXmlResourceHandler *handlerToUse = NULL);
 
+    // Helper of Load() and Unload(): returns the URL corresponding to the
+    // given file if it's indeed a file, otherwise returns the original string
+    // unmodified
+    static wxString ConvertFileNameToURL(const wxString& filename);
+
+    // loading resources from archives is impossible without wxFileSystem
+#if wxUSE_FILESYSTEM
+    // Another helper: detect if the filename is a ZIP or XRS file
+    static bool IsArchive(const wxString& filename);
+#endif // wxUSE_FILESYSTEM
+
 private:
     long m_version;
 
diff --git a/src/xrc/xmlres.cpp b/src/xrc/xmlres.cpp
index 870363db17..12441c1320 100644
--- a/src/xrc/xmlres.cpp
+++ b/src/xrc/xmlres.cpp
@@ -84,6 +84,46 @@ wxXmlResource::~wxXmlResource()
 }
 
 
+/* static */
+wxString wxXmlResource::ConvertFileNameToURL(const wxString& filename)
+{
+    wxString fnd(filename);
+
+    // NB: as Load() and Unload() accept both filenames and URLs (should
+    //     probably be changed to filenames only, but embedded resources
+    //     currently rely on its ability to handle URLs - FIXME) we need to
+    //     determine whether found name is filename and not URL and this is the
+    //     fastest/simplest way to do it
+    if (wxFileName::FileExists(fnd))
+    {
+        // Make the name absolute filename, because the app may
+        // change working directory later:
+        wxFileName fn(fnd);
+        if (fn.IsRelative())
+        {
+            fn.MakeAbsolute();
+            fnd = fn.GetFullPath();
+        }
+#if wxUSE_FILESYSTEM
+        fnd = wxFileSystem::FileNameToURL(fnd);
+#endif
+    }
+
+    return fnd;
+}
+
+#if wxUSE_FILESYSTEM
+
+/* static */
+bool wxXmlResource::IsArchive(const wxString& filename)
+{
+    const wxString fnd = filename.Lower();
+
+    return fnd.Matches(wxT("*.zip")) || fnd.Matches(wxT("*.xrs"));
+}
+
+#endif // wxUSE_FILESYSTEM
+
 bool wxXmlResource::Load(const wxString& filemask)
 {
     wxString fnd;
@@ -105,34 +145,15 @@ bool wxXmlResource::Load(const wxString& filemask)
         fnd = filemask;
     while (!fnd.empty())
     {
-        // NB: Load() accepts both filenames and URLs (should probably be
-        //     changed to filenames only, but embedded resources currently
-        //     rely on its ability to handle URLs - FIXME). This check
-        //     serves as a quick way to determine whether found name is
-        //     filename and not URL:
-        if (wxFileName::FileExists(fnd))
-        {
-            // Make the name absolute filename, because the app may
-            // change working directory later:
-            wxFileName fn(fnd);
-            if (fn.IsRelative())
-            {
-                fn.MakeAbsolute();
-                fnd = fn.GetFullPath();
-            }
-#if wxUSE_FILESYSTEM
-            fnd = wxFileSystem::FileNameToURL(fnd);
-#endif
-        }
+        fnd = ConvertFileNameToURL(fnd);
 
 #if wxUSE_FILESYSTEM
-        if (fnd.Lower().Matches(wxT("*.zip")) ||
-            fnd.Lower().Matches(wxT("*.xrs")))
+        if ( IsArchive(fnd) )
         {
             rt = rt && Load(fnd + wxT("#zip:*.xrc"));
         }
-        else
-#endif
+        else // a single resource URL
+#endif // wxUSE_FILESYSTEM
         {
             drec = new wxXmlResourceDataRecord;
             drec->File = fnd;
@@ -149,6 +170,46 @@ bool wxXmlResource::Load(const wxString& filemask)
     return rt && UpdateResources();
 }
 
+bool wxXmlResource::Unload(const wxString& filename)
+{
+    wxASSERT_MSG( !wxIsWild(filename),
+                    _T("wildcards not supported by wxXmlResource::Unload()") );
+
+    wxString fnd = ConvertFileNameToURL(filename);
+#if wxUSE_FILESYSTEM
+    const bool isArchive = IsArchive(fnd);
+    if ( isArchive )
+        fnd += _T("#zip:");
+#endif // wxUSE_FILESYSTEM
+
+    bool unloaded = false;
+    const size_t count = m_data.GetCount();
+    for ( size_t i = 0; i < count; i++ )
+    {
+#if wxUSE_FILESYSTEM
+        if ( isArchive )
+        {
+            if ( m_data[i].File.StartsWith(fnd) )
+                unloaded = true;
+            // don't break from the loop, we can have other matching files
+        }
+        else // a single resource URL
+#endif // wxUSE_FILESYSTEM
+        {
+            if ( m_data[i].File == fnd )
+            {
+                m_data.RemoveAt(i);
+                unloaded = true;
+
+                // no sense in continuing, there is only one file with this URL
+                break;
+            }
+        }
+    }
+
+    return unloaded;
+}
+
 
 IMPLEMENT_ABSTRACT_CLASS(wxXmlResourceHandler, wxObject)
 
-- 
2.45.2

