///////////////////////////////////////////////////////////////////////////// // Name: props.cpp // Purpose: Basic Property Classes // Author: Jaakko Salli // Modified by: // Created: May-14-2004 // 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 #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/dcclient.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/combobox.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" #endif #include #include #include #define wxPG_CUSTOM_IMAGE_WIDTH 20 // for wxColourProperty etc. // ----------------------------------------------------------------------- // wxStringProperty // ----------------------------------------------------------------------- WX_PG_IMPLEMENT_PROPERTY_CLASS(wxStringProperty,wxBaseProperty, wxString,const wxString&,TextCtrl) wxStringPropertyClass::wxStringPropertyClass( const wxString& label, const wxString& name, const wxString& value ) : wxPGProperty(label,name) { DoSetValue(value); } wxStringPropertyClass::~wxStringPropertyClass() { } void wxStringPropertyClass::DoSetValue( wxPGVariant value ) { m_value = wxPGVariantToString(value); } wxPGVariant wxStringPropertyClass::DoGetValue() const { return wxPGVariant(m_value); } wxString wxStringPropertyClass::GetValueAsString( int argFlags ) const { // If string is password and value is for visual purposes, // then return asterisks instead the actual string. if ( (m_flags & wxPG_PROP_PASSWORD) && !(argFlags & (wxPG_FULL_VALUE|wxPG_EDITABLE_VALUE)) ) return wxString(wxChar('*'), m_value.Length()); return m_value; } bool wxStringPropertyClass::SetValueFromString( const wxString& text, int ) { if ( m_value != text ) return StdValidationProcedure(text); return false; } void wxStringPropertyClass::SetAttribute( int id, wxVariant& value ) { if ( id == wxPG_STRING_PASSWORD ) { m_flags &= ~(wxPG_PROP_PASSWORD); if ( value.GetLong() ) m_flags |= wxPG_PROP_PASSWORD; RecreateEditor(); } } // ----------------------------------------------------------------------- // wxIntProperty // ----------------------------------------------------------------------- wxPG_BEGIN_PROPERTY_CLASS_BODY(wxIntProperty,wxPGProperty,long,long) WX_PG_DECLARE_BASIC_TYPE_METHODS() virtual bool SetValueFromInt( long value, int flags ); #if wxUSE_VALIDATORS static wxValidator* GetClassValidator(); virtual wxValidator* DoGetValidator() const; #endif wxPG_END_PROPERTY_CLASS_BODY() WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty,wxBaseProperty, long,long,TextCtrl) wxIntPropertyClass::wxIntPropertyClass( const wxString& label, const wxString& name, long value ) : wxPGProperty(label,name) { DoSetValue(value); } wxIntPropertyClass::~wxIntPropertyClass() { } void wxIntPropertyClass::DoSetValue( wxPGVariant value ) { m_value = wxPGVariantToLong(value); } wxPGVariant wxIntPropertyClass::DoGetValue() const { return wxPGVariant(m_value); } wxString wxIntPropertyClass::GetValueAsString( int ) const { return wxString::Format(wxT("%li"),m_value); } bool wxIntPropertyClass::SetValueFromString( const wxString& text, int argFlags ) { wxString s; long value; if ( text.length() == 0 ) { SetValueToUnspecified(); return true; } // We know it is a number, but let's still check // the return value. if ( text.IsNumber() && text.ToLong( &value, 0 ) ) { if ( m_value != value ) { return StdValidationProcedure(value); } } else if ( argFlags & wxPG_REPORT_ERROR ) { s.Printf( wxT("! %s: \"%s\" is not a number."), m_label.c_str(), text.c_str() ); ShowError(s); } return false; } bool wxIntPropertyClass::SetValueFromInt( long value, int WXUNUSED(flags) ) { if ( m_value != value ) { m_value = value; return true; } return false; } #if wxUSE_VALIDATORS wxValidator* wxIntPropertyClass::GetClassValidator() { WX_PG_DOGETVALIDATOR_ENTRY() // Atleast wxPython 2.6.2.1 required that the string argument is given static wxString v; wxTextValidator* validator = new wxTextValidator(wxFILTER_NUMERIC,&v); WX_PG_DOGETVALIDATOR_EXIT(validator) } wxValidator* wxIntPropertyClass::DoGetValidator() const { return GetClassValidator(); } #endif // ----------------------------------------------------------------------- // wxUIntProperty // ----------------------------------------------------------------------- #define wxPG_UINT_TEMPLATE_MAX 8 static const wxChar* gs_uintTemplates[wxPG_UINT_TEMPLATE_MAX] = { wxT("%x"),wxT("0x%x"),wxT("$%x"), wxT("%X"),wxT("0x%X"),wxT("$%X"), wxT("%u"),wxT("%o") }; wxPG_BEGIN_PROPERTY_CLASS_BODY(wxUIntProperty,wxBasePropertyClass,long,unsigned long) WX_PG_DECLARE_BASIC_TYPE_METHODS() WX_PG_DECLARE_ATTRIBUTE_METHODS() virtual bool SetValueFromInt ( long value, int flags ); protected: wxByte m_base; wxByte m_realBase; // translated to 8,16,etc. wxByte m_prefix; wxPG_END_PROPERTY_CLASS_BODY() WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty,wxBaseProperty, long,unsigned long,TextCtrl) wxUIntPropertyClass::wxUIntPropertyClass( const wxString& label, const wxString& name, unsigned long value ) : wxBasePropertyClass(label,name) { m_base = 6; // This is magic number for dec base (must be same as in setattribute) m_realBase = 10; m_prefix = wxPG_PREFIX_NONE; DoSetValue((long)value); } wxUIntPropertyClass::~wxUIntPropertyClass() { } void wxUIntPropertyClass::DoSetValue( wxPGVariant value ) { m_value = wxPGVariantToLong(value); } wxPGVariant wxUIntPropertyClass::DoGetValue() const { return wxPGVariant(m_value); } wxString wxUIntPropertyClass::GetValueAsString( int ) const { //return wxString::Format(wxPGGlobalVars->m_uintTemplate.c_str(),m_value); size_t index = m_base + m_prefix; if ( index >= wxPG_UINT_TEMPLATE_MAX ) index = wxPG_BASE_DEC; return wxString::Format(gs_uintTemplates[index],m_value); } bool wxUIntPropertyClass::SetValueFromString( const wxString& text, int WXUNUSED(argFlags) ) { //wxString s; long unsigned value = 0; if ( text.length() == 0 ) { SetValueToUnspecified(); return true; } size_t start = 0; if ( text.length() > 0 && !wxIsalnum(text[0]) ) start++; wxString s = text.substr(start, text.length() - start); bool res = s.ToULong(&value, (unsigned int)m_realBase); //wxChar *end; //value = wxStrtoul(text.c_str() + ((size_t)start), &end, (unsigned int)m_realBase); if ( res && m_value != (long)value ) { return StdValidationProcedure((long)value); } /*} else if ( argFlags & wxPG_REPORT_ERROR ) { s.Printf ( wxT("! %s: \"%s\" is not a number."), m_label.c_str(), text.c_str() ); ShowError(s); }*/ return false; } bool wxUIntPropertyClass::SetValueFromInt( long value, int WXUNUSED(flags) ) { if ( m_value != value ) { m_value = value; return true; } return false; } void wxUIntPropertyClass::SetAttribute( int id, wxVariant& value ) { if ( id == wxPG_UINT_BASE ) { int val = value.GetLong(); m_realBase = (wxByte) val; if ( m_realBase > 16 ) m_realBase = 16; // // Translate logical base to a template array index m_base = 7; // oct if ( val == wxPG_BASE_HEX ) m_base = 3; else if ( val == wxPG_BASE_DEC ) m_base = 6; else if ( val == wxPG_BASE_HEXL ) m_base = 0; } else if ( id == wxPG_UINT_PREFIX ) m_prefix = (wxByte) value.GetLong(); } // ----------------------------------------------------------------------- // wxFloatProperty // ----------------------------------------------------------------------- wxPG_BEGIN_PROPERTY_CLASS_BODY(wxFloatProperty,wxPGProperty,double,double) WX_PG_DECLARE_BASIC_TYPE_METHODS() WX_PG_DECLARE_ATTRIBUTE_METHODS() protected: int m_precision; #if wxUSE_VALIDATORS //static wxValidator* GetClassValidator (); virtual wxValidator* DoGetValidator () const; #endif wxPG_END_PROPERTY_CLASS_BODY() WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty,wxBaseProperty, double,double,TextCtrl) wxFloatPropertyClass::wxFloatPropertyClass( const wxString& label, const wxString& name, double value ) : wxPGProperty(label,name) { m_precision = -1; DoSetValue(value); } wxFloatPropertyClass::~wxFloatPropertyClass() { } void wxFloatPropertyClass::DoSetValue( wxPGVariant value ) { m_value = wxPGVariantToDouble(value); } wxPGVariant wxFloatPropertyClass::DoGetValue() const { return wxPGVariant(m_value); } // This helper method provides standard way for floating point-using // properties to convert values to string. void wxPropertyGrid::DoubleToString(wxString& target, double value, int precision, bool removeZeroes, wxString* precTemplate) { if ( precision >= 0 ) { wxString text1; if (!precTemplate) precTemplate = &text1; if ( !precTemplate->length() ) { *precTemplate = wxT("%."); *precTemplate << wxString::Format( wxT("%i"), precision ); *precTemplate << wxT('f'); } target.Printf( precTemplate->c_str(), value ); } else { target.Printf( wxT("%f"), value ); } if ( removeZeroes && precision != 0 && target.length() ) { // Remove excess zeroes (do not remove this code just yet, // since sprintf can't do the same consistently across platforms). wxString::const_iterator i = target.end() - 1; size_t new_len = target.length() - 1; for ( ; i != target.begin(); i-- ) { if ( wxPGGetIterChar(target, i) != wxT('0') ) break; new_len--; } wxChar cur_char = wxPGGetIterChar(target, i); if ( cur_char != wxT('.') && cur_char != wxT(',') ) new_len++; if ( new_len != target.length() ) target.resize(new_len); /* unsigned int cur_pos = target.length() - 1; wxChar a; a = target.GetChar( cur_pos ); while ( a == wxT('0') && cur_pos > 0 ) { cur_pos--; a = target.GetChar( cur_pos ); } wxChar cur_char = target.GetChar( cur_pos ); if ( cur_char != wxT('.') && cur_char != wxT(',') ) cur_pos += 1; if ( cur_pos < target.length() ) target.Truncate( cur_pos ); */ } } wxString wxFloatPropertyClass::GetValueAsString( int argFlags ) const { wxString text; wxPropertyGrid::DoubleToString(text,m_value, m_precision, !(argFlags & wxPG_FULL_VALUE), (wxString*) NULL); return text; } bool wxFloatPropertyClass::SetValueFromString( const wxString& text, int argFlags ) { wxString s; double value; if ( text.length() == 0 ) { SetValueToUnspecified(); return true; } bool res = text.ToDouble(&value); if ( res ) { if ( m_value != value ) { m_value = value; return true; } } else if ( argFlags & wxPG_REPORT_ERROR ) { ShowError(wxString::Format( _("\"%s\" is not a floating-point number"), text.c_str() )); } return false; } void wxFloatPropertyClass::SetAttribute( int id, wxVariant& value ) { if ( id == wxPG_FLOAT_PRECISION ) { m_precision = value.GetLong(); } } #if wxUSE_VALIDATORS wxValidator* wxFloatPropertyClass::DoGetValidator() const { return wxIntPropertyClass::GetClassValidator(); } #endif // ----------------------------------------------------------------------- // wxBoolProperty // ----------------------------------------------------------------------- wxPG_BEGIN_PROPERTY_CLASS_BODY2(wxBoolPropertyClass,wxPGProperty,bool,long,bool,class) WX_PG_DECLARE_BASIC_TYPE_METHODS() WX_PG_DECLARE_CHOICE_METHODS() WX_PG_DECLARE_ATTRIBUTE_METHODS() wxPG_END_PROPERTY_CLASS_BODY() // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since // there is a custom GetEditorClass. WX_PG_IMPLEMENT_CONSTFUNC(wxBoolProperty,bool) WX_PG_IMPLEMENT_CLASSINFO(wxBoolProperty,wxBasePropertyClass) wxPG_GETCLASSNAME_IMPLEMENTATION(wxBoolProperty) wxPG_VALUETYPE_MSGVAL wxBoolPropertyClass::GetValueType() const { return wxPG_VALUETYPE(bool); } const wxChar* wxPG_ClassName_wxBoolProperty = wxBoolProperty_ClassName; const wxPGEditor* wxBoolPropertyClass::DoGetEditorClass() const { // Select correct editor control. #if wxPG_INCLUDE_CHECKBOX if ( !(m_flags & wxPG_PROP_USE_CHECKBOX) ) return wxPG_EDITOR(Choice); return wxPG_EDITOR(CheckBox); #else return wxPG_EDITOR(Choice); #endif } wxBoolPropertyClass::wxBoolPropertyClass( const wxString& label, const wxString& name, bool value ) : wxPGProperty(label,name) { int useVal; if ( value ) useVal = 1; else useVal = 0; DoSetValue((long)useVal); m_flags |= wxPG_PROP_USE_DCC; } wxBoolPropertyClass::~wxBoolPropertyClass() { } void wxBoolPropertyClass::DoSetValue( wxPGVariant value ) { long v = wxPGVariantToLong(value); if ( v == 2 ) SetValueToUnspecified(); else if ( v != 0 ) m_value = 1; else m_value = 0; } wxPGVariant wxBoolPropertyClass::DoGetValue() const { return wxPGVariant(m_value); } wxString wxBoolPropertyClass::GetValueAsString( int argFlags ) const { if ( !(argFlags & wxPG_FULL_VALUE) ) { return wxPGGlobalVars->m_boolChoices[m_value]; } wxString text; if (m_value) text = wxT("true"); else text = wxT("false"); return text; } int wxBoolPropertyClass::GetChoiceInfo( wxPGChoiceInfo* choiceinfo ) { if ( choiceinfo ) { // 3 choice mode (ie. true, false, unspecified) does not work well (yet). //choiceinfo->m_itemCount = wxPGGlobalVars->m_numBoolChoices; choiceinfo->m_itemCount = 2; choiceinfo->m_arrWxString = wxPGGlobalVars->m_boolChoices; } return m_value; } bool wxBoolPropertyClass::SetValueFromString( const wxString& text, int /*argFlags*/ ) { int value = 0; if ( text.CmpNoCase(wxPGGlobalVars->m_boolChoices[1]) == 0 || text.CmpNoCase(wxT("true")) == 0 ) value = 1; if ( text.length() == 0 ) { SetValueToUnspecified(); return true; } if ( (m_value && !value) || (!m_value && value) ) { DoSetValue( (long) value ); return true; } /* else if ( argFlags & wxPG_REPORT_ERROR ) { wxLogError ( wxT("Property %s: \"%s\" is not a boolean value (True and False are valid)."), m_label.c_str(), text.c_str() ); } */ return false; } bool wxBoolPropertyClass::SetValueFromInt( long value, int ) { if ( value != 0 ) value = 1; if ( (m_value && !value) || (!m_value && value) ) { // (wxPG_BOOLPROP_VAL_INTERNAL_LONG) m_value = value; return true; } return false; } void wxBoolPropertyClass::SetAttribute( int id, wxVariant& value ) { int ival = value.GetLong(); #if wxPG_INCLUDE_CHECKBOX if ( id == wxPG_BOOL_USE_CHECKBOX ) { if ( ival ) m_flags |= wxPG_PROP_USE_CHECKBOX; else m_flags &= ~(wxPG_PROP_USE_CHECKBOX); } //else #endif if ( id == wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING ) { if ( ival ) m_flags |= wxPG_PROP_USE_DCC; else m_flags &= ~(wxPG_PROP_USE_DCC); } } // ----------------------------------------------------------------------- // wxBaseEnumPropertyClass // ----------------------------------------------------------------------- // Class body is in propdev.h. wxBaseEnumPropertyClass::wxBaseEnumPropertyClass( const wxString& label, const wxString& name ) : wxPGProperty(label,name) { } /** If has values array, then returns number at index with value - otherwise just returns the value. */ int wxBaseEnumPropertyClass::GetIndexForValue( int value ) const { return value; } void wxBaseEnumPropertyClass::DoSetValue( wxPGVariant value ) { int intval = (int) value.GetLong(); m_index = GetIndexForValue(intval); } wxPGVariant wxBaseEnumPropertyClass::DoGetValue() const { if ( m_index < 0 ) return wxPGVariant((long)-1); int val; GetEntry(m_index,&val); return wxPGVariantCreator(val); } wxString wxBaseEnumPropertyClass::GetValueAsString( int ) const { if ( m_index >= 0 ) { int unused_val; const wxString* pstr = GetEntry( m_index, &unused_val ); if ( pstr ) return *pstr; } return wxEmptyString; } bool wxBaseEnumPropertyClass::SetValueFromString ( const wxString& text, int WXUNUSED(argFlags) ) { size_t i = 0; const wxString* entry_label; int entry_value; int use_index = -1; long use_value = 0; entry_label = GetEntry(i,&entry_value); while ( entry_label ) { if ( text.CmpNoCase(*entry_label) == 0 ) { use_index = (int)i; use_value = (long)entry_value; break; } i++; entry_label = GetEntry(i,&entry_value); } if ( m_index != use_index ) { if ( use_index != -1 ) // FIXME: Why can't this be virtual call? wxBaseEnumPropertyClass::DoSetValue ( use_value ); else m_index = -1; return true; } /*} else if ( argFlags & wxPG_REPORT_ERROR ) { wxString s; s.Printf ( wxT("\"%s\" was not among valid choices."), text.c_str() ); ShowError(s); }*/ return false; } bool wxBaseEnumPropertyClass::SetValueFromInt ( long value, int argFlags ) { if ( argFlags & wxPG_FULL_VALUE ) { DoSetValue(value); return true; } else { if ( m_index != value ) { m_index = value; return true; } } return false; } // ----------------------------------------------------------------------- // wxEnumProperty // ----------------------------------------------------------------------- // Class body is in propdev.h. wxPGProperty* wxEnumProperty( const wxString& label, const wxString& name, const wxChar** labels, const long* values, int value ) { return new wxEnumPropertyClass (label,name,labels,values,value); } wxPGProperty* wxEnumProperty( const wxString& label, const wxString& name, const wxArrayString& labels, const wxArrayInt& values, int value ) { return new wxEnumPropertyClass(label,name,labels,values,value); } wxPGProperty* wxEnumProperty( const wxString& label, const wxString& name, const wxArrayString& labels, int value ) { return new wxEnumPropertyClass (label,name,labels,*((const wxArrayInt*)NULL),value); } wxPGProperty* wxEnumProperty( const wxString& label, const wxString& name, wxPGChoices& choices, int value ) { return new wxEnumPropertyClass (label,name,choices,value); } WX_PG_IMPLEMENT_CLASSINFO(wxEnumProperty,wxBasePropertyClass) WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty,long,Choice) wxEnumPropertyClass::wxEnumPropertyClass ( const wxString& label, const wxString& name, const wxChar** labels, const long* values, int value ) : wxBaseEnumPropertyClass(label,name) { m_index = 0; if ( labels ) { m_choices.Add(labels,values); if ( GetItemCount() ) wxEnumPropertyClass::DoSetValue( (long)value ); } } wxEnumPropertyClass::wxEnumPropertyClass ( const wxString& label, const wxString& name, const wxChar** labels, const long* values, wxPGChoices* choicesCache, int value ) : wxBaseEnumPropertyClass(label,name) { m_index = 0; wxASSERT( choicesCache ); if ( choicesCache->IsOk() ) { m_choices.Assign( *choicesCache ); } else if ( labels ) { m_choices.Add(labels,values); if ( GetItemCount() ) wxEnumPropertyClass::DoSetValue( (long)value ); } } wxEnumPropertyClass::wxEnumPropertyClass ( const wxString& label, const wxString& name, const wxArrayString& labels, const wxArrayInt& values, int value ) : wxBaseEnumPropertyClass(label,name) { m_index = 0; if ( &labels ) { wxPGChoices choices(labels,values); m_choices = choices.ExtractData(); if ( GetItemCount() ) wxEnumPropertyClass::DoSetValue( (long)value ); } } wxEnumPropertyClass::wxEnumPropertyClass ( const wxString& label, const wxString& name, wxPGChoices& choices, int value ) : wxBaseEnumPropertyClass(label,name) { m_choices.Assign( choices ); if ( GetItemCount() ) wxEnumPropertyClass::DoSetValue( (long)value ); } int wxEnumPropertyClass::GetIndexForValue( int value ) const { if ( !m_choices.IsOk() ) return -1; const wxArrayInt& arrValues = m_choices.GetValues(); if ( arrValues.GetCount() ) { int intval = arrValues.Index(value); // TODO: Use real default instead of 0. if ( intval < 0 ) intval = 0; return intval; } return value; } wxEnumPropertyClass::~wxEnumPropertyClass () { } const wxString* wxEnumPropertyClass::GetEntry( size_t index, int* pvalue ) const { if ( m_choices.IsOk() && index < m_choices.GetCount() ) { const wxArrayInt& arrValues = m_choices.GetValues(); int value = (int)index; if ( arrValues.GetCount() ) value = arrValues[index]; *pvalue = value; return &m_choices.GetLabel(index); } return (const wxString*) NULL; } int wxEnumPropertyClass::GetChoiceInfo( wxPGChoiceInfo* choiceinfo ) { if ( choiceinfo ) { if ( !(m_flags & wxPG_PROP_STATIC_CHOICES) ) choiceinfo->m_choices = &m_choices; if ( !m_choices.IsOk() ) return -1; choiceinfo->m_itemCount = m_choices.GetCount(); if ( m_choices.GetCount() ) choiceinfo->m_arrWxString = (wxString*)&m_choices.GetLabel(0); } if ( !m_choices.IsOk() ) return -1; return m_index; } // ----------------------------------------------------------------------- // wxEditEnumProperty // ----------------------------------------------------------------------- class wxEditEnumPropertyClass : public wxEnumPropertyClass { WX_PG_DECLARE_PROPERTY_CLASS() public: wxEditEnumPropertyClass( const wxString& label, const wxString& name, const wxChar** labels, const long* values, const wxString& value ); wxEditEnumPropertyClass( const wxString& label, const wxString& name, const wxArrayString& labels, const wxArrayInt& values, const wxString& value ); wxEditEnumPropertyClass( const wxString& label, const wxString& name, wxPGChoices& choices, const wxString& value ); // Special constructor for caching choices (used by derived class) wxEditEnumPropertyClass( const wxString& label, const wxString& name, const wxChar** labels, const long* values, wxPGChoices* choicesCache, const wxString& value ); WX_PG_DECLARE_BASIC_TYPE_METHODS() int GetChoiceInfo( wxPGChoiceInfo* choiceinfo ); virtual ~wxEditEnumPropertyClass (); protected: wxString m_value_wxString; }; wxPGProperty* wxEditEnumProperty( const wxString& label, const wxString& name, const wxChar** labels, const long* values, const wxString& value ) { return new wxEditEnumPropertyClass(label,name,labels,values,value); } wxPGProperty* wxEditEnumProperty( const wxString& label, const wxString& name, const wxArrayString& labels, const wxArrayInt& values, const wxString& value ) { return new wxEditEnumPropertyClass(label,name,labels,values,value); } wxPGProperty* wxEditEnumProperty( const wxString& label, const wxString& name, const wxArrayString& labels, const wxString& value ) { return new wxEditEnumPropertyClass(label,name,labels,*((const wxArrayInt*)NULL),value); } wxPGProperty* wxEditEnumProperty( const wxString& label, const wxString& name, wxPGChoices& choices, const wxString& value ) { return new wxEditEnumPropertyClass(label,name,choices,value); } WX_PG_IMPLEMENT_CLASSINFO(wxEditEnumProperty,wxBasePropertyClass) WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty,wxString,ComboBox) wxEditEnumPropertyClass::wxEditEnumPropertyClass( const wxString& label, const wxString& name, const wxChar** labels, const long* values, const wxString& value ) : wxEnumPropertyClass(label,name,labels,values,0) { wxEditEnumPropertyClass::DoSetValue( value ); } wxEditEnumPropertyClass::wxEditEnumPropertyClass( const wxString& label, const wxString& name, const wxChar** labels, const long* values, wxPGChoices* choicesCache, const wxString& value ) : wxEnumPropertyClass(label,name,labels,values,choicesCache,0) { wxEditEnumPropertyClass::DoSetValue( value ); } wxEditEnumPropertyClass::wxEditEnumPropertyClass( const wxString& label, const wxString& name, const wxArrayString& labels, const wxArrayInt& values, const wxString& value ) : wxEnumPropertyClass(label,name,labels,values,0) { wxEditEnumPropertyClass::DoSetValue( value ); } wxEditEnumPropertyClass::wxEditEnumPropertyClass( const wxString& label, const wxString& name, wxPGChoices& choices, const wxString& value ) : wxEnumPropertyClass(label,name,choices,0) { wxEditEnumPropertyClass::DoSetValue( value ); } wxEditEnumPropertyClass::~wxEditEnumPropertyClass() { } void wxEditEnumPropertyClass::DoSetValue( wxPGVariant value ) { m_value_wxString = wxPGVariantToString(value); } wxPGVariant wxEditEnumPropertyClass::DoGetValue() const { return wxPGVariant(m_value_wxString); } wxString wxEditEnumPropertyClass::GetValueAsString( int ) const { return m_value_wxString; } bool wxEditEnumPropertyClass::SetValueFromString( const wxString& text, int ) { if ( m_value_wxString != text ) return StdValidationProcedure(text); return false; } int wxEditEnumPropertyClass::GetChoiceInfo( wxPGChoiceInfo* choiceinfo ) { wxEnumPropertyClass::GetChoiceInfo(choiceinfo); // However, select index using the current value wxPGChoices& choices = m_choices; const wxString& value = m_value_wxString; int index = -1; unsigned int k; for ( k=0; kGetParentState(); parent = parent->GetParent(); } wxASSERT( state ); if ( state ) { wxPGProperty* selected = state->GetSelection(); if ( selected ) { if ( selected->GetParent() == this ) oldSel = selected->GetArrIndex(); else if ( selected == this ) oldSel = -2; } } state->ClearSelection(); } // Delete old children for ( i=0; im_autoGetTranslation ) { bool_prop = wxBoolProperty( ::wxGetTranslation ( GetLabel(i) ), wxEmptyString, child_val ); } else #endif { bool_prop = wxBoolProperty( GetLabel(i), wxEmptyString, child_val ); } AddChild(bool_prop); } m_oldChoicesData = m_choices.GetDataPtr(); } if ( prevChildCount ) SubPropsChanged(oldSel); } wxFlagsPropertyClass::wxFlagsPropertyClass ( const wxString& label, const wxString& name, const wxChar** labels, const long* values, long value ) : wxPGPropertyWithChildren(label,name) { m_value = 0; m_oldChoicesData = (wxPGChoicesData*) NULL; if ( labels ) { m_choices.Set(labels,values); wxASSERT ( GetItemCount() ); DoSetValue( value ); } } wxFlagsPropertyClass::wxFlagsPropertyClass ( const wxString& label, const wxString& name, const wxArrayString& labels, const wxArrayInt& values, int value ) : wxPGPropertyWithChildren(label,name) { m_value = 0; m_oldChoicesData = (wxPGChoicesData*) NULL; if ( &labels ) { m_choices.Set(labels,values); wxASSERT( GetItemCount() ); DoSetValue( (long)value ); } } wxFlagsPropertyClass::wxFlagsPropertyClass ( const wxString& label, const wxString& name, wxPGChoices& choices, long value ) : wxPGPropertyWithChildren(label,name) { m_oldChoicesData = (wxPGChoicesData*) NULL; m_choices.Assign(choices); wxASSERT ( GetItemCount() ); DoSetValue( value ); } wxFlagsPropertyClass::~wxFlagsPropertyClass () { //wxPGUnRefChoices(m_choices); } void wxFlagsPropertyClass::DoSetValue ( wxPGVariant value ) { if ( !m_choices.IsOk() || !GetItemCount() ) { m_value = 0; return; } long val = value.GetLong(); long full_flags = 0; // normalize the value (i.e. remove extra flags) unsigned int i; const wxArrayInt& values = GetValues(); if ( values.GetCount() ) { for ( i = 0; i < GetItemCount(); i++ ) full_flags |= values[i]; } else { for ( i = 0; i < GetItemCount(); i++ ) full_flags |= (1< 1 ) text.Truncate ( text.Len() - 2 ); return text; } // Translate string into flag tokens bool wxFlagsPropertyClass::SetValueFromString ( const wxString& text, int ) { if ( !m_choices.IsOk() || !GetItemCount() ) return false; long new_flags = 0; // semicolons are no longer valid delimeters WX_PG_TOKENIZER1_BEGIN(text,wxT(',')) if ( token.length() ) { // Determine which one it is long bit = IdToBit( token ); if ( bit != -1 ) { // Changed? new_flags |= bit; } else { // Unknown identifier wxString s; s.Printf ( wxT("! %s: Unknown flag identifier \"%s\""), m_label.c_str(), token.c_str() ); ShowError(s); } } WX_PG_TOKENIZER1_END() if ( new_flags != m_value ) { // Set child modified states unsigned int i; const wxArrayInt& values = GetValues(); if ( values.GetCount() ) for ( i = 0; i < GetItemCount(); i++ ) { long flag = values[i]; if ( (new_flags & flag) != (m_value & flag) ) ((wxPGProperty*)m_children.Item( i ))->SetFlag ( wxPG_PROP_MODIFIED ); } else for ( i = 0; i < GetItemCount(); i++ ) { long flag = (1<SetFlag ( wxPG_PROP_MODIFIED ); } DoSetValue ( new_flags ); return TRUE; } return FALSE; } // Converts string id to a relevant bit. long wxFlagsPropertyClass::IdToBit ( const wxString& id ) const { unsigned int i; const wxArrayInt& values = GetValues(); for ( i = 0; i < GetItemCount(); i++ ) { #if wxCHECK_VERSION(2,9,0) const wxString ptr = GetLabel(i); #else const wxChar* ptr = GetLabel(i); #endif if ( id == ptr ) { //*pindex = i; if ( values.GetCount() ) return values[i]; return (1<DoSetValue ( ((long)((flags & values[i])?TRUE:FALSE)) ); else for ( i = 0; i < GetItemCount(); i++ ) Item(i)->DoSetValue ( ((long)((flags & (1<GetParent() ); const wxArrayInt& values = GetValues(); long val = p->DoGetValue().GetLong(); // bypass type checking unsigned int iip = p->GetIndexInParent(); unsigned long vi = (1<m_choices = &m_choices; return -1; } // ----------------------------------------------------------------------- // wxDirProperty // ----------------------------------------------------------------------- class wxDirPropertyClass : public wxLongStringPropertyClass { WX_PG_DECLARE_DERIVED_PROPERTY_CLASS() public: wxDirPropertyClass( const wxString& name, const wxString& label, const wxString& value ); virtual ~wxDirPropertyClass(); WX_PG_DECLARE_ATTRIBUTE_METHODS() WX_PG_DECLARE_VALIDATOR_METHODS() virtual bool OnButtonClick ( wxPropertyGrid* propGrid, wxString& value ); protected: wxString m_dlgMessage; }; WX_PG_IMPLEMENT_DERIVED_PROPERTY_CLASS(wxDirProperty,wxLongStringProperty,const wxString&) wxDirPropertyClass::wxDirPropertyClass( const wxString& name, const wxString& label, const wxString& value ) : wxLongStringPropertyClass(name,label,value) { m_flags |= wxPG_NO_ESCAPE; } wxDirPropertyClass::~wxDirPropertyClass() { } #if wxUSE_VALIDATORS wxValidator* wxDirPropertyClass::DoGetValidator() const { return wxFilePropertyClass::GetClassValidator(); } #endif bool wxDirPropertyClass::OnButtonClick( wxPropertyGrid* propGrid, wxString& value ) { wxSize dlg_sz(300,400); wxDirDialog dlg( propGrid, m_dlgMessage.length() ? m_dlgMessage : wxString(_("Choose a directory:")), value, 0, #if !wxPG_SMALL_SCREEN propGrid->GetGoodEditorDialogPosition(this,dlg_sz), dlg_sz ); #else wxDefaultPosition, wxDefaultSize ); #endif if ( dlg.ShowModal() == wxID_OK ) { value = dlg.GetPath(); return true; } return false; } void wxDirPropertyClass::SetAttribute( int id, wxVariant& value ) { if ( id == wxPG_DIR_DIALOG_MESSAGE ) { m_dlgMessage = value.GetString(); } } // ----------------------------------------------------------------------- // wxFileProperty // ----------------------------------------------------------------------- // Class body is in propdev.h. WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty,wxBaseProperty, wxString,const wxString&,TextCtrlAndButton) wxFilePropertyClass::wxFilePropertyClass( const wxString& label, const wxString& name, const wxString& value ) : wxPGProperty(label,name) { m_wildcard = _("All files (*.*)|*.*"); m_flags |= wxPG_PROP_SHOW_FULL_FILENAME; m_indFilter = -1; DoSetValue(value); } wxFilePropertyClass::~wxFilePropertyClass() {} #if wxUSE_VALIDATORS wxValidator* wxFilePropertyClass::GetClassValidator() { WX_PG_DOGETVALIDATOR_ENTRY() // Atleast wxPython 2.6.2.1 required that the string argument is given static wxString v; wxTextValidator* validator = new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST,&v); wxArrayString exChars; exChars.Add(wxT("?")); exChars.Add(wxT("*")); exChars.Add(wxT("|")); exChars.Add(wxT("<")); exChars.Add(wxT(">")); exChars.Add(wxT("\"")); validator->SetExcludes(exChars); WX_PG_DOGETVALIDATOR_EXIT(validator) } wxValidator* wxFilePropertyClass::DoGetValidator() const { return GetClassValidator(); } #endif void wxFilePropertyClass::DoSetValue( wxPGVariant value ) { const wxString& str = wxPGVariantToString(value); m_fnstr = str; m_filename = str; if ( !m_filename.HasName() ) { m_fnstr = wxEmptyString; m_filename.Clear(); } // Find index for extension. if ( m_indFilter < 0 && m_fnstr.length() ) { wxString ext = m_filename.GetExt(); int curind = 0; size_t pos = 0; size_t len = m_wildcard.length(); pos = m_wildcard.find(wxT("|"), pos); while ( pos != wxString::npos && pos < (len-3) ) { size_t ext_begin = pos + 3; pos = m_wildcard.find(wxT("|"), ext_begin); if ( pos == wxString::npos ) pos = len; wxString found_ext = m_wildcard.substr(ext_begin, pos-ext_begin); if ( found_ext.length() > 0 ) { if ( found_ext[0] == wxT('*') ) { m_indFilter = curind; break; } if ( ext.CmpNoCase(found_ext) == 0 ) { m_indFilter = curind; break; } } if ( pos != len ) pos = m_wildcard.find(wxT("|"), pos+1); curind++; } /* wxChar a = wxT(' '); const wxChar* p = m_wildcard.c_str(); wxString ext = m_filename.GetExt(); int curind = 0; do { while ( a && a != wxT('|') ) { a = *p; p++; } if ( !a ) break; a = *p; p++; if ( !a ) break; a = *p; p++; const wxChar* ext_begin = p; if ( *ext_begin == wxT('*') ) { m_indFilter = curind; break; } while ( a && a != '|' ) { a = *p; p++; } a = wxT(' '); int count = p-ext_begin-1; if ( count > 0 ) { wxASSERT( count < 32 ); wxString found_ext = m_wildcard.Mid(ext_begin-m_wildcard.c_str(),count); if ( ext.CmpNoCase(found_ext) == 0 ) { m_indFilter = curind; break; } } curind++; } while ( a ); */ } } wxPGVariant wxFilePropertyClass::DoGetValue() const { return wxPGVariant(m_fnstr); } wxString wxFilePropertyClass::GetValueAsString( int argFlags ) const { if ( argFlags & wxPG_FULL_VALUE ) { return m_filename.GetFullPath(); } else if ( m_flags & wxPG_PROP_SHOW_FULL_FILENAME ) { if ( m_basePath.Length() ) { wxFileName fn2(m_filename); fn2.MakeRelativeTo(m_basePath); return fn2.GetFullPath(); } return m_filename.GetFullPath(); } return m_filename.GetFullName(); } bool wxFilePropertyClass::OnEvent( wxPropertyGrid* propGrid, wxWindow* primary, wxEvent& event ) { if ( event.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED ) { // If text in control is changed, then update it to value. PrepareValueForDialogEditing(propGrid); wxString path; path = m_filename.GetPath(); wxFileDialog dlg( propGrid, m_dlgTitle.length() ? m_dlgTitle : wxString(_("Choose a file")), !m_initialPath.empty() ? m_initialPath : m_filename.GetPath(), wxEmptyString, m_wildcard, 0, wxDefaultPosition ); if ( m_indFilter >= 0 ) dlg.SetFilterIndex( m_indFilter ); if ( dlg.ShowModal() == wxID_OK ) { m_indFilter = dlg.GetFilterIndex(); wxString path = dlg.GetPath(); SetValueFromString( path, wxPG_FULL_VALUE ); if ( primary ) GetEditorClass()->SetControlStringValue( primary, GetValueAsString(0) ); return true; } } return false; } bool wxFilePropertyClass::SetValueFromString( const wxString& text, int argFlags ) { if ( (m_flags & wxPG_PROP_SHOW_FULL_FILENAME) || (argFlags & wxPG_FULL_VALUE) ) { if ( m_filename != text ) { return StdValidationProcedure( text ); } } else { if ( m_filename.GetFullName() != text ) { wxFileName fn = m_filename; fn.SetFullName(text); wxString val = fn.GetFullPath(); return StdValidationProcedure( val ); } } return false; } void wxFilePropertyClass::SetAttribute( int id, wxVariant& value ) { if ( id == wxPG_FILE_SHOW_FULL_PATH ) { if ( value.GetLong() ) m_flags |= wxPG_PROP_SHOW_FULL_FILENAME; else m_flags &= ~(wxPG_PROP_SHOW_FULL_FILENAME); } else if ( id == wxPG_FILE_WILDCARD ) { m_wildcard = value.GetString(); } else if ( id == wxPG_FILE_SHOW_RELATIVE_PATH ) { m_basePath = value.GetString(); } else if ( id == wxPG_FILE_INITIAL_PATH ) { m_initialPath = value.GetString(); } else if ( id == wxPG_FILE_DIALOG_TITLE ) { m_dlgTitle = value.GetString(); } } // ----------------------------------------------------------------------- // wxLongStringProperty // ----------------------------------------------------------------------- // Class body is in propdev.h. WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty,wxBaseProperty, wxString,const wxString&,TextCtrlAndButton) wxLongStringPropertyClass::wxLongStringPropertyClass( const wxString& label, const wxString& name, const wxString& value ) : wxBasePropertyClass(label,name) { DoSetValue(value); } wxLongStringPropertyClass::~wxLongStringPropertyClass() {} void wxLongStringPropertyClass::DoSetValue( wxPGVariant value ) { m_value = wxPGVariantToString(value); } wxPGVariant wxLongStringPropertyClass::DoGetValue() const { return wxPGVariant(m_value); } wxString wxLongStringPropertyClass::GetValueAsString( int ) const { return m_value; } bool wxLongStringPropertyClass::OnEvent( wxPropertyGrid* propGrid, wxWindow* primary, wxEvent& event ) { if ( event.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED ) { // Update the value PrepareValueForDialogEditing(propGrid); wxString val1 = GetValueAsString(0); wxString val_orig = val1; wxString value; if ( !(m_flags & wxPG_PROP_NO_ESCAPE) ) wxPropertyGrid::ExpandEscapeSequences(value,val1); else value = wxString(val1); // Run editor dialog. if ( OnButtonClick(propGrid,value) ) { if ( !(m_flags & wxPG_PROP_NO_ESCAPE) ) wxPropertyGrid::CreateEscapeSequences(val1,value); else val1 = value; if ( val1 != val_orig ) { SetValueFromString ( val1, 0 ); UpdateControl ( primary ); return true; } } } return false; } bool wxLongStringPropertyClass::OnButtonClick( wxPropertyGrid* propGrid, wxString& value ) { // launch editor dialog wxDialog* dlg = new wxDialog(propGrid,-1,m_label,wxDefaultPosition,wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxCLIP_CHILDREN); dlg->SetFont(propGrid->GetFont()); // To allow entering chars of the same set as the propGrid // Multi-line text editor dialog. #if !wxPG_SMALL_SCREEN const int spacing = 8; #else const int spacing = 4; #endif wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL ); wxBoxSizer* rowsizer = new wxBoxSizer( wxHORIZONTAL ); wxTextCtrl* ed = new wxTextCtrl(dlg,11,value, wxDefaultPosition,wxDefaultSize,wxTE_MULTILINE); rowsizer->Add( ed, 1, wxEXPAND|wxALL, spacing ); topsizer->Add( rowsizer, 1, wxEXPAND, 0 ); rowsizer = new wxBoxSizer( wxHORIZONTAL ); const int but_sz_flags = wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT; rowsizer->Add( new wxButton(dlg,wxID_OK,_("Ok")), 0, but_sz_flags, spacing ); rowsizer->Add( new wxButton(dlg,wxID_CANCEL,_("Cancel")), 0, but_sz_flags, spacing ); topsizer->Add( rowsizer, 0, wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL, 0 ); dlg->SetSizer( topsizer ); topsizer->SetSizeHints( dlg ); #if !wxPG_SMALL_SCREEN dlg->SetSize(400,300); dlg->Move( propGrid->GetGoodEditorDialogPosition(this,dlg->GetSize()) ); #endif int res = dlg->ShowModal(); if ( res == wxID_OK ) { value = ed->GetValue(); dlg->Destroy(); return true; } dlg->Destroy(); return false; } bool wxLongStringPropertyClass::SetValueFromString( const wxString& text, int ) { if ( m_value != text ) { DoSetValue ( text ); return true; } return false; } // ----------------------------------------------------------------------- // wxArrayEditorDialog // ----------------------------------------------------------------------- BEGIN_EVENT_TABLE(wxArrayEditorDialog, wxDialog) EVT_IDLE(wxArrayEditorDialog::OnIdle) EVT_LISTBOX(24, wxArrayEditorDialog::OnListBoxClick) EVT_TEXT_ENTER(21, wxArrayEditorDialog::OnAddClick) EVT_BUTTON(22, wxArrayEditorDialog::OnAddClick) EVT_BUTTON(23, wxArrayEditorDialog::OnDeleteClick) EVT_BUTTON(25, wxArrayEditorDialog::OnUpClick) EVT_BUTTON(26, wxArrayEditorDialog::OnDownClick) EVT_BUTTON(27, wxArrayEditorDialog::OnUpdateClick) //EVT_BUTTON(28, wxArrayEditorDialog::OnCustomEditClick) END_EVENT_TABLE() IMPLEMENT_ABSTRACT_CLASS(wxArrayEditorDialog, wxDialog) #include // ----------------------------------------------------------------------- void wxArrayEditorDialog::OnIdle(wxIdleEvent& event) { // // Do control focus detection here. // wxWindow* focused = FindFocus(); // This strange focus thing is a workaround for wxGTK wxListBox focus // reporting bug. if ( m_curFocus == 0 && focused != m_edValue && focused != m_butAdd && focused != m_butUpdate && m_lbStrings->GetSelection() >= 0 ) { //wxLogDebug(wxT("Focused: %s"),focused?focused->GetClassInfo()->GetClassName():wxT("NULL")); // ListBox was just focused. m_butAdd->Enable(false); m_butUpdate->Enable(false); m_butRemove->Enable(true); m_butUp->Enable(true); m_butDown->Enable(true); m_curFocus = 1; } else if ( (m_curFocus == 1 && focused == m_edValue) /*|| m_curFocus == 2*/ ) { //wxLogDebug(wxT("Focused: %s"),focused?focused->GetClassInfo()->GetClassName():wxT("NULL")); // TextCtrl was just focused. m_butAdd->Enable(true); bool upd_enable = false; if ( m_lbStrings->GetCount() && m_lbStrings->GetSelection() >= 0 ) upd_enable = true; m_butUpdate->Enable(upd_enable); m_butRemove->Enable(false); m_butUp->Enable(false); m_butDown->Enable(false); m_curFocus = 0; } event.Skip(); } // ----------------------------------------------------------------------- wxArrayEditorDialog::wxArrayEditorDialog() : wxDialog() { Init(); } // ----------------------------------------------------------------------- void wxArrayEditorDialog::Init() { m_custBtText = (const wxChar*) NULL; //m_pCallingClass = (wxArrayStringPropertyClass*) NULL; } // ----------------------------------------------------------------------- wxArrayEditorDialog::wxArrayEditorDialog( wxWindow *parent, const wxString& message, const wxString& caption, long style, const wxPoint& pos, const wxSize& sz ) : wxDialog() { Init(); Create(parent,message,caption,style,pos,sz); } // ----------------------------------------------------------------------- bool wxArrayEditorDialog::Create( wxWindow *parent, const wxString& message, const wxString& caption, long style, const wxPoint& pos, const wxSize& sz ) { // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION // FIXME: This should be only a temporary fix. #ifdef __WXMAC__ int useStyle = wxCAPTION; #else int useStyle = style; #endif bool res = wxDialog::Create(parent, wxID_ANY, caption, pos, sz, useStyle); SetFont(parent->GetFont()); // To allow entering chars of the same set as the propGrid #if !wxPG_SMALL_SCREEN const int spacing = 4; #else const int spacing = 3; #endif m_modified = false; m_curFocus = 1; const int but_sz_flags = wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxALL; //wxBOTTOM|wxLEFT|wxRIGHT; wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL ); // Message if ( message.length() ) topsizer->Add( new wxStaticText(this,-1,message), 0, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxALL, spacing ); // String editor wxBoxSizer* rowsizer = new wxBoxSizer( wxHORIZONTAL ); m_edValue = new wxTextCtrl(this,21,wxEmptyString, wxDefaultPosition,wxDefaultSize,wxTE_PROCESS_ENTER); wxValidator* validator = GetTextCtrlValidator(); if ( validator ) { m_edValue->SetValidator( *validator ); delete validator; } rowsizer->Add( m_edValue, 1, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxALL, spacing ); // Add button m_butAdd = new wxButton(this,22,_("Add")); rowsizer->Add( m_butAdd, 0, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, spacing ); topsizer->Add( rowsizer, 0, wxEXPAND, spacing ); // Separator line topsizer->Add( new wxStaticLine(this,-1), 0, wxEXPAND|wxBOTTOM|wxLEFT|wxRIGHT, spacing ); rowsizer = new wxBoxSizer( wxHORIZONTAL ); // list box m_lbStrings = new wxListBox(this, 24, wxDefaultPosition, wxDefaultSize); unsigned int i; for ( i=0; iAppend( ArrayGet(i) ); rowsizer->Add( m_lbStrings, 1, wxEXPAND|wxRIGHT, spacing ); // Manipulator buttons wxBoxSizer* colsizer = new wxBoxSizer( wxVERTICAL ); m_butCustom = (wxButton*) NULL; if ( m_custBtText ) { m_butCustom = new wxButton(this,28,::wxGetTranslation(m_custBtText)); colsizer->Add( m_butCustom, 0, wxALIGN_CENTER|wxTOP/*wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT*/, spacing ); } m_butUpdate = new wxButton(this,27,_("Update")); colsizer->Add( m_butUpdate, 0, wxALIGN_CENTER|wxTOP, spacing ); m_butRemove = new wxButton(this,23,_("Remove")); colsizer->Add( m_butRemove, 0, wxALIGN_CENTER|wxTOP, spacing ); m_butUp = new wxButton(this,25,_("Up")); colsizer->Add( m_butUp, 0, wxALIGN_CENTER|wxTOP, spacing ); m_butDown = new wxButton(this,26,_("Down")); colsizer->Add( m_butDown, 0, wxALIGN_CENTER|wxTOP, spacing ); rowsizer->Add( colsizer, 0, 0, spacing ); topsizer->Add( rowsizer, 1, wxLEFT|wxRIGHT|wxEXPAND, spacing ); // Separator line topsizer->Add( new wxStaticLine(this,-1), 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, spacing ); // buttons rowsizer = new wxBoxSizer( wxHORIZONTAL ); /* const int but_sz_flags = wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT; */ rowsizer->Add( new wxButton(this,wxID_OK,_("Ok")), 0, but_sz_flags, spacing ); rowsizer->Add( new wxButton(this,wxID_CANCEL,_("Cancel")), 0, but_sz_flags, spacing ); topsizer->Add( rowsizer, 0, wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL, 0 ); m_edValue->SetFocus(); SetSizer( topsizer ); topsizer->SetSizeHints( this ); #if !wxPG_SMALL_SCREEN if ( sz.x == wxDefaultSize.x && sz.y == wxDefaultSize.y ) SetSize( wxSize(275,360) ); else SetSize(sz); #endif return res; } // ----------------------------------------------------------------------- void wxArrayEditorDialog::OnAddClick(wxCommandEvent& ) { wxString text = m_edValue->GetValue(); if ( text.length() ) { if ( ArrayInsert( text, -1 ) ) { m_lbStrings->Append( text ); m_modified = true; m_edValue->Clear(); } } } // ----------------------------------------------------------------------- void wxArrayEditorDialog::OnDeleteClick(wxCommandEvent& ) { int index = m_lbStrings->GetSelection(); if ( index >= 0 ) { ArrayRemoveAt( index ); m_lbStrings->Delete ( index ); m_modified = true; } } // ----------------------------------------------------------------------- void wxArrayEditorDialog::OnUpClick(wxCommandEvent& ) { int index = m_lbStrings->GetSelection(); if ( index > 0 ) { ArraySwap(index-1,index); /*wxString old_str = m_array[index-1]; wxString new_str = m_array[index]; m_array[index-1] = new_str; m_array[index] = old_str;*/ m_lbStrings->SetString ( index-1, ArrayGet(index-1) ); m_lbStrings->SetString ( index, ArrayGet(index) ); m_lbStrings->SetSelection ( index-1 ); m_modified = true; } } // ----------------------------------------------------------------------- void wxArrayEditorDialog::OnDownClick(wxCommandEvent& ) { int index = m_lbStrings->GetSelection(); int lastStringIndex = ((int) m_lbStrings->GetCount()) - 1; if ( index >= 0 && index < lastStringIndex ) { ArraySwap(index,index+1); /*wxString old_str = m_array[index+1]; wxString new_str = m_array[index]; m_array[index+1] = new_str; m_array[index] = old_str;*/ m_lbStrings->SetString ( index+1, ArrayGet(index+1) ); m_lbStrings->SetString ( index, ArrayGet(index) ); m_lbStrings->SetSelection ( index+1 ); m_modified = true; } } // ----------------------------------------------------------------------- void wxArrayEditorDialog::OnUpdateClick(wxCommandEvent& ) { int index = m_lbStrings->GetSelection(); if ( index >= 0 ) { wxString str = m_edValue->GetValue(); if ( ArraySet(index,str) ) { m_lbStrings->SetString ( index, str ); //m_array[index] = str; m_modified = true; } } } // ----------------------------------------------------------------------- /*void wxArrayEditorDialog::OnCustomEditClick(wxCommandEvent& ) { wxASSERT ( m_pCallingClass ); wxString str = m_edValue->GetValue(); if ( m_pCallingClass->OnCustomStringEdit(m_parent,str) ) { //m_edValue->SetValue ( str ); if ( ArrayInsert(-1,str) ) { m_lbStrings->Append ( str ); m_modified = true; } } }*/ // ----------------------------------------------------------------------- void wxArrayEditorDialog::OnListBoxClick(wxCommandEvent& ) { int index = m_lbStrings->GetSelection(); if ( index >= 0 ) { m_edValue->SetValue( m_lbStrings->GetString(index) ); } } // ----------------------------------------------------------------------- // wxArrayStringEditorDialog // ----------------------------------------------------------------------- class wxArrayStringEditorDialog : public wxArrayEditorDialog { public: wxArrayStringEditorDialog(); void Init(); virtual void SetDialogValue( const wxVariant& value ) { m_array = value.GetArrayString(); } virtual wxVariant GetDialogValue() const { return m_array; } inline void SetCustomButton( const wxChar* custBtText, wxArrayStringPropertyClass* pcc ) { m_custBtText = custBtText; m_pCallingClass = pcc; } void OnCustomEditClick(wxCommandEvent& event); protected: wxArrayString m_array; wxArrayStringPropertyClass* m_pCallingClass; virtual wxString ArrayGet( size_t index ); virtual size_t ArrayGetCount(); virtual bool ArrayInsert( const wxString& str, int index ); virtual bool ArraySet( size_t index, const wxString& str ); virtual void ArrayRemoveAt( int index ); virtual void ArraySwap( size_t first, size_t second ); private: DECLARE_DYNAMIC_CLASS_NO_COPY(wxArrayStringEditorDialog) DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(wxArrayStringEditorDialog, wxArrayEditorDialog) EVT_BUTTON(28, wxArrayStringEditorDialog::OnCustomEditClick) END_EVENT_TABLE() IMPLEMENT_DYNAMIC_CLASS(wxArrayStringEditorDialog, wxArrayEditorDialog) // ----------------------------------------------------------------------- wxString wxArrayStringEditorDialog::ArrayGet( size_t index ) { return m_array[index]; } size_t wxArrayStringEditorDialog::ArrayGetCount() { return m_array.GetCount(); } bool wxArrayStringEditorDialog::ArrayInsert( const wxString& str, int index ) { if (index<0) m_array.Add(str); else m_array.Insert(str,index); return true; } bool wxArrayStringEditorDialog::ArraySet( size_t index, const wxString& str ) { m_array[index] = str; return true; } void wxArrayStringEditorDialog::ArrayRemoveAt( int index ) { m_array.RemoveAt(index); } void wxArrayStringEditorDialog::ArraySwap( size_t first, size_t second ) { wxString old_str = m_array[first]; wxString new_str = m_array[second]; m_array[first] = new_str; m_array[second] = old_str; } wxArrayStringEditorDialog::wxArrayStringEditorDialog() : wxArrayEditorDialog() { Init(); } void wxArrayStringEditorDialog::Init() { m_pCallingClass = (wxArrayStringPropertyClass*) NULL; } void wxArrayStringEditorDialog::OnCustomEditClick(wxCommandEvent& ) { wxASSERT( m_pCallingClass ); wxString str = m_edValue->GetValue(); if ( m_pCallingClass->OnCustomStringEdit(m_parent,str) ) { //m_edValue->SetValue ( str ); m_lbStrings->Append ( str ); m_array.Add ( str ); m_modified = true; } } // ----------------------------------------------------------------------- // wxArrayStringProperty // ----------------------------------------------------------------------- // Class body is in propdev.h WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty, // Property name wxBaseProperty, // Property we inherit from wxArrayString, // Value type name const wxArrayString&, // Value type, as given in constructor TextCtrlAndButton) // Initial editor wxArrayStringPropertyClass::wxArrayStringPropertyClass( const wxString& label, const wxString& name, const wxArrayString& array ) : wxPGProperty(label,name) { DoSetValue( array ); } wxArrayStringPropertyClass::~wxArrayStringPropertyClass() { } void wxArrayStringPropertyClass::DoSetValue( wxPGVariant value ) { m_value = wxPGVariantToArrayString(value); GenerateValueAsString(); } wxPGVariant wxArrayStringPropertyClass::DoGetValue() const { return wxPGVariantCreator(m_value); } wxString wxArrayStringPropertyClass::GetValueAsString( int WXUNUSED(argFlags) ) const { return m_display; } // Converts wxArrayString to a string separated by delimeters and spaces. // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash // conversion. void wxPropertyGrid::ArrayStringToString( wxString& dst, const wxArrayString& src, wxChar preDelim, wxChar postDelim, int flags ) { wxString pdr; unsigned int i; unsigned int itemCount = src.GetCount(); wxChar preas[2]; dst.Empty(); if ( !preDelim ) preas[0] = 0; else if ( (flags & 1) ) { preas[0] = preDelim; preas[1] = 0; pdr = wxT("\\"); pdr += preDelim; } if ( itemCount ) dst.append( preas ); wxASSERT( postDelim ); for ( i = 0; i < itemCount; i++ ) { wxString str( src.Item(i) ); // Do some character conversion. // Convertes \ to \\ and to \ // Useful when preDelim and postDelim are "\"". if ( flags & 1 ) { str.Replace( wxT("\\"), wxT("\\\\"), true ); if ( pdr.length() ) str.Replace( preas, pdr, true ); } dst.append ( str ); if ( i < (itemCount-1) ) { dst.append( wxString(postDelim) ); dst.append( wxT(" ") ); dst.append( wxString(preas) ); } else if ( preDelim ) dst.append( wxString(postDelim) ); } } #define ARRSTRPROP_ARRAY_TO_STRING(STRING,ARRAY) \ wxPropertyGrid::ArrayStringToString(STRING,ARRAY,wxT('"'),wxT('"'),1); void wxArrayStringPropertyClass::GenerateValueAsString() { ARRSTRPROP_ARRAY_TO_STRING(m_display, m_value) } // Default implementation doesn't do anything. bool wxArrayStringPropertyClass::OnCustomStringEdit( wxWindow*, wxString& ) { return false; } wxArrayEditorDialog* wxArrayStringPropertyClass::CreateEditorDialog() { return new wxArrayStringEditorDialog(); } bool wxArrayStringPropertyClass::OnButtonClick( wxPropertyGrid* propGrid, wxWindow* primaryCtrl, const wxChar* cbt ) { // Update the value PrepareValueForDialogEditing(propGrid); if ( !propGrid->EditorValidate() ) return false; // Create editor dialog. wxArrayEditorDialog* dlg = CreateEditorDialog(); wxValidator* validator = GetValidator(); wxPGInDialogValidator dialogValidator; wxArrayStringEditorDialog* strEdDlg = wxDynamicCast(dlg, wxArrayStringEditorDialog); if ( strEdDlg ) strEdDlg->SetCustomButton(cbt, this); dlg->SetDialogValue( wxVariant(m_value) ); dlg->Create(propGrid, wxEmptyString, m_label); #if !wxPG_SMALL_SCREEN dlg->Move( propGrid->GetGoodEditorDialogPosition(this,dlg->GetSize()) ); #endif bool retVal; for (;;) { retVal = false; int res = dlg->ShowModal(); if ( res == wxID_OK && dlg->IsModified() ) { wxVariant value = dlg->GetDialogValue(); if ( !value.IsNull() ) { wxArrayString actualValue = value.GetArrayString(); wxString tempStr; ARRSTRPROP_ARRAY_TO_STRING(tempStr, actualValue) if ( dialogValidator.DoValidate( propGrid, validator, tempStr ) ) { DoSetValue( actualValue ); UpdateControl( primaryCtrl ); retVal = true; break; } } else break; } else break; } delete dlg; return retVal; } bool wxArrayStringPropertyClass::OnEvent( wxPropertyGrid* propGrid, wxWindow* primary, wxEvent& event ) { if ( event.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED ) return OnButtonClick(propGrid,primary,(const wxChar*) NULL); return false; } bool wxArrayStringPropertyClass::SetValueFromString( const wxString& text, int ) { m_value.Empty(); WX_PG_TOKENIZER2_BEGIN(text,wxT('"')) // Need to replace backslashes with empty characters // (opposite what is done in GenerateValueString). token.Replace ( wxT("\\"), wxT(""), true ); m_value.Add ( token ); WX_PG_TOKENIZER2_END() GenerateValueAsString(); return true; } // ----------------------------------------------------------------------- // wxCustomProperty // ----------------------------------------------------------------------- wxPGProperty* wxCustomProperty( const wxString& label, const wxString& name ) { return new wxCustomPropertyClass (label,name); } WX_PG_IMPLEMENT_CLASSINFO(wxCustomProperty,wxBaseParentPropertyClass) wxPG_GETCLASSNAME_IMPLEMENTATION(wxCustomProperty) wxPG_VALUETYPE_MSGVAL wxCustomPropertyClass::GetValueType() const { return wxPG_VALUETYPE(wxString); } const wxPGEditor* wxCustomPropertyClass::DoGetEditorClass() const { return wxPG_EDITOR(TextCtrl); } wxCustomPropertyClass::wxCustomPropertyClass(const wxString& label, const wxString& name) : wxPGPropertyWithChildren(label,name) { m_parentingType = -2; #ifdef wxPG_COMPATIBILITY_1_0_0 m_callback = (wxPropertyGridCallback) NULL; #endif //m_choices = &wxPGGlobalVars->m_emptyChoicesData; m_paintCallback = (wxPGPaintCallback) NULL; } wxCustomPropertyClass::~wxCustomPropertyClass() { //wxPGUnRefChoices(m_choices); } void wxCustomPropertyClass::DoSetValue ( wxPGVariant value ) { m_value = value.GetString(); } wxPGVariant wxCustomPropertyClass::DoGetValue () const { return m_value; } bool wxCustomPropertyClass::SetValueFromString ( const wxString& text, int /*flags*/ ) { if ( text != m_value ) { m_value = text; return true; } return false; } wxString wxCustomPropertyClass::GetValueAsString ( int /*argFlags*/ ) const { return m_value; } // Need to do some extra event handling. #ifdef wxPG_COMPATIBILITY_1_0_0 bool wxCustomPropertyClass::OnEvent ( wxPropertyGrid* propGrid, wxWindow* primary, wxEvent& event ) { if ( event.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED ) { if ( m_callback ) return m_callback(propGrid,this,primary,0); } return false; } #endif wxSize wxCustomPropertyClass::GetImageSize() const { if ( m_paintCallback ) return wxSize(-wxPG_CUSTOM_IMAGE_WIDTH,-wxPG_CUSTOM_IMAGE_WIDTH); return wxPGPropertyWithChildren::GetImageSize(); } void wxCustomPropertyClass::OnCustomPaint( wxDC& dc, const wxRect& rect, wxPGPaintData& paintData ) { if ( m_paintCallback ) m_paintCallback(this,dc,rect,paintData); else wxPGPropertyWithChildren::OnCustomPaint(dc,rect,paintData); } bool wxCustomPropertyClass::SetValueFromInt ( long value, int ) { size_t index = value; const wxArrayInt& values = m_choices.GetValues(); if ( values.GetCount() ) index = values.Index(value); const wxString& sAtIndex = m_choices.GetLabel(index); if ( sAtIndex != m_value ) { m_value = sAtIndex; return true; } return false; } int wxCustomPropertyClass::GetChoiceInfo( wxPGChoiceInfo* choiceinfo ) { if ( choiceinfo ) { choiceinfo->m_choices = &m_choices; if ( !m_choices.IsOk() ) return -1; choiceinfo->m_itemCount = m_choices.GetCount(); if ( m_choices.GetCount() ) choiceinfo->m_arrWxString = (wxString*)&m_choices.GetLabel(0); } if ( !m_choices.IsOk() ) return -1; return m_choices.GetLabels().Index(m_value); } void wxCustomPropertyClass::SetAttribute ( int id, wxVariant& value ) { #ifdef wxPG_COMPATIBILITY_1_0_0 wxPropertyGrid* grid = GetGrid(); if ( id == wxPG_CUSTOM_EDITOR ) { if ( grid ) grid->SetPropertyEditor( wxPGIdGen(this), (wxPGEditor*) value.GetVoidPtr() ); else SetEditor( (wxPGEditor*) value.GetVoidPtr() ); } else if ( id == wxPG_CUSTOM_IMAGE ) { wxBitmap* bmp = (wxBitmap*) value.GetWxObjectPtr(); if ( grid ) grid->SetPropertyImage(wxPGIdGen(this),*bmp); else SetValueImage(*bmp); } else if ( id == wxPG_CUSTOM_CALLBACK ) { m_callback = (wxPropertyGridCallback) value.GetVoidPtr(); } else #endif if ( id == wxPG_CUSTOM_PAINT_CALLBACK ) { void* voidValue = value.GetVoidPtr(); m_paintCallback = (wxPGPaintCallback) voidValue; if ( voidValue ) m_flags |= wxPG_PROP_CUSTOMIMAGE; else if ( !GetValueImage() ) m_flags &= ~(wxPG_PROP_CUSTOMIMAGE); } else if ( id == wxPG_CUSTOM_PRIVATE_CHILDREN ) { if ( value.GetLong() ) m_parentingType = -1; else m_parentingType = -2; } } // -----------------------------------------------------------------------