}
+wxSizer* wxSizerXmlHandler::DoCreateSizer(const wxString& name)
+{
+ if (name == wxT("wxBoxSizer"))
+ return Handle_wxBoxSizer();
+#if wxUSE_STATBOX
+ else if (name == wxT("wxStaticBoxSizer"))
+ return Handle_wxStaticBoxSizer();
+#endif
+ else if (name == wxT("wxGridSizer"))
+ {
+ if ( !ValidateGridSizerChildren() )
+ return NULL;
+ return Handle_wxGridSizer();
+ }
+ else if (name == wxT("wxFlexGridSizer"))
+ {
+ return Handle_wxFlexGridSizer();
+ }
+ else if (name == wxT("wxGridBagSizer"))
+ {
+ return Handle_wxGridBagSizer();
+ }
+ else if (name == wxT("wxWrapSizer"))
+ {
+ return Handle_wxWrapSizer();
+ }
+
+ ReportError(wxString::Format("unknown sizer class \"%s\"", name));
+ return NULL;
+}
+
-bool wxSizerXmlHandler::IsSizerNode(wxXmlNode *node)
+bool wxSizerXmlHandler::IsSizerNode(wxXmlNode *node) const
{
return (IsOfClass(node, wxT("wxBoxSizer"))) ||
(IsOfClass(node, wxT("wxStaticBoxSizer"))) ||
else if (wnd)
sitem->AssignWindow(wnd);
else
- wxLogError(wxT("Error in resource."));
+ ReportError(n, "unexpected item in sizer");
// finally, set other wxSizerItem attributes
SetSizerItemAttributes(sitem);
}
else /*n == NULL*/
{
- wxLogError(wxT("Error in resource: no window/sizer/spacer within sizeritem object."));
+ ReportError("no window/sizer/spacer within sizeritem object");
return NULL;
}
}
{
if ( !m_parentSizer )
{
- wxLogError(_("XRC syntax error: \"spacer\" only allowed inside a "
- "sizer"));
+ ReportError("spacer only allowed inside a sizer");
return NULL;
}
wxObject* wxSizerXmlHandler::Handle_sizer()
{
- wxSizer *sizer = NULL;
- wxFlexGridSizer *flexsizer = NULL;
-
wxXmlNode *parentNode = m_node->GetParent();
if ( !m_parentSizer &&
(!parentNode || parentNode->GetType() != wxXML_ELEMENT_NODE ||
!m_parentAsWindow) )
{
- wxLogError(_("XRC syntax error: sizer must have a window parent."));
+ ReportError("sizer must have a window parent");
return NULL;
}
- if (m_class == wxT("wxBoxSizer"))
- sizer = Handle_wxBoxSizer();
-#if wxUSE_STATBOX
- else if (m_class == wxT("wxStaticBoxSizer"))
- sizer = Handle_wxStaticBoxSizer();
-#endif
- else if (m_class == wxT("wxGridSizer"))
- sizer = Handle_wxGridSizer();
- else if (m_class == wxT("wxFlexGridSizer"))
- {
- flexsizer = Handle_wxFlexGridSizer();
- sizer = flexsizer;
- }
- else if (m_class == wxT("wxGridBagSizer"))
- {
- flexsizer = Handle_wxGridBagSizer();
- sizer = flexsizer;
- }
- else if (m_class == wxT("wxWrapSizer"))
- sizer = Handle_wxWrapSizer();
+ // Create the sizer of the appropriate class.
+ wxSizer * const sizer = DoCreateSizer(m_class);
+ // creation of sizer failed for some (already reported) reason, so exit:
if ( !sizer )
- {
- wxLogError(_T("Failed to create size of class \"%s\""), m_class.c_str());
return NULL;
- }
wxSize minsize = GetSize(wxT("minsize"));
if (!(minsize == wxDefaultSize))
m_isInside = true;
m_isGBS = (m_class == wxT("wxGridBagSizer"));
- CreateChildren(m_parent, true/*only this handler*/);
+ wxObject* parent = m_parent;
+#if wxUSE_STATBOX
+ // wxStaticBoxSizer's child controls should be parented by the box itself,
+ // not its parent.
+ wxStaticBoxSizer* const stsizer = wxDynamicCast(sizer, wxStaticBoxSizer);
+ if ( stsizer )
+ parent = stsizer->GetStaticBox();
+#endif // wxUSE_STATBOX
+
+ CreateChildren(parent, true/*only this handler*/);
// set growable rows and cols for sizers which support this
- if ( flexsizer )
+ if ( wxFlexGridSizer *flexsizer = wxDynamicCast(sizer, wxFlexGridSizer) )
{
SetGrowables(flexsizer, wxT("growablerows"), true);
SetGrowables(flexsizer, wxT("growablecols"), false);
wxFlexGridSizer* wxSizerXmlHandler::Handle_wxFlexGridSizer()
{
+ if ( !ValidateGridSizerChildren() )
+ return NULL;
return new wxFlexGridSizer(GetLong(wxT("rows")), GetLong(wxT("cols")),
GetDimension(wxT("vgap")), GetDimension(wxT("hgap")));
}
wxGridBagSizer* wxSizerXmlHandler::Handle_wxGridBagSizer()
{
+ if ( !ValidateGridSizerChildren() )
+ return NULL;
return new wxGridBagSizer(GetDimension(wxT("vgap")), GetDimension(wxT("hgap")));
}
}
+bool wxSizerXmlHandler::ValidateGridSizerChildren()
+{
+ int rows = GetLong("rows");
+ int cols = GetLong("cols");
+
+ if ( rows && cols )
+ {
+ // fixed number of cells, need to verify children count
+ int children = 0;
+ for ( wxXmlNode *n = m_node->GetChildren(); n; n = n->GetNext() )
+ {
+ if ( n->GetType() == wxXML_ELEMENT_NODE &&
+ (n->GetName() == "object" || n->GetName() == "object_ref") )
+ {
+ children++;
+ }
+ }
+
+ if ( children > rows * cols )
+ {
+ ReportError
+ (
+ wxString::Format
+ (
+ "too many children in grid sizer: %d > %d x %d"
+ " (consider omitting the number of rows or columns)",
+ children,
+ cols,
+ rows
+ )
+ );
+ return false;
+ }
+ }
+
+ return true;
+}
+
void wxSizerXmlHandler::SetGrowables(wxFlexGridSizer* sizer,
const wxChar* param,
bool rows)
{
+ int nrows, ncols;
+ sizer->CalcRowsCols(nrows, ncols);
+ const int nslots = rows ? nrows : ncols;
+
wxStringTokenizer tkn;
- unsigned long l;
tkn.SetString(GetParamValue(param), wxT(","));
+
while (tkn.HasMoreTokens())
{
+ unsigned long l;
if (!tkn.GetNextToken().ToULong(&l))
{
- wxLogError(wxT("growable[rows|cols] must be comma-separated list of row numbers"));
+ ReportParamError
+ (
+ param,
+ "value must be comma-separated list of row numbers"
+ );
break;
}
+ const int n = static_cast<int>(l);
+ if ( n >= nslots )
+ {
+ ReportParamError
+ (
+ param,
+ wxString::Format
+ (
+ "invalid %s index %d: must be less than %d",
+ rows ? "row" : "column",
+ n,
+ nslots
+ )
+ );
+
+ // ignore incorrect value, still try to process the rest
+ continue;
+ }
+
if (rows)
- sizer->AddGrowableRow(l);
+ sizer->AddGrowableRow(n);
else
- sizer->AddGrowableCol(l);
+ sizer->AddGrowableCol(n);
}
}
if (button)
m_parentSizer->AddButton(button);
else
- wxLogError(wxT("Error in resource - expected button."));
+ ReportError(n, "expected wxButton");
return item;
}
else /*n == NULL*/
{
- wxLogError(wxT("Error in resource: no button within wxStdDialogButtonSizer."));
+ ReportError("no button within wxStdDialogButtonSizer");
return NULL;
}
}