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