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