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