]> git.saurik.com Git - wxWidgets.git/commitdiff
Add wxXmlResource::LoadObjectRecursively().
authorVadim Zeitlin <vadim@wxwidgets.org>
Mon, 14 Sep 2009 23:22:00 +0000 (23:22 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Mon, 14 Sep 2009 23:22:00 +0000 (23:22 +0000)
These methods can be used to load objects from anywhere in the XRC resource
tree and not just from the top level.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61934 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
include/wx/xrc/xmlres.h
interface/wx/xrc/xmlres.h
samples/xrc/myframe.cpp
samples/xrc/myframe.h
samples/xrc/rc/menu.xrc
src/xrc/xmlres.cpp

index 24e241ff9d2ec1e2908fa24d80d0b9194efd6a39..9862a02889775a3bbb2dc894766fee0bbb0be202 100644 (file)
@@ -413,6 +413,7 @@ All (GUI):
 - wxPropertyGrid: added wxPG_NO_INTERNAL_BORDER, wxPG_EX_NO_TOOLBAR_DIVIDER
   and wxPG_EX_TOOLBAR_SEPARATOR styles for finer control over borders.
   Borders around property grid are now native for consistency.
+- Added wxXmlResource::LoadObjectRecursively().
 
 GTK:
 
index 97c1732d894e6b8aa74bb11e02c67552320cd8cd..bee65df5a4ec745f567390abe4e9ffc7241f6b83 100644 (file)
@@ -188,13 +188,40 @@ public:
     // Load an object from the resource specifying both the resource name and
     // the classname.  This lets you load nonstandard container windows.
     wxObject *LoadObject(wxWindow *parent, const wxString& name,
-                         const wxString& classname);
+                         const wxString& classname)
+    {
+        return DoLoadObject(parent, name, classname, false /* !recursive */);
+    }
 
     // Load an object from the resource specifying both the resource name and
     // the classname.  This form lets you finish the creation of an existing
     // instance.
-    bool LoadObject(wxObject *instance, wxWindow *parent, const wxString& name,
-                    const wxString& classname);
+    bool LoadObject(wxObject *instance,
+                    wxWindow *parent,
+                    const wxString& name,
+                    const wxString& classname)
+    {
+        return DoLoadObject(instance, parent, name, classname, false);
+    }
+
+    // These versions of LoadObject() look for the object with the given name
+    // recursively (breadth first) and can be used to instantiate an individual
+    // control defined anywhere in an XRC file. No check is done that the name
+    // is unique, it's up to the caller to ensure this.
+    wxObject *LoadObjectRecursively(wxWindow *parent,
+                                    const wxString& name,
+                                    const wxString& classname)
+    {
+        return DoLoadObject(parent, name, classname, true /* recursive */);
+    }
+
+    bool LoadObjectRecursively(wxObject *instance,
+                               wxWindow *parent,
+                               const wxString& name,
+                               const wxString& classname)
+    {
+        return DoLoadObject(instance, parent, name, classname, true);
+    }
 
     // Loads a bitmap resource from a file.
     wxBitmap LoadBitmap(const wxString& name);
@@ -309,7 +336,11 @@ protected:
     // (Uses only 'handlerToUse' if != NULL)
     wxObject *CreateResFromNode(wxXmlNode *node, wxObject *parent,
                                 wxObject *instance = NULL,
-                                wxXmlResourceHandler *handlerToUse = NULL);
+                                wxXmlResourceHandler *handlerToUse = NULL)
+    {
+        return node ? DoCreateResFromNode(*node, parent, instance, 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
@@ -326,6 +357,24 @@ private:
     wxXmlResourceDataRecords& Data() { return *m_data; }
     const wxXmlResourceDataRecords& Data() const { return *m_data; }
 
+    // the real implementation of CreateResFromNode(): this should be only
+    // called if node is non-NULL
+    wxObject *DoCreateResFromNode(wxXmlNode& node,
+                                  wxObject *parent,
+                                  wxObject *instance,
+                                  wxXmlResourceHandler *handlerToUse = NULL);
+
+    // common part of LoadObject() and LoadObjectRecursively()
+    wxObject *DoLoadObject(wxWindow *parent,
+                           const wxString& name,
+                           const wxString& classname,
+                           bool recursive);
+    bool DoLoadObject(wxObject *instance,
+                      wxWindow *parent,
+                      const wxString& name,
+                      const wxString& classname,
+                      bool recursive);
+
 private:
     long m_version;
 
index eba741549b0682e85e870cdc942eade99973c29c..a906d188c61f3882375363d64d69b0adc2919436 100644 (file)
@@ -286,6 +286,10 @@ public:
         The first overload lets you load nonstandard container windows and returns
         @NULL on failure. The second one lets you finish the creation of an existing
         instance and returns @false on failure.
+
+        In either case, only the resources defined at the top level of XRC
+        files can be loaded by this function, use LoadObjectRecursively() if
+        you need to load an object defined deeper in the hierarchy.
     */
     wxObject* LoadObject(wxWindow* parent, const wxString& name,
                          const wxString& classname);
@@ -294,6 +298,27 @@ public:
                     const wxString& classname);
     //@}
 
+    //@{
+    /**
+        Load an object from anywhere in the resource tree.
+
+        These methods are similar to LoadObject() but may be used to load an
+        object from anywhere in the resource tree and not only the top level.
+        Note that you will very rarely need to do this as in normal use the
+        entire container window (defined at the top level) is loaded and not
+        its individual children but this method can be useful in some
+        particular situations.
+
+        @since 2.9.1
+    */
+    wxObject* LoadObjectRecursively(wxWindow* parent,
+                                    const wxString& name,
+                                    const wxString& classname);
+    bool LoadObjectRecursively(wxObject* instance, wxWindow* parent,
+                    const wxString& name,
+                    const wxString& classname);
+    //@}
+
     /**
         Loads a panel. @a parent points to the parent window.
     */
index 50797d3a910ac2036674d387174c77f33826843a..0e8e1f604923fc49c846fc8326b6d035d999b6a4 100644 (file)
@@ -87,6 +87,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_MENU(XRCID("platform_property_tool_or_menuitem"), MyFrame::OnPlatformPropertyToolOrMenuCommand)
     EVT_MENU(XRCID("art_provider_tool_or_menuitem"), MyFrame::OnArtProviderToolOrMenuCommand)
     EVT_MENU(XRCID("variable_expansion_tool_or_menuitem"), MyFrame::OnVariableExpansionToolOrMenuCommand)
+    EVT_MENU(XRCID("recursive_load"), MyFrame::OnRecursiveLoad)
     EVT_MENU(wxID_ABOUT, MyFrame::OnAboutToolOrMenuCommand)
 END_EVENT_TABLE()
 
@@ -311,6 +312,47 @@ void MyFrame::OnVariableExpansionToolOrMenuCommand(wxCommandEvent& WXUNUSED(even
     dlg.ShowModal();
 }
 
+void MyFrame::OnRecursiveLoad(wxCommandEvent& WXUNUSED(event))
+{
+    // this dialog is created manually to show how you can inject a single
+    // control from XRC into an existing dialog
+    //
+    // this is a slightly contrived example, please keep in mind that it's done
+    // only to demonstrate LoadObjectRecursively() in action and is not the
+    // recommended to do this
+    wxDialog dlg(NULL, wxID_ANY, "Recursive Load Example",
+                 wxDefaultPosition, wxDefaultSize,
+                 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
+    wxSizer * const sizer = new wxBoxSizer(wxVERTICAL);
+    sizer->Add
+    (
+        new wxStaticText
+        (
+            &dlg,
+            wxID_ANY,
+            "The entire tree book control below is loaded from XRC"
+        ),
+        wxSizerFlags().Expand().Border()
+    );
+
+    sizer->Add
+    (
+        static_cast<wxWindow *>
+        (
+            // notice that controls_treebook is defined inside a notebook page
+            // inside a dialog defined in controls.xrc and so LoadObject()
+            // wouldn't find it -- but LoadObjectRecursively() does
+            wxXmlResource::Get()->
+                LoadObjectRecursively(&dlg, "controls_treebook", "wxTreebook")
+        ),
+        wxSizerFlags(1).Expand().Border()
+    );
+
+    dlg.SetSizer(sizer);
+    dlg.SetClientSize(400, 200);
+
+    dlg.ShowModal();
+}
 
 void MyFrame::OnAboutToolOrMenuCommand(wxCommandEvent& WXUNUSED(event))
 {
index c9f4ac97619e2245b1ffd70df18a2ed6331caa61..9701213ac8b998153fb58ac7e52d93a774d36a4b 100644 (file)
@@ -48,6 +48,7 @@ private:
     void OnPlatformPropertyToolOrMenuCommand(wxCommandEvent& event);
     void OnArtProviderToolOrMenuCommand(wxCommandEvent& event);
     void OnVariableExpansionToolOrMenuCommand(wxCommandEvent& event);
+    void OnRecursiveLoad(wxCommandEvent& event);
     void OnAnimationCtrlPlay(wxCommandEvent& event);
 
     // Any class wishing to process wxWidgets events must use this macro
index 91409e5c21537d9394d45102f8b6cfb091b04d5f..d60980dcf58adaead63d394c5fe8177030b2640a 100644 (file)
             <bitmap>variable.xpm</bitmap>
             <help>Replace variables in the XRC file at runtime</help>
         </object>        
+        <object class="wxMenuItem" name="recursive_load">
+            <label>_Recursive Load</label>
+            <help>Show how an individual control can be loaded</help>
+        </object>
     </object>    
     <object class="wxMenu" name="help_menu">
         <label>_Help</label>
index 94064a2cfc867e71fc20ac6f0615985abb36f383..dac420862eca800c7b0ddb52410c4b5f2a0ee549 100644 (file)
@@ -431,14 +431,27 @@ wxIcon wxXmlResource::LoadIcon(const wxString& name)
 }
 
 
-wxObject *wxXmlResource::LoadObject(wxWindow *parent, const wxString& name, const wxString& classname)
+wxObject *
+wxXmlResource::DoLoadObject(wxWindow *parent,
+                            const wxString& name,
+                            const wxString& classname,
+                            bool recursive)
 {
-    return CreateResFromNode(FindResource(name, classname), parent, NULL);
+    wxXmlNode * const node = FindResource(name, classname, recursive);
+
+    return node ? DoCreateResFromNode(*node, parent, NULL) : NULL;
 }
 
-bool wxXmlResource::LoadObject(wxObject *instance, wxWindow *parent, const wxString& name, const wxString& classname)
+bool
+wxXmlResource::DoLoadObject(wxObject *instance,
+                            wxWindow *parent,
+                            const wxString& name,
+                            const wxString& classname,
+                            bool recursive)
 {
-    return CreateResFromNode(FindResource(name, classname), parent, instance) != NULL;
+    wxXmlNode * const node = FindResource(name, classname, recursive);
+
+    return node && DoCreateResFromNode(*node, parent, instance) != NULL;
 }
 
 
@@ -819,23 +832,23 @@ static void MergeNodesOver(wxXmlNode& dest, wxXmlNode& overwriteWith,
          dest.SetContent(overwriteWith.GetContent());
 }
 
-wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
-                                           wxObject *instance,
-                                           wxXmlResourceHandler *handlerToUse)
+wxObject *
+wxXmlResource::DoCreateResFromNode(wxXmlNode& node,
+                                   wxObject *parent,
+                                   wxObject *instance,
+                                   wxXmlResourceHandler *handlerToUse)
 {
-    if (node == NULL) return NULL;
-
     // handling of referenced resource
-    if ( node->GetName() == wxT("object_ref") )
+    if ( node.GetName() == wxT("object_ref") )
     {
-        wxString refName = node->GetAttribute(wxT("ref"), wxEmptyString);
+        wxString refName = node.GetAttribute(wxT("ref"), wxEmptyString);
         wxXmlNode* refNode = FindResource(refName, wxEmptyString, true);
 
         if ( !refNode )
         {
             ReportError
             (
-                node,
+                &node,
                 wxString::Format
                 (
                     "referenced object node with ref=\"%s\" not found",
@@ -845,14 +858,14 @@ wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
             return NULL;
         }
 
-        if ( !node->GetChildren() )
+        if ( !node.GetChildren() )
         {
             // In the typical, simple case, <object_ref> is used to link
             // to another node and doesn't have any content of its own that
             // would overwrite linked object's properties. In this case,
             // we can simply create the resource from linked node.
 
-            return CreateResFromNode(refNode, parent, instance);
+            return DoCreateResFromNode(*refNode, parent, instance);
         }
         else
         {
@@ -862,42 +875,42 @@ wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
             // load the resource from result of the merge.
 
             wxXmlNode copy(*refNode);
-            MergeNodesOver(copy, *node, GetFileNameFromNode(node, Data()));
+            MergeNodesOver(copy, node, GetFileNameFromNode(&node, Data()));
 
             // remember referenced object's file, see GetFileNameFromNode()
             copy.AddAttribute(ATTR_INPUT_FILENAME,
                               GetFileNameFromNode(refNode, Data()));
 
-            return CreateResFromNode(&copy, parent, instance);
+            return DoCreateResFromNode(copy, parent, instance);
         }
     }
 
     if (handlerToUse)
     {
-        if (handlerToUse->CanHandle(node))
+        if (handlerToUse->CanHandle(&node))
         {
-            return handlerToUse->CreateResource(node, parent, instance);
+            return handlerToUse->CreateResource(&node, parent, instance);
         }
     }
-    else if (node->GetName() == wxT("object"))
+    else if (node.GetName() == wxT("object"))
     {
         for ( wxVector<wxXmlResourceHandler*>::iterator h = m_handlers.begin();
               h != m_handlers.end(); ++h )
         {
             wxXmlResourceHandler *handler = *h;
-            if (handler->CanHandle(node))
-                return handler->CreateResource(node, parent, instance);
+            if (handler->CanHandle(&node))
+                return handler->CreateResource(&node, parent, instance);
         }
     }
 
     ReportError
     (
-        node,
+        &node,
         wxString::Format
         (
             "no handler found for XML node \"%s\" (class \"%s\")",
-            node->GetName(),
-            node->GetAttribute("class", wxEmptyString)
+            node.GetName(),
+            node.GetAttribute("class", wxEmptyString)
         )
     );
     return NULL;
@@ -1883,8 +1896,8 @@ void wxXmlResourceHandler::CreateChildren(wxObject *parent, bool this_hnd_only)
     {
         if ( IsObjectNode(n) )
         {
-            m_resource->CreateResFromNode(n, parent, NULL,
-                                          this_hnd_only ? this : NULL);
+            m_resource->DoCreateResFromNode(*n, parent, NULL,
+                                            this_hnd_only ? this : NULL);
         }
     }
 }