]> git.saurik.com Git - wxWidgets.git/blob - src/propgrid/props.cpp
Don't reset bullet number and outline number when applying style sheet.
[wxWidgets.git] / src / propgrid / props.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/props.cpp
3 // Purpose: Basic Property Classes
4 // Author: Jaakko Salli
5 // Modified by:
6 // Created: 2005-05-14
7 // RCS-ID: $Id$
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_PROPGRID
20
21 #ifndef WX_PRECOMP
22 #include "wx/defs.h"
23 #include "wx/object.h"
24 #include "wx/hash.h"
25 #include "wx/string.h"
26 #include "wx/log.h"
27 #include "wx/event.h"
28 #include "wx/window.h"
29 #include "wx/panel.h"
30 #include "wx/dc.h"
31 #include "wx/dcclient.h"
32 #include "wx/dcmemory.h"
33 #include "wx/button.h"
34 #include "wx/bmpbuttn.h"
35 #include "wx/pen.h"
36 #include "wx/brush.h"
37 #include "wx/cursor.h"
38 #include "wx/dialog.h"
39 #include "wx/settings.h"
40 #include "wx/msgdlg.h"
41 #include "wx/choice.h"
42 #include "wx/stattext.h"
43 #include "wx/scrolwin.h"
44 #include "wx/dirdlg.h"
45 #include "wx/combobox.h"
46 #include "wx/layout.h"
47 #include "wx/sizer.h"
48 #include "wx/textdlg.h"
49 #include "wx/filedlg.h"
50 #include "wx/intl.h"
51 #endif
52
53 #include "wx/filename.h"
54
55 #include "wx/propgrid/propgrid.h"
56
57 #define wxPG_CUSTOM_IMAGE_WIDTH 20 // for wxColourProperty etc.
58
59
60 // -----------------------------------------------------------------------
61 // wxStringProperty
62 // -----------------------------------------------------------------------
63
64 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxStringProperty,wxPGProperty,
65 wxString,const wxString&,TextCtrl)
66
67 wxStringProperty::wxStringProperty( const wxString& label,
68 const wxString& name,
69 const wxString& value )
70 : wxPGProperty(label,name)
71 {
72 SetValue(value);
73 }
74
75 void wxStringProperty::OnSetValue()
76 {
77 if ( !m_value.IsNull() && m_value.GetString() == wxS("<composed>") )
78 SetFlag(wxPG_PROP_COMPOSED_VALUE);
79
80 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE) )
81 {
82 wxString s;
83 DoGenerateComposedValue(s);
84 m_value = s;
85 }
86 }
87
88 wxStringProperty::~wxStringProperty() { }
89
90 wxString wxStringProperty::ValueToString( wxVariant& value,
91 int argFlags ) const
92 {
93 wxString s = value.GetString();
94
95 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE) )
96 {
97 // Value stored in m_value is non-editable, non-full value
98 if ( (argFlags & wxPG_FULL_VALUE) || (argFlags & wxPG_EDITABLE_VALUE) )
99 {
100 // Calling this under incorrect conditions will fail
101 wxASSERT_MSG( argFlags & wxPG_VALUE_IS_CURRENT,
102 "Sorry, currently default wxPGProperty::ValueToString() "
103 "implementation only works if value is m_value." );
104
105 DoGenerateComposedValue(s, argFlags);
106 }
107
108 return s;
109 }
110
111 // If string is password and value is for visual purposes,
112 // then return asterisks instead the actual string.
113 if ( (m_flags & wxPG_PROP_PASSWORD) && !(argFlags & (wxPG_FULL_VALUE|wxPG_EDITABLE_VALUE)) )
114 return wxString(wxChar('*'), s.Length());
115
116 return s;
117 }
118
119 bool wxStringProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
120 {
121 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE) )
122 return wxPGProperty::StringToValue(variant, text, argFlags);
123
124 if ( variant != text )
125 {
126 variant = text;
127 return true;
128 }
129
130 return false;
131 }
132
133 bool wxStringProperty::DoSetAttribute( const wxString& name, wxVariant& value )
134 {
135 if ( name == wxPG_STRING_PASSWORD )
136 {
137 m_flags &= ~(wxPG_PROP_PASSWORD);
138 if ( value.GetLong() ) m_flags |= wxPG_PROP_PASSWORD;
139 RecreateEditor();
140 return false;
141 }
142 return true;
143 }
144
145 // -----------------------------------------------------------------------
146 // wxIntProperty
147 // -----------------------------------------------------------------------
148
149 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty,wxPGProperty,
150 long,long,TextCtrl)
151
152 wxIntProperty::wxIntProperty( const wxString& label, const wxString& name,
153 long value ) : wxPGProperty(label,name)
154 {
155 SetValue(value);
156 }
157
158 wxIntProperty::wxIntProperty( const wxString& label, const wxString& name,
159 const wxLongLong& value ) : wxPGProperty(label,name)
160 {
161 SetValue(WXVARIANT(value));
162 }
163
164 wxIntProperty::~wxIntProperty() { }
165
166 wxString wxIntProperty::ValueToString( wxVariant& value,
167 int WXUNUSED(argFlags) ) const
168 {
169 if ( value.GetType() == wxPG_VARIANT_TYPE_LONG )
170 {
171 return wxString::Format(wxS("%li"),value.GetLong());
172 }
173 else if ( value.GetType() == wxPG_VARIANT_TYPE_LONGLONG )
174 {
175 wxLongLong ll = value.GetLongLong();
176 return ll.ToString();
177 }
178
179 return wxEmptyString;
180 }
181
182 bool wxIntProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
183 {
184 wxString s;
185 long value32;
186
187 if ( text.length() == 0 )
188 {
189 variant.MakeNull();
190 return true;
191 }
192
193 // We know it is a number, but let's still check
194 // the return value.
195 if ( text.IsNumber() )
196 {
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
200
201 int firstNonZeroPos = 0;
202
203 for ( ; i != iMax; ++i )
204 {
205 wxChar c = *i;
206 if ( c != wxS('0') && c != wxS(' ') )
207 break;
208 firstNonZeroPos++;
209 }
210
211 wxString useText = text.substr(firstNonZeroPos, text.length() - firstNonZeroPos);
212
213 wxString variantType = variant.GetType();
214 bool isPrevLong = variantType == wxPG_VARIANT_TYPE_LONG;
215
216 wxLongLong_t value64 = 0;
217
218 if ( useText.ToLongLong(&value64, 10) &&
219 ( value64 >= INT_MAX || value64 <= INT_MIN )
220 )
221 {
222 bool doChangeValue = isPrevLong;
223
224 if ( !isPrevLong && variantType == wxPG_VARIANT_TYPE_LONGLONG )
225 {
226 wxLongLong oldValue = variant.GetLongLong();
227 if ( oldValue.GetValue() != value64 )
228 doChangeValue = true;
229 }
230
231 if ( doChangeValue )
232 {
233 wxLongLong ll(value64);
234 variant = ll;
235 return true;
236 }
237 }
238
239 if ( useText.ToLong( &value32, 0 ) )
240 {
241 if ( !isPrevLong || variant != value32 )
242 {
243 variant = value32;
244 return true;
245 }
246 }
247 }
248 else if ( argFlags & wxPG_REPORT_ERROR )
249 {
250 }
251 return false;
252 }
253
254 bool wxIntProperty::IntToValue( wxVariant& variant, int value, int WXUNUSED(argFlags) ) const
255 {
256 if ( variant.GetType() != wxPG_VARIANT_TYPE_LONG || variant != (long)value )
257 {
258 variant = (long)value;
259 return true;
260 }
261 return false;
262 }
263
264 //
265 // Common validation code to be called in ValidateValue()
266 // implementations.
267 //
268 // Note that 'value' is reference on purpose, so we can write
269 // back to it when mode is wxPG_PROPERTY_VALIDATION_SATURATE.
270 //
271 template<typename T>
272 bool NumericValidation( const wxPGProperty* property,
273 T& value,
274 wxPGValidationInfo* pValidationInfo,
275 int mode,
276 const wxString& strFmt )
277 {
278 T min = (T) wxINT64_MIN;
279 T max = (T) wxINT64_MAX;
280 wxVariant variant;
281 bool minOk = false;
282 bool maxOk = false;
283
284 variant = property->GetAttribute(wxPGGlobalVars->m_strMin);
285 if ( !variant.IsNull() )
286 {
287 variant.Convert(&min);
288 minOk = true;
289 }
290
291 variant = property->GetAttribute(wxPGGlobalVars->m_strMax);
292 if ( !variant.IsNull() )
293 {
294 variant.Convert(&max);
295 maxOk = true;
296 }
297
298 if ( minOk )
299 {
300 if ( value < min )
301 {
302 if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE )
303 {
304 wxString msg;
305 wxString smin = wxString::Format(strFmt, min);
306 wxString smax = wxString::Format(strFmt, max);
307 if ( !maxOk )
308 msg = wxString::Format(
309 _("Value must be %s or higher."),
310 smin.c_str());
311 else
312 msg = wxString::Format(
313 _("Value must be between %s and %s."),
314 smin.c_str(), smax.c_str());
315 pValidationInfo->SetFailureMessage(msg);
316 }
317 else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE )
318 value = min;
319 else
320 value = max - (min - value);
321 return false;
322 }
323 }
324
325 if ( maxOk )
326 {
327 if ( value > max )
328 {
329 if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE )
330 {
331 wxString msg;
332 wxString smin = wxString::Format(strFmt, min);
333 wxString smax = wxString::Format(strFmt, max);
334 if ( !minOk )
335 msg = wxString::Format(
336 _("Value must be %s or less."),
337 smax.c_str());
338 else
339 msg = wxString::Format(
340 _("Value must be between %s and %s."),
341 smin.c_str(), smax.c_str());
342 pValidationInfo->SetFailureMessage(msg);
343 }
344 else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE )
345 value = max;
346 else
347 value = min + (value - max);
348 return false;
349 }
350 }
351 return true;
352 }
353
354 bool wxIntProperty::DoValidation( const wxPGProperty* property,
355 wxLongLong_t& value,
356 wxPGValidationInfo* pValidationInfo,
357 int mode )
358 {
359 return NumericValidation<wxLongLong_t>(property,
360 value,
361 pValidationInfo,
362 mode,
363 wxS("%lld"));
364 }
365
366 bool wxIntProperty::ValidateValue( wxVariant& value,
367 wxPGValidationInfo& validationInfo ) const
368 {
369 wxLongLong_t ll = value.GetLongLong().GetValue();
370 return DoValidation(this, ll, &validationInfo,
371 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE);
372 }
373
374 wxValidator* wxIntProperty::GetClassValidator()
375 {
376 #if wxUSE_VALIDATORS
377 WX_PG_DOGETVALIDATOR_ENTRY()
378
379 // Atleast wxPython 2.6.2.1 required that the string argument is given
380 static wxString v;
381 wxTextValidator* validator = new wxTextValidator(wxFILTER_NUMERIC,&v);
382
383 WX_PG_DOGETVALIDATOR_EXIT(validator)
384 #else
385 return NULL;
386 #endif
387 }
388
389 wxValidator* wxIntProperty::DoGetValidator() const
390 {
391 return GetClassValidator();
392 }
393
394 // -----------------------------------------------------------------------
395 // wxUIntProperty
396 // -----------------------------------------------------------------------
397
398
399 #define wxPG_UINT_TEMPLATE_MAX 8
400
401 static const wxChar* const gs_uintTemplates32[wxPG_UINT_TEMPLATE_MAX] = {
402 wxT("%x"),wxT("0x%x"),wxT("$%x"),
403 wxT("%X"),wxT("0x%X"),wxT("$%X"),
404 wxT("%u"),wxT("%o")
405 };
406
407 static const char* const gs_uintTemplates64[wxPG_UINT_TEMPLATE_MAX] = {
408 "%" wxLongLongFmtSpec "x",
409 "0x%" wxLongLongFmtSpec "x",
410 "$%" wxLongLongFmtSpec "x",
411 "%" wxLongLongFmtSpec "X",
412 "0x%" wxLongLongFmtSpec "X",
413 "$%" wxLongLongFmtSpec "X",
414 "%" wxLongLongFmtSpec "u",
415 "%" wxLongLongFmtSpec "o"
416 };
417
418 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty,wxPGProperty,
419 long,unsigned long,TextCtrl)
420
421 void wxUIntProperty::Init()
422 {
423 m_base = 6; // This is magic number for dec base (must be same as in setattribute)
424 m_realBase = 10;
425 m_prefix = wxPG_PREFIX_NONE;
426 }
427
428 wxUIntProperty::wxUIntProperty( const wxString& label, const wxString& name,
429 unsigned long value ) : wxPGProperty(label,name)
430 {
431 Init();
432 SetValue((long)value);
433 }
434
435 wxUIntProperty::wxUIntProperty( const wxString& label, const wxString& name,
436 const wxULongLong& value ) : wxPGProperty(label,name)
437 {
438 Init();
439 SetValue(WXVARIANT(value));
440 }
441
442 wxUIntProperty::~wxUIntProperty() { }
443
444 wxString wxUIntProperty::ValueToString( wxVariant& value,
445 int WXUNUSED(argFlags) ) const
446 {
447 size_t index = m_base + m_prefix;
448 if ( index >= wxPG_UINT_TEMPLATE_MAX )
449 index = wxPG_BASE_DEC;
450
451 if ( value.GetType() == wxPG_VARIANT_TYPE_LONG )
452 {
453 return wxString::Format(gs_uintTemplates32[index],
454 (unsigned long)value.GetLong());
455 }
456
457 wxULongLong ull = value.GetULongLong();
458
459 return wxString::Format(gs_uintTemplates64[index], ull.GetValue());
460 }
461
462 bool wxUIntProperty::StringToValue( wxVariant& variant, const wxString& text, int WXUNUSED(argFlags) ) const
463 {
464 wxString variantType = variant.GetType();
465 bool isPrevLong = variantType == wxPG_VARIANT_TYPE_LONG;
466
467 if ( text.length() == 0 )
468 {
469 variant.MakeNull();
470 return true;
471 }
472
473 size_t start = 0;
474 if ( text[0] == wxS('$') )
475 start++;
476
477 wxULongLong_t value64 = 0;
478 wxString s = text.substr(start, text.length() - start);
479
480 if ( s.ToULongLong(&value64, (unsigned int)m_realBase) )
481 {
482 if ( value64 >= LONG_MAX )
483 {
484 bool doChangeValue = isPrevLong;
485
486 if ( !isPrevLong && variantType == wxPG_VARIANT_TYPE_ULONGLONG )
487 {
488 wxULongLong oldValue = variant.GetULongLong();
489 if ( oldValue.GetValue() != value64 )
490 doChangeValue = true;
491 }
492
493 if ( doChangeValue )
494 {
495 variant = wxULongLong(value64);
496 return true;
497 }
498 }
499 else
500 {
501 unsigned long value32 = wxLongLong(value64).GetLo();
502 if ( !isPrevLong || m_value != (long)value32 )
503 {
504 variant = (long)value32;
505 return true;
506 }
507 }
508
509 }
510 return false;
511 }
512
513 bool wxUIntProperty::IntToValue( wxVariant& variant, int number, int WXUNUSED(argFlags) ) const
514 {
515 if ( variant != (long)number )
516 {
517 variant = (long)number;
518 return true;
519 }
520 return false;
521 }
522
523 bool wxUIntProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& validationInfo ) const
524 {
525 wxULongLong_t uul = value.GetULongLong().GetValue();
526 return
527 NumericValidation<wxULongLong_t>(this,
528 uul,
529 &validationInfo,
530 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE,
531 wxS("%llu"));
532 }
533
534 bool wxUIntProperty::DoSetAttribute( const wxString& name, wxVariant& value )
535 {
536 if ( name == wxPG_UINT_BASE )
537 {
538 int val = value.GetLong();
539
540 m_realBase = (wxByte) val;
541 if ( m_realBase > 16 )
542 m_realBase = 16;
543
544 //
545 // Translate logical base to a template array index
546 m_base = 7; // oct
547 if ( val == wxPG_BASE_HEX )
548 m_base = 3;
549 else if ( val == wxPG_BASE_DEC )
550 m_base = 6;
551 else if ( val == wxPG_BASE_HEXL )
552 m_base = 0;
553 return true;
554 }
555 else if ( name == wxPG_UINT_PREFIX )
556 {
557 m_prefix = (wxByte) value.GetLong();
558 return true;
559 }
560 return false;
561 }
562
563 // -----------------------------------------------------------------------
564 // wxFloatProperty
565 // -----------------------------------------------------------------------
566
567 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty,wxPGProperty,
568 double,double,TextCtrl)
569
570 wxFloatProperty::wxFloatProperty( const wxString& label,
571 const wxString& name,
572 double value )
573 : wxPGProperty(label,name)
574 {
575 m_precision = -1;
576 SetValue(value);
577 }
578
579 wxFloatProperty::~wxFloatProperty() { }
580
581 // This helper method provides standard way for floating point-using
582 // properties to convert values to string.
583 void wxPropertyGrid::DoubleToString(wxString& target,
584 double value,
585 int precision,
586 bool removeZeroes,
587 wxString* precTemplate)
588 {
589 if ( precision >= 0 )
590 {
591 wxString text1;
592 if (!precTemplate)
593 precTemplate = &text1;
594
595 if ( !precTemplate->length() )
596 {
597 *precTemplate = wxS("%.");
598 *precTemplate << wxString::Format( wxS("%i"), precision );
599 *precTemplate << wxS('f');
600 }
601
602 target.Printf( precTemplate->c_str(), value );
603 }
604 else
605 {
606 target.Printf( wxS("%f"), value );
607 }
608
609 if ( removeZeroes && precision != 0 && target.length() )
610 {
611 // Remove excess zeroes (do not remove this code just yet,
612 // since sprintf can't do the same consistently across platforms).
613 wxString::const_iterator i = target.end() - 1;
614 size_t new_len = target.length() - 1;
615
616 for ( ; i != target.begin(); --i )
617 {
618 if ( *i != wxS('0') )
619 break;
620 new_len--;
621 }
622
623 wxChar cur_char = *i;
624 if ( cur_char != wxS('.') && cur_char != wxS(',') )
625 new_len++;
626
627 if ( new_len != target.length() )
628 target.resize(new_len);
629 }
630 }
631
632 wxString wxFloatProperty::ValueToString( wxVariant& value,
633 int argFlags ) const
634 {
635 wxString text;
636 if ( !value.IsNull() )
637 {
638 wxPropertyGrid::DoubleToString(text,
639 value,
640 m_precision,
641 !(argFlags & wxPG_FULL_VALUE),
642 NULL);
643 }
644 return text;
645 }
646
647 bool wxFloatProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
648 {
649 wxString s;
650 double value;
651
652 if ( text.length() == 0 )
653 {
654 variant.MakeNull();
655 return true;
656 }
657
658 bool res = text.ToDouble(&value);
659 if ( res )
660 {
661 if ( variant != value )
662 {
663 variant = value;
664 return true;
665 }
666 }
667 else if ( argFlags & wxPG_REPORT_ERROR )
668 {
669 }
670 return false;
671 }
672
673 bool wxFloatProperty::DoValidation( const wxPGProperty* property,
674 double& value,
675 wxPGValidationInfo* pValidationInfo,
676 int mode )
677 {
678 return NumericValidation<double>(property,
679 value,
680 pValidationInfo,
681 mode,
682 wxS("%g"));
683 }
684
685 bool
686 wxFloatProperty::ValidateValue( wxVariant& value,
687 wxPGValidationInfo& validationInfo ) const
688 {
689 double fpv = value.GetDouble();
690 return DoValidation(this, fpv, &validationInfo,
691 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE);
692 }
693
694 bool wxFloatProperty::DoSetAttribute( const wxString& name, wxVariant& value )
695 {
696 if ( name == wxPG_FLOAT_PRECISION )
697 {
698 m_precision = value.GetLong();
699 return true;
700 }
701 return false;
702 }
703
704 wxValidator* wxFloatProperty::DoGetValidator() const
705 {
706 return wxIntProperty::GetClassValidator();
707 }
708
709 // -----------------------------------------------------------------------
710 // wxBoolProperty
711 // -----------------------------------------------------------------------
712
713 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
714 // there is a custom GetEditorClass.
715
716 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty, wxPGProperty)
717
718 const wxPGEditor* wxBoolProperty::DoGetEditorClass() const
719 {
720 // Select correct editor control.
721 #if wxPG_INCLUDE_CHECKBOX
722 if ( !(m_flags & wxPG_PROP_USE_CHECKBOX) )
723 return wxPGEditor_Choice;
724 return wxPGEditor_CheckBox;
725 #else
726 return wxPGEditor_Choice;
727 #endif
728 }
729
730 wxBoolProperty::wxBoolProperty( const wxString& label, const wxString& name, bool value ) :
731 wxPGProperty(label,name)
732 {
733 m_choices.Assign(wxPGGlobalVars->m_boolChoices);
734
735 SetValue(wxPGVariant_Bool(value));
736
737 m_flags |= wxPG_PROP_USE_DCC;
738 }
739
740 wxBoolProperty::~wxBoolProperty() { }
741
742 wxString wxBoolProperty::ValueToString( wxVariant& value,
743 int argFlags ) const
744 {
745 bool boolValue = value.GetBool();
746
747 // As a fragment of composite string value,
748 // make it a little more readable.
749 if ( argFlags & wxPG_COMPOSITE_FRAGMENT )
750 {
751 if ( boolValue )
752 {
753 return m_label;
754 }
755 else
756 {
757 if ( argFlags & wxPG_UNEDITABLE_COMPOSITE_FRAGMENT )
758 return wxEmptyString;
759
760 wxString notFmt;
761 if ( wxPGGlobalVars->m_autoGetTranslation )
762 notFmt = _("Not %s");
763 else
764 notFmt = wxS("Not %s");
765
766 return wxString::Format(notFmt.c_str(), m_label.c_str());
767 }
768 }
769
770 if ( !(argFlags & wxPG_FULL_VALUE) )
771 {
772 return wxPGGlobalVars->m_boolChoices[boolValue?1:0].GetText();
773 }
774
775 wxString text;
776
777 if ( boolValue ) text = wxS("true");
778 else text = wxS("false");
779
780 return text;
781 }
782
783 bool wxBoolProperty::StringToValue( wxVariant& variant, const wxString& text, int WXUNUSED(argFlags) ) const
784 {
785 bool boolValue = false;
786 if ( text.CmpNoCase(wxPGGlobalVars->m_boolChoices[1].GetText()) == 0 ||
787 text.CmpNoCase(wxS("true")) == 0 ||
788 text.CmpNoCase(m_label) == 0 )
789 boolValue = true;
790
791 if ( text.length() == 0 )
792 {
793 variant.MakeNull();
794 return true;
795 }
796
797 if ( variant != boolValue )
798 {
799 variant = wxPGVariant_Bool(boolValue);
800 return true;
801 }
802 return false;
803 }
804
805 bool wxBoolProperty::IntToValue( wxVariant& variant, int value, int ) const
806 {
807 bool boolValue = value ? true : false;
808
809 if ( variant != boolValue )
810 {
811 variant = wxPGVariant_Bool(boolValue);
812 return true;
813 }
814 return false;
815 }
816
817 bool wxBoolProperty::DoSetAttribute( const wxString& name, wxVariant& value )
818 {
819 #if wxPG_INCLUDE_CHECKBOX
820 if ( name == wxPG_BOOL_USE_CHECKBOX )
821 {
822 if ( value.GetLong() )
823 m_flags |= wxPG_PROP_USE_CHECKBOX;
824 else
825 m_flags &= ~(wxPG_PROP_USE_CHECKBOX);
826 return true;
827 }
828 #endif
829 if ( name == wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING )
830 {
831 if ( value.GetLong() )
832 m_flags |= wxPG_PROP_USE_DCC;
833 else
834 m_flags &= ~(wxPG_PROP_USE_DCC);
835 return true;
836 }
837 return false;
838 }
839
840 // -----------------------------------------------------------------------
841 // wxEnumProperty
842 // -----------------------------------------------------------------------
843
844 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty, wxPGProperty)
845
846 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty,long,Choice)
847
848 wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name, const wxChar* const* labels,
849 const long* values, int value ) : wxPGProperty(label,name)
850 {
851 SetIndex(0);
852
853 if ( labels )
854 {
855 m_choices.Add(labels,values);
856
857 if ( GetItemCount() )
858 SetValue( (long)value );
859 }
860 }
861
862 wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name, const wxChar* const* labels,
863 const long* values, wxPGChoices* choicesCache, int value )
864 : wxPGProperty(label,name)
865 {
866 SetIndex(0);
867
868 wxASSERT( choicesCache );
869
870 if ( choicesCache->IsOk() )
871 {
872 m_choices.Assign( *choicesCache );
873 m_value = wxPGVariant_Zero;
874 }
875 else if ( labels )
876 {
877 m_choices.Add(labels,values);
878
879 if ( GetItemCount() )
880 SetValue( (long)value );
881 }
882 }
883
884 wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name,
885 const wxArrayString& labels, const wxArrayInt& values, int value )
886 : wxPGProperty(label,name)
887 {
888 SetIndex(0);
889
890 if ( &labels && labels.size() )
891 {
892 m_choices.Set(labels, values);
893
894 if ( GetItemCount() )
895 SetValue( (long)value );
896 }
897 }
898
899 wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name,
900 wxPGChoices& choices, int value )
901 : wxPGProperty(label,name)
902 {
903 m_choices.Assign( choices );
904
905 if ( GetItemCount() )
906 SetValue( (long)value );
907 }
908
909 int wxEnumProperty::GetIndexForValue( int value ) const
910 {
911 if ( !m_choices.IsOk() )
912 return -1;
913
914 int intVal = m_choices.Index(value);
915 if ( intVal >= 0 )
916 return intVal;
917
918 return value;
919 }
920
921 wxEnumProperty::~wxEnumProperty ()
922 {
923 }
924
925 int wxEnumProperty::ms_nextIndex = -2;
926
927 void wxEnumProperty::OnSetValue()
928 {
929 wxString variantType = m_value.GetType();
930
931 if ( variantType == wxPG_VARIANT_TYPE_LONG )
932 {
933 ValueFromInt_( m_value, m_value.GetLong(), wxPG_FULL_VALUE );
934 }
935 else if ( variantType == wxPG_VARIANT_TYPE_STRING )
936 {
937 ValueFromString_( m_value, m_value.GetString(), 0 );
938 }
939 else
940 {
941 wxFAIL;
942 }
943
944 if ( ms_nextIndex != -2 )
945 {
946 m_index = ms_nextIndex;
947 ms_nextIndex = -2;
948 }
949 }
950
951 bool wxEnumProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& WXUNUSED(validationInfo) ) const
952 {
953 // Make sure string value is in the list,
954 // unless property has string as preferred value type
955 // To reduce code size, use conversion here as well
956 if ( value.GetType() == wxPG_VARIANT_TYPE_STRING &&
957 !this->IsKindOf(CLASSINFO(wxEditEnumProperty)) )
958 return ValueFromString_( value, value.GetString(), wxPG_PROPERTY_SPECIFIC );
959
960 return true;
961 }
962
963 wxString wxEnumProperty::ValueToString( wxVariant& value,
964 int WXUNUSED(argFlags) ) const
965 {
966 if ( value.GetType() == wxPG_VARIANT_TYPE_STRING )
967 return value.GetString();
968
969 int index = m_choices.Index(value.GetLong());
970 if ( index < 0 )
971 return wxEmptyString;
972
973 return m_choices.GetLabel(index);
974 }
975
976 bool wxEnumProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
977 {
978 return ValueFromString_( variant, text, argFlags );
979 }
980
981 bool wxEnumProperty::IntToValue( wxVariant& variant, int intVal, int argFlags ) const
982 {
983 return ValueFromInt_( variant, intVal, argFlags );
984 }
985
986 bool wxEnumProperty::ValueFromString_( wxVariant& value, const wxString& text, int argFlags ) const
987 {
988 int useIndex = -1;
989 long useValue = 0;
990
991 for ( unsigned int i=0; i<m_choices.GetCount(); i++ )
992 {
993 const wxString& entryLabel = m_choices.GetLabel(i);
994 if ( text.CmpNoCase(entryLabel) == 0 )
995 {
996 useIndex = (int)i;
997 useValue = m_choices.GetValue(i);
998 break;
999 }
1000 }
1001
1002 bool asText = false;
1003
1004 bool isEdit = this->IsKindOf(CLASSINFO(wxEditEnumProperty));
1005
1006 // If text not any of the choices, store as text instead
1007 // (but only if we are wxEditEnumProperty)
1008 if ( useIndex == -1 && isEdit )
1009 {
1010 asText = true;
1011 }
1012
1013 int setAsNextIndex = -2;
1014
1015 if ( asText )
1016 {
1017 setAsNextIndex = -1;
1018 value = text;
1019 }
1020 else if ( useIndex != GetIndex() )
1021 {
1022 if ( useIndex != -1 )
1023 {
1024 setAsNextIndex = useIndex;
1025 value = (long)useValue;
1026 }
1027 else
1028 {
1029 setAsNextIndex = -1;
1030 value = wxPGVariant_MinusOne;
1031 }
1032 }
1033
1034 if ( setAsNextIndex != -2 )
1035 {
1036 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1037 // validation purposes only, and index must not be changed
1038 if ( !(argFlags & wxPG_PROPERTY_SPECIFIC) )
1039 ms_nextIndex = setAsNextIndex;
1040
1041 if ( isEdit || setAsNextIndex != -1 )
1042 return true;
1043 else
1044 return false;
1045 }
1046 return false;
1047 }
1048
1049 bool wxEnumProperty::ValueFromInt_( wxVariant& variant, int intVal, int argFlags ) const
1050 {
1051 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1052 //
1053 ms_nextIndex = -2;
1054
1055 if ( argFlags & wxPG_FULL_VALUE )
1056 {
1057 ms_nextIndex = GetIndexForValue( intVal );
1058 }
1059 else
1060 {
1061 if ( intVal != GetIndex() )
1062 {
1063 ms_nextIndex = intVal;
1064 }
1065 }
1066
1067 if ( ms_nextIndex != -2 )
1068 {
1069 if ( !(argFlags & wxPG_FULL_VALUE) )
1070 intVal = m_choices.GetValue(intVal);
1071
1072 variant = (long)intVal;
1073
1074 return true;
1075 }
1076
1077 return false;
1078 }
1079
1080 void
1081 wxEnumProperty::OnValidationFailure( wxVariant& WXUNUSED(pendingValue) )
1082 {
1083 // Revert index
1084 ResetNextIndex();
1085 }
1086
1087 void wxEnumProperty::SetIndex( int index )
1088 {
1089 ms_nextIndex = -2;
1090 m_index = index;
1091 }
1092
1093 int wxEnumProperty::GetIndex() const
1094 {
1095 if ( m_value.IsNull() )
1096 return -1;
1097
1098 if ( ms_nextIndex != -2 )
1099 return ms_nextIndex;
1100
1101 return m_index;
1102 }
1103
1104 // -----------------------------------------------------------------------
1105 // wxEditEnumProperty
1106 // -----------------------------------------------------------------------
1107
1108 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty, wxPGProperty)
1109
1110 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty,wxString,ComboBox)
1111
1112 wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name, const wxChar* const* labels,
1113 const long* values, const wxString& value )
1114 : wxEnumProperty(label,name,labels,values,0)
1115 {
1116 SetValue( value );
1117 }
1118
1119 wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name, const wxChar* const* labels,
1120 const long* values, wxPGChoices* choicesCache, const wxString& value )
1121 : wxEnumProperty(label,name,labels,values,choicesCache,0)
1122 {
1123 SetValue( value );
1124 }
1125
1126 wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name,
1127 const wxArrayString& labels, const wxArrayInt& values, const wxString& value )
1128 : wxEnumProperty(label,name,labels,values,0)
1129 {
1130 SetValue( value );
1131 }
1132
1133 wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name,
1134 wxPGChoices& choices, const wxString& value )
1135 : wxEnumProperty(label,name,choices,0)
1136 {
1137 SetValue( value );
1138 }
1139
1140 wxEditEnumProperty::~wxEditEnumProperty()
1141 {
1142 }
1143
1144 // -----------------------------------------------------------------------
1145 // wxFlagsProperty
1146 // -----------------------------------------------------------------------
1147
1148 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty,wxPGProperty)
1149
1150 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty,long,TextCtrl)
1151
1152 void wxFlagsProperty::Init()
1153 {
1154 long value = m_value;
1155
1156 //
1157 // Generate children
1158 //
1159 unsigned int i;
1160
1161 unsigned int prevChildCount = m_children.size();
1162
1163 int oldSel = -1;
1164 if ( prevChildCount )
1165 {
1166 wxPropertyGridPageState* state = GetParentState();
1167
1168 // State safety check (it may be NULL in immediate parent)
1169 wxASSERT( state );
1170
1171 if ( state )
1172 {
1173 wxPGProperty* selected = state->GetSelection();
1174 if ( selected )
1175 {
1176 if ( selected->GetParent() == this )
1177 oldSel = selected->GetIndexInParent();
1178 else if ( selected == this )
1179 oldSel = -2;
1180 }
1181 }
1182 state->DoClearSelection();
1183 }
1184
1185 // Delete old children
1186 for ( i=0; i<prevChildCount; i++ )
1187 delete m_children[i];
1188
1189 m_children.clear();
1190
1191 // Relay wxPG_BOOL_USE_CHECKBOX and wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
1192 // to child bool property controls.
1193 long attrUseCheckBox = GetAttributeAsLong(wxPG_BOOL_USE_CHECKBOX, 0);
1194 long attrUseDCC = GetAttributeAsLong(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING,
1195 0);
1196
1197 if ( m_choices.IsOk() )
1198 {
1199 const wxPGChoices& choices = m_choices;
1200
1201 for ( i=0; i<GetItemCount(); i++ )
1202 {
1203 bool child_val;
1204 child_val = ( value & choices.GetValue(i) )?true:false;
1205
1206 wxPGProperty* boolProp;
1207 wxString label = GetLabel(i);
1208
1209 #if wxUSE_INTL
1210 if ( wxPGGlobalVars->m_autoGetTranslation )
1211 {
1212 boolProp = new wxBoolProperty( ::wxGetTranslation(label), label, child_val );
1213 }
1214 else
1215 #endif
1216 {
1217 boolProp = new wxBoolProperty( label, label, child_val );
1218 }
1219 if ( attrUseCheckBox )
1220 boolProp->SetAttribute(wxPG_BOOL_USE_CHECKBOX,
1221 true);
1222 if ( attrUseDCC )
1223 boolProp->SetAttribute(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING,
1224 true);
1225 AddPrivateChild(boolProp);
1226 }
1227
1228 m_oldChoicesData = m_choices.GetDataPtr();
1229 }
1230
1231 m_oldValue = m_value;
1232
1233 if ( prevChildCount )
1234 SubPropsChanged(oldSel);
1235 }
1236
1237 wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
1238 const wxChar* const* labels, const long* values, long value ) : wxPGProperty(label,name)
1239 {
1240 m_oldChoicesData = NULL;
1241
1242 if ( labels )
1243 {
1244 m_choices.Set(labels,values);
1245
1246 wxASSERT( GetItemCount() );
1247
1248 SetValue( value );
1249 }
1250 else
1251 {
1252 m_value = wxPGVariant_Zero;
1253 }
1254 }
1255
1256 wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
1257 const wxArrayString& labels, const wxArrayInt& values, int value )
1258 : wxPGProperty(label,name)
1259 {
1260 m_oldChoicesData = NULL;
1261
1262 if ( &labels && labels.size() )
1263 {
1264 m_choices.Set(labels,values);
1265
1266 wxASSERT( GetItemCount() );
1267
1268 SetValue( (long)value );
1269 }
1270 else
1271 {
1272 m_value = wxPGVariant_Zero;
1273 }
1274 }
1275
1276 wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
1277 wxPGChoices& choices, long value )
1278 : wxPGProperty(label,name)
1279 {
1280 m_oldChoicesData = NULL;
1281
1282 if ( choices.IsOk() )
1283 {
1284 m_choices.Assign(choices);
1285
1286 wxASSERT( GetItemCount() );
1287
1288 SetValue( value );
1289 }
1290 else
1291 {
1292 m_value = wxPGVariant_Zero;
1293 }
1294 }
1295
1296 wxFlagsProperty::~wxFlagsProperty()
1297 {
1298 }
1299
1300 void wxFlagsProperty::OnSetValue()
1301 {
1302 if ( !m_choices.IsOk() || !GetItemCount() )
1303 {
1304 m_value = wxPGVariant_Zero;
1305 }
1306 else
1307 {
1308 long val = m_value.GetLong();
1309
1310 long fullFlags = 0;
1311
1312 // normalize the value (i.e. remove extra flags)
1313 unsigned int i;
1314 const wxPGChoices& choices = m_choices;
1315 for ( i = 0; i < GetItemCount(); i++ )
1316 {
1317 fullFlags |= choices.GetValue(i);
1318 }
1319
1320 val &= fullFlags;
1321
1322 m_value = val;
1323
1324 // Need to (re)init now?
1325 if ( GetChildCount() != GetItemCount() ||
1326 m_choices.GetDataPtr() != m_oldChoicesData )
1327 {
1328 Init();
1329 }
1330 }
1331
1332 long newFlags = m_value;
1333
1334 if ( newFlags != m_oldValue )
1335 {
1336 // Set child modified states
1337 unsigned int i;
1338 const wxPGChoices& choices = m_choices;
1339 for ( i = 0; i<GetItemCount(); i++ )
1340 {
1341 int flag;
1342
1343 flag = choices.GetValue(i);
1344
1345 if ( (newFlags & flag) != (m_oldValue & flag) )
1346 Item(i)->SetFlag( wxPG_PROP_MODIFIED );
1347 }
1348
1349 m_oldValue = newFlags;
1350 }
1351 }
1352
1353 wxString wxFlagsProperty::ValueToString( wxVariant& value,
1354 int WXUNUSED(argFlags) ) const
1355 {
1356 wxString text;
1357
1358 if ( !m_choices.IsOk() )
1359 return text;
1360
1361 long flags = value;
1362 unsigned int i;
1363 const wxPGChoices& choices = m_choices;
1364
1365 for ( i = 0; i < GetItemCount(); i++ )
1366 {
1367 int doAdd;
1368 doAdd = ( flags & choices.GetValue(i) );
1369
1370 if ( doAdd )
1371 {
1372 text += choices.GetLabel(i);
1373 text += wxS(", ");
1374 }
1375 }
1376
1377 // remove last comma
1378 if ( text.Len() > 1 )
1379 text.Truncate ( text.Len() - 2 );
1380
1381 return text;
1382 }
1383
1384 // Translate string into flag tokens
1385 bool wxFlagsProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
1386 {
1387 if ( !m_choices.IsOk() )
1388 return false;
1389
1390 long newFlags = 0;
1391
1392 // semicolons are no longer valid delimeters
1393 WX_PG_TOKENIZER1_BEGIN(text,wxS(','))
1394
1395 if ( token.length() )
1396 {
1397 // Determine which one it is
1398 long bit = IdToBit( token );
1399
1400 if ( bit != -1 )
1401 {
1402 // Changed?
1403 newFlags |= bit;
1404 }
1405 else
1406 {
1407 break;
1408 }
1409 }
1410
1411 WX_PG_TOKENIZER1_END()
1412
1413 if ( variant != (long)newFlags )
1414 {
1415 variant = (long)newFlags;
1416 return true;
1417 }
1418
1419 return false;
1420 }
1421
1422 // Converts string id to a relevant bit.
1423 long wxFlagsProperty::IdToBit( const wxString& id ) const
1424 {
1425 unsigned int i;
1426 for ( i = 0; i < GetItemCount(); i++ )
1427 {
1428 if ( id == GetLabel(i) )
1429 {
1430 return m_choices.GetValue(i);
1431 }
1432 }
1433 return -1;
1434 }
1435
1436 void wxFlagsProperty::RefreshChildren()
1437 {
1438 if ( !m_choices.IsOk() || !GetChildCount() ) return;
1439
1440 int flags = m_value.GetLong();
1441
1442 const wxPGChoices& choices = m_choices;
1443 unsigned int i;
1444 for ( i = 0; i < GetItemCount(); i++ )
1445 {
1446 long flag;
1447
1448 flag = choices.GetValue(i);
1449
1450 long subVal = flags & flag;
1451 wxPGProperty* p = Item(i);
1452
1453 if ( subVal != (m_oldValue & flag) )
1454 p->SetFlag( wxPG_PROP_MODIFIED );
1455
1456 p->SetValue( subVal?true:false );
1457 }
1458
1459 m_oldValue = flags;
1460 }
1461
1462 wxVariant wxFlagsProperty::ChildChanged( wxVariant& thisValue,
1463 int childIndex,
1464 wxVariant& childValue ) const
1465 {
1466 long oldValue = thisValue.GetLong();
1467 long val = childValue.GetLong();
1468 unsigned long vi = m_choices.GetValue(childIndex);
1469
1470 if ( val )
1471 return (long) (oldValue | vi);
1472
1473 return (long) (oldValue & ~(vi));
1474 }
1475
1476 bool wxFlagsProperty::DoSetAttribute( const wxString& name, wxVariant& value )
1477 {
1478 if ( name == wxPG_BOOL_USE_CHECKBOX ||
1479 name == wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING )
1480 {
1481 for ( size_t i=0; i<GetChildCount(); i++ )
1482 {
1483 Item(i)->SetAttribute(name, value);
1484 }
1485 // Must return false so that the attribute is stored in
1486 // flag property's actual property storage
1487 return false;
1488 }
1489 return false;
1490 }
1491
1492 // -----------------------------------------------------------------------
1493 // wxDirProperty
1494 // -----------------------------------------------------------------------
1495
1496 IMPLEMENT_DYNAMIC_CLASS(wxDirProperty, wxLongStringProperty)
1497
1498 wxDirProperty::wxDirProperty( const wxString& name, const wxString& label, const wxString& value )
1499 : wxLongStringProperty(name,label,value)
1500 {
1501 m_flags |= wxPG_PROP_NO_ESCAPE;
1502 }
1503
1504 wxDirProperty::~wxDirProperty() { }
1505
1506 wxValidator* wxDirProperty::DoGetValidator() const
1507 {
1508 return wxFileProperty::GetClassValidator();
1509 }
1510
1511 bool wxDirProperty::OnButtonClick( wxPropertyGrid* propGrid, wxString& value )
1512 {
1513 // Update property value from editor, if necessary
1514 wxSize dlg_sz(300,400);
1515
1516 wxString dlgMessage(m_dlgMessage);
1517 if ( dlgMessage.empty() )
1518 dlgMessage = _("Choose a directory:");
1519 wxDirDialog dlg( propGrid,
1520 dlgMessage,
1521 value,
1522 0,
1523 #if !wxPG_SMALL_SCREEN
1524 propGrid->GetGoodEditorDialogPosition(this,dlg_sz),
1525 dlg_sz
1526 #else
1527 wxDefaultPosition,
1528 wxDefaultSize
1529 #endif
1530 );
1531
1532 if ( dlg.ShowModal() == wxID_OK )
1533 {
1534 value = dlg.GetPath();
1535 return true;
1536 }
1537 return false;
1538 }
1539
1540 bool wxDirProperty::DoSetAttribute( const wxString& name, wxVariant& value )
1541 {
1542 if ( name == wxPG_DIR_DIALOG_MESSAGE )
1543 {
1544 m_dlgMessage = value.GetString();
1545 return true;
1546 }
1547 return false;
1548 }
1549
1550 // -----------------------------------------------------------------------
1551 // wxPGFileDialogAdapter
1552 // -----------------------------------------------------------------------
1553
1554 bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid* propGrid, wxPGProperty* property )
1555 {
1556 wxFileProperty* fileProp = NULL;
1557 wxString path;
1558 int indFilter = -1;
1559
1560 if ( property->IsKindOf(CLASSINFO(wxFileProperty)) )
1561 {
1562 fileProp = ((wxFileProperty*)property);
1563 wxFileName filename = fileProp->GetValue().GetString();
1564 path = filename.GetPath();
1565 indFilter = fileProp->m_indFilter;
1566
1567 if ( !path.length() && fileProp->m_basePath.length() )
1568 path = fileProp->m_basePath;
1569 }
1570 else
1571 {
1572 wxFileName fn(property->GetValue().GetString());
1573 path = fn.GetPath();
1574 }
1575
1576 wxFileDialog dlg( propGrid->GetPanel(),
1577 property->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1578 property->GetAttribute(wxS("InitialPath"), path),
1579 wxEmptyString,
1580 property->GetAttribute(wxPG_FILE_WILDCARD, _("All files (*.*)|*.*")),
1581 0,
1582 wxDefaultPosition );
1583
1584 if ( indFilter >= 0 )
1585 dlg.SetFilterIndex( indFilter );
1586
1587 if ( dlg.ShowModal() == wxID_OK )
1588 {
1589 if ( fileProp )
1590 fileProp->m_indFilter = dlg.GetFilterIndex();
1591 SetValue( dlg.GetPath() );
1592 return true;
1593 }
1594 return false;
1595 }
1596
1597 // -----------------------------------------------------------------------
1598 // wxFileProperty
1599 // -----------------------------------------------------------------------
1600
1601 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty,wxPGProperty,
1602 wxString,const wxString&,TextCtrlAndButton)
1603
1604 wxFileProperty::wxFileProperty( const wxString& label, const wxString& name,
1605 const wxString& value ) : wxPGProperty(label,name)
1606 {
1607 m_flags |= wxPG_PROP_SHOW_FULL_FILENAME;
1608 m_indFilter = -1;
1609 SetAttribute( wxPG_FILE_WILDCARD, _("All files (*.*)|*.*") );
1610
1611 SetValue(value);
1612 }
1613
1614 wxFileProperty::~wxFileProperty() {}
1615
1616 wxValidator* wxFileProperty::GetClassValidator()
1617 {
1618 #if wxUSE_VALIDATORS
1619 WX_PG_DOGETVALIDATOR_ENTRY()
1620
1621 // Atleast wxPython 2.6.2.1 required that the string argument is given
1622 static wxString v;
1623 wxTextValidator* validator = new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST,&v);
1624
1625 wxArrayString exChars;
1626 exChars.Add(wxS("?"));
1627 exChars.Add(wxS("*"));
1628 exChars.Add(wxS("|"));
1629 exChars.Add(wxS("<"));
1630 exChars.Add(wxS(">"));
1631 exChars.Add(wxS("\""));
1632
1633 validator->SetExcludes(exChars);
1634
1635 WX_PG_DOGETVALIDATOR_EXIT(validator)
1636 #else
1637 return NULL;
1638 #endif
1639 }
1640
1641 wxValidator* wxFileProperty::DoGetValidator() const
1642 {
1643 return GetClassValidator();
1644 }
1645
1646 void wxFileProperty::OnSetValue()
1647 {
1648 const wxString& fnstr = m_value.GetString();
1649
1650 wxFileName filename = fnstr;
1651
1652 if ( !filename.HasName() )
1653 {
1654 m_value = wxPGVariant_EmptyString;
1655 }
1656
1657 // Find index for extension.
1658 if ( m_indFilter < 0 && fnstr.length() )
1659 {
1660 wxString ext = filename.GetExt();
1661 int curind = 0;
1662 size_t pos = 0;
1663 size_t len = m_wildcard.length();
1664
1665 pos = m_wildcard.find(wxS("|"), pos);
1666 while ( pos != wxString::npos && pos < (len-3) )
1667 {
1668 size_t ext_begin = pos + 3;
1669
1670 pos = m_wildcard.find(wxS("|"), ext_begin);
1671 if ( pos == wxString::npos )
1672 pos = len;
1673 wxString found_ext = m_wildcard.substr(ext_begin, pos-ext_begin);
1674
1675 if ( found_ext.length() > 0 )
1676 {
1677 if ( found_ext[0] == wxS('*') )
1678 {
1679 m_indFilter = curind;
1680 break;
1681 }
1682 if ( ext.CmpNoCase(found_ext) == 0 )
1683 {
1684 m_indFilter = curind;
1685 break;
1686 }
1687 }
1688
1689 if ( pos != len )
1690 pos = m_wildcard.find(wxS("|"), pos+1);
1691
1692 curind++;
1693 }
1694 }
1695 }
1696
1697 wxFileName wxFileProperty::GetFileName() const
1698 {
1699 wxFileName filename;
1700
1701 if ( !m_value.IsNull() )
1702 filename = m_value.GetString();
1703
1704 return filename;
1705 }
1706
1707 wxString wxFileProperty::ValueToString( wxVariant& value,
1708 int argFlags ) const
1709 {
1710 wxFileName filename = value.GetString();
1711
1712 if ( !filename.HasName() )
1713 return wxEmptyString;
1714
1715 wxString fullName = filename.GetFullName();
1716 if ( !fullName.length() )
1717 return wxEmptyString;
1718
1719 if ( argFlags & wxPG_FULL_VALUE )
1720 {
1721 return filename.GetFullPath();
1722 }
1723 else if ( m_flags & wxPG_PROP_SHOW_FULL_FILENAME )
1724 {
1725 if ( m_basePath.Length() )
1726 {
1727 wxFileName fn2(filename);
1728 fn2.MakeRelativeTo(m_basePath);
1729 return fn2.GetFullPath();
1730 }
1731 return filename.GetFullPath();
1732 }
1733
1734 return filename.GetFullName();
1735 }
1736
1737 wxPGEditorDialogAdapter* wxFileProperty::GetEditorDialog() const
1738 {
1739 return new wxPGFileDialogAdapter();
1740 }
1741
1742 bool wxFileProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
1743 {
1744 wxFileName filename = variant.GetString();
1745
1746 if ( (m_flags & wxPG_PROP_SHOW_FULL_FILENAME) || (argFlags & wxPG_FULL_VALUE) )
1747 {
1748 if ( filename != text )
1749 {
1750 variant = text;
1751 return true;
1752 }
1753 }
1754 else
1755 {
1756 if ( filename.GetFullName() != text )
1757 {
1758 wxFileName fn = filename;
1759 fn.SetFullName(text);
1760 variant = fn.GetFullPath();
1761 return true;
1762 }
1763 }
1764
1765 return false;
1766 }
1767
1768 bool wxFileProperty::DoSetAttribute( const wxString& name, wxVariant& value )
1769 {
1770 // Return false on some occasions to make sure those attribs will get
1771 // stored in m_attributes.
1772 if ( name == wxPG_FILE_SHOW_FULL_PATH )
1773 {
1774 if ( value.GetLong() )
1775 m_flags |= wxPG_PROP_SHOW_FULL_FILENAME;
1776 else
1777 m_flags &= ~(wxPG_PROP_SHOW_FULL_FILENAME);
1778 return true;
1779 }
1780 else if ( name == wxPG_FILE_WILDCARD )
1781 {
1782 m_wildcard = value.GetString();
1783 }
1784 else if ( name == wxPG_FILE_SHOW_RELATIVE_PATH )
1785 {
1786 m_basePath = value.GetString();
1787
1788 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1789 m_flags |= wxPG_PROP_SHOW_FULL_FILENAME;
1790 }
1791 else if ( name == wxPG_FILE_INITIAL_PATH )
1792 {
1793 m_initialPath = value.GetString();
1794 return true;
1795 }
1796 else if ( name == wxPG_FILE_DIALOG_TITLE )
1797 {
1798 m_dlgTitle = value.GetString();
1799 return true;
1800 }
1801 return false;
1802 }
1803
1804 // -----------------------------------------------------------------------
1805 // wxPGLongStringDialogAdapter
1806 // -----------------------------------------------------------------------
1807
1808 bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid* propGrid, wxPGProperty* property )
1809 {
1810 wxString val1 = property->GetValueAsString(0);
1811 wxString val_orig = val1;
1812
1813 wxString value;
1814 if ( !property->HasFlag(wxPG_PROP_NO_ESCAPE) )
1815 wxPropertyGrid::ExpandEscapeSequences(value, val1);
1816 else
1817 value = wxString(val1);
1818
1819 // Run editor dialog.
1820 if ( wxLongStringProperty::DisplayEditorDialog(property, propGrid, value) )
1821 {
1822 if ( !property->HasFlag(wxPG_PROP_NO_ESCAPE) )
1823 wxPropertyGrid::CreateEscapeSequences(val1,value);
1824 else
1825 val1 = value;
1826
1827 if ( val1 != val_orig )
1828 {
1829 SetValue( val1 );
1830 return true;
1831 }
1832 }
1833 return false;
1834 }
1835
1836 // -----------------------------------------------------------------------
1837 // wxLongStringProperty
1838 // -----------------------------------------------------------------------
1839
1840 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty,wxPGProperty,
1841 wxString,const wxString&,TextCtrlAndButton)
1842
1843 wxLongStringProperty::wxLongStringProperty( const wxString& label, const wxString& name,
1844 const wxString& value ) : wxPGProperty(label,name)
1845 {
1846 SetValue(value);
1847 }
1848
1849 wxLongStringProperty::~wxLongStringProperty() {}
1850
1851 wxString wxLongStringProperty::ValueToString( wxVariant& value,
1852 int WXUNUSED(argFlags) ) const
1853 {
1854 return value;
1855 }
1856
1857 bool wxLongStringProperty::OnEvent( wxPropertyGrid* propGrid, wxWindow* WXUNUSED(primary),
1858 wxEvent& event )
1859 {
1860 if ( propGrid->IsMainButtonEvent(event) )
1861 {
1862 // Update the value
1863 wxVariant useValue = propGrid->GetUncommittedPropertyValue();
1864
1865 wxString val1 = useValue.GetString();
1866 wxString val_orig = val1;
1867
1868 wxString value;
1869 if ( !(m_flags & wxPG_PROP_NO_ESCAPE) )
1870 wxPropertyGrid::ExpandEscapeSequences(value,val1);
1871 else
1872 value = wxString(val1);
1873
1874 // Run editor dialog.
1875 if ( OnButtonClick(propGrid,value) )
1876 {
1877 if ( !(m_flags & wxPG_PROP_NO_ESCAPE) )
1878 wxPropertyGrid::CreateEscapeSequences(val1,value);
1879 else
1880 val1 = value;
1881
1882 if ( val1 != val_orig )
1883 {
1884 SetValueInEvent( val1 );
1885 return true;
1886 }
1887 }
1888 }
1889 return false;
1890 }
1891
1892 bool wxLongStringProperty::OnButtonClick( wxPropertyGrid* propGrid, wxString& value )
1893 {
1894 return DisplayEditorDialog(this, propGrid, value);
1895 }
1896
1897 bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty* prop, wxPropertyGrid* propGrid, wxString& value )
1898
1899 {
1900 // launch editor dialog
1901 wxDialog* dlg = new wxDialog(propGrid,-1,prop->GetLabel(),wxDefaultPosition,wxDefaultSize,
1902 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxCLIP_CHILDREN);
1903
1904 dlg->SetFont(propGrid->GetFont()); // To allow entering chars of the same set as the propGrid
1905
1906 // Multi-line text editor dialog.
1907 #if !wxPG_SMALL_SCREEN
1908 const int spacing = 8;
1909 #else
1910 const int spacing = 4;
1911 #endif
1912 wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL );
1913 wxBoxSizer* rowsizer = new wxBoxSizer( wxHORIZONTAL );
1914 wxTextCtrl* ed = new wxTextCtrl(dlg,11,value,
1915 wxDefaultPosition,wxDefaultSize,wxTE_MULTILINE);
1916
1917 rowsizer->Add( ed, 1, wxEXPAND|wxALL, spacing );
1918 topsizer->Add( rowsizer, 1, wxEXPAND, 0 );
1919
1920 wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
1921 buttonSizer->AddButton(new wxButton(dlg, wxID_OK));
1922 buttonSizer->AddButton(new wxButton(dlg, wxID_CANCEL));
1923 buttonSizer->Realize();
1924 topsizer->Add( buttonSizer, 0,
1925 wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxRIGHT,
1926 spacing );
1927
1928 dlg->SetSizer( topsizer );
1929 topsizer->SetSizeHints( dlg );
1930
1931 #if !wxPG_SMALL_SCREEN
1932 dlg->SetSize(400,300);
1933
1934 dlg->Move( propGrid->GetGoodEditorDialogPosition(prop,dlg->GetSize()) );
1935 #endif
1936
1937 int res = dlg->ShowModal();
1938
1939 if ( res == wxID_OK )
1940 {
1941 value = ed->GetValue();
1942 dlg->Destroy();
1943 return true;
1944 }
1945 dlg->Destroy();
1946 return false;
1947 }
1948
1949 bool wxLongStringProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
1950 {
1951 if ( variant != text )
1952 {
1953 variant = text;
1954 return true;
1955 }
1956 return false;
1957 }
1958
1959 #if wxUSE_EDITABLELISTBOX
1960
1961 // -----------------------------------------------------------------------
1962 // wxPGArrayEditorDialog
1963 // -----------------------------------------------------------------------
1964
1965 BEGIN_EVENT_TABLE(wxPGArrayEditorDialog, wxDialog)
1966 EVT_IDLE(wxPGArrayEditorDialog::OnIdle)
1967 END_EVENT_TABLE()
1968
1969 IMPLEMENT_ABSTRACT_CLASS(wxPGArrayEditorDialog, wxDialog)
1970
1971 #include "wx/editlbox.h"
1972 #include "wx/listctrl.h"
1973
1974 // -----------------------------------------------------------------------
1975
1976 void wxPGArrayEditorDialog::OnIdle(wxIdleEvent& event)
1977 {
1978 // Repair focus - wxEditableListBox has bitmap buttons, which
1979 // get focus, and lose focus (into the oblivion) when they
1980 // become disabled due to change in control state.
1981
1982 wxWindow* lastFocused = m_lastFocused;
1983 wxWindow* focus = ::wxWindow::FindFocus();
1984
1985 // If last focused control became disabled, set focus back to
1986 // wxEditableListBox
1987 if ( lastFocused && focus != lastFocused &&
1988 lastFocused->GetParent() == m_elbSubPanel &&
1989 !lastFocused->IsEnabled() )
1990 {
1991 m_elb->GetListCtrl()->SetFocus();
1992 }
1993
1994 m_lastFocused = focus;
1995
1996 event.Skip();
1997 }
1998
1999 // -----------------------------------------------------------------------
2000
2001 wxPGArrayEditorDialog::wxPGArrayEditorDialog()
2002 : wxDialog()
2003 {
2004 Init();
2005 }
2006
2007 // -----------------------------------------------------------------------
2008
2009 void wxPGArrayEditorDialog::Init()
2010 {
2011 m_lastFocused = NULL;
2012 m_hasCustomNewAction = false;
2013 m_itemPendingAtIndex = -1;
2014 }
2015
2016 // -----------------------------------------------------------------------
2017
2018 wxPGArrayEditorDialog::wxPGArrayEditorDialog( wxWindow *parent,
2019 const wxString& message,
2020 const wxString& caption,
2021 long style,
2022 const wxPoint& pos,
2023 const wxSize& sz )
2024 : wxDialog()
2025 {
2026 Init();
2027 Create(parent,message,caption,style,pos,sz);
2028 }
2029
2030 // -----------------------------------------------------------------------
2031
2032 bool wxPGArrayEditorDialog::Create( wxWindow *parent,
2033 const wxString& message,
2034 const wxString& caption,
2035 long style,
2036 const wxPoint& pos,
2037 const wxSize& sz )
2038 {
2039 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2040 // FIXME: This should be only a temporary fix.
2041 #ifdef __WXMAC__
2042 wxUnusedVar(style);
2043 int useStyle = wxCAPTION;
2044 #else
2045 int useStyle = style;
2046 #endif
2047
2048 bool res = wxDialog::Create(parent, wxID_ANY, caption, pos, sz, useStyle);
2049
2050 SetFont(parent->GetFont()); // To allow entering chars of the same set as the propGrid
2051
2052 #if !wxPG_SMALL_SCREEN
2053 const int spacing = 4;
2054 #else
2055 const int spacing = 3;
2056 #endif
2057
2058 m_modified = false;
2059
2060 wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL );
2061
2062 // Message
2063 if ( message.length() )
2064 topsizer->Add( new wxStaticText(this,-1,message),
2065 0, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxALL, spacing );
2066
2067 m_elb = new wxEditableListBox(this, wxID_ANY, message,
2068 wxDefaultPosition,
2069 wxDefaultSize,
2070 wxEL_ALLOW_NEW |
2071 wxEL_ALLOW_EDIT |
2072 wxEL_ALLOW_DELETE);
2073
2074 // Populate the list box
2075 wxArrayString arr;
2076 for ( unsigned int i=0; i<ArrayGetCount(); i++ )
2077 arr.push_back(ArrayGet(i));
2078 m_elb->SetStrings(arr);
2079
2080 // Connect event handlers
2081 wxButton* but;
2082 wxListCtrl* lc = m_elb->GetListCtrl();
2083
2084 but = m_elb->GetNewButton();
2085 m_elbSubPanel = but->GetParent();
2086 but->Connect(but->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
2087 wxCommandEventHandler(wxPGArrayEditorDialog::OnAddClick),
2088 NULL, this);
2089
2090 but = m_elb->GetDelButton();
2091 but->Connect(but->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
2092 wxCommandEventHandler(wxPGArrayEditorDialog::OnDeleteClick),
2093 NULL, this);
2094
2095 but = m_elb->GetUpButton();
2096 but->Connect(but->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
2097 wxCommandEventHandler(wxPGArrayEditorDialog::OnUpClick),
2098 NULL, this);
2099
2100 but = m_elb->GetDownButton();
2101 but->Connect(but->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
2102 wxCommandEventHandler(wxPGArrayEditorDialog::OnDownClick),
2103 NULL, this);
2104
2105 lc->Connect(lc->GetId(), wxEVT_COMMAND_LIST_END_LABEL_EDIT,
2106 wxListEventHandler(wxPGArrayEditorDialog::OnEndLabelEdit),
2107 NULL, this);
2108
2109 topsizer->Add( m_elb, 1, wxEXPAND, spacing );
2110
2111 // Standard dialog buttons
2112 wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
2113 buttonSizer->AddButton(new wxButton(this, wxID_OK));
2114 buttonSizer->AddButton(new wxButton(this, wxID_CANCEL));
2115 buttonSizer->Realize();
2116 topsizer->Add( buttonSizer, 0,
2117 wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxALL,
2118 spacing );
2119
2120 m_elb->SetFocus();
2121
2122 SetSizer( topsizer );
2123 topsizer->SetSizeHints( this );
2124
2125 #if !wxPG_SMALL_SCREEN
2126 if ( sz.x == wxDefaultSize.x &&
2127 sz.y == wxDefaultSize.y )
2128 SetSize( wxSize(275,360) );
2129 else
2130 SetSize(sz);
2131 #endif
2132
2133 return res;
2134 }
2135
2136 // -----------------------------------------------------------------------
2137
2138 int wxPGArrayEditorDialog::GetSelection() const
2139 {
2140 wxListCtrl* lc = m_elb->GetListCtrl();
2141
2142 int index = lc->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2143 if ( index == -1 )
2144 return wxNOT_FOUND;
2145
2146 return index;
2147 }
2148
2149 // -----------------------------------------------------------------------
2150
2151 void wxPGArrayEditorDialog::OnAddClick(wxCommandEvent& event)
2152 {
2153 wxListCtrl* lc = m_elb->GetListCtrl();
2154 int newItemIndex = lc->GetItemCount() - 1;
2155
2156 if ( m_hasCustomNewAction )
2157 {
2158 wxString str;
2159 if ( OnCustomNewAction(&str) )
2160 {
2161 if ( ArrayInsert(str, newItemIndex) )
2162 {
2163 lc->InsertItem(newItemIndex, str);
2164 m_modified = true;
2165 }
2166 }
2167
2168 // Do *not* skip the event! We do not want the wxEditableListBox
2169 // to do anything.
2170 }
2171 else
2172 {
2173 m_itemPendingAtIndex = newItemIndex;
2174
2175 event.Skip();
2176 }
2177 }
2178
2179 // -----------------------------------------------------------------------
2180
2181 void wxPGArrayEditorDialog::OnDeleteClick(wxCommandEvent& event)
2182 {
2183 int index = GetSelection();
2184 if ( index >= 0 )
2185 {
2186 ArrayRemoveAt( index );
2187 m_modified = true;
2188 }
2189
2190 event.Skip();
2191 }
2192
2193 // -----------------------------------------------------------------------
2194
2195 void wxPGArrayEditorDialog::OnUpClick(wxCommandEvent& event)
2196 {
2197 int index = GetSelection();
2198 if ( index > 0 )
2199 {
2200 ArraySwap(index-1,index);
2201 m_modified = true;
2202 }
2203
2204 event.Skip();
2205 }
2206
2207 // -----------------------------------------------------------------------
2208
2209 void wxPGArrayEditorDialog::OnDownClick(wxCommandEvent& event)
2210 {
2211 wxListCtrl* lc = m_elb->GetListCtrl();
2212 int index = GetSelection();
2213 int lastStringIndex = lc->GetItemCount() - 1;
2214 if ( index >= 0 && index < lastStringIndex )
2215 {
2216 ArraySwap(index, index+1);
2217 m_modified = true;
2218 }
2219
2220 event.Skip();
2221 }
2222
2223 // -----------------------------------------------------------------------
2224
2225 void wxPGArrayEditorDialog::OnEndLabelEdit(wxListEvent& event)
2226 {
2227 wxString str = event.GetLabel();
2228
2229 if ( m_itemPendingAtIndex >= 0 )
2230 {
2231 // Add a new item
2232 if ( ArrayInsert(str, m_itemPendingAtIndex) )
2233 {
2234 m_modified = true;
2235 }
2236 else
2237 {
2238 // Editable list box doesn't really respect Veto(), but
2239 // it recognizes if no text was added, so we simulate
2240 // Veto() using it.
2241 event.m_item.SetText(wxEmptyString);
2242 m_elb->GetListCtrl()->SetItemText(m_itemPendingAtIndex,
2243 wxEmptyString);
2244
2245 event.Veto();
2246 }
2247 }
2248 else
2249 {
2250 // Change an existing item
2251 int index = GetSelection();
2252 wxASSERT( index != wxNOT_FOUND );
2253 if ( ArraySet(index, str) )
2254 m_modified = true;
2255 else
2256 event.Veto();
2257 }
2258
2259 event.Skip();
2260 }
2261
2262 #endif // wxUSE_EDITABLELISTBOX
2263
2264 // -----------------------------------------------------------------------
2265 // wxPGArrayStringEditorDialog
2266 // -----------------------------------------------------------------------
2267
2268 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog, wxPGArrayEditorDialog)
2269
2270 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog, wxPGArrayEditorDialog)
2271 END_EVENT_TABLE()
2272
2273 // -----------------------------------------------------------------------
2274
2275 wxString wxPGArrayStringEditorDialog::ArrayGet( size_t index )
2276 {
2277 return m_array[index];
2278 }
2279
2280 size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2281 {
2282 return m_array.size();
2283 }
2284
2285 bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString& str, int index )
2286 {
2287 if (index<0)
2288 m_array.Add(str);
2289 else
2290 m_array.Insert(str,index);
2291 return true;
2292 }
2293
2294 bool wxPGArrayStringEditorDialog::ArraySet( size_t index, const wxString& str )
2295 {
2296 m_array[index] = str;
2297 return true;
2298 }
2299
2300 void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index )
2301 {
2302 m_array.RemoveAt(index);
2303 }
2304
2305 void wxPGArrayStringEditorDialog::ArraySwap( size_t first, size_t second )
2306 {
2307 wxString old_str = m_array[first];
2308 wxString new_str = m_array[second];
2309 m_array[first] = new_str;
2310 m_array[second] = old_str;
2311 }
2312
2313 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2314 : wxPGArrayEditorDialog()
2315 {
2316 Init();
2317 }
2318
2319 void wxPGArrayStringEditorDialog::Init()
2320 {
2321 m_pCallingClass = NULL;
2322 }
2323
2324 bool
2325 wxPGArrayStringEditorDialog::OnCustomNewAction(wxString* resString)
2326 {
2327 return m_pCallingClass->OnCustomStringEdit(m_parent, *resString);
2328 }
2329
2330 // -----------------------------------------------------------------------
2331 // wxArrayStringProperty
2332 // -----------------------------------------------------------------------
2333
2334 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty, // Property name
2335 wxPGProperty, // Property we inherit from
2336 wxArrayString, // Value type name
2337 const wxArrayString&, // Value type, as given in constructor
2338 TextCtrlAndButton) // Initial editor
2339
2340 wxArrayStringProperty::wxArrayStringProperty( const wxString& label,
2341 const wxString& name,
2342 const wxArrayString& array )
2343 : wxPGProperty(label,name)
2344 {
2345 m_delimiter = '"';
2346 SetValue( array );
2347 }
2348
2349 wxArrayStringProperty::~wxArrayStringProperty() { }
2350
2351 void wxArrayStringProperty::OnSetValue()
2352 {
2353 GenerateValueAsString();
2354 }
2355
2356 void
2357 wxArrayStringProperty::ConvertArrayToString(const wxArrayString& arr,
2358 wxString* pString,
2359 const wxUniChar& delimiter) const
2360 {
2361 if ( delimiter == '"' || delimiter == '\'' )
2362 {
2363 // Quoted strings
2364 ArrayStringToString(*pString,
2365 arr,
2366 delimiter,
2367 Escape | QuoteStrings);
2368 }
2369 else
2370 {
2371 // Regular delimiter
2372 ArrayStringToString(*pString,
2373 arr,
2374 delimiter,
2375 0);
2376 }
2377 }
2378
2379 wxString wxArrayStringProperty::ValueToString( wxVariant& WXUNUSED(value),
2380 int argFlags ) const
2381 {
2382 //
2383 // If this is called from GetValueAsString(), return cached string
2384 if ( argFlags & wxPG_VALUE_IS_CURRENT )
2385 {
2386 return m_display;
2387 }
2388
2389 wxArrayString arr = m_value.GetArrayString();
2390 wxString s;
2391 ConvertArrayToString(arr, &s, m_delimiter);
2392 return s;
2393 }
2394
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
2397 // conversion.
2398 void
2399 wxArrayStringProperty::ArrayStringToString( wxString& dst,
2400 const wxArrayString& src,
2401 wxUniChar delimiter, int flags )
2402 {
2403 wxString pdr;
2404 wxString preas;
2405
2406 unsigned int i;
2407 unsigned int itemCount = src.size();
2408
2409 dst.Empty();
2410
2411 if ( flags & Escape )
2412 {
2413 preas = delimiter;
2414 pdr = wxS("\\") + static_cast<wchar_t>(delimiter);
2415 }
2416
2417 if ( itemCount )
2418 dst.append( preas );
2419
2420 wxString delimStr(delimiter);
2421
2422 for ( i = 0; i < itemCount; i++ )
2423 {
2424 wxString str( src.Item(i) );
2425
2426 // Do some character conversion.
2427 // Converts \ to \\ and $delimiter to \$delimiter
2428 // Useful when quoting.
2429 if ( flags & Escape )
2430 {
2431 str.Replace( wxS("\\"), wxS("\\\\"), true );
2432 if ( pdr.length() )
2433 str.Replace( preas, pdr, true );
2434 }
2435
2436 dst.append( str );
2437
2438 if ( i < (itemCount-1) )
2439 {
2440 dst.append( delimStr );
2441 dst.append( wxS(" ") );
2442 dst.append( preas );
2443 }
2444 else if ( flags & QuoteStrings )
2445 dst.append( delimStr );
2446 }
2447 }
2448
2449 void wxArrayStringProperty::GenerateValueAsString()
2450 {
2451 wxArrayString arr = m_value.GetArrayString();
2452 ConvertArrayToString(arr, &m_display, m_delimiter);
2453 }
2454
2455 // Default implementation doesn't do anything.
2456 bool wxArrayStringProperty::OnCustomStringEdit( wxWindow*, wxString& )
2457 {
2458 return false;
2459 }
2460
2461 wxPGArrayEditorDialog* wxArrayStringProperty::CreateEditorDialog()
2462 {
2463 return new wxPGArrayStringEditorDialog();
2464 }
2465
2466 bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid* propGrid,
2467 wxWindow* WXUNUSED(primaryCtrl),
2468 const wxChar* cbt )
2469 {
2470 // Update the value
2471 wxVariant useValue = propGrid->GetUncommittedPropertyValue();
2472
2473 if ( !propGrid->EditorValidate() )
2474 return false;
2475
2476 // Create editor dialog.
2477 wxPGArrayEditorDialog* dlg = CreateEditorDialog();
2478 #if wxUSE_VALIDATORS
2479 wxValidator* validator = GetValidator();
2480 wxPGInDialogValidator dialogValidator;
2481 #endif
2482
2483 wxPGArrayStringEditorDialog* strEdDlg = wxDynamicCast(dlg, wxPGArrayStringEditorDialog);
2484
2485 if ( strEdDlg )
2486 strEdDlg->SetCustomButton(cbt, this);
2487
2488 dlg->SetDialogValue( useValue );
2489 dlg->Create(propGrid, wxEmptyString, m_label);
2490
2491 #if !wxPG_SMALL_SCREEN
2492 dlg->Move( propGrid->GetGoodEditorDialogPosition(this,dlg->GetSize()) );
2493 #endif
2494
2495 bool retVal;
2496
2497 for (;;)
2498 {
2499 retVal = false;
2500
2501 int res = dlg->ShowModal();
2502
2503 if ( res == wxID_OK && dlg->IsModified() )
2504 {
2505 wxVariant value = dlg->GetDialogValue();
2506 if ( !value.IsNull() )
2507 {
2508 wxArrayString actualValue = value.GetArrayString();
2509 wxString tempStr;
2510 ConvertArrayToString(actualValue, &tempStr, m_delimiter);
2511 #if wxUSE_VALIDATORS
2512 if ( dialogValidator.DoValidate(propGrid, validator,
2513 tempStr) )
2514 #endif
2515 {
2516 SetValueInEvent( actualValue );
2517 retVal = true;
2518 break;
2519 }
2520 }
2521 else
2522 break;
2523 }
2524 else
2525 break;
2526 }
2527
2528 delete dlg;
2529
2530 return retVal;
2531 }
2532
2533 bool wxArrayStringProperty::OnEvent( wxPropertyGrid* propGrid,
2534 wxWindow* primary,
2535 wxEvent& event )
2536 {
2537 if ( propGrid->IsMainButtonEvent(event) )
2538 return OnButtonClick(propGrid,primary,(const wxChar*) NULL);
2539 return false;
2540 }
2541
2542 bool wxArrayStringProperty::StringToValue( wxVariant& variant,
2543 const wxString& text, int ) const
2544 {
2545 wxArrayString arr;
2546
2547 if ( m_delimiter == '"' || m_delimiter == '\'' )
2548 {
2549 // Quoted strings
2550 WX_PG_TOKENIZER2_BEGIN(text, m_delimiter)
2551
2552 // Need to replace backslashes with empty characters
2553 // (opposite what is done in ConvertArrayToString()).
2554 token.Replace ( wxS("\\\\"), wxS("\\"), true );
2555
2556 arr.Add( token );
2557
2558 WX_PG_TOKENIZER2_END()
2559 }
2560 else
2561 {
2562 // Regular delimiter
2563 WX_PG_TOKENIZER1_BEGIN(text, m_delimiter)
2564 arr.Add( token );
2565 WX_PG_TOKENIZER1_END()
2566 }
2567
2568 variant = arr;
2569
2570 return true;
2571 }
2572
2573 bool wxArrayStringProperty::DoSetAttribute( const wxString& name, wxVariant& value )
2574 {
2575 if ( name == wxPG_ARRAY_DELIMITER )
2576 {
2577 m_delimiter = value.GetChar();
2578 GenerateValueAsString();
2579 return false;
2580 }
2581 return true;
2582 }
2583
2584 // -----------------------------------------------------------------------
2585 // wxPGInDialogValidator
2586 // -----------------------------------------------------------------------
2587
2588 #if wxUSE_VALIDATORS
2589 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid* propGrid,
2590 wxValidator* validator,
2591 const wxString& value )
2592 {
2593 if ( !validator )
2594 return true;
2595
2596 wxTextCtrl* tc = m_textCtrl;
2597
2598 if ( !tc )
2599 {
2600 {
2601 tc = new wxTextCtrl( propGrid, wxPG_SUBID_TEMP1, wxEmptyString,
2602 wxPoint(30000,30000));
2603 tc->Hide();
2604 }
2605
2606 m_textCtrl = tc;
2607 }
2608
2609 tc->SetValue(value);
2610
2611 validator->SetWindow(tc);
2612 bool res = validator->Validate(propGrid);
2613
2614 return res;
2615 }
2616 #else
2617 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid* WXUNUSED(propGrid),
2618 wxValidator* WXUNUSED(validator),
2619 const wxString& WXUNUSED(value) )
2620 {
2621 return true;
2622 }
2623 #endif
2624
2625 // -----------------------------------------------------------------------
2626
2627 #endif // wxUSE_PROPGRID