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