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