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