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