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