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