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"
52 #include "wx/filename.h"
54 #include "wx/propgrid/propgrid.h"
56 #define wxPG_CUSTOM_IMAGE_WIDTH 20 // for wxColourProperty etc.
59 // -----------------------------------------------------------------------
61 // -----------------------------------------------------------------------
63 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxStringProperty
,wxPGProperty
,
64 wxString
,const wxString
&,TextCtrl
)
66 wxStringProperty::wxStringProperty( const wxString
& label
,
68 const wxString
& value
)
69 : wxPGProperty(label
,name
)
74 void wxStringProperty::OnSetValue()
76 if ( !m_value
.IsNull() && m_value
.GetString() == wxS("<composed>") )
77 SetFlag(wxPG_PROP_COMPOSED_VALUE
);
79 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
82 DoGenerateComposedValue(s
);
87 wxStringProperty::~wxStringProperty() { }
89 wxString
wxStringProperty::ValueToString( wxVariant
& value
,
92 wxString s
= 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
) )
99 // Calling this under incorrect conditions will fail
100 wxASSERT_MSG( argFlags
& wxPG_VALUE_IS_CURRENT
,
101 "Sorry, currently default wxPGProperty::ValueToString() "
102 "implementation only works if value is m_value." );
104 DoGenerateComposedValue(s
, argFlags
);
110 // If string is password and value is for visual purposes,
111 // then return asterisks instead the actual string.
112 if ( (m_flags
& wxPG_PROP_PASSWORD
) && !(argFlags
& (wxPG_FULL_VALUE
|wxPG_EDITABLE_VALUE
)) )
113 return wxString(wxChar('*'), s
.Length());
118 bool wxStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
120 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
121 return wxPGProperty::StringToValue(variant
, text
, argFlags
);
123 if ( variant
!= text
)
132 bool wxStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
134 if ( name
== wxPG_STRING_PASSWORD
)
136 m_flags
&= ~(wxPG_PROP_PASSWORD
);
137 if ( wxPGVariantToInt(value
) ) m_flags
|= wxPG_PROP_PASSWORD
;
144 // -----------------------------------------------------------------------
146 // -----------------------------------------------------------------------
148 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty
,wxPGProperty
,
151 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
152 long value
) : wxPGProperty(label
,name
)
157 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
158 const wxLongLong
& value
) : wxPGProperty(label
,name
)
160 SetValue(WXVARIANT(value
));
163 wxIntProperty::~wxIntProperty() { }
165 wxString
wxIntProperty::ValueToString( wxVariant
& value
,
166 int WXUNUSED(argFlags
) ) const
168 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
170 return wxString::Format(wxS("%li"),value
.GetLong());
172 else if ( value
.GetType() == wxLongLong_VariantType
)
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
== wxLongLong_VariantType
)
228 if ( oldValue
.GetValue() != value64
)
229 doChangeValue
= true;
234 wxLongLong
ll(value64
);
240 if ( useText
.ToLong( &value32
, 0 ) )
242 if ( !isPrevLong
|| variant
!= value32
)
249 else if ( argFlags
& wxPG_REPORT_ERROR
)
255 bool wxIntProperty::IntToValue( wxVariant
& variant
, int value
, int WXUNUSED(argFlags
) ) const
257 if ( variant
.GetType() != wxPG_VARIANT_TYPE_LONG
|| variant
!= (long)value
)
259 variant
= (long)value
;
265 bool wxIntProperty::DoValidation( const wxPGProperty
* property
, wxLongLong_t
& value
, wxPGValidationInfo
* pValidationInfo
, int mode
)
268 wxLongLong_t min
= wxINT64_MIN
;
269 wxLongLong_t max
= wxINT64_MAX
;
274 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
275 if ( !variant
.IsNull() )
277 wxPGVariantToLongLong(variant
, &min
);
281 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
282 if ( !variant
.IsNull() )
284 wxPGVariantToLongLong(variant
, &max
);
292 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
293 pValidationInfo
->SetFailureMessage(
294 wxString::Format(_("Value must be %lld or higher"),min
)
296 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
299 value
= max
- (min
- value
);
308 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
309 pValidationInfo
->SetFailureMessage(
310 wxString::Format(_("Value must be %lld or higher"),min
)
312 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
315 value
= min
+ (value
- max
);
322 bool wxIntProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
325 if ( wxPGVariantToLongLong(value
, &ll
) )
326 return DoValidation(this, ll
, &validationInfo
, wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
330 wxValidator
* wxIntProperty::GetClassValidator()
333 WX_PG_DOGETVALIDATOR_ENTRY()
335 // Atleast wxPython 2.6.2.1 required that the string argument is given
337 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_NUMERIC
,&v
);
339 WX_PG_DOGETVALIDATOR_EXIT(validator
)
345 wxValidator
* wxIntProperty::DoGetValidator() const
347 return GetClassValidator();
350 // -----------------------------------------------------------------------
352 // -----------------------------------------------------------------------
355 #define wxPG_UINT_TEMPLATE_MAX 8
357 static const wxChar
* gs_uintTemplates32
[wxPG_UINT_TEMPLATE_MAX
] = {
358 wxT("%x"),wxT("0x%x"),wxT("$%x"),
359 wxT("%X"),wxT("0x%X"),wxT("$%X"),
363 static const wxChar
* gs_uintTemplates64
[wxPG_UINT_TEMPLATE_MAX
] = {
364 wxT("%") wxLongLongFmtSpec
wxT("x"),
365 wxT("0x%") wxLongLongFmtSpec
wxT("x"),
366 wxT("$%") wxLongLongFmtSpec
wxT("x"),
367 wxT("%") wxLongLongFmtSpec
wxT("X"),
368 wxT("0x%") wxLongLongFmtSpec
wxT("X"),
369 wxT("$%") wxLongLongFmtSpec
wxT("X"),
370 wxT("%") wxLongLongFmtSpec
wxT("u"),
371 wxT("%") wxLongLongFmtSpec
wxT("o")
374 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty
,wxPGProperty
,
375 long,unsigned long,TextCtrl
)
377 void wxUIntProperty::Init()
379 m_base
= 6; // This is magic number for dec base (must be same as in setattribute)
381 m_prefix
= wxPG_PREFIX_NONE
;
384 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
385 unsigned long value
) : wxPGProperty(label
,name
)
388 SetValue((long)value
);
391 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
392 const wxULongLong
& value
) : wxPGProperty(label
,name
)
395 SetValue(WXVARIANT(value
));
398 wxUIntProperty::~wxUIntProperty() { }
400 wxString
wxUIntProperty::ValueToString( wxVariant
& value
,
401 int WXUNUSED(argFlags
) ) const
403 size_t index
= m_base
+ m_prefix
;
404 if ( index
>= wxPG_UINT_TEMPLATE_MAX
)
405 index
= wxPG_BASE_DEC
;
407 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
409 return wxString::Format(gs_uintTemplates32
[index
], (unsigned long)value
.GetLong());
415 return wxString::Format(gs_uintTemplates64
[index
], ull
.GetValue());
418 bool wxUIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
420 wxString variantType
= variant
.GetType();
421 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
423 if ( text
.length() == 0 )
430 if ( text
[0] == wxS('$') )
433 wxULongLong_t value64
= 0;
434 wxString s
= text
.substr(start
, text
.length() - start
);
436 if ( s
.ToULongLong(&value64
, (unsigned int)m_realBase
) )
438 if ( value64
>= LONG_MAX
)
440 bool doChangeValue
= isPrevLong
;
442 if ( !isPrevLong
&& variantType
== wxULongLong_VariantType
)
444 wxULongLong oldValue
;
446 if ( oldValue
.GetValue() != value64
)
447 doChangeValue
= true;
452 wxULongLong
ull(value64
);
459 unsigned long value32
= wxLongLong(value64
).GetLo();
460 if ( !isPrevLong
|| m_value
!= (long)value32
)
462 variant
= (long)value32
;
471 bool wxUIntProperty::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
473 if ( variant
!= (long)number
)
475 variant
= (long)number
;
482 #define wxUINT64_MAX ULLONG_MAX
483 #define wxUINT64_MIN wxULL(0)
485 #define wxUINT64_MAX wxULL(0xFFFFFFFFFFFFFFFF)
486 #define wxUINT64_MIN wxULL(0)
489 bool wxUIntProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
493 if ( wxPGVariantToULongLong(value
, &ll
) )
495 wxULongLong_t min
= wxUINT64_MIN
;
496 wxULongLong_t max
= wxUINT64_MAX
;
499 variant
= GetAttribute(wxPGGlobalVars
->m_strMin
);
500 if ( !variant
.IsNull() )
502 wxPGVariantToULongLong(variant
, &min
);
505 validationInfo
.SetFailureMessage(
506 wxString::Format(_("Value must be %llu or higher"),min
)
511 variant
= GetAttribute(wxPGGlobalVars
->m_strMax
);
512 if ( !variant
.IsNull() )
514 wxPGVariantToULongLong(variant
, &max
);
517 validationInfo
.SetFailureMessage(
518 wxString::Format(_("Value must be %llu or less"),max
)
527 bool wxUIntProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
529 if ( name
== wxPG_UINT_BASE
)
531 int val
= value
.GetLong();
533 m_realBase
= (wxByte
) val
;
534 if ( m_realBase
> 16 )
538 // Translate logical base to a template array index
540 if ( val
== wxPG_BASE_HEX
)
542 else if ( val
== wxPG_BASE_DEC
)
544 else if ( val
== wxPG_BASE_HEXL
)
548 else if ( name
== wxPG_UINT_PREFIX
)
550 m_prefix
= (wxByte
) value
.GetLong();
556 // -----------------------------------------------------------------------
558 // -----------------------------------------------------------------------
560 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty
,wxPGProperty
,
561 double,double,TextCtrl
)
563 wxFloatProperty::wxFloatProperty( const wxString
& label
,
564 const wxString
& name
,
566 : wxPGProperty(label
,name
)
572 wxFloatProperty::~wxFloatProperty() { }
574 // This helper method provides standard way for floating point-using
575 // properties to convert values to string.
576 void wxPropertyGrid::DoubleToString(wxString
& target
,
580 wxString
* precTemplate
)
582 if ( precision
>= 0 )
586 precTemplate
= &text1
;
588 if ( !precTemplate
->length() )
590 *precTemplate
= wxS("%.");
591 *precTemplate
<< wxString::Format( wxS("%i"), precision
);
592 *precTemplate
<< wxS('f');
595 target
.Printf( precTemplate
->c_str(), value
);
599 target
.Printf( wxS("%f"), value
);
602 if ( removeZeroes
&& precision
!= 0 && target
.length() )
604 // Remove excess zeroes (do not remove this code just yet,
605 // since sprintf can't do the same consistently across platforms).
606 wxString::const_iterator i
= target
.end() - 1;
607 size_t new_len
= target
.length() - 1;
609 for ( ; i
!= target
.begin(); i
-- )
611 if ( *i
!= wxS('0') )
616 wxChar cur_char
= *i
;
617 if ( cur_char
!= wxS('.') && cur_char
!= wxS(',') )
620 if ( new_len
!= target
.length() )
621 target
.resize(new_len
);
625 wxString
wxFloatProperty::ValueToString( wxVariant
& value
,
629 if ( !value
.IsNull() )
631 wxPropertyGrid::DoubleToString(text
,
634 !(argFlags
& wxPG_FULL_VALUE
),
640 bool wxFloatProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
645 if ( text
.length() == 0 )
651 bool res
= text
.ToDouble(&value
);
654 if ( variant
!= value
)
660 else if ( argFlags
& wxPG_REPORT_ERROR
)
666 bool wxFloatProperty::DoValidation( const wxPGProperty
* property
, double& value
, wxPGValidationInfo
* pValidationInfo
, int mode
)
669 double min
= (double)wxINT64_MIN
;
670 double max
= (double)wxINT64_MAX
;
675 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
676 if ( !variant
.IsNull() )
678 wxPGVariantToDouble(variant
, &min
);
682 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
683 if ( !variant
.IsNull() )
685 wxPGVariantToDouble(variant
, &max
);
693 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
694 pValidationInfo
->SetFailureMessage(
695 wxString::Format(_("Value must be %f or higher"),min
)
697 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
700 value
= max
- (min
- value
);
707 wxPGVariantToDouble(variant
, &max
);
710 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
711 pValidationInfo
->SetFailureMessage(
712 wxString::Format(_("Value must be %f or less"),max
)
714 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
717 value
= min
+ (value
- max
);
724 bool wxFloatProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
727 if ( wxPGVariantToDouble(value
, &fpv
) )
728 return DoValidation(this, fpv
, &validationInfo
, wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
732 bool wxFloatProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
734 if ( name
== wxPG_FLOAT_PRECISION
)
736 m_precision
= value
.GetLong();
742 wxValidator
* wxFloatProperty::DoGetValidator() const
744 return wxIntProperty::GetClassValidator();
747 // -----------------------------------------------------------------------
749 // -----------------------------------------------------------------------
751 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
752 // there is a custom GetEditorClass.
754 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty
, wxPGProperty
)
756 const wxPGEditor
* wxBoolProperty::DoGetEditorClass() const
758 // Select correct editor control.
759 #if wxPG_INCLUDE_CHECKBOX
760 if ( !(m_flags
& wxPG_PROP_USE_CHECKBOX
) )
761 return wxPGEditor_Choice
;
762 return wxPGEditor_CheckBox
;
764 return wxPGEditor_Choice
;
768 wxBoolProperty::wxBoolProperty( const wxString
& label
, const wxString
& name
, bool value
) :
769 wxPGProperty(label
,name
)
771 m_choices
.Assign(wxPGGlobalVars
->m_boolChoices
);
773 SetValue(wxPGVariant_Bool(value
));
775 m_flags
|= wxPG_PROP_USE_DCC
;
778 wxBoolProperty::~wxBoolProperty() { }
780 wxString
wxBoolProperty::ValueToString( wxVariant
& value
,
783 bool boolValue
= value
.GetBool();
785 // As a fragment of composite string value,
786 // make it a little more readable.
787 if ( argFlags
& wxPG_COMPOSITE_FRAGMENT
)
795 if ( argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
)
796 return wxEmptyString
;
799 if ( wxPGGlobalVars
->m_autoGetTranslation
)
800 notFmt
= _("Not %s");
802 notFmt
= wxS("Not %s");
804 return wxString::Format(notFmt
.c_str(), m_label
.c_str());
808 if ( !(argFlags
& wxPG_FULL_VALUE
) )
810 return wxPGGlobalVars
->m_boolChoices
[boolValue
?1:0].GetText();
815 if ( boolValue
) text
= wxS("true");
816 else text
= wxS("false");
821 bool wxBoolProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
823 bool boolValue
= false;
824 if ( text
.CmpNoCase(wxPGGlobalVars
->m_boolChoices
[1].GetText()) == 0 ||
825 text
.CmpNoCase(wxS("true")) == 0 ||
826 text
.CmpNoCase(m_label
) == 0 )
829 if ( text
.length() == 0 )
835 if ( variant
!= boolValue
)
837 variant
= wxPGVariant_Bool(boolValue
);
843 bool wxBoolProperty::IntToValue( wxVariant
& variant
, int value
, int ) const
845 bool boolValue
= value
? true : false;
847 if ( variant
!= boolValue
)
849 variant
= wxPGVariant_Bool(boolValue
);
855 bool wxBoolProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
857 #if wxPG_INCLUDE_CHECKBOX
858 if ( name
== wxPG_BOOL_USE_CHECKBOX
)
860 int ival
= wxPGVariantToInt(value
);
862 m_flags
|= wxPG_PROP_USE_CHECKBOX
;
864 m_flags
&= ~(wxPG_PROP_USE_CHECKBOX
);
868 if ( name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
870 int ival
= wxPGVariantToInt(value
);
872 m_flags
|= wxPG_PROP_USE_DCC
;
874 m_flags
&= ~(wxPG_PROP_USE_DCC
);
880 // -----------------------------------------------------------------------
881 // wxBaseEnumProperty
882 // -----------------------------------------------------------------------
884 int wxBaseEnumProperty::ms_nextIndex
= -2;
886 wxBaseEnumProperty::wxBaseEnumProperty( const wxString
& label
, const wxString
& name
)
887 : wxPGProperty(label
,name
)
889 m_value
= wxPGVariant_Zero
;
892 /** If has values array, then returns number at index with value -
893 otherwise just returns the value.
895 int wxBaseEnumProperty::GetIndexForValue( int value
) const
900 void wxBaseEnumProperty::OnSetValue()
902 wxString variantType
= m_value
.GetType();
904 if ( variantType
== wxPG_VARIANT_TYPE_LONG
)
905 ValueFromInt_( m_value
, m_value
.GetLong(), wxPG_FULL_VALUE
);
906 else if ( variantType
== wxPG_VARIANT_TYPE_STRING
)
907 ValueFromString_( m_value
, m_value
.GetString(), 0 );
911 if ( ms_nextIndex
!= -2 )
913 m_index
= ms_nextIndex
;
918 bool wxBaseEnumProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
920 // Make sure string value is in the list,
921 // unless property has string as preferred value type
922 // To reduce code size, use conversion here as well
923 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
&&
924 !this->IsKindOf(CLASSINFO(wxEditEnumProperty
)) )
925 return ValueFromString_( value
, value
.GetString(), wxPG_PROPERTY_SPECIFIC
);
930 wxString
wxBaseEnumProperty::ValueToString( wxVariant
& value
,
931 int WXUNUSED(argFlags
) ) const
933 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
)
934 return value
.GetString();
936 int index
= m_choices
.Index(value
.GetLong());
938 return wxEmptyString
;
940 return m_choices
.GetLabel(index
);
943 bool wxBaseEnumProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
945 return ValueFromString_( variant
, text
, argFlags
);
948 bool wxBaseEnumProperty::IntToValue( wxVariant
& variant
, int intVal
, int argFlags
) const
950 return ValueFromInt_( variant
, intVal
, argFlags
);
953 bool wxBaseEnumProperty::ValueFromString_( wxVariant
& value
, const wxString
& text
, int argFlags
) const
956 const wxString
* entryLabel
;
961 entryLabel
= GetEntry(i
, &entryValue
);
964 if ( text
.CmpNoCase(*entryLabel
) == 0 )
967 useValue
= (long)entryValue
;
972 entryLabel
= GetEntry(i
, &entryValue
);
977 bool isEdit
= this->IsKindOf(CLASSINFO(wxEditEnumProperty
));
979 // If text not any of the choices, store as text instead
980 // (but only if we are wxEditEnumProperty)
981 if ( useIndex
== -1 &&
982 (value
.GetType() != wxPG_VARIANT_TYPE_STRING
|| (m_value
.GetString() != text
)) &&
988 int setAsNextIndex
= -2;
995 else if ( m_index
!= useIndex
)
997 if ( useIndex
!= -1 )
999 setAsNextIndex
= useIndex
;
1000 value
= (long)useValue
;
1004 setAsNextIndex
= -1;
1005 value
= wxPGVariant_MinusOne
;
1009 if ( setAsNextIndex
!= -2 )
1011 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1012 // validation purposes only, and index must not be changed
1013 if ( !(argFlags
& wxPG_PROPERTY_SPECIFIC
) )
1014 ms_nextIndex
= setAsNextIndex
;
1016 if ( isEdit
|| setAsNextIndex
!= -1 )
1024 bool wxBaseEnumProperty::ValueFromInt_( wxVariant
& variant
, int intVal
, int argFlags
) const
1026 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1030 if ( argFlags
& wxPG_FULL_VALUE
)
1032 ms_nextIndex
= GetIndexForValue( intVal
);
1036 if ( m_index
!= intVal
)
1038 ms_nextIndex
= intVal
;
1042 if ( ms_nextIndex
!= -2 )
1044 if ( !(argFlags
& wxPG_FULL_VALUE
) )
1045 GetEntry(intVal
, &intVal
);
1047 variant
= (long)intVal
;
1055 void wxBaseEnumProperty::SetIndex( int index
)
1061 int wxBaseEnumProperty::GetIndex() const
1063 if ( ms_nextIndex
!= -2 )
1064 return ms_nextIndex
;
1068 // -----------------------------------------------------------------------
1070 // -----------------------------------------------------------------------
1072 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty
, wxPGProperty
)
1074 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty
,long,Choice
)
1076 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
** labels
,
1077 const long* values
, int value
) : wxBaseEnumProperty(label
,name
)
1083 m_choices
.Add(labels
,values
);
1085 if ( GetItemCount() )
1086 SetValue( (long)value
);
1090 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
** labels
,
1091 const long* values
, wxPGChoices
* choicesCache
, int value
)
1092 : wxBaseEnumProperty(label
,name
)
1096 wxASSERT( choicesCache
);
1098 if ( choicesCache
->IsOk() )
1100 m_choices
.Assign( *choicesCache
);
1101 m_value
= wxPGVariant_Zero
;
1105 m_choices
.Add(labels
,values
);
1107 if ( GetItemCount() )
1108 SetValue( (long)value
);
1112 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1113 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
) : wxBaseEnumProperty(label
,name
)
1117 if ( &labels
&& labels
.size() )
1119 m_choices
.Set(labels
, values
);
1121 if ( GetItemCount() )
1122 SetValue( (long)value
);
1126 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1127 wxPGChoices
& choices
, int value
)
1128 : wxBaseEnumProperty(label
,name
)
1130 m_choices
.Assign( choices
);
1132 if ( GetItemCount() )
1133 SetValue( (long)value
);
1136 int wxEnumProperty::GetIndexForValue( int value
) const
1138 if ( !m_choices
.IsOk() )
1141 if ( m_choices
.HasValues() )
1143 int intVal
= m_choices
.Index(value
);
1151 wxEnumProperty::~wxEnumProperty ()
1155 const wxString
* wxEnumProperty::GetEntry( size_t index
, int* pvalue
) const
1157 if ( m_choices
.IsOk() && index
< m_choices
.GetCount() )
1159 int value
= (int)index
;
1160 if ( m_choices
.HasValue(index
) )
1161 value
= m_choices
.GetValue(index
);
1166 return &m_choices
.GetLabel(index
);
1168 return (const wxString
*) NULL
;
1171 // -----------------------------------------------------------------------
1172 // wxEditEnumProperty
1173 // -----------------------------------------------------------------------
1175 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty
, wxPGProperty
)
1177 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty
,wxString
,ComboBox
)
1179 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
** labels
,
1180 const long* values
, const wxString
& value
)
1181 : wxEnumProperty(label
,name
,labels
,values
,0)
1186 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
** labels
,
1187 const long* values
, wxPGChoices
* choicesCache
, const wxString
& value
)
1188 : wxEnumProperty(label
,name
,labels
,values
,choicesCache
,0)
1193 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1194 const wxArrayString
& labels
, const wxArrayInt
& values
, const wxString
& value
)
1195 : wxEnumProperty(label
,name
,labels
,values
,0)
1200 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1201 wxPGChoices
& choices
, const wxString
& value
)
1202 : wxEnumProperty(label
,name
,choices
,0)
1207 wxEditEnumProperty::~wxEditEnumProperty()
1211 // -----------------------------------------------------------------------
1213 // -----------------------------------------------------------------------
1215 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty
,wxPGProperty
)
1217 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty
,long,TextCtrl
)
1219 void wxFlagsProperty::Init()
1221 SetParentalType(wxPG_PROP_AGGREGATE
);
1223 long value
= m_value
;
1226 // Generate children
1230 unsigned int prevChildCount
= m_children
.size();
1233 if ( prevChildCount
)
1235 wxPropertyGridPageState
* state
= GetParentState();
1237 // State safety check (it may be NULL in immediate parent)
1242 wxPGProperty
* selected
= state
->GetSelection();
1245 if ( selected
->GetParent() == this )
1246 oldSel
= selected
->GetIndexInParent();
1247 else if ( selected
== this )
1251 state
->DoClearSelection();
1254 // Delete old children
1255 for ( i
=0; i
<prevChildCount
; i
++ )
1256 delete m_children
[i
];
1260 if ( m_choices
.IsOk() )
1262 const wxPGChoices
& choices
= m_choices
;
1264 for ( i
=0; i
<GetItemCount(); i
++ )
1267 if ( choices
.HasValue(i
) )
1268 child_val
= ( value
& choices
.GetValue(i
) )?true:false;
1270 child_val
= ( value
& (1<<i
) )?true:false;
1272 wxPGProperty
* boolProp
;
1273 wxString label
= GetLabel(i
);
1276 if ( wxPGGlobalVars
->m_autoGetTranslation
)
1278 boolProp
= new wxBoolProperty( ::wxGetTranslation(label
), label
, child_val
);
1283 boolProp
= new wxBoolProperty( label
, label
, child_val
);
1288 m_oldChoicesData
= m_choices
.GetDataPtr();
1291 m_oldValue
= m_value
;
1293 if ( prevChildCount
)
1294 SubPropsChanged(oldSel
);
1297 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1298 const wxChar
** labels
, const long* values
, long value
) : wxPGProperty(label
,name
)
1300 m_oldChoicesData
= (wxPGChoicesData
*) NULL
;
1304 m_choices
.Set(labels
,values
);
1306 wxASSERT( GetItemCount() );
1312 m_value
= wxPGVariant_Zero
;
1316 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1317 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1318 : wxPGProperty(label
,name
)
1320 m_oldChoicesData
= (wxPGChoicesData
*) NULL
;
1322 if ( &labels
&& labels
.size() )
1324 m_choices
.Set(labels
,values
);
1326 wxASSERT( GetItemCount() );
1328 SetValue( (long)value
);
1332 m_value
= wxPGVariant_Zero
;
1336 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1337 wxPGChoices
& choices
, long value
)
1338 : wxPGProperty(label
,name
)
1340 m_oldChoicesData
= (wxPGChoicesData
*) NULL
;
1342 if ( choices
.IsOk() )
1344 m_choices
.Assign(choices
);
1346 wxASSERT( GetItemCount() );
1352 m_value
= wxPGVariant_Zero
;
1356 wxFlagsProperty::~wxFlagsProperty()
1360 void wxFlagsProperty::OnSetValue()
1362 if ( !m_choices
.IsOk() || !GetItemCount() )
1364 m_value
= wxPGVariant_Zero
;
1368 long val
= m_value
.GetLong();
1372 // normalize the value (i.e. remove extra flags)
1374 const wxPGChoices
& choices
= m_choices
;
1375 for ( i
= 0; i
< GetItemCount(); i
++ )
1377 if ( choices
.HasValue(i
) )
1378 fullFlags
|= choices
.GetValue(i
);
1380 fullFlags
|= (1<<i
);
1387 // Need to (re)init now?
1388 if ( GetChildCount() != GetItemCount() ||
1389 m_choices
.GetDataPtr() != m_oldChoicesData
)
1395 long newFlags
= m_value
;
1397 if ( newFlags
!= m_oldValue
)
1399 // Set child modified states
1401 const wxPGChoices
& choices
= m_choices
;
1402 for ( i
= 0; i
<GetItemCount(); i
++ )
1406 if ( choices
.HasValue(i
) )
1407 flag
= choices
.GetValue(i
);
1411 if ( (newFlags
& flag
) != (m_oldValue
& flag
) )
1412 Item(i
)->SetFlag( wxPG_PROP_MODIFIED
);
1415 m_oldValue
= newFlags
;
1419 wxString
wxFlagsProperty::ValueToString( wxVariant
& value
,
1420 int WXUNUSED(argFlags
) ) const
1424 if ( !m_choices
.IsOk() )
1429 const wxPGChoices
& choices
= m_choices
;
1431 for ( i
= 0; i
< GetItemCount(); i
++ )
1434 if ( choices
.HasValue(i
) )
1435 doAdd
= ( flags
& choices
.GetValue(i
) );
1437 doAdd
= ( flags
& (1<<i
) );
1441 text
+= choices
.GetLabel(i
);
1446 // remove last comma
1447 if ( text
.Len() > 1 )
1448 text
.Truncate ( text
.Len() - 2 );
1453 // Translate string into flag tokens
1454 bool wxFlagsProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1456 if ( !m_choices
.IsOk() )
1461 // semicolons are no longer valid delimeters
1462 WX_PG_TOKENIZER1_BEGIN(text
,wxS(','))
1464 if ( token
.length() )
1466 // Determine which one it is
1467 long bit
= IdToBit( token
);
1480 WX_PG_TOKENIZER1_END()
1482 if ( variant
!= (long)newFlags
)
1484 variant
= (long)newFlags
;
1491 // Converts string id to a relevant bit.
1492 long wxFlagsProperty::IdToBit( const wxString
& id
) const
1495 for ( i
= 0; i
< GetItemCount(); i
++ )
1497 if ( id
== GetLabel(i
) )
1499 if ( m_choices
.HasValue(i
) )
1500 return m_choices
.GetValue(i
);
1507 void wxFlagsProperty::RefreshChildren()
1509 if ( !m_choices
.IsOk() || !GetChildCount() ) return;
1511 int flags
= m_value
.GetLong();
1513 const wxPGChoices
& choices
= m_choices
;
1515 for ( i
= 0; i
< GetItemCount(); i
++ )
1519 if ( choices
.HasValue(i
) )
1520 flag
= choices
.GetValue(i
);
1524 long subVal
= flags
& flag
;
1525 wxPGProperty
* p
= Item(i
);
1527 if ( subVal
!= (m_oldValue
& flag
) )
1528 p
->SetFlag( wxPG_PROP_MODIFIED
);
1530 p
->SetValue( subVal
?true:false );
1536 void wxFlagsProperty::ChildChanged( wxVariant
& thisValue
, int childIndex
, wxVariant
& childValue
) const
1538 long oldValue
= thisValue
.GetLong();
1539 long val
= childValue
.GetLong();
1540 unsigned long vi
= (1<<childIndex
);
1541 if ( m_choices
.HasValue(childIndex
) ) vi
= m_choices
.GetValue(childIndex
);
1543 thisValue
= (long)(oldValue
| vi
);
1545 thisValue
= (long)(oldValue
& ~(vi
));
1548 // -----------------------------------------------------------------------
1550 // -----------------------------------------------------------------------
1552 IMPLEMENT_DYNAMIC_CLASS(wxDirProperty
, wxLongStringProperty
)
1554 wxDirProperty::wxDirProperty( const wxString
& name
, const wxString
& label
, const wxString
& value
)
1555 : wxLongStringProperty(name
,label
,value
)
1557 m_flags
|= wxPG_PROP_NO_ESCAPE
;
1560 wxDirProperty::~wxDirProperty() { }
1562 wxValidator
* wxDirProperty::DoGetValidator() const
1564 return wxFileProperty::GetClassValidator();
1567 bool wxDirProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1569 // Update property value from editor, if necessary
1570 wxSize
dlg_sz(300,400);
1572 wxString
dlgMessage(m_dlgMessage
);
1573 if ( dlgMessage
.empty() )
1574 dlgMessage
= _("Choose a directory:");
1575 wxDirDialog
dlg( propGrid
,
1579 #if !wxPG_SMALL_SCREEN
1580 propGrid
->GetGoodEditorDialogPosition(this,dlg_sz
),
1588 if ( dlg
.ShowModal() == wxID_OK
)
1590 value
= dlg
.GetPath();
1596 bool wxDirProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1598 if ( name
== wxPG_DIR_DIALOG_MESSAGE
)
1600 m_dlgMessage
= value
.GetString();
1606 // -----------------------------------------------------------------------
1607 // wxPGFileDialogAdapter
1608 // -----------------------------------------------------------------------
1610 bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1612 wxFileProperty
* fileProp
= NULL
;
1616 if ( property
->IsKindOf(CLASSINFO(wxFileProperty
)) )
1618 fileProp
= ((wxFileProperty
*)property
);
1619 wxFileName filename
= fileProp
->GetValue().GetString();
1620 path
= filename
.GetPath();
1621 indFilter
= fileProp
->m_indFilter
;
1623 if ( !path
.length() && fileProp
->m_basePath
.length() )
1624 path
= fileProp
->m_basePath
;
1628 wxFileName
fn(property
->GetValue().GetString());
1629 path
= fn
.GetPath();
1632 wxFileDialog
dlg( propGrid
->GetPanel(),
1633 property
->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1634 property
->GetAttribute(wxS("InitialPath"), path
),
1636 property
->GetAttribute(wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*")),
1638 wxDefaultPosition
);
1640 if ( indFilter
>= 0 )
1641 dlg
.SetFilterIndex( indFilter
);
1643 if ( dlg
.ShowModal() == wxID_OK
)
1646 fileProp
->m_indFilter
= dlg
.GetFilterIndex();
1647 SetValue( dlg
.GetPath() );
1653 // -----------------------------------------------------------------------
1655 // -----------------------------------------------------------------------
1657 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty
,wxPGProperty
,
1658 wxString
,const wxString
&,TextCtrlAndButton
)
1660 wxFileProperty::wxFileProperty( const wxString
& label
, const wxString
& name
,
1661 const wxString
& value
) : wxPGProperty(label
,name
)
1663 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1665 SetAttribute( wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*") );
1670 wxFileProperty::~wxFileProperty() {}
1672 #if wxUSE_VALIDATORS
1674 wxValidator
* wxFileProperty::GetClassValidator()
1676 WX_PG_DOGETVALIDATOR_ENTRY()
1678 // Atleast wxPython 2.6.2.1 required that the string argument is given
1680 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST
,&v
);
1682 wxArrayString exChars
;
1683 exChars
.Add(wxS("?"));
1684 exChars
.Add(wxS("*"));
1685 exChars
.Add(wxS("|"));
1686 exChars
.Add(wxS("<"));
1687 exChars
.Add(wxS(">"));
1688 exChars
.Add(wxS("\""));
1690 validator
->SetExcludes(exChars
);
1692 WX_PG_DOGETVALIDATOR_EXIT(validator
)
1695 wxValidator
* wxFileProperty::DoGetValidator() const
1697 return GetClassValidator();
1702 void wxFileProperty::OnSetValue()
1704 const wxString
& fnstr
= m_value
.GetString();
1706 wxFileName filename
= fnstr
;
1708 if ( !filename
.HasName() )
1710 m_value
= wxPGVariant_EmptyString
;
1713 // Find index for extension.
1714 if ( m_indFilter
< 0 && fnstr
.length() )
1716 wxString ext
= filename
.GetExt();
1719 size_t len
= m_wildcard
.length();
1721 pos
= m_wildcard
.find(wxS("|"), pos
);
1722 while ( pos
!= wxString::npos
&& pos
< (len
-3) )
1724 size_t ext_begin
= pos
+ 3;
1726 pos
= m_wildcard
.find(wxS("|"), ext_begin
);
1727 if ( pos
== wxString::npos
)
1729 wxString found_ext
= m_wildcard
.substr(ext_begin
, pos
-ext_begin
);
1731 if ( found_ext
.length() > 0 )
1733 if ( found_ext
[0] == wxS('*') )
1735 m_indFilter
= curind
;
1738 if ( ext
.CmpNoCase(found_ext
) == 0 )
1740 m_indFilter
= curind
;
1746 pos
= m_wildcard
.find(wxS("|"), pos
+1);
1753 wxFileName
wxFileProperty::GetFileName() const
1755 wxFileName filename
;
1757 if ( !m_value
.IsNull() )
1758 filename
= m_value
.GetString();
1763 wxString
wxFileProperty::ValueToString( wxVariant
& value
,
1764 int argFlags
) const
1766 wxFileName filename
= value
.GetString();
1768 if ( !filename
.HasName() )
1769 return wxEmptyString
;
1771 wxString fullName
= filename
.GetFullName();
1772 if ( !fullName
.length() )
1773 return wxEmptyString
;
1775 if ( argFlags
& wxPG_FULL_VALUE
)
1777 return filename
.GetFullPath();
1779 else if ( m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
)
1781 if ( m_basePath
.Length() )
1783 wxFileName
fn2(filename
);
1784 fn2
.MakeRelativeTo(m_basePath
);
1785 return fn2
.GetFullPath();
1787 return filename
.GetFullPath();
1790 return filename
.GetFullName();
1793 wxPGEditorDialogAdapter
* wxFileProperty::GetEditorDialog() const
1795 return new wxPGFileDialogAdapter();
1798 bool wxFileProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1800 wxFileName filename
= variant
.GetString();
1802 if ( (m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
) || (argFlags
& wxPG_FULL_VALUE
) )
1804 if ( filename
!= text
)
1812 if ( filename
.GetFullName() != text
)
1814 wxFileName fn
= filename
;
1815 fn
.SetFullName(text
);
1816 variant
= fn
.GetFullPath();
1824 bool wxFileProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1826 // Return false on some occasions to make sure those attribs will get
1827 // stored in m_attributes.
1828 if ( name
== wxPG_FILE_SHOW_FULL_PATH
)
1830 if ( wxPGVariantToInt(value
) )
1831 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1833 m_flags
&= ~(wxPG_PROP_SHOW_FULL_FILENAME
);
1836 else if ( name
== wxPG_FILE_WILDCARD
)
1838 m_wildcard
= value
.GetString();
1840 else if ( name
== wxPG_FILE_SHOW_RELATIVE_PATH
)
1842 m_basePath
= value
.GetString();
1844 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1845 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1847 else if ( name
== wxPG_FILE_INITIAL_PATH
)
1849 m_initialPath
= value
.GetString();
1852 else if ( name
== wxPG_FILE_DIALOG_TITLE
)
1854 m_dlgTitle
= value
.GetString();
1860 // -----------------------------------------------------------------------
1861 // wxPGLongStringDialogAdapter
1862 // -----------------------------------------------------------------------
1864 bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1866 wxString val1
= property
->GetValueAsString(0);
1867 wxString val_orig
= val1
;
1870 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1871 wxPropertyGrid::ExpandEscapeSequences(value
, val1
);
1873 value
= wxString(val1
);
1875 // Run editor dialog.
1876 if ( wxLongStringProperty::DisplayEditorDialog(property
, propGrid
, value
) )
1878 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1879 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1883 if ( val1
!= val_orig
)
1892 // -----------------------------------------------------------------------
1893 // wxLongStringProperty
1894 // -----------------------------------------------------------------------
1896 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty
,wxPGProperty
,
1897 wxString
,const wxString
&,TextCtrlAndButton
)
1899 wxLongStringProperty::wxLongStringProperty( const wxString
& label
, const wxString
& name
,
1900 const wxString
& value
) : wxPGProperty(label
,name
)
1905 wxLongStringProperty::~wxLongStringProperty() {}
1907 wxString
wxLongStringProperty::ValueToString( wxVariant
& value
,
1908 int WXUNUSED(argFlags
) ) const
1913 bool wxLongStringProperty::OnEvent( wxPropertyGrid
* propGrid
, wxWindow
* WXUNUSED(primary
),
1916 if ( propGrid
->IsMainButtonEvent(event
) )
1919 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
1921 wxString val1
= useValue
.GetString();
1922 wxString val_orig
= val1
;
1925 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1926 wxPropertyGrid::ExpandEscapeSequences(value
,val1
);
1928 value
= wxString(val1
);
1930 // Run editor dialog.
1931 if ( OnButtonClick(propGrid
,value
) )
1933 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1934 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1938 if ( val1
!= val_orig
)
1940 SetValueInEvent( val1
);
1948 bool wxLongStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1950 return DisplayEditorDialog(this, propGrid
, value
);
1953 bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty
* prop
, wxPropertyGrid
* propGrid
, wxString
& value
)
1956 // launch editor dialog
1957 wxDialog
* dlg
= new wxDialog(propGrid
,-1,prop
->GetLabel(),wxDefaultPosition
,wxDefaultSize
,
1958 wxDEFAULT_DIALOG_STYLE
|wxRESIZE_BORDER
|wxCLIP_CHILDREN
);
1960 dlg
->SetFont(propGrid
->GetFont()); // To allow entering chars of the same set as the propGrid
1962 // Multi-line text editor dialog.
1963 #if !wxPG_SMALL_SCREEN
1964 const int spacing
= 8;
1966 const int spacing
= 4;
1968 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
1969 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
1970 wxTextCtrl
* ed
= new wxTextCtrl(dlg
,11,value
,
1971 wxDefaultPosition
,wxDefaultSize
,wxTE_MULTILINE
);
1973 rowsizer
->Add( ed
, 1, wxEXPAND
|wxALL
, spacing
);
1974 topsizer
->Add( rowsizer
, 1, wxEXPAND
, 0 );
1975 rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
1976 const int but_sz_flags
=
1977 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxBOTTOM
|wxLEFT
|wxRIGHT
;
1978 rowsizer
->Add( new wxButton(dlg
,wxID_OK
,_("Ok")),
1979 0, but_sz_flags
, spacing
);
1980 rowsizer
->Add( new wxButton(dlg
,wxID_CANCEL
,_("Cancel")),
1981 0, but_sz_flags
, spacing
);
1982 topsizer
->Add( rowsizer
, 0, wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
, 0 );
1984 dlg
->SetSizer( topsizer
);
1985 topsizer
->SetSizeHints( dlg
);
1987 #if !wxPG_SMALL_SCREEN
1988 dlg
->SetSize(400,300);
1990 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(prop
,dlg
->GetSize()) );
1993 int res
= dlg
->ShowModal();
1995 if ( res
== wxID_OK
)
1997 value
= ed
->GetValue();
2005 bool wxLongStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
2007 if ( variant
!= text
)
2015 // -----------------------------------------------------------------------
2016 // wxArrayEditorDialog
2017 // -----------------------------------------------------------------------
2019 BEGIN_EVENT_TABLE(wxArrayEditorDialog
, wxDialog
)
2020 EVT_IDLE(wxArrayEditorDialog::OnIdle
)
2021 EVT_LISTBOX(24, wxArrayEditorDialog::OnListBoxClick
)
2022 EVT_TEXT_ENTER(21, wxArrayEditorDialog::OnAddClick
)
2023 EVT_BUTTON(22, wxArrayEditorDialog::OnAddClick
)
2024 EVT_BUTTON(23, wxArrayEditorDialog::OnDeleteClick
)
2025 EVT_BUTTON(25, wxArrayEditorDialog::OnUpClick
)
2026 EVT_BUTTON(26, wxArrayEditorDialog::OnDownClick
)
2027 EVT_BUTTON(27, wxArrayEditorDialog::OnUpdateClick
)
2028 //EVT_BUTTON(28, wxArrayEditorDialog::OnCustomEditClick)
2031 IMPLEMENT_ABSTRACT_CLASS(wxArrayEditorDialog
, wxDialog
)
2033 #include "wx/statline.h"
2035 // -----------------------------------------------------------------------
2037 void wxArrayEditorDialog::OnIdle(wxIdleEvent
& event
)
2040 // Do control focus detection here.
2043 wxWindow
* focused
= FindFocus();
2045 // This strange focus thing is a workaround for wxGTK wxListBox focus
2047 if ( m_curFocus
== 0 && focused
!= m_edValue
&&
2048 focused
!= m_butAdd
&& focused
!= m_butUpdate
&&
2049 m_lbStrings
->GetSelection() >= 0 )
2051 // ListBox was just focused.
2052 m_butAdd
->Enable(false);
2053 m_butUpdate
->Enable(false);
2054 m_butRemove
->Enable(true);
2055 m_butUp
->Enable(true);
2056 m_butDown
->Enable(true);
2059 else if ( (m_curFocus
== 1 && focused
== m_edValue
) /*|| m_curFocus == 2*/ )
2061 // TextCtrl was just focused.
2062 m_butAdd
->Enable(true);
2063 bool upd_enable
= false;
2064 if ( m_lbStrings
->GetCount() && m_lbStrings
->GetSelection() >= 0 )
2066 m_butUpdate
->Enable(upd_enable
);
2067 m_butRemove
->Enable(false);
2068 m_butUp
->Enable(false);
2069 m_butDown
->Enable(false);
2076 // -----------------------------------------------------------------------
2078 wxArrayEditorDialog::wxArrayEditorDialog()
2084 // -----------------------------------------------------------------------
2086 void wxArrayEditorDialog::Init()
2088 m_custBtText
= (const wxChar
*) NULL
;
2091 // -----------------------------------------------------------------------
2093 wxArrayEditorDialog::wxArrayEditorDialog( wxWindow
*parent
,
2094 const wxString
& message
,
2095 const wxString
& caption
,
2102 Create(parent
,message
,caption
,style
,pos
,sz
);
2105 // -----------------------------------------------------------------------
2107 bool wxArrayEditorDialog::Create( wxWindow
*parent
,
2108 const wxString
& message
,
2109 const wxString
& caption
,
2114 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2115 // FIXME: This should be only a temporary fix.
2117 int useStyle
= wxCAPTION
;
2119 int useStyle
= style
;
2122 bool res
= wxDialog::Create(parent
, wxID_ANY
, caption
, pos
, sz
, useStyle
);
2124 SetFont(parent
->GetFont()); // To allow entering chars of the same set as the propGrid
2126 #if !wxPG_SMALL_SCREEN
2127 const int spacing
= 4;
2129 const int spacing
= 3;
2136 const int but_sz_flags
=
2137 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxALL
; //wxBOTTOM|wxLEFT|wxRIGHT;
2139 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2142 if ( message
.length() )
2143 topsizer
->Add( new wxStaticText(this,-1,message
),
2144 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2147 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2148 m_edValue
= new wxTextCtrl(this,21,wxEmptyString
,
2149 wxDefaultPosition
,wxDefaultSize
,wxTE_PROCESS_ENTER
);
2150 wxValidator
* validator
= GetTextCtrlValidator();
2153 m_edValue
->SetValidator( *validator
);
2156 rowsizer
->Add( m_edValue
,
2157 1, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2160 m_butAdd
= new wxButton(this,22,_("Add"));
2161 rowsizer
->Add( m_butAdd
,
2162 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxTOP
|wxBOTTOM
|wxRIGHT
, spacing
);
2163 topsizer
->Add( rowsizer
, 0, wxEXPAND
, spacing
);
2166 topsizer
->Add( new wxStaticLine(this,-1),
2167 0, wxEXPAND
|wxBOTTOM
|wxLEFT
|wxRIGHT
, spacing
);
2169 rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2172 m_lbStrings
= new wxListBox(this, 24, wxDefaultPosition
, wxDefaultSize
);
2174 for ( i
=0; i
<ArrayGetCount(); i
++ )
2175 m_lbStrings
->Append( ArrayGet(i
) );
2176 rowsizer
->Add( m_lbStrings
, 1, wxEXPAND
|wxRIGHT
, spacing
);
2178 // Manipulator buttons
2179 wxBoxSizer
* colsizer
= new wxBoxSizer( wxVERTICAL
);
2180 m_butCustom
= (wxButton
*) NULL
;
2183 m_butCustom
= new wxButton(this,28,::wxGetTranslation(m_custBtText
));
2184 colsizer
->Add( m_butCustom
,
2185 0, wxALIGN_CENTER
|wxTOP
/*wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT*/,
2188 m_butUpdate
= new wxButton(this,27,_("Update"));
2189 colsizer
->Add( m_butUpdate
,
2190 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2191 m_butRemove
= new wxButton(this,23,_("Remove"));
2192 colsizer
->Add( m_butRemove
,
2193 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2194 m_butUp
= new wxButton(this,25,_("Up"));
2195 colsizer
->Add( m_butUp
,
2196 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2197 m_butDown
= new wxButton(this,26,_("Down"));
2198 colsizer
->Add( m_butDown
,
2199 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2200 rowsizer
->Add( colsizer
, 0, 0, spacing
);
2202 topsizer
->Add( rowsizer
, 1, wxLEFT
|wxRIGHT
|wxEXPAND
, spacing
);
2205 topsizer
->Add( new wxStaticLine(this,-1),
2206 0, wxEXPAND
|wxTOP
|wxLEFT
|wxRIGHT
, spacing
);
2209 rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2211 const int but_sz_flags =
2212 wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT;
2214 rowsizer
->Add( new wxButton(this,wxID_OK
,_("Ok")),
2215 0, but_sz_flags
, spacing
);
2216 rowsizer
->Add( new wxButton(this,wxID_CANCEL
,_("Cancel")),
2217 0, but_sz_flags
, spacing
);
2218 topsizer
->Add( rowsizer
, 0, wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
, 0 );
2220 m_edValue
->SetFocus();
2222 SetSizer( topsizer
);
2223 topsizer
->SetSizeHints( this );
2225 #if !wxPG_SMALL_SCREEN
2226 if ( sz
.x
== wxDefaultSize
.x
&&
2227 sz
.y
== wxDefaultSize
.y
)
2228 SetSize( wxSize(275,360) );
2236 // -----------------------------------------------------------------------
2238 void wxArrayEditorDialog::OnAddClick(wxCommandEvent
& )
2240 wxString text
= m_edValue
->GetValue();
2241 if ( text
.length() )
2243 if ( ArrayInsert( text
, -1 ) )
2245 m_lbStrings
->Append( text
);
2252 // -----------------------------------------------------------------------
2254 void wxArrayEditorDialog::OnDeleteClick(wxCommandEvent
& )
2256 int index
= m_lbStrings
->GetSelection();
2259 ArrayRemoveAt( index
);
2260 m_lbStrings
->Delete ( index
);
2265 // -----------------------------------------------------------------------
2267 void wxArrayEditorDialog::OnUpClick(wxCommandEvent
& )
2269 int index
= m_lbStrings
->GetSelection();
2272 ArraySwap(index
-1,index
);
2273 /*wxString old_str = m_array[index-1];
2274 wxString new_str = m_array[index];
2275 m_array[index-1] = new_str;
2276 m_array[index] = old_str;*/
2277 m_lbStrings
->SetString ( index
-1, ArrayGet(index
-1) );
2278 m_lbStrings
->SetString ( index
, ArrayGet(index
) );
2279 m_lbStrings
->SetSelection ( index
-1 );
2284 // -----------------------------------------------------------------------
2286 void wxArrayEditorDialog::OnDownClick(wxCommandEvent
& )
2288 int index
= m_lbStrings
->GetSelection();
2289 int lastStringIndex
= ((int) m_lbStrings
->GetCount()) - 1;
2290 if ( index
>= 0 && index
< lastStringIndex
)
2292 ArraySwap(index
,index
+1);
2293 /*wxString old_str = m_array[index+1];
2294 wxString new_str = m_array[index];
2295 m_array[index+1] = new_str;
2296 m_array[index] = old_str;*/
2297 m_lbStrings
->SetString ( index
+1, ArrayGet(index
+1) );
2298 m_lbStrings
->SetString ( index
, ArrayGet(index
) );
2299 m_lbStrings
->SetSelection ( index
+1 );
2304 // -----------------------------------------------------------------------
2306 void wxArrayEditorDialog::OnUpdateClick(wxCommandEvent
& )
2308 int index
= m_lbStrings
->GetSelection();
2311 wxString str
= m_edValue
->GetValue();
2312 if ( ArraySet(index
,str
) )
2314 m_lbStrings
->SetString ( index
, str
);
2315 //m_array[index] = str;
2321 // -----------------------------------------------------------------------
2323 void wxArrayEditorDialog::OnListBoxClick(wxCommandEvent
& )
2325 int index
= m_lbStrings
->GetSelection();
2328 m_edValue
->SetValue( m_lbStrings
->GetString(index
) );
2332 // -----------------------------------------------------------------------
2333 // wxPGArrayStringEditorDialog
2334 // -----------------------------------------------------------------------
2336 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog
, wxArrayEditorDialog
)
2338 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog
, wxArrayEditorDialog
)
2339 EVT_BUTTON(28, wxPGArrayStringEditorDialog::OnCustomEditClick
)
2342 // -----------------------------------------------------------------------
2344 wxString
wxPGArrayStringEditorDialog::ArrayGet( size_t index
)
2346 return m_array
[index
];
2349 size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2351 return m_array
.size();
2354 bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString
& str
, int index
)
2359 m_array
.Insert(str
,index
);
2363 bool wxPGArrayStringEditorDialog::ArraySet( size_t index
, const wxString
& str
)
2365 m_array
[index
] = str
;
2369 void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index
)
2371 m_array
.RemoveAt(index
);
2374 void wxPGArrayStringEditorDialog::ArraySwap( size_t first
, size_t second
)
2376 wxString old_str
= m_array
[first
];
2377 wxString new_str
= m_array
[second
];
2378 m_array
[first
] = new_str
;
2379 m_array
[second
] = old_str
;
2382 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2383 : wxArrayEditorDialog()
2388 void wxPGArrayStringEditorDialog::Init()
2390 m_pCallingClass
= (wxArrayStringProperty
*) NULL
;
2393 void wxPGArrayStringEditorDialog::OnCustomEditClick(wxCommandEvent
& )
2395 wxASSERT( m_pCallingClass
);
2396 wxString str
= m_edValue
->GetValue();
2397 if ( m_pCallingClass
->OnCustomStringEdit(m_parent
,str
) )
2399 //m_edValue->SetValue ( str );
2400 m_lbStrings
->Append ( str
);
2401 m_array
.Add ( str
);
2406 // -----------------------------------------------------------------------
2407 // wxArrayStringProperty
2408 // -----------------------------------------------------------------------
2410 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty
, // Property name
2411 wxPGProperty
, // Property we inherit from
2412 wxArrayString
, // Value type name
2413 const wxArrayString
&, // Value type, as given in constructor
2414 TextCtrlAndButton
) // Initial editor
2416 wxArrayStringProperty::wxArrayStringProperty( const wxString
& label
,
2417 const wxString
& name
,
2418 const wxArrayString
& array
)
2419 : wxPGProperty(label
,name
)
2424 wxArrayStringProperty::~wxArrayStringProperty() { }
2426 void wxArrayStringProperty::OnSetValue()
2428 GenerateValueAsString();
2431 #define ARRSTRPROP_ARRAY_TO_STRING(STRING,ARRAY) \
2432 wxPropertyGrid::ArrayStringToString(STRING,ARRAY,wxS('"'),wxS('"'),1)
2434 wxString
wxArrayStringProperty::ValueToString( wxVariant
& WXUNUSED(value
),
2435 int argFlags
) const
2438 // If this is called from GetValueAsString(), return cached string
2439 if ( argFlags
& wxPG_VALUE_IS_CURRENT
)
2444 wxArrayString arr
= m_value
.GetArrayString();
2446 ARRSTRPROP_ARRAY_TO_STRING(s
, arr
);
2450 // Converts wxArrayString to a string separated by delimeters and spaces.
2451 // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2453 void wxPropertyGrid::ArrayStringToString( wxString
& dst
, const wxArrayString
& src
,
2454 wxChar preDelim
, wxChar postDelim
,
2460 unsigned int itemCount
= src
.size();
2468 else if ( (flags
& 1) )
2470 preas
[0] = preDelim
;
2477 dst
.append( preas
);
2479 wxASSERT( postDelim
);
2480 wxString
postDelimStr(postDelim
);
2481 //wxString preDelimStr(preDelim);
2483 for ( i
= 0; i
< itemCount
; i
++ )
2485 wxString
str( src
.Item(i
) );
2487 // Do some character conversion.
2488 // Convertes \ to \\ and <preDelim> to \<preDelim>
2489 // Useful when preDelim and postDelim are "\"".
2492 str
.Replace( wxS("\\"), wxS("\\\\"), true );
2494 str
.Replace( preas
, pdr
, true );
2499 if ( i
< (itemCount
-1) )
2501 dst
.append( postDelimStr
);
2502 dst
.append( wxS(" ") );
2503 dst
.append( preas
);
2505 else if ( preDelim
)
2506 dst
.append( postDelimStr
);
2510 void wxArrayStringProperty::GenerateValueAsString()
2512 wxArrayString arr
= m_value
.GetArrayString();
2513 ARRSTRPROP_ARRAY_TO_STRING(m_display
, arr
);
2516 // Default implementation doesn't do anything.
2517 bool wxArrayStringProperty::OnCustomStringEdit( wxWindow
*, wxString
& )
2522 wxArrayEditorDialog
* wxArrayStringProperty::CreateEditorDialog()
2524 return new wxPGArrayStringEditorDialog();
2527 bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
,
2528 wxWindow
* WXUNUSED(primaryCtrl
),
2532 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
2534 if ( !propGrid
->EditorValidate() )
2537 // Create editor dialog.
2538 wxArrayEditorDialog
* dlg
= CreateEditorDialog();
2539 #if wxUSE_VALIDATORS
2540 wxValidator
* validator
= GetValidator();
2541 wxPGInDialogValidator dialogValidator
;
2544 wxPGArrayStringEditorDialog
* strEdDlg
= wxDynamicCast(dlg
, wxPGArrayStringEditorDialog
);
2547 strEdDlg
->SetCustomButton(cbt
, this);
2549 dlg
->SetDialogValue( useValue
);
2550 dlg
->Create(propGrid
, wxEmptyString
, m_label
);
2552 #if !wxPG_SMALL_SCREEN
2553 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(this,dlg
->GetSize()) );
2562 int res
= dlg
->ShowModal();
2564 if ( res
== wxID_OK
&& dlg
->IsModified() )
2566 wxVariant value
= dlg
->GetDialogValue();
2567 if ( !value
.IsNull() )
2569 wxArrayString actualValue
= value
.GetArrayString();
2571 ARRSTRPROP_ARRAY_TO_STRING(tempStr
, actualValue
);
2572 #if wxUSE_VALIDATORS
2573 if ( dialogValidator
.DoValidate( propGrid
, validator
, tempStr
) )
2576 SetValueInEvent( actualValue
);
2593 bool wxArrayStringProperty::OnEvent( wxPropertyGrid
* propGrid
,
2597 if ( propGrid
->IsMainButtonEvent(event
) )
2598 return OnButtonClick(propGrid
,primary
,(const wxChar
*) NULL
);
2602 bool wxArrayStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
2606 WX_PG_TOKENIZER2_BEGIN(text
,wxS('"'))
2608 // Need to replace backslashes with empty characters
2609 // (opposite what is done in GenerateValueString).
2610 token
.Replace ( wxS("\\"), wxEmptyString
, true );
2614 WX_PG_TOKENIZER2_END()
2621 // -----------------------------------------------------------------------
2622 // wxPGInDialogValidator
2623 // -----------------------------------------------------------------------
2625 #if wxUSE_VALIDATORS
2626 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* propGrid
,
2627 wxValidator
* validator
,
2628 const wxString
& value
)
2633 wxTextCtrl
* tc
= m_textCtrl
;
2638 tc
= new wxTextCtrl( propGrid
, wxPG_SUBID_TEMP1
, wxEmptyString
,
2639 wxPoint(30000,30000));
2646 tc
->SetValue(value
);
2648 validator
->SetWindow(tc
);
2649 bool res
= validator
->Validate(propGrid
);
2654 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* WXUNUSED(propGrid
),
2655 wxValidator
* WXUNUSED(validator
),
2656 const wxString
& WXUNUSED(value
) )
2662 // -----------------------------------------------------------------------
2664 #endif // wxUSE_PROPGRID