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