1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/props.cpp
3 // Purpose: Basic Property Classes
4 // Author: Jaakko Salli
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows licence
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"
34 #include "wx/bmpbuttn.h"
37 #include "wx/cursor.h"
38 #include "wx/dialog.h"
39 #include "wx/settings.h"
40 #include "wx/msgdlg.h"
41 #include "wx/choice.h"
42 #include "wx/stattext.h"
43 #include "wx/scrolwin.h"
44 #include "wx/dirdlg.h"
45 #include "wx/combobox.h"
46 #include "wx/layout.h"
48 #include "wx/textdlg.h"
49 #include "wx/filedlg.h"
53 #include "wx/filename.h"
55 #include "wx/propgrid/propgrid.h"
57 #define wxPG_CUSTOM_IMAGE_WIDTH 20 // for wxColourProperty etc.
60 // -----------------------------------------------------------------------
62 // -----------------------------------------------------------------------
64 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxStringProperty
,wxPGProperty
,
65 wxString
,const wxString
&,TextCtrl
)
67 wxStringProperty::wxStringProperty( const wxString
& label
,
69 const wxString
& value
)
70 : wxPGProperty(label
,name
)
75 void wxStringProperty::OnSetValue()
77 if ( !m_value
.IsNull() && m_value
.GetString() == wxS("<composed>") )
78 SetFlag(wxPG_PROP_COMPOSED_VALUE
);
80 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
83 DoGenerateComposedValue(s
);
88 wxStringProperty::~wxStringProperty() { }
90 wxString
wxStringProperty::ValueToString( wxVariant
& value
,
93 wxString s
= value
.GetString();
95 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
97 // Value stored in m_value is non-editable, non-full value
98 if ( (argFlags
& wxPG_FULL_VALUE
) || (argFlags
& wxPG_EDITABLE_VALUE
) )
100 // Calling this under incorrect conditions will fail
101 wxASSERT_MSG( argFlags
& wxPG_VALUE_IS_CURRENT
,
102 "Sorry, currently default wxPGProperty::ValueToString() "
103 "implementation only works if value is m_value." );
105 DoGenerateComposedValue(s
, argFlags
);
111 // If string is password and value is for visual purposes,
112 // then return asterisks instead the actual string.
113 if ( (m_flags
& wxPG_PROP_PASSWORD
) && !(argFlags
& (wxPG_FULL_VALUE
|wxPG_EDITABLE_VALUE
)) )
114 return wxString(wxChar('*'), s
.Length());
119 bool wxStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
121 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
122 return wxPGProperty::StringToValue(variant
, text
, argFlags
);
124 if ( variant
!= text
)
133 bool wxStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
135 if ( name
== wxPG_STRING_PASSWORD
)
137 m_flags
&= ~(wxPG_PROP_PASSWORD
);
138 if ( value
.GetLong() ) m_flags
|= wxPG_PROP_PASSWORD
;
145 // -----------------------------------------------------------------------
147 // -----------------------------------------------------------------------
149 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty
,wxPGProperty
,
152 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
153 long value
) : wxPGProperty(label
,name
)
158 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
159 const wxLongLong
& value
) : wxPGProperty(label
,name
)
161 SetValue(WXVARIANT(value
));
164 wxIntProperty::~wxIntProperty() { }
166 wxString
wxIntProperty::ValueToString( wxVariant
& value
,
167 int WXUNUSED(argFlags
) ) const
169 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
171 return wxString::Format(wxS("%li"),value
.GetLong());
173 else if ( value
.GetType() == wxPG_VARIANT_TYPE_LONGLONG
)
175 wxLongLong ll
= value
.GetLongLong();
176 return ll
.ToString();
179 return wxEmptyString
;
182 bool wxIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
187 if ( text
.length() == 0 )
193 // We know it is a number, but let's still check
195 if ( text
.IsNumber() )
197 // Remove leading zeroes, so that the number is not interpreted as octal
198 wxString::const_iterator i
= text
.begin();
199 wxString::const_iterator iMax
= text
.end() - 1; // Let's allow one, last zero though
201 int firstNonZeroPos
= 0;
203 for ( ; i
!= iMax
; ++i
)
206 if ( c
!= wxS('0') && c
!= wxS(' ') )
211 wxString useText
= text
.substr(firstNonZeroPos
, text
.length() - firstNonZeroPos
);
213 wxString variantType
= variant
.GetType();
214 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
216 wxLongLong_t value64
= 0;
218 if ( useText
.ToLongLong(&value64
, 10) &&
219 ( value64
>= INT_MAX
|| value64
<= INT_MIN
)
222 bool doChangeValue
= isPrevLong
;
224 if ( !isPrevLong
&& variantType
== wxPG_VARIANT_TYPE_LONGLONG
)
226 wxLongLong oldValue
= variant
.GetLongLong();
227 if ( oldValue
.GetValue() != value64
)
228 doChangeValue
= true;
233 wxLongLong
ll(value64
);
239 if ( useText
.ToLong( &value32
, 0 ) )
241 if ( !isPrevLong
|| variant
!= value32
)
248 else if ( argFlags
& wxPG_REPORT_ERROR
)
254 bool wxIntProperty::IntToValue( wxVariant
& variant
, int value
, int WXUNUSED(argFlags
) ) const
256 if ( variant
.GetType() != wxPG_VARIANT_TYPE_LONG
|| variant
!= (long)value
)
258 variant
= (long)value
;
265 // Common validation code to be called in ValidateValue()
268 // Note that 'value' is reference on purpose, so we can write
269 // back to it when mode is wxPG_PROPERTY_VALIDATION_SATURATE.
272 bool NumericValidation( const wxPGProperty
* property
,
274 wxPGValidationInfo
* pValidationInfo
,
276 const wxString
& strFmt
)
278 T min
= (T
) wxINT64_MIN
;
279 T max
= (T
) wxINT64_MAX
;
284 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
285 if ( !variant
.IsNull() )
287 variant
.Convert(&min
);
291 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
292 if ( !variant
.IsNull() )
294 variant
.Convert(&max
);
302 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
305 wxString smin
= wxString::Format(strFmt
, min
);
306 wxString smax
= wxString::Format(strFmt
, max
);
308 msg
= wxString::Format(
309 _("Value must be %s or higher."),
312 msg
= wxString::Format(
313 _("Value must be between %s and %s."),
314 smin
.c_str(), smax
.c_str());
315 pValidationInfo
->SetFailureMessage(msg
);
317 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
320 value
= max
- (min
- value
);
329 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
332 wxString smin
= wxString::Format(strFmt
, min
);
333 wxString smax
= wxString::Format(strFmt
, max
);
335 msg
= wxString::Format(
336 _("Value must be %s or less."),
339 msg
= wxString::Format(
340 _("Value must be between %s and %s."),
341 smin
.c_str(), smax
.c_str());
342 pValidationInfo
->SetFailureMessage(msg
);
344 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
347 value
= min
+ (value
- max
);
354 bool wxIntProperty::DoValidation( const wxPGProperty
* property
,
356 wxPGValidationInfo
* pValidationInfo
,
359 return NumericValidation
<wxLongLong_t
>(property
,
366 bool wxIntProperty::ValidateValue( wxVariant
& value
,
367 wxPGValidationInfo
& validationInfo
) const
369 wxLongLong_t ll
= value
.GetLongLong().GetValue();
370 return DoValidation(this, ll
, &validationInfo
,
371 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
374 wxValidator
* wxIntProperty::GetClassValidator()
377 WX_PG_DOGETVALIDATOR_ENTRY()
379 // Atleast wxPython 2.6.2.1 required that the string argument is given
381 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_NUMERIC
,&v
);
383 WX_PG_DOGETVALIDATOR_EXIT(validator
)
389 wxValidator
* wxIntProperty::DoGetValidator() const
391 return GetClassValidator();
394 // -----------------------------------------------------------------------
396 // -----------------------------------------------------------------------
399 #define wxPG_UINT_TEMPLATE_MAX 8
401 static const wxChar
* const gs_uintTemplates32
[wxPG_UINT_TEMPLATE_MAX
] = {
402 wxT("%x"),wxT("0x%x"),wxT("$%x"),
403 wxT("%X"),wxT("0x%X"),wxT("$%X"),
407 static const char* const gs_uintTemplates64
[wxPG_UINT_TEMPLATE_MAX
] = {
408 "%" wxLongLongFmtSpec
"x",
409 "0x%" wxLongLongFmtSpec
"x",
410 "$%" wxLongLongFmtSpec
"x",
411 "%" wxLongLongFmtSpec
"X",
412 "0x%" wxLongLongFmtSpec
"X",
413 "$%" wxLongLongFmtSpec
"X",
414 "%" wxLongLongFmtSpec
"u",
415 "%" wxLongLongFmtSpec
"o"
418 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty
,wxPGProperty
,
419 long,unsigned long,TextCtrl
)
421 void wxUIntProperty::Init()
423 m_base
= 6; // This is magic number for dec base (must be same as in setattribute)
425 m_prefix
= wxPG_PREFIX_NONE
;
428 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
429 unsigned long value
) : wxPGProperty(label
,name
)
432 SetValue((long)value
);
435 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
436 const wxULongLong
& value
) : wxPGProperty(label
,name
)
439 SetValue(WXVARIANT(value
));
442 wxUIntProperty::~wxUIntProperty() { }
444 wxString
wxUIntProperty::ValueToString( wxVariant
& value
,
445 int WXUNUSED(argFlags
) ) const
447 size_t index
= m_base
+ m_prefix
;
448 if ( index
>= wxPG_UINT_TEMPLATE_MAX
)
449 index
= wxPG_BASE_DEC
;
451 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
453 return wxString::Format(gs_uintTemplates32
[index
],
454 (unsigned long)value
.GetLong());
457 wxULongLong ull
= value
.GetULongLong();
459 return wxString::Format(gs_uintTemplates64
[index
], ull
.GetValue());
462 bool wxUIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
464 wxString variantType
= variant
.GetType();
465 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
467 if ( text
.length() == 0 )
474 if ( text
[0] == wxS('$') )
477 wxULongLong_t value64
= 0;
478 wxString s
= text
.substr(start
, text
.length() - start
);
480 if ( s
.ToULongLong(&value64
, (unsigned int)m_realBase
) )
482 if ( value64
>= LONG_MAX
)
484 bool doChangeValue
= isPrevLong
;
486 if ( !isPrevLong
&& variantType
== wxPG_VARIANT_TYPE_ULONGLONG
)
488 wxULongLong oldValue
= variant
.GetULongLong();
489 if ( oldValue
.GetValue() != value64
)
490 doChangeValue
= true;
495 variant
= wxULongLong(value64
);
501 unsigned long value32
= wxLongLong(value64
).GetLo();
502 if ( !isPrevLong
|| m_value
!= (long)value32
)
504 variant
= (long)value32
;
513 bool wxUIntProperty::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
515 if ( variant
!= (long)number
)
517 variant
= (long)number
;
523 bool wxUIntProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
525 wxULongLong_t uul
= value
.GetULongLong().GetValue();
527 NumericValidation
<wxULongLong_t
>(this,
530 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
,
534 bool wxUIntProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
536 if ( name
== wxPG_UINT_BASE
)
538 int val
= value
.GetLong();
540 m_realBase
= (wxByte
) val
;
541 if ( m_realBase
> 16 )
545 // Translate logical base to a template array index
547 if ( val
== wxPG_BASE_HEX
)
549 else if ( val
== wxPG_BASE_DEC
)
551 else if ( val
== wxPG_BASE_HEXL
)
555 else if ( name
== wxPG_UINT_PREFIX
)
557 m_prefix
= (wxByte
) value
.GetLong();
563 // -----------------------------------------------------------------------
565 // -----------------------------------------------------------------------
567 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty
,wxPGProperty
,
568 double,double,TextCtrl
)
570 wxFloatProperty::wxFloatProperty( const wxString
& label
,
571 const wxString
& name
,
573 : wxPGProperty(label
,name
)
579 wxFloatProperty::~wxFloatProperty() { }
581 // This helper method provides standard way for floating point-using
582 // properties to convert values to string.
583 void wxPropertyGrid::DoubleToString(wxString
& target
,
587 wxString
* precTemplate
)
589 if ( precision
>= 0 )
593 precTemplate
= &text1
;
595 if ( !precTemplate
->length() )
597 *precTemplate
= wxS("%.");
598 *precTemplate
<< wxString::Format( wxS("%i"), precision
);
599 *precTemplate
<< wxS('f');
602 target
.Printf( precTemplate
->c_str(), value
);
606 target
.Printf( wxS("%f"), value
);
609 if ( removeZeroes
&& precision
!= 0 && target
.length() )
611 // Remove excess zeroes (do not remove this code just yet,
612 // since sprintf can't do the same consistently across platforms).
613 wxString::const_iterator i
= target
.end() - 1;
614 size_t new_len
= target
.length() - 1;
616 for ( ; i
!= target
.begin(); --i
)
618 if ( *i
!= wxS('0') )
623 wxChar cur_char
= *i
;
624 if ( cur_char
!= wxS('.') && cur_char
!= wxS(',') )
627 if ( new_len
!= target
.length() )
628 target
.resize(new_len
);
632 wxString
wxFloatProperty::ValueToString( wxVariant
& value
,
636 if ( !value
.IsNull() )
638 wxPropertyGrid::DoubleToString(text
,
641 !(argFlags
& wxPG_FULL_VALUE
),
647 bool wxFloatProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
652 if ( text
.length() == 0 )
658 bool res
= text
.ToDouble(&value
);
661 if ( variant
!= value
)
667 else if ( argFlags
& wxPG_REPORT_ERROR
)
673 bool wxFloatProperty::DoValidation( const wxPGProperty
* property
,
675 wxPGValidationInfo
* pValidationInfo
,
678 return NumericValidation
<double>(property
,
686 wxFloatProperty::ValidateValue( wxVariant
& value
,
687 wxPGValidationInfo
& validationInfo
) const
689 double fpv
= value
.GetDouble();
690 return DoValidation(this, fpv
, &validationInfo
,
691 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
694 bool wxFloatProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
696 if ( name
== wxPG_FLOAT_PRECISION
)
698 m_precision
= value
.GetLong();
704 wxValidator
* wxFloatProperty::DoGetValidator() const
706 return wxIntProperty::GetClassValidator();
709 // -----------------------------------------------------------------------
711 // -----------------------------------------------------------------------
713 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
714 // there is a custom GetEditorClass.
716 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty
, wxPGProperty
)
718 const wxPGEditor
* wxBoolProperty::DoGetEditorClass() const
720 // Select correct editor control.
721 #if wxPG_INCLUDE_CHECKBOX
722 if ( !(m_flags
& wxPG_PROP_USE_CHECKBOX
) )
723 return wxPGEditor_Choice
;
724 return wxPGEditor_CheckBox
;
726 return wxPGEditor_Choice
;
730 wxBoolProperty::wxBoolProperty( const wxString
& label
, const wxString
& name
, bool value
) :
731 wxPGProperty(label
,name
)
733 m_choices
.Assign(wxPGGlobalVars
->m_boolChoices
);
735 SetValue(wxPGVariant_Bool(value
));
737 m_flags
|= wxPG_PROP_USE_DCC
;
740 wxBoolProperty::~wxBoolProperty() { }
742 wxString
wxBoolProperty::ValueToString( wxVariant
& value
,
745 bool boolValue
= value
.GetBool();
747 // As a fragment of composite string value,
748 // make it a little more readable.
749 if ( argFlags
& wxPG_COMPOSITE_FRAGMENT
)
757 if ( argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
)
758 return wxEmptyString
;
761 if ( wxPGGlobalVars
->m_autoGetTranslation
)
762 notFmt
= _("Not %s");
764 notFmt
= wxS("Not %s");
766 return wxString::Format(notFmt
.c_str(), m_label
.c_str());
770 if ( !(argFlags
& wxPG_FULL_VALUE
) )
772 return wxPGGlobalVars
->m_boolChoices
[boolValue
?1:0].GetText();
777 if ( boolValue
) text
= wxS("true");
778 else text
= wxS("false");
783 bool wxBoolProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
785 bool boolValue
= false;
786 if ( text
.CmpNoCase(wxPGGlobalVars
->m_boolChoices
[1].GetText()) == 0 ||
787 text
.CmpNoCase(wxS("true")) == 0 ||
788 text
.CmpNoCase(m_label
) == 0 )
791 if ( text
.length() == 0 )
797 if ( variant
!= boolValue
)
799 variant
= wxPGVariant_Bool(boolValue
);
805 bool wxBoolProperty::IntToValue( wxVariant
& variant
, int value
, int ) const
807 bool boolValue
= value
? true : false;
809 if ( variant
!= boolValue
)
811 variant
= wxPGVariant_Bool(boolValue
);
817 bool wxBoolProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
819 #if wxPG_INCLUDE_CHECKBOX
820 if ( name
== wxPG_BOOL_USE_CHECKBOX
)
822 if ( value
.GetLong() )
823 m_flags
|= wxPG_PROP_USE_CHECKBOX
;
825 m_flags
&= ~(wxPG_PROP_USE_CHECKBOX
);
829 if ( name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
831 if ( value
.GetLong() )
832 m_flags
|= wxPG_PROP_USE_DCC
;
834 m_flags
&= ~(wxPG_PROP_USE_DCC
);
840 // -----------------------------------------------------------------------
842 // -----------------------------------------------------------------------
844 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty
, wxPGProperty
)
846 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty
,long,Choice
)
848 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
849 const long* values
, int value
) : wxPGProperty(label
,name
)
855 m_choices
.Add(labels
,values
);
857 if ( GetItemCount() )
858 SetValue( (long)value
);
862 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
863 const long* values
, wxPGChoices
* choicesCache
, int value
)
864 : wxPGProperty(label
,name
)
868 wxASSERT( choicesCache
);
870 if ( choicesCache
->IsOk() )
872 m_choices
.Assign( *choicesCache
);
873 m_value
= wxPGVariant_Zero
;
877 m_choices
.Add(labels
,values
);
879 if ( GetItemCount() )
880 SetValue( (long)value
);
884 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
885 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
886 : wxPGProperty(label
,name
)
890 if ( &labels
&& labels
.size() )
892 m_choices
.Set(labels
, values
);
894 if ( GetItemCount() )
895 SetValue( (long)value
);
899 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
900 wxPGChoices
& choices
, int value
)
901 : wxPGProperty(label
,name
)
903 m_choices
.Assign( choices
);
905 if ( GetItemCount() )
906 SetValue( (long)value
);
909 int wxEnumProperty::GetIndexForValue( int value
) const
911 if ( !m_choices
.IsOk() )
914 int intVal
= m_choices
.Index(value
);
921 wxEnumProperty::~wxEnumProperty ()
925 int wxEnumProperty::ms_nextIndex
= -2;
927 void wxEnumProperty::OnSetValue()
929 wxString variantType
= m_value
.GetType();
931 if ( variantType
== wxPG_VARIANT_TYPE_LONG
)
933 ValueFromInt_( m_value
, m_value
.GetLong(), wxPG_FULL_VALUE
);
935 else if ( variantType
== wxPG_VARIANT_TYPE_STRING
)
937 ValueFromString_( m_value
, m_value
.GetString(), 0 );
944 if ( ms_nextIndex
!= -2 )
946 m_index
= ms_nextIndex
;
951 bool wxEnumProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
953 // Make sure string value is in the list,
954 // unless property has string as preferred value type
955 // To reduce code size, use conversion here as well
956 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
&&
957 !this->IsKindOf(CLASSINFO(wxEditEnumProperty
)) )
958 return ValueFromString_( value
, value
.GetString(), wxPG_PROPERTY_SPECIFIC
);
963 wxString
wxEnumProperty::ValueToString( wxVariant
& value
,
964 int WXUNUSED(argFlags
) ) const
966 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
)
967 return value
.GetString();
969 int index
= m_choices
.Index(value
.GetLong());
971 return wxEmptyString
;
973 return m_choices
.GetLabel(index
);
976 bool wxEnumProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
978 return ValueFromString_( variant
, text
, argFlags
);
981 bool wxEnumProperty::IntToValue( wxVariant
& variant
, int intVal
, int argFlags
) const
983 return ValueFromInt_( variant
, intVal
, argFlags
);
986 bool wxEnumProperty::ValueFromString_( wxVariant
& value
, const wxString
& text
, int argFlags
) const
991 for ( unsigned int i
=0; i
<m_choices
.GetCount(); i
++ )
993 const wxString
& entryLabel
= m_choices
.GetLabel(i
);
994 if ( text
.CmpNoCase(entryLabel
) == 0 )
997 useValue
= m_choices
.GetValue(i
);
1002 bool asText
= false;
1004 bool isEdit
= this->IsKindOf(CLASSINFO(wxEditEnumProperty
));
1006 // If text not any of the choices, store as text instead
1007 // (but only if we are wxEditEnumProperty)
1008 if ( useIndex
== -1 && isEdit
)
1013 int setAsNextIndex
= -2;
1017 setAsNextIndex
= -1;
1020 else if ( useIndex
!= GetIndex() )
1022 if ( useIndex
!= -1 )
1024 setAsNextIndex
= useIndex
;
1025 value
= (long)useValue
;
1029 setAsNextIndex
= -1;
1030 value
= wxPGVariant_MinusOne
;
1034 if ( setAsNextIndex
!= -2 )
1036 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1037 // validation purposes only, and index must not be changed
1038 if ( !(argFlags
& wxPG_PROPERTY_SPECIFIC
) )
1039 ms_nextIndex
= setAsNextIndex
;
1041 if ( isEdit
|| setAsNextIndex
!= -1 )
1049 bool wxEnumProperty::ValueFromInt_( wxVariant
& variant
, int intVal
, int argFlags
) const
1051 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1055 if ( argFlags
& wxPG_FULL_VALUE
)
1057 ms_nextIndex
= GetIndexForValue( intVal
);
1061 if ( intVal
!= GetIndex() )
1063 ms_nextIndex
= intVal
;
1067 if ( ms_nextIndex
!= -2 )
1069 if ( !(argFlags
& wxPG_FULL_VALUE
) )
1070 intVal
= m_choices
.GetValue(intVal
);
1072 variant
= (long)intVal
;
1081 wxEnumProperty::OnValidationFailure( wxVariant
& WXUNUSED(pendingValue
) )
1087 void wxEnumProperty::SetIndex( int index
)
1093 int wxEnumProperty::GetIndex() const
1095 if ( m_value
.IsNull() )
1098 if ( ms_nextIndex
!= -2 )
1099 return ms_nextIndex
;
1104 // -----------------------------------------------------------------------
1105 // wxEditEnumProperty
1106 // -----------------------------------------------------------------------
1108 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty
, wxPGProperty
)
1110 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty
,wxString
,ComboBox
)
1112 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1113 const long* values
, const wxString
& value
)
1114 : wxEnumProperty(label
,name
,labels
,values
,0)
1119 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1120 const long* values
, wxPGChoices
* choicesCache
, const wxString
& value
)
1121 : wxEnumProperty(label
,name
,labels
,values
,choicesCache
,0)
1126 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1127 const wxArrayString
& labels
, const wxArrayInt
& values
, const wxString
& value
)
1128 : wxEnumProperty(label
,name
,labels
,values
,0)
1133 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1134 wxPGChoices
& choices
, const wxString
& value
)
1135 : wxEnumProperty(label
,name
,choices
,0)
1140 wxEditEnumProperty::~wxEditEnumProperty()
1144 // -----------------------------------------------------------------------
1146 // -----------------------------------------------------------------------
1148 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty
,wxPGProperty
)
1150 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty
,long,TextCtrl
)
1152 void wxFlagsProperty::Init()
1154 long value
= m_value
;
1157 // Generate children
1161 unsigned int prevChildCount
= m_children
.size();
1164 if ( prevChildCount
)
1166 wxPropertyGridPageState
* state
= GetParentState();
1168 // State safety check (it may be NULL in immediate parent)
1173 wxPGProperty
* selected
= state
->GetSelection();
1176 if ( selected
->GetParent() == this )
1177 oldSel
= selected
->GetIndexInParent();
1178 else if ( selected
== this )
1182 state
->DoClearSelection();
1185 // Delete old children
1186 for ( i
=0; i
<prevChildCount
; i
++ )
1187 delete m_children
[i
];
1191 // Relay wxPG_BOOL_USE_CHECKBOX and wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
1192 // to child bool property controls.
1193 long attrUseCheckBox
= GetAttributeAsLong(wxPG_BOOL_USE_CHECKBOX
, 0);
1194 long attrUseDCC
= GetAttributeAsLong(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1197 if ( m_choices
.IsOk() )
1199 const wxPGChoices
& choices
= m_choices
;
1201 for ( i
=0; i
<GetItemCount(); i
++ )
1204 child_val
= ( value
& choices
.GetValue(i
) )?true:false;
1206 wxPGProperty
* boolProp
;
1207 wxString label
= GetLabel(i
);
1210 if ( wxPGGlobalVars
->m_autoGetTranslation
)
1212 boolProp
= new wxBoolProperty( ::wxGetTranslation(label
), label
, child_val
);
1217 boolProp
= new wxBoolProperty( label
, label
, child_val
);
1219 if ( attrUseCheckBox
)
1220 boolProp
->SetAttribute(wxPG_BOOL_USE_CHECKBOX
,
1223 boolProp
->SetAttribute(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1225 AddPrivateChild(boolProp
);
1228 m_oldChoicesData
= m_choices
.GetDataPtr();
1231 m_oldValue
= m_value
;
1233 if ( prevChildCount
)
1234 SubPropsChanged(oldSel
);
1237 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1238 const wxChar
* const* labels
, const long* values
, long value
) : wxPGProperty(label
,name
)
1240 m_oldChoicesData
= NULL
;
1244 m_choices
.Set(labels
,values
);
1246 wxASSERT( GetItemCount() );
1252 m_value
= wxPGVariant_Zero
;
1256 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1257 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1258 : wxPGProperty(label
,name
)
1260 m_oldChoicesData
= NULL
;
1262 if ( &labels
&& labels
.size() )
1264 m_choices
.Set(labels
,values
);
1266 wxASSERT( GetItemCount() );
1268 SetValue( (long)value
);
1272 m_value
= wxPGVariant_Zero
;
1276 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1277 wxPGChoices
& choices
, long value
)
1278 : wxPGProperty(label
,name
)
1280 m_oldChoicesData
= NULL
;
1282 if ( choices
.IsOk() )
1284 m_choices
.Assign(choices
);
1286 wxASSERT( GetItemCount() );
1292 m_value
= wxPGVariant_Zero
;
1296 wxFlagsProperty::~wxFlagsProperty()
1300 void wxFlagsProperty::OnSetValue()
1302 if ( !m_choices
.IsOk() || !GetItemCount() )
1304 m_value
= wxPGVariant_Zero
;
1308 long val
= m_value
.GetLong();
1312 // normalize the value (i.e. remove extra flags)
1314 const wxPGChoices
& choices
= m_choices
;
1315 for ( i
= 0; i
< GetItemCount(); i
++ )
1317 fullFlags
|= choices
.GetValue(i
);
1324 // Need to (re)init now?
1325 if ( GetChildCount() != GetItemCount() ||
1326 m_choices
.GetDataPtr() != m_oldChoicesData
)
1332 long newFlags
= m_value
;
1334 if ( newFlags
!= m_oldValue
)
1336 // Set child modified states
1338 const wxPGChoices
& choices
= m_choices
;
1339 for ( i
= 0; i
<GetItemCount(); i
++ )
1343 flag
= choices
.GetValue(i
);
1345 if ( (newFlags
& flag
) != (m_oldValue
& flag
) )
1346 Item(i
)->SetFlag( wxPG_PROP_MODIFIED
);
1349 m_oldValue
= newFlags
;
1353 wxString
wxFlagsProperty::ValueToString( wxVariant
& value
,
1354 int WXUNUSED(argFlags
) ) const
1358 if ( !m_choices
.IsOk() )
1363 const wxPGChoices
& choices
= m_choices
;
1365 for ( i
= 0; i
< GetItemCount(); i
++ )
1368 doAdd
= ( flags
& choices
.GetValue(i
) );
1372 text
+= choices
.GetLabel(i
);
1377 // remove last comma
1378 if ( text
.Len() > 1 )
1379 text
.Truncate ( text
.Len() - 2 );
1384 // Translate string into flag tokens
1385 bool wxFlagsProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1387 if ( !m_choices
.IsOk() )
1392 // semicolons are no longer valid delimeters
1393 WX_PG_TOKENIZER1_BEGIN(text
,wxS(','))
1395 if ( token
.length() )
1397 // Determine which one it is
1398 long bit
= IdToBit( token
);
1411 WX_PG_TOKENIZER1_END()
1413 if ( variant
!= (long)newFlags
)
1415 variant
= (long)newFlags
;
1422 // Converts string id to a relevant bit.
1423 long wxFlagsProperty::IdToBit( const wxString
& id
) const
1426 for ( i
= 0; i
< GetItemCount(); i
++ )
1428 if ( id
== GetLabel(i
) )
1430 return m_choices
.GetValue(i
);
1436 void wxFlagsProperty::RefreshChildren()
1438 if ( !m_choices
.IsOk() || !GetChildCount() ) return;
1440 int flags
= m_value
.GetLong();
1442 const wxPGChoices
& choices
= m_choices
;
1444 for ( i
= 0; i
< GetItemCount(); i
++ )
1448 flag
= choices
.GetValue(i
);
1450 long subVal
= flags
& flag
;
1451 wxPGProperty
* p
= Item(i
);
1453 if ( subVal
!= (m_oldValue
& flag
) )
1454 p
->SetFlag( wxPG_PROP_MODIFIED
);
1456 p
->SetValue( subVal
?true:false );
1462 wxVariant
wxFlagsProperty::ChildChanged( wxVariant
& thisValue
,
1464 wxVariant
& childValue
) const
1466 long oldValue
= thisValue
.GetLong();
1467 long val
= childValue
.GetLong();
1468 unsigned long vi
= m_choices
.GetValue(childIndex
);
1471 return (long) (oldValue
| vi
);
1473 return (long) (oldValue
& ~(vi
));
1476 bool wxFlagsProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1478 if ( name
== wxPG_BOOL_USE_CHECKBOX
||
1479 name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
1481 for ( size_t i
=0; i
<GetChildCount(); i
++ )
1483 Item(i
)->SetAttribute(name
, value
);
1485 // Must return false so that the attribute is stored in
1486 // flag property's actual property storage
1492 // -----------------------------------------------------------------------
1494 // -----------------------------------------------------------------------
1496 IMPLEMENT_DYNAMIC_CLASS(wxDirProperty
, wxLongStringProperty
)
1498 wxDirProperty::wxDirProperty( const wxString
& name
, const wxString
& label
, const wxString
& value
)
1499 : wxLongStringProperty(name
,label
,value
)
1501 m_flags
|= wxPG_PROP_NO_ESCAPE
;
1504 wxDirProperty::~wxDirProperty() { }
1506 wxValidator
* wxDirProperty::DoGetValidator() const
1508 return wxFileProperty::GetClassValidator();
1511 bool wxDirProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1513 // Update property value from editor, if necessary
1514 wxSize
dlg_sz(300,400);
1516 wxString
dlgMessage(m_dlgMessage
);
1517 if ( dlgMessage
.empty() )
1518 dlgMessage
= _("Choose a directory:");
1519 wxDirDialog
dlg( propGrid
,
1523 #if !wxPG_SMALL_SCREEN
1524 propGrid
->GetGoodEditorDialogPosition(this,dlg_sz
),
1532 if ( dlg
.ShowModal() == wxID_OK
)
1534 value
= dlg
.GetPath();
1540 bool wxDirProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1542 if ( name
== wxPG_DIR_DIALOG_MESSAGE
)
1544 m_dlgMessage
= value
.GetString();
1550 // -----------------------------------------------------------------------
1551 // wxPGFileDialogAdapter
1552 // -----------------------------------------------------------------------
1554 bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1556 wxFileProperty
* fileProp
= NULL
;
1560 if ( property
->IsKindOf(CLASSINFO(wxFileProperty
)) )
1562 fileProp
= ((wxFileProperty
*)property
);
1563 wxFileName filename
= fileProp
->GetValue().GetString();
1564 path
= filename
.GetPath();
1565 indFilter
= fileProp
->m_indFilter
;
1567 if ( !path
.length() && fileProp
->m_basePath
.length() )
1568 path
= fileProp
->m_basePath
;
1572 wxFileName
fn(property
->GetValue().GetString());
1573 path
= fn
.GetPath();
1576 wxFileDialog
dlg( propGrid
->GetPanel(),
1577 property
->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1578 property
->GetAttribute(wxS("InitialPath"), path
),
1580 property
->GetAttribute(wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*")),
1582 wxDefaultPosition
);
1584 if ( indFilter
>= 0 )
1585 dlg
.SetFilterIndex( indFilter
);
1587 if ( dlg
.ShowModal() == wxID_OK
)
1590 fileProp
->m_indFilter
= dlg
.GetFilterIndex();
1591 SetValue( dlg
.GetPath() );
1597 // -----------------------------------------------------------------------
1599 // -----------------------------------------------------------------------
1601 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty
,wxPGProperty
,
1602 wxString
,const wxString
&,TextCtrlAndButton
)
1604 wxFileProperty::wxFileProperty( const wxString
& label
, const wxString
& name
,
1605 const wxString
& value
) : wxPGProperty(label
,name
)
1607 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1609 SetAttribute( wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*") );
1614 wxFileProperty::~wxFileProperty() {}
1616 wxValidator
* wxFileProperty::GetClassValidator()
1618 #if wxUSE_VALIDATORS
1619 WX_PG_DOGETVALIDATOR_ENTRY()
1621 // Atleast wxPython 2.6.2.1 required that the string argument is given
1623 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST
,&v
);
1625 wxArrayString exChars
;
1626 exChars
.Add(wxS("?"));
1627 exChars
.Add(wxS("*"));
1628 exChars
.Add(wxS("|"));
1629 exChars
.Add(wxS("<"));
1630 exChars
.Add(wxS(">"));
1631 exChars
.Add(wxS("\""));
1633 validator
->SetExcludes(exChars
);
1635 WX_PG_DOGETVALIDATOR_EXIT(validator
)
1641 wxValidator
* wxFileProperty::DoGetValidator() const
1643 return GetClassValidator();
1646 void wxFileProperty::OnSetValue()
1648 const wxString
& fnstr
= m_value
.GetString();
1650 wxFileName filename
= fnstr
;
1652 if ( !filename
.HasName() )
1654 m_value
= wxPGVariant_EmptyString
;
1657 // Find index for extension.
1658 if ( m_indFilter
< 0 && fnstr
.length() )
1660 wxString ext
= filename
.GetExt();
1663 size_t len
= m_wildcard
.length();
1665 pos
= m_wildcard
.find(wxS("|"), pos
);
1666 while ( pos
!= wxString::npos
&& pos
< (len
-3) )
1668 size_t ext_begin
= pos
+ 3;
1670 pos
= m_wildcard
.find(wxS("|"), ext_begin
);
1671 if ( pos
== wxString::npos
)
1673 wxString found_ext
= m_wildcard
.substr(ext_begin
, pos
-ext_begin
);
1675 if ( found_ext
.length() > 0 )
1677 if ( found_ext
[0] == wxS('*') )
1679 m_indFilter
= curind
;
1682 if ( ext
.CmpNoCase(found_ext
) == 0 )
1684 m_indFilter
= curind
;
1690 pos
= m_wildcard
.find(wxS("|"), pos
+1);
1697 wxFileName
wxFileProperty::GetFileName() const
1699 wxFileName filename
;
1701 if ( !m_value
.IsNull() )
1702 filename
= m_value
.GetString();
1707 wxString
wxFileProperty::ValueToString( wxVariant
& value
,
1708 int argFlags
) const
1710 wxFileName filename
= value
.GetString();
1712 if ( !filename
.HasName() )
1713 return wxEmptyString
;
1715 wxString fullName
= filename
.GetFullName();
1716 if ( !fullName
.length() )
1717 return wxEmptyString
;
1719 if ( argFlags
& wxPG_FULL_VALUE
)
1721 return filename
.GetFullPath();
1723 else if ( m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
)
1725 if ( m_basePath
.Length() )
1727 wxFileName
fn2(filename
);
1728 fn2
.MakeRelativeTo(m_basePath
);
1729 return fn2
.GetFullPath();
1731 return filename
.GetFullPath();
1734 return filename
.GetFullName();
1737 wxPGEditorDialogAdapter
* wxFileProperty::GetEditorDialog() const
1739 return new wxPGFileDialogAdapter();
1742 bool wxFileProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1744 wxFileName filename
= variant
.GetString();
1746 if ( (m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
) || (argFlags
& wxPG_FULL_VALUE
) )
1748 if ( filename
!= text
)
1756 if ( filename
.GetFullName() != text
)
1758 wxFileName fn
= filename
;
1759 fn
.SetFullName(text
);
1760 variant
= fn
.GetFullPath();
1768 bool wxFileProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1770 // Return false on some occasions to make sure those attribs will get
1771 // stored in m_attributes.
1772 if ( name
== wxPG_FILE_SHOW_FULL_PATH
)
1774 if ( value
.GetLong() )
1775 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1777 m_flags
&= ~(wxPG_PROP_SHOW_FULL_FILENAME
);
1780 else if ( name
== wxPG_FILE_WILDCARD
)
1782 m_wildcard
= value
.GetString();
1784 else if ( name
== wxPG_FILE_SHOW_RELATIVE_PATH
)
1786 m_basePath
= value
.GetString();
1788 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1789 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1791 else if ( name
== wxPG_FILE_INITIAL_PATH
)
1793 m_initialPath
= value
.GetString();
1796 else if ( name
== wxPG_FILE_DIALOG_TITLE
)
1798 m_dlgTitle
= value
.GetString();
1804 // -----------------------------------------------------------------------
1805 // wxPGLongStringDialogAdapter
1806 // -----------------------------------------------------------------------
1808 bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1810 wxString val1
= property
->GetValueAsString(0);
1811 wxString val_orig
= val1
;
1814 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1815 wxPropertyGrid::ExpandEscapeSequences(value
, val1
);
1817 value
= wxString(val1
);
1819 // Run editor dialog.
1820 if ( wxLongStringProperty::DisplayEditorDialog(property
, propGrid
, value
) )
1822 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1823 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1827 if ( val1
!= val_orig
)
1836 // -----------------------------------------------------------------------
1837 // wxLongStringProperty
1838 // -----------------------------------------------------------------------
1840 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty
,wxPGProperty
,
1841 wxString
,const wxString
&,TextCtrlAndButton
)
1843 wxLongStringProperty::wxLongStringProperty( const wxString
& label
, const wxString
& name
,
1844 const wxString
& value
) : wxPGProperty(label
,name
)
1849 wxLongStringProperty::~wxLongStringProperty() {}
1851 wxString
wxLongStringProperty::ValueToString( wxVariant
& value
,
1852 int WXUNUSED(argFlags
) ) const
1857 bool wxLongStringProperty::OnEvent( wxPropertyGrid
* propGrid
, wxWindow
* WXUNUSED(primary
),
1860 if ( propGrid
->IsMainButtonEvent(event
) )
1863 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
1865 wxString val1
= useValue
.GetString();
1866 wxString val_orig
= val1
;
1869 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1870 wxPropertyGrid::ExpandEscapeSequences(value
,val1
);
1872 value
= wxString(val1
);
1874 // Run editor dialog.
1875 if ( OnButtonClick(propGrid
,value
) )
1877 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1878 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1882 if ( val1
!= val_orig
)
1884 SetValueInEvent( val1
);
1892 bool wxLongStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1894 return DisplayEditorDialog(this, propGrid
, value
);
1897 bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty
* prop
, wxPropertyGrid
* propGrid
, wxString
& value
)
1900 // launch editor dialog
1901 wxDialog
* dlg
= new wxDialog(propGrid
,-1,prop
->GetLabel(),wxDefaultPosition
,wxDefaultSize
,
1902 wxDEFAULT_DIALOG_STYLE
|wxRESIZE_BORDER
|wxCLIP_CHILDREN
);
1904 dlg
->SetFont(propGrid
->GetFont()); // To allow entering chars of the same set as the propGrid
1906 // Multi-line text editor dialog.
1907 #if !wxPG_SMALL_SCREEN
1908 const int spacing
= 8;
1910 const int spacing
= 4;
1912 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
1913 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
1914 wxTextCtrl
* ed
= new wxTextCtrl(dlg
,11,value
,
1915 wxDefaultPosition
,wxDefaultSize
,wxTE_MULTILINE
);
1917 rowsizer
->Add( ed
, 1, wxEXPAND
|wxALL
, spacing
);
1918 topsizer
->Add( rowsizer
, 1, wxEXPAND
, 0 );
1920 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
1921 buttonSizer
->AddButton(new wxButton(dlg
, wxID_OK
));
1922 buttonSizer
->AddButton(new wxButton(dlg
, wxID_CANCEL
));
1923 buttonSizer
->Realize();
1924 topsizer
->Add( buttonSizer
, 0,
1925 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxBOTTOM
|wxRIGHT
,
1928 dlg
->SetSizer( topsizer
);
1929 topsizer
->SetSizeHints( dlg
);
1931 #if !wxPG_SMALL_SCREEN
1932 dlg
->SetSize(400,300);
1934 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(prop
,dlg
->GetSize()) );
1937 int res
= dlg
->ShowModal();
1939 if ( res
== wxID_OK
)
1941 value
= ed
->GetValue();
1949 bool wxLongStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1951 if ( variant
!= text
)
1959 #if wxUSE_EDITABLELISTBOX
1961 // -----------------------------------------------------------------------
1962 // wxPGArrayEditorDialog
1963 // -----------------------------------------------------------------------
1965 BEGIN_EVENT_TABLE(wxPGArrayEditorDialog
, wxDialog
)
1966 EVT_IDLE(wxPGArrayEditorDialog::OnIdle
)
1969 IMPLEMENT_ABSTRACT_CLASS(wxPGArrayEditorDialog
, wxDialog
)
1971 #include "wx/editlbox.h"
1972 #include "wx/listctrl.h"
1974 // -----------------------------------------------------------------------
1976 void wxPGArrayEditorDialog::OnIdle(wxIdleEvent
& event
)
1978 // Repair focus - wxEditableListBox has bitmap buttons, which
1979 // get focus, and lose focus (into the oblivion) when they
1980 // become disabled due to change in control state.
1982 wxWindow
* lastFocused
= m_lastFocused
;
1983 wxWindow
* focus
= ::wxWindow::FindFocus();
1985 // If last focused control became disabled, set focus back to
1986 // wxEditableListBox
1987 if ( lastFocused
&& focus
!= lastFocused
&&
1988 lastFocused
->GetParent() == m_elbSubPanel
&&
1989 !lastFocused
->IsEnabled() )
1991 m_elb
->GetListCtrl()->SetFocus();
1994 m_lastFocused
= focus
;
1999 // -----------------------------------------------------------------------
2001 wxPGArrayEditorDialog::wxPGArrayEditorDialog()
2007 // -----------------------------------------------------------------------
2009 void wxPGArrayEditorDialog::Init()
2011 m_lastFocused
= NULL
;
2012 m_hasCustomNewAction
= false;
2013 m_itemPendingAtIndex
= -1;
2016 // -----------------------------------------------------------------------
2018 wxPGArrayEditorDialog::wxPGArrayEditorDialog( wxWindow
*parent
,
2019 const wxString
& message
,
2020 const wxString
& caption
,
2027 Create(parent
,message
,caption
,style
,pos
,sz
);
2030 // -----------------------------------------------------------------------
2032 bool wxPGArrayEditorDialog::Create( wxWindow
*parent
,
2033 const wxString
& message
,
2034 const wxString
& caption
,
2039 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2040 // FIXME: This should be only a temporary fix.
2043 int useStyle
= wxCAPTION
;
2045 int useStyle
= style
;
2048 bool res
= wxDialog::Create(parent
, wxID_ANY
, caption
, pos
, sz
, useStyle
);
2050 SetFont(parent
->GetFont()); // To allow entering chars of the same set as the propGrid
2052 #if !wxPG_SMALL_SCREEN
2053 const int spacing
= 4;
2055 const int spacing
= 3;
2060 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2063 if ( message
.length() )
2064 topsizer
->Add( new wxStaticText(this,-1,message
),
2065 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2067 m_elb
= new wxEditableListBox(this, wxID_ANY
, message
,
2074 // Populate the list box
2076 for ( unsigned int i
=0; i
<ArrayGetCount(); i
++ )
2077 arr
.push_back(ArrayGet(i
));
2078 m_elb
->SetStrings(arr
);
2080 // Connect event handlers
2082 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2084 but
= m_elb
->GetNewButton();
2085 m_elbSubPanel
= but
->GetParent();
2086 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2087 wxCommandEventHandler(wxPGArrayEditorDialog::OnAddClick
),
2090 but
= m_elb
->GetDelButton();
2091 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2092 wxCommandEventHandler(wxPGArrayEditorDialog::OnDeleteClick
),
2095 but
= m_elb
->GetUpButton();
2096 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2097 wxCommandEventHandler(wxPGArrayEditorDialog::OnUpClick
),
2100 but
= m_elb
->GetDownButton();
2101 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2102 wxCommandEventHandler(wxPGArrayEditorDialog::OnDownClick
),
2105 lc
->Connect(lc
->GetId(), wxEVT_COMMAND_LIST_END_LABEL_EDIT
,
2106 wxListEventHandler(wxPGArrayEditorDialog::OnEndLabelEdit
),
2109 topsizer
->Add( m_elb
, 1, wxEXPAND
, spacing
);
2111 // Standard dialog buttons
2112 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2113 buttonSizer
->AddButton(new wxButton(this, wxID_OK
));
2114 buttonSizer
->AddButton(new wxButton(this, wxID_CANCEL
));
2115 buttonSizer
->Realize();
2116 topsizer
->Add( buttonSizer
, 0,
2117 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxALL
,
2122 SetSizer( topsizer
);
2123 topsizer
->SetSizeHints( this );
2125 #if !wxPG_SMALL_SCREEN
2126 if ( sz
.x
== wxDefaultSize
.x
&&
2127 sz
.y
== wxDefaultSize
.y
)
2128 SetSize( wxSize(275,360) );
2136 // -----------------------------------------------------------------------
2138 int wxPGArrayEditorDialog::GetSelection() const
2140 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2142 int index
= lc
->GetNextItem(-1, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
);
2149 // -----------------------------------------------------------------------
2151 void wxPGArrayEditorDialog::OnAddClick(wxCommandEvent
& event
)
2153 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2154 int newItemIndex
= lc
->GetItemCount() - 1;
2156 if ( m_hasCustomNewAction
)
2159 if ( OnCustomNewAction(&str
) )
2161 if ( ArrayInsert(str
, newItemIndex
) )
2163 lc
->InsertItem(newItemIndex
, str
);
2168 // Do *not* skip the event! We do not want the wxEditableListBox
2173 m_itemPendingAtIndex
= newItemIndex
;
2179 // -----------------------------------------------------------------------
2181 void wxPGArrayEditorDialog::OnDeleteClick(wxCommandEvent
& event
)
2183 int index
= GetSelection();
2186 ArrayRemoveAt( index
);
2193 // -----------------------------------------------------------------------
2195 void wxPGArrayEditorDialog::OnUpClick(wxCommandEvent
& event
)
2197 int index
= GetSelection();
2200 ArraySwap(index
-1,index
);
2207 // -----------------------------------------------------------------------
2209 void wxPGArrayEditorDialog::OnDownClick(wxCommandEvent
& event
)
2211 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2212 int index
= GetSelection();
2213 int lastStringIndex
= lc
->GetItemCount() - 1;
2214 if ( index
>= 0 && index
< lastStringIndex
)
2216 ArraySwap(index
, index
+1);
2223 // -----------------------------------------------------------------------
2225 void wxPGArrayEditorDialog::OnEndLabelEdit(wxListEvent
& event
)
2227 wxString str
= event
.GetLabel();
2229 if ( m_itemPendingAtIndex
>= 0 )
2232 if ( ArrayInsert(str
, m_itemPendingAtIndex
) )
2238 // Editable list box doesn't really respect Veto(), but
2239 // it recognizes if no text was added, so we simulate
2241 event
.m_item
.SetText(wxEmptyString
);
2242 m_elb
->GetListCtrl()->SetItemText(m_itemPendingAtIndex
,
2250 // Change an existing item
2251 int index
= GetSelection();
2252 wxASSERT( index
!= wxNOT_FOUND
);
2253 if ( ArraySet(index
, str
) )
2262 #endif // wxUSE_EDITABLELISTBOX
2264 // -----------------------------------------------------------------------
2265 // wxPGArrayStringEditorDialog
2266 // -----------------------------------------------------------------------
2268 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2270 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2273 // -----------------------------------------------------------------------
2275 wxString
wxPGArrayStringEditorDialog::ArrayGet( size_t index
)
2277 return m_array
[index
];
2280 size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2282 return m_array
.size();
2285 bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString
& str
, int index
)
2290 m_array
.Insert(str
,index
);
2294 bool wxPGArrayStringEditorDialog::ArraySet( size_t index
, const wxString
& str
)
2296 m_array
[index
] = str
;
2300 void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index
)
2302 m_array
.RemoveAt(index
);
2305 void wxPGArrayStringEditorDialog::ArraySwap( size_t first
, size_t second
)
2307 wxString old_str
= m_array
[first
];
2308 wxString new_str
= m_array
[second
];
2309 m_array
[first
] = new_str
;
2310 m_array
[second
] = old_str
;
2313 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2314 : wxPGArrayEditorDialog()
2319 void wxPGArrayStringEditorDialog::Init()
2321 m_pCallingClass
= NULL
;
2325 wxPGArrayStringEditorDialog::OnCustomNewAction(wxString
* resString
)
2327 return m_pCallingClass
->OnCustomStringEdit(m_parent
, *resString
);
2330 // -----------------------------------------------------------------------
2331 // wxArrayStringProperty
2332 // -----------------------------------------------------------------------
2334 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty
, // Property name
2335 wxPGProperty
, // Property we inherit from
2336 wxArrayString
, // Value type name
2337 const wxArrayString
&, // Value type, as given in constructor
2338 TextCtrlAndButton
) // Initial editor
2340 wxArrayStringProperty::wxArrayStringProperty( const wxString
& label
,
2341 const wxString
& name
,
2342 const wxArrayString
& array
)
2343 : wxPGProperty(label
,name
)
2349 wxArrayStringProperty::~wxArrayStringProperty() { }
2351 void wxArrayStringProperty::OnSetValue()
2353 GenerateValueAsString();
2357 wxArrayStringProperty::ConvertArrayToString(const wxArrayString
& arr
,
2359 const wxUniChar
& delimiter
) const
2361 if ( delimiter
== '"' || delimiter
== '\'' )
2364 ArrayStringToString(*pString
,
2367 Escape
| QuoteStrings
);
2371 // Regular delimiter
2372 ArrayStringToString(*pString
,
2379 wxString
wxArrayStringProperty::ValueToString( wxVariant
& WXUNUSED(value
),
2380 int argFlags
) const
2383 // If this is called from GetValueAsString(), return cached string
2384 if ( argFlags
& wxPG_VALUE_IS_CURRENT
)
2389 wxArrayString arr
= m_value
.GetArrayString();
2391 ConvertArrayToString(arr
, &s
, m_delimiter
);
2395 // Converts wxArrayString to a string separated by delimeters and spaces.
2396 // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2399 wxArrayStringProperty::ArrayStringToString( wxString
& dst
,
2400 const wxArrayString
& src
,
2401 wxUniChar delimiter
, int flags
)
2407 unsigned int itemCount
= src
.size();
2411 if ( flags
& Escape
)
2414 pdr
= wxS("\\") + static_cast<wchar_t>(delimiter
);
2418 dst
.append( preas
);
2420 wxString
delimStr(delimiter
);
2422 for ( i
= 0; i
< itemCount
; i
++ )
2424 wxString
str( src
.Item(i
) );
2426 // Do some character conversion.
2427 // Converts \ to \\ and $delimiter to \$delimiter
2428 // Useful when quoting.
2429 if ( flags
& Escape
)
2431 str
.Replace( wxS("\\"), wxS("\\\\"), true );
2433 str
.Replace( preas
, pdr
, true );
2438 if ( i
< (itemCount
-1) )
2440 dst
.append( delimStr
);
2441 dst
.append( wxS(" ") );
2442 dst
.append( preas
);
2444 else if ( flags
& QuoteStrings
)
2445 dst
.append( delimStr
);
2449 void wxArrayStringProperty::GenerateValueAsString()
2451 wxArrayString arr
= m_value
.GetArrayString();
2452 ConvertArrayToString(arr
, &m_display
, m_delimiter
);
2455 // Default implementation doesn't do anything.
2456 bool wxArrayStringProperty::OnCustomStringEdit( wxWindow
*, wxString
& )
2461 wxPGArrayEditorDialog
* wxArrayStringProperty::CreateEditorDialog()
2463 return new wxPGArrayStringEditorDialog();
2466 bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
,
2467 wxWindow
* WXUNUSED(primaryCtrl
),
2471 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
2473 if ( !propGrid
->EditorValidate() )
2476 // Create editor dialog.
2477 wxPGArrayEditorDialog
* dlg
= CreateEditorDialog();
2478 #if wxUSE_VALIDATORS
2479 wxValidator
* validator
= GetValidator();
2480 wxPGInDialogValidator dialogValidator
;
2483 wxPGArrayStringEditorDialog
* strEdDlg
= wxDynamicCast(dlg
, wxPGArrayStringEditorDialog
);
2486 strEdDlg
->SetCustomButton(cbt
, this);
2488 dlg
->SetDialogValue( useValue
);
2489 dlg
->Create(propGrid
, wxEmptyString
, m_label
);
2491 #if !wxPG_SMALL_SCREEN
2492 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(this,dlg
->GetSize()) );
2501 int res
= dlg
->ShowModal();
2503 if ( res
== wxID_OK
&& dlg
->IsModified() )
2505 wxVariant value
= dlg
->GetDialogValue();
2506 if ( !value
.IsNull() )
2508 wxArrayString actualValue
= value
.GetArrayString();
2510 ConvertArrayToString(actualValue
, &tempStr
, m_delimiter
);
2511 #if wxUSE_VALIDATORS
2512 if ( dialogValidator
.DoValidate(propGrid
, validator
,
2516 SetValueInEvent( actualValue
);
2533 bool wxArrayStringProperty::OnEvent( wxPropertyGrid
* propGrid
,
2537 if ( propGrid
->IsMainButtonEvent(event
) )
2538 return OnButtonClick(propGrid
,primary
,(const wxChar
*) NULL
);
2542 bool wxArrayStringProperty::StringToValue( wxVariant
& variant
,
2543 const wxString
& text
, int ) const
2547 if ( m_delimiter
== '"' || m_delimiter
== '\'' )
2550 WX_PG_TOKENIZER2_BEGIN(text
, m_delimiter
)
2552 // Need to replace backslashes with empty characters
2553 // (opposite what is done in ConvertArrayToString()).
2554 token
.Replace ( wxS("\\\\"), wxS("\\"), true );
2558 WX_PG_TOKENIZER2_END()
2562 // Regular delimiter
2563 WX_PG_TOKENIZER1_BEGIN(text
, m_delimiter
)
2565 WX_PG_TOKENIZER1_END()
2573 bool wxArrayStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
2575 if ( name
== wxPG_ARRAY_DELIMITER
)
2577 m_delimiter
= value
.GetChar();
2578 GenerateValueAsString();
2584 // -----------------------------------------------------------------------
2585 // wxPGInDialogValidator
2586 // -----------------------------------------------------------------------
2588 #if wxUSE_VALIDATORS
2589 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* propGrid
,
2590 wxValidator
* validator
,
2591 const wxString
& value
)
2596 wxTextCtrl
* tc
= m_textCtrl
;
2601 tc
= new wxTextCtrl( propGrid
, wxPG_SUBID_TEMP1
, wxEmptyString
,
2602 wxPoint(30000,30000));
2609 tc
->SetValue(value
);
2611 validator
->SetWindow(tc
);
2612 bool res
= validator
->Validate(propGrid
);
2617 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* WXUNUSED(propGrid
),
2618 wxValidator
* WXUNUSED(validator
),
2619 const wxString
& WXUNUSED(value
) )
2625 // -----------------------------------------------------------------------
2627 #endif // wxUSE_PROPGRID