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