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