]> git.saurik.com Git - wxWidgets.git/blame - src/propgrid/props.cpp
need to AdjustScrollbars() after changing the virtual size in CalcDimensions()
[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;
d665918b 1244 wxString label = GetLabel(i);
1c4293cb
VZ
1245
1246 #if wxUSE_INTL
1247 if ( wxPGGlobalVars->m_autoGetTranslation )
1248 {
d665918b 1249 boolProp = new wxBoolProperty( ::wxGetTranslation(label), label, child_val );
1c4293cb
VZ
1250 }
1251 else
1252 #endif
1253 {
d665918b 1254 boolProp = new wxBoolProperty( label, label, child_val );
1c4293cb
VZ
1255 }
1256 AddChild(boolProp);
1257 }
1258
1259 m_oldChoicesData = m_choices.GetDataPtr();
1260 }
1261
1262 m_oldValue = m_value;
1263
1264 if ( prevChildCount )
1265 SubPropsChanged(oldSel);
1266}
1267
1268wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
1269 const wxChar** labels, const long* values, long value ) : wxPGProperty(label,name)
1270{
1271 m_oldChoicesData = (wxPGChoicesData*) NULL;
1272
1273 if ( labels )
1274 {
1275 m_choices.Set(labels,values);
1276
1277 wxASSERT( GetItemCount() );
1278
1279 SetValue( value );
1280 }
1281 else
1282 {
1283 m_value = wxPGVariant_Zero;
1284 }
1285}
1286
1287wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
1288 const wxArrayString& labels, const wxArrayInt& values, int value )
1289 : wxPGProperty(label,name)
1290{
1291 m_oldChoicesData = (wxPGChoicesData*) NULL;
1292
1293 if ( &labels && labels.size() )
1294 {
1295 m_choices.Set(labels,values);
1296
1297 wxASSERT( GetItemCount() );
1298
1299 SetValue( (long)value );
1300 }
1301 else
1302 {
1303 m_value = wxPGVariant_Zero;
1304 }
1305}
1306
1307wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
1308 wxPGChoices& choices, long value )
1309 : wxPGProperty(label,name)
1310{
1311 m_oldChoicesData = (wxPGChoicesData*) NULL;
1312
1313 if ( choices.IsOk() )
1314 {
1315 m_choices.Assign(choices);
1316
1317 wxASSERT( GetItemCount() );
1318
1319 SetValue( value );
1320 }
1321 else
1322 {
1323 m_value = wxPGVariant_Zero;
1324 }
1325}
1326
1327wxFlagsProperty::~wxFlagsProperty()
1328{
1329}
1330
1331void wxFlagsProperty::OnSetValue()
1332{
1333 if ( !m_choices.IsOk() || !GetItemCount() )
1334 {
1335 m_value = wxPGVariant_Zero;
1336 }
1337 else
1338 {
1339 long val = m_value.GetLong();
1340
1341 long fullFlags = 0;
1342
1343 // normalize the value (i.e. remove extra flags)
1344 unsigned int i;
1345 const wxPGChoices& choices = m_choices;
1346 for ( i = 0; i < GetItemCount(); i++ )
1347 {
1348 if ( choices.HasValue(i) )
1349 fullFlags |= choices.GetValue(i);
1350 else
1351 fullFlags |= (1<<i);
1352 }
1353
1354 val &= fullFlags;
1355
1356 m_value = val;
1357
1358 // Need to (re)init now?
1359 if ( GetChildCount() != GetItemCount() ||
1360 m_choices.GetDataPtr() != m_oldChoicesData )
1361 {
1362 Init();
1363 }
1364 }
1365
1366 long newFlags = m_value;
1367
1368 if ( newFlags != m_oldValue )
1369 {
1370 // Set child modified states
1371 unsigned int i;
1372 const wxPGChoices& choices = m_choices;
1373 for ( i = 0; i<GetItemCount(); i++ )
1374 {
1375 int flag;
1376
1377 if ( choices.HasValue(i) )
1378 flag = choices.GetValue(i);
1379 else
1380 flag = (1<<i);
1381
1382 if ( (newFlags & flag) != (m_oldValue & flag) )
1383 Item(i)->SetFlag( wxPG_PROP_MODIFIED );
1384 }
1385
1386 m_oldValue = newFlags;
1387 }
1388}
1389
1390wxString wxFlagsProperty::GetValueAsString( int ) const
1391{
1392 wxString text;
1393
1394 if ( !m_choices.IsOk() )
1395 return text;
1396
1397 long flags = m_value;
1398 unsigned int i;
1399 const wxPGChoices& choices = m_choices;
1400
1401 for ( i = 0; i < GetItemCount(); i++ )
1402 {
1403 int doAdd;
1404 if ( choices.HasValue(i) )
1405 doAdd = ( flags & choices.GetValue(i) );
1406 else
1407 doAdd = ( flags & (1<<i) );
1408
1409 if ( doAdd )
1410 {
1411 text += choices.GetLabel(i);
1412 text += wxS(", ");
1413 }
1414 }
1415
1416 // remove last comma
1417 if ( text.Len() > 1 )
1418 text.Truncate ( text.Len() - 2 );
1419
1420 return text;
1421}
1422
1423// Translate string into flag tokens
1424bool wxFlagsProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
1425{
1426 if ( !m_choices.IsOk() )
1427 return false;
1428
1429 long newFlags = 0;
1430 long oldValue = m_value;
1431
1432 // semicolons are no longer valid delimeters
1433 WX_PG_TOKENIZER1_BEGIN(text,wxS(','))
1434
1435 if ( token.length() )
1436 {
1437 // Determine which one it is
1438 long bit = IdToBit( token );
1439
1440 if ( bit != -1 )
1441 {
1442 // Changed?
1443 newFlags |= bit;
1444 }
1445 else
1446 {
1447 break;
1448 }
1449 }
1450
1451 WX_PG_TOKENIZER1_END()
1452
1453 variant = newFlags;
1454
1455 if ( newFlags != oldValue )
1456 return true;
1457
1458 return false;
1459}
1460
1461// Converts string id to a relevant bit.
1462long wxFlagsProperty::IdToBit( const wxString& id ) const
1463{
1464 unsigned int i;
1465 for ( i = 0; i < GetItemCount(); i++ )
1466 {
1467 if ( id == GetLabel(i) )
1468 {
1469 if ( m_choices.HasValue(i) )
1470 return m_choices.GetValue(i);
1471 return (1<<i);
1472 }
1473 }
1474 return -1;
1475}
1476
1477void wxFlagsProperty::RefreshChildren()
1478{
1479 if ( !m_choices.IsOk() || !GetChildCount() ) return;
1480
1481 int flags = m_value.GetLong();
1482
1483 const wxPGChoices& choices = m_choices;
1484 unsigned int i;
1485 for ( i = 0; i < GetItemCount(); i++ )
1486 {
1487 long flag;
1488
1489 if ( choices.HasValue(i) )
1490 flag = choices.GetValue(i);
1491 else
1492 flag = (1<<i);
1493
1494 long subVal = flags & flag;
1495 wxPGProperty* p = Item(i);
1496
1497 if ( subVal != (m_oldValue & flag) )
1498 p->SetFlag( wxPG_PROP_MODIFIED );
1499
1500 p->SetValue( subVal?true:false );
1501 }
1502
1503 m_oldValue = flags;
1504}
1505
1506void wxFlagsProperty::ChildChanged( wxVariant& thisValue, int childIndex, wxVariant& childValue ) const
1507{
1508 long oldValue = thisValue.GetLong();
1509 long val = childValue.GetLong();
1510 unsigned long vi = (1<<childIndex);
1511 if ( m_choices.HasValue(childIndex) ) vi = m_choices.GetValue(childIndex);
1512 if ( val )
1513 thisValue = (long)(oldValue | vi);
1514 else
1515 thisValue = (long)(oldValue & ~(vi));
1516}
1517
1518int wxFlagsProperty::GetChoiceInfo( wxPGChoiceInfo* choiceinfo )
1519{
1520 if ( choiceinfo )
1521 choiceinfo->m_choices = &m_choices;
1522 return -1;
1523}
1524
1525// -----------------------------------------------------------------------
1526// wxDirProperty
1527// -----------------------------------------------------------------------
1528
1529WX_PG_IMPLEMENT_DERIVED_PROPERTY_CLASS(wxDirProperty,wxLongStringProperty,const wxString&)
1530
1531wxDirProperty::wxDirProperty( const wxString& name, const wxString& label, const wxString& value )
1532 : wxLongStringProperty(name,label,value)
1533{
1534 m_flags |= wxPG_NO_ESCAPE;
1535}
1536wxDirProperty::~wxDirProperty() { }
1537
1538wxValidator* wxDirProperty::DoGetValidator() const
1539{
1540 return wxFileProperty::GetClassValidator();
1541}
1542
1543bool wxDirProperty::OnButtonClick( wxPropertyGrid* propGrid, wxString& value )
1544{
1545 wxSize dlg_sz(300,400);
1546
1547 wxDirDialog dlg( propGrid,
1548 m_dlgMessage.length() ? m_dlgMessage : wxString(_("Choose a directory:")),
1549 value,
1550 0,
1551#if !wxPG_SMALL_SCREEN
1552 propGrid->GetGoodEditorDialogPosition(this,dlg_sz),
1553 dlg_sz );
1554#else
1555 wxDefaultPosition,
1556 wxDefaultSize );
1557#endif
1558
1559 if ( dlg.ShowModal() == wxID_OK )
1560 {
1561 value = dlg.GetPath();
1562 return true;
1563 }
1564 return false;
1565}
1566
1567bool wxDirProperty::DoSetAttribute( const wxString& name, wxVariant& value )
1568{
1569 if ( name == wxPG_DIR_DIALOG_MESSAGE )
1570 {
1571 m_dlgMessage = value.GetString();
1572 return true;
1573 }
1574 return false;
1575}
1576
1577// -----------------------------------------------------------------------
1578// wxPGFileDialogAdapter
1579// -----------------------------------------------------------------------
1580
1581bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid* propGrid, wxPGProperty* property )
1582{
1583 wxFileProperty* fileProp = NULL;
1584 wxString path;
1585 int indFilter = -1;
1586
1587 if ( property->IsKindOf(CLASSINFO(wxFileProperty)) )
1588 {
1589 fileProp = ((wxFileProperty*)property);
1590 path = fileProp->m_filename.GetPath();
1591 indFilter = fileProp->m_indFilter;
1592
1593 if ( !path.length() && fileProp->m_basePath.length() )
1594 path = fileProp->m_basePath;
1595 }
1596 else
1597 {
1598 wxFileName fn(property->GetValue().GetString());
1599 path = fn.GetPath();
1600 }
1601
1602 wxFileDialog dlg( propGrid->GetPanel(),
1603 property->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1604 property->GetAttribute(wxS("InitialPath"), path),
1605 wxEmptyString,
1606 property->GetAttribute(wxPG_FILE_WILDCARD, _("All files (*.*)|*.*")),
1607 0,
1608 wxDefaultPosition );
1609
1610 if ( indFilter >= 0 )
1611 dlg.SetFilterIndex( indFilter );
1612
1613 if ( dlg.ShowModal() == wxID_OK )
1614 {
1615 if ( fileProp )
1616 fileProp->m_indFilter = dlg.GetFilterIndex();
1617 SetValue( dlg.GetPath() );
1618 return true;
1619 }
1620 return false;
1621}
1622
1623// -----------------------------------------------------------------------
1624// wxFileProperty
1625// -----------------------------------------------------------------------
1626
1627WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty,wxPGProperty,
1628 wxString,const wxString&,TextCtrlAndButton)
1629
1630wxFileProperty::wxFileProperty( const wxString& label, const wxString& name,
1631 const wxString& value ) : wxPGProperty(label,name)
1632{
1633 m_flags |= wxPG_PROP_SHOW_FULL_FILENAME;
1634 m_indFilter = -1;
1635 SetAttribute( wxPG_FILE_WILDCARD, _("All files (*.*)|*.*") );
1636
1637 SetValue(value);
1638}
1639
1640wxFileProperty::~wxFileProperty() {}
1641
1642#if wxUSE_VALIDATORS
1643
1644wxValidator* wxFileProperty::GetClassValidator()
1645{
1646 WX_PG_DOGETVALIDATOR_ENTRY()
1647
1648 // Atleast wxPython 2.6.2.1 required that the string argument is given
1649 static wxString v;
1650 wxTextValidator* validator = new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST,&v);
1651
1652 wxArrayString exChars;
1653 exChars.Add(wxS("?"));
1654 exChars.Add(wxS("*"));
1655 exChars.Add(wxS("|"));
1656 exChars.Add(wxS("<"));
1657 exChars.Add(wxS(">"));
1658 exChars.Add(wxS("\""));
1659
1660 validator->SetExcludes(exChars);
1661
1662 WX_PG_DOGETVALIDATOR_EXIT(validator)
1663}
1664
1665wxValidator* wxFileProperty::DoGetValidator() const
1666{
1667 return GetClassValidator();
1668}
1669
1670#endif
1671
1672void wxFileProperty::OnSetValue()
1673{
1674 const wxString& fnstr = m_value.GetString();
1675
1676 m_filename = fnstr;
1677
1678 if ( !m_filename.HasName() )
1679 {
1680 m_value = wxPGVariant_EmptyString;
1681 m_filename.Clear();
1682 }
1683
1684 // Find index for extension.
1685 if ( m_indFilter < 0 && fnstr.length() )
1686 {
1687 wxString ext = m_filename.GetExt();
1688 int curind = 0;
1689 size_t pos = 0;
1690 size_t len = m_wildcard.length();
1691
1692 pos = m_wildcard.find(wxS("|"), pos);
1693 while ( pos != wxString::npos && pos < (len-3) )
1694 {
1695 size_t ext_begin = pos + 3;
1696
1697 pos = m_wildcard.find(wxS("|"), ext_begin);
1698 if ( pos == wxString::npos )
1699 pos = len;
1700 wxString found_ext = m_wildcard.substr(ext_begin, pos-ext_begin);
1701
1702 if ( found_ext.length() > 0 )
1703 {
1704 if ( found_ext[0] == wxS('*') )
1705 {
1706 m_indFilter = curind;
1707 break;
1708 }
1709 if ( ext.CmpNoCase(found_ext) == 0 )
1710 {
1711 m_indFilter = curind;
1712 break;
1713 }
1714 }
1715
1716 if ( pos != len )
1717 pos = m_wildcard.find(wxS("|"), pos+1);
1718
1719 curind++;
1720 }
1721 }
1722}
1723
1724wxString wxFileProperty::GetValueAsString( int argFlags ) const
1725{
1726 // Always return empty string when name component is empty
1727 wxString fullName = m_filename.GetFullName();
1728 if ( !fullName.length() )
1729 return fullName;
1730
1731 if ( argFlags & wxPG_FULL_VALUE )
1732 {
1733 return m_filename.GetFullPath();
1734 }
1735 else if ( m_flags & wxPG_PROP_SHOW_FULL_FILENAME )
1736 {
1737 if ( m_basePath.Length() )
1738 {
1739 wxFileName fn2(m_filename);
1740 fn2.MakeRelativeTo(m_basePath);
1741 return fn2.GetFullPath();
1742 }
1743 return m_filename.GetFullPath();
1744 }
1745
1746 return m_filename.GetFullName();
1747}
1748
1749wxPGEditorDialogAdapter* wxFileProperty::GetEditorDialog() const
1750{
1751 return new wxPGFileDialogAdapter();
1752}
1753
1754bool wxFileProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
1755{
1756 if ( (m_flags & wxPG_PROP_SHOW_FULL_FILENAME) || (argFlags & wxPG_FULL_VALUE) )
1757 {
1758 if ( m_filename != text )
1759 {
1760 variant = text;
1761 return true;
1762 }
1763 }
1764 else
1765 {
1766 if ( m_filename.GetFullName() != text )
1767 {
1768 wxFileName fn = m_filename;
1769 fn.SetFullName(text);
1770 variant = fn.GetFullPath();
1771 return true;
1772 }
1773 }
1774
1775 return false;
1776}
1777
1778bool wxFileProperty::DoSetAttribute( const wxString& name, wxVariant& value )
1779{
1780 // Return false on some occasions to make sure those attribs will get
1781 // stored in m_attributes.
1782 if ( name == wxPG_FILE_SHOW_FULL_PATH )
1783 {
1784 if ( wxPGVariantToInt(value) )
1785 m_flags |= wxPG_PROP_SHOW_FULL_FILENAME;
1786 else
1787 m_flags &= ~(wxPG_PROP_SHOW_FULL_FILENAME);
1788 return true;
1789 }
1790 else if ( name == wxPG_FILE_WILDCARD )
1791 {
1792 m_wildcard = value.GetString();
1793 }
1794 else if ( name == wxPG_FILE_SHOW_RELATIVE_PATH )
1795 {
1796 m_basePath = value.GetString();
1797
1798 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1799 m_flags |= wxPG_PROP_SHOW_FULL_FILENAME;
1800 }
1801 else if ( name == wxPG_FILE_INITIAL_PATH )
1802 {
1803 m_initialPath = value.GetString();
1804 return true;
1805 }
1806 else if ( name == wxPG_FILE_DIALOG_TITLE )
1807 {
1808 m_dlgTitle = value.GetString();
1809 return true;
1810 }
1811 return false;
1812}
1813
1814// -----------------------------------------------------------------------
1815// wxPGLongStringDialogAdapter
1816// -----------------------------------------------------------------------
1817
1818bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid* propGrid, wxPGProperty* property )
1819{
1820 wxString val1 = property->GetValueAsString(0);
1821 wxString val_orig = val1;
1822
1823 wxString value;
1824 if ( !property->HasFlag(wxPG_PROP_NO_ESCAPE) )
1825 wxPropertyGrid::ExpandEscapeSequences(value, val1);
1826 else
1827 value = wxString(val1);
1828
1829 // Run editor dialog.
1830 if ( wxLongStringProperty::DisplayEditorDialog(property, propGrid, value) )
1831 {
1832 if ( !property->HasFlag(wxPG_PROP_NO_ESCAPE) )
1833 wxPropertyGrid::CreateEscapeSequences(val1,value);
1834 else
1835 val1 = value;
1836
1837 if ( val1 != val_orig )
1838 {
1839 SetValue( val1 );
1840 return true;
1841 }
1842 }
1843 return false;
1844}
1845
1846// -----------------------------------------------------------------------
1847// wxLongStringProperty
1848// -----------------------------------------------------------------------
1849
1850WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty,wxPGProperty,
1851 wxString,const wxString&,TextCtrlAndButton)
1852
1853wxLongStringProperty::wxLongStringProperty( const wxString& label, const wxString& name,
1854 const wxString& value ) : wxPGProperty(label,name)
1855{
1856 SetValue(value);
1857}
1858
1859wxLongStringProperty::~wxLongStringProperty() {}
1860
1861wxString wxLongStringProperty::GetValueAsString( int ) const
1862{
1863 return m_value;
1864}
1865
1866bool wxLongStringProperty::OnEvent( wxPropertyGrid* propGrid, wxWindow* WXUNUSED(primary),
1867 wxEvent& event )
1868{
1869 if ( propGrid->IsMainButtonEvent(event) )
1870 {
1871 // Update the value
1872 PrepareValueForDialogEditing(propGrid);
1873
1874 wxString val1 = GetValueAsString(0);
1875 wxString val_orig = val1;
1876
1877 wxString value;
1878 if ( !(m_flags & wxPG_PROP_NO_ESCAPE) )
1879 wxPropertyGrid::ExpandEscapeSequences(value,val1);
1880 else
1881 value = wxString(val1);
1882
1883 // Run editor dialog.
1884 if ( OnButtonClick(propGrid,value) )
1885 {
1886 if ( !(m_flags & wxPG_PROP_NO_ESCAPE) )
1887 wxPropertyGrid::CreateEscapeSequences(val1,value);
1888 else
1889 val1 = value;
1890
1891 if ( val1 != val_orig )
1892 {
1893 SetValueInEvent( val1 );
1894 return true;
1895 }
1896 }
1897 }
1898 return false;
1899}
1900
1901bool wxLongStringProperty::OnButtonClick( wxPropertyGrid* propGrid, wxString& value )
1902{
1903 return DisplayEditorDialog(this, propGrid, value);
1904}
1905
1906bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty* prop, wxPropertyGrid* propGrid, wxString& value )
1907
1908{
1909 // launch editor dialog
1910 wxDialog* dlg = new wxDialog(propGrid,-1,prop->GetLabel(),wxDefaultPosition,wxDefaultSize,
1911 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxCLIP_CHILDREN);
1912
1913 dlg->SetFont(propGrid->GetFont()); // To allow entering chars of the same set as the propGrid
1914
1915 // Multi-line text editor dialog.
1916#if !wxPG_SMALL_SCREEN
1917 const int spacing = 8;
1918#else
1919 const int spacing = 4;
1920#endif
1921 wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL );
1922 wxBoxSizer* rowsizer = new wxBoxSizer( wxHORIZONTAL );
1923 wxTextCtrl* ed = new wxTextCtrl(dlg,11,value,
1924 wxDefaultPosition,wxDefaultSize,wxTE_MULTILINE);
1925
1926 rowsizer->Add( ed, 1, wxEXPAND|wxALL, spacing );
1927 topsizer->Add( rowsizer, 1, wxEXPAND, 0 );
1928 rowsizer = new wxBoxSizer( wxHORIZONTAL );
1929 const int but_sz_flags =
1930 wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT;
1931 rowsizer->Add( new wxButton(dlg,wxID_OK,_("Ok")),
1932 0, but_sz_flags, spacing );
1933 rowsizer->Add( new wxButton(dlg,wxID_CANCEL,_("Cancel")),
1934 0, but_sz_flags, spacing );
1935 topsizer->Add( rowsizer, 0, wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL, 0 );
1936
1937 dlg->SetSizer( topsizer );
1938 topsizer->SetSizeHints( dlg );
1939
1940#if !wxPG_SMALL_SCREEN
1941 dlg->SetSize(400,300);
1942
1943 dlg->Move( propGrid->GetGoodEditorDialogPosition(prop,dlg->GetSize()) );
1944#endif
1945
1946 int res = dlg->ShowModal();
1947
1948 if ( res == wxID_OK )
1949 {
1950 value = ed->GetValue();
1951 dlg->Destroy();
1952 return true;
1953 }
1954 dlg->Destroy();
1955 return false;
1956}
1957
1958bool wxLongStringProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
1959{
1960 if ( m_value != text )
1961 {
1962 variant = text;
1963 return true;
1964 }
1965 return false;
1966}
1967
1968// -----------------------------------------------------------------------
1969// wxArrayEditorDialog
1970// -----------------------------------------------------------------------
1971
1972BEGIN_EVENT_TABLE(wxArrayEditorDialog, wxDialog)
1973 EVT_IDLE(wxArrayEditorDialog::OnIdle)
1974 EVT_LISTBOX(24, wxArrayEditorDialog::OnListBoxClick)
1975 EVT_TEXT_ENTER(21, wxArrayEditorDialog::OnAddClick)
1976 EVT_BUTTON(22, wxArrayEditorDialog::OnAddClick)
1977 EVT_BUTTON(23, wxArrayEditorDialog::OnDeleteClick)
1978 EVT_BUTTON(25, wxArrayEditorDialog::OnUpClick)
1979 EVT_BUTTON(26, wxArrayEditorDialog::OnDownClick)
1980 EVT_BUTTON(27, wxArrayEditorDialog::OnUpdateClick)
1981 //EVT_BUTTON(28, wxArrayEditorDialog::OnCustomEditClick)
1982END_EVENT_TABLE()
1983
1984IMPLEMENT_ABSTRACT_CLASS(wxArrayEditorDialog, wxDialog)
1985
1986#include <wx/statline.h>
1987
1988// -----------------------------------------------------------------------
1989
1990void wxArrayEditorDialog::OnIdle(wxIdleEvent& event)
1991{
1992 //
1993 // Do control focus detection here.
1994 //
1995
1996 wxWindow* focused = FindFocus();
1997
1998 // This strange focus thing is a workaround for wxGTK wxListBox focus
1999 // reporting bug.
2000 if ( m_curFocus == 0 && focused != m_edValue &&
2001 focused != m_butAdd && focused != m_butUpdate &&
2002 m_lbStrings->GetSelection() >= 0 )
2003 {
2004 // ListBox was just focused.
2005 m_butAdd->Enable(false);
2006 m_butUpdate->Enable(false);
2007 m_butRemove->Enable(true);
2008 m_butUp->Enable(true);
2009 m_butDown->Enable(true);
2010 m_curFocus = 1;
2011 }
2012 else if ( (m_curFocus == 1 && focused == m_edValue) /*|| m_curFocus == 2*/ )
2013 {
2014 // TextCtrl was just focused.
2015 m_butAdd->Enable(true);
2016 bool upd_enable = false;
2017 if ( m_lbStrings->GetCount() && m_lbStrings->GetSelection() >= 0 )
2018 upd_enable = true;
2019 m_butUpdate->Enable(upd_enable);
2020 m_butRemove->Enable(false);
2021 m_butUp->Enable(false);
2022 m_butDown->Enable(false);
2023 m_curFocus = 0;
2024 }
2025
2026 event.Skip();
2027}
2028
2029// -----------------------------------------------------------------------
2030
2031wxArrayEditorDialog::wxArrayEditorDialog()
2032 : wxDialog()
2033{
2034 Init();
2035}
2036
2037// -----------------------------------------------------------------------
2038
2039void wxArrayEditorDialog::Init()
2040{
2041 m_custBtText = (const wxChar*) NULL;
2042}
2043
2044// -----------------------------------------------------------------------
2045
2046wxArrayEditorDialog::wxArrayEditorDialog( wxWindow *parent,
2047 const wxString& message,
2048 const wxString& caption,
2049 long style,
2050 const wxPoint& pos,
2051 const wxSize& sz )
2052 : wxDialog()
2053{
2054 Init();
2055 Create(parent,message,caption,style,pos,sz);
2056}
2057
2058// -----------------------------------------------------------------------
2059
2060bool wxArrayEditorDialog::Create( wxWindow *parent,
2061 const wxString& message,
2062 const wxString& caption,
2063 long style,
2064 const wxPoint& pos,
2065 const wxSize& sz )
2066{
2067 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2068 // FIXME: This should be only a temporary fix.
2069#ifdef __WXMAC__
2070 int useStyle = wxCAPTION;
2071#else
2072 int useStyle = style;
2073#endif
2074
2075 bool res = wxDialog::Create(parent, wxID_ANY, caption, pos, sz, useStyle);
2076
2077 SetFont(parent->GetFont()); // To allow entering chars of the same set as the propGrid
2078
2079#if !wxPG_SMALL_SCREEN
2080 const int spacing = 4;
2081#else
2082 const int spacing = 3;
2083#endif
2084
2085 m_modified = false;
2086
2087 m_curFocus = 1;
2088
2089 const int but_sz_flags =
2090 wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxALL; //wxBOTTOM|wxLEFT|wxRIGHT;
2091
2092 wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL );
2093
2094 // Message
2095 if ( message.length() )
2096 topsizer->Add( new wxStaticText(this,-1,message),
2097 0, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxALL, spacing );
2098
2099 // String editor
2100 wxBoxSizer* rowsizer = new wxBoxSizer( wxHORIZONTAL );
2101 m_edValue = new wxTextCtrl(this,21,wxEmptyString,
2102 wxDefaultPosition,wxDefaultSize,wxTE_PROCESS_ENTER);
2103 wxValidator* validator = GetTextCtrlValidator();
2104 if ( validator )
2105 {
2106 m_edValue->SetValidator( *validator );
2107 delete validator;
2108 }
2109 rowsizer->Add( m_edValue,
2110 1, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxALL, spacing );
2111
2112 // Add button
2113 m_butAdd = new wxButton(this,22,_("Add"));
2114 rowsizer->Add( m_butAdd,
2115 0, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, spacing );
2116 topsizer->Add( rowsizer, 0, wxEXPAND, spacing );
2117
2118 // Separator line
2119 topsizer->Add( new wxStaticLine(this,-1),
2120 0, wxEXPAND|wxBOTTOM|wxLEFT|wxRIGHT, spacing );
2121
2122 rowsizer = new wxBoxSizer( wxHORIZONTAL );
2123
2124 // list box
2125 m_lbStrings = new wxListBox(this, 24, wxDefaultPosition, wxDefaultSize);
2126 unsigned int i;
2127 for ( i=0; i<ArrayGetCount(); i++ )
2128 m_lbStrings->Append( ArrayGet(i) );
2129 rowsizer->Add( m_lbStrings, 1, wxEXPAND|wxRIGHT, spacing );
2130
2131 // Manipulator buttons
2132 wxBoxSizer* colsizer = new wxBoxSizer( wxVERTICAL );
2133 m_butCustom = (wxButton*) NULL;
2134 if ( m_custBtText )
2135 {
2136 m_butCustom = new wxButton(this,28,::wxGetTranslation(m_custBtText));
2137 colsizer->Add( m_butCustom,
2138 0, wxALIGN_CENTER|wxTOP/*wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT*/,
2139 spacing );
2140 }
2141 m_butUpdate = new wxButton(this,27,_("Update"));
2142 colsizer->Add( m_butUpdate,
2143 0, wxALIGN_CENTER|wxTOP, spacing );
2144 m_butRemove = new wxButton(this,23,_("Remove"));
2145 colsizer->Add( m_butRemove,
2146 0, wxALIGN_CENTER|wxTOP, spacing );
2147 m_butUp = new wxButton(this,25,_("Up"));
2148 colsizer->Add( m_butUp,
2149 0, wxALIGN_CENTER|wxTOP, spacing );
2150 m_butDown = new wxButton(this,26,_("Down"));
2151 colsizer->Add( m_butDown,
2152 0, wxALIGN_CENTER|wxTOP, spacing );
2153 rowsizer->Add( colsizer, 0, 0, spacing );
2154
2155 topsizer->Add( rowsizer, 1, wxLEFT|wxRIGHT|wxEXPAND, spacing );
2156
2157 // Separator line
2158 topsizer->Add( new wxStaticLine(this,-1),
2159 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, spacing );
2160
2161 // buttons
2162 rowsizer = new wxBoxSizer( wxHORIZONTAL );
2163 /*
2164 const int but_sz_flags =
2165 wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT;
2166 */
2167 rowsizer->Add( new wxButton(this,wxID_OK,_("Ok")),
2168 0, but_sz_flags, spacing );
2169 rowsizer->Add( new wxButton(this,wxID_CANCEL,_("Cancel")),
2170 0, but_sz_flags, spacing );
2171 topsizer->Add( rowsizer, 0, wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL, 0 );
2172
2173 m_edValue->SetFocus();
2174
2175 SetSizer( topsizer );
2176 topsizer->SetSizeHints( this );
2177
2178#if !wxPG_SMALL_SCREEN
2179 if ( sz.x == wxDefaultSize.x &&
2180 sz.y == wxDefaultSize.y )
2181 SetSize( wxSize(275,360) );
2182 else
2183 SetSize(sz);
2184#endif
2185
2186 return res;
2187}
2188
2189// -----------------------------------------------------------------------
2190
2191void wxArrayEditorDialog::OnAddClick(wxCommandEvent& )
2192{
2193 wxString text = m_edValue->GetValue();
2194 if ( text.length() )
2195 {
2196 if ( ArrayInsert( text, -1 ) )
2197 {
2198 m_lbStrings->Append( text );
2199 m_modified = true;
2200 m_edValue->Clear();
2201 }
2202 }
2203}
2204
2205// -----------------------------------------------------------------------
2206
2207void wxArrayEditorDialog::OnDeleteClick(wxCommandEvent& )
2208{
2209 int index = m_lbStrings->GetSelection();
2210 if ( index >= 0 )
2211 {
2212 ArrayRemoveAt( index );
2213 m_lbStrings->Delete ( index );
2214 m_modified = true;
2215 }
2216}
2217
2218// -----------------------------------------------------------------------
2219
2220void wxArrayEditorDialog::OnUpClick(wxCommandEvent& )
2221{
2222 int index = m_lbStrings->GetSelection();
2223 if ( index > 0 )
2224 {
2225 ArraySwap(index-1,index);
2226 /*wxString old_str = m_array[index-1];
2227 wxString new_str = m_array[index];
2228 m_array[index-1] = new_str;
2229 m_array[index] = old_str;*/
2230 m_lbStrings->SetString ( index-1, ArrayGet(index-1) );
2231 m_lbStrings->SetString ( index, ArrayGet(index) );
2232 m_lbStrings->SetSelection ( index-1 );
2233 m_modified = true;
2234 }
2235}
2236
2237// -----------------------------------------------------------------------
2238
2239void wxArrayEditorDialog::OnDownClick(wxCommandEvent& )
2240{
2241 int index = m_lbStrings->GetSelection();
2242 int lastStringIndex = ((int) m_lbStrings->GetCount()) - 1;
2243 if ( index >= 0 && index < lastStringIndex )
2244 {
2245 ArraySwap(index,index+1);
2246 /*wxString old_str = m_array[index+1];
2247 wxString new_str = m_array[index];
2248 m_array[index+1] = new_str;
2249 m_array[index] = old_str;*/
2250 m_lbStrings->SetString ( index+1, ArrayGet(index+1) );
2251 m_lbStrings->SetString ( index, ArrayGet(index) );
2252 m_lbStrings->SetSelection ( index+1 );
2253 m_modified = true;
2254 }
2255}
2256
2257// -----------------------------------------------------------------------
2258
2259void wxArrayEditorDialog::OnUpdateClick(wxCommandEvent& )
2260{
2261 int index = m_lbStrings->GetSelection();
2262 if ( index >= 0 )
2263 {
2264 wxString str = m_edValue->GetValue();
2265 if ( ArraySet(index,str) )
2266 {
2267 m_lbStrings->SetString ( index, str );
2268 //m_array[index] = str;
2269 m_modified = true;
2270 }
2271 }
2272}
2273
2274// -----------------------------------------------------------------------
2275
2276void wxArrayEditorDialog::OnListBoxClick(wxCommandEvent& )
2277{
2278 int index = m_lbStrings->GetSelection();
2279 if ( index >= 0 )
2280 {
2281 m_edValue->SetValue( m_lbStrings->GetString(index) );
2282 }
2283}
2284
2285// -----------------------------------------------------------------------
2286// wxPGArrayStringEditorDialog
2287// -----------------------------------------------------------------------
2288
2289IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog, wxArrayEditorDialog)
2290
2291BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog, wxArrayEditorDialog)
2292 EVT_BUTTON(28, wxPGArrayStringEditorDialog::OnCustomEditClick)
2293END_EVENT_TABLE()
2294
2295// -----------------------------------------------------------------------
2296
2297wxString wxPGArrayStringEditorDialog::ArrayGet( size_t index )
2298{
2299 return m_array[index];
2300}
2301
2302size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2303{
2304 return m_array.size();
2305}
2306
2307bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString& str, int index )
2308{
2309 if (index<0)
2310 m_array.Add(str);
2311 else
2312 m_array.Insert(str,index);
2313 return true;
2314}
2315
2316bool wxPGArrayStringEditorDialog::ArraySet( size_t index, const wxString& str )
2317{
2318 m_array[index] = str;
2319 return true;
2320}
2321
2322void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index )
2323{
2324 m_array.RemoveAt(index);
2325}
2326
2327void wxPGArrayStringEditorDialog::ArraySwap( size_t first, size_t second )
2328{
2329 wxString old_str = m_array[first];
2330 wxString new_str = m_array[second];
2331 m_array[first] = new_str;
2332 m_array[second] = old_str;
2333}
2334
2335wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2336 : wxArrayEditorDialog()
2337{
2338 Init();
2339}
2340
2341void wxPGArrayStringEditorDialog::Init()
2342{
2343 m_pCallingClass = (wxArrayStringProperty*) NULL;
2344}
2345
2346void wxPGArrayStringEditorDialog::OnCustomEditClick(wxCommandEvent& )
2347{
2348 wxASSERT( m_pCallingClass );
2349 wxString str = m_edValue->GetValue();
2350 if ( m_pCallingClass->OnCustomStringEdit(m_parent,str) )
2351 {
2352 //m_edValue->SetValue ( str );
2353 m_lbStrings->Append ( str );
2354 m_array.Add ( str );
2355 m_modified = true;
2356 }
2357}
2358
2359// -----------------------------------------------------------------------
2360// wxArrayStringProperty
2361// -----------------------------------------------------------------------
2362
2363WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty, // Property name
2364 wxPGProperty, // Property we inherit from
2365 wxArrayString, // Value type name
2366 const wxArrayString&, // Value type, as given in constructor
2367 TextCtrlAndButton) // Initial editor
2368
2369wxArrayStringProperty::wxArrayStringProperty( const wxString& label,
2370 const wxString& name,
2371 const wxArrayString& array )
2372 : wxPGProperty(label,name)
2373{
2374 SetValue( array );
2375}
2376
2377wxArrayStringProperty::~wxArrayStringProperty() { }
2378
2379void wxArrayStringProperty::OnSetValue()
2380{
2381 GenerateValueAsString();
2382}
2383
2384wxString wxArrayStringProperty::GetValueAsString( int WXUNUSED(argFlags) ) const
2385{
2386 return m_display;
2387}
2388
2389// Converts wxArrayString to a string separated by delimeters and spaces.
2390// preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2391// conversion.
2392void wxPropertyGrid::ArrayStringToString( wxString& dst, const wxArrayString& src,
2393 wxChar preDelim, wxChar postDelim,
2394 int flags )
2395{
2396 wxString pdr;
2397
2398 unsigned int i;
2399 unsigned int itemCount = src.size();
2400
2401 wxChar preas[2];
2402
2403 dst.Empty();
2404
2405 if ( !preDelim )
2406 preas[0] = 0;
2407 else if ( (flags & 1) )
2408 {
2409 preas[0] = preDelim;
2410 preas[1] = 0;
2411 pdr = wxS("\\");
2412 pdr += preDelim;
2413 }
2414
2415 if ( itemCount )
2416 dst.append( preas );
2417
2418 wxASSERT( postDelim );
2419 wxString postDelimStr(postDelim);
2420 //wxString preDelimStr(preDelim);
2421
2422 for ( i = 0; i < itemCount; i++ )
2423 {
2424 wxString str( src.Item(i) );
2425
2426 // Do some character conversion.
2427 // Convertes \ to \\ and <preDelim> to \<preDelim>
2428 // Useful when preDelim and postDelim are "\"".
2429 if ( flags & 1 )
2430 {
2431 str.Replace( wxS("\\"), wxS("\\\\"), true );
2432 if ( pdr.length() )
2433 str.Replace( preas, pdr, true );
2434 }
2435
2436 dst.append( str );
2437
2438 if ( i < (itemCount-1) )
2439 {
2440 dst.append( postDelimStr );
2441 dst.append( wxS(" ") );
2442 dst.append( preas );
2443 }
2444 else if ( preDelim )
2445 dst.append( postDelimStr );
2446 }
2447}
2448
2449#define ARRSTRPROP_ARRAY_TO_STRING(STRING,ARRAY) \
2450 wxPropertyGrid::ArrayStringToString(STRING,ARRAY,wxS('"'),wxS('"'),1);
2451
2452void wxArrayStringProperty::GenerateValueAsString()
2453{
2454 wxArrayString arr = m_value.GetArrayString();
2455 ARRSTRPROP_ARRAY_TO_STRING(m_display, arr)
2456}
2457
2458// Default implementation doesn't do anything.
2459bool wxArrayStringProperty::OnCustomStringEdit( wxWindow*, wxString& )
2460{
2461 return false;
2462}
2463
2464wxArrayEditorDialog* wxArrayStringProperty::CreateEditorDialog()
2465{
2466 return new wxPGArrayStringEditorDialog();
2467}
2468
2469bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid* propGrid,
2470 wxWindow* WXUNUSED(primaryCtrl),
2471 const wxChar* cbt )
2472{
2473 // Update the value
2474 PrepareValueForDialogEditing(propGrid);
2475
2476 if ( !propGrid->EditorValidate() )
2477 return false;
2478
2479 // Create editor dialog.
2480 wxArrayEditorDialog* dlg = CreateEditorDialog();
2481#if wxUSE_VALIDATORS
2482 wxValidator* validator = GetValidator();
2483 wxPGInDialogValidator dialogValidator;
2484#endif
2485
2486 wxPGArrayStringEditorDialog* strEdDlg = wxDynamicCast(dlg, wxPGArrayStringEditorDialog);
2487
2488 if ( strEdDlg )
2489 strEdDlg->SetCustomButton(cbt, this);
2490
2491 dlg->SetDialogValue( wxVariant(m_value) );
2492 dlg->Create(propGrid, wxEmptyString, m_label);
2493
2494#if !wxPG_SMALL_SCREEN
2495 dlg->Move( propGrid->GetGoodEditorDialogPosition(this,dlg->GetSize()) );
2496#endif
2497
2498 bool retVal;
2499
2500 for (;;)
2501 {
2502 retVal = false;
2503
2504 int res = dlg->ShowModal();
2505
2506 if ( res == wxID_OK && dlg->IsModified() )
2507 {
2508 wxVariant value = dlg->GetDialogValue();
2509 if ( !value.IsNull() )
2510 {
2511 wxArrayString actualValue = value.GetArrayString();
2512 wxString tempStr;
2513 ARRSTRPROP_ARRAY_TO_STRING(tempStr, actualValue)
2514 #if wxUSE_VALIDATORS
2515 if ( dialogValidator.DoValidate( propGrid, validator, tempStr ) )
2516 #endif
2517 {
2518 SetValueInEvent( actualValue );
2519 retVal = true;
2520 break;
2521 }
2522 }
2523 else
2524 break;
2525 }
2526 else
2527 break;
2528 }
2529
2530 delete dlg;
2531
2532 return retVal;
2533}
2534
2535bool wxArrayStringProperty::OnEvent( wxPropertyGrid* propGrid,
2536 wxWindow* primary,
2537 wxEvent& event )
2538{
2539 if ( propGrid->IsMainButtonEvent(event) )
2540 return OnButtonClick(propGrid,primary,(const wxChar*) NULL);
2541 return false;
2542}
2543
2544bool wxArrayStringProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
2545{
2546 wxArrayString arr;
2547
2548 WX_PG_TOKENIZER2_BEGIN(text,wxS('"'))
2549
2550 // Need to replace backslashes with empty characters
2551 // (opposite what is done in GenerateValueString).
2552 token.Replace ( wxS("\\"), wxEmptyString, true );
2553
2554 arr.Add( token );
2555
2556 WX_PG_TOKENIZER2_END()
2557
2558 variant = arr;
2559
2560 return true;
2561}
2562
2563// -----------------------------------------------------------------------
2564// wxPGInDialogValidator
2565// -----------------------------------------------------------------------
2566
2567#if wxUSE_VALIDATORS
2568bool wxPGInDialogValidator::DoValidate( wxPropertyGrid* propGrid,
2569 wxValidator* validator,
2570 const wxString& value )
2571{
2572 if ( !validator )
2573 return true;
2574
2575 wxTextCtrl* tc = m_textCtrl;
2576
2577 if ( !tc )
2578 {
2579 {
2580 tc = new wxTextCtrl( propGrid, wxPG_SUBID_TEMP1, wxEmptyString,
2581 wxPoint(30000,30000));
2582 tc->Hide();
2583 }
2584
2585 m_textCtrl = tc;
2586 }
2587
2588 tc->SetValue(value);
2589
2590 validator->SetWindow(tc);
2591 bool res = validator->Validate(propGrid);
2592
2593 return res;
2594}
2595#else
2596bool wxPGInDialogValidator::DoValidate( wxPropertyGrid* WXUNUSED(propGrid),
2597 wxValidator* WXUNUSED(validator),
2598 const wxString& WXUNUSED(value) )
2599{
2600 return true;
2601}
2602#endif
2603
2604// -----------------------------------------------------------------------
2605