Add support for id ranges to XRC.

Allow to declare ranges of consecutive IDs in XRC by using the "id[n]" syntax.
Show this functionality in the xrc sample and test it in the new unit test.

Also show and test the "object reference" XRC functionality.

Closes #11431.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@66059 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2010-11-07 14:00:59 +00:00
parent 1f6ea93556
commit 0526c8cc07
37 changed files with 1671 additions and 23 deletions

View File

@ -424,6 +424,7 @@ All (GUI):
- Fix display of right aligned columns in wxGenericListCtrl (jl).
- Restore text drag-and-drop in wxSTC broken by Scintilla 2 update (Jens Lody).
- Improve wxGTK print/page setup dialog (rafravago).
- Add support for id ranges to XRC (David Hart).
- Added wxToolbook XRC handler (Andrea Zanellato).
- Added wxDocManager::FindTemplate() (troelsk).
- Return bool, not void, from wxImage::ConvertAlphaToMask() (troelsk).

View File

@ -31,6 +31,7 @@ Table of contents:
- @ref overview_xrcformat_sizers
- @ref overview_xrcformat_other_objects
- @ref overview_xrcformat_platform
- @ref overview_xrcformat_idranges
- @ref overview_xrcformat_extending
- @ref overview_xrcformat_extending_subclass
- @ref overview_xrcformat_extending_unknown
@ -2060,6 +2061,64 @@ Examples:
@section overview_xrcformat_idranges ID Ranges
Usually you won't care what value the XRCID macro returns for the ID of an
object. Sometimes though it is convenient to have a range of IDs that are
guaranteed to be consecutive. An example of this would be connecting a group of
similar controls to the same event handler.
The following XRC fragment 'declares' an ID range called @em foo and another
called @em bar; each with some items.
@code
<object class="wxButton" name="foo[start]">
<object class="wxButton" name="foo[end]">
<object class="wxButton" name="foo[2]">
...
<object class="wxButton" name="bar[0]">
<object class="wxButton" name="bar[2]">
<object class="wxButton" name="bar[1]">
...
<ids-range name="foo" />
<ids-range name="bar" size="30" start="10000" />
@endcode
For the range foo, no @em size or @em start parameters were given, so the size
will be calculated from the number of range items, and IDs allocated by
wxWindow::NewControlId (so they'll be negative). Range bar asked for a size of
30, so this will be its minimum size: should it have more items, the range will
automatically expand to fit them. It specified a start ID of 10000, so
XRCID("bar[0]") will be 10000, XRCID("bar[1]") 10001 etc. Note that if you
choose to supply a start value it must be positive, and it's your
responsibility to avoid clashes.
For every ID range, the first item can be referenced either as
<em>rangename</em>[0] or <em>rangename</em>[start]. Similarly
<em>rangename</em>[end] is the last item. Using [start] and [end] is more
descriptive in e.g. a Bind() event range or a @em for loop, and they don't have
to be altered whenever the number of items changes.
Whether a range has positive or negative IDs, [start] is always a smaller
number than [end]; so code like this works as expected:
@code
for (int n=XRCID("foo[start]"); n < XRCID("foo[end]"); ++n)
...
@endcode
ID ranges can be seen in action in the <em>objref</em> dialog section of the
@sample{xrc}.
@note
@li All the items in an ID range must be contained in the same XRC file.
@li You can't use an ID range in a situation where static initialisation
occurs; in particular, they won't work as expected in an event table. This is
because the event table's IDs are set to their integer values before the XRC
file is loaded, and aren't subsequently altered when the XRCID value changes.
@since 2.9.2
@section overview_xrcformat_extending Extending the XRC Format
The XRC format is designed to be extensible and allows specifying and loading

View File

@ -391,6 +391,8 @@ private:
friend class wxXmlResourceHandler;
friend class wxXmlResourceModule;
friend class wxIdRangeManager;
friend class wxIdRange;
static wxXmlSubclassFactories *ms_subclassFactories;

View File

@ -43,7 +43,7 @@ wx_top_builddir = @wx_top_builddir@
DESTDIR =
WX_RELEASE = 2.9
WX_VERSION = $(WX_RELEASE).1
WX_VERSION = $(WX_RELEASE).2
LIBDIRNAME = $(wx_top_builddir)/lib
XRCDEMO_CXXFLAGS = -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) \
$(__EXCEPTIONS_DEFINE_p) $(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) \
@ -55,7 +55,8 @@ XRCDEMO_OBJECTS = \
xrcdemo_xrcdemo.o \
xrcdemo_myframe.o \
xrcdemo_derivdlg.o \
xrcdemo_custclas.o
xrcdemo_custclas.o \
xrcdemo_objrefdlg.o
### Conditionally set variables: ###
@ -195,7 +196,7 @@ xrcdemo$(EXEEXT): $(XRCDEMO_OBJECTS) $(__xrcdemo___win32rc)
data:
@mkdir -p ./rc
@for f in artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm; do \
@for f in artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm objref.xrc objrefdlg.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm; do \
if test ! -f ./rc/$$f -a ! -d ./rc/$$f ; \
then x=yep ; \
else x=`find $(srcdir)/rc/$$f -newer ./rc/$$f -print` ; \
@ -220,6 +221,9 @@ xrcdemo_derivdlg.o: $(srcdir)/derivdlg.cpp
xrcdemo_custclas.o: $(srcdir)/custclas.cpp
$(CXXC) -c -o $@ $(XRCDEMO_CXXFLAGS) $(srcdir)/custclas.cpp
xrcdemo_objrefdlg.o: $(srcdir)/objrefdlg.cpp
$(CXXC) -c -o $@ $(XRCDEMO_CXXFLAGS) $(srcdir)/objrefdlg.cpp
# Include dependency info, if present:
@IF_GNU_MAKE@-include ./.deps/*.d

View File

@ -1,5 +1,5 @@
//-----------------------------------------------------------------------------
// Name: xmldemo.cpp
// Name: derivdlg.h
// Purpose: XML resources sample: A derived dialog
// Author: Robert O'Connor (rob@medicalmnemonics.com), Vaclav Slavik
// RCS-ID: $Id$

View File

@ -39,7 +39,8 @@ XRCDEMO_OBJECTS = \
$(OBJS)\xrcdemo_xrcdemo.obj \
$(OBJS)\xrcdemo_myframe.obj \
$(OBJS)\xrcdemo_derivdlg.obj \
$(OBJS)\xrcdemo_custclas.obj
$(OBJS)\xrcdemo_custclas.obj \
$(OBJS)\xrcdemo_objrefdlg.obj
### Conditionally set variables: ###
@ -255,7 +256,7 @@ $(OBJS)\xrcdemo.exe: $(XRCDEMO_OBJECTS) $(OBJS)\xrcdemo_sample.res
data:
if not exist $(OBJS)\rc mkdir $(OBJS)\rc
for %f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%f copy .\rc\%f $(OBJS)\rc
for %f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm objref.xrc objrefdlg.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%f copy .\rc\%f $(OBJS)\rc
$(OBJS)\xrcdemo_sample.res: .\..\..\samples\sample.rc
brcc32 -32 -r -fo$@ -i$(BCCDIR)\include -d__WXMSW__ $(__WXUNIV_DEFINE_p_1) $(__DEBUG_DEFINE_p_1) $(__NDEBUG_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) $(__UNICODE_DEFINE_p_1) $(__MSLU_DEFINE_p_1) -i$(SETUPHDIR) -i.\..\..\include $(____CAIRO_INCLUDEDIR_FILENAMES_1_p) -i. $(__DLLFLAG_p_1) -i.\..\..\samples -dNOPCH .\..\..\samples\sample.rc
@ -272,3 +273,5 @@ $(OBJS)\xrcdemo_derivdlg.obj: .\derivdlg.cpp
$(OBJS)\xrcdemo_custclas.obj: .\custclas.cpp
$(CXX) -q -c -P -o$@ $(XRCDEMO_CXXFLAGS) .\custclas.cpp
$(OBJS)\xrcdemo_objrefdlg.obj: .\objrefdlg.cpp
$(CXX) -q -c -P -o$@ $(XRCDEMO_CXXFLAGS) .\objrefdlg.cpp

View File

@ -33,7 +33,8 @@ XRCDEMO_OBJECTS = \
$(OBJS)\xrcdemo_xrcdemo.o \
$(OBJS)\xrcdemo_myframe.o \
$(OBJS)\xrcdemo_derivdlg.o \
$(OBJS)\xrcdemo_custclas.o
$(OBJS)\xrcdemo_custclas.o \
$(OBJS)\xrcdemo_objrefdlg.o
### Conditionally set variables: ###
@ -242,7 +243,7 @@ $(OBJS)\xrcdemo.exe: $(XRCDEMO_OBJECTS) $(OBJS)\xrcdemo_sample_rc.o
data:
if not exist $(OBJS)\rc mkdir $(OBJS)\rc
for %%f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%%f copy .\rc\%%f $(OBJS)\rc
for %%f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm objref.xrc objrefdlg.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%%f copy .\rc\%%f $(OBJS)\rc
$(OBJS)\xrcdemo_sample_rc.o: ./../../samples/sample.rc
windres --use-temp-file -i$< -o$@ --define __WXMSW__ $(__WXUNIV_DEFINE_p_1) $(__DEBUG_DEFINE_p_1) $(__NDEBUG_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) $(__UNICODE_DEFINE_p_1) $(__MSLU_DEFINE_p_1) --include-dir $(SETUPHDIR) --include-dir ./../../include $(__CAIRO_INCLUDEDIR_p) --include-dir . $(__DLLFLAG_p_1) --include-dir ./../../samples --define NOPCH
@ -259,6 +260,9 @@ $(OBJS)\xrcdemo_derivdlg.o: ./derivdlg.cpp
$(OBJS)\xrcdemo_custclas.o: ./custclas.cpp
$(CXX) -c -o $@ $(XRCDEMO_CXXFLAGS) $(CPPDEPS) $<
$(OBJS)\xrcdemo_objrefdlg.o: ./objrefdlg.cpp
$(CXX) -c -o $@ $(XRCDEMO_CXXFLAGS) $(CPPDEPS) $<
.PHONY: all clean data

View File

@ -56,7 +56,8 @@ XRCDEMO_OBJECTS = \
xrcdemo_xrcdemo.o \
xrcdemo_myframe.o \
xrcdemo_derivdlg.o \
xrcdemo_custclas.o
xrcdemo_custclas.o \
xrcdemo_objrefdlg.o
### Conditionally set variables: ###
@ -105,6 +106,9 @@ xrcdemo_derivdlg.o: ./derivdlg.cpp
xrcdemo_custclas.o: ./custclas.cpp
$(CXX) -c -o $@ $(XRCDEMO_CXXFLAGS) $(CPPDEPS) $<
xrcdemo_objrefdlg.o: ./objrefdlg.cpp
$(CXX) -c -o $@ $(XRCDEMO_CXXFLAGS) $(CPPDEPS) $<
.PHONY: all install uninstall clean

View File

@ -33,7 +33,8 @@ XRCDEMO_OBJECTS = \
$(OBJS)\xrcdemo_xrcdemo.obj \
$(OBJS)\xrcdemo_myframe.obj \
$(OBJS)\xrcdemo_derivdlg.obj \
$(OBJS)\xrcdemo_custclas.obj
$(OBJS)\xrcdemo_custclas.obj \
$(OBJS)\xrcdemo_objrefdlg.obj
XRCDEMO_RESOURCES = \
$(OBJS)\xrcdemo_sample.res
@ -365,7 +366,7 @@ $(OBJS)\xrcdemo.exe: $(XRCDEMO_OBJECTS) $(OBJS)\xrcdemo_sample.res
data:
if not exist $(OBJS)\rc mkdir $(OBJS)\rc
for %f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%f copy .\rc\%f $(OBJS)\rc
for %f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm objref.xrc objrefdlg.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%f copy .\rc\%f $(OBJS)\rc
$(OBJS)\xrcdemo_sample.res: .\..\..\samples\sample.rc
rc /fo$@ /d WIN32 $(____DEBUGRUNTIME_3_p_1) $(__NO_VC_CRTDBG_p_1) /d __WXMSW__ $(__WXUNIV_DEFINE_p_1) $(__DEBUG_DEFINE_p_1) $(__NDEBUG_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) $(__UNICODE_DEFINE_p_1) $(__MSLU_DEFINE_p_1) /i $(SETUPHDIR) /i .\..\..\include $(____CAIRO_INCLUDEDIR_FILENAMES_1_p) /i . $(__DLLFLAG_p_1) /d _WINDOWS /i .\..\..\samples /d NOPCH .\..\..\samples\sample.rc
@ -382,3 +383,5 @@ $(OBJS)\xrcdemo_derivdlg.obj: .\derivdlg.cpp
$(OBJS)\xrcdemo_custclas.obj: .\custclas.cpp
$(CXX) /c /nologo /TP /Fo$@ $(XRCDEMO_CXXFLAGS) .\custclas.cpp
$(OBJS)\xrcdemo_objrefdlg.obj: .\objrefdlg.cpp
$(CXX) /c /nologo /TP /Fo$@ $(XRCDEMO_CXXFLAGS) .\objrefdlg.cpp

View File

@ -252,7 +252,8 @@ XRCDEMO_OBJECTS = &
$(OBJS)\xrcdemo_xrcdemo.obj &
$(OBJS)\xrcdemo_myframe.obj &
$(OBJS)\xrcdemo_derivdlg.obj &
$(OBJS)\xrcdemo_custclas.obj
$(OBJS)\xrcdemo_custclas.obj &
$(OBJS)\xrcdemo_objrefdlg.obj
all : $(OBJS)
@ -285,7 +286,7 @@ $(OBJS)\xrcdemo.exe : $(XRCDEMO_OBJECTS) $(OBJS)\xrcdemo_sample.res
data : .SYMBOLIC
if not exist $(OBJS)\rc mkdir $(OBJS)\rc
for %f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%f copy .\rc\%f $(OBJS)\rc
for %f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm objref.xrc objrefdlg.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%f copy .\rc\%f $(OBJS)\rc
$(OBJS)\xrcdemo_sample.res : .AUTODEPEND .\..\..\samples\sample.rc
wrc -q -ad -bt=nt -r -fo=$^@ -d__WXMSW__ $(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) $(__NDEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) $(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) $(__UNICODE_DEFINE_p) -i=$(SETUPHDIR) -i=.\..\..\include $(____CAIRO_INCLUDEDIR_FILENAMES) -i=. $(__DLLFLAG_p) -i=.\..\..\samples -dNOPCH $<
@ -302,3 +303,5 @@ $(OBJS)\xrcdemo_derivdlg.obj : .AUTODEPEND .\derivdlg.cpp
$(OBJS)\xrcdemo_custclas.obj : .AUTODEPEND .\custclas.cpp
$(CXX) -bt=nt -zq -fo=$^@ $(XRCDEMO_CXXFLAGS) $<
$(OBJS)\xrcdemo_objrefdlg.obj : .AUTODEPEND .\objrefdlg.cpp
$(CXX) -bt=nt -zq -fo=$^@ $(XRCDEMO_CXXFLAGS) $<

View File

@ -49,6 +49,8 @@
#include "derivdlg.h"
// Our custom class, for the custom class example.
#include "custclas.h"
// And our objref dialog, for the object reference and ID range example.
#include "objrefdlg.h"
// For functions to manipulate our wxTreeCtrl and wxListCtrl
#include "wx/treectrl.h"
#include "wx/listctrl.h"
@ -83,6 +85,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(XRCID("derived_tool_or_menuitem"), MyFrame::OnDerivedDialogToolOrMenuCommand)
EVT_MENU(XRCID("controls_tool_or_menuitem"), MyFrame::OnControlsToolOrMenuCommand)
EVT_MENU(XRCID("uncentered_tool_or_menuitem"), MyFrame::OnUncenteredToolOrMenuCommand)
EVT_MENU(XRCID("obj_ref_tool_or_menuitem"), MyFrame::OnObjRefToolOrMenuCommand)
EVT_MENU(XRCID("custom_class_tool_or_menuitem"), MyFrame::OnCustomClassToolOrMenuCommand)
EVT_MENU(XRCID("platform_property_tool_or_menuitem"), MyFrame::OnPlatformPropertyToolOrMenuCommand)
EVT_MENU(XRCID("art_provider_tool_or_menuitem"), MyFrame::OnArtProviderToolOrMenuCommand)
@ -268,6 +271,22 @@ void MyFrame::OnUncenteredToolOrMenuCommand(wxCommandEvent& WXUNUSED(event))
}
void MyFrame::OnObjRefToolOrMenuCommand(wxCommandEvent& WXUNUSED(event))
{
// The dialog redirects log messages, so save the old log target first
wxLog* oldlogtarget = wxLog::SetActiveTarget(NULL);
// Make an instance of the dialog
ObjrefDialog* objrefDialog = new ObjrefDialog(this);
// Show the instance of the dialog, modally.
objrefDialog->ShowModal();
objrefDialog->Destroy();
// Restore the old log target
delete wxLog::SetActiveTarget(oldlogtarget);
}
void MyFrame::OnCustomClassToolOrMenuCommand(wxCommandEvent& WXUNUSED(event))
{
wxDialog dlg;

View File

@ -44,6 +44,7 @@ private:
void OnDerivedDialogToolOrMenuCommand(wxCommandEvent& event);
void OnControlsToolOrMenuCommand(wxCommandEvent& event);
void OnUncenteredToolOrMenuCommand(wxCommandEvent& event);
void OnObjRefToolOrMenuCommand(wxCommandEvent& event);
void OnCustomClassToolOrMenuCommand(wxCommandEvent& event);
void OnPlatformPropertyToolOrMenuCommand(wxCommandEvent& event);
void OnArtProviderToolOrMenuCommand(wxCommandEvent& event);

290
samples/xrc/objrefdlg.cpp Normal file
View File

@ -0,0 +1,290 @@
//-----------------------------------------------------------------------------
// Name: objref.cpp
// Purpose: XML resources sample: Object references and ID ranges dialog
// Author: David Hart, Vaclav Slavik
// RCS-ID: $Id$
// Copyright: (c) Vaclav Slavik
// Licence: wxWindows licence
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Standard wxWidgets headers
//-----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// For all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
//-----------------------------------------------------------------------------
// Header of this .cpp file
//-----------------------------------------------------------------------------
#include "objrefdlg.h"
//-----------------------------------------------------------------------------
// Remaining headers: Needed wx headers, then wx/contrib headers, then application headers
//-----------------------------------------------------------------------------
#include "wx/xrc/xmlres.h" // XRC XML resouces
//-----------------------------------------------------------------------------
// Public members
//-----------------------------------------------------------------------------
ObjrefDialog::ObjrefDialog(wxWindow* parent)
{
wxXmlResource::Get()->LoadDialog(this, parent, wxT("objref_dialog"));
nb = XRCCTRL(*this, "objref_notebook", wxNotebook);
wxCHECK_RET(nb, "failed to find objref_notebook");
nb->Bind(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &ObjrefDialog::OnNotebookPageChanged, this);
iconspage_bound = false;
calcpage_bound = false;
}
ObjrefDialog::~ObjrefDialog()
{
// Select page 0. Otherwise if the Calc page were selected, when it's removed the Icons page is selected
// and sets the log target again in idle time, *after* myframe restores the old one!
nb->ChangeSelection(0);
}
//-----------------------------------------------------------------------------
// Private members (including the event handlers)
//-----------------------------------------------------------------------------
void ObjrefDialog::OnNotebookPageChanged( wxNotebookEvent &event )
{
switch(event.GetSelection())
{
case copy_page:
{
// This is a straight object reference to the first page
// so change the text programmatically
nb->SetPageText(copy_page, "Page 1 copy");
wxNotebookPage *page = nb->GetPage(copy_page);
wxTextCtrl *text = XRCCTRL(*page, "description_text", wxTextCtrl);
text->ChangeValue(
wxString("This is a duplicate of page 1, using an object reference. ")
+ wxString("It was created by this very simple xml:\n\n")
+ wxString("<object class=\"notebookpage\">\n\t<object_ref ref=\"page1\"/>\n")
+ wxString("\t<label>Page 1 copy</label>\n</object>")
+ wxString("\n\n(Then I'm cheating by inserting this text programmatically.)")
);
break;
}
case icons_page:
{
wxNotebookPage *page = nb->GetPage(icons_page);
if (!iconspage_bound)
{
iconspage_bound = true;
// We want to direct UpdateUI events for the ID range 'first_row' to OnUpdateUIFirst().
// We could achieve this using first_row[0] and first_row[2], but what if a fourth
// column were added? It's safer to use the 'typedefs' for the two ends of the range:
page->Bind(wxEVT_UPDATE_UI, &ObjrefDialog::OnUpdateUIFirst,
this, XRCID("first_row[start]"), XRCID("first_row[end]"));
// Similarly for the other two rows
page->Bind(wxEVT_UPDATE_UI, &ObjrefDialog::OnUpdateUISecond,
this, XRCID("second_row[start]"), XRCID("second_row[end]"));
page->Bind(wxEVT_UPDATE_UI, &ObjrefDialog::OnUpdateUIThird,
this, XRCID("third_row[start]"), XRCID("third_row[end]"));
}
text = XRCCTRL(*page, "log_text", wxTextCtrl);
if (text)
delete wxLog::SetActiveTarget(new wxLogTextCtrl(text));
break;
}
case calc_page:
{
wxNotebookPage *page = nb->GetPage(calc_page);
if (!calcpage_bound)
{
calcpage_bound = true;
// Bind the id ranges, using the [start] and [end] 'typedefs'
page->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ObjrefDialog::OnNumeralClick,
this, XRCID("digits[start]"), XRCID("digits[end]"));
page->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ObjrefDialog::OnOperatorClick,
this, XRCID("operators[start]"), XRCID("operators[end]"));
}
result_txt = XRCCTRL(*page, "result", wxTextCtrl);
text = XRCCTRL(*page, "log_text", wxTextCtrl);
if (text)
delete wxLog::SetActiveTarget(new wxLogTextCtrl(text));
ClearCalculator();
break;
}
default: return;
}
}
// There are undoubtedly simpler ways of doing all this, but we're demonstrating the use of ID ranges
void ObjrefDialog::OnUpdateUIFirst(wxUpdateUIEvent& event)
{
// The checkbox with the XRCID 'check[0]' controls this row of icons
wxCheckBox *chk = XRCCTRL(*(nb->GetPage(icons_page)), "check[0]", wxCheckBox);
if (chk)
event.Enable(chk->IsChecked());
// Let's create a log-window entry
static bool checked = true;
if (chk->IsChecked() != checked)
{
checked = chk->IsChecked();
wxLogMessage("Row one has been %s by check[0], XRCID = %i", checked ? "enabled" : "disabled", XRCID("check[0]"));
wxLogMessage("XRCIDs: first_row[start] = %i, first_row[0] = %i, first_row[1] = %i, first_row[2] = %i, first_row[end] = %i",
XRCID("first_row[start]"), XRCID("first_row[0]"), XRCID("first_row[1]"), XRCID("first_row[2]"), XRCID("first_row[end]"));
}
}
void ObjrefDialog::OnUpdateUISecond(wxUpdateUIEvent& event)
{
// The checkbox with the XRCID 'check[1]' controls this row of icons
wxCheckBox *chk = XRCCTRL(*(nb->GetPage(icons_page)), "check[1]", wxCheckBox);
if (chk)
event.Enable(chk->IsChecked());
// Let's create a log-window entry
static bool checked = true;
if (chk->IsChecked() != checked)
{
checked = chk->IsChecked();
wxLogMessage("Row two has been %s by check[1], XRCID = %i", checked ? "enabled" : "disabled", XRCID("check[1]"));
wxLogMessage("XRCIDs: second_row[start] = %i, second_row[0] = %i, second_row[1] = %i, second_row[2] = %i, second_row[end] = %i",
XRCID("second_row[start]"), XRCID("second_row[0]"), XRCID("second_row[1]"), XRCID("second_row[2]"), XRCID("second_row[end]"));
}
}
void ObjrefDialog::OnUpdateUIThird(wxUpdateUIEvent& event)
{
// The checkbox with the XRCID 'check[2]' controls this row of icons
wxCheckBox *chk = XRCCTRL(*(nb->GetPage(icons_page)), "check[2]", wxCheckBox);
if (chk)
event.Enable(chk->IsChecked());
// Let's create a log-window entry
static bool checked = true;
if (chk->IsChecked() != checked)
{
checked = chk->IsChecked();
wxLogMessage("Row three has been %s by check[2], XRCID = %i", checked ? "enabled" : "disabled", XRCID("check[2]"));
wxLogMessage("XRCIDs: third_row[start] = %i, third_row[0] = %i, third_row[1] = %i, third_row[2] = %i, third_row[end] = %i",
XRCID("third_row[start]"), XRCID("third_row[0]"), XRCID("third_row[1]"), XRCID("third_row[2]"), XRCID("third_row[end]"));
}
}
void ObjrefDialog::OnNumeralClick(wxCommandEvent& event)
{
// See how the id range simplifies determining which numeral was clicked
int digit = event.GetId() - XRCID("digits[start]");
char c = '0' + digit;
if (current==0 && previous==0)
{
// We're just starting a calculation, so get rid of the placeholder '0'
result_txt->Clear();
}
else if (operator_expected == true)
{
// If we've just finished one calculation, and now a digit is entered, clear
ClearCalculator();
result_txt->Clear();
}
(*result_txt) << c;
current = current*10 + digit;
wxLogMessage("You clicked digits[%c], XRCID %i", c, event.GetId());
}
void ObjrefDialog::OnOperatorClick(wxCommandEvent& event)
{
static const char symbols[] = "+-*/=";
operator_expected = false;
int ID = event.GetId() - XRCID("operators[start]");
// We carefully used "operators[end]" as the name of the Clear button
if (event.GetId() == XRCID("operators[end]"))
{
wxLogMessage("You clicked operators[%i], XRCID %i, 'Clear'", ID, event.GetId());
return ClearCalculator();
}
switch(ID)
{
case operator_plus:
case operator_minus:
case operator_multiply:
case operator_divide:
if (current!=0 || previous!=0)
{
// We're in the middle of a complex calculation, so do the first bit
Calculate();
}
curr_operator = (CalcOperator)ID;
break;
case operator_equals:
Calculate();
wxLogMessage("You clicked operators[%i], XRCID %i, giving a '%c'", ID, event.GetId(), symbols[ID]);
curr_operator = operator_equals;
// Flag that the next entry should be an operator, not a digit
operator_expected = true;
return;
}
(*result_txt) << ' ' << symbols[ID] << ' ';
wxLogMessage("You clicked operators[%i], XRCID %i, giving a '%c'", ID, event.GetId(), symbols[ID]);
}
void ObjrefDialog::Calculate()
{
switch(curr_operator)
{
case operator_plus:
previous += current; break;
case operator_minus:
previous -= current; break;
case operator_multiply:
previous *= current; break;
case operator_divide:
if (current!=0)
previous /= current;
break;
default: return;
}
curr_operator = operator_plus;
current = 0;
result_txt->Clear();
(*result_txt) << previous;
}
void ObjrefDialog::ClearCalculator()
{
current = previous = 0;
curr_operator = operator_plus;
operator_expected = false;
result_txt->ChangeValue("0");
}

64
samples/xrc/objrefdlg.h Normal file
View File

@ -0,0 +1,64 @@
//-----------------------------------------------------------------------------
// Name: objref.h
// Purpose: XML resources sample: Object references and ID ranges dialog
// Author: David Hart, Vaclav Slavik
// RCS-ID: $Id$
// Copyright: (c) Vaclav Slavik
// Licence: wxWindows licence
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Begin single inclusion of this .h file condition
//-----------------------------------------------------------------------------
#ifndef _OBJREFDLG_H_
#define _OBJREFDLG_H_
//-----------------------------------------------------------------------------
// Headers
//-----------------------------------------------------------------------------
#include "wx/dialog.h"
#include "wx/notebook.h"
//-----------------------------------------------------------------------------
// Class definition: ObjrefDialog
//-----------------------------------------------------------------------------
class ObjrefDialog : public wxDialog
{
public:
// Constructor.
ObjrefDialog( wxWindow* parent );
// Destructor.
~ObjrefDialog();
private:
enum PageNumbers { first_page, copy_page, icons_page, calc_page };
enum CalcOperator { operator_plus, operator_minus, operator_multiply, operator_divide, operator_equals };
void OnNotebookPageChanged( wxNotebookEvent &event );
void OnUpdateUIFirst(wxUpdateUIEvent& event);
void OnUpdateUISecond(wxUpdateUIEvent& event);
void OnUpdateUIThird(wxUpdateUIEvent& event);
void OnNumeralClick(wxCommandEvent& event);
void OnOperatorClick(wxCommandEvent& event);
void Calculate();
void ClearCalculator();
wxNotebook *nb;
wxTextCtrl *text;
wxTextCtrl *result_txt;
bool iconspage_bound;
bool calcpage_bound;
int current;
int previous;
bool operator_expected;
CalcOperator curr_operator;
};
#endif //_OBJREFDLG_H_

View File

@ -49,6 +49,11 @@
<object class="wxMenu" name="advanced_demos_menu">
<label>_Advanced</label>
<help>Advanced techniques with XRC</help>
<object class="wxMenuItem" name="obj_ref_tool_or_menuitem">
<label>_Object References Example</label>
<bitmap>objrefdlg.xpm</bitmap>
<help>Use of object references and event ranges</help>
</object>
<object class="wxMenuItem" name="custom_class_tool_or_menuitem">
<label>_Custom Class Example</label>
<bitmap>custclas.xpm</bitmap>

418
samples/xrc/rc/objref.xrc Normal file
View File

@ -0,0 +1,418 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<resource version="2.3.0.1" xmlns="http://www.wxwidgets.org/wxxrc">
<object class="wxDialog" name="objref_dialog">
<object class="wxFlexGridSizer">
<object class="sizeritem">
<object class="wxNotebook" name="objref_notebook">
<object class="notebookpage">
<object class="wxPanel" name="page1">
<object class="wxFlexGridSizer">
<object class="sizeritem">
<object class="wxTextCtrl" name="description_text">
<value>This dialog demonstrates the use of object references and ID arrays.\n\nAs you turn the pages of the notebook, you will notice that each has an identical section at the bottom. Instead of writing that section's xml several times, this is done just once, as a wxPanel named 'bottom__panel'. The panel is then added to each page's sizer by the single line: &lt;object__ref ref=&quot;bottom__panel&quot;/&gt;</value>
<style>wxTE_MULTILINE|wxTE_READONLY</style>
</object>
<option>1</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object_ref ref="bottom_panel"/>
<flag>wxEXPAND</flag>
</object>
<cols>1</cols>
<rows>0</rows>
<vgap>0</vgap>
<hgap>10</hgap>
<growablecols>0</growablecols>
<growablerows>0</growablerows>
<growablerows>1</growablerows>
</object>
</object>
<label>Page 1</label>
</object>
<object class="notebookpage">
<object_ref ref="page1"/>
<label>Page 1 copy</label>
</object>
<object class="notebookpage">
<object class="wxPanel" name="page2">
<object class="wxFlexGridSizer">
<object class="sizeritem">
<object class="wxTextCtrl" name="description_text">
<value>ID ranges are a way to simplify the management of several similar controls, especially their event-handling.\nAn ID range is declared by putting something like this into the XRC file:\n &lt;ids-range name=&quot;check&quot; size=&quot;3&quot; start=&quot;10000&quot; /&gt;\n'size' and 'start' being optional.\n\nIf you then give an item the name 'check[2]', it will be allocated that ID in the range.\n\nBy default the IDs in a range are negative, being assigned by wxWindow::NewControlId. If you wish, you can specify the start of the range; if so, the IDs *must* be positive (and it's your responsibility to avoid clashes, so start above wxID__HIGHEST).</value>
<style>wxTE_MULTILINE|wxTE_READONLY</style>
</object>
<option>1</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxBoxSizer">
<object class="spacer">
<option>1</option>
<flag>wxLEFT</flag>
<border>100</border>
</object>
<object class="sizeritem">
<object class="wxBoxSizer">
<object class="sizeritem">
<object class="wxStaticText">
<label>Uncheck to disable a row</label>
</object>
</object>
<object class="sizeritem">
<object_ref ref="checkboxes"/>
<flag>wxALIGN_CENTRE</flag>
</object>
<orient>wxVERTICAL</orient>
</object>
<flag>wxALIGN_CENTRE_VERTICAL</flag>
</object>
<orient>wxHORIZONTAL</orient>
<object class="spacer">
<size>50,-1</size>
</object>
<object class="sizeritem">
<object class="wxStaticBoxSizer">
<object class="sizeritem">
<object class="wxGridSizer">
<object class="sizeritem">
<object class="wxStaticBitmap" name="first_row[0]">
<bitmap>update.gif</bitmap>
</object>
</object>
<object class="sizeritem">
<object class="wxStaticBitmap" name="first_row[1]">
<bitmap>basicdlg.xpm</bitmap>
</object>
</object>
<object class="sizeritem">
<object class="wxStaticBitmap" name="first_row[2]">
<bitmap>controls.xpm</bitmap>
</object>
</object>
<object class="sizeritem">
<object class="wxStaticBitmap" name="second_row[0]">
<bitmap>custclas.xpm</bitmap>
</object>
</object>
<object class="sizeritem">
<object class="wxStaticBitmap" name="second_row[1]">
<bitmap>derivdlg.xpm</bitmap>
</object>
</object>
<object class="sizeritem">
<object class="wxStaticBitmap" name="second_row[2]">
<bitmap>platform.xpm</bitmap>
</object>
</object>
<object class="sizeritem">
<object class="wxStaticBitmap" name="third_row[0]">
<bitmap>objrefdlg.xpm</bitmap>
</object>
</object>
<object class="sizeritem">
<object class="wxStaticBitmap" name="third_row[1]">
<bitmap>uncenter.xpm</bitmap>
</object>
</object>
<object class="sizeritem">
<object class="wxStaticBitmap" name="third_row[2]">
<bitmap>variable.xpm</bitmap>
</object>
</object>
<rows>3</rows>
<vgap>7</vgap>
<hgap>7</hgap>
</object>
<flag>wxALL</flag>
<border>3</border>
</object>
<label>Icons</label>
<orient>wxVERTICAL</orient>
</object>
<flag>wxALIGN_CENTRE_VERTICAL</flag>
</object>
<object class="spacer">
<option>1</option>
<flag>wxLEFT</flag>
<border>100</border>
</object>
</object>
<flag>wxTOP|wxBOTTOM|wxEXPAND</flag>
<border>15</border>
</object>
<object class="sizeritem">
<object_ref ref="bottom_panel"/>
<option>1</option>
<flag>wxEXPAND</flag>
</object>
<cols>1</cols>
<rows>0</rows>
<vgap>0</vgap>
<hgap>10</hgap>
<growablecols>0</growablecols>
<growablerows>0</growablerows>
<growablerows>2</growablerows>
</object>
</object>
<label>Icons</label>
</object>
<object class="notebookpage">
<object class="wxPanel" name="page3">
<object class="wxFlexGridSizer">
<object class="sizeritem">
<object class="wxTextCtrl" name="description_text">
<value>This not very useful calculator demonstrates some features of ID ranges. One range is defined for the number keys, and another for the operators.\n\nIf you look at the .xrc file, you'll see that I wrote:\n &lt;ids-range name=&quot;digits&quot; size=&quot;8&quot;/&gt;\ncreating that range with a size of 8 (I must have forgotten to count my thumbs). The code will still work, though: the actual number of range items is counted when the file is loaded, and the range extended if necessary to accommodate them. However if the size is too big, it isn't truncated.\n\nAn ID range always has the special items defined: &lt;rangename&gt;[start] and &lt;rangename&gt;[end]. So, for the range 'digits', digits[start] == digits[0], and digits[end] == digits[9]. [end] will always refer to the end of the range, even if there's no object with that ID.\n\nThe digits of the calculator are named 'digits[0]' to 'digits[9]'. Adjacent range items are guaranteed to be assigned consecutive IDs, so code such as this will work as expected:\n for (int n=XRCID(&quot;digits[start]&quot;); n &lt; XRCID(&quot;digits[end]&quot;); ++n) { DoFoo(n); }\nor\n int index = event.GetId() - XRCID(&quot;digits[0]&quot;);</value>
<style>wxTE_MULTILINE|wxTE_READONLY</style>
</object>
<option>1</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxStaticBoxSizer">
<object class="sizeritem">
<object class="wxGridBagSizer">
<object class="sizeritem">
<object class="wxButton" name="digits[7]">
<label>7</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>0,0</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="digits[8]">
<label>8</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>0,1</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="digits[9]">
<label>9</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>0,2</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="operators[3]">
<label>/</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>0,3</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="digits[4]">
<label>4</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>1,0</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="digits[5]">
<label>5</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>1,1</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="digits[6]">
<label>6</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>1,2</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="operators[2]">
<label>X</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>1,3</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="digits[1]">
<label>1</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>2,0</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="digits[2]">
<label>2</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>2,1</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="digits[3]">
<label>3</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>2,2</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="operators[1]">
<label>-</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>2,3</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="digits[0]">
<label>0</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>3,0</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="operators[4]">
<label>=</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>3,1</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="operators[end]">
<label>Cl</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>3,2</cellpos>
</object>
<object class="sizeritem">
<object class="wxButton" name="operators[0]">
<label>+</label>
<style>wxBU_EXACTFIT</style>
</object>
<flag>wxEXPAND</flag>
<cellpos>3,3</cellpos>
</object>
<object class="sizeritem">
<object class="wxTextCtrl" name="result"/>
<flag>wxEXPAND</flag>
<cellpos>4,0</cellpos>
<cellspan>1,4</cellspan>
</object>
<vgap>5</vgap>
<hgap>5</hgap>
</object>
<flag>wxALL</flag>
<border>5</border>
</object>
<label>Calculator</label>
<orient>wxVERTICAL</orient>
</object>
<flag>wxTOP|wxALIGN_CENTRE_HORIZONTAL</flag>
<border>10</border>
</object>
<object class="sizeritem">
<object_ref ref="bottom_panel"/>
<option>1</option>
<flag>wxEXPAND</flag>
</object>
<cols>1</cols>
<rows>0</rows>
<vgap>0</vgap>
<hgap>10</hgap>
<growablecols>0</growablecols>
<growablerows>0</growablerows>
<growablerows>2</growablerows>
</object>
</object>
<label>Calc</label>
</object>
</object>
<option>1</option>
<flag>wxGROW|wxALIGN_CENTER_VERTICAL|wxALL</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxButton" name="wxID_OK">
<label>OK</label>
<default>1</default>
</object>
<flag>wxTOP|wxBOTTOM|wxALIGN_CENTRE</flag>
<border>20</border>
</object>
<cols>1</cols>
<rows>0</rows>
<vgap>0</vgap>
<hgap>0</hgap>
<growablecols>0</growablecols>
<growablerows>0</growablerows>
</object>
<title>Object References and ID Ranges Example</title>
<centered>1</centered>
<style>wxCAPTION|wxSYSTEM_MENU|wxRESIZE_BORDER</style>
<exstyle>wxDIALOG_EX_CONTEXTHELP</exstyle>
</object>
<object class="wxPanel" name="bottom_panel">
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<object class="wxStaticLine">
<style>wxLI_HORIZONTAL</style>
</object>
<flag>wxTOP|wxEXPAND</flag>
<border>20</border>
</object>
<object class="sizeritem">
<object class="wxStaticText">
<label>Log window:</label>
</object>
<flag>wxTOP</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxTextCtrl" name="log_text">
<size>-1,100</size>
<style>wxTE_MULTILINE</style>
</object>
<option>1</option>
<flag>wxEXPAND</flag>
</object>
</object>
</object>
<object class="wxPanel" name="checkboxes">
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<object class="wxCheckBox" name="check[0]">
<checked>1</checked>
</object>
</object>
<object class="sizeritem">
<object class="wxCheckBox" name="check[1]">
<checked>1</checked>
</object>
</object>
<object class="sizeritem">
<object class="wxCheckBox" name="check[2]">
<checked>1</checked>
</object>
</object>
</object>
</object>
<ids-range name="check" size="3" start="10000"/>
<ids-range name="first_row"/>
<ids-range name="second_row"/>
<ids-range name="third_row"/>
<ids-range name="digits" size="8"/>
<ids-range name="operators"/>
</resource>

View File

@ -0,0 +1,26 @@
/* XPM */
static const char *const objrefdlg_xpm[] = {
"16 16 7 1",
" c None",
". c #EBF70E",
"+ c #000000",
"@ c #808080",
"# c #0000FF",
"$ c #FFFFFF",
"% c #F8A836",
" . ",
"+++.++++++++++++",
"+.@.@.@@@@@@.@@+",
"+@...#######.#@+",
"...@....@@.@.@.+",
"+@...$$$$$$...@+",
"+.$.@.@@@%%%$%..",
"+@$.@@@@@@@%%%@+",
"+@$.$$$$$$%$%$%+",
"+@$$$$$$$$$$%$@+",
"+@$$$$@@@@$$$$@+",
"+@$$$$@@@@$$$$@+",
"+@$$$$$$$$$$$$@+",
"+@@@@@@@@@@@@@@+",
"++++++++++++++++",
" "};

View File

@ -26,6 +26,11 @@
<longhelp>Disable autocentering of a dialog on its parent</longhelp>
</object>
<object class="separator"/>
<object class="tool" name="obj_ref_tool_or_menuitem">
<bitmap>objrefdlg.xpm</bitmap>
<tooltip>Object references and event ranges example</tooltip>
<longhelp>Use of object references and event ranges</longhelp>
</object>
<object class="tool" name="custom_class_tool_or_menuitem">
<tooltip>Custom Class Example</tooltip>
<bitmap>custclas.xpm</bitmap>

View File

@ -9,12 +9,14 @@
myframe.cpp
derivdlg.cpp
custclas.cpp
objrefdlg.cpp
</sources>
<headers>
derivdlg.h
xrcdemo.h
myframe.h
custclas.h
objrefdlg.h
</headers>
<wx-lib>xrc</wx-lib>
<wx-lib>html</wx-lib>
@ -33,6 +35,7 @@
derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc
fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif
resource.xrc toolbar.xrc uncenter.xpm
objref.xrc objrefdlg.xpm
uncenter.xrc update.gif variable.xpm variable.xrc
throbber.gif stop.xpm
</files>

View File

@ -64,10 +64,11 @@ bool MyApp::OnInit()
return false;
// If there is any of a certain format of image in the xrcs, then first
// load a handler for that image type. This example uses XPMs, but if
// you want PNGs, then add a PNG handler, etc. See wxImage::AddHandler()
// load a handler for that image type. This example uses XPMs & a gif, but
// if you want PNGs, then add a PNG handler, etc. See wxImage::AddHandler()
// documentation for the types of image handlers available.
wxImage::AddHandler(new wxXPMHandler);
wxImage::AddHandler(new wxGIFHandler);
// Initialize all the XRC handlers. Always required (unless you feel like
// going through and initializing a handler of each control type you will

View File

@ -264,10 +264,14 @@ SOURCE=.\myframe.cpp
# End Source File
# Begin Source File
SOURCE=.\..\..\samples\sample.rc
SOURCE=.\objrefdlg.cpp
# End Source File
# Begin Source File
SOURCE=.\..\..\samples\sample.rc
# End Source File
# Begin Source File
SOURCE=.\xrcdemo.cpp
# End Source File
# End Group
@ -288,6 +292,10 @@ SOURCE=.\myframe.h
# End Source File
# Begin Source File
SOURCE=.\objrefdlg.h
# End Source File
# Begin Source File
SOURCE=.\xrcdemo.h
# End Source File
# End Group

View File

@ -1,5 +1,5 @@
//-----------------------------------------------------------------------------
// Name: xmldemo.cpp
// Name: xmldemo.h
// Purpose: XML resources sample: Main application file
// Author: Robert O'Connor (rob@medicalmnemonics.com), Vaclav Slavik
// RCS-ID: $Id$

View File

@ -551,6 +551,9 @@
RelativePath=".\myframe.cpp">
</File>
<File
RelativePath=".\objrefdlg.cpp">
</File>
<File
RelativePath=".\xrcdemo.cpp">
</File>
</Filter>
@ -568,6 +571,9 @@
RelativePath=".\myframe.h">
</File>
<File
RelativePath=".\objrefdlg.h">
</File>
<File
RelativePath=".\xrcdemo.h">
</File>
</Filter>

View File

@ -816,6 +816,10 @@
>
</File>
<File
RelativePath=".\objrefdlg.cpp"
>
</File>
<File
RelativePath=".\xrcdemo.cpp"
>
</File>
@ -838,6 +842,10 @@
>
</File>
<File
RelativePath=".\objrefdlg.h"
>
</File>
<File
RelativePath=".\xrcdemo.h"
>
</File>

View File

@ -788,6 +788,10 @@
>
</File>
<File
RelativePath=".\objrefdlg.cpp"
>
</File>
<File
RelativePath=".\xrcdemo.cpp"
>
</File>
@ -810,6 +814,10 @@
>
</File>
<File
RelativePath=".\objrefdlg.h"
>
</File>
<File
RelativePath=".\xrcdemo.h"
>
</File>

View File

@ -47,6 +47,7 @@
#include "wx/imaglist.h"
#include "wx/dir.h"
#include "wx/xml/xml.h"
#include "wx/hashset.h"
class wxXmlResourceDataRecord
@ -71,6 +72,69 @@ class wxXmlResourceDataRecords : public wxVector<wxXmlResourceDataRecord*>
// this is a class so that it can be forward-declared
};
WX_DECLARE_HASH_SET(int, wxIntegerHash, wxIntegerEqual, wxHashSetInt);
class wxIdRange // Holds data for a particular rangename
{
protected:
wxIdRange(const wxXmlNode* node,
const wxString& rname,
const wxString& startno,
const wxString& rsize);
// Note the existence of an item within the range
void NoteItem(const wxXmlNode* node, const wxString& item);
// The manager is telling us that it's finished adding items
void Finalise(const wxXmlNode* node);
wxString GetName() const { return m_name; }
bool IsFinalised() const { return m_finalised; }
const wxString m_name;
int m_start;
int m_end;
unsigned int m_size;
bool m_item_end_found;
bool m_finalised;
wxHashSetInt m_indices;
friend class wxIdRangeManager;
};
class wxIdRangeManager
{
public:
~wxIdRangeManager();
// Gets the global resources object or creates one if none exists.
static wxIdRangeManager *Get();
// Sets the global resources object and returns a pointer to the previous
// one (may be NULL).
static wxIdRangeManager *Set(wxIdRangeManager *res);
// Create a new IDrange from this node
void AddRange(const wxXmlNode* node);
// Tell the IdRange that this item exists, and should be pre-allocated an ID
void NotifyRangeOfItem(const wxXmlNode* node, const wxString& item) const;
// Tells all IDranges that they're now complete, and can create their IDs
void FinaliseRanges(const wxXmlNode* node) const;
// Searches for a known IdRange matching 'name', returning its index or -1
int Find(const wxString& rangename) const;
// Removes, if it exists, an entry from the XRCID table. Used in id-ranges
// to replace defunct or statically-initialised entries with current values
static void RemoveXRCIDEntry(const char *str_id);
protected:
wxIdRange* FindRangeForItem(const wxXmlNode* node,
const wxString& item,
wxString& value) const;
wxVector<wxIdRange*> m_IdRanges;
private:
static wxIdRangeManager *ms_instance;
};
namespace
{
@ -520,7 +584,31 @@ static void ProcessPlatformProperty(wxXmlNode *node)
}
}
static void PreprocessForIdRanges(wxXmlNode *rootnode)
{
// First go through the top level, looking for the names of ID ranges
// as processing items is a lot easier if names are already known
wxXmlNode *c = rootnode->GetChildren();
while (c)
{
if (c->GetName() == wxT("ids-range"))
wxIdRangeManager::Get()->AddRange(c);
c = c->GetNext();
}
// Next, examine every 'name' for the '[' that denotes an ID in a range
c = rootnode->GetChildren();
while (c)
{
wxString name = c->GetAttribute(wxT("name"));
if (name.find('[') != wxString::npos)
wxIdRangeManager::Get()->NotifyRangeOfItem(rootnode, name);
// Do any children by recursion, then proceed to the next sibling
PreprocessForIdRanges(c);
c = c->GetNext();
}
}
bool wxXmlResource::UpdateResources()
{
@ -631,6 +719,8 @@ bool wxXmlResource::UpdateResources()
}
ProcessPlatformProperty(rec->Doc->GetRoot());
PreprocessForIdRanges(rec->Doc->GetRoot());
wxIdRangeManager::Get()->FinaliseRanges(rec->Doc->GetRoot());
#if wxUSE_DATETIME
#if wxUSE_FILESYSTEM
rec->Time = file->GetModificationTime();
@ -744,7 +834,7 @@ wxXmlResource::GetResourceNodeAndLocation(const wxString& name,
bool recursive,
wxString *path) const
{
// ensure everything is up-to-date: this is needed to support on-remand
// ensure everything is up-to-date: this is needed to support on-demand
// reloading of XRC files
const_cast<wxXmlResource *>(this)->UpdateResources();
@ -916,6 +1006,329 @@ wxXmlResource::DoCreateResFromNode(wxXmlNode& node,
return NULL;
}
wxIdRange::wxIdRange(const wxXmlNode* node,
const wxString& rname,
const wxString& startno,
const wxString& rsize)
: m_name(rname),
m_start(0),
m_size(0),
m_item_end_found(0),
m_finalised(0)
{
long l;
if ( startno.ToLong(&l) )
{
if ( l >= 0 )
{
m_start = l;
}
else
{
wxXmlResource::Get()->ReportError
(
node,
"a negative id-range start parameter was given"
);
}
}
else
{
wxXmlResource::Get()->ReportError
(
node,
"the id-range start parameter was malformed"
);
}
unsigned long ul;
if ( rsize.ToULong(&ul) )
{
m_size = ul;
}
else
{
wxXmlResource::Get()->ReportError
(
node,
"the id-range size parameter was malformed"
);
}
}
void wxIdRange::NoteItem(const wxXmlNode* node, const wxString& item)
{
// Nothing gets added here, but the existence of each item is noted
// thus getting an accurate count. 'item' will be either an integer e.g.
// [0] [123]: will eventually create an XRCID as start+integer or [start]
// or [end] which are synonyms for [0] or [range_size-1] respectively.
wxString content(item.Mid(1, item.length()-2));
// Check that basename+item wasn't foo[]
if (content.empty())
{
wxXmlResource::Get()->ReportError(node, "an empty id-range item found");
return;
}
if (content=="start")
{
// "start" means [0], so store that in the set
if (m_indices.count(0) == 0)
{
m_indices.insert(0);
}
else
{
wxXmlResource::Get()->ReportError
(
node,
"duplicate id-range item found"
);
}
}
else if (content=="end")
{
// We can't yet be certain which XRCID this will be equivalent to, so
// just note that there's an item with this name, in case we need to
// inc the range size
m_item_end_found = true;
}
else
{
// Anything else will be an integer, or rubbish
unsigned long l;
if ( content.ToULong(&l) )
{
if (m_indices.count(l) == 0)
{
m_indices.insert(l);
// Check that this item wouldn't fall outside the current range
// extent
if (l >= m_size)
{
m_size = l + 1;
}
}
else
{
wxXmlResource::Get()->ReportError
(
node,
"duplicate id-range item found"
);
}
}
else
{
wxXmlResource::Get()->ReportError
(
node,
"an id-range item had a malformed index"
);
}
}
}
void wxIdRange::Finalise(const wxXmlNode* node)
{
wxCHECK_RET( !IsFinalised(),
"Trying to finalise an already-finalised range" );
// Now we know about all the items, we can get an accurate range size
// Expand any requested range-size if there were more items than would fit
m_size = wxMax(m_size, m_indices.size());
// If an item is explicitly called foo[end], ensure it won't clash with
// another item
if ( m_item_end_found && m_indices.count(m_size-1) )
++m_size;
if (m_size == 0)
{
// This will happen if someone creates a range but no items in this xrc
// file Report the error and abort, but don't finalise, in case items
// appear later
wxXmlResource::Get()->ReportError
(
node,
"trying to create an empty id-range"
);
return;
}
if (m_start==0)
{
// This is the usual case, where the user didn't specify a start ID
// So get the range using NewControlId().
//
// NB: negative numbers, but NewControlId already returns the most
// negative
m_start = wxWindow::NewControlId(m_size);
wxCHECK_RET( m_start != wxID_NONE,
"insufficient IDs available to create range" );
m_end = m_start + m_size - 1;
}
else
{
// The user already specified a start value, which must be positive
m_end = m_start + m_size - 1;
}
// Create the XRCIDs
for (int i=m_start; i <= m_end; ++i)
{
// First clear any pre-existing XRCID
// Necessary for wxXmlResource::Unload() followed by Load()
wxIdRangeManager::RemoveXRCIDEntry(
m_name + wxString::Format("[%i]", i-m_start));
// Use the second parameter of GetXRCID to force it to take the value i
wxXmlResource::GetXRCID(m_name + wxString::Format("[%i]", i-m_start), i);
wxLogTrace("xrcrange","integer = %i %s now returns %i", i,
m_name + wxString::Format("[%i]", i-m_start).mb_str(),
XRCID(m_name + wxString::Format("[%i]", i-m_start).mb_str()));
}
// and these special ones
wxIdRangeManager::RemoveXRCIDEntry(m_name + "[start]");
wxXmlResource::GetXRCID(m_name + "[start]", m_start);
wxIdRangeManager::RemoveXRCIDEntry(m_name + "[end]");
wxXmlResource::GetXRCID(m_name + "[end]", m_end);
wxLogTrace("xrcrange","%s[start] = %i %s[end] = %i",
m_name.mb_str(),XRCID(wxString(m_name+"[start]").mb_str()),
m_name.mb_str(),XRCID(wxString(m_name+"[end]").mb_str()));
m_finalised = true;
}
wxIdRangeManager *wxIdRangeManager::ms_instance = NULL;
/*static*/ wxIdRangeManager *wxIdRangeManager::Get()
{
if ( !ms_instance )
ms_instance = new wxIdRangeManager;
return ms_instance;
}
/*static*/ wxIdRangeManager *wxIdRangeManager::Set(wxIdRangeManager *res)
{
wxIdRangeManager *old = ms_instance;
ms_instance = res;
return old;
}
wxIdRangeManager::~wxIdRangeManager()
{
for ( wxVector<wxIdRange*>::iterator i = m_IdRanges.begin();
i != m_IdRanges.end(); ++i )
{
delete *i;
}
m_IdRanges.clear();
delete ms_instance;
}
void wxIdRangeManager::AddRange(const wxXmlNode* node)
{
wxString name = node->GetAttribute("name");
wxString start = node->GetAttribute("start", "0");
wxString size = node->GetAttribute("size", "0");
if (name.empty())
{
wxXmlResource::Get()->ReportError
(
node,
"xrc file contains an id-range without a name"
);
return;
}
int index = Find(name);
if (index == wxNOT_FOUND)
{
wxLogTrace("xrcrange",
"Adding ID range, name=%s start=%s size=%s",
name, start, size);
m_IdRanges.push_back(new wxIdRange(node, name, start, size));
}
else
{
// There was already a range with this name. Let's hope this is
// from an Unload()/(re)Load(), not an unintentional duplication
wxLogTrace("xrcrange",
"Replacing ID range, name=%s start=%s size=%s",
name, start, size);
wxIdRange* oldrange = m_IdRanges.at(index);
m_IdRanges.at(index) = new wxIdRange(node, name, start, size);
delete oldrange;
}
}
wxIdRange *
wxIdRangeManager::FindRangeForItem(const wxXmlNode* node,
const wxString& item,
wxString& value) const
{
wxString basename = item.BeforeFirst('[');
wxCHECK_MSG( !basename.empty(), NULL,
"an id-range item without a range name" );
int index = Find(basename);
if (index == wxNOT_FOUND)
{
// Don't assert just because we've found an unexpected foo[123]
// Someone might just want such a name, nothing to do with ranges
return NULL;
}
value = item.Mid(basename.Len());
if (value.at(value.length()-1)==']')
{
return m_IdRanges.at(index);
}
wxXmlResource::Get()->ReportError(node, "a malformed id-range item");
return NULL;
}
void
wxIdRangeManager::NotifyRangeOfItem(const wxXmlNode* node,
const wxString& item) const
{
wxString value;
wxIdRange* range = FindRangeForItem(node, item, value);
if (range)
range->NoteItem(node, value);
}
int wxIdRangeManager::Find(const wxString& rangename) const
{
for ( int i=0; i < (int)m_IdRanges.size(); ++i )
{
if (m_IdRanges.at(i)->GetName() == rangename)
return i;
}
return wxNOT_FOUND;
}
void wxIdRangeManager::FinaliseRanges(const wxXmlNode* node) const
{
for ( wxVector<wxIdRange*>::const_iterator i = m_IdRanges.begin();
i != m_IdRanges.end(); ++i )
{
// Check if this range has already been finalised. Quite possible,
// as FinaliseRanges() gets called for each .xrc file loaded
if (!(*i)->IsFinalised())
{
wxLogTrace("xrcrange", "Finalising ID range %s", (*i)->GetName());
(*i)->Finalise(node);
}
}
}
class wxXmlSubclassFactories : public wxVector<wxXmlSubclassFactory*>
{
@ -2203,6 +2616,33 @@ wxString wxXmlResource::FindXRCIDById(int numId)
return wxString();
}
/* static */
void wxIdRangeManager::RemoveXRCIDEntry(const char *str_id)
{
int index = 0;
for (const char *c = str_id; *c != '\0'; c++) index += (int)*c;
index %= XRCID_TABLE_SIZE;
XRCID_record **p_previousrec = &XRCID_Records[index];
for (XRCID_record *rec = XRCID_Records[index]; rec; rec = rec->next)
{
if (wxStrcmp(rec->key, str_id) == 0)
{
// Found the item to be removed so delete its record; but first
// replace it in the table with any rec->next (usually == NULL)
(*p_previousrec) = rec->next;
free(rec->key);
delete rec;
return;
}
else
{
(*p_previousrec) = rec;
}
}
}
static void CleanXRCID_Record(XRCID_record *rec)
{
if (rec)
@ -2254,6 +2694,7 @@ public:
void OnExit()
{
delete wxXmlResource::Set(NULL);
delete wxIdRangeManager::Set(NULL);
if(wxXmlResource::ms_subclassFactories)
{
for ( wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();

View File

@ -207,7 +207,8 @@ TEST_GUI_OBJECTS = \
test_gui_socket.o \
test_gui_boxsizer.o \
test_gui_clientsize.o \
test_gui_setsize.o
test_gui_setsize.o \
test_gui_xrctest.o
TEST_GUI_ODEP = $(_____pch_testprec_test_gui_testprec_h_gch___depname)
### Conditionally set variables: ###
@ -843,6 +844,9 @@ test_gui_clientsize.o: $(srcdir)/window/clientsize.cpp $(TEST_GUI_ODEP)
test_gui_setsize.o: $(srcdir)/window/setsize.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/window/setsize.cpp
test_gui_xrctest.o: $(srcdir)/xml/xrctest.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/xml/xrctest.cpp
# notice the ugly hack with using CXXWARNINGS: we can't use CPPFLAGS as
# currently the value in the makefile would be ignored if we did, but

View File

@ -192,7 +192,8 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_socket.obj \
$(OBJS)\test_gui_boxsizer.obj \
$(OBJS)\test_gui_clientsize.obj \
$(OBJS)\test_gui_setsize.obj
$(OBJS)\test_gui_setsize.obj \
$(OBJS)\test_gui_xrctest.obj
### Conditionally set variables: ###
@ -889,3 +890,5 @@ $(OBJS)\test_gui_clientsize.obj: .\window\clientsize.cpp
$(OBJS)\test_gui_setsize.obj: .\window\setsize.cpp
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\window\setsize.cpp
$(OBJS)\test_gui_xrctest.obj: .\xml\xrctest.cpp
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\xml\xrctest.cpp

View File

@ -185,7 +185,8 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_socket.o \
$(OBJS)\test_gui_boxsizer.o \
$(OBJS)\test_gui_clientsize.o \
$(OBJS)\test_gui_setsize.o
$(OBJS)\test_gui_setsize.o \
$(OBJS)\test_gui_xrctest.o
### Conditionally set variables: ###
@ -870,6 +871,9 @@ $(OBJS)\test_gui_clientsize.o: ./window/clientsize.cpp
$(OBJS)\test_gui_setsize.o: ./window/setsize.cpp
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
$(OBJS)\test_gui_xrctest.o: ./xml/xrctest.cpp
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
.PHONY: all clean data fr

View File

@ -187,7 +187,8 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_socket.obj \
$(OBJS)\test_gui_boxsizer.obj \
$(OBJS)\test_gui_clientsize.obj \
$(OBJS)\test_gui_setsize.obj
$(OBJS)\test_gui_setsize.obj \
$(OBJS)\test_gui_xrctest.obj
TEST_GUI_RESOURCES = \
$(OBJS)\test_gui_sample.res
@ -1015,3 +1016,5 @@ $(OBJS)\test_gui_clientsize.obj: .\window\clientsize.cpp
$(OBJS)\test_gui_setsize.obj: .\window\setsize.cpp
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\window\setsize.cpp
$(OBJS)\test_gui_xrctest.obj: .\xml\xrctest.cpp
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\xml\xrctest.cpp

View File

@ -427,7 +427,8 @@ TEST_GUI_OBJECTS = &
$(OBJS)\test_gui_socket.obj &
$(OBJS)\test_gui_boxsizer.obj &
$(OBJS)\test_gui_clientsize.obj &
$(OBJS)\test_gui_setsize.obj
$(OBJS)\test_gui_setsize.obj &
$(OBJS)\test_gui_xrctest.obj
all : $(OBJS)
@ -928,3 +929,5 @@ $(OBJS)\test_gui_clientsize.obj : .AUTODEPEND .\window\clientsize.cpp
$(OBJS)\test_gui_setsize.obj : .AUTODEPEND .\window\setsize.cpp
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<
$(OBJS)\test_gui_xrctest.obj : .AUTODEPEND .\xml\xrctest.cpp
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<

View File

@ -194,6 +194,7 @@
sizers/boxsizer.cpp
window/clientsize.cpp
window/setsize.cpp
xml/xrctest.cpp
</sources>
<wx-lib>richtext</wx-lib>
<wx-lib>media</wx-lib>

View File

@ -499,6 +499,10 @@ SOURCE=.\controls\treectrltest.cpp
SOURCE=.\controls\windowtest.cpp
# End Source File
# Begin Source File
SOURCE=.\xml\xrctest.cpp
# End Source File
# End Group
# End Target
# End Project

View File

@ -808,6 +808,9 @@
<File
RelativePath=".\controls\windowtest.cpp">
</File>
<File
RelativePath=".\xml\xrctest.cpp">
</File>
</Filter>
<Filter
Name="Resource Files"

View File

@ -1151,6 +1151,10 @@
RelativePath=".\controls\windowtest.cpp"
>
</File>
<File
RelativePath=".\xml\xrctest.cpp"
>
</File>
</Filter>
<Filter
Name="Resource Files"

View File

@ -1123,6 +1123,10 @@
RelativePath=".\controls\windowtest.cpp"
>
</File>
<File
RelativePath=".\xml\xrctest.cpp"
>
</File>
</Filter>
<Filter
Name="Resource Files"

229
tests/xml/xrctest.cpp Normal file
View File

@ -0,0 +1,229 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/xml/xrctest.cpp
// Purpose: XRC classes unit test
// Author: wxWidgets team
// Created: 2010-10-30
// RCS-ID: $Id$
// Copyright: (c) 2010 wxWidgets team
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif // WX_PRECOMP
#include "wx/xml/xml.h"
#include "wx/sstream.h"
#include "wx/wfstream.h"
#include "wx/xrc/xmlres.h"
#include <stdarg.h>
// ----------------------------------------------------------------------------
// helpers to create/save some xrc
// ----------------------------------------------------------------------------
namespace
{
static const char *TEST_XRC_FILE = "test.xrc";
// I'm hard-wiring the xrc into this function for now
// If different xrcs are wanted for future tests, it'll be easy to refactor
void CreateXrc()
{
const char *xrcText =
"<?xml version=\"1.0\" ?>"
"<resource>"
" <object class=\"wxDialog\" name=\"dialog\">"
" <object class=\"wxBoxSizer\">"
" <orient>wxVERTICAL</orient>"
" <object class=\"sizeritem\">"
" <object class=\"wxPanel\" name=\"panel1\">"
" <object class=\"wxBoxSizer\">"
" <object class=\"sizeritem\">"
" <object class=\"wxBoxSizer\">"
" <orient>wxVERTICAL</orient>"
" <object class=\"sizeritem\">"
" <object class=\"wxButton\" name=\"FirstCol[0]\">"
" <label>0</label>"
" </object>"
" </object>"
" <object class=\"sizeritem\">"
" <object class=\"wxButton\" name=\"FirstCol[1]\">"
" <label>1</label>"
" </object>"
" </object>"
" <object class=\"sizeritem\">"
" <object class=\"wxButton\" name=\"FirstCol[2]\">"
" <label>2</label>"
" </object>"
" </object>"
" <object class=\"sizeritem\">"
" <object class=\"wxButton\" name=\"FirstCol[3]\">"
" <label>3</label>"
" </object>"
" </object>"
" </object>"
" </object>"
" <object class=\"sizeritem\">"
" <object class=\"wxBoxSizer\">"
" <orient>wxVERTICAL</orient>"
" <object class=\"sizeritem\">"
" <object class=\"wxButton\" name=\"SecondCol[start]\">"
" <label>0</label>"
" </object>"
" </object>"
" <object class=\"sizeritem\">"
" <object class=\"wxButton\" name=\"SecondCol[1]\">"
" <label>1</label>"
" </object>"
" </object>"
" <object class=\"sizeritem\">"
" <object class=\"wxButton\" name=\"SecondCol[2]\">"
" <label>2</label>"
" </object>"
" </object>"
" <object class=\"sizeritem\">"
" <object class=\"wxButton\" name=\"SecondCol[end]\">"
" <label>3</label>"
" </object>"
" </object>"
" </object>"
" </object>"
" <orient>wxHORIZONTAL</orient>"
" </object>"
" </object>"
" </object>"
" <object class=\"sizeritem\">"
" <object class=\"wxPanel\" name=\"ref_of_panel1\">"
" <object_ref ref=\"panel1\"/>"
" </object>"
" </object>"
" </object>"
" <title>test</title>"
" </object>"
" <ids-range name=\"FirstCol\" size=\"2\" start=\"10000\"/>"
" <ids-range name=\"SecondCol\" size=\"100\" />"
"</resource>"
;
// afaict there's no elegant way to load xrc direct from a string
// So save it as a file, from which it can be loaded
wxStringInputStream sis(xrcText);
wxFFileOutputStream fos(TEST_XRC_FILE);
CPPUNIT_ASSERT(fos.IsOk());
fos.Write(sis);
CPPUNIT_ASSERT(fos.Close());
}
} // anon namespace
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
class XrcTestCase : public CppUnit::TestCase
{
public:
XrcTestCase() {}
virtual void setUp() { CreateXrc(); }
virtual void tearDown() { wxRemoveFile(TEST_XRC_FILE); }
private:
CPPUNIT_TEST_SUITE( XrcTestCase );
CPPUNIT_TEST( ObjectReferences );
CPPUNIT_TEST( IDRanges );
CPPUNIT_TEST_SUITE_END();
void ObjectReferences();
void IDRanges();
DECLARE_NO_COPY_CLASS(XrcTestCase)
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( XrcTestCase );
// also include in it's own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( XrcTestCase, "XrcTestCase" );
void XrcTestCase::ObjectReferences()
{
wxXmlResource::Get()->InitAllHandlers();
for ( int n = 0; n < 2; ++n )
{
// Load the xrc file we're just created
CPPUNIT_ASSERT( wxXmlResource::Get()->Load(TEST_XRC_FILE) );
// In xrc there's now a dialog containing two panels, one an object
// reference of the other
wxDialog dlg;
CPPUNIT_ASSERT( wxXmlResource::Get()->LoadDialog(&dlg, NULL, "dialog") );
// Might as well test XRCCTRL too
wxPanel* panel1 = XRCCTRL(dlg,"panel1",wxPanel);
wxPanel* panel2 = XRCCTRL(dlg,"ref_of_panel1",wxPanel);
// Check that the object reference panel is a different object
CPPUNIT_ASSERT( panel2 != panel1 );
// Unload the xrc, so it can be reloaded and the test rerun
CPPUNIT_ASSERT( wxXmlResource::Get()->Unload(TEST_XRC_FILE) );
}
}
void XrcTestCase::IDRanges()
{
// Tests ID ranges
for ( int n = 0; n < 2; ++n )
{
// Load the xrc file we're just created
CPPUNIT_ASSERT( wxXmlResource::Get()->Load(TEST_XRC_FILE) );
// foo[start] should == foo[0]
CPPUNIT_ASSERT_EQUAL( XRCID("SecondCol[start]"), XRCID("SecondCol[0]") );
// foo[start] should be < foo[end]. Usually that means more negative
CPPUNIT_ASSERT( XRCID("SecondCol[start]") < XRCID("SecondCol[end]") );
// Check it works for the positive values in FirstCol too
CPPUNIT_ASSERT( XRCID("FirstCol[start]") < XRCID("FirstCol[end]") );
// Check that values are adjacent
CPPUNIT_ASSERT_EQUAL( XRCID("SecondCol[0]")+1, XRCID("SecondCol[1]") );
CPPUNIT_ASSERT_EQUAL( XRCID("SecondCol[1]")+1, XRCID("SecondCol[2]") );
// And for the positive range
CPPUNIT_ASSERT_EQUAL( XRCID("FirstCol[2]")+1, XRCID("FirstCol[3]") );
// Check that a large-enough range was created, despite the small
// 'size' parameter
CPPUNIT_ASSERT_EQUAL
(
4,
XRCID("FirstCol[end]") - XRCID("FirstCol[start]") + 1
);
// Check that the far-too-large size range worked off the scale too
CPPUNIT_ASSERT( XRCID("SecondCol[start]") < XRCID("SecondCol[90]") );
CPPUNIT_ASSERT( XRCID("SecondCol[90]") < XRCID("SecondCol[end]") );
CPPUNIT_ASSERT_EQUAL( XRCID("SecondCol[90]")+1, XRCID("SecondCol[91]") );
// Check that the positive range-start parameter worked, even after a
// reload
CPPUNIT_ASSERT_EQUAL( XRCID("FirstCol[start]"), 10000 );
// Unload the xrc, so it can be reloaded and the tests rerun
CPPUNIT_ASSERT( wxXmlResource::Get()->Unload(TEST_XRC_FILE) );
}
}