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