Files
wxWidgets/src/propgrid/propgridiface.cpp
2008-09-21 15:42:08 +00:00

1157 lines
34 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/propgrid/propgridiface.cpp
// Purpose: wxPropertyGridInterface class
// Author: Jaakko Salli
// Modified by:
// Created: 2008-08-24
// RCS-ID: $Id:
// Copyright: (c) Jaakko Salli
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
// 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/cursor.h"
#include "wx/dialog.h"
#include "wx/settings.h"
#include "wx/msgdlg.h"
#include "wx/choice.h"
#include "wx/stattext.h"
#include "wx/scrolwin.h"
#include "wx/dirdlg.h"
#include "wx/layout.h"
#include "wx/sizer.h"
#include "wx/textdlg.h"
#include "wx/filedlg.h"
#include "wx/statusbr.h"
#include "wx/intl.h"
#include "wx/frame.h"
#endif
#include <wx/propgrid/property.h>
#include <wx/propgrid/propgrid.h>
#include <typeinfo>
const wxChar *wxPGTypeName_long = wxT("long");
const wxChar *wxPGTypeName_bool = wxT("bool");
const wxChar *wxPGTypeName_double = wxT("double");
const wxChar *wxPGTypeName_wxString = wxT("string");
const wxChar *wxPGTypeName_void = wxT("void*");
const wxChar *wxPGTypeName_wxArrayString = wxT("arrstring");
// ----------------------------------------------------------------------------
// 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)
WX_PG_IMPLEMENT_VARIANT_DATA_EXPORTED(wxLongLong, WXDLLIMPEXP_PROPGRID)
WX_PG_IMPLEMENT_VARIANT_DATA_EXPORTED(wxULongLong, WXDLLIMPEXP_PROPGRID)
IMPLEMENT_VARIANT_OBJECT_EXPORTED(wxFont, WXDLLIMPEXP_PROPGRID)
// -----------------------------------------------------------------------
// wxVariant helpers
// -----------------------------------------------------------------------
long wxPGVariantToInt( const wxVariant& variant, long defVal )
{
if ( variant.IsNull() )
return defVal;
if ( variant.GetType() == wxS("long") )
return variant.GetLong();
if ( variant.GetType() == wxS("bool") )
return variant.GetBool() ? 1 : 0;
if ( variant.GetType() == wxS("wxLongLong") )
{
wxLongLong ll;
ll << variant;
if ( ll >= LONG_MAX )
return LONG_MAX;
else if ( ll <= LONG_MIN )
return LONG_MIN;
return ll.ToLong();
}
long l = defVal;
if ( variant.GetType() == wxPG_VARIANT_TYPE_STRING )
variant.GetString().ToLong(&l, 0);
return l;
}
// -----------------------------------------------------------------------
bool wxPGVariantToLongLong( const wxVariant& variant, wxLongLong_t* pResult )
{
if ( variant.IsNull() )
return false;
wxString variantType = variant.GetType();
if ( variantType == wxPG_VARIANT_TYPE_LONG )
{
*pResult = variant.GetLong();
return true;
}
if ( variantType == wxLongLong_VariantType )
{
wxLongLong ll;
ll << variant;
*pResult = ll.GetValue();
return true;
}
return false;
}
// -----------------------------------------------------------------------
bool wxPGVariantToULongLong( const wxVariant& variant, wxULongLong_t* pResult )
{
if ( variant.IsNull() )
return false;
wxString variantType = variant.GetType();
if ( variantType == wxPG_VARIANT_TYPE_LONG )
{
*pResult = (unsigned long)variant.GetLong();
return true;
}
if ( variantType == wxULongLong_VariantType )
{
wxULongLong ull;
ull << variant;
*pResult = ull.GetValue();
return true;
}
return false;
}
// -----------------------------------------------------------------------
bool wxPGVariantToDouble( const wxVariant& variant, double* pResult )
{
if ( variant.IsNull() )
return false;
wxString variantType = variant.GetType();
if ( variantType == wxPG_VARIANT_TYPE_DOUBLE )
{
*pResult = variant.GetDouble();
return true;
}
if ( variantType == wxPG_VARIANT_TYPE_LONG )
{
*pResult = (double)variant.GetLong();
return true;
}
if ( variantType == wxLongLong_VariantType )
{
wxLongLong ll;
ll << variant;
*pResult = ll.ToDouble();
return true;
}
if ( variantType == wxPG_VARIANT_TYPE_STRING )
if ( variant.GetString().ToDouble(pResult) )
return true;
return false;
}
// -----------------------------------------------------------------------
// wxPGPropArgCls
// -----------------------------------------------------------------------
wxPGProperty* wxPGPropArgCls::GetPtr( wxPropertyGridInterface* iface ) const
{
if ( m_flags == IsProperty )
{
wxASSERT_MSG( m_ptr.property, wxT("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);
#if wxUSE_WCHAR_T
else if ( m_flags & IsWCharPtr )
return iface->GetPropertyByNameA(m_ptr.wcharName);
#endif
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->GetArrIndex(), 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();
wxPropertyGrid* grid = state->GetGrid();
if ( grid->GetState() == state )
{
bool selRes = grid->DoSelectProperty(NULL, wxPG_SEL_DELETING);
wxPG_CHECK_RET_DBG( selRes,
wxT("failed to deselect a property (editor probably had invalid value)") );
}
state->DoDelete( p );
RefreshGrid(state);
}
// -----------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::ReplaceProperty( wxPGPropArg id, wxPGProperty* property )
{
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
wxPGProperty* replaced = p;
wxCHECK_MSG( replaced && property,
wxNullProperty,
wxT("NULL property") );
wxCHECK_MSG( !replaced->IsCategory(),
wxNullProperty,
wxT("cannot replace this type of property") );
wxCHECK_MSG( !m_pState->IsInNonCatMode(),
wxNullProperty,
wxT("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
// -----------------------------------------------------------------------
bool wxPropertyGridInterface::ClearSelection()
{
wxPropertyGridPageState* state = m_pState;
wxPropertyGrid* pg = state->GetGrid();
if ( pg->GetState() == state )
return pg->DoClearSelection();
else
state->SetSelection(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->m_flags & wxPG_PROP_DISABLED) )
return false;
// If active, Set active Editor.
if ( grid->GetState() == state && p == grid->GetSelection() )
grid->DoSelectProperty( p, wxPG_SEL_FORCE );
}
else
{
if ( p->m_flags & wxPG_PROP_DISABLED )
return false;
// If active, Disable as active Editor.
if ( grid->GetState() == state && p == grid->GetSelection() )
grid->DoSelectProperty( p, wxPG_SEL_FORCE );
}
state->DoEnableProperty(p, enable);
RefreshProperty( p );
return true;
}
// -----------------------------------------------------------------------
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 )
{
if ( !pg->ClearSelection() )
return false;
}
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::SetPropertyValueUnspecified( wxPGPropArg id )
{
wxPG_PROP_ARG_CALL_PROLOG()
wxPropertyGrid* propGrid = p->GetGridIfDisplayed();
if ( propGrid )
propGrid->DoSetPropertyValueUnspecified(p);
else
p->GetParentState()->DoSetPropertyValueUnspecified(p);
}
// -----------------------------------------------------------------------
// 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);
wxPropertyGrid* propGrid = p->GetGridIfDisplayed();
if ( propGrid )
propGrid->DrawItemAndValueRelated( p );
}
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::SetPropertyValueString( wxPGPropArg id, const wxString& value )
{
wxPG_PROP_ARG_CALL_PROLOG()
if ( m_pState->DoSetPropertyValueString(p,value) )
{
wxPropertyGrid* propGrid = p->GetGridIfDisplayed();
if ( propGrid )
propGrid->DrawItemAndValueRelated( p );
}
}
// -----------------------------------------------------------------------
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(wxT("no property with name '%s'"),name.c_str()));
return p;
}
// ----------------------------------------------------------------------------
wxPGProperty* wxPropertyGridInterface::GetPropertyByLabel( const wxString& label ) const
{
wxPGVIterator it;
for ( it = GetVIterator( wxPG_ITERATE_PROPERTIES ); !it.AtEnd(); it.Next() )
{
if ( it.GetProperty()->GetLabel() == label )
return it.GetProperty();
}
return wxNullProperty;
}
// ----------------------------------------------------------------------------
void wxPropertyGridInterface::DoSetPropertyAttribute( wxPGPropArg id, const wxString& name,
wxVariant& value, long argFlags )
{
wxPG_PROP_ARG_CALL_PROLOG()
p->SetAttribute( name, value );
if ( argFlags & wxPG_RECURSE )
{
unsigned int i;
for ( 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->GetFlags() & flags) == flags )
targetArr->push_back((wxPGProperty*)property);
}
else
{
if ( (property->GetFlags() & flags) != flags )
targetArr->push_back((wxPGProperty*)property);
}
}
}
// -----------------------------------------------------------------------
void wxPropertyGridInterface::SetPropertiesFlag( const wxArrayPGProperty& srcArr,
wxPGProperty::FlagType flags,
bool inverse )
{
unsigned int i;
for ( i=0; i<srcArr.size(); i++ )
{
wxPGProperty* property = srcArr[i];
if ( !inverse )
property->SetFlag(flags);
else
property->ClearFlag(flags);
}
// If collapsed flag or hidden was manipulated, we need to update virtual
// size.
wxPropertyGrid* pg = GetPropertyGrid();
if ( flags & (wxPG_PROP_COLLAPSED|wxPG_PROP_HIDDEN) )
{
GetState()->VirtualHeightChanged();
pg->RecalculateVirtualSize();
}
}
// -----------------------------------------------------------------------
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 its "Property.SubProperty" format
int pos = name.Find(wxT('.'));
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)
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::SetPropertyLabel( wxPGPropArg id, const wxString& newproplabel )
{
wxPG_PROP_ARG_CALL_PROLOG()
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();
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;
}
// -----------------------------------------------------------------------
// GetPropertyValueAsXXX methods
#define IMPLEMENT_GET_VALUE(T,TRET,BIGNAME,DEFRETVAL) \
TRET wxPropertyGridInterface::GetPropertyValueAs##BIGNAME( wxPGPropArg id ) const \
{ \
wxPG_PROP_ARG_CALL_PROLOG_RETVAL(DEFRETVAL) \
wxVariant value = p->GetValue(); \
if ( wxStrcmp(value.GetType(), wxPGTypeName_##T) != 0 ) \
{ \
wxPGGetFailed(p,wxPGTypeName_##T); \
return (TRET)DEFRETVAL; \
} \
return (TRET)value.Get##BIGNAME(); \
}
// String is different than 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 ( wxStrcmp(value.GetType(), wxPGTypeName_bool) == 0 )
{
return value.GetBool();
}
if ( wxStrcmp(value.GetType(), wxPGTypeName_long) == 0 )
{
return value.GetLong()?true:false;
}
wxPGGetFailed(p,wxPGTypeName_bool);
return false;
}
IMPLEMENT_GET_VALUE(long,long,Long,0)
IMPLEMENT_GET_VALUE(double,double,Double,0.0)
IMPLEMENT_GET_VALUE(void,void*,VoidPtr,NULL)
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), wxT("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), wxT("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() { 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.Alloc(s.length());
const wxChar* ch = s.c_str();
while (*ch)
{
if (*ch == wxT(';') || *ch == wxT('|') || *ch == wxT(','))
result += wxT('\\');
result += *ch;
++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 )
{
wxArrayPGProperty ptrs;
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;");
}
result.RemoveLast(); // Remove last semicolon
result += wxS("|");
}
// Remove last '|'
if ( result.length() )
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.size() > 0 )
{
if ( pageState->IsDisplayed() )
{
if ( values[0].length() )
newSelection = GetPropertyByName(value);
pgSelectionSet = true;
}
else
{
if ( values[0].length() )
pageState->SetSelection(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
{
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->SelectProperty(newSelection);
else
pg->ClearSelection();
}
if ( selectedPage != -1 )
{
DoSelectPage(selectedPage);
}
if ( vx >= 0 )
{
pg->Scroll(vx, vy);
}
return res;
}
#endif // wxUSE_PROPGRID