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.
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 GenerateComposedValue(s
, 0);
88 wxStringProperty
::~wxStringProperty() { }
90 wxString wxStringProperty
::GetValueAsString( int argFlags
) const
92 wxString s
= m_value
.GetString();
94 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
96 // Value stored in m_value is non-editable, non-full value
97 if ( (argFlags
& wxPG_FULL_VALUE
) || (argFlags
& wxPG_EDITABLE_VALUE
) )
98 GenerateComposedValue(s
, argFlags
);
103 // If string is password and value is for visual purposes,
104 // then return asterisks instead the actual string.
105 if ( (m_flags
& wxPG_PROP_PASSWORD
) && !(argFlags
& (wxPG_FULL_VALUE
|wxPG_EDITABLE_VALUE
)) )
106 return wxString(wxChar('*'), s
.Length());
111 bool wxStringProperty
::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
113 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
114 return wxPGProperty
::StringToValue(variant
, text
, argFlags
);
116 if ( m_value
.GetString() != text
)
125 bool wxStringProperty
::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
127 if ( name
== wxPG_STRING_PASSWORD
)
129 m_flags
&= ~(wxPG_PROP_PASSWORD
);
130 if ( wxPGVariantToInt(value
) ) m_flags
|= wxPG_PROP_PASSWORD
;
137 // -----------------------------------------------------------------------
139 // -----------------------------------------------------------------------
141 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty
,wxPGProperty
,
144 wxIntProperty
::wxIntProperty( const wxString
& label
, const wxString
& name
,
145 long value
) : wxPGProperty(label
,name
)
150 wxIntProperty
::wxIntProperty( const wxString
& label
, const wxString
& name
,
151 const wxLongLong
& value
) : wxPGProperty(label
,name
)
153 SetValue(WXVARIANT(value
));
156 wxIntProperty
::~wxIntProperty() { }
158 wxString wxIntProperty
::GetValueAsString( int ) const
160 if ( m_value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
162 return wxString
::Format(wxS("%li"),m_value
.GetLong());
164 else if ( m_value
.GetType() == wxLongLong_VariantType
)
168 return ll
.ToString();
171 return wxEmptyString
;
174 bool wxIntProperty
::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
179 if ( text
.length() == 0 )
185 // We know it is a number, but let's still check
187 if ( text
.IsNumber() )
189 // Remove leading zeroes, so that the number is not interpreted as octal
190 wxString
::const_iterator i
= text
.begin();
191 wxString
::const_iterator iMax
= text
.end() - 1; // Let's allow one, last zero though
193 int firstNonZeroPos
= 0;
195 for ( ; i
!= iMax
; i
++ )
198 if ( c
!= wxS('0') && c
!= wxS(' ') )
203 wxString useText
= text
.substr(firstNonZeroPos
, text
.length() - firstNonZeroPos
);
205 wxString variantType
= variant
.GetType();
206 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
208 wxLongLong_t value64
= 0;
210 if ( useText
.ToLongLong(&value64
, 10) &&
211 ( value64
>= INT_MAX
|| value64
<= INT_MIN
)
214 bool doChangeValue
= isPrevLong
;
216 if ( !isPrevLong
&& variantType
== wxLongLong_VariantType
)
220 if ( oldValue
.GetValue() != value64
)
221 doChangeValue
= true;
226 wxLongLong
ll(value64
);
232 if ( useText
.ToLong( &value32
, 0 ) )
234 if ( !isPrevLong
|| m_value
.GetLong() != value32
)
241 else if ( argFlags
& wxPG_REPORT_ERROR
)
247 bool wxIntProperty
::IntToValue( wxVariant
& variant
, int value
, int WXUNUSED(argFlags
) ) const
249 if ( variant
.GetType() != wxPG_VARIANT_TYPE_LONG
|| variant
.GetLong() != value
)
251 variant
= (long)value
;
257 bool wxIntProperty
::DoValidation( const wxPGProperty
* property
, wxLongLong_t
& value
, wxPGValidationInfo
* pValidationInfo
, int mode
)
260 wxLongLong_t min
= wxINT64_MIN
;
261 wxLongLong_t max
= wxINT64_MAX
;
266 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
267 if ( !variant
.IsNull() )
269 wxPGVariantToLongLong(variant
, &min
);
273 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
274 if ( !variant
.IsNull() )
276 wxPGVariantToLongLong(variant
, &max
);
284 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
285 pValidationInfo
->m_failureMessage
= wxString
::Format(_("Value must be %lld or higher"),min
);
286 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
289 value
= max
- (min
- value
);
298 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
299 pValidationInfo
->m_failureMessage
= wxString
::Format(_("Value must be %lld or higher"),min
);
300 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
303 value
= min
+ (value
- max
);
310 bool wxIntProperty
::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
313 if ( wxPGVariantToLongLong(value
, &ll
) )
314 return DoValidation(this, ll
, &validationInfo
, wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
318 wxValidator
* wxIntProperty
::GetClassValidator()
321 WX_PG_DOGETVALIDATOR_ENTRY()
323 // Atleast wxPython 2.6.2.1 required that the string argument is given
325 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_NUMERIC
,&v
);
327 WX_PG_DOGETVALIDATOR_EXIT(validator
)
333 wxValidator
* wxIntProperty
::DoGetValidator() const
335 return GetClassValidator();
338 // -----------------------------------------------------------------------
340 // -----------------------------------------------------------------------
343 #define wxPG_UINT_TEMPLATE_MAX 8
345 static const wxChar
* gs_uintTemplates32
[wxPG_UINT_TEMPLATE_MAX
] = {
346 wxT("%x"),wxT("0x%x"),wxT("$%x"),
347 wxT("%X"),wxT("0x%X"),wxT("$%X"),
351 static const wxChar
* gs_uintTemplates64
[wxPG_UINT_TEMPLATE_MAX
] = {
352 wxT("%") wxLongLongFmtSpec
wxT("x"),
353 wxT("0x%") wxLongLongFmtSpec
wxT("x"),
354 wxT("$%") wxLongLongFmtSpec
wxT("x"),
355 wxT("%") wxLongLongFmtSpec
wxT("X"),
356 wxT("0x%") wxLongLongFmtSpec
wxT("X"),
357 wxT("$%") wxLongLongFmtSpec
wxT("X"),
358 wxT("%") wxLongLongFmtSpec
wxT("u"),
359 wxT("%") wxLongLongFmtSpec
wxT("o")
362 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty
,wxPGProperty
,
363 long,unsigned long,TextCtrl
)
365 void wxUIntProperty
::Init()
367 m_base
= 6; // This is magic number for dec base (must be same as in setattribute)
369 m_prefix
= wxPG_PREFIX_NONE
;
372 wxUIntProperty
::wxUIntProperty( const wxString
& label
, const wxString
& name
,
373 unsigned long value
) : wxPGProperty(label
,name
)
376 SetValue((long)value
);
379 wxUIntProperty
::wxUIntProperty( const wxString
& label
, const wxString
& name
,
380 const wxULongLong
& value
) : wxPGProperty(label
,name
)
383 SetValue(WXVARIANT(value
));
386 wxUIntProperty
::~wxUIntProperty() { }
388 wxString wxUIntProperty
::GetValueAsString( int ) const
390 size_t index
= m_base
+ m_prefix
;
391 if ( index
>= wxPG_UINT_TEMPLATE_MAX
)
392 index
= wxPG_BASE_DEC
;
394 if ( m_value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
396 return wxString
::Format(gs_uintTemplates32
[index
], (unsigned long)m_value
.GetLong());
402 return wxString
::Format(gs_uintTemplates64
[index
], ull
.GetValue());
405 bool wxUIntProperty
::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
407 wxString variantType
= variant
.GetType();
408 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
410 if ( text
.length() == 0 )
417 if ( text
[0] == wxS('$') )
420 wxULongLong_t value64
= 0;
421 wxString s
= text
.substr(start
, text
.length() - start
);
423 if ( s
.ToULongLong(&value64
, (unsigned int)m_realBase
) )
425 if ( value64
>= LONG_MAX
)
427 bool doChangeValue
= isPrevLong
;
429 if ( !isPrevLong
&& variantType
== wxULongLong_VariantType
)
431 wxULongLong oldValue
;
433 if ( oldValue
.GetValue() != value64
)
434 doChangeValue
= true;
439 wxULongLong
ull(value64
);
446 unsigned long value32
= wxLongLong(value64
).GetLo();
447 if ( !isPrevLong
|| m_value
.GetLong() != (long)value32
)
449 variant
= (long)value32
;
458 bool wxUIntProperty
::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
460 if ( m_value
!= (long)number
)
462 variant
= (long)number
;
469 #define wxUINT64_MAX ULLONG_MAX
470 #define wxUINT64_MIN wxULL(0)
472 #define wxUINT64_MAX wxULL(0xFFFFFFFFFFFFFFFF)
473 #define wxUINT64_MIN wxULL(0)
476 bool wxUIntProperty
::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
480 if ( wxPGVariantToULongLong(value
, &ll
) )
482 wxULongLong_t min
= wxUINT64_MIN
;
483 wxULongLong_t max
= wxUINT64_MAX
;
486 variant
= GetAttribute(wxPGGlobalVars
->m_strMin
);
487 if ( !variant
.IsNull() )
489 wxPGVariantToULongLong(variant
, &min
);
492 validationInfo
.m_failureMessage
= wxString
::Format(_("Value must be %llu or higher"),min
);
496 variant
= GetAttribute(wxPGGlobalVars
->m_strMax
);
497 if ( !variant
.IsNull() )
499 wxPGVariantToULongLong(variant
, &max
);
502 validationInfo
.m_failureMessage
= wxString
::Format(_("Value must be %llu or less"),max
);
510 bool wxUIntProperty
::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
512 if ( name
== wxPG_UINT_BASE
)
514 int val
= value
.GetLong();
516 m_realBase
= (wxByte
) val
;
517 if ( m_realBase
> 16 )
521 // Translate logical base to a template array index
523 if ( val
== wxPG_BASE_HEX
)
525 else if ( val
== wxPG_BASE_DEC
)
527 else if ( val
== wxPG_BASE_HEXL
)
531 else if ( name
== wxPG_UINT_PREFIX
)
533 m_prefix
= (wxByte
) value
.GetLong();
539 // -----------------------------------------------------------------------
541 // -----------------------------------------------------------------------
543 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty
,wxPGProperty
,
544 double,double,TextCtrl
)
546 wxFloatProperty
::wxFloatProperty( const wxString
& label
,
547 const wxString
& name
,
549 : wxPGProperty(label
,name
)
555 wxFloatProperty
::~wxFloatProperty() { }
557 // This helper method provides standard way for floating point-using
558 // properties to convert values to string.
559 void wxPropertyGrid
::DoubleToString(wxString
& target
,
563 wxString
* precTemplate
)
565 if ( precision
>= 0 )
569 precTemplate
= &text1
;
571 if ( !precTemplate
->length() )
573 *precTemplate
= wxS("%.");
574 *precTemplate
<< wxString
::Format( wxS("%i"), precision
);
575 *precTemplate
<< wxS('f');
578 target
.Printf( precTemplate
->c_str(), value
);
582 target
.Printf( wxS("%f"), value
);
585 if ( removeZeroes
&& precision
!= 0 && target
.length() )
587 // Remove excess zeroes (do not remove this code just yet,
588 // since sprintf can't do the same consistently across platforms).
589 wxString
::const_iterator i
= target
.end() - 1;
590 size_t new_len
= target
.length() - 1;
592 for ( ; i
!= target
.begin(); i
-- )
594 if ( *i
!= wxS('0') )
599 wxChar cur_char
= *i
;
600 if ( cur_char
!= wxS('.') && cur_char
!= wxS(',') )
603 if ( new_len
!= target
.length() )
604 target
.resize(new_len
);
608 wxString wxFloatProperty
::GetValueAsString( int argFlags
) const
611 if ( !m_value
.IsNull() )
613 wxPropertyGrid
::DoubleToString(text
,
616 !(argFlags
& wxPG_FULL_VALUE
),
622 bool wxFloatProperty
::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
627 if ( text
.length() == 0 )
633 bool res
= text
.ToDouble(&value
);
636 if ( m_value
!= value
)
642 else if ( argFlags
& wxPG_REPORT_ERROR
)
648 bool wxFloatProperty
::DoValidation( const wxPGProperty
* property
, double& value
, wxPGValidationInfo
* pValidationInfo
, int mode
)
651 double min
= (double)wxINT64_MIN
;
652 double max
= (double)wxINT64_MAX
;
657 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
658 if ( !variant
.IsNull() )
660 wxPGVariantToDouble(variant
, &min
);
664 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
665 if ( !variant
.IsNull() )
667 wxPGVariantToDouble(variant
, &max
);
675 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
676 pValidationInfo
->m_failureMessage
= wxString
::Format(_("Value must be %f or higher"),min
);
677 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
680 value
= max
- (min
- value
);
687 wxPGVariantToDouble(variant
, &max
);
690 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
691 pValidationInfo
->m_failureMessage
= wxString
::Format(_("Value must be %f or less"),max
);
692 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
695 value
= min
+ (value
- max
);
702 bool wxFloatProperty
::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
705 if ( wxPGVariantToDouble(value
, &fpv
) )
706 return DoValidation(this, fpv
, &validationInfo
, wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
710 bool wxFloatProperty
::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
712 if ( name
== wxPG_FLOAT_PRECISION
)
714 m_precision
= value
.GetLong();
720 wxValidator
* wxFloatProperty
::DoGetValidator() const
722 return wxIntProperty
::GetClassValidator();
725 // -----------------------------------------------------------------------
727 // -----------------------------------------------------------------------
729 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
730 // there is a custom GetEditorClass.
732 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty
, wxPGProperty
)
734 const wxPGEditor
* wxBoolProperty
::DoGetEditorClass() const
736 // Select correct editor control.
737 #if wxPG_INCLUDE_CHECKBOX
738 if ( !(m_flags
& wxPG_PROP_USE_CHECKBOX
) )
739 return wxPG_EDITOR(Choice
);
740 return wxPG_EDITOR(CheckBox
);
742 return wxPG_EDITOR(Choice
);
746 wxBoolProperty
::wxBoolProperty( const wxString
& label
, const wxString
& name
, bool value
) :
747 wxPGProperty(label
,name
)
749 m_choices
.Assign(wxPGGlobalVars
->m_boolChoices
);
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 bool wxBoolProperty
::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
801 if ( text
.CmpNoCase(wxPGGlobalVars
->m_boolChoices
[1].GetText()) == 0 ||
802 text
.CmpNoCase(wxS("true")) == 0 ||
803 text
.CmpNoCase(m_label
) == 0 )
806 if ( text
.length() == 0 )
812 bool oldValue
= m_value
.GetBool();
814 if ( (oldValue
&& !value
) || (!oldValue
&& value
) )
816 variant
= wxPGVariant_Bool(value
);
822 bool wxBoolProperty
::IntToValue( wxVariant
& variant
, int value
, int ) const
824 bool boolValue
= value ?
true : false;
825 bool oldValue
= m_value
.GetBool();
827 if ( oldValue
!= boolValue
)
829 variant
= wxPGVariant_Bool(boolValue
);
835 bool wxBoolProperty
::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
837 #if wxPG_INCLUDE_CHECKBOX
838 if ( name
== wxPG_BOOL_USE_CHECKBOX
)
840 int ival
= wxPGVariantToInt(value
);
842 m_flags
|= wxPG_PROP_USE_CHECKBOX
;
844 m_flags
&= ~(wxPG_PROP_USE_CHECKBOX
);
848 if ( name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
850 int ival
= wxPGVariantToInt(value
);
852 m_flags
|= wxPG_PROP_USE_DCC
;
854 m_flags
&= ~(wxPG_PROP_USE_DCC
);
860 // -----------------------------------------------------------------------
861 // wxBaseEnumProperty
862 // -----------------------------------------------------------------------
864 int wxBaseEnumProperty
::ms_nextIndex
= -2;
866 wxBaseEnumProperty
::wxBaseEnumProperty( const wxString
& label
, const wxString
& name
)
867 : wxPGProperty(label
,name
)
869 m_value
= wxPGVariant_Zero
;
872 /** If has values array, then returns number at index with value -
873 otherwise just returns the value.
875 int wxBaseEnumProperty
::GetIndexForValue( int value
) const
880 void wxBaseEnumProperty
::OnSetValue()
882 wxString variantType
= m_value
.GetType();
884 if ( variantType
== wxPG_VARIANT_TYPE_LONG
)
885 ValueFromInt_( m_value
, m_value
.GetLong(), wxPG_FULL_VALUE
);
886 else if ( variantType
== wxPG_VARIANT_TYPE_STRING
)
887 ValueFromString_( m_value
, m_value
.GetString(), 0 );
891 if ( ms_nextIndex
!= -2 )
893 m_index
= ms_nextIndex
;
898 bool wxBaseEnumProperty
::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
900 // Make sure string value is in the list,
901 // unless property has string as preferred value type
902 // To reduce code size, use conversion here as well
903 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
&&
904 !this->IsKindOf(CLASSINFO(wxEditEnumProperty
)) )
905 return ValueFromString_( value
, value
.GetString(), wxPG_PROPERTY_SPECIFIC
);
910 wxString wxBaseEnumProperty
::GetValueAsString( int ) const
912 if ( m_value
.GetType() == wxPG_VARIANT_TYPE_STRING
)
913 return m_value
.GetString();
918 const wxString
* pstr
= GetEntry( m_index
, &unusedVal
);
923 return wxEmptyString
;
926 bool wxBaseEnumProperty
::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
928 return ValueFromString_( variant
, text
, argFlags
);
931 bool wxBaseEnumProperty
::IntToValue( wxVariant
& variant
, int intVal
, int argFlags
) const
933 return ValueFromInt_( variant
, intVal
, argFlags
);
936 bool wxBaseEnumProperty
::ValueFromString_( wxVariant
& value
, const wxString
& text
, int argFlags
) const
939 const wxString
* entryLabel
;
944 entryLabel
= GetEntry(i
, &entryValue
);
947 if ( text
.CmpNoCase(*entryLabel
) == 0 )
950 useValue
= (long)entryValue
;
955 entryLabel
= GetEntry(i
, &entryValue
);
960 bool isEdit
= this->IsKindOf(CLASSINFO(wxEditEnumProperty
));
962 // If text not any of the choices, store as text instead
963 // (but only if we are wxEditEnumProperty)
964 if ( useIndex
== -1 &&
965 (value
.GetType() != wxPG_VARIANT_TYPE_STRING
|| (m_value
.GetString() != text
)) &&
971 int setAsNextIndex
= -2;
978 else if ( m_index
!= useIndex
)
980 if ( useIndex
!= -1 )
982 setAsNextIndex
= useIndex
;
983 value
= (long)useValue
;
988 value
= wxPGVariant_MinusOne
;
992 if ( setAsNextIndex
!= -2 )
994 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
995 // validation purposes only, and index must not be changed
996 if ( !(argFlags
& wxPG_PROPERTY_SPECIFIC
) )
997 ms_nextIndex
= setAsNextIndex
;
999 if ( isEdit
|| setAsNextIndex
!= -1 )
1007 bool wxBaseEnumProperty
::ValueFromInt_( wxVariant
& variant
, int intVal
, int argFlags
) const
1009 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1013 if ( argFlags
& wxPG_FULL_VALUE
)
1015 ms_nextIndex
= GetIndexForValue( intVal
);
1019 if ( m_index
!= intVal
)
1021 ms_nextIndex
= intVal
;
1025 if ( ms_nextIndex
!= -2 )
1027 if ( !(argFlags
& wxPG_FULL_VALUE
) )
1028 GetEntry(intVal
, &intVal
);
1030 variant
= (long)intVal
;
1038 void wxBaseEnumProperty
::SetIndex( int index
)
1044 int wxBaseEnumProperty
::GetIndex() const
1046 if ( ms_nextIndex
!= -2 )
1047 return ms_nextIndex
;
1051 // -----------------------------------------------------------------------
1053 // -----------------------------------------------------------------------
1055 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty
, wxPGProperty
)
1057 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty
,long,Choice
)
1059 wxEnumProperty
::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
** labels
,
1060 const long* values
, int value
) : wxBaseEnumProperty(label
,name
)
1066 m_choices
.Add(labels
,values
);
1068 if ( GetItemCount() )
1069 SetValue( (long)value
);
1073 wxEnumProperty
::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
** labels
,
1074 const long* values
, wxPGChoices
* choicesCache
, int value
)
1075 : wxBaseEnumProperty(label
,name
)
1079 wxASSERT( choicesCache
);
1081 if ( choicesCache
->IsOk() )
1083 m_choices
.Assign( *choicesCache
);
1084 m_value
= wxPGVariant_Zero
;
1088 m_choices
.Add(labels
,values
);
1090 if ( GetItemCount() )
1091 SetValue( (long)value
);
1095 wxEnumProperty
::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1096 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
) : wxBaseEnumProperty(label
,name
)
1100 if ( &labels
&& labels
.size() )
1102 m_choices
.Set(labels
, values
);
1104 if ( GetItemCount() )
1105 SetValue( (long)value
);
1109 wxEnumProperty
::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1110 wxPGChoices
& choices
, int value
)
1111 : wxBaseEnumProperty(label
,name
)
1113 m_choices
.Assign( choices
);
1115 if ( GetItemCount() )
1116 SetValue( (long)value
);
1119 int wxEnumProperty
::GetIndexForValue( int value
) const
1121 if ( !m_choices
.IsOk() )
1124 if ( m_choices
.HasValues() )
1126 int intVal
= m_choices
.Index(value
);
1134 wxEnumProperty
::~wxEnumProperty ()
1138 const wxString
* wxEnumProperty
::GetEntry( size_t index
, int* pvalue
) const
1140 if ( m_choices
.IsOk() && index
< m_choices
.GetCount() )
1142 int value
= (int)index
;
1143 if ( m_choices
.HasValue(index
) )
1144 value
= m_choices
.GetValue(index
);
1149 return &m_choices
.GetLabel(index
);
1151 return (const wxString
*) NULL
;
1154 // -----------------------------------------------------------------------
1155 // wxEditEnumProperty
1156 // -----------------------------------------------------------------------
1158 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty
, wxPGProperty
)
1160 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty
,wxString
,ComboBox
)
1162 wxEditEnumProperty
::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
** labels
,
1163 const long* values
, const wxString
& value
)
1164 : wxEnumProperty(label
,name
,labels
,values
,0)
1169 wxEditEnumProperty
::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
** labels
,
1170 const long* values
, wxPGChoices
* choicesCache
, const wxString
& value
)
1171 : wxEnumProperty(label
,name
,labels
,values
,choicesCache
,0)
1176 wxEditEnumProperty
::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1177 const wxArrayString
& labels
, const wxArrayInt
& values
, const wxString
& value
)
1178 : wxEnumProperty(label
,name
,labels
,values
,0)
1183 wxEditEnumProperty
::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1184 wxPGChoices
& choices
, const wxString
& value
)
1185 : wxEnumProperty(label
,name
,choices
,0)
1190 wxEditEnumProperty
::~wxEditEnumProperty()
1194 // -----------------------------------------------------------------------
1196 // -----------------------------------------------------------------------
1198 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty
,wxPGProperty
)
1200 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty
,long,TextCtrl
)
1202 void wxFlagsProperty
::Init()
1204 SetFlag(wxPG_PROP_AGGREGATE
); // This is must be done here to support flag props
1205 // with inital zero children.
1207 long value
= m_value
;
1210 // Generate children
1214 unsigned int prevChildCount
= m_children
.GetCount();
1217 if ( prevChildCount
)
1219 wxPropertyGridPageState
* state
= GetParentState();
1221 // State safety check (it may be NULL in immediate parent)
1226 wxPGProperty
* selected
= state
->GetSelection();
1229 if ( selected
->GetParent() == this )
1230 oldSel
= selected
->GetArrIndex();
1231 else if ( selected
== this )
1235 state
->DoClearSelection();
1238 // Delete old children
1239 for ( i
=0; i
<prevChildCount
; i
++ )
1240 delete ( (wxPGProperty
*) m_children
[i
] );
1244 if ( m_choices
.IsOk() )
1246 const wxPGChoices
& choices
= m_choices
;
1248 for ( i
=0; i
<GetItemCount(); i
++ )
1251 if ( choices
.HasValue(i
) )
1252 child_val
= ( value
& choices
.GetValue(i
) )?
true:false;
1254 child_val
= ( value
& (1<<i
) )?
true:false;
1256 wxPGProperty
* boolProp
;
1257 wxString label
= GetLabel(i
);
1260 if ( wxPGGlobalVars
->m_autoGetTranslation
)
1262 boolProp
= new wxBoolProperty( ::wxGetTranslation(label
), label
, child_val
);
1267 boolProp
= new wxBoolProperty( label
, label
, child_val
);
1272 m_oldChoicesData
= m_choices
.GetDataPtr();
1275 m_oldValue
= m_value
;
1277 if ( prevChildCount
)
1278 SubPropsChanged(oldSel
);
1281 wxFlagsProperty
::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1282 const wxChar
** labels
, const long* values
, long value
) : wxPGProperty(label
,name
)
1284 m_oldChoicesData
= (wxPGChoicesData
*) NULL
;
1288 m_choices
.Set(labels
,values
);
1290 wxASSERT( GetItemCount() );
1296 m_value
= wxPGVariant_Zero
;
1300 wxFlagsProperty
::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1301 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1302 : wxPGProperty(label
,name
)
1304 m_oldChoicesData
= (wxPGChoicesData
*) NULL
;
1306 if ( &labels
&& labels
.size() )
1308 m_choices
.Set(labels
,values
);
1310 wxASSERT( GetItemCount() );
1312 SetValue( (long)value
);
1316 m_value
= wxPGVariant_Zero
;
1320 wxFlagsProperty
::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1321 wxPGChoices
& choices
, long value
)
1322 : wxPGProperty(label
,name
)
1324 m_oldChoicesData
= (wxPGChoicesData
*) NULL
;
1326 if ( choices
.IsOk() )
1328 m_choices
.Assign(choices
);
1330 wxASSERT( GetItemCount() );
1336 m_value
= wxPGVariant_Zero
;
1340 wxFlagsProperty
::~wxFlagsProperty()
1344 void wxFlagsProperty
::OnSetValue()
1346 if ( !m_choices
.IsOk() || !GetItemCount() )
1348 m_value
= wxPGVariant_Zero
;
1352 long val
= m_value
.GetLong();
1356 // normalize the value (i.e. remove extra flags)
1358 const wxPGChoices
& choices
= m_choices
;
1359 for ( i
= 0; i
< GetItemCount(); i
++ )
1361 if ( choices
.HasValue(i
) )
1362 fullFlags
|= choices
.GetValue(i
);
1364 fullFlags
|= (1<<i
);
1371 // Need to (re)init now?
1372 if ( GetChildCount() != GetItemCount() ||
1373 m_choices
.GetDataPtr() != m_oldChoicesData
)
1379 long newFlags
= m_value
;
1381 if ( newFlags
!= m_oldValue
)
1383 // Set child modified states
1385 const wxPGChoices
& choices
= m_choices
;
1386 for ( i
= 0; i
<GetItemCount(); i
++ )
1390 if ( choices
.HasValue(i
) )
1391 flag
= choices
.GetValue(i
);
1395 if ( (newFlags
& flag
) != (m_oldValue
& flag
) )
1396 Item(i
)->SetFlag( wxPG_PROP_MODIFIED
);
1399 m_oldValue
= newFlags
;
1403 wxString wxFlagsProperty
::GetValueAsString( int ) const
1407 if ( !m_choices
.IsOk() )
1410 long flags
= m_value
;
1412 const wxPGChoices
& choices
= m_choices
;
1414 for ( i
= 0; i
< GetItemCount(); i
++ )
1417 if ( choices
.HasValue(i
) )
1418 doAdd
= ( flags
& choices
.GetValue(i
) );
1420 doAdd
= ( flags
& (1<<i
) );
1424 text
+= choices
.GetLabel(i
);
1429 // remove last comma
1430 if ( text
.Len() > 1 )
1431 text
.Truncate ( text
.Len() - 2 );
1436 // Translate string into flag tokens
1437 bool wxFlagsProperty
::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1439 if ( !m_choices
.IsOk() )
1443 long oldValue
= m_value
;
1445 // semicolons are no longer valid delimeters
1446 WX_PG_TOKENIZER1_BEGIN(text
,wxS(','))
1448 if ( token
.length() )
1450 // Determine which one it is
1451 long bit
= IdToBit( token
);
1464 WX_PG_TOKENIZER1_END()
1468 if ( newFlags
!= oldValue
)
1474 // Converts string id to a relevant bit.
1475 long wxFlagsProperty
::IdToBit( const wxString
& id
) const
1478 for ( i
= 0; i
< GetItemCount(); i
++ )
1480 if ( id
== GetLabel(i
) )
1482 if ( m_choices
.HasValue(i
) )
1483 return m_choices
.GetValue(i
);
1490 void wxFlagsProperty
::RefreshChildren()
1492 if ( !m_choices
.IsOk() || !GetChildCount() ) return;
1494 int flags
= m_value
.GetLong();
1496 const wxPGChoices
& choices
= m_choices
;
1498 for ( i
= 0; i
< GetItemCount(); i
++ )
1502 if ( choices
.HasValue(i
) )
1503 flag
= choices
.GetValue(i
);
1507 long subVal
= flags
& flag
;
1508 wxPGProperty
* p
= Item(i
);
1510 if ( subVal
!= (m_oldValue
& flag
) )
1511 p
->SetFlag( wxPG_PROP_MODIFIED
);
1513 p
->SetValue( subVal?
true:false );
1519 void wxFlagsProperty
::ChildChanged( wxVariant
& thisValue
, int childIndex
, wxVariant
& childValue
) const
1521 long oldValue
= thisValue
.GetLong();
1522 long val
= childValue
.GetLong();
1523 unsigned long vi
= (1<<childIndex
);
1524 if ( m_choices
.HasValue(childIndex
) ) vi
= m_choices
.GetValue(childIndex
);
1526 thisValue
= (long)(oldValue
| vi
);
1528 thisValue
= (long)(oldValue
& ~(vi
));
1531 // -----------------------------------------------------------------------
1533 // -----------------------------------------------------------------------
1535 IMPLEMENT_DYNAMIC_CLASS(wxDirProperty
, wxLongStringProperty
)
1537 wxDirProperty
::wxDirProperty( const wxString
& name
, const wxString
& label
, const wxString
& value
)
1538 : wxLongStringProperty(name
,label
,value
)
1540 m_flags
|= wxPG_NO_ESCAPE
;
1542 wxDirProperty
::~wxDirProperty() { }
1544 wxValidator
* wxDirProperty
::DoGetValidator() const
1546 return wxFileProperty
::GetClassValidator();
1549 bool wxDirProperty
::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1551 wxSize
dlg_sz(300,400);
1553 wxDirDialog
dlg( propGrid
,
1554 m_dlgMessage
.length() ? m_dlgMessage
: wxString(_("Choose a directory:")),
1557 #if !wxPG_SMALL_SCREEN
1558 propGrid
->GetGoodEditorDialogPosition(this,dlg_sz
),
1565 if ( dlg
.ShowModal() == wxID_OK
)
1567 value
= dlg
.GetPath();
1573 bool wxDirProperty
::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1575 if ( name
== wxPG_DIR_DIALOG_MESSAGE
)
1577 m_dlgMessage
= value
.GetString();
1583 // -----------------------------------------------------------------------
1584 // wxPGFileDialogAdapter
1585 // -----------------------------------------------------------------------
1587 bool wxPGFileDialogAdapter
::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1589 wxFileProperty
* fileProp
= NULL
;
1593 if ( property
->IsKindOf(CLASSINFO(wxFileProperty
)) )
1595 fileProp
= ((wxFileProperty
*)property
);
1596 path
= fileProp
->m_filename
.GetPath();
1597 indFilter
= fileProp
->m_indFilter
;
1599 if ( !path
.length() && fileProp
->m_basePath
.length() )
1600 path
= fileProp
->m_basePath
;
1604 wxFileName
fn(property
->GetValue().GetString());
1605 path
= fn
.GetPath();
1608 wxFileDialog
dlg( propGrid
->GetPanel(),
1609 property
->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1610 property
->GetAttribute(wxS("InitialPath"), path
),
1612 property
->GetAttribute(wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*")),
1614 wxDefaultPosition
);
1616 if ( indFilter
>= 0 )
1617 dlg
.SetFilterIndex( indFilter
);
1619 if ( dlg
.ShowModal() == wxID_OK
)
1622 fileProp
->m_indFilter
= dlg
.GetFilterIndex();
1623 SetValue( dlg
.GetPath() );
1629 // -----------------------------------------------------------------------
1631 // -----------------------------------------------------------------------
1633 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty
,wxPGProperty
,
1634 wxString
,const wxString
&,TextCtrlAndButton
)
1636 wxFileProperty
::wxFileProperty( const wxString
& label
, const wxString
& name
,
1637 const wxString
& value
) : wxPGProperty(label
,name
)
1639 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1641 SetAttribute( wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*") );
1646 wxFileProperty
::~wxFileProperty() {}
1648 #if wxUSE_VALIDATORS
1650 wxValidator
* wxFileProperty
::GetClassValidator()
1652 WX_PG_DOGETVALIDATOR_ENTRY()
1654 // Atleast wxPython 2.6.2.1 required that the string argument is given
1656 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST
,&v
);
1658 wxArrayString exChars
;
1659 exChars
.Add(wxS("?"));
1660 exChars
.Add(wxS("*"));
1661 exChars
.Add(wxS("|"));
1662 exChars
.Add(wxS("<"));
1663 exChars
.Add(wxS(">"));
1664 exChars
.Add(wxS("\""));
1666 validator
->SetExcludes(exChars
);
1668 WX_PG_DOGETVALIDATOR_EXIT(validator
)
1671 wxValidator
* wxFileProperty
::DoGetValidator() const
1673 return GetClassValidator();
1678 void wxFileProperty
::OnSetValue()
1680 const wxString
& fnstr
= m_value
.GetString();
1684 if ( !m_filename
.HasName() )
1686 m_value
= wxPGVariant_EmptyString
;
1690 // Find index for extension.
1691 if ( m_indFilter
< 0 && fnstr
.length() )
1693 wxString ext
= m_filename
.GetExt();
1696 size_t len
= m_wildcard
.length();
1698 pos
= m_wildcard
.find(wxS("|"), pos
);
1699 while ( pos
!= wxString
::npos
&& pos
< (len
-3) )
1701 size_t ext_begin
= pos
+ 3;
1703 pos
= m_wildcard
.find(wxS("|"), ext_begin
);
1704 if ( pos
== wxString
::npos
)
1706 wxString found_ext
= m_wildcard
.substr(ext_begin
, pos
-ext_begin
);
1708 if ( found_ext
.length() > 0 )
1710 if ( found_ext
[0] == wxS('*') )
1712 m_indFilter
= curind
;
1715 if ( ext
.CmpNoCase(found_ext
) == 0 )
1717 m_indFilter
= curind
;
1723 pos
= m_wildcard
.find(wxS("|"), pos
+1);
1730 wxString wxFileProperty
::GetValueAsString( int argFlags
) const
1732 // Always return empty string when name component is empty
1733 wxString fullName
= m_filename
.GetFullName();
1734 if ( !fullName
.length() )
1737 if ( argFlags
& wxPG_FULL_VALUE
)
1739 return m_filename
.GetFullPath();
1741 else if ( m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
)
1743 if ( m_basePath
.Length() )
1745 wxFileName
fn2(m_filename
);
1746 fn2
.MakeRelativeTo(m_basePath
);
1747 return fn2
.GetFullPath();
1749 return m_filename
.GetFullPath();
1752 return m_filename
.GetFullName();
1755 wxPGEditorDialogAdapter
* wxFileProperty
::GetEditorDialog() const
1757 return new wxPGFileDialogAdapter();
1760 bool wxFileProperty
::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1762 if ( (m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
) || (argFlags
& wxPG_FULL_VALUE
) )
1764 if ( m_filename
!= text
)
1772 if ( m_filename
.GetFullName() != text
)
1774 wxFileName fn
= m_filename
;
1775 fn
.SetFullName(text
);
1776 variant
= fn
.GetFullPath();
1784 bool wxFileProperty
::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1786 // Return false on some occasions to make sure those attribs will get
1787 // stored in m_attributes.
1788 if ( name
== wxPG_FILE_SHOW_FULL_PATH
)
1790 if ( wxPGVariantToInt(value
) )
1791 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1793 m_flags
&= ~(wxPG_PROP_SHOW_FULL_FILENAME
);
1796 else if ( name
== wxPG_FILE_WILDCARD
)
1798 m_wildcard
= value
.GetString();
1800 else if ( name
== wxPG_FILE_SHOW_RELATIVE_PATH
)
1802 m_basePath
= value
.GetString();
1804 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1805 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1807 else if ( name
== wxPG_FILE_INITIAL_PATH
)
1809 m_initialPath
= value
.GetString();
1812 else if ( name
== wxPG_FILE_DIALOG_TITLE
)
1814 m_dlgTitle
= value
.GetString();
1820 // -----------------------------------------------------------------------
1821 // wxPGLongStringDialogAdapter
1822 // -----------------------------------------------------------------------
1824 bool wxPGLongStringDialogAdapter
::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1826 wxString val1
= property
->GetValueAsString(0);
1827 wxString val_orig
= val1
;
1830 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1831 wxPropertyGrid
::ExpandEscapeSequences(value
, val1
);
1833 value
= wxString(val1
);
1835 // Run editor dialog.
1836 if ( wxLongStringProperty
::DisplayEditorDialog(property
, propGrid
, value
) )
1838 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1839 wxPropertyGrid
::CreateEscapeSequences(val1
,value
);
1843 if ( val1
!= val_orig
)
1852 // -----------------------------------------------------------------------
1853 // wxLongStringProperty
1854 // -----------------------------------------------------------------------
1856 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty
,wxPGProperty
,
1857 wxString
,const wxString
&,TextCtrlAndButton
)
1859 wxLongStringProperty
::wxLongStringProperty( const wxString
& label
, const wxString
& name
,
1860 const wxString
& value
) : wxPGProperty(label
,name
)
1865 wxLongStringProperty
::~wxLongStringProperty() {}
1867 wxString wxLongStringProperty
::GetValueAsString( int ) const
1872 bool wxLongStringProperty
::OnEvent( wxPropertyGrid
* propGrid
, wxWindow
* WXUNUSED(primary
),
1875 if ( propGrid
->IsMainButtonEvent(event
) )
1878 PrepareValueForDialogEditing(propGrid
);
1880 wxString val1
= GetValueAsString(0);
1881 wxString val_orig
= val1
;
1884 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1885 wxPropertyGrid
::ExpandEscapeSequences(value
,val1
);
1887 value
= wxString(val1
);
1889 // Run editor dialog.
1890 if ( OnButtonClick(propGrid
,value
) )
1892 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1893 wxPropertyGrid
::CreateEscapeSequences(val1
,value
);
1897 if ( val1
!= val_orig
)
1899 SetValueInEvent( val1
);
1907 bool wxLongStringProperty
::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1909 return DisplayEditorDialog(this, propGrid
, value
);
1912 bool wxLongStringProperty
::DisplayEditorDialog( wxPGProperty
* prop
, wxPropertyGrid
* propGrid
, wxString
& value
)
1915 // launch editor dialog
1916 wxDialog
* dlg
= new wxDialog(propGrid
,-1,prop
->GetLabel(),wxDefaultPosition
,wxDefaultSize
,
1917 wxDEFAULT_DIALOG_STYLE
|wxRESIZE_BORDER
|wxCLIP_CHILDREN
);
1919 dlg
->SetFont(propGrid
->GetFont()); // To allow entering chars of the same set as the propGrid
1921 // Multi-line text editor dialog.
1922 #if !wxPG_SMALL_SCREEN
1923 const int spacing
= 8;
1925 const int spacing
= 4;
1927 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
1928 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
1929 wxTextCtrl
* ed
= new wxTextCtrl(dlg
,11,value
,
1930 wxDefaultPosition
,wxDefaultSize
,wxTE_MULTILINE
);
1932 rowsizer
->Add( ed
, 1, wxEXPAND
|wxALL
, spacing
);
1933 topsizer
->Add( rowsizer
, 1, wxEXPAND
, 0 );
1934 rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
1935 const int but_sz_flags
=
1936 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxBOTTOM
|wxLEFT
|wxRIGHT
;
1937 rowsizer
->Add( new wxButton(dlg
,wxID_OK
,_("Ok")),
1938 0, but_sz_flags
, spacing
);
1939 rowsizer
->Add( new wxButton(dlg
,wxID_CANCEL
,_("Cancel")),
1940 0, but_sz_flags
, spacing
);
1941 topsizer
->Add( rowsizer
, 0, wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
, 0 );
1943 dlg
->SetSizer( topsizer
);
1944 topsizer
->SetSizeHints( dlg
);
1946 #if !wxPG_SMALL_SCREEN
1947 dlg
->SetSize(400,300);
1949 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(prop
,dlg
->GetSize()) );
1952 int res
= dlg
->ShowModal();
1954 if ( res
== wxID_OK
)
1956 value
= ed
->GetValue();
1964 bool wxLongStringProperty
::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1966 if ( m_value
!= text
)
1974 // -----------------------------------------------------------------------
1975 // wxArrayEditorDialog
1976 // -----------------------------------------------------------------------
1978 BEGIN_EVENT_TABLE(wxArrayEditorDialog
, wxDialog
)
1979 EVT_IDLE(wxArrayEditorDialog
::OnIdle
)
1980 EVT_LISTBOX(24, wxArrayEditorDialog
::OnListBoxClick
)
1981 EVT_TEXT_ENTER(21, wxArrayEditorDialog
::OnAddClick
)
1982 EVT_BUTTON(22, wxArrayEditorDialog
::OnAddClick
)
1983 EVT_BUTTON(23, wxArrayEditorDialog
::OnDeleteClick
)
1984 EVT_BUTTON(25, wxArrayEditorDialog
::OnUpClick
)
1985 EVT_BUTTON(26, wxArrayEditorDialog
::OnDownClick
)
1986 EVT_BUTTON(27, wxArrayEditorDialog
::OnUpdateClick
)
1987 //EVT_BUTTON(28, wxArrayEditorDialog::OnCustomEditClick)
1990 IMPLEMENT_ABSTRACT_CLASS(wxArrayEditorDialog
, wxDialog
)
1992 #include <wx/statline.h>
1994 // -----------------------------------------------------------------------
1996 void wxArrayEditorDialog
::OnIdle(wxIdleEvent
& event
)
1999 // Do control focus detection here.
2002 wxWindow
* focused
= FindFocus();
2004 // This strange focus thing is a workaround for wxGTK wxListBox focus
2006 if ( m_curFocus
== 0 && focused
!= m_edValue
&&
2007 focused
!= m_butAdd
&& focused
!= m_butUpdate
&&
2008 m_lbStrings
->GetSelection() >= 0 )
2010 // ListBox was just focused.
2011 m_butAdd
->Enable(false);
2012 m_butUpdate
->Enable(false);
2013 m_butRemove
->Enable(true);
2014 m_butUp
->Enable(true);
2015 m_butDown
->Enable(true);
2018 else if ( (m_curFocus
== 1 && focused
== m_edValue
) /*|| m_curFocus == 2*/ )
2020 // TextCtrl was just focused.
2021 m_butAdd
->Enable(true);
2022 bool upd_enable
= false;
2023 if ( m_lbStrings
->GetCount() && m_lbStrings
->GetSelection() >= 0 )
2025 m_butUpdate
->Enable(upd_enable
);
2026 m_butRemove
->Enable(false);
2027 m_butUp
->Enable(false);
2028 m_butDown
->Enable(false);
2035 // -----------------------------------------------------------------------
2037 wxArrayEditorDialog
::wxArrayEditorDialog()
2043 // -----------------------------------------------------------------------
2045 void wxArrayEditorDialog
::Init()
2047 m_custBtText
= (const wxChar
*) NULL
;
2050 // -----------------------------------------------------------------------
2052 wxArrayEditorDialog
::wxArrayEditorDialog( wxWindow
*parent
,
2053 const wxString
& message
,
2054 const wxString
& caption
,
2061 Create(parent
,message
,caption
,style
,pos
,sz
);
2064 // -----------------------------------------------------------------------
2066 bool wxArrayEditorDialog
::Create( wxWindow
*parent
,
2067 const wxString
& message
,
2068 const wxString
& caption
,
2073 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2074 // FIXME: This should be only a temporary fix.
2076 int useStyle
= wxCAPTION
;
2078 int useStyle
= style
;
2081 bool res
= wxDialog
::Create(parent
, wxID_ANY
, caption
, pos
, sz
, useStyle
);
2083 SetFont(parent
->GetFont()); // To allow entering chars of the same set as the propGrid
2085 #if !wxPG_SMALL_SCREEN
2086 const int spacing
= 4;
2088 const int spacing
= 3;
2095 const int but_sz_flags
=
2096 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxALL
; //wxBOTTOM|wxLEFT|wxRIGHT;
2098 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2101 if ( message
.length() )
2102 topsizer
->Add( new wxStaticText(this,-1,message
),
2103 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2106 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2107 m_edValue
= new wxTextCtrl(this,21,wxEmptyString
,
2108 wxDefaultPosition
,wxDefaultSize
,wxTE_PROCESS_ENTER
);
2109 wxValidator
* validator
= GetTextCtrlValidator();
2112 m_edValue
->SetValidator( *validator
);
2115 rowsizer
->Add( m_edValue
,
2116 1, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2119 m_butAdd
= new wxButton(this,22,_("Add"));
2120 rowsizer
->Add( m_butAdd
,
2121 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxTOP
|wxBOTTOM
|wxRIGHT
, spacing
);
2122 topsizer
->Add( rowsizer
, 0, wxEXPAND
, spacing
);
2125 topsizer
->Add( new wxStaticLine(this,-1),
2126 0, wxEXPAND
|wxBOTTOM
|wxLEFT
|wxRIGHT
, spacing
);
2128 rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2131 m_lbStrings
= new wxListBox(this, 24, wxDefaultPosition
, wxDefaultSize
);
2133 for ( i
=0; i
<ArrayGetCount(); i
++ )
2134 m_lbStrings
->Append( ArrayGet(i
) );
2135 rowsizer
->Add( m_lbStrings
, 1, wxEXPAND
|wxRIGHT
, spacing
);
2137 // Manipulator buttons
2138 wxBoxSizer
* colsizer
= new wxBoxSizer( wxVERTICAL
);
2139 m_butCustom
= (wxButton
*) NULL
;
2142 m_butCustom
= new wxButton(this,28,::wxGetTranslation(m_custBtText
));
2143 colsizer
->Add( m_butCustom
,
2144 0, wxALIGN_CENTER
|wxTOP
/*wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT*/,
2147 m_butUpdate
= new wxButton(this,27,_("Update"));
2148 colsizer
->Add( m_butUpdate
,
2149 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2150 m_butRemove
= new wxButton(this,23,_("Remove"));
2151 colsizer
->Add( m_butRemove
,
2152 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2153 m_butUp
= new wxButton(this,25,_("Up"));
2154 colsizer
->Add( m_butUp
,
2155 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2156 m_butDown
= new wxButton(this,26,_("Down"));
2157 colsizer
->Add( m_butDown
,
2158 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2159 rowsizer
->Add( colsizer
, 0, 0, spacing
);
2161 topsizer
->Add( rowsizer
, 1, wxLEFT
|wxRIGHT
|wxEXPAND
, spacing
);
2164 topsizer
->Add( new wxStaticLine(this,-1),
2165 0, wxEXPAND
|wxTOP
|wxLEFT
|wxRIGHT
, spacing
);
2168 rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2170 const int but_sz_flags =
2171 wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT;
2173 rowsizer
->Add( new wxButton(this,wxID_OK
,_("Ok")),
2174 0, but_sz_flags
, spacing
);
2175 rowsizer
->Add( new wxButton(this,wxID_CANCEL
,_("Cancel")),
2176 0, but_sz_flags
, spacing
);
2177 topsizer
->Add( rowsizer
, 0, wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
, 0 );
2179 m_edValue
->SetFocus();
2181 SetSizer( topsizer
);
2182 topsizer
->SetSizeHints( this );
2184 #if !wxPG_SMALL_SCREEN
2185 if ( sz
.x
== wxDefaultSize
.x
&&
2186 sz
.y
== wxDefaultSize
.y
)
2187 SetSize( wxSize(275,360) );
2195 // -----------------------------------------------------------------------
2197 void wxArrayEditorDialog
::OnAddClick(wxCommandEvent
& )
2199 wxString text
= m_edValue
->GetValue();
2200 if ( text
.length() )
2202 if ( ArrayInsert( text
, -1 ) )
2204 m_lbStrings
->Append( text
);
2211 // -----------------------------------------------------------------------
2213 void wxArrayEditorDialog
::OnDeleteClick(wxCommandEvent
& )
2215 int index
= m_lbStrings
->GetSelection();
2218 ArrayRemoveAt( index
);
2219 m_lbStrings
->Delete ( index
);
2224 // -----------------------------------------------------------------------
2226 void wxArrayEditorDialog
::OnUpClick(wxCommandEvent
& )
2228 int index
= m_lbStrings
->GetSelection();
2231 ArraySwap(index
-1,index
);
2232 /*wxString old_str = m_array[index-1];
2233 wxString new_str = m_array[index];
2234 m_array[index-1] = new_str;
2235 m_array[index] = old_str;*/
2236 m_lbStrings
->SetString ( index
-1, ArrayGet(index
-1) );
2237 m_lbStrings
->SetString ( index
, ArrayGet(index
) );
2238 m_lbStrings
->SetSelection ( index
-1 );
2243 // -----------------------------------------------------------------------
2245 void wxArrayEditorDialog
::OnDownClick(wxCommandEvent
& )
2247 int index
= m_lbStrings
->GetSelection();
2248 int lastStringIndex
= ((int) m_lbStrings
->GetCount()) - 1;
2249 if ( index
>= 0 && index
< lastStringIndex
)
2251 ArraySwap(index
,index
+1);
2252 /*wxString old_str = m_array[index+1];
2253 wxString new_str = m_array[index];
2254 m_array[index+1] = new_str;
2255 m_array[index] = old_str;*/
2256 m_lbStrings
->SetString ( index
+1, ArrayGet(index
+1) );
2257 m_lbStrings
->SetString ( index
, ArrayGet(index
) );
2258 m_lbStrings
->SetSelection ( index
+1 );
2263 // -----------------------------------------------------------------------
2265 void wxArrayEditorDialog
::OnUpdateClick(wxCommandEvent
& )
2267 int index
= m_lbStrings
->GetSelection();
2270 wxString str
= m_edValue
->GetValue();
2271 if ( ArraySet(index
,str
) )
2273 m_lbStrings
->SetString ( index
, str
);
2274 //m_array[index] = str;
2280 // -----------------------------------------------------------------------
2282 void wxArrayEditorDialog
::OnListBoxClick(wxCommandEvent
& )
2284 int index
= m_lbStrings
->GetSelection();
2287 m_edValue
->SetValue( m_lbStrings
->GetString(index
) );
2291 // -----------------------------------------------------------------------
2292 // wxPGArrayStringEditorDialog
2293 // -----------------------------------------------------------------------
2295 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog
, wxArrayEditorDialog
)
2297 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog
, wxArrayEditorDialog
)
2298 EVT_BUTTON(28, wxPGArrayStringEditorDialog
::OnCustomEditClick
)
2301 // -----------------------------------------------------------------------
2303 wxString wxPGArrayStringEditorDialog
::ArrayGet( size_t index
)
2305 return m_array
[index
];
2308 size_t wxPGArrayStringEditorDialog
::ArrayGetCount()
2310 return m_array
.size();
2313 bool wxPGArrayStringEditorDialog
::ArrayInsert( const wxString
& str
, int index
)
2318 m_array
.Insert(str
,index
);
2322 bool wxPGArrayStringEditorDialog
::ArraySet( size_t index
, const wxString
& str
)
2324 m_array
[index
] = str
;
2328 void wxPGArrayStringEditorDialog
::ArrayRemoveAt( int index
)
2330 m_array
.RemoveAt(index
);
2333 void wxPGArrayStringEditorDialog
::ArraySwap( size_t first
, size_t second
)
2335 wxString old_str
= m_array
[first
];
2336 wxString new_str
= m_array
[second
];
2337 m_array
[first
] = new_str
;
2338 m_array
[second
] = old_str
;
2341 wxPGArrayStringEditorDialog
::wxPGArrayStringEditorDialog()
2342 : wxArrayEditorDialog()
2347 void wxPGArrayStringEditorDialog
::Init()
2349 m_pCallingClass
= (wxArrayStringProperty
*) NULL
;
2352 void wxPGArrayStringEditorDialog
::OnCustomEditClick(wxCommandEvent
& )
2354 wxASSERT( m_pCallingClass
);
2355 wxString str
= m_edValue
->GetValue();
2356 if ( m_pCallingClass
->OnCustomStringEdit(m_parent
,str
) )
2358 //m_edValue->SetValue ( str );
2359 m_lbStrings
->Append ( str
);
2360 m_array
.Add ( str
);
2365 // -----------------------------------------------------------------------
2366 // wxArrayStringProperty
2367 // -----------------------------------------------------------------------
2369 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty
, // Property name
2370 wxPGProperty
, // Property we inherit from
2371 wxArrayString
, // Value type name
2372 const wxArrayString
&, // Value type, as given in constructor
2373 TextCtrlAndButton
) // Initial editor
2375 wxArrayStringProperty
::wxArrayStringProperty( const wxString
& label
,
2376 const wxString
& name
,
2377 const wxArrayString
& array
)
2378 : wxPGProperty(label
,name
)
2383 wxArrayStringProperty
::~wxArrayStringProperty() { }
2385 void wxArrayStringProperty
::OnSetValue()
2387 GenerateValueAsString();
2390 wxString wxArrayStringProperty
::GetValueAsString( int WXUNUSED(argFlags
) ) const
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
2398 void wxPropertyGrid
::ArrayStringToString( wxString
& dst
, const wxArrayString
& src
,
2399 wxChar preDelim
, wxChar postDelim
,
2405 unsigned int itemCount
= src
.size();
2413 else if ( (flags
& 1) )
2415 preas
[0] = preDelim
;
2422 dst
.append( preas
);
2424 wxASSERT( postDelim
);
2425 wxString
postDelimStr(postDelim
);
2426 //wxString preDelimStr(preDelim);
2428 for ( i
= 0; i
< itemCount
; i
++ )
2430 wxString
str( src
.Item(i
) );
2432 // Do some character conversion.
2433 // Convertes \ to \\ and <preDelim> to \<preDelim>
2434 // Useful when preDelim and postDelim are "\"".
2437 str
.Replace( wxS("\\"), wxS("\\\\"), true );
2439 str
.Replace( preas
, pdr
, true );
2444 if ( i
< (itemCount
-1) )
2446 dst
.append( postDelimStr
);
2447 dst
.append( wxS(" ") );
2448 dst
.append( preas
);
2450 else if ( preDelim
)
2451 dst
.append( postDelimStr
);
2455 #define ARRSTRPROP_ARRAY_TO_STRING(STRING,ARRAY) \
2456 wxPropertyGrid::ArrayStringToString(STRING,ARRAY,wxS('"'),wxS('"'),1);
2458 void wxArrayStringProperty
::GenerateValueAsString()
2460 wxArrayString arr
= m_value
.GetArrayString();
2461 ARRSTRPROP_ARRAY_TO_STRING(m_display
, arr
)
2464 // Default implementation doesn't do anything.
2465 bool wxArrayStringProperty
::OnCustomStringEdit( wxWindow
*, wxString
& )
2470 wxArrayEditorDialog
* wxArrayStringProperty
::CreateEditorDialog()
2472 return new wxPGArrayStringEditorDialog();
2475 bool wxArrayStringProperty
::OnButtonClick( wxPropertyGrid
* propGrid
,
2476 wxWindow
* WXUNUSED(primaryCtrl
),
2480 PrepareValueForDialogEditing(propGrid
);
2482 if ( !propGrid
->EditorValidate() )
2485 // Create editor dialog.
2486 wxArrayEditorDialog
* dlg
= CreateEditorDialog();
2487 #if wxUSE_VALIDATORS
2488 wxValidator
* validator
= GetValidator();
2489 wxPGInDialogValidator dialogValidator
;
2492 wxPGArrayStringEditorDialog
* strEdDlg
= wxDynamicCast(dlg
, wxPGArrayStringEditorDialog
);
2495 strEdDlg
->SetCustomButton(cbt
, this);
2497 dlg
->SetDialogValue( wxVariant(m_value
) );
2498 dlg
->Create(propGrid
, wxEmptyString
, m_label
);
2500 #if !wxPG_SMALL_SCREEN
2501 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(this,dlg
->GetSize()) );
2510 int res
= dlg
->ShowModal();
2512 if ( res
== wxID_OK
&& dlg
->IsModified() )
2514 wxVariant value
= dlg
->GetDialogValue();
2515 if ( !value
.IsNull() )
2517 wxArrayString actualValue
= value
.GetArrayString();
2519 ARRSTRPROP_ARRAY_TO_STRING(tempStr
, actualValue
)
2520 #if wxUSE_VALIDATORS
2521 if ( dialogValidator
.DoValidate( propGrid
, validator
, tempStr
) )
2524 SetValueInEvent( actualValue
);
2541 bool wxArrayStringProperty
::OnEvent( wxPropertyGrid
* propGrid
,
2545 if ( propGrid
->IsMainButtonEvent(event
) )
2546 return OnButtonClick(propGrid
,primary
,(const wxChar
*) NULL
);
2550 bool wxArrayStringProperty
::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
2554 WX_PG_TOKENIZER2_BEGIN(text
,wxS('"'))
2556 // Need to replace backslashes with empty characters
2557 // (opposite what is done in GenerateValueString).
2558 token
.Replace ( wxS("\\"), wxEmptyString
, true );
2562 WX_PG_TOKENIZER2_END()
2569 // -----------------------------------------------------------------------
2570 // wxPGInDialogValidator
2571 // -----------------------------------------------------------------------
2573 #if wxUSE_VALIDATORS
2574 bool wxPGInDialogValidator
::DoValidate( wxPropertyGrid
* propGrid
,
2575 wxValidator
* validator
,
2576 const wxString
& value
)
2581 wxTextCtrl
* tc
= m_textCtrl
;
2586 tc
= new wxTextCtrl( propGrid
, wxPG_SUBID_TEMP1
, wxEmptyString
,
2587 wxPoint(30000,30000));
2594 tc
->SetValue(value
);
2596 validator
->SetWindow(tc
);
2597 bool res
= validator
->Validate(propGrid
);
2602 bool wxPGInDialogValidator
::DoValidate( wxPropertyGrid
* WXUNUSED(propGrid
),
2603 wxValidator
* WXUNUSED(validator
),
2604 const wxString
& WXUNUSED(value
) )
2610 // -----------------------------------------------------------------------
2612 #endif // wxUSE_PROPGRID