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