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