]> git.saurik.com Git - wxWidgets.git/blame - src/generic/grideditors.cpp
updated setup.h for OpenVMS
[wxWidgets.git] / src / generic / grideditors.cpp
CommitLineData
a3ef8eb5
VZ
1///////////////////////////////////////////////////////////////////////////
2// Name: src/generic/grideditors.cpp
3// Purpose: wxGridCellEditorEvtHandler and wxGrid editors
4// Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
5// Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios
6// Created: 1/08/1999
7// RCS-ID: $Id$
8// Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9// Licence: wxWindows licence
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#if wxUSE_GRID
20
21#include "wx/grid.h"
22
23#ifndef WX_PRECOMP
24 #include "wx/utils.h"
25 #include "wx/dcclient.h"
26 #include "wx/settings.h"
27 #include "wx/log.h"
28 #include "wx/textctrl.h"
29 #include "wx/checkbox.h"
30 #include "wx/combobox.h"
a3ef8eb5
VZ
31 #include "wx/intl.h"
32 #include "wx/math.h"
33 #include "wx/listbox.h"
34#endif
35
a54cf371 36#include "wx/valnum.h"
a3ef8eb5
VZ
37#include "wx/textfile.h"
38#include "wx/spinctrl.h"
39#include "wx/tokenzr.h"
40#include "wx/renderer.h"
41#include "wx/headerctrl.h"
42
43#include "wx/generic/gridsel.h"
44#include "wx/generic/grideditors.h"
45#include "wx/generic/private/grid.h"
46
47#if defined(__WXMOTIF__)
48 #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier)
49#else
50 #define WXUNUSED_MOTIF(identifier) identifier
51#endif
52
53#if defined(__WXGTK__)
54 #define WXUNUSED_GTK(identifier) WXUNUSED(identifier)
55#else
56 #define WXUNUSED_GTK(identifier) identifier
57#endif
58
0090b737
SC
59#ifdef __WXOSX__
60#include "wx/osx/private.h"
61#endif
62
a3ef8eb5
VZ
63// Required for wxIs... functions
64#include <ctype.h>
65
66// ============================================================================
67// implementation
68// ============================================================================
69
70// ----------------------------------------------------------------------------
71// wxGridCellEditorEvtHandler
72// ----------------------------------------------------------------------------
73
74void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent& event)
75{
76 // Don't disable the cell if we're just starting to edit it
77 if ( m_inSetFocus )
78 {
79 event.Skip();
80 return;
81 }
82
83 // accept changes
84 m_grid->DisableCellEditControl();
85
86 // notice that we must not skip the event here because the call above may
87 // delete the control which received the kill focus event in the first
88 // place and if we pretend not having processed the event, the search for a
89 // handler for it will continue using the now deleted object resulting in a
90 // crash
91}
92
93void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
94{
95 switch ( event.GetKeyCode() )
96 {
97 case WXK_ESCAPE:
98 m_editor->Reset();
99 m_grid->DisableCellEditControl();
100 break;
101
102 case WXK_TAB:
103 m_grid->GetEventHandler()->ProcessEvent( event );
104 break;
105
106 case WXK_RETURN:
107 case WXK_NUMPAD_ENTER:
108 if (!m_grid->GetEventHandler()->ProcessEvent(event))
109 m_editor->HandleReturn(event);
110 break;
111
112 default:
113 event.Skip();
114 break;
115 }
116}
117
118void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event)
119{
120 int row = m_grid->GetGridCursorRow();
121 int col = m_grid->GetGridCursorCol();
122 wxRect rect = m_grid->CellToRect( row, col );
123 int cw, ch;
124 m_grid->GetGridWindow()->GetClientSize( &cw, &ch );
125
126 // if cell width is smaller than grid client area, cell is wholly visible
127 bool wholeCellVisible = (rect.GetWidth() < cw);
128
129 switch ( event.GetKeyCode() )
130 {
131 case WXK_ESCAPE:
132 case WXK_TAB:
133 case WXK_RETURN:
134 case WXK_NUMPAD_ENTER:
135 break;
136
137 case WXK_HOME:
138 {
139 if ( wholeCellVisible )
140 {
141 // no special processing needed...
142 event.Skip();
143 break;
144 }
145
146 // do special processing for partly visible cell...
147
148 // get the widths of all cells previous to this one
149 int colXPos = 0;
150 for ( int i = 0; i < col; i++ )
151 {
152 colXPos += m_grid->GetColSize(i);
153 }
154
155 int xUnit = 1, yUnit = 1;
156 m_grid->GetScrollPixelsPerUnit(&xUnit, &yUnit);
157 if (col != 0)
158 {
159 m_grid->Scroll(colXPos / xUnit - 1, m_grid->GetScrollPos(wxVERTICAL));
160 }
161 else
162 {
163 m_grid->Scroll(colXPos / xUnit, m_grid->GetScrollPos(wxVERTICAL));
164 }
165 event.Skip();
166 break;
167 }
168
169 case WXK_END:
170 {
171 if ( wholeCellVisible )
172 {
173 // no special processing needed...
174 event.Skip();
175 break;
176 }
177
178 // do special processing for partly visible cell...
179
180 int textWidth = 0;
181 wxString value = m_grid->GetCellValue(row, col);
182 if ( wxEmptyString != value )
183 {
184 // get width of cell CONTENTS (text)
185 int y;
186 wxFont font = m_grid->GetCellFont(row, col);
187 m_grid->GetTextExtent(value, &textWidth, &y, NULL, NULL, &font);
188
189 // try to RIGHT align the text by scrolling
190 int client_right = m_grid->GetGridWindow()->GetClientSize().GetWidth();
191
192 // (m_grid->GetScrollLineX()*2) is a factor for not scrolling to far,
193 // otherwise the last part of the cell content might be hidden below the scroll bar
194 // FIXME: maybe there is a more suitable correction?
195 textWidth -= (client_right - (m_grid->GetScrollLineX() * 2));
196 if ( textWidth < 0 )
197 {
198 textWidth = 0;
199 }
200 }
201
202 // get the widths of all cells previous to this one
203 int colXPos = 0;
204 for ( int i = 0; i < col; i++ )
205 {
206 colXPos += m_grid->GetColSize(i);
207 }
208
209 // and add the (modified) text width of the cell contents
210 // as we'd like to see the last part of the cell contents
211 colXPos += textWidth;
212
213 int xUnit = 1, yUnit = 1;
214 m_grid->GetScrollPixelsPerUnit(&xUnit, &yUnit);
215 m_grid->Scroll(colXPos / xUnit - 1, m_grid->GetScrollPos(wxVERTICAL));
216 event.Skip();
217 break;
218 }
219
220 default:
221 event.Skip();
222 break;
223 }
224}
225
226// ----------------------------------------------------------------------------
227// wxGridCellEditor
228// ----------------------------------------------------------------------------
229
230wxGridCellEditor::wxGridCellEditor()
231{
232 m_control = NULL;
233 m_attr = NULL;
234}
235
236wxGridCellEditor::~wxGridCellEditor()
237{
238 Destroy();
239}
240
241void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
242 wxWindowID WXUNUSED(id),
243 wxEvtHandler* evtHandler)
244{
245 if ( evtHandler )
246 m_control->PushEventHandler(evtHandler);
247}
248
249void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
250 wxGridCellAttr *attr)
251{
252 // erase the background because we might not fill the cell
253 wxClientDC dc(m_control->GetParent());
254 wxGridWindow* gridWindow = wxDynamicCast(m_control->GetParent(), wxGridWindow);
255 if (gridWindow)
256 gridWindow->GetOwner()->PrepareDC(dc);
257
258 dc.SetPen(*wxTRANSPARENT_PEN);
259 dc.SetBrush(wxBrush(attr->GetBackgroundColour()));
260 dc.DrawRectangle(rectCell);
261
262 // redraw the control we just painted over
263 m_control->Refresh();
264}
265
266void wxGridCellEditor::Destroy()
267{
268 if (m_control)
269 {
270 m_control->PopEventHandler( true /* delete it*/ );
271
272 m_control->Destroy();
273 m_control = NULL;
274 }
275}
276
277void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
278{
279 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
280
281 m_control->Show(show);
282
283 if ( show )
284 {
285 // set the colours/fonts if we have any
286 if ( attr )
287 {
288 m_colFgOld = m_control->GetForegroundColour();
289 m_control->SetForegroundColour(attr->GetTextColour());
290
291 m_colBgOld = m_control->GetBackgroundColour();
292 m_control->SetBackgroundColour(attr->GetBackgroundColour());
293
294// Workaround for GTK+1 font setting problem on some platforms
295#if !defined(__WXGTK__) || defined(__WXGTK20__)
296 m_fontOld = m_control->GetFont();
297 m_control->SetFont(attr->GetFont());
298#endif
299
300 // can't do anything more in the base class version, the other
301 // attributes may only be used by the derived classes
302 }
303 }
304 else
305 {
306 // restore the standard colours fonts
a1b806b9 307 if ( m_colFgOld.IsOk() )
a3ef8eb5
VZ
308 {
309 m_control->SetForegroundColour(m_colFgOld);
310 m_colFgOld = wxNullColour;
311 }
312
a1b806b9 313 if ( m_colBgOld.IsOk() )
a3ef8eb5
VZ
314 {
315 m_control->SetBackgroundColour(m_colBgOld);
316 m_colBgOld = wxNullColour;
317 }
318
319// Workaround for GTK+1 font setting problem on some platforms
320#if !defined(__WXGTK__) || defined(__WXGTK20__)
a1b806b9 321 if ( m_fontOld.IsOk() )
a3ef8eb5
VZ
322 {
323 m_control->SetFont(m_fontOld);
324 m_fontOld = wxNullFont;
325 }
326#endif
327 }
328}
329
330void wxGridCellEditor::SetSize(const wxRect& rect)
331{
332 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
333
334 m_control->SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
335}
336
337void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
338{
339 event.Skip();
340}
341
342bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event)
343{
344 bool ctrl = event.ControlDown();
6a1e8a63 345 bool alt;
a3ef8eb5
VZ
346
347#ifdef __WXMAC__
348 // On the Mac the Alt key is more like shift and is used for entry of
349 // valid characters, so check for Ctrl and Meta instead.
350 alt = event.MetaDown();
6a1e8a63
VZ
351#else // !__WXMAC__
352 alt = event.AltDown();
353#endif // __WXMAC__/!__WXMAC__
a3ef8eb5
VZ
354
355 // Assume it's not a valid char if ctrl or alt is down, but if both are
356 // down then it may be because of an AltGr key combination, so let them
357 // through in that case.
358 if ((ctrl || alt) && !(ctrl && alt))
359 return false;
360
361#if wxUSE_UNICODE
97e07b1c 362 if ( static_cast<int>(event.GetUnicodeKey()) == WXK_NONE )
a3ef8eb5
VZ
363 return false;
364#else
6a1e8a63 365 if ( event.GetKeyCode() > WXK_START )
a3ef8eb5
VZ
366 return false;
367#endif
368
369 return true;
370}
371
372void wxGridCellEditor::StartingKey(wxKeyEvent& event)
373{
374 event.Skip();
375}
376
377void wxGridCellEditor::StartingClick()
378{
379}
380
381#if wxUSE_TEXTCTRL
382
383// ----------------------------------------------------------------------------
384// wxGridCellTextEditor
385// ----------------------------------------------------------------------------
386
387wxGridCellTextEditor::wxGridCellTextEditor()
388{
389 m_maxChars = 0;
390}
391
392void wxGridCellTextEditor::Create(wxWindow* parent,
393 wxWindowID id,
394 wxEvtHandler* evtHandler)
395{
396 DoCreate(parent, id, evtHandler);
397}
398
399void wxGridCellTextEditor::DoCreate(wxWindow* parent,
400 wxWindowID id,
401 wxEvtHandler* evtHandler,
402 long style)
403{
0033b1df
VZ
404 // Use of wxTE_RICH2 is a strange hack to work around the bug #11681: a
405 // plain text control seems to lose its caret somehow when we hide it and
406 // show it again for a different cell.
407 style |= wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxNO_BORDER | wxTE_RICH2;
a3ef8eb5
VZ
408
409 m_control = new wxTextCtrl(parent, id, wxEmptyString,
410 wxDefaultPosition, wxDefaultSize,
411 style);
412
0090b737
SC
413#ifdef __WXOSX__
414 wxWidgetImpl* impl = m_control->GetPeer();
415 impl->SetNeedsFocusRect(false);
416#endif
a3ef8eb5
VZ
417 // set max length allowed in the textctrl, if the parameter was set
418 if ( m_maxChars != 0 )
419 {
420 Text()->SetMaxLength(m_maxChars);
421 }
422
423 wxGridCellEditor::Create(parent, id, evtHandler);
424}
425
426void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell),
427 wxGridCellAttr * WXUNUSED(attr))
428{
429 // as we fill the entire client area,
430 // don't do anything here to minimize flicker
431}
432
433void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
434{
435 wxRect rect(rectOrig);
436
437 // Make the edit control large enough to allow for internal margins
438 //
439 // TODO: remove this if the text ctrl sizing is improved esp. for unix
440 //
441#if defined(__WXGTK__)
442 if (rect.x != 0)
443 {
444 rect.x += 1;
445 rect.y += 1;
446 rect.width -= 1;
447 rect.height -= 1;
448 }
449#elif defined(__WXMSW__)
450 if ( rect.x == 0 )
451 rect.x += 2;
452 else
453 rect.x += 3;
454
455 if ( rect.y == 0 )
456 rect.y += 2;
457 else
458 rect.y += 3;
459
460 rect.width -= 2;
461 rect.height -= 2;
0090b737
SC
462#elif defined(__WXOSX__)
463 rect.x += 1;
464 rect.y += 1;
465
466 rect.width -= 1;
467 rect.height -= 1;
a3ef8eb5
VZ
468#else
469 int extra_x = ( rect.x > 2 ) ? 2 : 1;
470 int extra_y = ( rect.y > 2 ) ? 2 : 1;
471
472 #if defined(__WXMOTIF__)
473 extra_x *= 2;
474 extra_y *= 2;
475 #endif
476
477 rect.SetLeft( wxMax(0, rect.x - extra_x) );
478 rect.SetTop( wxMax(0, rect.y - extra_y) );
479 rect.SetRight( rect.GetRight() + 2 * extra_x );
480 rect.SetBottom( rect.GetBottom() + 2 * extra_y );
481#endif
482
483 wxGridCellEditor::SetSize(rect);
484}
485
486void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid)
487{
488 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
489
490 m_value = grid->GetTable()->GetValue(row, col);
491
492 DoBeginEdit(m_value);
493}
494
495void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
496{
497 Text()->SetValue(startValue);
498 Text()->SetInsertionPointEnd();
499 Text()->SetSelection(-1, -1);
500 Text()->SetFocus();
501}
502
503bool wxGridCellTextEditor::EndEdit(int WXUNUSED(row),
504 int WXUNUSED(col),
505 const wxGrid* WXUNUSED(grid),
506 const wxString& WXUNUSED(oldval),
507 wxString *newval)
508{
509 wxCHECK_MSG( m_control, false,
510 "wxGridCellTextEditor must be created first!" );
511
512 const wxString value = Text()->GetValue();
513 if ( value == m_value )
514 return false;
515
516 m_value = value;
517
518 if ( newval )
519 *newval = m_value;
520
521 return true;
522}
523
524void wxGridCellTextEditor::ApplyEdit(int row, int col, wxGrid* grid)
525{
526 grid->GetTable()->SetValue(row, col, m_value);
527 m_value.clear();
528}
529
530void wxGridCellTextEditor::Reset()
531{
532 wxASSERT_MSG( m_control, "wxGridCellTextEditor must be created first!" );
533
534 DoReset(m_value);
535}
536
537void wxGridCellTextEditor::DoReset(const wxString& startValue)
538{
539 Text()->SetValue(startValue);
540 Text()->SetInsertionPointEnd();
541}
542
543bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event)
544{
6a1e8a63
VZ
545 switch ( event.GetKeyCode() )
546 {
547 case WXK_DELETE:
548 case WXK_BACK:
549 return true;
550
551 default:
552 return wxGridCellEditor::IsAcceptedKey(event);
553 }
a3ef8eb5
VZ
554}
555
556void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
557{
558 // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no
559 // longer an appropriate way to get the character into the text control.
560 // Do it ourselves instead. We know that if we get this far that we have
561 // a valid character, so not a whole lot of testing needs to be done.
562
563 wxTextCtrl* tc = Text();
97e07b1c 564 int ch;
a3ef8eb5 565
6a1e8a63
VZ
566 bool isPrintable;
567
a3ef8eb5
VZ
568#if wxUSE_UNICODE
569 ch = event.GetUnicodeKey();
6a1e8a63
VZ
570 if ( ch != WXK_NONE )
571 isPrintable = true;
572 else
573#endif // wxUSE_UNICODE
574 {
97e07b1c 575 ch = event.GetKeyCode();
6a1e8a63
VZ
576 isPrintable = ch >= WXK_SPACE && ch < WXK_START;
577 }
a3ef8eb5
VZ
578
579 switch (ch)
580 {
581 case WXK_DELETE:
b7ff06ad
VZ
582 // Delete the initial character when starting to edit with DELETE.
583 tc->Remove(0, 1);
a3ef8eb5
VZ
584 break;
585
586 case WXK_BACK:
b7ff06ad
VZ
587 // Delete the last character when starting to edit with BACKSPACE.
588 {
589 const long pos = tc->GetLastPosition();
a3ef8eb5 590 tc->Remove(pos - 1, pos);
b7ff06ad 591 }
a3ef8eb5
VZ
592 break;
593
594 default:
6a1e8a63 595 if ( isPrintable )
97e07b1c 596 tc->WriteText(static_cast<wxChar>(ch));
a3ef8eb5
VZ
597 break;
598 }
599}
600
601void wxGridCellTextEditor::HandleReturn( wxKeyEvent&
602 WXUNUSED_GTK(WXUNUSED_MOTIF(event)) )
603{
604#if defined(__WXMOTIF__) || defined(__WXGTK__)
605 // wxMotif needs a little extra help...
606 size_t pos = (size_t)( Text()->GetInsertionPoint() );
607 wxString s( Text()->GetValue() );
608 s = s.Left(pos) + wxT("\n") + s.Mid(pos);
609 Text()->SetValue(s);
610 Text()->SetInsertionPoint( pos );
611#else
612 // the other ports can handle a Return key press
613 //
614 event.Skip();
615#endif
616}
617
618void wxGridCellTextEditor::SetParameters(const wxString& params)
619{
620 if ( !params )
621 {
622 // reset to default
623 m_maxChars = 0;
624 }
625 else
626 {
627 long tmp;
628 if ( params.ToLong(&tmp) )
629 {
630 m_maxChars = (size_t)tmp;
631 }
632 else
633 {
9a83f860 634 wxLogDebug( wxT("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str() );
a3ef8eb5
VZ
635 }
636 }
637}
638
639// return the value in the text control
640wxString wxGridCellTextEditor::GetValue() const
641{
642 return Text()->GetValue();
643}
644
645// ----------------------------------------------------------------------------
646// wxGridCellNumberEditor
647// ----------------------------------------------------------------------------
648
649wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max)
650{
651 m_min = min;
652 m_max = max;
653}
654
655void wxGridCellNumberEditor::Create(wxWindow* parent,
656 wxWindowID id,
657 wxEvtHandler* evtHandler)
658{
659#if wxUSE_SPINCTRL
660 if ( HasRange() )
661 {
662 // create a spin ctrl
663 m_control = new wxSpinCtrl(parent, wxID_ANY, wxEmptyString,
664 wxDefaultPosition, wxDefaultSize,
665 wxSP_ARROW_KEYS,
666 m_min, m_max);
667
668 wxGridCellEditor::Create(parent, id, evtHandler);
669 }
670 else
671#endif
672 {
673 // just a text control
674 wxGridCellTextEditor::Create(parent, id, evtHandler);
675
676#if wxUSE_VALIDATORS
a54cf371 677 Text()->SetValidator(wxIntegerValidator<int>());
a3ef8eb5
VZ
678#endif
679 }
680}
681
682void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
683{
684 // first get the value
685 wxGridTableBase *table = grid->GetTable();
686 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
687 {
688 m_value = table->GetValueAsLong(row, col);
689 }
690 else
691 {
692 m_value = 0;
693 wxString sValue = table->GetValue(row, col);
694 if (! sValue.ToLong(&m_value) && ! sValue.empty())
695 {
9a83f860 696 wxFAIL_MSG( wxT("this cell doesn't have numeric value") );
a3ef8eb5
VZ
697 return;
698 }
699 }
700
701#if wxUSE_SPINCTRL
702 if ( HasRange() )
703 {
704 Spin()->SetValue((int)m_value);
705 Spin()->SetFocus();
706 }
707 else
708#endif
709 {
710 DoBeginEdit(GetString());
711 }
712}
713
714bool wxGridCellNumberEditor::EndEdit(int WXUNUSED(row),
715 int WXUNUSED(col),
716 const wxGrid* WXUNUSED(grid),
717 const wxString& oldval, wxString *newval)
718{
719 long value = 0;
720 wxString text;
721
722#if wxUSE_SPINCTRL
723 if ( HasRange() )
724 {
725 value = Spin()->GetValue();
726 if ( value == m_value )
727 return false;
728
729 text.Printf(wxT("%ld"), value);
730 }
731 else // using unconstrained input
732#endif // wxUSE_SPINCTRL
733 {
734 text = Text()->GetValue();
735 if ( text.empty() )
736 {
737 if ( oldval.empty() )
738 return false;
739 }
740 else // non-empty text now (maybe 0)
741 {
742 if ( !text.ToLong(&value) )
743 return false;
744
745 // if value == m_value == 0 but old text was "" and new one is
746 // "0" something still did change
747 if ( value == m_value && (value || !oldval.empty()) )
748 return false;
749 }
750 }
751
752 m_value = value;
753
754 if ( newval )
755 *newval = text;
756
757 return true;
758}
759
760void wxGridCellNumberEditor::ApplyEdit(int row, int col, wxGrid* grid)
761{
762 wxGridTableBase * const table = grid->GetTable();
763 if ( table->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER) )
764 table->SetValueAsLong(row, col, m_value);
765 else
766 table->SetValue(row, col, wxString::Format("%ld", m_value));
767}
768
769void wxGridCellNumberEditor::Reset()
770{
771#if wxUSE_SPINCTRL
772 if ( HasRange() )
773 {
774 Spin()->SetValue((int)m_value);
775 }
776 else
777#endif
778 {
779 DoReset(GetString());
780 }
781}
782
783bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent& event)
784{
785 if ( wxGridCellEditor::IsAcceptedKey(event) )
786 {
787 int keycode = event.GetKeyCode();
788 if ( (keycode < 128) &&
789 (wxIsdigit(keycode) || keycode == '+' || keycode == '-'))
790 {
791 return true;
792 }
793 }
794
795 return false;
796}
797
798void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event)
799{
800 int keycode = event.GetKeyCode();
801 if ( !HasRange() )
802 {
803 if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-')
804 {
805 wxGridCellTextEditor::StartingKey(event);
806
807 // skip Skip() below
808 return;
809 }
810 }
811#if wxUSE_SPINCTRL
812 else
813 {
814 if ( wxIsdigit(keycode) )
815 {
816 wxSpinCtrl* spin = (wxSpinCtrl*)m_control;
817 spin->SetValue(keycode - '0');
818 spin->SetSelection(1,1);
819 return;
820 }
821 }
822#endif
823
824 event.Skip();
825}
826
827void wxGridCellNumberEditor::SetParameters(const wxString& params)
828{
829 if ( !params )
830 {
831 // reset to default
832 m_min =
833 m_max = -1;
834 }
835 else
836 {
837 long tmp;
9a83f860 838 if ( params.BeforeFirst(wxT(',')).ToLong(&tmp) )
a3ef8eb5
VZ
839 {
840 m_min = (int)tmp;
841
9a83f860 842 if ( params.AfterFirst(wxT(',')).ToLong(&tmp) )
a3ef8eb5
VZ
843 {
844 m_max = (int)tmp;
845
846 // skip the error message below
847 return;
848 }
849 }
850
9a83f860 851 wxLogDebug(wxT("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str());
a3ef8eb5
VZ
852 }
853}
854
855// return the value in the spin control if it is there (the text control otherwise)
856wxString wxGridCellNumberEditor::GetValue() const
857{
858 wxString s;
859
860#if wxUSE_SPINCTRL
861 if ( HasRange() )
862 {
863 long value = Spin()->GetValue();
864 s.Printf(wxT("%ld"), value);
865 }
866 else
867#endif
868 {
869 s = Text()->GetValue();
870 }
871
872 return s;
873}
874
875// ----------------------------------------------------------------------------
876// wxGridCellFloatEditor
877// ----------------------------------------------------------------------------
878
1d8d3cc5
VZ
879wxGridCellFloatEditor::wxGridCellFloatEditor(int width,
880 int precision,
881 int format)
a3ef8eb5
VZ
882{
883 m_width = width;
884 m_precision = precision;
1d8d3cc5 885 m_style = format;
a3ef8eb5
VZ
886}
887
888void wxGridCellFloatEditor::Create(wxWindow* parent,
889 wxWindowID id,
890 wxEvtHandler* evtHandler)
891{
892 wxGridCellTextEditor::Create(parent, id, evtHandler);
893
894#if wxUSE_VALIDATORS
a54cf371 895 Text()->SetValidator(wxFloatingPointValidator<double>(m_precision));
a3ef8eb5
VZ
896#endif
897}
898
899void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid)
900{
901 // first get the value
902 wxGridTableBase * const table = grid->GetTable();
903 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
904 {
905 m_value = table->GetValueAsDouble(row, col);
906 }
907 else
908 {
909 m_value = 0.0;
910
911 const wxString value = table->GetValue(row, col);
912 if ( !value.empty() )
913 {
914 if ( !value.ToDouble(&m_value) )
915 {
9a83f860 916 wxFAIL_MSG( wxT("this cell doesn't have float value") );
a3ef8eb5
VZ
917 return;
918 }
919 }
920 }
921
922 DoBeginEdit(GetString());
923}
924
925bool wxGridCellFloatEditor::EndEdit(int WXUNUSED(row),
926 int WXUNUSED(col),
927 const wxGrid* WXUNUSED(grid),
928 const wxString& oldval, wxString *newval)
929{
930 const wxString text(Text()->GetValue());
931
932 double value;
933 if ( !text.empty() )
934 {
935 if ( !text.ToDouble(&value) )
936 return false;
937 }
938 else // new value is empty string
939 {
940 if ( oldval.empty() )
941 return false; // nothing changed
942
943 value = 0.;
944 }
945
946 // the test for empty strings ensures that we don't skip the value setting
947 // when "" is replaced by "0" or vice versa as "" numeric value is also 0.
948 if ( wxIsSameDouble(value, m_value) && !text.empty() && !oldval.empty() )
949 return false; // nothing changed
950
951 m_value = value;
952
953 if ( newval )
954 *newval = text;
955
956 return true;
957}
958
959void wxGridCellFloatEditor::ApplyEdit(int row, int col, wxGrid* grid)
960{
961 wxGridTableBase * const table = grid->GetTable();
962
963 if ( table->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT) )
964 table->SetValueAsDouble(row, col, m_value);
965 else
966 table->SetValue(row, col, Text()->GetValue());
967}
968
969void wxGridCellFloatEditor::Reset()
970{
971 DoReset(GetString());
972}
973
974void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
975{
976 int keycode = event.GetKeyCode();
977 char tmpbuf[2];
978 tmpbuf[0] = (char) keycode;
979 tmpbuf[1] = '\0';
980 wxString strbuf(tmpbuf, *wxConvCurrent);
981
982#if wxUSE_INTL
983 bool is_decimal_point = ( strbuf ==
984 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER) );
985#else
9a83f860 986 bool is_decimal_point = ( strbuf == wxT(".") );
a3ef8eb5
VZ
987#endif
988
989 if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-'
990 || is_decimal_point )
991 {
992 wxGridCellTextEditor::StartingKey(event);
993
994 // skip Skip() below
995 return;
996 }
997
998 event.Skip();
999}
1000
1001void wxGridCellFloatEditor::SetParameters(const wxString& params)
1002{
1003 if ( !params )
1004 {
1005 // reset to default
1006 m_width =
1007 m_precision = -1;
1d8d3cc5
VZ
1008 m_style = wxGRID_FLOAT_FORMAT_DEFAULT;
1009 m_format.clear();
a3ef8eb5
VZ
1010 }
1011 else
1012 {
1d8d3cc5
VZ
1013 wxString rest;
1014 wxString tmp = params.BeforeFirst(wxT(','), &rest);
1015 if ( !tmp.empty() )
a3ef8eb5 1016 {
1d8d3cc5
VZ
1017 long width;
1018 if ( tmp.ToLong(&width) )
1019 {
1020 m_width = (int)width;
1021 }
1022 else
a3ef8eb5 1023 {
1d8d3cc5
VZ
1024 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
1025 }
1026 }
a3ef8eb5 1027
1d8d3cc5
VZ
1028 tmp = rest.BeforeFirst(wxT(','));
1029 if ( !tmp.empty() )
1030 {
1031 long precision;
1032 if ( tmp.ToLong(&precision) )
1033 {
1034 m_precision = (int)precision;
1035 }
1036 else
1037 {
1038 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
a3ef8eb5
VZ
1039 }
1040 }
1041
1d8d3cc5
VZ
1042 tmp = rest.AfterFirst(wxT(','));
1043 if ( !tmp.empty() )
1044 {
1045 if ( tmp[0] == wxT('f') )
1046 {
1047 m_style = wxGRID_FLOAT_FORMAT_FIXED;
1048 }
1049 else if ( tmp[0] == wxT('e') )
1050 {
1051 m_style = wxGRID_FLOAT_FORMAT_SCIENTIFIC;
1052 }
1053 else if ( tmp[0] == wxT('g') )
1054 {
1055 m_style = wxGRID_FLOAT_FORMAT_COMPACT;
1056 }
1057 else if ( tmp[0] == wxT('E') )
1058 {
1059 m_style = wxGRID_FLOAT_FORMAT_SCIENTIFIC |
1060 wxGRID_FLOAT_FORMAT_UPPER;
1061 }
1062 else if ( tmp[0] == wxT('F') )
1063 {
1064 m_style = wxGRID_FLOAT_FORMAT_FIXED |
1065 wxGRID_FLOAT_FORMAT_UPPER;
1066 }
1067 else if ( tmp[0] == wxT('G') )
1068 {
1069 m_style = wxGRID_FLOAT_FORMAT_COMPACT |
1070 wxGRID_FLOAT_FORMAT_UPPER;
1071 }
1072 else
1073 {
1074 wxLogDebug("Invalid wxGridCellFloatRenderer format "
1075 "parameter string '%s ignored", params);
1076 }
1077 }
a3ef8eb5
VZ
1078 }
1079}
1080
1d8d3cc5 1081wxString wxGridCellFloatEditor::GetString()
a3ef8eb5 1082{
1d8d3cc5 1083 if ( !m_format )
a3ef8eb5 1084 {
1d8d3cc5
VZ
1085 if ( m_precision == -1 && m_width != -1)
1086 {
1087 // default precision
1088 m_format.Printf(wxT("%%%d."), m_width);
1089 }
1090 else if ( m_precision != -1 && m_width == -1)
1091 {
1092 // default width
1093 m_format.Printf(wxT("%%.%d"), m_precision);
1094 }
1095 else if ( m_precision != -1 && m_width != -1 )
1096 {
1097 m_format.Printf(wxT("%%%d.%d"), m_width, m_precision);
1098 }
1099 else
1100 {
1101 // default width/precision
1102 m_format = wxT("%");
1103 }
1104
1105 bool isUpper = (m_style & wxGRID_FLOAT_FORMAT_UPPER) != 0;
1106 if ( m_style & wxGRID_FLOAT_FORMAT_SCIENTIFIC )
1107 m_format += isUpper ? wxT('E') : wxT('e');
1108 else if ( m_style & wxGRID_FLOAT_FORMAT_COMPACT )
1109 m_format += isUpper ? wxT('G') : wxT('g');
1110 else
1111 m_format += wxT('f');
a3ef8eb5
VZ
1112 }
1113
1d8d3cc5 1114 return wxString::Format(m_format, m_value);
a3ef8eb5
VZ
1115}
1116
1117bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event)
1118{
1119 if ( wxGridCellEditor::IsAcceptedKey(event) )
1120 {
1121 const int keycode = event.GetKeyCode();
7a0079d5 1122 if ( wxIsascii(keycode) )
a3ef8eb5 1123 {
a3ef8eb5
VZ
1124#if wxUSE_INTL
1125 const wxString decimalPoint =
1126 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
1127#else
9a83f860 1128 const wxString decimalPoint(wxT('.'));
a3ef8eb5
VZ
1129#endif
1130
1131 // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
1132 if ( wxIsdigit(keycode) ||
1133 tolower(keycode) == 'e' ||
1134 keycode == decimalPoint ||
1135 keycode == '+' ||
1136 keycode == '-' )
1137 {
1138 return true;
1139 }
1140 }
1141 }
1142
1143 return false;
1144}
1145
1146#endif // wxUSE_TEXTCTRL
1147
1148#if wxUSE_CHECKBOX
1149
1150// ----------------------------------------------------------------------------
1151// wxGridCellBoolEditor
1152// ----------------------------------------------------------------------------
1153
1154// the default values for GetValue()
9a83f860 1155wxString wxGridCellBoolEditor::ms_stringValues[2] = { wxT(""), wxT("1") };
a3ef8eb5
VZ
1156
1157void wxGridCellBoolEditor::Create(wxWindow* parent,
1158 wxWindowID id,
1159 wxEvtHandler* evtHandler)
1160{
1161 m_control = new wxCheckBox(parent, id, wxEmptyString,
1162 wxDefaultPosition, wxDefaultSize,
1163 wxNO_BORDER);
1164
1165 wxGridCellEditor::Create(parent, id, evtHandler);
1166}
1167
1168void wxGridCellBoolEditor::SetSize(const wxRect& r)
1169{
1170 bool resize = false;
1171 wxSize size = m_control->GetSize();
1172 wxCoord minSize = wxMin(r.width, r.height);
1173
1174 // check if the checkbox is not too big/small for this cell
1175 wxSize sizeBest = m_control->GetBestSize();
1176 if ( !(size == sizeBest) )
1177 {
1178 // reset to default size if it had been made smaller
1179 size = sizeBest;
1180
1181 resize = true;
1182 }
1183
1184 if ( size.x >= minSize || size.y >= minSize )
1185 {
1186 // leave 1 pixel margin
1187 size.x = size.y = minSize - 2;
1188
1189 resize = true;
1190 }
1191
1192 if ( resize )
1193 {
1194 m_control->SetSize(size);
1195 }
1196
1197 // position it in the centre of the rectangle (TODO: support alignment?)
1198
1199#if defined(__WXGTK__) || defined (__WXMOTIF__)
1200 // the checkbox without label still has some space to the right in wxGTK,
1201 // so shift it to the right
1202 size.x -= 8;
1203#elif defined(__WXMSW__)
1204 // here too, but in other way
1205 size.x += 1;
1206 size.y -= 2;
1207#endif
1208
1209 int hAlign = wxALIGN_CENTRE;
1210 int vAlign = wxALIGN_CENTRE;
1211 if (GetCellAttr())
1212 GetCellAttr()->GetAlignment(& hAlign, & vAlign);
1213
1214 int x = 0, y = 0;
1215 if (hAlign == wxALIGN_LEFT)
1216 {
1217 x = r.x + 2;
1218
1219#ifdef __WXMSW__
1220 x += 2;
1221#endif
1222
1223 y = r.y + r.height / 2 - size.y / 2;
1224 }
1225 else if (hAlign == wxALIGN_RIGHT)
1226 {
1227 x = r.x + r.width - size.x - 2;
1228 y = r.y + r.height / 2 - size.y / 2;
1229 }
1230 else if (hAlign == wxALIGN_CENTRE)
1231 {
1232 x = r.x + r.width / 2 - size.x / 2;
1233 y = r.y + r.height / 2 - size.y / 2;
1234 }
1235
1236 m_control->Move(x, y);
1237}
1238
1239void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
1240{
1241 m_control->Show(show);
1242
1243 if ( show )
1244 {
1245 wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
1246 CBox()->SetBackgroundColour(colBg);
1247 }
1248}
1249
1250void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid)
1251{
1252 wxASSERT_MSG(m_control,
1253 wxT("The wxGridCellEditor must be created first!"));
1254
1255 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
1256 {
1257 m_value = grid->GetTable()->GetValueAsBool(row, col);
1258 }
1259 else
1260 {
1261 wxString cellval( grid->GetTable()->GetValue(row, col) );
1262
1263 if ( cellval == ms_stringValues[false] )
1264 m_value = false;
1265 else if ( cellval == ms_stringValues[true] )
1266 m_value = true;
1267 else
1268 {
1269 // do not try to be smart here and convert it to true or false
1270 // because we'll still overwrite it with something different and
1271 // this risks to be very surprising for the user code, let them
1272 // know about it
9a83f860 1273 wxFAIL_MSG( wxT("invalid value for a cell with bool editor!") );
a3ef8eb5
VZ
1274 }
1275 }
1276
1277 CBox()->SetValue(m_value);
1278 CBox()->SetFocus();
1279}
1280
1281bool wxGridCellBoolEditor::EndEdit(int WXUNUSED(row),
1282 int WXUNUSED(col),
1283 const wxGrid* WXUNUSED(grid),
1284 const wxString& WXUNUSED(oldval),
1285 wxString *newval)
1286{
1287 bool value = CBox()->GetValue();
1288 if ( value == m_value )
1289 return false;
1290
1291 m_value = value;
1292
1293 if ( newval )
1294 *newval = GetValue();
1295
1296 return true;
1297}
1298
1299void wxGridCellBoolEditor::ApplyEdit(int row, int col, wxGrid* grid)
1300{
1301 wxGridTableBase * const table = grid->GetTable();
1302 if ( table->CanSetValueAs(row, col, wxGRID_VALUE_BOOL) )
1303 table->SetValueAsBool(row, col, m_value);
1304 else
1305 table->SetValue(row, col, GetValue());
1306}
1307
1308void wxGridCellBoolEditor::Reset()
1309{
1310 wxASSERT_MSG(m_control,
1311 wxT("The wxGridCellEditor must be created first!"));
1312
1313 CBox()->SetValue(m_value);
1314}
1315
1316void wxGridCellBoolEditor::StartingClick()
1317{
1318 CBox()->SetValue(!CBox()->GetValue());
1319}
1320
1321bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent& event)
1322{
1323 if ( wxGridCellEditor::IsAcceptedKey(event) )
1324 {
1325 int keycode = event.GetKeyCode();
1326 switch ( keycode )
1327 {
1328 case WXK_SPACE:
1329 case '+':
1330 case '-':
1331 return true;
1332 }
1333 }
1334
1335 return false;
1336}
1337
1338void wxGridCellBoolEditor::StartingKey(wxKeyEvent& event)
1339{
1340 int keycode = event.GetKeyCode();
1341 switch ( keycode )
1342 {
1343 case WXK_SPACE:
1344 CBox()->SetValue(!CBox()->GetValue());
1345 break;
1346
1347 case '+':
1348 CBox()->SetValue(true);
1349 break;
1350
1351 case '-':
1352 CBox()->SetValue(false);
1353 break;
1354 }
1355}
1356
1357wxString wxGridCellBoolEditor::GetValue() const
1358{
1359 return ms_stringValues[CBox()->GetValue()];
1360}
1361
1362/* static */ void
1363wxGridCellBoolEditor::UseStringValues(const wxString& valueTrue,
1364 const wxString& valueFalse)
1365{
1366 ms_stringValues[false] = valueFalse;
1367 ms_stringValues[true] = valueTrue;
1368}
1369
1370/* static */ bool
1371wxGridCellBoolEditor::IsTrueValue(const wxString& value)
1372{
1373 return value == ms_stringValues[true];
1374}
1375
1376#endif // wxUSE_CHECKBOX
1377
1378#if wxUSE_COMBOBOX
1379
1380// ----------------------------------------------------------------------------
1381// wxGridCellChoiceEditor
1382// ----------------------------------------------------------------------------
1383
1384wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString& choices,
1385 bool allowOthers)
1386 : m_choices(choices),
1387 m_allowOthers(allowOthers) { }
1388
1389wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count,
1390 const wxString choices[],
1391 bool allowOthers)
1392 : m_allowOthers(allowOthers)
1393{
1394 if ( count )
1395 {
1396 m_choices.Alloc(count);
1397 for ( size_t n = 0; n < count; n++ )
1398 {
1399 m_choices.Add(choices[n]);
1400 }
1401 }
1402}
1403
1404wxGridCellEditor *wxGridCellChoiceEditor::Clone() const
1405{
1406 wxGridCellChoiceEditor *editor = new wxGridCellChoiceEditor;
1407 editor->m_allowOthers = m_allowOthers;
1408 editor->m_choices = m_choices;
1409
1410 return editor;
1411}
1412
1413void wxGridCellChoiceEditor::Create(wxWindow* parent,
1414 wxWindowID id,
1415 wxEvtHandler* evtHandler)
1416{
1417 int style = wxTE_PROCESS_ENTER |
1418 wxTE_PROCESS_TAB |
1419 wxBORDER_NONE;
1420
1421 if ( !m_allowOthers )
1422 style |= wxCB_READONLY;
1423 m_control = new wxComboBox(parent, id, wxEmptyString,
1424 wxDefaultPosition, wxDefaultSize,
1425 m_choices,
1426 style);
1427
1428 wxGridCellEditor::Create(parent, id, evtHandler);
1429}
1430
e59e670c
VZ
1431void wxGridCellChoiceEditor::SetSize(const wxRect& rect)
1432{
1433 wxASSERT_MSG(m_control,
1434 wxT("The wxGridCellChoiceEditor must be created first!"));
1435
1436 // Check that the height is not too small to fit the combobox.
1437 wxRect rectTallEnough = rect;
1438 const wxSize bestSize = m_control->GetBestSize();
1439 const wxCoord diffY = bestSize.GetHeight() - rectTallEnough.GetHeight();
1440 if ( diffY > 0 )
1441 {
1442 // Do make it tall enough.
1443 rectTallEnough.height += diffY;
1444
1445 // Also centre the effective rectangle vertically with respect to the
1446 // original one.
1447 rectTallEnough.y -= diffY/2;
1448 }
1449 //else: The rectangle provided is already tall enough.
1450
1451 wxGridCellEditor::SetSize(rectTallEnough);
1452}
1453
a3ef8eb5
VZ
1454void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
1455 wxGridCellAttr * attr)
1456{
1457 // as we fill the entire client area, don't do anything here to minimize
1458 // flicker
1459
1460 // TODO: It doesn't actually fill the client area since the height of a
1461 // combo always defaults to the standard. Until someone has time to
1462 // figure out the right rectangle to paint, just do it the normal way.
1463 wxGridCellEditor::PaintBackground(rectCell, attr);
1464}
1465
1466void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
1467{
1468 wxASSERT_MSG(m_control,
1469 wxT("The wxGridCellEditor must be created first!"));
1470
1471 wxGridCellEditorEvtHandler* evtHandler = NULL;
1472 if (m_control)
1473 evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler);
1474
1475 // Don't immediately end if we get a kill focus event within BeginEdit
1476 if (evtHandler)
1477 evtHandler->SetInSetFocus(true);
1478
1479 m_value = grid->GetTable()->GetValue(row, col);
1480
1481 Reset(); // this updates combo box to correspond to m_value
1482
1483 Combo()->SetFocus();
1484
cf82560a
VZ
1485#ifdef __WXOSX_COCOA__
1486 // This is a work around for the combobox being simply dismissed when a
1487 // choice is made in it under OS X. The bug is almost certainly due to a
1488 // problem in focus events generation logic but it's not obvious to fix and
1489 // for now this at least allows to use wxGrid.
1490 Combo()->Popup();
1491#endif
1492
a3ef8eb5
VZ
1493 if (evtHandler)
1494 {
1495 // When dropping down the menu, a kill focus event
1496 // happens after this point, so we can't reset the flag yet.
1497#if !defined(__WXGTK20__)
1498 evtHandler->SetInSetFocus(false);
1499#endif
1500 }
1501}
1502
1503bool wxGridCellChoiceEditor::EndEdit(int WXUNUSED(row),
1504 int WXUNUSED(col),
1505 const wxGrid* WXUNUSED(grid),
1506 const wxString& WXUNUSED(oldval),
1507 wxString *newval)
1508{
1509 const wxString value = Combo()->GetValue();
1510 if ( value == m_value )
1511 return false;
1512
1513 m_value = value;
1514
1515 if ( newval )
1516 *newval = value;
1517
1518 return true;
1519}
1520
1521void wxGridCellChoiceEditor::ApplyEdit(int row, int col, wxGrid* grid)
1522{
1523 grid->GetTable()->SetValue(row, col, m_value);
1524}
1525
1526void wxGridCellChoiceEditor::Reset()
1527{
1528 if (m_allowOthers)
1529 {
1530 Combo()->SetValue(m_value);
1531 Combo()->SetInsertionPointEnd();
1532 }
1533 else // the combobox is read-only
1534 {
1535 // find the right position, or default to the first if not found
1536 int pos = Combo()->FindString(m_value);
1537 if (pos == wxNOT_FOUND)
1538 pos = 0;
1539 Combo()->SetSelection(pos);
1540 }
1541}
1542
1543void wxGridCellChoiceEditor::SetParameters(const wxString& params)
1544{
1545 if ( !params )
1546 {
1547 // what can we do?
1548 return;
1549 }
1550
1551 m_choices.Empty();
1552
9a83f860 1553 wxStringTokenizer tk(params, wxT(','));
a3ef8eb5
VZ
1554 while ( tk.HasMoreTokens() )
1555 {
1556 m_choices.Add(tk.GetNextToken());
1557 }
1558}
1559
1560// return the value in the text control
1561wxString wxGridCellChoiceEditor::GetValue() const
1562{
1563 return Combo()->GetValue();
1564}
1565
1566#endif // wxUSE_COMBOBOX
1567
1568#if wxUSE_COMBOBOX
1569
1570// ----------------------------------------------------------------------------
1571// wxGridCellEnumEditor
1572// ----------------------------------------------------------------------------
1573
1574// A cell editor which displays an enum number as a textual equivalent. eg
1575// data in cell is 0,1,2 ... n the cell could be displayed as
1576// "John","Fred"..."Bob" in the combo choice box
1577
1578wxGridCellEnumEditor::wxGridCellEnumEditor(const wxString& choices)
1579 :wxGridCellChoiceEditor()
1580{
1581 m_index = -1;
1582
1583 if (!choices.empty())
1584 SetParameters(choices);
1585}
1586
1587wxGridCellEditor *wxGridCellEnumEditor::Clone() const
1588{
1589 wxGridCellEnumEditor *editor = new wxGridCellEnumEditor();
1590 editor->m_index = m_index;
1591 return editor;
1592}
1593
1594void wxGridCellEnumEditor::BeginEdit(int row, int col, wxGrid* grid)
1595{
1596 wxASSERT_MSG(m_control,
1597 wxT("The wxGridCellEnumEditor must be Created first!"));
1598
3ac2562a
VZ
1599 wxGridCellEditorEvtHandler* evtHandler = NULL;
1600 if (m_control)
1601 evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler);
1602
1603 // Don't immediately end if we get a kill focus event within BeginEdit
1604 if (evtHandler)
1605 evtHandler->SetInSetFocus(true);
1606
a3ef8eb5
VZ
1607 wxGridTableBase *table = grid->GetTable();
1608
1609 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
1610 {
1611 m_index = table->GetValueAsLong(row, col);
1612 }
1613 else
1614 {
1615 wxString startValue = table->GetValue(row, col);
1616 if (startValue.IsNumber() && !startValue.empty())
1617 {
1618 startValue.ToLong(&m_index);
1619 }
1620 else
1621 {
1622 m_index = -1;
1623 }
1624 }
1625
1626 Combo()->SetSelection(m_index);
a3ef8eb5
VZ
1627 Combo()->SetFocus();
1628
3ac2562a
VZ
1629#ifdef __WXOSX_COCOA__
1630 // This is a work around for the combobox being simply dismissed when a
1631 // choice is made in it under OS X. The bug is almost certainly due to a
1632 // problem in focus events generation logic but it's not obvious to fix and
1633 // for now this at least allows to use wxGrid.
1634 Combo()->Popup();
1635#endif
1636
1637 if (evtHandler)
1638 {
1639 // When dropping down the menu, a kill focus event
1640 // happens after this point, so we can't reset the flag yet.
1641#if !defined(__WXGTK20__)
1642 evtHandler->SetInSetFocus(false);
1643#endif
1644 }
a3ef8eb5
VZ
1645}
1646
1647bool wxGridCellEnumEditor::EndEdit(int WXUNUSED(row),
1648 int WXUNUSED(col),
1649 const wxGrid* WXUNUSED(grid),
1650 const wxString& WXUNUSED(oldval),
1651 wxString *newval)
1652{
1653 long idx = Combo()->GetSelection();
1654 if ( idx == m_index )
1655 return false;
1656
1657 m_index = idx;
1658
1659 if ( newval )
1660 newval->Printf("%ld", m_index);
1661
1662 return true;
1663}
1664
1665void wxGridCellEnumEditor::ApplyEdit(int row, int col, wxGrid* grid)
1666{
1667 wxGridTableBase * const table = grid->GetTable();
1668 if ( table->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER) )
1669 table->SetValueAsLong(row, col, m_index);
1670 else
1671 table->SetValue(row, col, wxString::Format("%ld", m_index));
1672}
1673
1674#endif // wxUSE_COMBOBOX
1675
1676// ----------------------------------------------------------------------------
1677// wxGridCellAutoWrapStringEditor
1678// ----------------------------------------------------------------------------
1679
1680void
1681wxGridCellAutoWrapStringEditor::Create(wxWindow* parent,
1682 wxWindowID id,
1683 wxEvtHandler* evtHandler)
1684{
1685 wxGridCellTextEditor::DoCreate(parent, id, evtHandler,
1686 wxTE_MULTILINE | wxTE_RICH);
1687}
1688
1689
1690#endif // wxUSE_GRID