]> git.saurik.com Git - wxWidgets.git/blame - src/propgrid/props.cpp
Don't use a cached best size if the window has a sizer
[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;
c82a80e8 82 DoGenerateComposedValue(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
c82a80e8 104 DoGenerateComposedValue(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
b7bc9d80 203 for ( ; i != iMax; ++i )
1c4293cb
VZ
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
b7bc9d80 609 for ( ; i != target.begin(); --i )
1c4293cb
VZ
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),
d3b9f782 635 NULL);
1c4293cb
VZ
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// -----------------------------------------------------------------------
78f2d746 881// wxEnumProperty
1c4293cb
VZ
882// -----------------------------------------------------------------------
883
78f2d746
JS
884IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty, wxPGProperty)
885
886WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty,long,Choice)
887
888wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name, const wxChar** labels,
889 const long* values, int value ) : wxPGProperty(label,name)
890{
891 SetIndex(0);
892
893 if ( labels )
894 {
895 m_choices.Add(labels,values);
896
897 if ( GetItemCount() )
898 SetValue( (long)value );
899 }
900}
901
902wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name, const wxChar** labels,
903 const long* values, wxPGChoices* choicesCache, int value )
904 : wxPGProperty(label,name)
905{
906 SetIndex(0);
907
908 wxASSERT( choicesCache );
909
910 if ( choicesCache->IsOk() )
911 {
912 m_choices.Assign( *choicesCache );
913 m_value = wxPGVariant_Zero;
914 }
915 else if ( labels )
916 {
917 m_choices.Add(labels,values);
918
919 if ( GetItemCount() )
920 SetValue( (long)value );
921 }
922}
923
924wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name,
925 const wxArrayString& labels, const wxArrayInt& values, int value )
926 : wxPGProperty(label,name)
927{
928 SetIndex(0);
929
930 if ( &labels && labels.size() )
931 {
932 m_choices.Set(labels, values);
933
934 if ( GetItemCount() )
935 SetValue( (long)value );
936 }
937}
1c4293cb 938
78f2d746
JS
939wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name,
940 wxPGChoices& choices, int value )
1c4293cb
VZ
941 : wxPGProperty(label,name)
942{
78f2d746
JS
943 m_choices.Assign( choices );
944
945 if ( GetItemCount() )
946 SetValue( (long)value );
1c4293cb
VZ
947}
948
78f2d746 949int wxEnumProperty::GetIndexForValue( int value ) const
1c4293cb 950{
78f2d746
JS
951 if ( !m_choices.IsOk() )
952 return -1;
953
954 int intVal = m_choices.Index(value);
955 if ( intVal >= 0 )
956 return intVal;
957
1c4293cb
VZ
958 return value;
959}
960
78f2d746
JS
961wxEnumProperty::~wxEnumProperty ()
962{
963}
964
965int wxEnumProperty::ms_nextIndex = -2;
d8812c6e 966int wxEnumProperty::ms_prevIndex = -1;
78f2d746
JS
967
968void wxEnumProperty::OnSetValue()
1c4293cb 969{
0372d42e
JS
970 wxString variantType = m_value.GetType();
971
972 if ( variantType == wxPG_VARIANT_TYPE_LONG )
1c4293cb 973 ValueFromInt_( m_value, m_value.GetLong(), wxPG_FULL_VALUE );
0372d42e 974 else if ( variantType == wxPG_VARIANT_TYPE_STRING )
1c4293cb
VZ
975 ValueFromString_( m_value, m_value.GetString(), 0 );
976 else
b7bc9d80 977 wxFAIL;
1c4293cb
VZ
978
979 if ( ms_nextIndex != -2 )
980 {
981 m_index = ms_nextIndex;
982 ms_nextIndex = -2;
983 }
984}
985
78f2d746 986bool wxEnumProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& WXUNUSED(validationInfo) ) const
1c4293cb
VZ
987{
988 // Make sure string value is in the list,
989 // unless property has string as preferred value type
990 // To reduce code size, use conversion here as well
0372d42e 991 if ( value.GetType() == wxPG_VARIANT_TYPE_STRING &&
1c4293cb
VZ
992 !this->IsKindOf(CLASSINFO(wxEditEnumProperty)) )
993 return ValueFromString_( value, value.GetString(), wxPG_PROPERTY_SPECIFIC );
994
995 return true;
996}
997
78f2d746 998wxString wxEnumProperty::ValueToString( wxVariant& value,
1425eca5 999 int WXUNUSED(argFlags) ) const
1c4293cb 1000{
1425eca5
JS
1001 if ( value.GetType() == wxPG_VARIANT_TYPE_STRING )
1002 return value.GetString();
1c4293cb 1003
1425eca5
JS
1004 int index = m_choices.Index(value.GetLong());
1005 if ( index < 0 )
1006 return wxEmptyString;
1c4293cb 1007
1425eca5 1008 return m_choices.GetLabel(index);
1c4293cb
VZ
1009}
1010
78f2d746 1011bool wxEnumProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
1c4293cb
VZ
1012{
1013 return ValueFromString_( variant, text, argFlags );
1014}
1015
78f2d746 1016bool wxEnumProperty::IntToValue( wxVariant& variant, int intVal, int argFlags ) const
1c4293cb
VZ
1017{
1018 return ValueFromInt_( variant, intVal, argFlags );
1019}
1020
78f2d746 1021bool wxEnumProperty::ValueFromString_( wxVariant& value, const wxString& text, int argFlags ) const
1c4293cb 1022{
1c4293cb
VZ
1023 int useIndex = -1;
1024 long useValue = 0;
1025
78f2d746 1026 for ( unsigned int i=0; i<m_choices.GetCount(); i++ )
1c4293cb 1027 {
78f2d746
JS
1028 const wxString& entryLabel = m_choices.GetLabel(i);
1029 if ( text.CmpNoCase(entryLabel) == 0 )
1c4293cb
VZ
1030 {
1031 useIndex = (int)i;
78f2d746 1032 useValue = m_choices.GetValue(i);
1c4293cb
VZ
1033 break;
1034 }
1c4293cb
VZ
1035 }
1036
1037 bool asText = false;
1038
1039 bool isEdit = this->IsKindOf(CLASSINFO(wxEditEnumProperty));
1040
1041 // If text not any of the choices, store as text instead
1042 // (but only if we are wxEditEnumProperty)
1043 if ( useIndex == -1 &&
0372d42e 1044 (value.GetType() != wxPG_VARIANT_TYPE_STRING || (m_value.GetString() != text)) &&
1c4293cb
VZ
1045 isEdit )
1046 {
1047 asText = true;
1048 }
1049
1050 int setAsNextIndex = -2;
1051
1052 if ( asText )
1053 {
1054 setAsNextIndex = -1;
1055 value = text;
1056 }
31f0b483 1057 else if ( useIndex != GetIndex() )
1c4293cb
VZ
1058 {
1059 if ( useIndex != -1 )
1060 {
1061 setAsNextIndex = useIndex;
1062 value = (long)useValue;
1063 }
1064 else
1065 {
1066 setAsNextIndex = -1;
1067 value = wxPGVariant_MinusOne;
1068 }
1069 }
1070
1071 if ( setAsNextIndex != -2 )
1072 {
1073 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1074 // validation purposes only, and index must not be changed
1075 if ( !(argFlags & wxPG_PROPERTY_SPECIFIC) )
1076 ms_nextIndex = setAsNextIndex;
1077
1078 if ( isEdit || setAsNextIndex != -1 )
1079 return true;
1080 else
1081 return false;
1082 }
1083 return false;
1084}
1085
78f2d746 1086bool wxEnumProperty::ValueFromInt_( wxVariant& variant, int intVal, int argFlags ) const
1c4293cb
VZ
1087{
1088 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1089 //
1090 ms_nextIndex = -2;
1091
1092 if ( argFlags & wxPG_FULL_VALUE )
1093 {
1094 ms_nextIndex = GetIndexForValue( intVal );
1095 }
1096 else
1097 {
31f0b483 1098 if ( intVal != GetIndex() )
1c4293cb
VZ
1099 {
1100 ms_nextIndex = intVal;
1101 }
1102 }
1103
1104 if ( ms_nextIndex != -2 )
1105 {
1106 if ( !(argFlags & wxPG_FULL_VALUE) )
78f2d746 1107 intVal = m_choices.GetValue(intVal);
1c4293cb
VZ
1108
1109 variant = (long)intVal;
1110
1111 return true;
1112 }
1113
1114 return false;
1115}
1116
d8812c6e
JS
1117void
1118wxEnumProperty::OnValidationFailure( wxVariant& WXUNUSED(pendingValue) )
1119{
1120 // Revert index
1121 m_index = ms_prevIndex;
1122 ResetNextIndex();
1123}
1124
78f2d746 1125void wxEnumProperty::SetIndex( int index )
1c4293cb 1126{
d8812c6e 1127 ms_prevIndex = m_index;
1c4293cb
VZ
1128 ms_nextIndex = -2;
1129 m_index = index;
1130}
1131
78f2d746 1132int wxEnumProperty::GetIndex() const
1c4293cb 1133{
31f0b483
JS
1134 if ( m_value.IsNull() )
1135 return -1;
1136
1c4293cb
VZ
1137 if ( ms_nextIndex != -2 )
1138 return ms_nextIndex;
31f0b483 1139
1c4293cb
VZ
1140 return m_index;
1141}
1142
1c4293cb
VZ
1143// -----------------------------------------------------------------------
1144// wxEditEnumProperty
1145// -----------------------------------------------------------------------
1146
1147IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty, wxPGProperty)
1148
1149WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty,wxString,ComboBox)
1150
1151wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name, const wxChar** labels,
1152 const long* values, const wxString& value )
1153 : wxEnumProperty(label,name,labels,values,0)
1154{
1155 SetValue( value );
1156}
1157
1158wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name, const wxChar** labels,
1159 const long* values, wxPGChoices* choicesCache, const wxString& value )
1160 : wxEnumProperty(label,name,labels,values,choicesCache,0)
1161{
1162 SetValue( value );
1163}
1164
1165wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name,
1166 const wxArrayString& labels, const wxArrayInt& values, const wxString& value )
1167 : wxEnumProperty(label,name,labels,values,0)
1168{
1169 SetValue( value );
1170}
1171
1172wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name,
1173 wxPGChoices& choices, const wxString& value )
1174 : wxEnumProperty(label,name,choices,0)
1175{
1176 SetValue( value );
1177}
1178
1179wxEditEnumProperty::~wxEditEnumProperty()
1180{
1181}
1182
1183// -----------------------------------------------------------------------
1184// wxFlagsProperty
1185// -----------------------------------------------------------------------
1186
1187IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty,wxPGProperty)
1188
1189WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty,long,TextCtrl)
1190
1191void wxFlagsProperty::Init()
1192{
2fd4a524 1193 SetParentalType(wxPG_PROP_AGGREGATE);
1c4293cb
VZ
1194
1195 long value = m_value;
1196
1197 //
1198 // Generate children
1199 //
1200 unsigned int i;
1201
63f62e76 1202 unsigned int prevChildCount = m_children.size();
1c4293cb
VZ
1203
1204 int oldSel = -1;
1205 if ( prevChildCount )
1206 {
1207 wxPropertyGridPageState* state = GetParentState();
1208
1209 // State safety check (it may be NULL in immediate parent)
1210 wxASSERT( state );
1211
1212 if ( state )
1213 {
1214 wxPGProperty* selected = state->GetSelection();
1215 if ( selected )
1216 {
1217 if ( selected->GetParent() == this )
b96a14e3 1218 oldSel = selected->GetIndexInParent();
1c4293cb
VZ
1219 else if ( selected == this )
1220 oldSel = -2;
1221 }
1222 }
1223 state->DoClearSelection();
1224 }
1225
1226 // Delete old children
1227 for ( i=0; i<prevChildCount; i++ )
63f62e76 1228 delete m_children[i];
1c4293cb 1229
63f62e76 1230 m_children.clear();
1c4293cb
VZ
1231
1232 if ( m_choices.IsOk() )
1233 {
1234 const wxPGChoices& choices = m_choices;
1235
1236 for ( i=0; i<GetItemCount(); i++ )
1237 {
1238 bool child_val;
98c04633 1239 child_val = ( value & choices.GetValue(i) )?true:false;
1c4293cb
VZ
1240
1241 wxPGProperty* boolProp;
d665918b 1242 wxString label = GetLabel(i);
1c4293cb
VZ
1243
1244 #if wxUSE_INTL
1245 if ( wxPGGlobalVars->m_autoGetTranslation )
1246 {
d665918b 1247 boolProp = new wxBoolProperty( ::wxGetTranslation(label), label, child_val );
1c4293cb
VZ
1248 }
1249 else
1250 #endif
1251 {
d665918b 1252 boolProp = new wxBoolProperty( label, label, child_val );
1c4293cb
VZ
1253 }
1254 AddChild(boolProp);
1255 }
1256
1257 m_oldChoicesData = m_choices.GetDataPtr();
1258 }
1259
1260 m_oldValue = m_value;
1261
1262 if ( prevChildCount )
1263 SubPropsChanged(oldSel);
1264}
1265
1266wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
1267 const wxChar** labels, const long* values, long value ) : wxPGProperty(label,name)
1268{
d3b9f782 1269 m_oldChoicesData = NULL;
1c4293cb
VZ
1270
1271 if ( labels )
1272 {
1273 m_choices.Set(labels,values);
1274
1275 wxASSERT( GetItemCount() );
1276
1277 SetValue( value );
1278 }
1279 else
1280 {
1281 m_value = wxPGVariant_Zero;
1282 }
1283}
1284
1285wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
1286 const wxArrayString& labels, const wxArrayInt& values, int value )
1287 : wxPGProperty(label,name)
1288{
d3b9f782 1289 m_oldChoicesData = NULL;
1c4293cb
VZ
1290
1291 if ( &labels && labels.size() )
1292 {
1293 m_choices.Set(labels,values);
1294
1295 wxASSERT( GetItemCount() );
1296
1297 SetValue( (long)value );
1298 }
1299 else
1300 {
1301 m_value = wxPGVariant_Zero;
1302 }
1303}
1304
1305wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
1306 wxPGChoices& choices, long value )
1307 : wxPGProperty(label,name)
1308{
d3b9f782 1309 m_oldChoicesData = NULL;
1c4293cb
VZ
1310
1311 if ( choices.IsOk() )
1312 {
1313 m_choices.Assign(choices);
1314
1315 wxASSERT( GetItemCount() );
1316
1317 SetValue( value );
1318 }
1319 else
1320 {
1321 m_value = wxPGVariant_Zero;
1322 }
1323}
1324
1325wxFlagsProperty::~wxFlagsProperty()
1326{
1327}
1328
1329void wxFlagsProperty::OnSetValue()
1330{
1331 if ( !m_choices.IsOk() || !GetItemCount() )
1332 {
1333 m_value = wxPGVariant_Zero;
1334 }
1335 else
1336 {
1337 long val = m_value.GetLong();
1338
1339 long fullFlags = 0;
1340
1341 // normalize the value (i.e. remove extra flags)
1342 unsigned int i;
1343 const wxPGChoices& choices = m_choices;
1344 for ( i = 0; i < GetItemCount(); i++ )
1345 {
98c04633 1346 fullFlags |= choices.GetValue(i);
1c4293cb
VZ
1347 }
1348
1349 val &= fullFlags;
1350
1351 m_value = val;
1352
1353 // Need to (re)init now?
1354 if ( GetChildCount() != GetItemCount() ||
1355 m_choices.GetDataPtr() != m_oldChoicesData )
1356 {
1357 Init();
1358 }
1359 }
1360
1361 long newFlags = m_value;
1362
1363 if ( newFlags != m_oldValue )
1364 {
1365 // Set child modified states
1366 unsigned int i;
1367 const wxPGChoices& choices = m_choices;
1368 for ( i = 0; i<GetItemCount(); i++ )
1369 {
1370 int flag;
1371
98c04633 1372 flag = choices.GetValue(i);
1c4293cb
VZ
1373
1374 if ( (newFlags & flag) != (m_oldValue & flag) )
1375 Item(i)->SetFlag( wxPG_PROP_MODIFIED );
1376 }
1377
1378 m_oldValue = newFlags;
1379 }
1380}
1381
1425eca5
JS
1382wxString wxFlagsProperty::ValueToString( wxVariant& value,
1383 int WXUNUSED(argFlags) ) const
1c4293cb
VZ
1384{
1385 wxString text;
1386
1387 if ( !m_choices.IsOk() )
1388 return text;
1389
1425eca5 1390 long flags = value;
1c4293cb
VZ
1391 unsigned int i;
1392 const wxPGChoices& choices = m_choices;
1393
1394 for ( i = 0; i < GetItemCount(); i++ )
1395 {
1396 int doAdd;
98c04633 1397 doAdd = ( flags & choices.GetValue(i) );
1c4293cb
VZ
1398
1399 if ( doAdd )
1400 {
1401 text += choices.GetLabel(i);
1402 text += wxS(", ");
1403 }
1404 }
1405
1406 // remove last comma
1407 if ( text.Len() > 1 )
1408 text.Truncate ( text.Len() - 2 );
1409
1410 return text;
1411}
1412
1413// Translate string into flag tokens
1414bool wxFlagsProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
1415{
1416 if ( !m_choices.IsOk() )
1417 return false;
1418
1419 long newFlags = 0;
1c4293cb
VZ
1420
1421 // semicolons are no longer valid delimeters
1422 WX_PG_TOKENIZER1_BEGIN(text,wxS(','))
1423
1424 if ( token.length() )
1425 {
1426 // Determine which one it is
1427 long bit = IdToBit( token );
1428
1429 if ( bit != -1 )
1430 {
1431 // Changed?
1432 newFlags |= bit;
1433 }
1434 else
1435 {
1436 break;
1437 }
1438 }
1439
1440 WX_PG_TOKENIZER1_END()
1441
0c931dd4
JS
1442 if ( variant != (long)newFlags )
1443 {
1444 variant = (long)newFlags;
1c4293cb 1445 return true;
0c931dd4 1446 }
1c4293cb
VZ
1447
1448 return false;
1449}
1450
1451// Converts string id to a relevant bit.
1452long wxFlagsProperty::IdToBit( const wxString& id ) const
1453{
1454 unsigned int i;
1455 for ( i = 0; i < GetItemCount(); i++ )
1456 {
1457 if ( id == GetLabel(i) )
1458 {
98c04633 1459 return m_choices.GetValue(i);
1c4293cb
VZ
1460 }
1461 }
1462 return -1;
1463}
1464
1465void wxFlagsProperty::RefreshChildren()
1466{
1467 if ( !m_choices.IsOk() || !GetChildCount() ) return;
1468
1469 int flags = m_value.GetLong();
1470
1471 const wxPGChoices& choices = m_choices;
1472 unsigned int i;
1473 for ( i = 0; i < GetItemCount(); i++ )
1474 {
1475 long flag;
1476
98c04633 1477 flag = choices.GetValue(i);
1c4293cb
VZ
1478
1479 long subVal = flags & flag;
1480 wxPGProperty* p = Item(i);
1481
1482 if ( subVal != (m_oldValue & flag) )
1483 p->SetFlag( wxPG_PROP_MODIFIED );
1484
1485 p->SetValue( subVal?true:false );
1486 }
1487
1488 m_oldValue = flags;
1489}
1490
1491void wxFlagsProperty::ChildChanged( wxVariant& thisValue, int childIndex, wxVariant& childValue ) const
1492{
1493 long oldValue = thisValue.GetLong();
1494 long val = childValue.GetLong();
98c04633 1495 unsigned long vi = m_choices.GetValue(childIndex);
1c4293cb
VZ
1496 if ( val )
1497 thisValue = (long)(oldValue | vi);
1498 else
1499 thisValue = (long)(oldValue & ~(vi));
1500}
1501
1c4293cb
VZ
1502// -----------------------------------------------------------------------
1503// wxDirProperty
1504// -----------------------------------------------------------------------
1505
d53f610c 1506IMPLEMENT_DYNAMIC_CLASS(wxDirProperty, wxLongStringProperty)
1c4293cb
VZ
1507
1508wxDirProperty::wxDirProperty( const wxString& name, const wxString& label, const wxString& value )
1509 : wxLongStringProperty(name,label,value)
1510{
3a89adc1 1511 m_flags |= wxPG_PROP_NO_ESCAPE;
1c4293cb 1512}
3a89adc1 1513
1c4293cb
VZ
1514wxDirProperty::~wxDirProperty() { }
1515
1516wxValidator* wxDirProperty::DoGetValidator() const
1517{
1518 return wxFileProperty::GetClassValidator();
1519}
1520
1521bool wxDirProperty::OnButtonClick( wxPropertyGrid* propGrid, wxString& value )
1522{
3a89adc1 1523 // Update property value from editor, if necessary
1c4293cb
VZ
1524 wxSize dlg_sz(300,400);
1525
bd8b65be
VZ
1526 wxString dlgMessage(m_dlgMessage);
1527 if ( dlgMessage.empty() )
1528 dlgMessage = _("Choose a directory:");
1c4293cb 1529 wxDirDialog dlg( propGrid,
bd8b65be 1530 dlgMessage,
1c4293cb
VZ
1531 value,
1532 0,
1533#if !wxPG_SMALL_SCREEN
1534 propGrid->GetGoodEditorDialogPosition(this,dlg_sz),
bd8b65be 1535 dlg_sz
1c4293cb
VZ
1536#else
1537 wxDefaultPosition,
bd8b65be 1538 wxDefaultSize
1c4293cb 1539#endif
bd8b65be 1540 );
1c4293cb
VZ
1541
1542 if ( dlg.ShowModal() == wxID_OK )
1543 {
1544 value = dlg.GetPath();
1545 return true;
1546 }
1547 return false;
1548}
1549
1550bool wxDirProperty::DoSetAttribute( const wxString& name, wxVariant& value )
1551{
1552 if ( name == wxPG_DIR_DIALOG_MESSAGE )
1553 {
1554 m_dlgMessage = value.GetString();
1555 return true;
1556 }
1557 return false;
1558}
1559
1560// -----------------------------------------------------------------------
1561// wxPGFileDialogAdapter
1562// -----------------------------------------------------------------------
1563
1564bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid* propGrid, wxPGProperty* property )
1565{
1566 wxFileProperty* fileProp = NULL;
1567 wxString path;
1568 int indFilter = -1;
1569
1570 if ( property->IsKindOf(CLASSINFO(wxFileProperty)) )
1571 {
1572 fileProp = ((wxFileProperty*)property);
1425eca5
JS
1573 wxFileName filename = fileProp->GetValue().GetString();
1574 path = filename.GetPath();
1c4293cb
VZ
1575 indFilter = fileProp->m_indFilter;
1576
1577 if ( !path.length() && fileProp->m_basePath.length() )
1578 path = fileProp->m_basePath;
1579 }
1580 else
1581 {
1582 wxFileName fn(property->GetValue().GetString());
1583 path = fn.GetPath();
1584 }
1585
1586 wxFileDialog dlg( propGrid->GetPanel(),
1587 property->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1588 property->GetAttribute(wxS("InitialPath"), path),
1589 wxEmptyString,
1590 property->GetAttribute(wxPG_FILE_WILDCARD, _("All files (*.*)|*.*")),
1591 0,
1592 wxDefaultPosition );
1593
1594 if ( indFilter >= 0 )
1595 dlg.SetFilterIndex( indFilter );
1596
1597 if ( dlg.ShowModal() == wxID_OK )
1598 {
1599 if ( fileProp )
1600 fileProp->m_indFilter = dlg.GetFilterIndex();
1601 SetValue( dlg.GetPath() );
1602 return true;
1603 }
1604 return false;
1605}
1606
1607// -----------------------------------------------------------------------
1608// wxFileProperty
1609// -----------------------------------------------------------------------
1610
1611WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty,wxPGProperty,
1612 wxString,const wxString&,TextCtrlAndButton)
1613
1614wxFileProperty::wxFileProperty( const wxString& label, const wxString& name,
1615 const wxString& value ) : wxPGProperty(label,name)
1616{
1617 m_flags |= wxPG_PROP_SHOW_FULL_FILENAME;
1618 m_indFilter = -1;
1619 SetAttribute( wxPG_FILE_WILDCARD, _("All files (*.*)|*.*") );
1620
1621 SetValue(value);
1622}
1623
1624wxFileProperty::~wxFileProperty() {}
1625
1626#if wxUSE_VALIDATORS
1627
1628wxValidator* wxFileProperty::GetClassValidator()
1629{
1630 WX_PG_DOGETVALIDATOR_ENTRY()
1631
1632 // Atleast wxPython 2.6.2.1 required that the string argument is given
1633 static wxString v;
1634 wxTextValidator* validator = new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST,&v);
1635
1636 wxArrayString exChars;
1637 exChars.Add(wxS("?"));
1638 exChars.Add(wxS("*"));
1639 exChars.Add(wxS("|"));
1640 exChars.Add(wxS("<"));
1641 exChars.Add(wxS(">"));
1642 exChars.Add(wxS("\""));
1643
1644 validator->SetExcludes(exChars);
1645
1646 WX_PG_DOGETVALIDATOR_EXIT(validator)
1647}
1648
1649wxValidator* wxFileProperty::DoGetValidator() const
1650{
1651 return GetClassValidator();
1652}
1653
1654#endif
1655
1656void wxFileProperty::OnSetValue()
1657{
1658 const wxString& fnstr = m_value.GetString();
1659
1425eca5 1660 wxFileName filename = fnstr;
1c4293cb 1661
1425eca5 1662 if ( !filename.HasName() )
1c4293cb
VZ
1663 {
1664 m_value = wxPGVariant_EmptyString;
1c4293cb
VZ
1665 }
1666
1667 // Find index for extension.
1668 if ( m_indFilter < 0 && fnstr.length() )
1669 {
1425eca5 1670 wxString ext = filename.GetExt();
1c4293cb
VZ
1671 int curind = 0;
1672 size_t pos = 0;
1673 size_t len = m_wildcard.length();
1674
1675 pos = m_wildcard.find(wxS("|"), pos);
1676 while ( pos != wxString::npos && pos < (len-3) )
1677 {
1678 size_t ext_begin = pos + 3;
1679
1680 pos = m_wildcard.find(wxS("|"), ext_begin);
1681 if ( pos == wxString::npos )
1682 pos = len;
1683 wxString found_ext = m_wildcard.substr(ext_begin, pos-ext_begin);
1684
1685 if ( found_ext.length() > 0 )
1686 {
1687 if ( found_ext[0] == wxS('*') )
1688 {
1689 m_indFilter = curind;
1690 break;
1691 }
1692 if ( ext.CmpNoCase(found_ext) == 0 )
1693 {
1694 m_indFilter = curind;
1695 break;
1696 }
1697 }
1698
1699 if ( pos != len )
1700 pos = m_wildcard.find(wxS("|"), pos+1);
1701
1702 curind++;
1703 }
1704 }
1705}
1706
1425eca5 1707wxFileName wxFileProperty::GetFileName() const
1c4293cb 1708{
1425eca5
JS
1709 wxFileName filename;
1710
1711 if ( !m_value.IsNull() )
1712 filename = m_value.GetString();
1713
1714 return filename;
1715}
1716
1717wxString wxFileProperty::ValueToString( wxVariant& value,
1718 int argFlags ) const
1719{
1720 wxFileName filename = value.GetString();
1721
1722 if ( !filename.HasName() )
1723 return wxEmptyString;
1724
1725 wxString fullName = filename.GetFullName();
1c4293cb 1726 if ( !fullName.length() )
1425eca5 1727 return wxEmptyString;
1c4293cb
VZ
1728
1729 if ( argFlags & wxPG_FULL_VALUE )
1730 {
1425eca5 1731 return filename.GetFullPath();
1c4293cb
VZ
1732 }
1733 else if ( m_flags & wxPG_PROP_SHOW_FULL_FILENAME )
1734 {
1735 if ( m_basePath.Length() )
1736 {
1425eca5 1737 wxFileName fn2(filename);
1c4293cb
VZ
1738 fn2.MakeRelativeTo(m_basePath);
1739 return fn2.GetFullPath();
1740 }
1425eca5 1741 return filename.GetFullPath();
1c4293cb
VZ
1742 }
1743
1425eca5 1744 return filename.GetFullName();
1c4293cb
VZ
1745}
1746
1747wxPGEditorDialogAdapter* wxFileProperty::GetEditorDialog() const
1748{
1749 return new wxPGFileDialogAdapter();
1750}
1751
1752bool wxFileProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
1753{
1425eca5
JS
1754 wxFileName filename = variant.GetString();
1755
1c4293cb
VZ
1756 if ( (m_flags & wxPG_PROP_SHOW_FULL_FILENAME) || (argFlags & wxPG_FULL_VALUE) )
1757 {
1425eca5 1758 if ( filename != text )
1c4293cb
VZ
1759 {
1760 variant = text;
1761 return true;
1762 }
1763 }
1764 else
1765 {
1425eca5 1766 if ( filename.GetFullName() != text )
1c4293cb 1767 {
1425eca5 1768 wxFileName fn = filename;
1c4293cb
VZ
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
1425eca5
JS
1861wxString wxLongStringProperty::ValueToString( wxVariant& value,
1862 int WXUNUSED(argFlags) ) const
1c4293cb 1863{
1425eca5 1864 return value;
1c4293cb
VZ
1865}
1866
1867bool wxLongStringProperty::OnEvent( wxPropertyGrid* propGrid, wxWindow* WXUNUSED(primary),
1868 wxEvent& event )
1869{
1870 if ( propGrid->IsMainButtonEvent(event) )
1871 {
1872 // Update the value
703ee9f5 1873 wxVariant useValue = propGrid->GetUncommittedPropertyValue();
1c4293cb 1874
9b5bafcf 1875 wxString val1 = useValue.GetString();
1c4293cb
VZ
1876 wxString val_orig = val1;
1877
1878 wxString value;
1879 if ( !(m_flags & wxPG_PROP_NO_ESCAPE) )
1880 wxPropertyGrid::ExpandEscapeSequences(value,val1);
1881 else
1882 value = wxString(val1);
1883
1884 // Run editor dialog.
1885 if ( OnButtonClick(propGrid,value) )
1886 {
1887 if ( !(m_flags & wxPG_PROP_NO_ESCAPE) )
1888 wxPropertyGrid::CreateEscapeSequences(val1,value);
1889 else
1890 val1 = value;
1891
1892 if ( val1 != val_orig )
1893 {
1894 SetValueInEvent( val1 );
1895 return true;
1896 }
1897 }
1898 }
1899 return false;
1900}
1901
1902bool wxLongStringProperty::OnButtonClick( wxPropertyGrid* propGrid, wxString& value )
1903{
1904 return DisplayEditorDialog(this, propGrid, value);
1905}
1906
1907bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty* prop, wxPropertyGrid* propGrid, wxString& value )
1908
1909{
1910 // launch editor dialog
1911 wxDialog* dlg = new wxDialog(propGrid,-1,prop->GetLabel(),wxDefaultPosition,wxDefaultSize,
1912 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxCLIP_CHILDREN);
1913
1914 dlg->SetFont(propGrid->GetFont()); // To allow entering chars of the same set as the propGrid
1915
1916 // Multi-line text editor dialog.
1917#if !wxPG_SMALL_SCREEN
1918 const int spacing = 8;
1919#else
1920 const int spacing = 4;
1921#endif
1922 wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL );
1923 wxBoxSizer* rowsizer = new wxBoxSizer( wxHORIZONTAL );
1924 wxTextCtrl* ed = new wxTextCtrl(dlg,11,value,
1925 wxDefaultPosition,wxDefaultSize,wxTE_MULTILINE);
1926
1927 rowsizer->Add( ed, 1, wxEXPAND|wxALL, spacing );
1928 topsizer->Add( rowsizer, 1, wxEXPAND, 0 );
1929 rowsizer = new wxBoxSizer( wxHORIZONTAL );
1930 const int but_sz_flags =
1931 wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT;
1932 rowsizer->Add( new wxButton(dlg,wxID_OK,_("Ok")),
1933 0, but_sz_flags, spacing );
1934 rowsizer->Add( new wxButton(dlg,wxID_CANCEL,_("Cancel")),
1935 0, but_sz_flags, spacing );
1936 topsizer->Add( rowsizer, 0, wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL, 0 );
1937
1938 dlg->SetSizer( topsizer );
1939 topsizer->SetSizeHints( dlg );
1940
1941#if !wxPG_SMALL_SCREEN
1942 dlg->SetSize(400,300);
1943
1944 dlg->Move( propGrid->GetGoodEditorDialogPosition(prop,dlg->GetSize()) );
1945#endif
1946
1947 int res = dlg->ShowModal();
1948
1949 if ( res == wxID_OK )
1950 {
1951 value = ed->GetValue();
1952 dlg->Destroy();
1953 return true;
1954 }
1955 dlg->Destroy();
1956 return false;
1957}
1958
1959bool wxLongStringProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
1960{
0c931dd4 1961 if ( variant != text )
1c4293cb
VZ
1962 {
1963 variant = text;
1964 return true;
1965 }
1966 return false;
1967}
1968
1969// -----------------------------------------------------------------------
1970// wxArrayEditorDialog
1971// -----------------------------------------------------------------------
1972
1973BEGIN_EVENT_TABLE(wxArrayEditorDialog, wxDialog)
1974 EVT_IDLE(wxArrayEditorDialog::OnIdle)
1975 EVT_LISTBOX(24, wxArrayEditorDialog::OnListBoxClick)
1976 EVT_TEXT_ENTER(21, wxArrayEditorDialog::OnAddClick)
1977 EVT_BUTTON(22, wxArrayEditorDialog::OnAddClick)
1978 EVT_BUTTON(23, wxArrayEditorDialog::OnDeleteClick)
1979 EVT_BUTTON(25, wxArrayEditorDialog::OnUpClick)
1980 EVT_BUTTON(26, wxArrayEditorDialog::OnDownClick)
1981 EVT_BUTTON(27, wxArrayEditorDialog::OnUpdateClick)
1982 //EVT_BUTTON(28, wxArrayEditorDialog::OnCustomEditClick)
1983END_EVENT_TABLE()
1984
1985IMPLEMENT_ABSTRACT_CLASS(wxArrayEditorDialog, wxDialog)
1986
3b211af1 1987#include "wx/statline.h"
1c4293cb
VZ
1988
1989// -----------------------------------------------------------------------
1990
1991void wxArrayEditorDialog::OnIdle(wxIdleEvent& event)
1992{
1993 //
1994 // Do control focus detection here.
1995 //
1996
1997 wxWindow* focused = FindFocus();
1998
1999 // This strange focus thing is a workaround for wxGTK wxListBox focus
2000 // reporting bug.
2001 if ( m_curFocus == 0 && focused != m_edValue &&
2002 focused != m_butAdd && focused != m_butUpdate &&
2003 m_lbStrings->GetSelection() >= 0 )
2004 {
2005 // ListBox was just focused.
2006 m_butAdd->Enable(false);
2007 m_butUpdate->Enable(false);
2008 m_butRemove->Enable(true);
2009 m_butUp->Enable(true);
2010 m_butDown->Enable(true);
2011 m_curFocus = 1;
2012 }
2013 else if ( (m_curFocus == 1 && focused == m_edValue) /*|| m_curFocus == 2*/ )
2014 {
2015 // TextCtrl was just focused.
2016 m_butAdd->Enable(true);
2017 bool upd_enable = false;
2018 if ( m_lbStrings->GetCount() && m_lbStrings->GetSelection() >= 0 )
2019 upd_enable = true;
2020 m_butUpdate->Enable(upd_enable);
2021 m_butRemove->Enable(false);
2022 m_butUp->Enable(false);
2023 m_butDown->Enable(false);
2024 m_curFocus = 0;
2025 }
2026
2027 event.Skip();
2028}
2029
2030// -----------------------------------------------------------------------
2031
2032wxArrayEditorDialog::wxArrayEditorDialog()
2033 : wxDialog()
2034{
2035 Init();
2036}
2037
2038// -----------------------------------------------------------------------
2039
2040void wxArrayEditorDialog::Init()
2041{
2042 m_custBtText = (const wxChar*) NULL;
2043}
2044
2045// -----------------------------------------------------------------------
2046
2047wxArrayEditorDialog::wxArrayEditorDialog( wxWindow *parent,
2048 const wxString& message,
2049 const wxString& caption,
2050 long style,
2051 const wxPoint& pos,
2052 const wxSize& sz )
2053 : wxDialog()
2054{
2055 Init();
2056 Create(parent,message,caption,style,pos,sz);
2057}
2058
2059// -----------------------------------------------------------------------
2060
2061bool wxArrayEditorDialog::Create( wxWindow *parent,
2062 const wxString& message,
2063 const wxString& caption,
2064 long style,
2065 const wxPoint& pos,
2066 const wxSize& sz )
2067{
2068 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2069 // FIXME: This should be only a temporary fix.
2070#ifdef __WXMAC__
b0f0eda8 2071 wxUnusedVar(style);
1c4293cb
VZ
2072 int useStyle = wxCAPTION;
2073#else
2074 int useStyle = style;
2075#endif
2076
2077 bool res = wxDialog::Create(parent, wxID_ANY, caption, pos, sz, useStyle);
2078
2079 SetFont(parent->GetFont()); // To allow entering chars of the same set as the propGrid
2080
2081#if !wxPG_SMALL_SCREEN
2082 const int spacing = 4;
2083#else
2084 const int spacing = 3;
2085#endif
2086
2087 m_modified = false;
2088
2089 m_curFocus = 1;
2090
2091 const int but_sz_flags =
2092 wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxALL; //wxBOTTOM|wxLEFT|wxRIGHT;
2093
2094 wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL );
2095
2096 // Message
2097 if ( message.length() )
2098 topsizer->Add( new wxStaticText(this,-1,message),
2099 0, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxALL, spacing );
2100
2101 // String editor
2102 wxBoxSizer* rowsizer = new wxBoxSizer( wxHORIZONTAL );
2103 m_edValue = new wxTextCtrl(this,21,wxEmptyString,
2104 wxDefaultPosition,wxDefaultSize,wxTE_PROCESS_ENTER);
2105 wxValidator* validator = GetTextCtrlValidator();
2106 if ( validator )
2107 {
2108 m_edValue->SetValidator( *validator );
2109 delete validator;
2110 }
2111 rowsizer->Add( m_edValue,
2112 1, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxALL, spacing );
2113
2114 // Add button
2115 m_butAdd = new wxButton(this,22,_("Add"));
2116 rowsizer->Add( m_butAdd,
2117 0, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, spacing );
2118 topsizer->Add( rowsizer, 0, wxEXPAND, spacing );
2119
2120 // Separator line
2121 topsizer->Add( new wxStaticLine(this,-1),
2122 0, wxEXPAND|wxBOTTOM|wxLEFT|wxRIGHT, spacing );
2123
2124 rowsizer = new wxBoxSizer( wxHORIZONTAL );
2125
2126 // list box
2127 m_lbStrings = new wxListBox(this, 24, wxDefaultPosition, wxDefaultSize);
2128 unsigned int i;
2129 for ( i=0; i<ArrayGetCount(); i++ )
2130 m_lbStrings->Append( ArrayGet(i) );
2131 rowsizer->Add( m_lbStrings, 1, wxEXPAND|wxRIGHT, spacing );
2132
2133 // Manipulator buttons
2134 wxBoxSizer* colsizer = new wxBoxSizer( wxVERTICAL );
d3b9f782 2135 m_butCustom = NULL;
1c4293cb
VZ
2136 if ( m_custBtText )
2137 {
2138 m_butCustom = new wxButton(this,28,::wxGetTranslation(m_custBtText));
2139 colsizer->Add( m_butCustom,
2140 0, wxALIGN_CENTER|wxTOP/*wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT*/,
2141 spacing );
2142 }
2143 m_butUpdate = new wxButton(this,27,_("Update"));
2144 colsizer->Add( m_butUpdate,
2145 0, wxALIGN_CENTER|wxTOP, spacing );
2146 m_butRemove = new wxButton(this,23,_("Remove"));
2147 colsizer->Add( m_butRemove,
2148 0, wxALIGN_CENTER|wxTOP, spacing );
2149 m_butUp = new wxButton(this,25,_("Up"));
2150 colsizer->Add( m_butUp,
2151 0, wxALIGN_CENTER|wxTOP, spacing );
2152 m_butDown = new wxButton(this,26,_("Down"));
2153 colsizer->Add( m_butDown,
2154 0, wxALIGN_CENTER|wxTOP, spacing );
2155 rowsizer->Add( colsizer, 0, 0, spacing );
2156
2157 topsizer->Add( rowsizer, 1, wxLEFT|wxRIGHT|wxEXPAND, spacing );
2158
2159 // Separator line
2160 topsizer->Add( new wxStaticLine(this,-1),
2161 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, spacing );
2162
2163 // buttons
2164 rowsizer = new wxBoxSizer( wxHORIZONTAL );
2165 /*
2166 const int but_sz_flags =
2167 wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT;
2168 */
2169 rowsizer->Add( new wxButton(this,wxID_OK,_("Ok")),
2170 0, but_sz_flags, spacing );
2171 rowsizer->Add( new wxButton(this,wxID_CANCEL,_("Cancel")),
2172 0, but_sz_flags, spacing );
2173 topsizer->Add( rowsizer, 0, wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL, 0 );
2174
2175 m_edValue->SetFocus();
2176
2177 SetSizer( topsizer );
2178 topsizer->SetSizeHints( this );
2179
2180#if !wxPG_SMALL_SCREEN
2181 if ( sz.x == wxDefaultSize.x &&
2182 sz.y == wxDefaultSize.y )
2183 SetSize( wxSize(275,360) );
2184 else
2185 SetSize(sz);
2186#endif
2187
2188 return res;
2189}
2190
2191// -----------------------------------------------------------------------
2192
2193void wxArrayEditorDialog::OnAddClick(wxCommandEvent& )
2194{
2195 wxString text = m_edValue->GetValue();
2196 if ( text.length() )
2197 {
2198 if ( ArrayInsert( text, -1 ) )
2199 {
2200 m_lbStrings->Append( text );
2201 m_modified = true;
2202 m_edValue->Clear();
2203 }
2204 }
2205}
2206
2207// -----------------------------------------------------------------------
2208
2209void wxArrayEditorDialog::OnDeleteClick(wxCommandEvent& )
2210{
2211 int index = m_lbStrings->GetSelection();
2212 if ( index >= 0 )
2213 {
2214 ArrayRemoveAt( index );
2215 m_lbStrings->Delete ( index );
2216 m_modified = true;
2217 }
2218}
2219
2220// -----------------------------------------------------------------------
2221
2222void wxArrayEditorDialog::OnUpClick(wxCommandEvent& )
2223{
2224 int index = m_lbStrings->GetSelection();
2225 if ( index > 0 )
2226 {
2227 ArraySwap(index-1,index);
2228 /*wxString old_str = m_array[index-1];
2229 wxString new_str = m_array[index];
2230 m_array[index-1] = new_str;
2231 m_array[index] = old_str;*/
2232 m_lbStrings->SetString ( index-1, ArrayGet(index-1) );
2233 m_lbStrings->SetString ( index, ArrayGet(index) );
2234 m_lbStrings->SetSelection ( index-1 );
2235 m_modified = true;
2236 }
2237}
2238
2239// -----------------------------------------------------------------------
2240
2241void wxArrayEditorDialog::OnDownClick(wxCommandEvent& )
2242{
2243 int index = m_lbStrings->GetSelection();
2244 int lastStringIndex = ((int) m_lbStrings->GetCount()) - 1;
2245 if ( index >= 0 && index < lastStringIndex )
2246 {
2247 ArraySwap(index,index+1);
2248 /*wxString old_str = m_array[index+1];
2249 wxString new_str = m_array[index];
2250 m_array[index+1] = new_str;
2251 m_array[index] = old_str;*/
2252 m_lbStrings->SetString ( index+1, ArrayGet(index+1) );
2253 m_lbStrings->SetString ( index, ArrayGet(index) );
2254 m_lbStrings->SetSelection ( index+1 );
2255 m_modified = true;
2256 }
2257}
2258
2259// -----------------------------------------------------------------------
2260
2261void wxArrayEditorDialog::OnUpdateClick(wxCommandEvent& )
2262{
2263 int index = m_lbStrings->GetSelection();
2264 if ( index >= 0 )
2265 {
2266 wxString str = m_edValue->GetValue();
2267 if ( ArraySet(index,str) )
2268 {
2269 m_lbStrings->SetString ( index, str );
2270 //m_array[index] = str;
2271 m_modified = true;
2272 }
2273 }
2274}
2275
2276// -----------------------------------------------------------------------
2277
2278void wxArrayEditorDialog::OnListBoxClick(wxCommandEvent& )
2279{
2280 int index = m_lbStrings->GetSelection();
2281 if ( index >= 0 )
2282 {
2283 m_edValue->SetValue( m_lbStrings->GetString(index) );
2284 }
2285}
2286
2287// -----------------------------------------------------------------------
2288// wxPGArrayStringEditorDialog
2289// -----------------------------------------------------------------------
2290
2291IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog, wxArrayEditorDialog)
2292
2293BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog, wxArrayEditorDialog)
2294 EVT_BUTTON(28, wxPGArrayStringEditorDialog::OnCustomEditClick)
2295END_EVENT_TABLE()
2296
2297// -----------------------------------------------------------------------
2298
2299wxString wxPGArrayStringEditorDialog::ArrayGet( size_t index )
2300{
2301 return m_array[index];
2302}
2303
2304size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2305{
2306 return m_array.size();
2307}
2308
2309bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString& str, int index )
2310{
2311 if (index<0)
2312 m_array.Add(str);
2313 else
2314 m_array.Insert(str,index);
2315 return true;
2316}
2317
2318bool wxPGArrayStringEditorDialog::ArraySet( size_t index, const wxString& str )
2319{
2320 m_array[index] = str;
2321 return true;
2322}
2323
2324void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index )
2325{
2326 m_array.RemoveAt(index);
2327}
2328
2329void wxPGArrayStringEditorDialog::ArraySwap( size_t first, size_t second )
2330{
2331 wxString old_str = m_array[first];
2332 wxString new_str = m_array[second];
2333 m_array[first] = new_str;
2334 m_array[second] = old_str;
2335}
2336
2337wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2338 : wxArrayEditorDialog()
2339{
2340 Init();
2341}
2342
2343void wxPGArrayStringEditorDialog::Init()
2344{
d3b9f782 2345 m_pCallingClass = NULL;
1c4293cb
VZ
2346}
2347
2348void wxPGArrayStringEditorDialog::OnCustomEditClick(wxCommandEvent& )
2349{
2350 wxASSERT( m_pCallingClass );
2351 wxString str = m_edValue->GetValue();
2352 if ( m_pCallingClass->OnCustomStringEdit(m_parent,str) )
2353 {
2354 //m_edValue->SetValue ( str );
2355 m_lbStrings->Append ( str );
2356 m_array.Add ( str );
2357 m_modified = true;
2358 }
2359}
2360
2361// -----------------------------------------------------------------------
2362// wxArrayStringProperty
2363// -----------------------------------------------------------------------
2364
2365WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty, // Property name
2366 wxPGProperty, // Property we inherit from
2367 wxArrayString, // Value type name
2368 const wxArrayString&, // Value type, as given in constructor
2369 TextCtrlAndButton) // Initial editor
2370
2371wxArrayStringProperty::wxArrayStringProperty( const wxString& label,
2372 const wxString& name,
2373 const wxArrayString& array )
2374 : wxPGProperty(label,name)
2375{
2376 SetValue( array );
2377}
2378
2379wxArrayStringProperty::~wxArrayStringProperty() { }
2380
2381void wxArrayStringProperty::OnSetValue()
2382{
2383 GenerateValueAsString();
2384}
2385
1425eca5
JS
2386#define ARRSTRPROP_ARRAY_TO_STRING(STRING,ARRAY) \
2387 wxPropertyGrid::ArrayStringToString(STRING,ARRAY,wxS('"'),wxS('"'),1)
2388
2389wxString wxArrayStringProperty::ValueToString( wxVariant& WXUNUSED(value),
2390 int argFlags ) const
1c4293cb 2391{
1425eca5
JS
2392 //
2393 // If this is called from GetValueAsString(), return cached string
2394 if ( argFlags & wxPG_VALUE_IS_CURRENT )
2395 {
2396 return m_display;
2397 }
2398
2399 wxArrayString arr = m_value.GetArrayString();
2400 wxString s;
2401 ARRSTRPROP_ARRAY_TO_STRING(s, arr);
2402 return s;
1c4293cb
VZ
2403}
2404
2405// Converts wxArrayString to a string separated by delimeters and spaces.
2406// preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2407// conversion.
2408void wxPropertyGrid::ArrayStringToString( wxString& dst, const wxArrayString& src,
2409 wxChar preDelim, wxChar postDelim,
2410 int flags )
2411{
2412 wxString pdr;
2413
2414 unsigned int i;
2415 unsigned int itemCount = src.size();
2416
b7bc9d80 2417 wxChar preas[2] = { 0, 0 };
1c4293cb
VZ
2418
2419 dst.Empty();
2420
b7bc9d80 2421 if ( flags & 1 )
1c4293cb
VZ
2422 {
2423 preas[0] = preDelim;
1c4293cb
VZ
2424 pdr = wxS("\\");
2425 pdr += preDelim;
2426 }
2427
2428 if ( itemCount )
2429 dst.append( preas );
2430
2431 wxASSERT( postDelim );
2432 wxString postDelimStr(postDelim);
2433 //wxString preDelimStr(preDelim);
2434
2435 for ( i = 0; i < itemCount; i++ )
2436 {
2437 wxString str( src.Item(i) );
2438
2439 // Do some character conversion.
2440 // Convertes \ to \\ and <preDelim> to \<preDelim>
2441 // Useful when preDelim and postDelim are "\"".
2442 if ( flags & 1 )
2443 {
2444 str.Replace( wxS("\\"), wxS("\\\\"), true );
2445 if ( pdr.length() )
2446 str.Replace( preas, pdr, true );
2447 }
2448
2449 dst.append( str );
2450
2451 if ( i < (itemCount-1) )
2452 {
2453 dst.append( postDelimStr );
2454 dst.append( wxS(" ") );
2455 dst.append( preas );
2456 }
2457 else if ( preDelim )
2458 dst.append( postDelimStr );
2459 }
2460}
2461
1c4293cb
VZ
2462void wxArrayStringProperty::GenerateValueAsString()
2463{
2464 wxArrayString arr = m_value.GetArrayString();
1425eca5 2465 ARRSTRPROP_ARRAY_TO_STRING(m_display, arr);
1c4293cb
VZ
2466}
2467
2468// Default implementation doesn't do anything.
2469bool wxArrayStringProperty::OnCustomStringEdit( wxWindow*, wxString& )
2470{
2471 return false;
2472}
2473
2474wxArrayEditorDialog* wxArrayStringProperty::CreateEditorDialog()
2475{
2476 return new wxPGArrayStringEditorDialog();
2477}
2478
2479bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid* propGrid,
2480 wxWindow* WXUNUSED(primaryCtrl),
2481 const wxChar* cbt )
2482{
2483 // Update the value
703ee9f5 2484 wxVariant useValue = propGrid->GetUncommittedPropertyValue();
1c4293cb
VZ
2485
2486 if ( !propGrid->EditorValidate() )
2487 return false;
2488
2489 // Create editor dialog.
2490 wxArrayEditorDialog* dlg = CreateEditorDialog();
2491#if wxUSE_VALIDATORS
2492 wxValidator* validator = GetValidator();
2493 wxPGInDialogValidator dialogValidator;
2494#endif
2495
2496 wxPGArrayStringEditorDialog* strEdDlg = wxDynamicCast(dlg, wxPGArrayStringEditorDialog);
2497
2498 if ( strEdDlg )
2499 strEdDlg->SetCustomButton(cbt, this);
2500
9b5bafcf 2501 dlg->SetDialogValue( useValue );
1c4293cb
VZ
2502 dlg->Create(propGrid, wxEmptyString, m_label);
2503
2504#if !wxPG_SMALL_SCREEN
2505 dlg->Move( propGrid->GetGoodEditorDialogPosition(this,dlg->GetSize()) );
2506#endif
2507
2508 bool retVal;
2509
2510 for (;;)
2511 {
2512 retVal = false;
2513
2514 int res = dlg->ShowModal();
2515
2516 if ( res == wxID_OK && dlg->IsModified() )
2517 {
2518 wxVariant value = dlg->GetDialogValue();
2519 if ( !value.IsNull() )
2520 {
2521 wxArrayString actualValue = value.GetArrayString();
2522 wxString tempStr;
1425eca5 2523 ARRSTRPROP_ARRAY_TO_STRING(tempStr, actualValue);
1c4293cb
VZ
2524 #if wxUSE_VALIDATORS
2525 if ( dialogValidator.DoValidate( propGrid, validator, tempStr ) )
2526 #endif
2527 {
2528 SetValueInEvent( actualValue );
2529 retVal = true;
2530 break;
2531 }
2532 }
2533 else
2534 break;
2535 }
2536 else
2537 break;
2538 }
2539
2540 delete dlg;
2541
2542 return retVal;
2543}
2544
2545bool wxArrayStringProperty::OnEvent( wxPropertyGrid* propGrid,
2546 wxWindow* primary,
2547 wxEvent& event )
2548{
2549 if ( propGrid->IsMainButtonEvent(event) )
2550 return OnButtonClick(propGrid,primary,(const wxChar*) NULL);
2551 return false;
2552}
2553
2554bool wxArrayStringProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
2555{
2556 wxArrayString arr;
2557
2558 WX_PG_TOKENIZER2_BEGIN(text,wxS('"'))
2559
2560 // Need to replace backslashes with empty characters
2561 // (opposite what is done in GenerateValueString).
2562 token.Replace ( wxS("\\"), wxEmptyString, true );
2563
2564 arr.Add( token );
2565
2566 WX_PG_TOKENIZER2_END()
2567
2568 variant = arr;
2569
2570 return true;
2571}
2572
2573// -----------------------------------------------------------------------
2574// wxPGInDialogValidator
2575// -----------------------------------------------------------------------
2576
2577#if wxUSE_VALIDATORS
2578bool wxPGInDialogValidator::DoValidate( wxPropertyGrid* propGrid,
2579 wxValidator* validator,
2580 const wxString& value )
2581{
2582 if ( !validator )
2583 return true;
2584
2585 wxTextCtrl* tc = m_textCtrl;
2586
2587 if ( !tc )
2588 {
2589 {
2590 tc = new wxTextCtrl( propGrid, wxPG_SUBID_TEMP1, wxEmptyString,
2591 wxPoint(30000,30000));
2592 tc->Hide();
2593 }
2594
2595 m_textCtrl = tc;
2596 }
2597
2598 tc->SetValue(value);
2599
2600 validator->SetWindow(tc);
2601 bool res = validator->Validate(propGrid);
2602
2603 return res;
2604}
2605#else
2606bool wxPGInDialogValidator::DoValidate( wxPropertyGrid* WXUNUSED(propGrid),
2607 wxValidator* WXUNUSED(validator),
2608 const wxString& WXUNUSED(value) )
2609{
2610 return true;
2611}
2612#endif
2613
2614// -----------------------------------------------------------------------
2615
f4bc1aa2 2616#endif // wxUSE_PROPGRID