Add wxXmlResource::LoadObjectRecursively().

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
This commit is contained in:
Vadim Zeitlin
2009-09-14 23:22:00 +00:00
parent c9a199c6a6
commit af0ac990fc
7 changed files with 165 additions and 30 deletions

View File

@@ -413,6 +413,7 @@ All (GUI):
- wxPropertyGrid: added wxPG_NO_INTERNAL_BORDER, wxPG_EX_NO_TOOLBAR_DIVIDER - wxPropertyGrid: added wxPG_NO_INTERNAL_BORDER, wxPG_EX_NO_TOOLBAR_DIVIDER
and wxPG_EX_TOOLBAR_SEPARATOR styles for finer control over borders. and wxPG_EX_TOOLBAR_SEPARATOR styles for finer control over borders.
Borders around property grid are now native for consistency. Borders around property grid are now native for consistency.
- Added wxXmlResource::LoadObjectRecursively().
GTK: GTK:

View File

@@ -188,13 +188,40 @@ public:
// Load an object from the resource specifying both the resource name and // Load an object from the resource specifying both the resource name and
// the classname. This lets you load nonstandard container windows. // the classname. This lets you load nonstandard container windows.
wxObject *LoadObject(wxWindow *parent, const wxString& name, 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 // Load an object from the resource specifying both the resource name and
// the classname. This form lets you finish the creation of an existing // the classname. This form lets you finish the creation of an existing
// instance. // instance.
bool LoadObject(wxObject *instance, wxWindow *parent, const wxString& name, bool LoadObject(wxObject *instance,
const wxString& classname); 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. // Loads a bitmap resource from a file.
wxBitmap LoadBitmap(const wxString& name); wxBitmap LoadBitmap(const wxString& name);
@@ -309,7 +336,11 @@ protected:
// (Uses only 'handlerToUse' if != NULL) // (Uses only 'handlerToUse' if != NULL)
wxObject *CreateResFromNode(wxXmlNode *node, wxObject *parent, wxObject *CreateResFromNode(wxXmlNode *node, wxObject *parent,
wxObject *instance = NULL, 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 // Helper of Load() and Unload(): returns the URL corresponding to the
// given file if it's indeed a file, otherwise returns the original string // given file if it's indeed a file, otherwise returns the original string
@@ -326,6 +357,24 @@ private:
wxXmlResourceDataRecords& Data() { return *m_data; } wxXmlResourceDataRecords& Data() { return *m_data; }
const wxXmlResourceDataRecords& Data() const { 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: private:
long m_version; long m_version;

View File

@@ -286,6 +286,10 @@ public:
The first overload lets you load nonstandard container windows and returns 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 @NULL on failure. The second one lets you finish the creation of an existing
instance and returns @false on failure. 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, wxObject* LoadObject(wxWindow* parent, const wxString& name,
const wxString& classname); const wxString& classname);
@@ -294,6 +298,27 @@ public:
const wxString& classname); 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. Loads a panel. @a parent points to the parent window.
*/ */

View File

@@ -87,6 +87,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(XRCID("platform_property_tool_or_menuitem"), MyFrame::OnPlatformPropertyToolOrMenuCommand) EVT_MENU(XRCID("platform_property_tool_or_menuitem"), MyFrame::OnPlatformPropertyToolOrMenuCommand)
EVT_MENU(XRCID("art_provider_tool_or_menuitem"), MyFrame::OnArtProviderToolOrMenuCommand) EVT_MENU(XRCID("art_provider_tool_or_menuitem"), MyFrame::OnArtProviderToolOrMenuCommand)
EVT_MENU(XRCID("variable_expansion_tool_or_menuitem"), MyFrame::OnVariableExpansionToolOrMenuCommand) EVT_MENU(XRCID("variable_expansion_tool_or_menuitem"), MyFrame::OnVariableExpansionToolOrMenuCommand)
EVT_MENU(XRCID("recursive_load"), MyFrame::OnRecursiveLoad)
EVT_MENU(wxID_ABOUT, MyFrame::OnAboutToolOrMenuCommand) EVT_MENU(wxID_ABOUT, MyFrame::OnAboutToolOrMenuCommand)
END_EVENT_TABLE() END_EVENT_TABLE()
@@ -311,6 +312,47 @@ void MyFrame::OnVariableExpansionToolOrMenuCommand(wxCommandEvent& WXUNUSED(even
dlg.ShowModal(); 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)) void MyFrame::OnAboutToolOrMenuCommand(wxCommandEvent& WXUNUSED(event))
{ {

View File

@@ -48,6 +48,7 @@ private:
void OnPlatformPropertyToolOrMenuCommand(wxCommandEvent& event); void OnPlatformPropertyToolOrMenuCommand(wxCommandEvent& event);
void OnArtProviderToolOrMenuCommand(wxCommandEvent& event); void OnArtProviderToolOrMenuCommand(wxCommandEvent& event);
void OnVariableExpansionToolOrMenuCommand(wxCommandEvent& event); void OnVariableExpansionToolOrMenuCommand(wxCommandEvent& event);
void OnRecursiveLoad(wxCommandEvent& event);
void OnAnimationCtrlPlay(wxCommandEvent& event); void OnAnimationCtrlPlay(wxCommandEvent& event);
// Any class wishing to process wxWidgets events must use this macro // Any class wishing to process wxWidgets events must use this macro

View File

@@ -69,6 +69,10 @@
<bitmap>variable.xpm</bitmap> <bitmap>variable.xpm</bitmap>
<help>Replace variables in the XRC file at runtime</help> <help>Replace variables in the XRC file at runtime</help>
</object> </object>
<object class="wxMenuItem" name="recursive_load">
<label>_Recursive Load</label>
<help>Show how an individual control can be loaded</help>
</object>
</object> </object>
<object class="wxMenu" name="help_menu"> <object class="wxMenu" name="help_menu">
<label>_Help</label> <label>_Help</label>

View 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()); dest.SetContent(overwriteWith.GetContent());
} }
wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent, wxObject *
wxObject *instance, wxXmlResource::DoCreateResFromNode(wxXmlNode& node,
wxXmlResourceHandler *handlerToUse) wxObject *parent,
wxObject *instance,
wxXmlResourceHandler *handlerToUse)
{ {
if (node == NULL) return NULL;
// handling of referenced resource // 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); wxXmlNode* refNode = FindResource(refName, wxEmptyString, true);
if ( !refNode ) if ( !refNode )
{ {
ReportError ReportError
( (
node, &node,
wxString::Format wxString::Format
( (
"referenced object node with ref=\"%s\" not found", "referenced object node with ref=\"%s\" not found",
@@ -845,14 +858,14 @@ wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
return NULL; return NULL;
} }
if ( !node->GetChildren() ) if ( !node.GetChildren() )
{ {
// In the typical, simple case, <object_ref> is used to link // In the typical, simple case, <object_ref> is used to link
// to another node and doesn't have any content of its own that // to another node and doesn't have any content of its own that
// would overwrite linked object's properties. In this case, // would overwrite linked object's properties. In this case,
// we can simply create the resource from linked node. // we can simply create the resource from linked node.
return CreateResFromNode(refNode, parent, instance); return DoCreateResFromNode(*refNode, parent, instance);
} }
else else
{ {
@@ -862,42 +875,42 @@ wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
// load the resource from result of the merge. // load the resource from result of the merge.
wxXmlNode copy(*refNode); wxXmlNode copy(*refNode);
MergeNodesOver(copy, *node, GetFileNameFromNode(node, Data())); MergeNodesOver(copy, node, GetFileNameFromNode(&node, Data()));
// remember referenced object's file, see GetFileNameFromNode() // remember referenced object's file, see GetFileNameFromNode()
copy.AddAttribute(ATTR_INPUT_FILENAME, copy.AddAttribute(ATTR_INPUT_FILENAME,
GetFileNameFromNode(refNode, Data())); GetFileNameFromNode(refNode, Data()));
return CreateResFromNode(&copy, parent, instance); return DoCreateResFromNode(copy, parent, instance);
} }
} }
if (handlerToUse) 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(); for ( wxVector<wxXmlResourceHandler*>::iterator h = m_handlers.begin();
h != m_handlers.end(); ++h ) h != m_handlers.end(); ++h )
{ {
wxXmlResourceHandler *handler = *h; wxXmlResourceHandler *handler = *h;
if (handler->CanHandle(node)) if (handler->CanHandle(&node))
return handler->CreateResource(node, parent, instance); return handler->CreateResource(&node, parent, instance);
} }
} }
ReportError ReportError
( (
node, &node,
wxString::Format wxString::Format
( (
"no handler found for XML node \"%s\" (class \"%s\")", "no handler found for XML node \"%s\" (class \"%s\")",
node->GetName(), node.GetName(),
node->GetAttribute("class", wxEmptyString) node.GetAttribute("class", wxEmptyString)
) )
); );
return NULL; return NULL;
@@ -1883,8 +1896,8 @@ void wxXmlResourceHandler::CreateChildren(wxObject *parent, bool this_hnd_only)
{ {
if ( IsObjectNode(n) ) if ( IsObjectNode(n) )
{ {
m_resource->CreateResFromNode(n, parent, NULL, m_resource->DoCreateResFromNode(*n, parent, NULL,
this_hnd_only ? this : NULL); this_hnd_only ? this : NULL);
} }
} }
} }