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