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