1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/props.cpp
3 // Purpose: Basic Property Classes
4 // Author: Jaakko Salli
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
23 #include "wx/object.h"
25 #include "wx/string.h"
28 #include "wx/window.h"
31 #include "wx/dcclient.h"
32 #include "wx/dcmemory.h"
33 #include "wx/button.h"
36 #include "wx/cursor.h"
37 #include "wx/dialog.h"
38 #include "wx/settings.h"
39 #include "wx/msgdlg.h"
40 #include "wx/choice.h"
41 #include "wx/stattext.h"
42 #include "wx/scrolwin.h"
43 #include "wx/dirdlg.h"
44 #include "wx/combobox.h"
45 #include "wx/layout.h"
47 #include "wx/textdlg.h"
48 #include "wx/filedlg.h"
49 #include "wx/statusbr.h"
53 #include <wx/filename.h>
55 #include <wx/propgrid/propgrid.h>
57 #define wxPG_CUSTOM_IMAGE_WIDTH 20 // for wxColourProperty etc.
62 // -----------------------------------------------------------------------
64 // -----------------------------------------------------------------------
66 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxStringProperty
,wxPGProperty
,
67 wxString
,const wxString
&,TextCtrl
)
69 wxStringProperty::wxStringProperty( const wxString
& label
,
71 const wxString
& value
)
72 : wxPGProperty(label
,name
)
77 void wxStringProperty::OnSetValue()
79 if ( !m_value
.IsNull() && m_value
.GetString() == wxS("<composed>") )
80 SetFlag(wxPG_PROP_COMPOSED_VALUE
);
82 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
85 GenerateComposedValue(s
, 0);
90 wxStringProperty::~wxStringProperty() { }
92 wxString
wxStringProperty::GetValueAsString( int argFlags
) const
94 wxString s
= m_value
.GetString();
96 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
98 // Value stored in m_value is non-editable, non-full value
99 if ( (argFlags
& wxPG_FULL_VALUE
) || (argFlags
& wxPG_EDITABLE_VALUE
) )
100 GenerateComposedValue(s
, argFlags
);
105 // If string is password and value is for visual purposes,
106 // then return asterisks instead the actual string.
107 if ( (m_flags
& wxPG_PROP_PASSWORD
) && !(argFlags
& (wxPG_FULL_VALUE
|wxPG_EDITABLE_VALUE
)) )
108 return wxString(wxChar('*'), s
.Length());
113 bool wxStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
115 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
116 return wxPGProperty::StringToValue(variant
, text
, argFlags
);
118 if ( m_value
.GetString() != text
)
127 bool wxStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
129 if ( name
== wxPG_STRING_PASSWORD
)
131 m_flags
&= ~(wxPG_PROP_PASSWORD
);
132 if ( wxPGVariantToInt(value
) ) m_flags
|= wxPG_PROP_PASSWORD
;
139 // -----------------------------------------------------------------------
141 // -----------------------------------------------------------------------
143 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty
,wxPGProperty
,
146 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
147 long value
) : wxPGProperty(label
,name
)
152 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
153 const wxLongLong
& value
) : wxPGProperty(label
,name
)
155 SetValue(WXVARIANT(value
));
158 wxIntProperty::~wxIntProperty() { }
160 wxString
wxIntProperty::GetValueAsString( int ) const
162 if ( m_value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
164 return wxString::Format(wxS("%li"),m_value
.GetLong());
166 else if ( m_value
.GetType() == wxLongLong_VariantType
)
170 return ll
.ToString();
173 return wxEmptyString
;
176 bool wxIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
181 if ( text
.length() == 0 )
187 // We know it is a number, but let's still check
189 if ( text
.IsNumber() )
191 // Remove leading zeroes, so that the number is not interpreted as octal
192 wxString::const_iterator i
= text
.begin();
193 wxString::const_iterator iMax
= text
.end() - 1; // Let's allow one, last zero though
195 int firstNonZeroPos
= 0;
197 for ( ; i
!= iMax
; i
++ )
200 if ( c
!= wxS('0') && c
!= wxS(' ') )
205 wxString useText
= text
.substr(firstNonZeroPos
, text
.length() - firstNonZeroPos
);
207 wxString variantType
= variant
.GetType();
208 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
210 wxLongLong_t value64
= 0;
212 if ( useText
.ToLongLong(&value64
, 10) &&
213 ( value64
>= INT_MAX
|| value64
<= INT_MIN
)
216 bool doChangeValue
= isPrevLong
;
218 if ( !isPrevLong
&& variantType
== wxLongLong_VariantType
)
222 if ( oldValue
.GetValue() != value64
)
223 doChangeValue
= true;
228 wxLongLong
ll(value64
);
234 if ( useText
.ToLong( &value32
, 0 ) )
236 if ( !isPrevLong
|| m_value
.GetLong() != value32
)
243 else if ( argFlags
& wxPG_REPORT_ERROR
)
249 bool wxIntProperty::IntToValue( wxVariant
& variant
, int value
, int WXUNUSED(argFlags
) ) const
251 if ( variant
.GetType() != wxPG_VARIANT_TYPE_LONG
|| variant
.GetLong() != value
)
253 variant
= (long)value
;
259 bool wxIntProperty::DoValidation( const wxPGProperty
* property
, wxLongLong_t
& value
, wxPGValidationInfo
* pValidationInfo
, int mode
)
262 wxLongLong_t min
= wxINT64_MIN
;
263 wxLongLong_t max
= wxINT64_MAX
;
268 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
269 if ( !variant
.IsNull() )
271 wxPGVariantToLongLong(variant
, &min
);
275 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
276 if ( !variant
.IsNull() )
278 wxPGVariantToLongLong(variant
, &max
);
286 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
287 pValidationInfo
->m_failureMessage
= wxString::Format(_("Value must be %lld or higher"),min
);
288 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
291 value
= max
- (min
- value
);
300 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
301 pValidationInfo
->m_failureMessage
= wxString::Format(_("Value must be %lld or higher"),min
);
302 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
305 value
= min
+ (value
- max
);
312 bool wxIntProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
315 if ( wxPGVariantToLongLong(value
, &ll
) )
316 return DoValidation(this, ll
, &validationInfo
, wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
320 wxValidator
* wxIntProperty::GetClassValidator()
323 WX_PG_DOGETVALIDATOR_ENTRY()
325 // Atleast wxPython 2.6.2.1 required that the string argument is given
327 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_NUMERIC
,&v
);
329 WX_PG_DOGETVALIDATOR_EXIT(validator
)
335 wxValidator
* wxIntProperty::DoGetValidator() const
337 return GetClassValidator();
340 // -----------------------------------------------------------------------
342 // -----------------------------------------------------------------------
345 #define wxPG_UINT_TEMPLATE_MAX 8
347 static const wxChar
* gs_uintTemplates32
[wxPG_UINT_TEMPLATE_MAX
] = {
348 wxT("%x"),wxT("0x%x"),wxT("$%x"),
349 wxT("%X"),wxT("0x%X"),wxT("$%X"),
353 static const wxChar
* gs_uintTemplates64
[wxPG_UINT_TEMPLATE_MAX
] = {
354 wxT("%") wxLongLongFmtSpec
wxT("x"),
355 wxT("0x%") wxLongLongFmtSpec
wxT("x"),
356 wxT("$%") wxLongLongFmtSpec
wxT("x"),
357 wxT("%") wxLongLongFmtSpec
wxT("X"),
358 wxT("0x%") wxLongLongFmtSpec
wxT("X"),
359 wxT("$%") wxLongLongFmtSpec
wxT("X"),
360 wxT("%") wxLongLongFmtSpec
wxT("u"),
361 wxT("%") wxLongLongFmtSpec
wxT("o")
364 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty
,wxPGProperty
,
365 long,unsigned long,TextCtrl
)
367 void wxUIntProperty::Init()
369 m_base
= 6; // This is magic number for dec base (must be same as in setattribute)
371 m_prefix
= wxPG_PREFIX_NONE
;
374 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
375 unsigned long value
) : wxPGProperty(label
,name
)
378 SetValue((long)value
);
381 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
382 const wxULongLong
& value
) : wxPGProperty(label
,name
)
385 SetValue(WXVARIANT(value
));
388 wxUIntProperty::~wxUIntProperty() { }
390 wxString
wxUIntProperty::GetValueAsString( int ) const
392 size_t index
= m_base
+ m_prefix
;
393 if ( index
>= wxPG_UINT_TEMPLATE_MAX
)
394 index
= wxPG_BASE_DEC
;
396 if ( m_value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
398 return wxString::Format(gs_uintTemplates32
[index
], (unsigned long)m_value
.GetLong());
404 return wxString::Format(gs_uintTemplates64
[index
], ull
.GetValue());
407 bool wxUIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
409 wxString variantType
= variant
.GetType();
410 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
412 if ( text
.length() == 0 )
419 if ( text
[0] == wxS('$') )
422 wxULongLong_t value64
= 0;
423 wxString s
= text
.substr(start
, text
.length() - start
);
425 if ( s
.ToULongLong(&value64
, (unsigned int)m_realBase
) )
427 if ( value64
>= LONG_MAX
)
429 bool doChangeValue
= isPrevLong
;
431 if ( !isPrevLong
&& variantType
== wxULongLong_VariantType
)
433 wxULongLong oldValue
;
435 if ( oldValue
.GetValue() != value64
)
436 doChangeValue
= true;
441 wxULongLong
ull(value64
);
448 unsigned long value32
= wxLongLong(value64
).GetLo();
449 if ( !isPrevLong
|| m_value
.GetLong() != (long)value32
)
451 variant
= (long)value32
;
460 bool wxUIntProperty::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
462 if ( m_value
!= (long)number
)
464 variant
= (long)number
;
471 #define wxUINT64_MAX ULLONG_MAX
472 #define wxUINT64_MIN wxULL(0)
474 #define wxUINT64_MAX wxULL(0xFFFFFFFFFFFFFFFF)
475 #define wxUINT64_MIN wxULL(0)
478 bool wxUIntProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
482 if ( wxPGVariantToULongLong(value
, &ll
) )
484 wxULongLong_t min
= wxUINT64_MIN
;
485 wxULongLong_t max
= wxUINT64_MAX
;
488 variant
= GetAttribute(wxPGGlobalVars
->m_strMin
);
489 if ( !variant
.IsNull() )
491 wxPGVariantToULongLong(variant
, &min
);
494 validationInfo
.m_failureMessage
= wxString::Format(_("Value must be %llu or higher"),min
);
498 variant
= GetAttribute(wxPGGlobalVars
->m_strMax
);
499 if ( !variant
.IsNull() )
501 wxPGVariantToULongLong(variant
, &max
);
504 validationInfo
.m_failureMessage
= wxString::Format(_("Value must be %llu or less"),max
);
512 bool wxUIntProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
514 if ( name
== wxPG_UINT_BASE
)
516 int val
= value
.GetLong();
518 m_realBase
= (wxByte
) val
;
519 if ( m_realBase
> 16 )
523 // Translate logical base to a template array index
525 if ( val
== wxPG_BASE_HEX
)
527 else if ( val
== wxPG_BASE_DEC
)
529 else if ( val
== wxPG_BASE_HEXL
)
533 else if ( name
== wxPG_UINT_PREFIX
)
535 m_prefix
= (wxByte
) value
.GetLong();
541 // -----------------------------------------------------------------------
543 // -----------------------------------------------------------------------
545 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty
,wxPGProperty
,
546 double,double,TextCtrl
)
548 wxFloatProperty::wxFloatProperty( const wxString
& label
,
549 const wxString
& name
,
551 : wxPGProperty(label
,name
)
557 wxFloatProperty::~wxFloatProperty() { }
559 // This helper method provides standard way for floating point-using
560 // properties to convert values to string.
561 void wxPropertyGrid::DoubleToString(wxString
& target
,
565 wxString
* precTemplate
)
567 if ( precision
>= 0 )
571 precTemplate
= &text1
;
573 if ( !precTemplate
->length() )
575 *precTemplate
= wxS("%.");
576 *precTemplate
<< wxString::Format( wxS("%i"), precision
);
577 *precTemplate
<< wxS('f');
580 target
.Printf( precTemplate
->c_str(), value
);
584 target
.Printf( wxS("%f"), value
);
587 if ( removeZeroes
&& precision
!= 0 && target
.length() )
589 // Remove excess zeroes (do not remove this code just yet,
590 // since sprintf can't do the same consistently across platforms).
591 wxString::const_iterator i
= target
.end() - 1;
592 size_t new_len
= target
.length() - 1;
594 for ( ; i
!= target
.begin(); i
-- )
596 if ( *i
!= wxS('0') )
601 wxChar cur_char
= *i
;
602 if ( cur_char
!= wxS('.') && cur_char
!= wxS(',') )
605 if ( new_len
!= target
.length() )
606 target
.resize(new_len
);
610 wxString
wxFloatProperty::GetValueAsString( int argFlags
) const
613 if ( !m_value
.IsNull() )
615 wxPropertyGrid::DoubleToString(text
,
618 !(argFlags
& wxPG_FULL_VALUE
),
624 bool wxFloatProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
629 if ( text
.length() == 0 )
635 bool res
= text
.ToDouble(&value
);
638 if ( m_value
!= value
)
644 else if ( argFlags
& wxPG_REPORT_ERROR
)
650 bool wxFloatProperty::DoValidation( const wxPGProperty
* property
, double& value
, wxPGValidationInfo
* pValidationInfo
, int mode
)
653 double min
= (double)wxINT64_MIN
;
654 double max
= (double)wxINT64_MAX
;
659 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
660 if ( !variant
.IsNull() )
662 wxPGVariantToDouble(variant
, &min
);
666 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
667 if ( !variant
.IsNull() )
669 wxPGVariantToDouble(variant
, &max
);
677 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
678 pValidationInfo
->m_failureMessage
= wxString::Format(_("Value must be %f or higher"),min
);
679 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
682 value
= max
- (min
- value
);
689 wxPGVariantToDouble(variant
, &max
);
692 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
693 pValidationInfo
->m_failureMessage
= wxString::Format(_("Value must be %f or less"),max
);
694 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
697 value
= min
+ (value
- max
);
704 bool wxFloatProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
707 if ( wxPGVariantToDouble(value
, &fpv
) )
708 return DoValidation(this, fpv
, &validationInfo
, wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
712 bool wxFloatProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
714 if ( name
== wxPG_FLOAT_PRECISION
)
716 m_precision
= value
.GetLong();
722 wxValidator
* wxFloatProperty::DoGetValidator() const
724 return wxIntProperty::GetClassValidator();
727 // -----------------------------------------------------------------------
729 // -----------------------------------------------------------------------
731 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
732 // there is a custom GetEditorClass.
734 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty
, wxPGProperty
)
736 const wxPGEditor
* wxBoolProperty::DoGetEditorClass() const
738 // Select correct editor control.
739 #if wxPG_INCLUDE_CHECKBOX
740 if ( !(m_flags
& wxPG_PROP_USE_CHECKBOX
) )
741 return wxPG_EDITOR(Choice
);
742 return wxPG_EDITOR(CheckBox
);
744 return wxPG_EDITOR(Choice
);
748 wxBoolProperty::wxBoolProperty( const wxString
& label
, const wxString
& name
, bool value
) :
749 wxPGProperty(label
,name
)
751 SetValue(wxPGVariant_Bool(value
));
753 m_flags
|= wxPG_PROP_USE_DCC
;
756 wxBoolProperty::~wxBoolProperty() { }
758 wxString
wxBoolProperty::GetValueAsString( int argFlags
) const
760 bool value
= m_value
.GetBool();
762 // As a fragment of composite string value,
763 // make it a little more readable.
764 if ( argFlags
& wxPG_COMPOSITE_FRAGMENT
)
772 if ( argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
)
773 return wxEmptyString
;
776 if ( wxPGGlobalVars
->m_autoGetTranslation
)
777 notFmt
= _("Not %s");
779 notFmt
= wxS("Not %s");
781 return wxString::Format(notFmt
.c_str(), m_label
.c_str());
785 if ( !(argFlags
& wxPG_FULL_VALUE
) )
787 return wxPGGlobalVars
->m_boolChoices
[value
?1:0].GetText();
792 if (value
) text
= wxS("true");
793 else text
= wxS("false");
798 int wxBoolProperty::GetChoiceInfo( wxPGChoiceInfo
* choiceinfo
)
800 if ( IsValueUnspecified() )
804 choiceinfo
->m_choices
= &wxPGGlobalVars
->m_boolChoices
;
805 return m_value
.GetBool()?1:0;
808 bool wxBoolProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
811 if ( text
.CmpNoCase(wxPGGlobalVars
->m_boolChoices
[1].GetText()) == 0 ||
812 text
.CmpNoCase(wxS("true")) == 0 ||
813 text
.CmpNoCase(m_label
) == 0 )
816 if ( text
.length() == 0 )
822 bool oldValue
= m_value
.GetBool();
824 if ( (oldValue
&& !value
) || (!oldValue
&& value
) )
826 variant
= wxPGVariant_Bool(value
);
832 bool wxBoolProperty::IntToValue( wxVariant
& variant
, int value
, int ) const
834 bool boolValue
= value
? true : false;
835 bool oldValue
= m_value
.GetBool();
837 if ( oldValue
!= boolValue
)
839 variant
= wxPGVariant_Bool(boolValue
);
845 bool wxBoolProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
847 #if wxPG_INCLUDE_CHECKBOX
848 if ( name
== wxPG_BOOL_USE_CHECKBOX
)
850 int ival
= wxPGVariantToInt(value
);
852 m_flags
|= wxPG_PROP_USE_CHECKBOX
;
854 m_flags
&= ~(wxPG_PROP_USE_CHECKBOX
);
858 if ( name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
860 int ival
= wxPGVariantToInt(value
);
862 m_flags
|= wxPG_PROP_USE_DCC
;
864 m_flags
&= ~(wxPG_PROP_USE_DCC
);
870 // -----------------------------------------------------------------------
871 // wxBaseEnumProperty
872 // -----------------------------------------------------------------------
874 int wxBaseEnumProperty::ms_nextIndex
= -2;
876 wxBaseEnumProperty::wxBaseEnumProperty( const wxString
& label
, const wxString
& name
)
877 : wxPGProperty(label
,name
)
879 m_value
= wxPGVariant_Zero
;
882 /** If has values array, then returns number at index with value -
883 otherwise just returns the value.
885 int wxBaseEnumProperty::GetIndexForValue( int value
) const
890 void wxBaseEnumProperty::OnSetValue()
892 wxString variantType
= m_value
.GetType();
894 if ( variantType
== wxPG_VARIANT_TYPE_LONG
)
895 ValueFromInt_( m_value
, m_value
.GetLong(), wxPG_FULL_VALUE
);
896 else if ( variantType
== wxPG_VARIANT_TYPE_STRING
)
897 ValueFromString_( m_value
, m_value
.GetString(), 0 );
901 if ( ms_nextIndex
!= -2 )
903 m_index
= ms_nextIndex
;
908 bool wxBaseEnumProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
910 // Make sure string value is in the list,
911 // unless property has string as preferred value type
912 // To reduce code size, use conversion here as well
913 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
&&
914 !this->IsKindOf(CLASSINFO(wxEditEnumProperty
)) )
915 return ValueFromString_( value
, value
.GetString(), wxPG_PROPERTY_SPECIFIC
);
920 wxString
wxBaseEnumProperty::GetValueAsString( int ) const
922 if ( m_value
.GetType() == wxPG_VARIANT_TYPE_STRING
)
923 return m_value
.GetString();
928 const wxString
* pstr
= GetEntry( m_index
, &unusedVal
);
933 return wxEmptyString
;
936 bool wxBaseEnumProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
938 return ValueFromString_( variant
, text
, argFlags
);
941 bool wxBaseEnumProperty::IntToValue( wxVariant
& variant
, int intVal
, int argFlags
) const
943 return ValueFromInt_( variant
, intVal
, argFlags
);
946 bool wxBaseEnumProperty::ValueFromString_( wxVariant
& value
, const wxString
& text
, int argFlags
) const
949 const wxString
* entryLabel
;
954 entryLabel
= GetEntry(i
, &entryValue
);
957 if ( text
.CmpNoCase(*entryLabel
) == 0 )
960 useValue
= (long)entryValue
;
965 entryLabel
= GetEntry(i
, &entryValue
);
970 bool isEdit
= this->IsKindOf(CLASSINFO(wxEditEnumProperty
));
972 // If text not any of the choices, store as text instead
973 // (but only if we are wxEditEnumProperty)
974 if ( useIndex
== -1 &&
975 (value
.GetType() != wxPG_VARIANT_TYPE_STRING
|| (m_value
.GetString() != text
)) &&
981 int setAsNextIndex
= -2;
988 else if ( m_index
!= useIndex
)
990 if ( useIndex
!= -1 )
992 setAsNextIndex
= useIndex
;
993 value
= (long)useValue
;
998 value
= wxPGVariant_MinusOne
;
1002 if ( setAsNextIndex
!= -2 )
1004 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1005 // validation purposes only, and index must not be changed
1006 if ( !(argFlags
& wxPG_PROPERTY_SPECIFIC
) )
1007 ms_nextIndex
= setAsNextIndex
;
1009 if ( isEdit
|| setAsNextIndex
!= -1 )
1017 bool wxBaseEnumProperty::ValueFromInt_( wxVariant
& variant
, int intVal
, int argFlags
) const
1019 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1023 if ( argFlags
& wxPG_FULL_VALUE
)
1025 ms_nextIndex
= GetIndexForValue( intVal
);
1029 if ( m_index
!= intVal
)
1031 ms_nextIndex
= intVal
;
1035 if ( ms_nextIndex
!= -2 )
1037 if ( !(argFlags
& wxPG_FULL_VALUE
) )
1038 GetEntry(intVal
, &intVal
);
1040 variant
= (long)intVal
;
1048 void wxBaseEnumProperty::SetIndex( int index
)
1054 int wxBaseEnumProperty::GetIndex() const
1056 if ( ms_nextIndex
!= -2 )
1057 return ms_nextIndex
;
1061 // -----------------------------------------------------------------------
1063 // -----------------------------------------------------------------------
1065 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty
, wxPGProperty
)
1067 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty
,long,Choice
)
1069 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
** labels
,
1070 const long* values
, int value
) : wxBaseEnumProperty(label
,name
)
1076 m_choices
.Add(labels
,values
);
1078 if ( GetItemCount() )
1079 SetValue( (long)value
);
1083 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
** labels
,
1084 const long* values
, wxPGChoices
* choicesCache
, int value
)
1085 : wxBaseEnumProperty(label
,name
)
1089 wxASSERT( choicesCache
);
1091 if ( choicesCache
->IsOk() )
1093 m_choices
.Assign( *choicesCache
);
1094 m_value
= wxPGVariant_Zero
;
1098 m_choices
.Add(labels
,values
);
1100 if ( GetItemCount() )
1101 SetValue( (long)value
);
1105 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1106 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
) : wxBaseEnumProperty(label
,name
)
1110 if ( &labels
&& labels
.size() )
1112 m_choices
.Set(labels
, values
);
1114 if ( GetItemCount() )
1115 SetValue( (long)value
);
1119 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1120 wxPGChoices
& choices
, int value
)
1121 : wxBaseEnumProperty(label
,name
)
1123 m_choices
.Assign( choices
);
1125 if ( GetItemCount() )
1126 SetValue( (long)value
);
1129 int wxEnumProperty::GetIndexForValue( int value
) const
1131 if ( !m_choices
.IsOk() )
1134 if ( m_choices
.HasValues() )
1136 int intVal
= m_choices
.Index(value
);
1144 wxEnumProperty::~wxEnumProperty ()
1148 const wxString
* wxEnumProperty::GetEntry( size_t index
, int* pvalue
) const
1150 if ( m_choices
.IsOk() && index
< m_choices
.GetCount() )
1152 int value
= (int)index
;
1153 if ( m_choices
.HasValue(index
) )
1154 value
= m_choices
.GetValue(index
);
1159 return &m_choices
.GetLabel(index
);
1161 return (const wxString
*) NULL
;
1164 int wxEnumProperty::GetChoiceInfo( wxPGChoiceInfo
* choiceinfo
)
1167 choiceinfo
->m_choices
= &m_choices
;
1169 if ( !m_choices
.IsOk() )
1175 // -----------------------------------------------------------------------
1176 // wxEditEnumProperty
1177 // -----------------------------------------------------------------------
1179 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty
, wxPGProperty
)
1181 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty
,wxString
,ComboBox
)
1183 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
** labels
,
1184 const long* values
, const wxString
& value
)
1185 : wxEnumProperty(label
,name
,labels
,values
,0)
1190 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
** labels
,
1191 const long* values
, wxPGChoices
* choicesCache
, const wxString
& value
)
1192 : wxEnumProperty(label
,name
,labels
,values
,choicesCache
,0)
1197 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1198 const wxArrayString
& labels
, const wxArrayInt
& values
, const wxString
& value
)
1199 : wxEnumProperty(label
,name
,labels
,values
,0)
1204 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1205 wxPGChoices
& choices
, const wxString
& value
)
1206 : wxEnumProperty(label
,name
,choices
,0)
1211 wxEditEnumProperty::~wxEditEnumProperty()
1215 // -----------------------------------------------------------------------
1217 // -----------------------------------------------------------------------
1219 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty
,wxPGProperty
)
1221 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty
,long,TextCtrl
)
1223 void wxFlagsProperty::Init()
1225 SetFlag(wxPG_PROP_AGGREGATE
); // This is must be done here to support flag props
1226 // with inital zero children.
1228 long value
= m_value
;
1231 // Generate children
1235 unsigned int prevChildCount
= m_children
.GetCount();
1238 if ( prevChildCount
)
1240 wxPropertyGridPageState
* state
= GetParentState();
1242 // State safety check (it may be NULL in immediate parent)
1247 wxPGProperty
* selected
= state
->GetSelection();
1250 if ( selected
->GetParent() == this )
1251 oldSel
= selected
->GetArrIndex();
1252 else if ( selected
== this )
1256 state
->DoClearSelection();
1259 // Delete old children
1260 for ( i
=0; i
<prevChildCount
; i
++ )
1261 delete ( (wxPGProperty
*) m_children
[i
] );
1265 if ( m_choices
.IsOk() )
1267 const wxPGChoices
& choices
= m_choices
;
1269 for ( i
=0; i
<GetItemCount(); i
++ )
1272 if ( choices
.HasValue(i
) )
1273 child_val
= ( value
& choices
.GetValue(i
) )?true:false;
1275 child_val
= ( value
& (1<<i
) )?true:false;
1277 wxPGProperty
* boolProp
;
1278 wxString label
= GetLabel(i
);
1281 if ( wxPGGlobalVars
->m_autoGetTranslation
)
1283 boolProp
= new wxBoolProperty( ::wxGetTranslation(label
), label
, child_val
);
1288 boolProp
= new wxBoolProperty( label
, label
, child_val
);
1293 m_oldChoicesData
= m_choices
.GetDataPtr();
1296 m_oldValue
= m_value
;
1298 if ( prevChildCount
)
1299 SubPropsChanged(oldSel
);
1302 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1303 const wxChar
** labels
, const long* values
, long value
) : wxPGProperty(label
,name
)
1305 m_oldChoicesData
= (wxPGChoicesData
*) NULL
;
1309 m_choices
.Set(labels
,values
);
1311 wxASSERT( GetItemCount() );
1317 m_value
= wxPGVariant_Zero
;
1321 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1322 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1323 : wxPGProperty(label
,name
)
1325 m_oldChoicesData
= (wxPGChoicesData
*) NULL
;
1327 if ( &labels
&& labels
.size() )
1329 m_choices
.Set(labels
,values
);
1331 wxASSERT( GetItemCount() );
1333 SetValue( (long)value
);
1337 m_value
= wxPGVariant_Zero
;
1341 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1342 wxPGChoices
& choices
, long value
)
1343 : wxPGProperty(label
,name
)
1345 m_oldChoicesData
= (wxPGChoicesData
*) NULL
;
1347 if ( choices
.IsOk() )
1349 m_choices
.Assign(choices
);
1351 wxASSERT( GetItemCount() );
1357 m_value
= wxPGVariant_Zero
;
1361 wxFlagsProperty::~wxFlagsProperty()
1365 void wxFlagsProperty::OnSetValue()
1367 if ( !m_choices
.IsOk() || !GetItemCount() )
1369 m_value
= wxPGVariant_Zero
;
1373 long val
= m_value
.GetLong();
1377 // normalize the value (i.e. remove extra flags)
1379 const wxPGChoices
& choices
= m_choices
;
1380 for ( i
= 0; i
< GetItemCount(); i
++ )
1382 if ( choices
.HasValue(i
) )
1383 fullFlags
|= choices
.GetValue(i
);
1385 fullFlags
|= (1<<i
);
1392 // Need to (re)init now?
1393 if ( GetChildCount() != GetItemCount() ||
1394 m_choices
.GetDataPtr() != m_oldChoicesData
)
1400 long newFlags
= m_value
;
1402 if ( newFlags
!= m_oldValue
)
1404 // Set child modified states
1406 const wxPGChoices
& choices
= m_choices
;
1407 for ( i
= 0; i
<GetItemCount(); i
++ )
1411 if ( choices
.HasValue(i
) )
1412 flag
= choices
.GetValue(i
);
1416 if ( (newFlags
& flag
) != (m_oldValue
& flag
) )
1417 Item(i
)->SetFlag( wxPG_PROP_MODIFIED
);
1420 m_oldValue
= newFlags
;
1424 wxString
wxFlagsProperty::GetValueAsString( int ) const
1428 if ( !m_choices
.IsOk() )
1431 long flags
= m_value
;
1433 const wxPGChoices
& choices
= m_choices
;
1435 for ( i
= 0; i
< GetItemCount(); i
++ )
1438 if ( choices
.HasValue(i
) )
1439 doAdd
= ( flags
& choices
.GetValue(i
) );
1441 doAdd
= ( flags
& (1<<i
) );
1445 text
+= choices
.GetLabel(i
);
1450 // remove last comma
1451 if ( text
.Len() > 1 )
1452 text
.Truncate ( text
.Len() - 2 );
1457 // Translate string into flag tokens
1458 bool wxFlagsProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1460 if ( !m_choices
.IsOk() )
1464 long oldValue
= m_value
;
1466 // semicolons are no longer valid delimeters
1467 WX_PG_TOKENIZER1_BEGIN(text
,wxS(','))
1469 if ( token
.length() )
1471 // Determine which one it is
1472 long bit
= IdToBit( token
);
1485 WX_PG_TOKENIZER1_END()
1489 if ( newFlags
!= oldValue
)
1495 // Converts string id to a relevant bit.
1496 long wxFlagsProperty::IdToBit( const wxString
& id
) const
1499 for ( i
= 0; i
< GetItemCount(); i
++ )
1501 if ( id
== GetLabel(i
) )
1503 if ( m_choices
.HasValue(i
) )
1504 return m_choices
.GetValue(i
);
1511 void wxFlagsProperty::RefreshChildren()
1513 if ( !m_choices
.IsOk() || !GetChildCount() ) return;
1515 int flags
= m_value
.GetLong();
1517 const wxPGChoices
& choices
= m_choices
;
1519 for ( i
= 0; i
< GetItemCount(); i
++ )
1523 if ( choices
.HasValue(i
) )
1524 flag
= choices
.GetValue(i
);
1528 long subVal
= flags
& flag
;
1529 wxPGProperty
* p
= Item(i
);
1531 if ( subVal
!= (m_oldValue
& flag
) )
1532 p
->SetFlag( wxPG_PROP_MODIFIED
);
1534 p
->SetValue( subVal
?true:false );
1540 void wxFlagsProperty::ChildChanged( wxVariant
& thisValue
, int childIndex
, wxVariant
& childValue
) const
1542 long oldValue
= thisValue
.GetLong();
1543 long val
= childValue
.GetLong();
1544 unsigned long vi
= (1<<childIndex
);
1545 if ( m_choices
.HasValue(childIndex
) ) vi
= m_choices
.GetValue(childIndex
);
1547 thisValue
= (long)(oldValue
| vi
);
1549 thisValue
= (long)(oldValue
& ~(vi
));
1552 int wxFlagsProperty::GetChoiceInfo( wxPGChoiceInfo
* choiceinfo
)
1555 choiceinfo
->m_choices
= &m_choices
;
1559 // -----------------------------------------------------------------------
1561 // -----------------------------------------------------------------------
1563 WX_PG_IMPLEMENT_DERIVED_PROPERTY_CLASS(wxDirProperty
,wxLongStringProperty
,const wxString
&)
1565 wxDirProperty::wxDirProperty( const wxString
& name
, const wxString
& label
, const wxString
& value
)
1566 : wxLongStringProperty(name
,label
,value
)
1568 m_flags
|= wxPG_NO_ESCAPE
;
1570 wxDirProperty::~wxDirProperty() { }
1572 wxValidator
* wxDirProperty::DoGetValidator() const
1574 return wxFileProperty::GetClassValidator();
1577 bool wxDirProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1579 wxSize
dlg_sz(300,400);
1581 wxDirDialog
dlg( propGrid
,
1582 m_dlgMessage
.length() ? m_dlgMessage
: wxString(_("Choose a directory:")),
1585 #if !wxPG_SMALL_SCREEN
1586 propGrid
->GetGoodEditorDialogPosition(this,dlg_sz
),
1593 if ( dlg
.ShowModal() == wxID_OK
)
1595 value
= dlg
.GetPath();
1601 bool wxDirProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1603 if ( name
== wxPG_DIR_DIALOG_MESSAGE
)
1605 m_dlgMessage
= value
.GetString();
1611 // -----------------------------------------------------------------------
1612 // wxPGFileDialogAdapter
1613 // -----------------------------------------------------------------------
1615 bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1617 wxFileProperty
* fileProp
= NULL
;
1621 if ( property
->IsKindOf(CLASSINFO(wxFileProperty
)) )
1623 fileProp
= ((wxFileProperty
*)property
);
1624 path
= fileProp
->m_filename
.GetPath();
1625 indFilter
= fileProp
->m_indFilter
;
1627 if ( !path
.length() && fileProp
->m_basePath
.length() )
1628 path
= fileProp
->m_basePath
;
1632 wxFileName
fn(property
->GetValue().GetString());
1633 path
= fn
.GetPath();
1636 wxFileDialog
dlg( propGrid
->GetPanel(),
1637 property
->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1638 property
->GetAttribute(wxS("InitialPath"), path
),
1640 property
->GetAttribute(wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*")),
1642 wxDefaultPosition
);
1644 if ( indFilter
>= 0 )
1645 dlg
.SetFilterIndex( indFilter
);
1647 if ( dlg
.ShowModal() == wxID_OK
)
1650 fileProp
->m_indFilter
= dlg
.GetFilterIndex();
1651 SetValue( dlg
.GetPath() );
1657 // -----------------------------------------------------------------------
1659 // -----------------------------------------------------------------------
1661 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty
,wxPGProperty
,
1662 wxString
,const wxString
&,TextCtrlAndButton
)
1664 wxFileProperty::wxFileProperty( const wxString
& label
, const wxString
& name
,
1665 const wxString
& value
) : wxPGProperty(label
,name
)
1667 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1669 SetAttribute( wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*") );
1674 wxFileProperty::~wxFileProperty() {}
1676 #if wxUSE_VALIDATORS
1678 wxValidator
* wxFileProperty::GetClassValidator()
1680 WX_PG_DOGETVALIDATOR_ENTRY()
1682 // Atleast wxPython 2.6.2.1 required that the string argument is given
1684 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST
,&v
);
1686 wxArrayString exChars
;
1687 exChars
.Add(wxS("?"));
1688 exChars
.Add(wxS("*"));
1689 exChars
.Add(wxS("|"));
1690 exChars
.Add(wxS("<"));
1691 exChars
.Add(wxS(">"));
1692 exChars
.Add(wxS("\""));
1694 validator
->SetExcludes(exChars
);
1696 WX_PG_DOGETVALIDATOR_EXIT(validator
)
1699 wxValidator
* wxFileProperty::DoGetValidator() const
1701 return GetClassValidator();
1706 void wxFileProperty::OnSetValue()
1708 const wxString
& fnstr
= m_value
.GetString();
1712 if ( !m_filename
.HasName() )
1714 m_value
= wxPGVariant_EmptyString
;
1718 // Find index for extension.
1719 if ( m_indFilter
< 0 && fnstr
.length() )
1721 wxString ext
= m_filename
.GetExt();
1724 size_t len
= m_wildcard
.length();
1726 pos
= m_wildcard
.find(wxS("|"), pos
);
1727 while ( pos
!= wxString::npos
&& pos
< (len
-3) )
1729 size_t ext_begin
= pos
+ 3;
1731 pos
= m_wildcard
.find(wxS("|"), ext_begin
);
1732 if ( pos
== wxString::npos
)
1734 wxString found_ext
= m_wildcard
.substr(ext_begin
, pos
-ext_begin
);
1736 if ( found_ext
.length() > 0 )
1738 if ( found_ext
[0] == wxS('*') )
1740 m_indFilter
= curind
;
1743 if ( ext
.CmpNoCase(found_ext
) == 0 )
1745 m_indFilter
= curind
;
1751 pos
= m_wildcard
.find(wxS("|"), pos
+1);
1758 wxString
wxFileProperty::GetValueAsString( int argFlags
) const
1760 // Always return empty string when name component is empty
1761 wxString fullName
= m_filename
.GetFullName();
1762 if ( !fullName
.length() )
1765 if ( argFlags
& wxPG_FULL_VALUE
)
1767 return m_filename
.GetFullPath();
1769 else if ( m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
)
1771 if ( m_basePath
.Length() )
1773 wxFileName
fn2(m_filename
);
1774 fn2
.MakeRelativeTo(m_basePath
);
1775 return fn2
.GetFullPath();
1777 return m_filename
.GetFullPath();
1780 return m_filename
.GetFullName();
1783 wxPGEditorDialogAdapter
* wxFileProperty::GetEditorDialog() const
1785 return new wxPGFileDialogAdapter();
1788 bool wxFileProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1790 if ( (m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
) || (argFlags
& wxPG_FULL_VALUE
) )
1792 if ( m_filename
!= text
)
1800 if ( m_filename
.GetFullName() != text
)
1802 wxFileName fn
= m_filename
;
1803 fn
.SetFullName(text
);
1804 variant
= fn
.GetFullPath();
1812 bool wxFileProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1814 // Return false on some occasions to make sure those attribs will get
1815 // stored in m_attributes.
1816 if ( name
== wxPG_FILE_SHOW_FULL_PATH
)
1818 if ( wxPGVariantToInt(value
) )
1819 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1821 m_flags
&= ~(wxPG_PROP_SHOW_FULL_FILENAME
);
1824 else if ( name
== wxPG_FILE_WILDCARD
)
1826 m_wildcard
= value
.GetString();
1828 else if ( name
== wxPG_FILE_SHOW_RELATIVE_PATH
)
1830 m_basePath
= value
.GetString();
1832 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1833 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1835 else if ( name
== wxPG_FILE_INITIAL_PATH
)
1837 m_initialPath
= value
.GetString();
1840 else if ( name
== wxPG_FILE_DIALOG_TITLE
)
1842 m_dlgTitle
= value
.GetString();
1848 // -----------------------------------------------------------------------
1849 // wxPGLongStringDialogAdapter
1850 // -----------------------------------------------------------------------
1852 bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1854 wxString val1
= property
->GetValueAsString(0);
1855 wxString val_orig
= val1
;
1858 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1859 wxPropertyGrid::ExpandEscapeSequences(value
, val1
);
1861 value
= wxString(val1
);
1863 // Run editor dialog.
1864 if ( wxLongStringProperty::DisplayEditorDialog(property
, propGrid
, value
) )
1866 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1867 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1871 if ( val1
!= val_orig
)
1880 // -----------------------------------------------------------------------
1881 // wxLongStringProperty
1882 // -----------------------------------------------------------------------
1884 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty
,wxPGProperty
,
1885 wxString
,const wxString
&,TextCtrlAndButton
)
1887 wxLongStringProperty::wxLongStringProperty( const wxString
& label
, const wxString
& name
,
1888 const wxString
& value
) : wxPGProperty(label
,name
)
1893 wxLongStringProperty::~wxLongStringProperty() {}
1895 wxString
wxLongStringProperty::GetValueAsString( int ) const
1900 bool wxLongStringProperty::OnEvent( wxPropertyGrid
* propGrid
, wxWindow
* WXUNUSED(primary
),
1903 if ( propGrid
->IsMainButtonEvent(event
) )
1906 PrepareValueForDialogEditing(propGrid
);
1908 wxString val1
= GetValueAsString(0);
1909 wxString val_orig
= val1
;
1912 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1913 wxPropertyGrid::ExpandEscapeSequences(value
,val1
);
1915 value
= wxString(val1
);
1917 // Run editor dialog.
1918 if ( OnButtonClick(propGrid
,value
) )
1920 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1921 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1925 if ( val1
!= val_orig
)
1927 SetValueInEvent( val1
);
1935 bool wxLongStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1937 return DisplayEditorDialog(this, propGrid
, value
);
1940 bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty
* prop
, wxPropertyGrid
* propGrid
, wxString
& value
)
1943 // launch editor dialog
1944 wxDialog
* dlg
= new wxDialog(propGrid
,-1,prop
->GetLabel(),wxDefaultPosition
,wxDefaultSize
,
1945 wxDEFAULT_DIALOG_STYLE
|wxRESIZE_BORDER
|wxCLIP_CHILDREN
);
1947 dlg
->SetFont(propGrid
->GetFont()); // To allow entering chars of the same set as the propGrid
1949 // Multi-line text editor dialog.
1950 #if !wxPG_SMALL_SCREEN
1951 const int spacing
= 8;
1953 const int spacing
= 4;
1955 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
1956 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
1957 wxTextCtrl
* ed
= new wxTextCtrl(dlg
,11,value
,
1958 wxDefaultPosition
,wxDefaultSize
,wxTE_MULTILINE
);
1960 rowsizer
->Add( ed
, 1, wxEXPAND
|wxALL
, spacing
);
1961 topsizer
->Add( rowsizer
, 1, wxEXPAND
, 0 );
1962 rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
1963 const int but_sz_flags
=
1964 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxBOTTOM
|wxLEFT
|wxRIGHT
;
1965 rowsizer
->Add( new wxButton(dlg
,wxID_OK
,_("Ok")),
1966 0, but_sz_flags
, spacing
);
1967 rowsizer
->Add( new wxButton(dlg
,wxID_CANCEL
,_("Cancel")),
1968 0, but_sz_flags
, spacing
);
1969 topsizer
->Add( rowsizer
, 0, wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
, 0 );
1971 dlg
->SetSizer( topsizer
);
1972 topsizer
->SetSizeHints( dlg
);
1974 #if !wxPG_SMALL_SCREEN
1975 dlg
->SetSize(400,300);
1977 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(prop
,dlg
->GetSize()) );
1980 int res
= dlg
->ShowModal();
1982 if ( res
== wxID_OK
)
1984 value
= ed
->GetValue();
1992 bool wxLongStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1994 if ( m_value
!= text
)
2002 // -----------------------------------------------------------------------
2003 // wxArrayEditorDialog
2004 // -----------------------------------------------------------------------
2006 BEGIN_EVENT_TABLE(wxArrayEditorDialog
, wxDialog
)
2007 EVT_IDLE(wxArrayEditorDialog::OnIdle
)
2008 EVT_LISTBOX(24, wxArrayEditorDialog::OnListBoxClick
)
2009 EVT_TEXT_ENTER(21, wxArrayEditorDialog::OnAddClick
)
2010 EVT_BUTTON(22, wxArrayEditorDialog::OnAddClick
)
2011 EVT_BUTTON(23, wxArrayEditorDialog::OnDeleteClick
)
2012 EVT_BUTTON(25, wxArrayEditorDialog::OnUpClick
)
2013 EVT_BUTTON(26, wxArrayEditorDialog::OnDownClick
)
2014 EVT_BUTTON(27, wxArrayEditorDialog::OnUpdateClick
)
2015 //EVT_BUTTON(28, wxArrayEditorDialog::OnCustomEditClick)
2018 IMPLEMENT_ABSTRACT_CLASS(wxArrayEditorDialog
, wxDialog
)
2020 #include <wx/statline.h>
2022 // -----------------------------------------------------------------------
2024 void wxArrayEditorDialog::OnIdle(wxIdleEvent
& event
)
2027 // Do control focus detection here.
2030 wxWindow
* focused
= FindFocus();
2032 // This strange focus thing is a workaround for wxGTK wxListBox focus
2034 if ( m_curFocus
== 0 && focused
!= m_edValue
&&
2035 focused
!= m_butAdd
&& focused
!= m_butUpdate
&&
2036 m_lbStrings
->GetSelection() >= 0 )
2038 // ListBox was just focused.
2039 m_butAdd
->Enable(false);
2040 m_butUpdate
->Enable(false);
2041 m_butRemove
->Enable(true);
2042 m_butUp
->Enable(true);
2043 m_butDown
->Enable(true);
2046 else if ( (m_curFocus
== 1 && focused
== m_edValue
) /*|| m_curFocus == 2*/ )
2048 // TextCtrl was just focused.
2049 m_butAdd
->Enable(true);
2050 bool upd_enable
= false;
2051 if ( m_lbStrings
->GetCount() && m_lbStrings
->GetSelection() >= 0 )
2053 m_butUpdate
->Enable(upd_enable
);
2054 m_butRemove
->Enable(false);
2055 m_butUp
->Enable(false);
2056 m_butDown
->Enable(false);
2063 // -----------------------------------------------------------------------
2065 wxArrayEditorDialog::wxArrayEditorDialog()
2071 // -----------------------------------------------------------------------
2073 void wxArrayEditorDialog::Init()
2075 m_custBtText
= (const wxChar
*) NULL
;
2078 // -----------------------------------------------------------------------
2080 wxArrayEditorDialog::wxArrayEditorDialog( wxWindow
*parent
,
2081 const wxString
& message
,
2082 const wxString
& caption
,
2089 Create(parent
,message
,caption
,style
,pos
,sz
);
2092 // -----------------------------------------------------------------------
2094 bool wxArrayEditorDialog::Create( wxWindow
*parent
,
2095 const wxString
& message
,
2096 const wxString
& caption
,
2101 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2102 // FIXME: This should be only a temporary fix.
2104 int useStyle
= wxCAPTION
;
2106 int useStyle
= style
;
2109 bool res
= wxDialog::Create(parent
, wxID_ANY
, caption
, pos
, sz
, useStyle
);
2111 SetFont(parent
->GetFont()); // To allow entering chars of the same set as the propGrid
2113 #if !wxPG_SMALL_SCREEN
2114 const int spacing
= 4;
2116 const int spacing
= 3;
2123 const int but_sz_flags
=
2124 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxALL
; //wxBOTTOM|wxLEFT|wxRIGHT;
2126 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2129 if ( message
.length() )
2130 topsizer
->Add( new wxStaticText(this,-1,message
),
2131 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2134 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2135 m_edValue
= new wxTextCtrl(this,21,wxEmptyString
,
2136 wxDefaultPosition
,wxDefaultSize
,wxTE_PROCESS_ENTER
);
2137 wxValidator
* validator
= GetTextCtrlValidator();
2140 m_edValue
->SetValidator( *validator
);
2143 rowsizer
->Add( m_edValue
,
2144 1, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2147 m_butAdd
= new wxButton(this,22,_("Add"));
2148 rowsizer
->Add( m_butAdd
,
2149 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxTOP
|wxBOTTOM
|wxRIGHT
, spacing
);
2150 topsizer
->Add( rowsizer
, 0, wxEXPAND
, spacing
);
2153 topsizer
->Add( new wxStaticLine(this,-1),
2154 0, wxEXPAND
|wxBOTTOM
|wxLEFT
|wxRIGHT
, spacing
);
2156 rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2159 m_lbStrings
= new wxListBox(this, 24, wxDefaultPosition
, wxDefaultSize
);
2161 for ( i
=0; i
<ArrayGetCount(); i
++ )
2162 m_lbStrings
->Append( ArrayGet(i
) );
2163 rowsizer
->Add( m_lbStrings
, 1, wxEXPAND
|wxRIGHT
, spacing
);
2165 // Manipulator buttons
2166 wxBoxSizer
* colsizer
= new wxBoxSizer( wxVERTICAL
);
2167 m_butCustom
= (wxButton
*) NULL
;
2170 m_butCustom
= new wxButton(this,28,::wxGetTranslation(m_custBtText
));
2171 colsizer
->Add( m_butCustom
,
2172 0, wxALIGN_CENTER
|wxTOP
/*wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT*/,
2175 m_butUpdate
= new wxButton(this,27,_("Update"));
2176 colsizer
->Add( m_butUpdate
,
2177 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2178 m_butRemove
= new wxButton(this,23,_("Remove"));
2179 colsizer
->Add( m_butRemove
,
2180 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2181 m_butUp
= new wxButton(this,25,_("Up"));
2182 colsizer
->Add( m_butUp
,
2183 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2184 m_butDown
= new wxButton(this,26,_("Down"));
2185 colsizer
->Add( m_butDown
,
2186 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2187 rowsizer
->Add( colsizer
, 0, 0, spacing
);
2189 topsizer
->Add( rowsizer
, 1, wxLEFT
|wxRIGHT
|wxEXPAND
, spacing
);
2192 topsizer
->Add( new wxStaticLine(this,-1),
2193 0, wxEXPAND
|wxTOP
|wxLEFT
|wxRIGHT
, spacing
);
2196 rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2198 const int but_sz_flags =
2199 wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT;
2201 rowsizer
->Add( new wxButton(this,wxID_OK
,_("Ok")),
2202 0, but_sz_flags
, spacing
);
2203 rowsizer
->Add( new wxButton(this,wxID_CANCEL
,_("Cancel")),
2204 0, but_sz_flags
, spacing
);
2205 topsizer
->Add( rowsizer
, 0, wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
, 0 );
2207 m_edValue
->SetFocus();
2209 SetSizer( topsizer
);
2210 topsizer
->SetSizeHints( this );
2212 #if !wxPG_SMALL_SCREEN
2213 if ( sz
.x
== wxDefaultSize
.x
&&
2214 sz
.y
== wxDefaultSize
.y
)
2215 SetSize( wxSize(275,360) );
2223 // -----------------------------------------------------------------------
2225 void wxArrayEditorDialog::OnAddClick(wxCommandEvent
& )
2227 wxString text
= m_edValue
->GetValue();
2228 if ( text
.length() )
2230 if ( ArrayInsert( text
, -1 ) )
2232 m_lbStrings
->Append( text
);
2239 // -----------------------------------------------------------------------
2241 void wxArrayEditorDialog::OnDeleteClick(wxCommandEvent
& )
2243 int index
= m_lbStrings
->GetSelection();
2246 ArrayRemoveAt( index
);
2247 m_lbStrings
->Delete ( index
);
2252 // -----------------------------------------------------------------------
2254 void wxArrayEditorDialog::OnUpClick(wxCommandEvent
& )
2256 int index
= m_lbStrings
->GetSelection();
2259 ArraySwap(index
-1,index
);
2260 /*wxString old_str = m_array[index-1];
2261 wxString new_str = m_array[index];
2262 m_array[index-1] = new_str;
2263 m_array[index] = old_str;*/
2264 m_lbStrings
->SetString ( index
-1, ArrayGet(index
-1) );
2265 m_lbStrings
->SetString ( index
, ArrayGet(index
) );
2266 m_lbStrings
->SetSelection ( index
-1 );
2271 // -----------------------------------------------------------------------
2273 void wxArrayEditorDialog::OnDownClick(wxCommandEvent
& )
2275 int index
= m_lbStrings
->GetSelection();
2276 int lastStringIndex
= ((int) m_lbStrings
->GetCount()) - 1;
2277 if ( index
>= 0 && index
< lastStringIndex
)
2279 ArraySwap(index
,index
+1);
2280 /*wxString old_str = m_array[index+1];
2281 wxString new_str = m_array[index];
2282 m_array[index+1] = new_str;
2283 m_array[index] = old_str;*/
2284 m_lbStrings
->SetString ( index
+1, ArrayGet(index
+1) );
2285 m_lbStrings
->SetString ( index
, ArrayGet(index
) );
2286 m_lbStrings
->SetSelection ( index
+1 );
2291 // -----------------------------------------------------------------------
2293 void wxArrayEditorDialog::OnUpdateClick(wxCommandEvent
& )
2295 int index
= m_lbStrings
->GetSelection();
2298 wxString str
= m_edValue
->GetValue();
2299 if ( ArraySet(index
,str
) )
2301 m_lbStrings
->SetString ( index
, str
);
2302 //m_array[index] = str;
2308 // -----------------------------------------------------------------------
2310 void wxArrayEditorDialog::OnListBoxClick(wxCommandEvent
& )
2312 int index
= m_lbStrings
->GetSelection();
2315 m_edValue
->SetValue( m_lbStrings
->GetString(index
) );
2319 // -----------------------------------------------------------------------
2320 // wxPGArrayStringEditorDialog
2321 // -----------------------------------------------------------------------
2323 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog
, wxArrayEditorDialog
)
2325 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog
, wxArrayEditorDialog
)
2326 EVT_BUTTON(28, wxPGArrayStringEditorDialog::OnCustomEditClick
)
2329 // -----------------------------------------------------------------------
2331 wxString
wxPGArrayStringEditorDialog::ArrayGet( size_t index
)
2333 return m_array
[index
];
2336 size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2338 return m_array
.size();
2341 bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString
& str
, int index
)
2346 m_array
.Insert(str
,index
);
2350 bool wxPGArrayStringEditorDialog::ArraySet( size_t index
, const wxString
& str
)
2352 m_array
[index
] = str
;
2356 void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index
)
2358 m_array
.RemoveAt(index
);
2361 void wxPGArrayStringEditorDialog::ArraySwap( size_t first
, size_t second
)
2363 wxString old_str
= m_array
[first
];
2364 wxString new_str
= m_array
[second
];
2365 m_array
[first
] = new_str
;
2366 m_array
[second
] = old_str
;
2369 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2370 : wxArrayEditorDialog()
2375 void wxPGArrayStringEditorDialog::Init()
2377 m_pCallingClass
= (wxArrayStringProperty
*) NULL
;
2380 void wxPGArrayStringEditorDialog::OnCustomEditClick(wxCommandEvent
& )
2382 wxASSERT( m_pCallingClass
);
2383 wxString str
= m_edValue
->GetValue();
2384 if ( m_pCallingClass
->OnCustomStringEdit(m_parent
,str
) )
2386 //m_edValue->SetValue ( str );
2387 m_lbStrings
->Append ( str
);
2388 m_array
.Add ( str
);
2393 // -----------------------------------------------------------------------
2394 // wxArrayStringProperty
2395 // -----------------------------------------------------------------------
2397 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty
, // Property name
2398 wxPGProperty
, // Property we inherit from
2399 wxArrayString
, // Value type name
2400 const wxArrayString
&, // Value type, as given in constructor
2401 TextCtrlAndButton
) // Initial editor
2403 wxArrayStringProperty::wxArrayStringProperty( const wxString
& label
,
2404 const wxString
& name
,
2405 const wxArrayString
& array
)
2406 : wxPGProperty(label
,name
)
2411 wxArrayStringProperty::~wxArrayStringProperty() { }
2413 void wxArrayStringProperty::OnSetValue()
2415 GenerateValueAsString();
2418 wxString
wxArrayStringProperty::GetValueAsString( int WXUNUSED(argFlags
) ) const
2423 // Converts wxArrayString to a string separated by delimeters and spaces.
2424 // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2426 void wxPropertyGrid::ArrayStringToString( wxString
& dst
, const wxArrayString
& src
,
2427 wxChar preDelim
, wxChar postDelim
,
2433 unsigned int itemCount
= src
.size();
2441 else if ( (flags
& 1) )
2443 preas
[0] = preDelim
;
2450 dst
.append( preas
);
2452 wxASSERT( postDelim
);
2453 wxString
postDelimStr(postDelim
);
2454 //wxString preDelimStr(preDelim);
2456 for ( i
= 0; i
< itemCount
; i
++ )
2458 wxString
str( src
.Item(i
) );
2460 // Do some character conversion.
2461 // Convertes \ to \\ and <preDelim> to \<preDelim>
2462 // Useful when preDelim and postDelim are "\"".
2465 str
.Replace( wxS("\\"), wxS("\\\\"), true );
2467 str
.Replace( preas
, pdr
, true );
2472 if ( i
< (itemCount
-1) )
2474 dst
.append( postDelimStr
);
2475 dst
.append( wxS(" ") );
2476 dst
.append( preas
);
2478 else if ( preDelim
)
2479 dst
.append( postDelimStr
);
2483 #define ARRSTRPROP_ARRAY_TO_STRING(STRING,ARRAY) \
2484 wxPropertyGrid::ArrayStringToString(STRING,ARRAY,wxS('"'),wxS('"'),1);
2486 void wxArrayStringProperty::GenerateValueAsString()
2488 wxArrayString arr
= m_value
.GetArrayString();
2489 ARRSTRPROP_ARRAY_TO_STRING(m_display
, arr
)
2492 // Default implementation doesn't do anything.
2493 bool wxArrayStringProperty::OnCustomStringEdit( wxWindow
*, wxString
& )
2498 wxArrayEditorDialog
* wxArrayStringProperty::CreateEditorDialog()
2500 return new wxPGArrayStringEditorDialog();
2503 bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
,
2504 wxWindow
* WXUNUSED(primaryCtrl
),
2508 PrepareValueForDialogEditing(propGrid
);
2510 if ( !propGrid
->EditorValidate() )
2513 // Create editor dialog.
2514 wxArrayEditorDialog
* dlg
= CreateEditorDialog();
2515 #if wxUSE_VALIDATORS
2516 wxValidator
* validator
= GetValidator();
2517 wxPGInDialogValidator dialogValidator
;
2520 wxPGArrayStringEditorDialog
* strEdDlg
= wxDynamicCast(dlg
, wxPGArrayStringEditorDialog
);
2523 strEdDlg
->SetCustomButton(cbt
, this);
2525 dlg
->SetDialogValue( wxVariant(m_value
) );
2526 dlg
->Create(propGrid
, wxEmptyString
, m_label
);
2528 #if !wxPG_SMALL_SCREEN
2529 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(this,dlg
->GetSize()) );
2538 int res
= dlg
->ShowModal();
2540 if ( res
== wxID_OK
&& dlg
->IsModified() )
2542 wxVariant value
= dlg
->GetDialogValue();
2543 if ( !value
.IsNull() )
2545 wxArrayString actualValue
= value
.GetArrayString();
2547 ARRSTRPROP_ARRAY_TO_STRING(tempStr
, actualValue
)
2548 #if wxUSE_VALIDATORS
2549 if ( dialogValidator
.DoValidate( propGrid
, validator
, tempStr
) )
2552 SetValueInEvent( actualValue
);
2569 bool wxArrayStringProperty::OnEvent( wxPropertyGrid
* propGrid
,
2573 if ( propGrid
->IsMainButtonEvent(event
) )
2574 return OnButtonClick(propGrid
,primary
,(const wxChar
*) NULL
);
2578 bool wxArrayStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
2582 WX_PG_TOKENIZER2_BEGIN(text
,wxS('"'))
2584 // Need to replace backslashes with empty characters
2585 // (opposite what is done in GenerateValueString).
2586 token
.Replace ( wxS("\\"), wxEmptyString
, true );
2590 WX_PG_TOKENIZER2_END()
2597 // -----------------------------------------------------------------------
2598 // wxPGInDialogValidator
2599 // -----------------------------------------------------------------------
2601 #if wxUSE_VALIDATORS
2602 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* propGrid
,
2603 wxValidator
* validator
,
2604 const wxString
& value
)
2609 wxTextCtrl
* tc
= m_textCtrl
;
2614 tc
= new wxTextCtrl( propGrid
, wxPG_SUBID_TEMP1
, wxEmptyString
,
2615 wxPoint(30000,30000));
2622 tc
->SetValue(value
);
2624 validator
->SetWindow(tc
);
2625 bool res
= validator
->Validate(propGrid
);
2630 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* WXUNUSED(propGrid
),
2631 wxValidator
* WXUNUSED(validator
),
2632 const wxString
& WXUNUSED(value
) )
2638 // -----------------------------------------------------------------------
2640 #endif // wxUSE_PROPGRID