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