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