Files
wxWidgets/src/propgrid/propgridiface.cpp
2018-11-07 22:12:56 +01:00

1200 lines
35 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/propgrid/propgridiface.cpp
// Purpose: wxPropertyGridInterface class
// Author: Jaakko Salli
// Modified by:
// Created: 2008-08-24
// Copyright: (c) Jaakko Salli
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_PROPGRID
#ifndef WX_PRECOMP
#include "wx/defs.h"
#include "wx/object.h"
#include "wx/hash.h"
#include "wx/string.h"
#include "wx/log.h"
#include "wx/event.h"
#include "wx/window.h"
#include "wx/panel.h"
#include "wx/dc.h"
#include "wx/dcmemory.h"
#include "wx/button.h"
#include "wx/pen.h"
#include "wx/brush.h"
#include "wx/settings.h"
#include "wx/sizer.h"
#include "wx/intl.h"
#endif
#include "wx/propgrid/property.h"
#include "wx/propgrid/propgrid.h"
// ----------------------------------------------------------------------------
// VariantDatas
// ----------------------------------------------------------------------------
WX_PG_IMPLEMENT_VARIANT_DATA_EXPORTED(wxPoint, WXDLLIMPEXP_PROPGRID)
WX_PG_IMPLEMENT_VARIANT_DATA_EXPORTED(wxSize, WXDLLIMPEXP_PROPGRID)
WX_PG_IMPLEMENT_VARIANT_DATA_EXPORTED_DUMMY_EQ(wxArrayInt, WXDLLIMPEXP_PROPGRID)
IMPLEMENT_VARIANT_OBJECT_EXPORTED(wxFont, WXDLLIMPEXP_PROPGRID)
// -----------------------------------------------------------------------
// wxPGPropArgCls
// -----------------------------------------------------------------------
wxPGProperty* wxPGPropArgCls::GetPtr( wxPropertyGridInterface* iface ) const
{
if ( m_flags == IsProperty )
{
wxASSERT_MSG( m_ptr.property, wxS("invalid property ptr") );
return m_ptr.property;
}
else if ( m_flags & IsWxString )
return iface->GetPropertyByNameA(*m_ptr.stringName);
else if ( m_flags & IsCharPtr )
return iface->GetPropertyByNameA(m_ptr.charName);
else if ( m_flags & IsWCharPtr )
return iface->GetPropertyByNameA(m_ptr.wcharName);
return NULL;
}
// -----------------------------------------------------------------------
// wxPropertyGridInterface
// -----------------------------------------------------------------------
void wxPropertyGridInterface::RefreshGrid( wxPropertyGridPageState* state )
{
if ( !state )
state = m_pState;
wxPropertyGrid* grid = state->GetGrid();
if ( grid->GetState() == state && !grid->IsFrozen() )
{
grid->Refresh();
}
}
// -----------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::Append( wxPGProperty* property )
{
wxPGProperty* retp = m_pState->DoAppend(property);
wxPropertyGrid* grid = m_pState->GetGrid();
if ( grid )
grid->RefreshGrid();
return retp;
}
// -----------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::AppendIn( wxPGPropArg id, wxPGProperty* newproperty )
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
wxPGProperty* pwc = (wxPGProperty*) p;
wxPGProperty* retp = m_pState->DoInsert(pwc, pwc->GetChildCount(), newproperty);
return retp;
}
// -----------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::Insert( wxPGPropArg id, wxPGProperty* property )
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
wxPGProperty* retp = m_pState->DoInsert(p->GetParent(), p->GetIndexInParent(), property);
RefreshGrid();
return retp;
}
// -----------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::Insert( wxPGPropArg id, int index, wxPGProperty* newproperty )
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
wxPGProperty* retp = m_pState->DoInsert((wxPGProperty*)p,index,newproperty);
RefreshGrid();
return retp;
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::DeleteProperty( wxPGPropArg id )
{
wxPG_PROP_ARG_CALL_PROLOG()
wxPropertyGridPageState* state = p->GetParentState();
state->DoDelete( p, true );
RefreshGrid(state);
}
// -----------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::RemoveProperty( wxPGPropArg id )
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
wxCHECK( !p->GetChildCount() || p->HasFlag(wxPG_PROP_AGGREGATE),
wxNullProperty);
wxPropertyGridPageState* state = p->GetParentState();
state->DoDelete( p, false );
RefreshGrid(state);
return p;
}
// -----------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::ReplaceProperty( wxPGPropArg id, wxPGProperty* property )
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
wxPGProperty* replaced = p;
wxCHECK_MSG( replaced && property,
wxNullProperty,
wxS("NULL property") );
wxCHECK_MSG( !replaced->IsCategory(),
wxNullProperty,
wxS("cannot replace this type of property") );
wxCHECK_MSG( !m_pState->IsInNonCatMode(),
wxNullProperty,
wxS("cannot replace properties in alphabetic mode") );
// Get address to the slot
wxPGProperty* parent = replaced->GetParent();
int ind = replaced->GetIndexInParent();
wxPropertyGridPageState* state = replaced->GetParentState();
DeleteProperty(replaced); // Must use generic Delete
state->DoInsert(parent,ind,property);
return property;
}
// -----------------------------------------------------------------------
// wxPropertyGridInterface property operations
// -----------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::GetSelection() const
{
return m_pState->GetSelection();
}
// -----------------------------------------------------------------------
bool wxPropertyGridInterface::ClearSelection( bool validation )
{
bool res = DoClearSelection(validation, wxPG_SEL_DONT_SEND_EVENT);
wxPropertyGrid* pg = GetPropertyGrid();
if ( pg )
pg->Refresh();
return res;
}
// -----------------------------------------------------------------------
bool wxPropertyGridInterface::DoClearSelection( bool validation,
int selFlags )
{
if ( !validation )
selFlags |= wxPG_SEL_NOVALIDATE;
wxPropertyGridPageState* state = m_pState;
if ( state )
{
wxPropertyGrid* pg = state->GetGrid();
if ( pg->GetState() == state )
return pg->DoSelectProperty(NULL, selFlags);
else
state->DoSetSelection(NULL);
}
return true;
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::LimitPropertyEditing( wxPGPropArg id, bool limit )
{
wxPG_PROP_ARG_CALL_PROLOG()
m_pState->DoLimitPropertyEditing(p, limit);
RefreshProperty(p);
}
// -----------------------------------------------------------------------
bool wxPropertyGridInterface::EnableProperty( wxPGPropArg id, bool enable )
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
wxPropertyGridPageState* state = p->GetParentState();
wxPropertyGrid* grid = state->GetGrid();
if ( enable )
{
if ( !p->HasFlag(wxPG_PROP_DISABLED) )
return false;
// If active, Set active Editor.
if ( grid && grid->GetState() == state && p == grid->GetSelection() )
grid->DoSelectProperty( p, wxPG_SEL_FORCE );
}
else
{
if ( p->HasFlag(wxPG_PROP_DISABLED) )
return false;
// If active, Disable as active Editor.
if ( grid && grid->GetState() == state && p == grid->GetSelection() )
grid->DoSelectProperty( p, wxPG_SEL_FORCE );
}
p->DoEnable(enable);
RefreshProperty( p );
return true;
}
void wxPropertyGridInterface::SetPropertyReadOnly( wxPGPropArg id, bool set, int flags)
{
wxPG_PROP_ARG_CALL_PROLOG()
if ( flags & wxPG_RECURSE )
{
p->SetFlagRecursively(wxPG_PROP_READONLY, set);
}
else
{
// Do nothing if flag is already set as required.
if ( set && p->HasFlag(wxPG_PROP_READONLY) )
return;
if ( !set && !p->HasFlag(wxPG_PROP_READONLY) )
return;
p->ChangeFlag(wxPG_PROP_READONLY, set);
}
wxPropertyGridPageState* state = p->GetParentState();
if( state )
{
// If property is attached to the property grid
// then refresh the view.
RefreshProperty( p );
}
}
// -----------------------------------------------------------------------
bool wxPropertyGridInterface::ExpandAll( bool doExpand )
{
wxPropertyGridPageState* state = m_pState;
if ( !state->DoGetRoot()->GetChildCount() )
return true;
wxPropertyGrid* pg = state->GetGrid();
if ( GetSelection() && GetSelection() != state->DoGetRoot() &&
!doExpand )
{
pg->DoClearSelection();
}
wxPGVIterator it;
for ( it = GetVIterator( wxPG_ITERATE_ALL ); !it.AtEnd(); it.Next() )
{
wxPGProperty* p = (wxPGProperty*) it.GetProperty();
if ( p->GetChildCount() )
{
if ( doExpand )
{
if ( !p->IsExpanded() )
{
state->DoExpand(p);
}
}
else
{
if ( p->IsExpanded() )
{
state->DoCollapse(p);
}
}
}
}
pg->RecalculateVirtualSize();
RefreshGrid();
return true;
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::ClearModifiedStatus()
{
unsigned int pageIndex = 0;
for (;;)
{
wxPropertyGridPageState* page = GetPageState(pageIndex);
if ( !page ) break;
page->DoGetRoot()->SetFlagRecursively(wxPG_PROP_MODIFIED, false);
page->m_anyModified = false;
pageIndex++;
}
// Update active editor control, if any
GetPropertyGrid()->RefreshEditor();
}
bool wxPropertyGridInterface::SetColumnProportion( unsigned int column,
int proportion )
{
wxCHECK(m_pState, false);
wxPropertyGrid* pg = m_pState->GetGrid();
wxCHECK(pg, false);
wxCHECK(pg->HasFlag(wxPG_SPLITTER_AUTO_CENTER), false);
m_pState->DoSetColumnProportion(column, proportion);
return true;
}
// -----------------------------------------------------------------------
// wxPropertyGridInterface property value setting and getting
// -----------------------------------------------------------------------
void wxPGGetFailed( const wxPGProperty* p, const wxString& typestr )
{
wxPGTypeOperationFailed(p, typestr, wxS("Get"));
}
// -----------------------------------------------------------------------
void wxPGTypeOperationFailed( const wxPGProperty* p,
const wxString& typestr,
const wxString& op )
{
wxASSERT( p != NULL );
wxLogError( _("Type operation \"%s\" failed: Property labeled \"%s\" is of type \"%s\", NOT \"%s\"."),
op.c_str(), p->GetLabel().c_str(), p->GetValue().GetType().c_str(), typestr.c_str() );
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::SetPropVal( wxPGPropArg id, wxVariant& value )
{
wxPG_PROP_ARG_CALL_PROLOG()
if ( p )
p->SetValue(value);
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::SetPropertyValueString( wxPGPropArg id, const wxString& value )
{
wxPG_PROP_ARG_CALL_PROLOG()
if ( p )
m_pState->DoSetPropertyValueString(p, value);
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::SetValidationFailureBehavior( int vfbFlags )
{
GetPropertyGrid()->m_permanentValidationFailureBehavior = vfbFlags;
}
// -----------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::GetPropertyByNameA( const wxString& name ) const
{
wxPGProperty* p = GetPropertyByName(name);
wxASSERT_MSG(p,wxString::Format(wxS("no property with name '%s'"),name.c_str()));
return p;
}
// ----------------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::GetPropertyByLabel( const wxString& label ) const
{
return m_pState->BaseGetPropertyByLabel(label, NULL);
}
// ----------------------------------------------------------------------------
void wxPropertyGridInterface::DoSetPropertyAttribute( wxPGPropArg id, const wxString& name,
wxVariant& value, long argFlags )
{
wxPG_PROP_ARG_CALL_PROLOG()
p->SetAttribute( name, value );
// If property is attached to the property grid
// then refresh the view.
if( p->GetParentState() )
{
RefreshProperty( p );
}
if ( argFlags & wxPG_RECURSE )
{
for ( unsigned int i = 0; i < p->GetChildCount(); i++ )
DoSetPropertyAttribute(p->Item(i), name, value, argFlags);
}
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::SetPropertyAttributeAll( const wxString& attrName,
wxVariant value )
{
unsigned int pageIndex = 0;
for (;;)
{
wxPropertyGridPageState* page = GetPageState(pageIndex);
if ( !page ) break;
DoSetPropertyAttribute(page->DoGetRoot(), attrName, value, wxPG_RECURSE);
pageIndex++;
}
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::GetPropertiesWithFlag( wxArrayPGProperty* targetArr,
wxPGProperty::FlagType flags,
bool inverse,
int iterFlags ) const
{
wxASSERT( targetArr );
wxPGVIterator it = GetVIterator( iterFlags );
for ( ;
!it.AtEnd();
it.Next() )
{
const wxPGProperty* property = it.GetProperty();
if ( !inverse )
{
if ( property->HasFlagsExact(flags) )
targetArr->push_back((wxPGProperty*)property);
}
else
{
if ( !property->HasFlagsExact(flags) )
targetArr->push_back((wxPGProperty*)property);
}
}
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::SetBoolChoices( const wxString& trueChoice,
const wxString& falseChoice )
{
wxPGGlobalVars->m_boolChoices[0] = falseChoice;
wxPGGlobalVars->m_boolChoices[1] = trueChoice;
}
// -----------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::DoGetPropertyByName( const wxString& name ) const
{
return m_pState->BaseGetPropertyByName(name);
}
// -----------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::GetPropertyByName( const wxString& name,
const wxString& subname ) const
{
wxPGProperty* p = DoGetPropertyByName(name);
if ( !p || !p->GetChildCount() )
return wxNullProperty;
return p->GetPropertyByName(subname);
}
// -----------------------------------------------------------------------
// Since GetPropertyByName is used *a lot*, this makes sense
// since non-virtual method can be called with less code.
wxPGProperty* wxPropertyGridInterface::GetPropertyByName( const wxString& name ) const
{
wxPGProperty* p = DoGetPropertyByName(name);
if ( p )
return p;
// Check if it is "Property.SubProperty" format
int pos = name.Find(wxS('.'));
if ( pos <= 0 )
return NULL;
return GetPropertyByName(name.substr(0,pos),
name.substr(pos+1,name.length()-pos-1));
}
// -----------------------------------------------------------------------
bool wxPropertyGridInterface::HideProperty( wxPGPropArg id, bool hide, int flags )
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
// Do nothing if single property is already hidden/visible as requested.
if ( !(flags & wxPG_RECURSE) )
{
if ( hide && p->HasFlag(wxPG_PROP_HIDDEN) )
return false;
if ( !hide && !p->HasFlag(wxPG_PROP_HIDDEN) )
return false;
}
wxPropertyGrid* pg = m_pState->GetGrid();
if ( pg == p->GetGrid() )
return pg->DoHideProperty(p, hide, flags);
else
m_pState->DoHideProperty(p, hide, flags);
return true;
}
// -----------------------------------------------------------------------
bool wxPropertyGridInterface::Collapse( wxPGPropArg id )
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
wxPropertyGrid* pg = p->GetGridIfDisplayed();
if ( pg )
return pg->DoCollapse(p);
return p->GetParentState()->DoCollapse(p);
}
// -----------------------------------------------------------------------
bool wxPropertyGridInterface::Expand( wxPGPropArg id )
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
wxPropertyGrid* pg = p->GetGridIfDisplayed();
if ( pg )
return pg->DoExpand(p);
return p->GetParentState()->DoExpand(p);
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::Sort( int flags )
{
wxPropertyGrid* pg = GetPropertyGrid();
unsigned int pageIndex = 0;
for (;;)
{
wxPropertyGridPageState* page = GetPageState(pageIndex);
if ( !page ) break;
page->DoSort(flags);
pageIndex++;
}
// Fix positions of any open editor controls
if ( pg )
pg->CorrectEditorWidgetPosY();
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::SetPropertyLabel( wxPGPropArg id, const wxString& newproplabel )
{
wxPG_PROP_ARG_CALL_PROLOG()
if ( p->GetLabel() == newproplabel )
return;
p->SetLabel( newproplabel );
wxPropertyGridPageState* state = p->GetParentState();
wxPropertyGrid* pg = state->GetGrid();
if ( pg->HasFlag(wxPG_AUTO_SORT) )
pg->SortChildren(p->GetParent());
if ( pg->GetState() == state )
{
if ( pg->HasFlag(wxPG_AUTO_SORT) )
{
pg->Refresh();
// If any property is selected it has to
// be refreshed in the new location.
if ( pg == p->GetGrid() && pg->GetSelectedProperty() )
{
RefreshProperty(pg->GetSelectedProperty());
}
}
else
{
pg->DrawItem( p );
}
}
}
// -----------------------------------------------------------------------
bool wxPropertyGridInterface::SetPropertyMaxLength( wxPGPropArg id, int maxLen )
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
wxPropertyGrid* pg = m_pState->GetGrid();
p->m_maxLen = (short) maxLen;
// Adjust control if selected currently
if ( pg == p->GetGrid() && p == m_pState->GetSelection() )
{
wxWindow* wnd = pg->GetEditorControl();
wxTextCtrl* tc = wxDynamicCast(wnd,wxTextCtrl);
if ( tc )
tc->SetMaxLength( maxLen );
else
// Not a text ctrl
return false;
}
return true;
}
// -----------------------------------------------------------------------
void
wxPropertyGridInterface::SetPropertyBackgroundColour( wxPGPropArg id,
const wxColour& colour,
int flags )
{
wxPG_PROP_ARG_CALL_PROLOG()
p->SetBackgroundColour(colour, flags);
// Redraw the control
wxPropertyGrid* pg = m_pState->GetGrid();
if ( pg == p->GetGrid() )
{
if ( flags & wxPG_RECURSE )
pg->DrawItemAndChildren(p);
else
pg->DrawItem(p);
}
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::SetPropertyTextColour( wxPGPropArg id,
const wxColour& colour,
int flags )
{
wxPG_PROP_ARG_CALL_PROLOG()
p->SetTextColour(colour, flags);
// Redraw the control
wxPropertyGrid* pg = m_pState->GetGrid();
if ( pg == p->GetGrid() )
{
if ( flags & wxPG_RECURSE )
pg->DrawItemAndChildren(p);
else
pg->DrawItem(p);
}
}
// -----------------------------------------------------------------------
#if WXWIN_COMPATIBILITY_3_0
void wxPropertyGridInterface::SetPropertyColoursToDefault(wxPGPropArg id)
{
SetPropertyColoursToDefault(id, wxPG_DONT_RECURSE);
}
#endif // WXWIN_COMPATIBILITY_3_0
void wxPropertyGridInterface::SetPropertyColoursToDefault(wxPGPropArg id, int flags)
{
wxPG_PROP_ARG_CALL_PROLOG()
p->SetDefaultColours(flags);
// Redraw the control
wxPropertyGrid* pg = m_pState->GetGrid();
if ( pg == p->GetGrid() )
{
if ( flags & wxPG_RECURSE )
pg->DrawItemAndChildren(p);
else
pg->DrawItem(p);
}
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::SetPropertyCell( wxPGPropArg id,
int column,
const wxString& text,
const wxBitmap& bitmap,
const wxColour& fgCol,
const wxColour& bgCol )
{
wxPG_PROP_ARG_CALL_PROLOG()
wxPGCell& cell = p->GetCell(column);
if ( !text.empty() && text != wxPG_LABEL )
cell.SetText(text);
if ( bitmap.IsOk() )
cell.SetBitmap(bitmap);
if ( fgCol != wxNullColour )
cell.SetFgCol(fgCol);
if ( bgCol != wxNullColour )
cell.SetBgCol(bgCol);
}
// -----------------------------------------------------------------------
// GetPropertyValueAsXXX methods
#define IMPLEMENT_GET_VALUE(TRET,PGTypeName,BIGNAME,DEFRETVAL) \
TRET wxPropertyGridInterface::GetPropertyValueAs##BIGNAME( wxPGPropArg id ) const \
{ \
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(DEFRETVAL) \
wxVariant value = p->GetValue(); \
if ( !value.IsType(PGTypeName) ) \
{ \
wxPGGetFailed(p, PGTypeName); \
return (TRET)DEFRETVAL; \
} \
return (TRET)value.Get##BIGNAME(); \
}
// String is different from others.
wxString wxPropertyGridInterface::GetPropertyValueAsString( wxPGPropArg id ) const
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxEmptyString)
return p->GetValueAsString(wxPG_FULL_VALUE);
}
bool wxPropertyGridInterface::GetPropertyValueAsBool( wxPGPropArg id ) const
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
wxVariant value = p->GetValue();
if ( value.IsType(wxPG_VARIANT_TYPE_BOOL) )
{
return value.GetBool();
}
if ( value.IsType(wxPG_VARIANT_TYPE_LONG) )
{
return value.GetLong()?true:false;
}
wxPGGetFailed(p, wxPG_VARIANT_TYPE_BOOL);
return false;
}
IMPLEMENT_GET_VALUE(long,wxPG_VARIANT_TYPE_LONG,Long,0)
IMPLEMENT_GET_VALUE(double,wxPG_VARIANT_TYPE_DOUBLE,Double,0.0)
bool wxPropertyGridInterface::IsPropertyExpanded( wxPGPropArg id ) const
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
return p->IsExpanded();
}
// -----------------------------------------------------------------------
// wxPropertyGridInterface wrappers
// -----------------------------------------------------------------------
bool wxPropertyGridInterface::ChangePropertyValue( wxPGPropArg id, wxVariant newValue )
{
return GetPropertyGrid()->ChangePropertyValue(id, newValue);
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::BeginAddChildren( wxPGPropArg id )
{
wxPG_PROP_ARG_CALL_PROLOG()
wxCHECK_RET( p->HasFlag(wxPG_PROP_AGGREGATE), wxS("only call on properties with fixed children") );
p->ClearFlag(wxPG_PROP_AGGREGATE);
p->SetFlag(wxPG_PROP_MISC_PARENT);
}
// -----------------------------------------------------------------------
bool wxPropertyGridInterface::EditorValidate()
{
return GetPropertyGrid()->DoEditorValidate();
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::EndAddChildren( wxPGPropArg id )
{
wxPG_PROP_ARG_CALL_PROLOG()
wxCHECK_RET( p->HasFlag(wxPG_PROP_MISC_PARENT), wxS("only call on properties for which BeginAddChildren was called prior") );
p->ClearFlag(wxPG_PROP_MISC_PARENT);
p->SetFlag(wxPG_PROP_AGGREGATE);
}
// -----------------------------------------------------------------------
// wxPGVIterator_State
// -----------------------------------------------------------------------
// Default returned by wxPropertyGridInterface::GetVIterator().
class wxPGVIteratorBase_State : public wxPGVIteratorBase
{
public:
wxPGVIteratorBase_State( wxPropertyGridPageState* state, int flags )
{
m_it.Init( state, flags );
}
virtual ~wxPGVIteratorBase_State() { }
virtual void Next() wxOVERRIDE { m_it.Next(); }
};
wxPGVIterator wxPropertyGridInterface::GetVIterator( int flags ) const
{
return wxPGVIterator( new wxPGVIteratorBase_State( m_pState, flags ) );
}
// -----------------------------------------------------------------------
// wxPGEditableState related functions
// -----------------------------------------------------------------------
// EscapeDelimiters() changes ";" into "\;" and "|" into "\|"
// in the input string. This is an internal functions which is
// used for saving states
// NB: Similar function exists in aui/framemanager.cpp
static wxString EscapeDelimiters(const wxString& s)
{
wxString result;
result.reserve(s.length());
for (wxString::const_iterator it = s.begin(); it != s.end(); ++it)
{
wxStringCharType ch = *it;
if ( ch == wxS(';') || ch == wxS('|') || ch == wxS(',') )
result += wxS('\\');
result += ch;
}
return result;
}
wxString wxPropertyGridInterface::SaveEditableState( int includedStates ) const
{
wxString result;
//
// Save state on page basis
unsigned int pageIndex = 0;
wxArrayPtrVoid pageStates;
for (;;)
{
wxPropertyGridPageState* page = GetPageState(pageIndex);
if ( !page ) break;
pageStates.Add(page);
pageIndex++;
}
for ( pageIndex=0; pageIndex < pageStates.size(); pageIndex++ )
{
wxPropertyGridPageState* pageState = (wxPropertyGridPageState*) pageStates[pageIndex];
if ( includedStates & SelectionState )
{
wxString sel;
if ( pageState->GetSelection() )
sel = pageState->GetSelection()->GetName();
result += wxS("selection=");
result += EscapeDelimiters(sel);
result += wxS(";");
}
if ( includedStates & ExpandedState )
{
wxPropertyGridConstIterator it =
wxPropertyGridConstIterator( pageState,
wxPG_ITERATE_ALL_PARENTS_RECURSIVELY|wxPG_ITERATE_HIDDEN,
wxNullProperty );
result += wxS("expanded=");
for ( ;
!it.AtEnd();
it.Next() )
{
const wxPGProperty* p = it.GetProperty();
if ( !p->HasFlag(wxPG_PROP_COLLAPSED) )
result += EscapeDelimiters(p->GetName());
result += wxS(",");
}
if ( result.Last() == wxS(',') )
result.RemoveLast();
result += wxS(";");
}
if ( includedStates & ScrollPosState )
{
int x, y;
GetPropertyGrid()->GetViewStart(&x,&y);
result += wxString::Format(wxS("scrollpos=%i,%i;"), x, y);
}
if ( includedStates & SplitterPosState )
{
result += wxS("splitterpos=");
for ( size_t i=0; i<pageState->GetColumnCount(); i++ )
result += wxString::Format(wxS("%i,"), pageState->DoGetSplitterPosition(i));
result.RemoveLast(); // Remove last comma
result += wxS(";");
}
if ( includedStates & PageState )
{
result += wxS("ispageselected=");
if ( GetPageState(-1) == pageState )
result += wxS("1;");
else
result += wxS("0;");
}
if ( includedStates & DescBoxState )
{
wxVariant v = GetEditableStateItem(wxS("descboxheight"));
if ( !v.IsNull() )
result += wxString::Format(wxS("descboxheight=%i;"), (int)v.GetLong());
}
result.RemoveLast(); // Remove last semicolon
result += wxS("|");
}
// Remove last '|'
if ( !result.empty() )
result.RemoveLast();
return result;
}
bool wxPropertyGridInterface::RestoreEditableState( const wxString& src, int restoreStates )
{
wxPropertyGrid* pg = GetPropertyGrid();
wxPGProperty* newSelection = NULL;
size_t pageIndex;
long vx = -1;
long vy = -1;
long selectedPage = -1;
bool pgSelectionSet = false;
bool res = true;
pg->Freeze();
wxArrayString pageStrings = ::wxSplit(src, wxS('|'), wxS('\\'));
for ( pageIndex=0; pageIndex<pageStrings.size(); pageIndex++ )
{
wxPropertyGridPageState* pageState = GetPageState(pageIndex);
if ( !pageState )
break;
wxArrayString kvpairStrings = ::wxSplit(pageStrings[pageIndex], wxS(';'), wxS('\\'));
for ( size_t i=0; i<kvpairStrings.size(); i++ )
{
const wxString& kvs = kvpairStrings[i];
int eq_pos = kvs.Find(wxS('='));
if ( eq_pos != wxNOT_FOUND )
{
wxString key = kvs.substr(0, eq_pos);
wxString value = kvs.substr(eq_pos+1);
// Further split value by commas
wxArrayString values = ::wxSplit(value, wxS(','), wxS('\\'));
if ( key == wxS("expanded") )
{
if ( restoreStates & ExpandedState )
{
wxPropertyGridIterator it =
wxPropertyGridIterator( pageState,
wxPG_ITERATE_ALL,
wxNullProperty );
// First collapse all
for ( ; !it.AtEnd(); it.Next() )
{
wxPGProperty* p = it.GetProperty();
pageState->DoCollapse(p);
}
// Then expand those which names are in values
for ( size_t n=0; n<values.size(); n++ )
{
const wxString& name = values[n];
wxPGProperty* prop = GetPropertyByName(name);
if ( prop )
pageState->DoExpand(prop);
}
}
}
else if ( key == wxS("scrollpos") )
{
if ( restoreStates & ScrollPosState )
{
if ( values.size() == 2 )
{
values[0].ToLong(&vx);
values[1].ToLong(&vy);
}
else
{
res = false;
}
}
}
else if ( key == wxS("splitterpos") )
{
if ( restoreStates & SplitterPosState )
{
for ( size_t n=1; n<values.size(); n++ )
{
long pos = 0;
values[n].ToLong(&pos);
if ( pos > 0 )
pageState->DoSetSplitterPosition(pos, n);
}
}
}
else if ( key == wxS("selection") )
{
if ( restoreStates & SelectionState )
{
if ( !values.empty() )
{
if ( pageState->IsDisplayed() )
{
if ( !values[0].empty() )
newSelection = GetPropertyByName(value);
pgSelectionSet = true;
}
else
{
if ( !values[0].empty() )
pageState->DoSetSelection(GetPropertyByName(value));
else
pageState->DoClearSelection();
}
}
}
}
else if ( key == wxS("ispageselected") )
{
if ( restoreStates & PageState )
{
long pageSelStatus;
if ( values.size() == 1 && values[0].ToLong(&pageSelStatus) )
{
if ( pageSelStatus )
selectedPage = pageIndex;
}
else
{
res = false;
}
}
}
else if ( key == wxS("descboxheight") )
{
if ( restoreStates & DescBoxState )
{
long descBoxHeight;
if ( values.size() == 1 && values[0].ToLong(&descBoxHeight) )
{
SetEditableStateItem(wxS("descboxheight"), descBoxHeight);
}
else
{
res = false;
}
}
}
else
{
res = false;
}
}
}
}
//
// Force recalculation of virtual heights of all pages
// (may be needed on unclean source string).
pageIndex = 0;
wxPropertyGridPageState* pageState = GetPageState(pageIndex);
while ( pageState )
{
pageState->VirtualHeightChanged();
pageIndex += 1;
pageState = GetPageState(pageIndex);
}
pg->Thaw();
//
// Selection of visible grid page must be set after Thaw() call
if ( pgSelectionSet )
{
if ( newSelection )
pg->DoSelectProperty(newSelection);
else
pg->DoClearSelection();
}
if ( selectedPage != -1 )
{
DoSelectPage(selectedPage);
}
if ( vx >= 0 )
{
pg->Scroll(vx, vy);
}
return res;
}
#endif // wxUSE_PROPGRID