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