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