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