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