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