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