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