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