/[pcsx2_0.9.7]/trunk/3rdparty/wxWidgets/src/generic/grid.cpp
ViewVC logotype

Contents of /trunk/3rdparty/wxWidgets/src/generic/grid.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years, 1 month ago) by william
File size: 325071 byte(s)
committing r3113 initial commit again...
1 ///////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/grid.cpp
3 // Purpose: wxGrid and related classes
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: grid.cpp 58753 2009-02-08 10:23:19Z VZ $
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/valtext.h"
32 #include "wx/intl.h"
33 #include "wx/math.h"
34 #include "wx/listbox.h"
35 #endif
36
37 #include "wx/textfile.h"
38 #include "wx/spinctrl.h"
39 #include "wx/tokenzr.h"
40 #include "wx/renderer.h"
41
42 #include "wx/generic/gridsel.h"
43
44 const wxChar wxGridNameStr[] = wxT("grid");
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
58 // Required for wxIs... functions
59 #include <ctype.h>
60
61 // ----------------------------------------------------------------------------
62 // array classes
63 // ----------------------------------------------------------------------------
64
65 WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridCellAttr *, wxArrayAttrs,
66 class WXDLLIMPEXP_ADV);
67
68 struct wxGridCellWithAttr
69 {
70 wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_)
71 : coords(row, col), attr(attr_)
72 {
73 wxASSERT( attr );
74 }
75
76 wxGridCellWithAttr(const wxGridCellWithAttr& other)
77 : coords(other.coords),
78 attr(other.attr)
79 {
80 attr->IncRef();
81 }
82
83 wxGridCellWithAttr& operator=(const wxGridCellWithAttr& other)
84 {
85 coords = other.coords;
86 if (attr != other.attr)
87 {
88 attr->DecRef();
89 attr = other.attr;
90 attr->IncRef();
91 }
92 return *this;
93 }
94
95 void ChangeAttr(wxGridCellAttr * new_attr)
96 {
97 if (attr != new_attr)
98 {
99 // "Delete" (i.e. DecRef) the old attribute.
100 attr->DecRef();
101 attr = new_attr;
102 // Take ownership of the new attribute, i.e. no IncRef.
103 }
104 }
105
106 ~wxGridCellWithAttr()
107 {
108 attr->DecRef();
109 }
110
111 wxGridCellCoords coords;
112 wxGridCellAttr *attr;
113 };
114
115 WX_DECLARE_OBJARRAY_WITH_DECL(wxGridCellWithAttr, wxGridCellWithAttrArray,
116 class WXDLLIMPEXP_ADV);
117
118 #include "wx/arrimpl.cpp"
119
120 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
121 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
122
123 // ----------------------------------------------------------------------------
124 // events
125 // ----------------------------------------------------------------------------
126
127 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_CLICK)
128 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_CLICK)
129 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_DCLICK)
130 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_DCLICK)
131 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_BEGIN_DRAG)
132 DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_CLICK)
133 DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_CLICK)
134 DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK)
135 DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK)
136 DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE)
137 DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE)
138 DEFINE_EVENT_TYPE(wxEVT_GRID_COL_MOVE)
139 DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT)
140 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE)
141 DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL)
142 DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN)
143 DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN)
144 DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED)
145
146 // ----------------------------------------------------------------------------
147 // private classes
148 // ----------------------------------------------------------------------------
149
150 class WXDLLIMPEXP_ADV wxGridRowLabelWindow : public wxWindow
151 {
152 public:
153 wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; }
154 wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
155 const wxPoint &pos, const wxSize &size );
156
157 virtual bool AcceptsFocus() const { return false; }
158
159 private:
160 wxGrid *m_owner;
161
162 void OnPaint( wxPaintEvent& event );
163 void OnMouseEvent( wxMouseEvent& event );
164 void OnMouseWheel( wxMouseEvent& event );
165 void OnKeyDown( wxKeyEvent& event );
166 void OnKeyUp( wxKeyEvent& );
167 void OnChar( wxKeyEvent& );
168
169 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
170 DECLARE_EVENT_TABLE()
171 DECLARE_NO_COPY_CLASS(wxGridRowLabelWindow)
172 };
173
174
175 class WXDLLIMPEXP_ADV wxGridColLabelWindow : public wxWindow
176 {
177 public:
178 wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; }
179 wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
180 const wxPoint &pos, const wxSize &size );
181
182 virtual bool AcceptsFocus() const { return false; }
183
184 private:
185 wxGrid *m_owner;
186
187 void OnPaint( wxPaintEvent& event );
188 void OnMouseEvent( wxMouseEvent& event );
189 void OnMouseWheel( wxMouseEvent& event );
190 void OnKeyDown( wxKeyEvent& event );
191 void OnKeyUp( wxKeyEvent& );
192 void OnChar( wxKeyEvent& );
193
194 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
195 DECLARE_EVENT_TABLE()
196 DECLARE_NO_COPY_CLASS(wxGridColLabelWindow)
197 };
198
199
200 class WXDLLIMPEXP_ADV wxGridCornerLabelWindow : public wxWindow
201 {
202 public:
203 wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; }
204 wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
205 const wxPoint &pos, const wxSize &size );
206
207 virtual bool AcceptsFocus() const { return false; }
208
209 private:
210 wxGrid *m_owner;
211
212 void OnMouseEvent( wxMouseEvent& event );
213 void OnMouseWheel( wxMouseEvent& event );
214 void OnKeyDown( wxKeyEvent& event );
215 void OnKeyUp( wxKeyEvent& );
216 void OnChar( wxKeyEvent& );
217 void OnPaint( wxPaintEvent& event );
218
219 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
220 DECLARE_EVENT_TABLE()
221 DECLARE_NO_COPY_CLASS(wxGridCornerLabelWindow)
222 };
223
224 class WXDLLIMPEXP_ADV wxGridWindow : public wxWindow
225 {
226 public:
227 wxGridWindow()
228 {
229 m_owner = NULL;
230 m_rowLabelWin = NULL;
231 m_colLabelWin = NULL;
232 }
233
234 wxGridWindow( wxGrid *parent,
235 wxGridRowLabelWindow *rowLblWin,
236 wxGridColLabelWindow *colLblWin,
237 wxWindowID id, const wxPoint &pos, const wxSize &size );
238 virtual ~wxGridWindow() {}
239
240 void ScrollWindow( int dx, int dy, const wxRect *rect );
241
242 wxGrid* GetOwner() { return m_owner; }
243
244 private:
245 wxGrid *m_owner;
246 wxGridRowLabelWindow *m_rowLabelWin;
247 wxGridColLabelWindow *m_colLabelWin;
248
249 void OnPaint( wxPaintEvent &event );
250 void OnMouseWheel( wxMouseEvent& event );
251 void OnMouseEvent( wxMouseEvent& event );
252 void OnKeyDown( wxKeyEvent& );
253 void OnKeyUp( wxKeyEvent& );
254 void OnChar( wxKeyEvent& );
255 void OnEraseBackground( wxEraseEvent& );
256 void OnFocus( wxFocusEvent& );
257
258 DECLARE_DYNAMIC_CLASS(wxGridWindow)
259 DECLARE_EVENT_TABLE()
260 DECLARE_NO_COPY_CLASS(wxGridWindow)
261 };
262
263
264 class wxGridCellEditorEvtHandler : public wxEvtHandler
265 {
266 public:
267 wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor)
268 : m_grid(grid),
269 m_editor(editor),
270 m_inSetFocus(false)
271 {
272 }
273
274 void OnKillFocus(wxFocusEvent& event);
275 void OnKeyDown(wxKeyEvent& event);
276 void OnChar(wxKeyEvent& event);
277
278 void SetInSetFocus(bool inSetFocus) { m_inSetFocus = inSetFocus; }
279
280 private:
281 wxGrid *m_grid;
282 wxGridCellEditor *m_editor;
283
284 // Work around the fact that a focus kill event can be sent to
285 // a combobox within a set focus event.
286 bool m_inSetFocus;
287
288 DECLARE_EVENT_TABLE()
289 DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler)
290 DECLARE_NO_COPY_CLASS(wxGridCellEditorEvtHandler)
291 };
292
293
294 IMPLEMENT_ABSTRACT_CLASS(wxGridCellEditorEvtHandler, wxEvtHandler)
295
296 BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler )
297 EVT_KILL_FOCUS( wxGridCellEditorEvtHandler::OnKillFocus )
298 EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown )
299 EVT_CHAR( wxGridCellEditorEvtHandler::OnChar )
300 END_EVENT_TABLE()
301
302
303 // ----------------------------------------------------------------------------
304 // the internal data representation used by wxGridCellAttrProvider
305 // ----------------------------------------------------------------------------
306
307 // this class stores attributes set for cells
308 class WXDLLIMPEXP_ADV wxGridCellAttrData
309 {
310 public:
311 void SetAttr(wxGridCellAttr *attr, int row, int col);
312 wxGridCellAttr *GetAttr(int row, int col) const;
313 void UpdateAttrRows( size_t pos, int numRows );
314 void UpdateAttrCols( size_t pos, int numCols );
315
316 private:
317 // searches for the attr for given cell, returns wxNOT_FOUND if not found
318 int FindIndex(int row, int col) const;
319
320 wxGridCellWithAttrArray m_attrs;
321 };
322
323 // this class stores attributes set for rows or columns
324 class WXDLLIMPEXP_ADV wxGridRowOrColAttrData
325 {
326 public:
327 // empty ctor to suppress warnings
328 wxGridRowOrColAttrData() {}
329 ~wxGridRowOrColAttrData();
330
331 void SetAttr(wxGridCellAttr *attr, int rowOrCol);
332 wxGridCellAttr *GetAttr(int rowOrCol) const;
333 void UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols );
334
335 private:
336 wxArrayInt m_rowsOrCols;
337 wxArrayAttrs m_attrs;
338 };
339
340 // NB: this is just a wrapper around 3 objects: one which stores cell
341 // attributes, and 2 others for row/col ones
342 class WXDLLIMPEXP_ADV wxGridCellAttrProviderData
343 {
344 public:
345 wxGridCellAttrData m_cellAttrs;
346 wxGridRowOrColAttrData m_rowAttrs,
347 m_colAttrs;
348 };
349
350
351 // ----------------------------------------------------------------------------
352 // data structures used for the data type registry
353 // ----------------------------------------------------------------------------
354
355 struct wxGridDataTypeInfo
356 {
357 wxGridDataTypeInfo(const wxString& typeName,
358 wxGridCellRenderer* renderer,
359 wxGridCellEditor* editor)
360 : m_typeName(typeName), m_renderer(renderer), m_editor(editor)
361 {}
362
363 ~wxGridDataTypeInfo()
364 {
365 wxSafeDecRef(m_renderer);
366 wxSafeDecRef(m_editor);
367 }
368
369 wxString m_typeName;
370 wxGridCellRenderer* m_renderer;
371 wxGridCellEditor* m_editor;
372
373 DECLARE_NO_COPY_CLASS(wxGridDataTypeInfo)
374 };
375
376
377 WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridDataTypeInfo*, wxGridDataTypeInfoArray,
378 class WXDLLIMPEXP_ADV);
379
380
381 class WXDLLIMPEXP_ADV wxGridTypeRegistry
382 {
383 public:
384 wxGridTypeRegistry() {}
385 ~wxGridTypeRegistry();
386
387 void RegisterDataType(const wxString& typeName,
388 wxGridCellRenderer* renderer,
389 wxGridCellEditor* editor);
390
391 // find one of already registered data types
392 int FindRegisteredDataType(const wxString& typeName);
393
394 // try to FindRegisteredDataType(), if this fails and typeName is one of
395 // standard typenames, register it and return its index
396 int FindDataType(const wxString& typeName);
397
398 // try to FindDataType(), if it fails see if it is not one of already
399 // registered data types with some params in which case clone the
400 // registered data type and set params for it
401 int FindOrCloneDataType(const wxString& typeName);
402
403 wxGridCellRenderer* GetRenderer(int index);
404 wxGridCellEditor* GetEditor(int index);
405
406 private:
407 wxGridDataTypeInfoArray m_typeinfo;
408 };
409
410
411 // ----------------------------------------------------------------------------
412 // conditional compilation
413 // ----------------------------------------------------------------------------
414
415 #ifndef WXGRID_DRAW_LINES
416 #define WXGRID_DRAW_LINES 1
417 #endif
418
419 // ----------------------------------------------------------------------------
420 // globals
421 // ----------------------------------------------------------------------------
422
423 //#define DEBUG_ATTR_CACHE
424 #ifdef DEBUG_ATTR_CACHE
425 static size_t gs_nAttrCacheHits = 0;
426 static size_t gs_nAttrCacheMisses = 0;
427 #endif
428
429 // ----------------------------------------------------------------------------
430 // constants
431 // ----------------------------------------------------------------------------
432
433 wxGridCellCoords wxGridNoCellCoords( -1, -1 );
434 wxRect wxGridNoCellRect( -1, -1, -1, -1 );
435
436 // scroll line size
437 // TODO: this doesn't work at all, grid cells have different sizes and approx
438 // calculations don't work as because of the size mismatch scrollbars
439 // sometimes fail to be shown when they should be or vice versa
440 //
441 // The scroll bars may be a little flakey once in a while, but that is
442 // surely much less horrible than having scroll lines of only 1!!!
443 // -- Robin
444 //
445 // Well, it's still seriously broken so it might be better but needs
446 // fixing anyhow
447 // -- Vadim
448 static const size_t GRID_SCROLL_LINE_X = 15; // 1;
449 static const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X;
450
451 // the size of hash tables used a bit everywhere (the max number of elements
452 // in these hash tables is the number of rows/columns)
453 static const int GRID_HASH_SIZE = 100;
454
455 #if 0
456 // ----------------------------------------------------------------------------
457 // private functions
458 // ----------------------------------------------------------------------------
459
460 static inline int GetScrollX(int x)
461 {
462 return (x + GRID_SCROLL_LINE_X - 1) / GRID_SCROLL_LINE_X;
463 }
464
465 static inline int GetScrollY(int y)
466 {
467 return (y + GRID_SCROLL_LINE_Y - 1) / GRID_SCROLL_LINE_Y;
468 }
469 #endif
470
471 // ============================================================================
472 // implementation
473 // ============================================================================
474
475 // ----------------------------------------------------------------------------
476 // wxGridCellEditor
477 // ----------------------------------------------------------------------------
478
479 wxGridCellEditor::wxGridCellEditor()
480 {
481 m_control = NULL;
482 m_attr = NULL;
483 }
484
485 wxGridCellEditor::~wxGridCellEditor()
486 {
487 Destroy();
488 }
489
490 void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
491 wxWindowID WXUNUSED(id),
492 wxEvtHandler* evtHandler)
493 {
494 if ( evtHandler )
495 m_control->PushEventHandler(evtHandler);
496 }
497
498 void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
499 wxGridCellAttr *attr)
500 {
501 // erase the background because we might not fill the cell
502 wxClientDC dc(m_control->GetParent());
503 wxGridWindow* gridWindow = wxDynamicCast(m_control->GetParent(), wxGridWindow);
504 if (gridWindow)
505 gridWindow->GetOwner()->PrepareDC(dc);
506
507 dc.SetPen(*wxTRANSPARENT_PEN);
508 dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
509 dc.DrawRectangle(rectCell);
510
511 // redraw the control we just painted over
512 m_control->Refresh();
513 }
514
515 void wxGridCellEditor::Destroy()
516 {
517 if (m_control)
518 {
519 m_control->PopEventHandler( true /* delete it*/ );
520
521 m_control->Destroy();
522 m_control = NULL;
523 }
524 }
525
526 void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
527 {
528 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
529
530 m_control->Show(show);
531
532 if ( show )
533 {
534 // set the colours/fonts if we have any
535 if ( attr )
536 {
537 m_colFgOld = m_control->GetForegroundColour();
538 m_control->SetForegroundColour(attr->GetTextColour());
539
540 m_colBgOld = m_control->GetBackgroundColour();
541 m_control->SetBackgroundColour(attr->GetBackgroundColour());
542
543 // Workaround for GTK+1 font setting problem on some platforms
544 #if !defined(__WXGTK__) || defined(__WXGTK20__)
545 m_fontOld = m_control->GetFont();
546 m_control->SetFont(attr->GetFont());
547 #endif
548
549 // can't do anything more in the base class version, the other
550 // attributes may only be used by the derived classes
551 }
552 }
553 else
554 {
555 // restore the standard colours fonts
556 if ( m_colFgOld.Ok() )
557 {
558 m_control->SetForegroundColour(m_colFgOld);
559 m_colFgOld = wxNullColour;
560 }
561
562 if ( m_colBgOld.Ok() )
563 {
564 m_control->SetBackgroundColour(m_colBgOld);
565 m_colBgOld = wxNullColour;
566 }
567
568 // Workaround for GTK+1 font setting problem on some platforms
569 #if !defined(__WXGTK__) || defined(__WXGTK20__)
570 if ( m_fontOld.Ok() )
571 {
572 m_control->SetFont(m_fontOld);
573 m_fontOld = wxNullFont;
574 }
575 #endif
576 }
577 }
578
579 void wxGridCellEditor::SetSize(const wxRect& rect)
580 {
581 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
582
583 m_control->SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
584 }
585
586 void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
587 {
588 event.Skip();
589 }
590
591 bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event)
592 {
593 bool ctrl = event.ControlDown();
594 bool alt = event.AltDown();
595
596 #ifdef __WXMAC__
597 // On the Mac the Alt key is more like shift and is used for entry of
598 // valid characters, so check for Ctrl and Meta instead.
599 alt = event.MetaDown();
600 #endif
601
602 // Assume it's not a valid char if ctrl or alt is down, but if both are
603 // down then it may be because of an AltGr key combination, so let them
604 // through in that case.
605 if ((ctrl || alt) && !(ctrl && alt))
606 return false;
607
608 int key = 0;
609 bool keyOk = true;
610
611 #ifdef __WXGTK20__
612 // If it's a F-Key or other special key then it shouldn't start the
613 // editor.
614 if (event.GetKeyCode() >= WXK_START)
615 return false;
616 #endif
617 #if wxUSE_UNICODE
618 // if the unicode key code is not really a unicode character (it may
619 // be a function key or etc., the platforms appear to always give us a
620 // small value in this case) then fallback to the ASCII key code but
621 // don't do anything for function keys or etc.
622 key = event.GetUnicodeKey();
623 if (key <= 127)
624 {
625 key = event.GetKeyCode();
626 keyOk = (key <= 127);
627 }
628 #else
629 key = event.GetKeyCode();
630 keyOk = (key <= 255);
631 #endif
632
633 return keyOk;
634 }
635
636 void wxGridCellEditor::StartingKey(wxKeyEvent& event)
637 {
638 event.Skip();
639 }
640
641 void wxGridCellEditor::StartingClick()
642 {
643 }
644
645 #if wxUSE_TEXTCTRL
646
647 // ----------------------------------------------------------------------------
648 // wxGridCellTextEditor
649 // ----------------------------------------------------------------------------
650
651 wxGridCellTextEditor::wxGridCellTextEditor()
652 {
653 m_maxChars = 0;
654 }
655
656 void wxGridCellTextEditor::Create(wxWindow* parent,
657 wxWindowID id,
658 wxEvtHandler* evtHandler)
659 {
660 m_control = new wxTextCtrl(parent, id, wxEmptyString,
661 wxDefaultPosition, wxDefaultSize
662 #if defined(__WXMSW__)
663 ,
664 wxTE_PROCESS_ENTER |
665 wxTE_PROCESS_TAB |
666 wxTE_AUTO_SCROLL |
667 wxNO_BORDER
668 #endif
669 );
670
671 // set max length allowed in the textctrl, if the parameter was set
672 if (m_maxChars != 0)
673 {
674 ((wxTextCtrl*)m_control)->SetMaxLength(m_maxChars);
675 }
676
677 wxGridCellEditor::Create(parent, id, evtHandler);
678 }
679
680 void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell),
681 wxGridCellAttr * WXUNUSED(attr))
682 {
683 // as we fill the entire client area,
684 // don't do anything here to minimize flicker
685 }
686
687 void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
688 {
689 wxRect rect(rectOrig);
690
691 // Make the edit control large enough to allow for internal margins
692 //
693 // TODO: remove this if the text ctrl sizing is improved esp. for unix
694 //
695 #if defined(__WXGTK__)
696 if (rect.x != 0)
697 {
698 rect.x += 1;
699 rect.y += 1;
700 rect.width -= 1;
701 rect.height -= 1;
702 }
703 #elif defined(__WXMSW__)
704 if ( rect.x == 0 )
705 rect.x += 2;
706 else
707 rect.x += 3;
708
709 if ( rect.y == 0 )
710 rect.y += 2;
711 else
712 rect.y += 3;
713
714 rect.width -= 2;
715 rect.height -= 2;
716 #else
717 int extra_x = ( rect.x > 2 ) ? 2 : 1;
718 int extra_y = ( rect.y > 2 ) ? 2 : 1;
719
720 #if defined(__WXMOTIF__)
721 extra_x *= 2;
722 extra_y *= 2;
723 #endif
724
725 rect.SetLeft( wxMax(0, rect.x - extra_x) );
726 rect.SetTop( wxMax(0, rect.y - extra_y) );
727 rect.SetRight( rect.GetRight() + 2 * extra_x );
728 rect.SetBottom( rect.GetBottom() + 2 * extra_y );
729 #endif
730
731 wxGridCellEditor::SetSize(rect);
732 }
733
734 void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid)
735 {
736 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
737
738 m_startValue = grid->GetTable()->GetValue(row, col);
739
740 DoBeginEdit(m_startValue);
741 }
742
743 void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
744 {
745 Text()->SetValue(startValue);
746 Text()->SetInsertionPointEnd();
747 Text()->SetSelection(-1, -1);
748 Text()->SetFocus();
749 }
750
751 bool wxGridCellTextEditor::EndEdit(int row, int col, wxGrid* grid)
752 {
753 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
754
755 bool changed = false;
756 wxString value = Text()->GetValue();
757 if (value != m_startValue)
758 changed = true;
759
760 if (changed)
761 grid->GetTable()->SetValue(row, col, value);
762
763 m_startValue = wxEmptyString;
764
765 // No point in setting the text of the hidden control
766 //Text()->SetValue(m_startValue);
767
768 return changed;
769 }
770
771 void wxGridCellTextEditor::Reset()
772 {
773 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
774
775 DoReset(m_startValue);
776 }
777
778 void wxGridCellTextEditor::DoReset(const wxString& startValue)
779 {
780 Text()->SetValue(startValue);
781 Text()->SetInsertionPointEnd();
782 }
783
784 bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event)
785 {
786 return wxGridCellEditor::IsAcceptedKey(event);
787 }
788
789 void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
790 {
791 // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no
792 // longer an appropriate way to get the character into the text control.
793 // Do it ourselves instead. We know that if we get this far that we have
794 // a valid character, so not a whole lot of testing needs to be done.
795
796 wxTextCtrl* tc = Text();
797 wxChar ch;
798 long pos;
799
800 #if wxUSE_UNICODE
801 ch = event.GetUnicodeKey();
802 if (ch <= 127)
803 ch = (wxChar)event.GetKeyCode();
804 #else
805 ch = (wxChar)event.GetKeyCode();
806 #endif
807
808 switch (ch)
809 {
810 case WXK_DELETE:
811 // delete the character at the cursor
812 pos = tc->GetInsertionPoint();
813 if (pos < tc->GetLastPosition())
814 tc->Remove(pos, pos + 1);
815 break;
816
817 case WXK_BACK:
818 // delete the character before the cursor
819 pos = tc->GetInsertionPoint();
820 if (pos > 0)
821 tc->Remove(pos - 1, pos);
822 break;
823
824 default:
825 tc->WriteText(ch);
826 break;
827 }
828 }
829
830 void wxGridCellTextEditor::HandleReturn( wxKeyEvent&
831 WXUNUSED_GTK(WXUNUSED_MOTIF(event)) )
832 {
833 #if defined(__WXMOTIF__) || defined(__WXGTK__)
834 // wxMotif needs a little extra help...
835 size_t pos = (size_t)( Text()->GetInsertionPoint() );
836 wxString s( Text()->GetValue() );
837 s = s.Left(pos) + wxT("\n") + s.Mid(pos);
838 Text()->SetValue(s);
839 Text()->SetInsertionPoint( pos );
840 #else
841 // the other ports can handle a Return key press
842 //
843 event.Skip();
844 #endif
845 }
846
847 void wxGridCellTextEditor::SetParameters(const wxString& params)
848 {
849 if ( !params )
850 {
851 // reset to default
852 m_maxChars = 0;
853 }
854 else
855 {
856 long tmp;
857 if ( params.ToLong(&tmp) )
858 {
859 m_maxChars = (size_t)tmp;
860 }
861 else
862 {
863 wxLogDebug( _T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str() );
864 }
865 }
866 }
867
868 // return the value in the text control
869 wxString wxGridCellTextEditor::GetValue() const
870 {
871 return Text()->GetValue();
872 }
873
874 // ----------------------------------------------------------------------------
875 // wxGridCellNumberEditor
876 // ----------------------------------------------------------------------------
877
878 wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max)
879 {
880 m_min = min;
881 m_max = max;
882 }
883
884 void wxGridCellNumberEditor::Create(wxWindow* parent,
885 wxWindowID id,
886 wxEvtHandler* evtHandler)
887 {
888 #if wxUSE_SPINCTRL
889 if ( HasRange() )
890 {
891 // create a spin ctrl
892 m_control = new wxSpinCtrl(parent, wxID_ANY, wxEmptyString,
893 wxDefaultPosition, wxDefaultSize,
894 wxSP_ARROW_KEYS,
895 m_min, m_max);
896
897 wxGridCellEditor::Create(parent, id, evtHandler);
898 }
899 else
900 #endif
901 {
902 // just a text control
903 wxGridCellTextEditor::Create(parent, id, evtHandler);
904
905 #if wxUSE_VALIDATORS
906 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
907 #endif
908 }
909 }
910
911 void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
912 {
913 // first get the value
914 wxGridTableBase *table = grid->GetTable();
915 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
916 {
917 m_valueOld = table->GetValueAsLong(row, col);
918 }
919 else
920 {
921 m_valueOld = 0;
922 wxString sValue = table->GetValue(row, col);
923 if (! sValue.ToLong(&m_valueOld) && ! sValue.empty())
924 {
925 wxFAIL_MSG( _T("this cell doesn't have numeric value") );
926 return;
927 }
928 }
929
930 #if wxUSE_SPINCTRL
931 if ( HasRange() )
932 {
933 Spin()->SetValue((int)m_valueOld);
934 Spin()->SetFocus();
935 }
936 else
937 #endif
938 {
939 DoBeginEdit(GetString());
940 }
941 }
942
943 bool wxGridCellNumberEditor::EndEdit(int row, int col,
944 wxGrid* grid)
945 {
946 long value = 0;
947 wxString text;
948
949 #if wxUSE_SPINCTRL
950 if ( HasRange() )
951 {
952 value = Spin()->GetValue();
953 if ( value == m_valueOld )
954 return false;
955
956 text.Printf(wxT("%ld"), value);
957 }
958 else // using unconstrained input
959 #endif // wxUSE_SPINCTRL
960 {
961 const wxString textOld(grid->GetCellValue(row, col));
962 text = Text()->GetValue();
963 if ( text.empty() )
964 {
965 if ( textOld.empty() )
966 return false;
967 }
968 else // non-empty text now (maybe 0)
969 {
970 if ( !text.ToLong(&value) )
971 return false;
972
973 // if value == m_valueOld == 0 but old text was "" and new one is
974 // "0" something still did change
975 if ( value == m_valueOld && (value || !textOld.empty()) )
976 return false;
977 }
978 }
979
980 wxGridTableBase * const table = grid->GetTable();
981 if ( table->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER) )
982 table->SetValueAsLong(row, col, value);
983 else
984 table->SetValue(row, col, text);
985
986 return true;
987 }
988
989 void wxGridCellNumberEditor::Reset()
990 {
991 #if wxUSE_SPINCTRL
992 if ( HasRange() )
993 {
994 Spin()->SetValue((int)m_valueOld);
995 }
996 else
997 #endif
998 {
999 DoReset(GetString());
1000 }
1001 }
1002
1003 bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent& event)
1004 {
1005 if ( wxGridCellEditor::IsAcceptedKey(event) )
1006 {
1007 int keycode = event.GetKeyCode();
1008 if ( (keycode < 128) &&
1009 (wxIsdigit(keycode) || keycode == '+' || keycode == '-'))
1010 {
1011 return true;
1012 }
1013 }
1014
1015 return false;
1016 }
1017
1018 void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event)
1019 {
1020 int keycode = event.GetKeyCode();
1021 if ( !HasRange() )
1022 {
1023 if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-')
1024 {
1025 wxGridCellTextEditor::StartingKey(event);
1026
1027 // skip Skip() below
1028 return;
1029 }
1030 }
1031 #if wxUSE_SPINCTRL
1032 else
1033 {
1034 if ( wxIsdigit(keycode) )
1035 {
1036 wxSpinCtrl* spin = (wxSpinCtrl*)m_control;
1037 spin->SetValue(keycode - '0');
1038 spin->SetSelection(1,1);
1039 return;
1040 }
1041 }
1042 #endif
1043
1044 event.Skip();
1045 }
1046
1047 void wxGridCellNumberEditor::SetParameters(const wxString& params)
1048 {
1049 if ( !params )
1050 {
1051 // reset to default
1052 m_min =
1053 m_max = -1;
1054 }
1055 else
1056 {
1057 long tmp;
1058 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
1059 {
1060 m_min = (int)tmp;
1061
1062 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
1063 {
1064 m_max = (int)tmp;
1065
1066 // skip the error message below
1067 return;
1068 }
1069 }
1070
1071 wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str());
1072 }
1073 }
1074
1075 // return the value in the spin control if it is there (the text control otherwise)
1076 wxString wxGridCellNumberEditor::GetValue() const
1077 {
1078 wxString s;
1079
1080 #if wxUSE_SPINCTRL
1081 if ( HasRange() )
1082 {
1083 long value = Spin()->GetValue();
1084 s.Printf(wxT("%ld"), value);
1085 }
1086 else
1087 #endif
1088 {
1089 s = Text()->GetValue();
1090 }
1091
1092 return s;
1093 }
1094
1095 // ----------------------------------------------------------------------------
1096 // wxGridCellFloatEditor
1097 // ----------------------------------------------------------------------------
1098
1099 wxGridCellFloatEditor::wxGridCellFloatEditor(int width, int precision)
1100 {
1101 m_width = width;
1102 m_precision = precision;
1103 }
1104
1105 void wxGridCellFloatEditor::Create(wxWindow* parent,
1106 wxWindowID id,
1107 wxEvtHandler* evtHandler)
1108 {
1109 wxGridCellTextEditor::Create(parent, id, evtHandler);
1110
1111 #if wxUSE_VALIDATORS
1112 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
1113 #endif
1114 }
1115
1116 void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid)
1117 {
1118 // first get the value
1119 wxGridTableBase * const table = grid->GetTable();
1120 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
1121 {
1122 m_valueOld = table->GetValueAsDouble(row, col);
1123 }
1124 else
1125 {
1126 m_valueOld = 0.0;
1127
1128 const wxString value = table->GetValue(row, col);
1129 if ( !value.empty() )
1130 {
1131 if ( !value.ToDouble(&m_valueOld) )
1132 {
1133 wxFAIL_MSG( _T("this cell doesn't have float value") );
1134 return;
1135 }
1136 }
1137 }
1138
1139 DoBeginEdit(GetString());
1140 }
1141
1142 bool wxGridCellFloatEditor::EndEdit(int row, int col, wxGrid* grid)
1143 {
1144 const wxString text(Text()->GetValue()),
1145 textOld(grid->GetCellValue(row, col));
1146
1147 double value;
1148 if ( !text.empty() )
1149 {
1150 if ( !text.ToDouble(&value) )
1151 return false;
1152 }
1153 else // new value is empty string
1154 {
1155 if ( textOld.empty() )
1156 return false; // nothing changed
1157
1158 value = 0.;
1159 }
1160
1161 // the test for empty strings ensures that we don't skip the value setting
1162 // when "" is replaced by "0" or vice versa as "" numeric value is also 0.
1163 if ( wxIsSameDouble(value, m_valueOld) && !text.empty() && !textOld.empty() )
1164 return false; // nothing changed
1165
1166 wxGridTableBase * const table = grid->GetTable();
1167
1168 if ( table->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT) )
1169 table->SetValueAsDouble(row, col, value);
1170 else
1171 table->SetValue(row, col, text);
1172
1173 return true;
1174 }
1175
1176 void wxGridCellFloatEditor::Reset()
1177 {
1178 DoReset(GetString());
1179 }
1180
1181 void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
1182 {
1183 int keycode = event.GetKeyCode();
1184 char tmpbuf[2];
1185 tmpbuf[0] = (char) keycode;
1186 tmpbuf[1] = '\0';
1187 wxString strbuf(tmpbuf, *wxConvCurrent);
1188
1189 #if wxUSE_INTL
1190 bool is_decimal_point = ( strbuf ==
1191 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER) );
1192 #else
1193 bool is_decimal_point = ( strbuf == _T(".") );
1194 #endif
1195
1196 if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-'
1197 || is_decimal_point )
1198 {
1199 wxGridCellTextEditor::StartingKey(event);
1200
1201 // skip Skip() below
1202 return;
1203 }
1204
1205 event.Skip();
1206 }
1207
1208 void wxGridCellFloatEditor::SetParameters(const wxString& params)
1209 {
1210 if ( !params )
1211 {
1212 // reset to default
1213 m_width =
1214 m_precision = -1;
1215 }
1216 else
1217 {
1218 long tmp;
1219 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
1220 {
1221 m_width = (int)tmp;
1222
1223 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
1224 {
1225 m_precision = (int)tmp;
1226
1227 // skip the error message below
1228 return;
1229 }
1230 }
1231
1232 wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params.c_str());
1233 }
1234 }
1235
1236 wxString wxGridCellFloatEditor::GetString() const
1237 {
1238 wxString fmt;
1239 if ( m_precision == -1 && m_width != -1)
1240 {
1241 // default precision
1242 fmt.Printf(_T("%%%d.f"), m_width);
1243 }
1244 else if ( m_precision != -1 && m_width == -1)
1245 {
1246 // default width
1247 fmt.Printf(_T("%%.%df"), m_precision);
1248 }
1249 else if ( m_precision != -1 && m_width != -1 )
1250 {
1251 fmt.Printf(_T("%%%d.%df"), m_width, m_precision);
1252 }
1253 else
1254 {
1255 // default width/precision
1256 fmt = _T("%f");
1257 }
1258
1259 return wxString::Format(fmt, m_valueOld);
1260 }
1261
1262 bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event)
1263 {
1264 if ( wxGridCellEditor::IsAcceptedKey(event) )
1265 {
1266 const int keycode = event.GetKeyCode();
1267 if ( isascii(keycode) )
1268 {
1269 char tmpbuf[2];
1270 tmpbuf[0] = (char) keycode;
1271 tmpbuf[1] = '\0';
1272 wxString strbuf(tmpbuf, *wxConvCurrent);
1273
1274 #if wxUSE_INTL
1275 const wxString decimalPoint =
1276 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
1277 #else
1278 const wxString decimalPoint(_T('.'));
1279 #endif
1280
1281 // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
1282 if ( wxIsdigit(keycode) ||
1283 tolower(keycode) == 'e' ||
1284 keycode == decimalPoint ||
1285 keycode == '+' ||
1286 keycode == '-' )
1287 {
1288 return true;
1289 }
1290 }
1291 }
1292
1293 return false;
1294 }
1295
1296 #endif // wxUSE_TEXTCTRL
1297
1298 #if wxUSE_CHECKBOX
1299
1300 // ----------------------------------------------------------------------------
1301 // wxGridCellBoolEditor
1302 // ----------------------------------------------------------------------------
1303
1304 // the default values for GetValue()
1305 wxString wxGridCellBoolEditor::ms_stringValues[2] = { _T(""), _T("1") };
1306
1307 void wxGridCellBoolEditor::Create(wxWindow* parent,
1308 wxWindowID id,
1309 wxEvtHandler* evtHandler)
1310 {
1311 m_control = new wxCheckBox(parent, id, wxEmptyString,
1312 wxDefaultPosition, wxDefaultSize,
1313 wxNO_BORDER);
1314
1315 wxGridCellEditor::Create(parent, id, evtHandler);
1316 }
1317
1318 void wxGridCellBoolEditor::SetSize(const wxRect& r)
1319 {
1320 bool resize = false;
1321 wxSize size = m_control->GetSize();
1322 wxCoord minSize = wxMin(r.width, r.height);
1323
1324 // check if the checkbox is not too big/small for this cell
1325 wxSize sizeBest = m_control->GetBestSize();
1326 if ( !(size == sizeBest) )
1327 {
1328 // reset to default size if it had been made smaller
1329 size = sizeBest;
1330
1331 resize = true;
1332 }
1333
1334 if ( size.x >= minSize || size.y >= minSize )
1335 {
1336 // leave 1 pixel margin
1337 size.x = size.y = minSize - 2;
1338
1339 resize = true;
1340 }
1341
1342 if ( resize )
1343 {
1344 m_control->SetSize(size);
1345 }
1346
1347 // position it in the centre of the rectangle (TODO: support alignment?)
1348
1349 #if defined(__WXGTK__) || defined (__WXMOTIF__)
1350 // the checkbox without label still has some space to the right in wxGTK,
1351 // so shift it to the right
1352 size.x -= 8;
1353 #elif defined(__WXMSW__)
1354 // here too, but in other way
1355 size.x += 1;
1356 size.y -= 2;
1357 #endif
1358
1359 int hAlign = wxALIGN_CENTRE;
1360 int vAlign = wxALIGN_CENTRE;
1361 if (GetCellAttr())
1362 GetCellAttr()->GetAlignment(& hAlign, & vAlign);
1363
1364 int x = 0, y = 0;
1365 if (hAlign == wxALIGN_LEFT)
1366 {
1367 x = r.x + 2;
1368
1369 #ifdef __WXMSW__
1370 x += 2;
1371 #endif
1372
1373 y = r.y + r.height / 2 - size.y / 2;
1374 }
1375 else if (hAlign == wxALIGN_RIGHT)
1376 {
1377 x = r.x + r.width - size.x - 2;
1378 y = r.y + r.height / 2 - size.y / 2;
1379 }
1380 else if (hAlign == wxALIGN_CENTRE)
1381 {
1382 x = r.x + r.width / 2 - size.x / 2;
1383 y = r.y + r.height / 2 - size.y / 2;
1384 }
1385
1386 m_control->Move(x, y);
1387 }
1388
1389 void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
1390 {
1391 m_control->Show(show);
1392
1393 if ( show )
1394 {
1395 wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
1396 CBox()->SetBackgroundColour(colBg);
1397 }
1398 }
1399
1400 void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid)
1401 {
1402 wxASSERT_MSG(m_control,
1403 wxT("The wxGridCellEditor must be created first!"));
1404
1405 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
1406 {
1407 m_startValue = grid->GetTable()->GetValueAsBool(row, col);
1408 }
1409 else
1410 {
1411 wxString cellval( grid->GetTable()->GetValue(row, col) );
1412
1413 if ( cellval == ms_stringValues[false] )
1414 m_startValue = false;
1415 else if ( cellval == ms_stringValues[true] )
1416 m_startValue = true;
1417 else
1418 {
1419 // do not try to be smart here and convert it to true or false
1420 // because we'll still overwrite it with something different and
1421 // this risks to be very surprising for the user code, let them
1422 // know about it
1423 wxFAIL_MSG( _T("invalid value for a cell with bool editor!") );
1424 }
1425 }
1426
1427 CBox()->SetValue(m_startValue);
1428 CBox()->SetFocus();
1429 }
1430
1431 bool wxGridCellBoolEditor::EndEdit(int row, int col,
1432 wxGrid* grid)
1433 {
1434 wxASSERT_MSG(m_control,
1435 wxT("The wxGridCellEditor must be created first!"));
1436
1437 bool changed = false;
1438 bool value = CBox()->GetValue();
1439 if ( value != m_startValue )
1440 changed = true;
1441
1442 if ( changed )
1443 {
1444 wxGridTableBase * const table = grid->GetTable();
1445 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
1446 table->SetValueAsBool(row, col, value);
1447 else
1448 table->SetValue(row, col, GetValue());
1449 }
1450
1451 return changed;
1452 }
1453
1454 void wxGridCellBoolEditor::Reset()
1455 {
1456 wxASSERT_MSG(m_control,
1457 wxT("The wxGridCellEditor must be created first!"));
1458
1459 CBox()->SetValue(m_startValue);
1460 }
1461
1462 void wxGridCellBoolEditor::StartingClick()
1463 {
1464 CBox()->SetValue(!CBox()->GetValue());
1465 }
1466
1467 bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent& event)
1468 {
1469 if ( wxGridCellEditor::IsAcceptedKey(event) )
1470 {
1471 int keycode = event.GetKeyCode();
1472 switch ( keycode )
1473 {
1474 case WXK_SPACE:
1475 case '+':
1476 case '-':
1477 return true;
1478 }
1479 }
1480
1481 return false;
1482 }
1483
1484 void wxGridCellBoolEditor::StartingKey(wxKeyEvent& event)
1485 {
1486 int keycode = event.GetKeyCode();
1487 switch ( keycode )
1488 {
1489 case WXK_SPACE:
1490 CBox()->SetValue(!CBox()->GetValue());
1491 break;
1492
1493 case '+':
1494 CBox()->SetValue(true);
1495 break;
1496
1497 case '-':
1498 CBox()->SetValue(false);
1499 break;
1500 }
1501 }
1502
1503 wxString wxGridCellBoolEditor::GetValue() const
1504 {
1505 return ms_stringValues[CBox()->GetValue()];
1506 }
1507
1508 /* static */ void
1509 wxGridCellBoolEditor::UseStringValues(const wxString& valueTrue,
1510 const wxString& valueFalse)
1511 {
1512 ms_stringValues[false] = valueFalse;
1513 ms_stringValues[true] = valueTrue;
1514 }
1515
1516 /* static */ bool
1517 wxGridCellBoolEditor::IsTrueValue(const wxString& value)
1518 {
1519 return value == ms_stringValues[true];
1520 }
1521
1522 #endif // wxUSE_CHECKBOX
1523
1524 #if wxUSE_COMBOBOX
1525
1526 // ----------------------------------------------------------------------------
1527 // wxGridCellChoiceEditor
1528 // ----------------------------------------------------------------------------
1529
1530 wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString& choices,
1531 bool allowOthers)
1532 : m_choices(choices),
1533 m_allowOthers(allowOthers) { }
1534
1535 wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count,
1536 const wxString choices[],
1537 bool allowOthers)
1538 : m_allowOthers(allowOthers)
1539 {
1540 if ( count )
1541 {
1542 m_choices.Alloc(count);
1543 for ( size_t n = 0; n < count; n++ )
1544 {
1545 m_choices.Add(choices[n]);
1546 }
1547 }
1548 }
1549
1550 wxGridCellEditor *wxGridCellChoiceEditor::Clone() const
1551 {
1552 wxGridCellChoiceEditor *editor = new wxGridCellChoiceEditor;
1553 editor->m_allowOthers = m_allowOthers;
1554 editor->m_choices = m_choices;
1555
1556 return editor;
1557 }
1558
1559 void wxGridCellChoiceEditor::Create(wxWindow* parent,
1560 wxWindowID id,
1561 wxEvtHandler* evtHandler)
1562 {
1563 int style = wxTE_PROCESS_ENTER |
1564 wxTE_PROCESS_TAB |
1565 wxBORDER_NONE;
1566
1567 if ( !m_allowOthers )
1568 style |= wxCB_READONLY;
1569
1570 m_control = new wxComboBox(parent, id, wxEmptyString,
1571 wxDefaultPosition, wxDefaultSize,
1572 m_choices,
1573 style);
1574
1575 wxGridCellEditor::Create(parent, id, evtHandler);
1576 }
1577
1578 void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
1579 wxGridCellAttr * attr)
1580 {
1581 // as we fill the entire client area, don't do anything here to minimize
1582 // flicker
1583
1584 // TODO: It doesn't actually fill the client area since the height of a
1585 // combo always defaults to the standard. Until someone has time to
1586 // figure out the right rectangle to paint, just do it the normal way.
1587 wxGridCellEditor::PaintBackground(rectCell, attr);
1588 }
1589
1590 void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
1591 {
1592 wxASSERT_MSG(m_control,
1593 wxT("The wxGridCellEditor must be created first!"));
1594
1595 wxGridCellEditorEvtHandler* evtHandler = NULL;
1596 if (m_control)
1597 evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler);
1598
1599 // Don't immediately end if we get a kill focus event within BeginEdit
1600 if (evtHandler)
1601 evtHandler->SetInSetFocus(true);
1602
1603 m_startValue = grid->GetTable()->GetValue(row, col);
1604
1605 if (m_allowOthers)
1606 {
1607 Combo()->SetValue(m_startValue);
1608 }
1609 else
1610 {
1611 // find the right position, or default to the first if not found
1612 int pos = Combo()->FindString(m_startValue);
1613 if (pos == wxNOT_FOUND)
1614 pos = 0;
1615 Combo()->SetSelection(pos);
1616 }
1617
1618 Combo()->SetInsertionPointEnd();
1619 Combo()->SetFocus();
1620
1621 if (evtHandler)
1622 {
1623 // When dropping down the menu, a kill focus event
1624 // happens after this point, so we can't reset the flag yet.
1625 #if !defined(__WXGTK20__)
1626 evtHandler->SetInSetFocus(false);
1627 #endif
1628 }
1629 }
1630
1631 bool wxGridCellChoiceEditor::EndEdit(int row, int col,
1632 wxGrid* grid)
1633 {
1634 wxString value = Combo()->GetValue();
1635 if ( value == m_startValue )
1636 return false;
1637
1638 grid->GetTable()->SetValue(row, col, value);
1639
1640 return true;
1641 }
1642
1643 void wxGridCellChoiceEditor::Reset()
1644 {
1645 Combo()->SetValue(m_startValue);
1646 Combo()->SetInsertionPointEnd();
1647 }
1648
1649 void wxGridCellChoiceEditor::SetParameters(const wxString& params)
1650 {
1651 if ( !params )
1652 {
1653 // what can we do?
1654 return;
1655 }
1656
1657 m_choices.Empty();
1658
1659 wxStringTokenizer tk(params, _T(','));
1660 while ( tk.HasMoreTokens() )
1661 {
1662 m_choices.Add(tk.GetNextToken());
1663 }
1664 }
1665
1666 // return the value in the text control
1667 wxString wxGridCellChoiceEditor::GetValue() const
1668 {
1669 return Combo()->GetValue();
1670 }
1671
1672 #endif // wxUSE_COMBOBOX
1673
1674 // ----------------------------------------------------------------------------
1675 // wxGridCellEditorEvtHandler
1676 // ----------------------------------------------------------------------------
1677
1678 void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent& event)
1679 {
1680 // Don't disable the cell if we're just starting to edit it
1681 if (m_inSetFocus)
1682 return;
1683
1684 // accept changes
1685 m_grid->DisableCellEditControl();
1686
1687 event.Skip();
1688 }
1689
1690 void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
1691 {
1692 switch ( event.GetKeyCode() )
1693 {
1694 case WXK_ESCAPE:
1695 m_editor->Reset();
1696 m_grid->DisableCellEditControl();
1697 break;
1698
1699 case WXK_TAB:
1700 m_grid->GetEventHandler()->ProcessEvent( event );
1701 break;
1702
1703 case WXK_RETURN:
1704 case WXK_NUMPAD_ENTER:
1705 if (!m_grid->GetEventHandler()->ProcessEvent(event))
1706 m_editor->HandleReturn(event);
1707 break;
1708
1709 default:
1710 event.Skip();
1711 break;
1712 }
1713 }
1714
1715 void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event)
1716 {
1717 int row = m_grid->GetGridCursorRow();
1718 int col = m_grid->GetGridCursorCol();
1719 wxRect rect = m_grid->CellToRect( row, col );
1720 int cw, ch;
1721 m_grid->GetGridWindow()->GetClientSize( &cw, &ch );
1722
1723 // if cell width is smaller than grid client area, cell is wholly visible
1724 bool wholeCellVisible = (rect.GetWidth() < cw);
1725
1726 switch ( event.GetKeyCode() )
1727 {
1728 case WXK_ESCAPE:
1729 case WXK_TAB:
1730 case WXK_RETURN:
1731 case WXK_NUMPAD_ENTER:
1732 break;
1733
1734 case WXK_HOME:
1735 {
1736 if ( wholeCellVisible )
1737 {
1738 // no special processing needed...
1739 event.Skip();
1740 break;
1741 }
1742
1743 // do special processing for partly visible cell...
1744
1745 // get the widths of all cells previous to this one
1746 int colXPos = 0;
1747 for ( int i = 0; i < col; i++ )
1748 {
1749 colXPos += m_grid->GetColSize(i);
1750 }
1751
1752 int xUnit = 1, yUnit = 1;
1753 m_grid->GetScrollPixelsPerUnit(&xUnit, &yUnit);
1754 if (col != 0)
1755 {
1756 m_grid->Scroll(colXPos / xUnit - 1, m_grid->GetScrollPos(wxVERTICAL));
1757 }
1758 else
1759 {
1760 m_grid->Scroll(colXPos / xUnit, m_grid->GetScrollPos(wxVERTICAL));
1761 }
1762 event.Skip();
1763 break;
1764 }
1765
1766 case WXK_END:
1767 {
1768 if ( wholeCellVisible )
1769 {
1770 // no special processing needed...
1771 event.Skip();
1772 break;
1773 }
1774
1775 // do special processing for partly visible cell...
1776
1777 int textWidth = 0;
1778 wxString value = m_grid->GetCellValue(row, col);
1779 if ( wxEmptyString != value )
1780 {
1781 // get width of cell CONTENTS (text)
1782 int y;
1783 wxFont font = m_grid->GetCellFont(row, col);
1784 m_grid->GetTextExtent(value, &textWidth, &y, NULL, NULL, &font);
1785
1786 // try to RIGHT align the text by scrolling
1787 int client_right = m_grid->GetGridWindow()->GetClientSize().GetWidth();
1788
1789 // (m_grid->GetScrollLineX()*2) is a factor for not scrolling to far,
1790 // otherwise the last part of the cell content might be hidden below the scroll bar
1791 // FIXME: maybe there is a more suitable correction?
1792 textWidth -= (client_right - (m_grid->GetScrollLineX() * 2));
1793 if ( textWidth < 0 )
1794 {
1795 textWidth = 0;
1796 }
1797 }
1798
1799 // get the widths of all cells previous to this one
1800 int colXPos = 0;
1801 for ( int i = 0; i < col; i++ )
1802 {
1803 colXPos += m_grid->GetColSize(i);
1804 }
1805
1806 // and add the (modified) text width of the cell contents
1807 // as we'd like to see the last part of the cell contents
1808 colXPos += textWidth;
1809
1810 int xUnit = 1, yUnit = 1;
1811 m_grid->GetScrollPixelsPerUnit(&xUnit, &yUnit);
1812 m_grid->Scroll(colXPos / xUnit - 1, m_grid->GetScrollPos(wxVERTICAL));
1813 event.Skip();
1814 break;
1815 }
1816
1817 default:
1818 event.Skip();
1819 break;
1820 }
1821 }
1822
1823 // ----------------------------------------------------------------------------
1824 // wxGridCellWorker is an (almost) empty common base class for
1825 // wxGridCellRenderer and wxGridCellEditor managing ref counting
1826 // ----------------------------------------------------------------------------
1827
1828 void wxGridCellWorker::SetParameters(const wxString& WXUNUSED(params))
1829 {
1830 // nothing to do
1831 }
1832
1833 wxGridCellWorker::~wxGridCellWorker()
1834 {
1835 }
1836
1837 // ============================================================================
1838 // renderer classes
1839 // ============================================================================
1840
1841 // ----------------------------------------------------------------------------
1842 // wxGridCellRenderer
1843 // ----------------------------------------------------------------------------
1844
1845 void wxGridCellRenderer::Draw(wxGrid& grid,
1846 wxGridCellAttr& attr,
1847 wxDC& dc,
1848 const wxRect& rect,
1849 int WXUNUSED(row), int WXUNUSED(col),
1850 bool isSelected)
1851 {
1852 dc.SetBackgroundMode( wxSOLID );
1853
1854 // grey out fields if the grid is disabled
1855 if ( grid.IsEnabled() )
1856 {
1857 if ( isSelected )
1858 {
1859 wxColour clr;
1860 if ( wxWindow::FindFocus() == grid.GetGridWindow() )
1861 clr = grid.GetSelectionBackground();
1862 else
1863 clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
1864 dc.SetBrush( wxBrush(clr, wxSOLID) );
1865 }
1866 else
1867 {
1868 dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) );
1869 }
1870 }
1871 else
1872 {
1873 dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxSOLID));
1874 }
1875
1876 dc.SetPen( *wxTRANSPARENT_PEN );
1877 dc.DrawRectangle(rect);
1878 }
1879
1880 // ----------------------------------------------------------------------------
1881 // wxGridCellStringRenderer
1882 // ----------------------------------------------------------------------------
1883
1884 void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid& grid,
1885 const wxGridCellAttr& attr,
1886 wxDC& dc,
1887 bool isSelected)
1888 {
1889 dc.SetBackgroundMode( wxTRANSPARENT );
1890
1891 // TODO some special colours for attr.IsReadOnly() case?
1892
1893 // different coloured text when the grid is disabled
1894 if ( grid.IsEnabled() )
1895 {
1896 if ( isSelected )
1897 {
1898 wxColour clr;
1899 if ( wxWindow::FindFocus() ==
1900 wx_const_cast(wxGrid&, grid).GetGridWindow() )
1901 clr = grid.GetSelectionBackground();
1902 else
1903 clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
1904 dc.SetTextBackground( clr );
1905 dc.SetTextForeground( grid.GetSelectionForeground() );
1906 }
1907 else
1908 {
1909 dc.SetTextBackground( attr.GetBackgroundColour() );
1910 dc.SetTextForeground( attr.GetTextColour() );
1911 }
1912 }
1913 else
1914 {
1915 dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
1916 dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
1917 }
1918
1919 dc.SetFont( attr.GetFont() );
1920 }
1921
1922 wxSize wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr& attr,
1923 wxDC& dc,
1924 const wxString& text)
1925 {
1926 wxCoord x = 0, y = 0, max_x = 0;
1927 dc.SetFont(attr.GetFont());
1928 wxStringTokenizer tk(text, _T('\n'));
1929 while ( tk.HasMoreTokens() )
1930 {
1931 dc.GetTextExtent(tk.GetNextToken(), &x, &y);
1932 max_x = wxMax(max_x, x);
1933 }
1934
1935 y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines.
1936
1937 return wxSize(max_x, y);
1938 }
1939
1940 wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
1941 wxGridCellAttr& attr,
1942 wxDC& dc,
1943 int row, int col)
1944 {
1945 return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
1946 }
1947
1948 void wxGridCellStringRenderer::Draw(wxGrid& grid,
1949 wxGridCellAttr& attr,
1950 wxDC& dc,
1951 const wxRect& rectCell,
1952 int row, int col,
1953 bool isSelected)
1954 {
1955 wxRect rect = rectCell;
1956 rect.Inflate(-1);
1957
1958 // erase only this cells background, overflow cells should have been erased
1959 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1960
1961 int hAlign, vAlign;
1962 attr.GetAlignment(&hAlign, &vAlign);
1963
1964 int overflowCols = 0;
1965
1966 if (attr.GetOverflow())
1967 {
1968 int cols = grid.GetNumberCols();
1969 int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth();
1970 int cell_rows, cell_cols;
1971 attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <= 0
1972 if ((best_width > rectCell.width) && (col < cols) && grid.GetTable())
1973 {
1974 int i, c_cols, c_rows;
1975 for (i = col+cell_cols; i < cols; i++)
1976 {
1977 bool is_empty = true;
1978 for (int j=row; j < row + cell_rows; j++)
1979 {
1980 // check w/ anchor cell for multicell block
1981 grid.GetCellSize(j, i, &c_rows, &c_cols);
1982 if (c_rows > 0)
1983 c_rows = 0;
1984 if (!grid.GetTable()->IsEmptyCell(j + c_rows, i))
1985 {
1986 is_empty = false;
1987 break;
1988 }
1989 }
1990
1991 if (is_empty)
1992 {
1993 rect.width += grid.GetColSize(i);
1994 }
1995 else
1996 {
1997 i--;
1998 break;
1999 }
2000
2001 if (rect.width >= best_width)
2002 break;
2003 }
2004
2005 overflowCols = i - col - cell_cols + 1;
2006 if (overflowCols >= cols)
2007 overflowCols = cols - 1;
2008 }
2009
2010 if (overflowCols > 0) // redraw overflow cells w/ proper hilight
2011 {
2012 hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned
2013 wxRect clip = rect;
2014 clip.x += rectCell.width;
2015 // draw each overflow cell individually
2016 int col_end = col + cell_cols + overflowCols;
2017 if (col_end >= grid.GetNumberCols())
2018 col_end = grid.GetNumberCols() - 1;
2019 for (int i = col + cell_cols; i <= col_end; i++)
2020 {
2021 clip.width = grid.GetColSize(i) - 1;
2022 dc.DestroyClippingRegion();
2023 dc.SetClippingRegion(clip);
2024
2025 SetTextColoursAndFont(grid, attr, dc,
2026 grid.IsInSelection(row,i));
2027
2028 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
2029 rect, hAlign, vAlign);
2030 clip.x += grid.GetColSize(i) - 1;
2031 }
2032
2033 rect = rectCell;
2034 rect.Inflate(-1);
2035 rect.width++;
2036 dc.DestroyClippingRegion();
2037 }
2038 }
2039
2040 // now we only have to draw the text
2041 SetTextColoursAndFont(grid, attr, dc, isSelected);
2042
2043 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
2044 rect, hAlign, vAlign);
2045 }
2046
2047 // ----------------------------------------------------------------------------
2048 // wxGridCellNumberRenderer
2049 // ----------------------------------------------------------------------------
2050
2051 wxString wxGridCellNumberRenderer::GetString(const wxGrid& grid, int row, int col)
2052 {
2053 wxGridTableBase *table = grid.GetTable();
2054 wxString text;
2055 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
2056 {
2057 text.Printf(_T("%ld"), table->GetValueAsLong(row, col));
2058 }
2059 else
2060 {
2061 text = table->GetValue(row, col);
2062 }
2063
2064 return text;
2065 }
2066
2067 void wxGridCellNumberRenderer::Draw(wxGrid& grid,
2068 wxGridCellAttr& attr,
2069 wxDC& dc,
2070 const wxRect& rectCell,
2071 int row, int col,
2072 bool isSelected)
2073 {
2074 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
2075
2076 SetTextColoursAndFont(grid, attr, dc, isSelected);
2077
2078 // draw the text right aligned by default
2079 int hAlign, vAlign;
2080 attr.GetAlignment(&hAlign, &vAlign);
2081 hAlign = wxALIGN_RIGHT;
2082
2083 wxRect rect = rectCell;
2084 rect.Inflate(-1);
2085
2086 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
2087 }
2088
2089 wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
2090 wxGridCellAttr& attr,
2091 wxDC& dc,
2092 int row, int col)
2093 {
2094 return DoGetBestSize(attr, dc, GetString(grid, row, col));
2095 }
2096
2097 // ----------------------------------------------------------------------------
2098 // wxGridCellFloatRenderer
2099 // ----------------------------------------------------------------------------
2100
2101 wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision)
2102 {
2103 SetWidth(width);
2104 SetPrecision(precision);
2105 }
2106
2107 wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
2108 {
2109 wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
2110 renderer->m_width = m_width;
2111 renderer->m_precision = m_precision;
2112 renderer->m_format = m_format;
2113
2114 return renderer;
2115 }
2116
2117 wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col)
2118 {
2119 wxGridTableBase *table = grid.GetTable();
2120
2121 bool hasDouble;
2122 double val;
2123 wxString text;
2124 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
2125 {
2126 val = table->GetValueAsDouble(row, col);
2127 hasDouble = true;
2128 }
2129 else
2130 {
2131 text = table->GetValue(row, col);
2132 hasDouble = text.ToDouble(&val);
2133 }
2134
2135 if ( hasDouble )
2136 {
2137 if ( !m_format )
2138 {
2139 if ( m_width == -1 )
2140 {
2141 if ( m_precision == -1 )
2142 {
2143 // default width/precision
2144 m_format = _T("%f");
2145 }
2146 else
2147 {
2148 m_format.Printf(_T("%%.%df"), m_precision);
2149 }
2150 }
2151 else if ( m_precision == -1 )
2152 {
2153 // default precision
2154 m_format.Printf(_T("%%%d.f"), m_width);
2155 }
2156 else
2157 {
2158 m_format.Printf(_T("%%%d.%df"), m_width, m_precision);
2159 }
2160 }
2161
2162 text.Printf(m_format, val);
2163
2164 }
2165 //else: text already contains the string
2166
2167 return text;
2168 }
2169
2170 void wxGridCellFloatRenderer::Draw(wxGrid& grid,
2171 wxGridCellAttr& attr,
2172 wxDC& dc,
2173 const wxRect& rectCell,
2174 int row, int col,
2175 bool isSelected)
2176 {
2177 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
2178
2179 SetTextColoursAndFont(grid, attr, dc, isSelected);
2180
2181 // draw the text right aligned by default
2182 int hAlign, vAlign;
2183 attr.GetAlignment(&hAlign, &vAlign);
2184 hAlign = wxALIGN_RIGHT;
2185
2186 wxRect rect = rectCell;
2187 rect.Inflate(-1);
2188
2189 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
2190 }
2191
2192 wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
2193 wxGridCellAttr& attr,
2194 wxDC& dc,
2195 int row, int col)
2196 {
2197 return DoGetBestSize(attr, dc, GetString(grid, row, col));
2198 }
2199
2200 void wxGridCellFloatRenderer::SetParameters(const wxString& params)
2201 {
2202 if ( !params )
2203 {
2204 // reset to defaults
2205 SetWidth(-1);
2206 SetPrecision(-1);
2207 }
2208 else
2209 {
2210 wxString tmp = params.BeforeFirst(_T(','));
2211 if ( !tmp.empty() )
2212 {
2213 long width;
2214 if ( tmp.ToLong(&width) )
2215 {
2216 SetWidth((int)width);
2217 }
2218 else
2219 {
2220 wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
2221 }
2222 }
2223
2224 tmp = params.AfterFirst(_T(','));
2225 if ( !tmp.empty() )
2226 {
2227 long precision;
2228 if ( tmp.ToLong(&precision) )
2229 {
2230 SetPrecision((int)precision);
2231 }
2232 else
2233 {
2234 wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
2235 }
2236 }
2237 }
2238 }
2239
2240 // ----------------------------------------------------------------------------
2241 // wxGridCellBoolRenderer
2242 // ----------------------------------------------------------------------------
2243
2244 wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
2245
2246 // FIXME these checkbox size calculations are really ugly...
2247
2248 // between checkmark and box
2249 static const wxCoord wxGRID_CHECKMARK_MARGIN = 2;
2250
2251 wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
2252 wxGridCellAttr& WXUNUSED(attr),
2253 wxDC& WXUNUSED(dc),
2254 int WXUNUSED(row),
2255 int WXUNUSED(col))
2256 {
2257 // compute it only once (no locks for MT safeness in GUI thread...)
2258 if ( !ms_sizeCheckMark.x )
2259 {
2260 // get checkbox size
2261 wxCheckBox *checkbox = new wxCheckBox(&grid, wxID_ANY, wxEmptyString);
2262 wxSize size = checkbox->GetBestSize();
2263 wxCoord checkSize = size.y + 2 * wxGRID_CHECKMARK_MARGIN;
2264
2265 // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
2266 #if defined(__WXGTK__) || defined(__WXMOTIF__)
2267 checkSize -= size.y / 2;
2268 #endif
2269
2270 delete checkbox;
2271
2272 ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize;
2273 }
2274
2275 return ms_sizeCheckMark;
2276 }
2277
2278 void wxGridCellBoolRenderer::Draw(wxGrid& grid,
2279 wxGridCellAttr& attr,
2280 wxDC& dc,
2281 const wxRect& rect,
2282 int row, int col,
2283 bool isSelected)
2284 {
2285 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
2286
2287 // draw a check mark in the centre (ignoring alignment - TODO)
2288 wxSize size = GetBestSize(grid, attr, dc, row, col);
2289
2290 // don't draw outside the cell
2291 wxCoord minSize = wxMin(rect.width, rect.height);
2292 if ( size.x >= minSize || size.y >= minSize )
2293 {
2294 // and even leave (at least) 1 pixel margin
2295 size.x = size.y = minSize - 2;
2296 }
2297
2298 // draw a border around checkmark
2299 int vAlign, hAlign;
2300 attr.GetAlignment(&hAlign, &vAlign);
2301
2302 wxRect rectBorder;
2303 if (hAlign == wxALIGN_CENTRE)
2304 {
2305 rectBorder.x = rect.x + rect.width / 2 - size.x / 2;
2306 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
2307 rectBorder.width = size.x;
2308 rectBorder.height = size.y;
2309 }
2310 else if (hAlign == wxALIGN_LEFT)
2311 {
2312 rectBorder.x = rect.x + 2;
2313 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
2314 rectBorder.width = size.x;
2315 rectBorder.height = size.y;
2316 }
2317 else if (hAlign == wxALIGN_RIGHT)
2318 {
2319 rectBorder.x = rect.x + rect.width - size.x - 2;
2320 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
2321 rectBorder.width = size.x;
2322 rectBorder.height = size.y;
2323 }
2324
2325 bool value;
2326 if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
2327 {
2328 value = grid.GetTable()->GetValueAsBool(row, col);
2329 }
2330 else
2331 {
2332 wxString cellval( grid.GetTable()->GetValue(row, col) );
2333 value = wxGridCellBoolEditor::IsTrueValue(cellval);
2334 }
2335
2336 if ( value )
2337 {
2338 wxRect rectMark = rectBorder;
2339
2340 #ifdef __WXMSW__
2341 // MSW DrawCheckMark() is weird (and should probably be changed...)
2342 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN / 2);
2343 rectMark.x++;
2344 rectMark.y++;
2345 #else
2346 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN);
2347 #endif
2348
2349 dc.SetTextForeground(attr.GetTextColour());
2350 dc.DrawCheckMark(rectMark);
2351 }
2352
2353 dc.SetBrush(*wxTRANSPARENT_BRUSH);
2354 dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID));
2355 dc.DrawRectangle(rectBorder);
2356 }
2357
2358 // ----------------------------------------------------------------------------
2359 // wxGridCellAttr
2360 // ----------------------------------------------------------------------------
2361
2362 void wxGridCellAttr::Init(wxGridCellAttr *attrDefault)
2363 {
2364 m_nRef = 1;
2365
2366 m_isReadOnly = Unset;
2367
2368 m_renderer = NULL;
2369 m_editor = NULL;
2370
2371 m_attrkind = wxGridCellAttr::Cell;
2372
2373 m_sizeRows = m_sizeCols = 1;
2374 m_overflow = UnsetOverflow;
2375
2376 SetDefAttr(attrDefault);
2377 }
2378
2379 wxGridCellAttr *wxGridCellAttr::Clone() const
2380 {
2381 wxGridCellAttr *attr = new wxGridCellAttr(m_defGridAttr);
2382
2383 if ( HasTextColour() )
2384 attr->SetTextColour(GetTextColour());
2385 if ( HasBackgroundColour() )
2386 attr->SetBackgroundColour(GetBackgroundColour());
2387 if ( HasFont() )
2388 attr->SetFont(GetFont());
2389 if ( HasAlignment() )
2390 attr->SetAlignment(m_hAlign, m_vAlign);
2391
2392 attr->SetSize( m_sizeRows, m_sizeCols );
2393
2394 if ( m_renderer )
2395 {
2396 attr->SetRenderer(m_renderer);
2397 m_renderer->IncRef();
2398 }
2399 if ( m_editor )
2400 {
2401 attr->SetEditor(m_editor);
2402 m_editor->IncRef();
2403 }
2404
2405 if ( IsReadOnly() )
2406 attr->SetReadOnly();
2407
2408 attr->SetOverflow( m_overflow == Overflow );
2409 attr->SetKind( m_attrkind );
2410
2411 return attr;
2412 }
2413
2414 void wxGridCellAttr::MergeWith(wxGridCellAttr *mergefrom)
2415 {
2416 if ( !HasTextColour() && mergefrom->HasTextColour() )
2417 SetTextColour(mergefrom->GetTextColour());
2418 if ( !HasBackgroundColour() && mergefrom->HasBackgroundColour() )
2419 SetBackgroundColour(mergefrom->GetBackgroundColour());
2420 if ( !HasFont() && mergefrom->HasFont() )
2421 SetFont(mergefrom->GetFont());
2422 if ( !HasAlignment() && mergefrom->HasAlignment() )
2423 {
2424 int hAlign, vAlign;
2425 mergefrom->GetAlignment( &hAlign, &vAlign);
2426 SetAlignment(hAlign, vAlign);
2427 }
2428 if ( !HasSize() && mergefrom->HasSize() )
2429 mergefrom->GetSize( &m_sizeRows, &m_sizeCols );
2430
2431 // Directly access member functions as GetRender/Editor don't just return
2432 // m_renderer/m_editor
2433 //
2434 // Maybe add support for merge of Render and Editor?
2435 if (!HasRenderer() && mergefrom->HasRenderer() )
2436 {
2437 m_renderer = mergefrom->m_renderer;
2438 m_renderer->IncRef();
2439 }
2440 if ( !HasEditor() && mergefrom->HasEditor() )
2441 {
2442 m_editor = mergefrom->m_editor;
2443 m_editor->IncRef();
2444 }
2445 if ( !HasReadWriteMode() && mergefrom->HasReadWriteMode() )
2446 SetReadOnly(mergefrom->IsReadOnly());
2447
2448 if (!HasOverflowMode() && mergefrom->HasOverflowMode() )
2449 SetOverflow(mergefrom->GetOverflow());
2450
2451 SetDefAttr(mergefrom->m_defGridAttr);
2452 }
2453
2454 void wxGridCellAttr::SetSize(int num_rows, int num_cols)
2455 {
2456 // The size of a cell is normally 1,1
2457
2458 // If this cell is larger (2,2) then this is the top left cell
2459 // the other cells that will be covered (lower right cells) must be
2460 // set to negative or zero values such that
2461 // row + num_rows of the covered cell points to the larger cell (this cell)
2462 // same goes for the col + num_cols.
2463
2464 // Size of 0,0 is NOT valid, neither is <=0 and any positive value
2465
2466 wxASSERT_MSG( (!((num_rows > 0) && (num_cols <= 0)) ||
2467 !((num_rows <= 0) && (num_cols > 0)) ||
2468 !((num_rows == 0) && (num_cols == 0))),
2469 wxT("wxGridCellAttr::SetSize only takes two postive values or negative/zero values"));
2470
2471 m_sizeRows = num_rows;
2472 m_sizeCols = num_cols;
2473 }
2474
2475 const wxColour& wxGridCellAttr::GetTextColour() const
2476 {
2477 if (HasTextColour())
2478 {
2479 return m_colText;
2480 }
2481 else if (m_defGridAttr && m_defGridAttr != this)
2482 {
2483 return m_defGridAttr->GetTextColour();
2484 }
2485 else
2486 {
2487 wxFAIL_MSG(wxT("Missing default cell attribute"));
2488 return wxNullColour;
2489 }
2490 }
2491
2492 const wxColour& wxGridCellAttr::GetBackgroundColour() const
2493 {
2494 if (HasBackgroundColour())
2495 {
2496 return m_colBack;
2497 }
2498 else if (m_defGridAttr && m_defGridAttr != this)
2499 {
2500 return m_defGridAttr->GetBackgroundColour();
2501 }
2502 else
2503 {
2504 wxFAIL_MSG(wxT("Missing default cell attribute"));
2505 return wxNullColour;
2506 }
2507 }
2508
2509 const wxFont& wxGridCellAttr::GetFont() const
2510 {
2511 if (HasFont())
2512 {
2513 return m_font;
2514 }
2515 else if (m_defGridAttr && m_defGridAttr != this)
2516 {
2517 return m_defGridAttr->GetFont();
2518 }
2519 else
2520 {
2521 wxFAIL_MSG(wxT("Missing default cell attribute"));
2522 return wxNullFont;
2523 }
2524 }
2525
2526 void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
2527 {
2528 if (HasAlignment())
2529 {
2530 if ( hAlign )
2531 *hAlign = m_hAlign;
2532 if ( vAlign )
2533 *vAlign = m_vAlign;
2534 }
2535 else if (m_defGridAttr && m_defGridAttr != this)
2536 {
2537 m_defGridAttr->GetAlignment(hAlign, vAlign);
2538 }
2539 else
2540 {
2541 wxFAIL_MSG(wxT("Missing default cell attribute"));
2542 }
2543 }
2544
2545 void wxGridCellAttr::GetSize( int *num_rows, int *num_cols ) const
2546 {
2547 if ( num_rows )
2548 *num_rows = m_sizeRows;
2549 if ( num_cols )
2550 *num_cols = m_sizeCols;
2551 }
2552
2553 // GetRenderer and GetEditor use a slightly different decision path about
2554 // which attribute to use. If a non-default attr object has one then it is
2555 // used, otherwise the default editor or renderer is fetched from the grid and
2556 // used. It should be the default for the data type of the cell. If it is
2557 // NULL (because the table has a type that the grid does not have in its
2558 // registry), then the grid's default editor or renderer is used.
2559
2560 wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const
2561 {
2562 wxGridCellRenderer *renderer = NULL;
2563
2564 if ( m_renderer && this != m_defGridAttr )
2565 {
2566 // use the cells renderer if it has one
2567 renderer = m_renderer;
2568 renderer->IncRef();
2569 }
2570 else // no non-default cell renderer
2571 {
2572 // get default renderer for the data type
2573 if ( grid )
2574 {
2575 // GetDefaultRendererForCell() will do IncRef() for us
2576 renderer = grid->GetDefaultRendererForCell(row, col);
2577 }
2578
2579 if ( renderer == NULL )
2580 {
2581 if ( (m_defGridAttr != NULL) && (m_defGridAttr != this) )
2582 {
2583 // if we still don't have one then use the grid default
2584 // (no need for IncRef() here neither)
2585 renderer = m_defGridAttr->GetRenderer(NULL, 0, 0);
2586 }
2587 else // default grid attr
2588 {
2589 // use m_renderer which we had decided not to use initially
2590 renderer = m_renderer;
2591 if ( renderer )
2592 renderer->IncRef();
2593 }
2594 }
2595 }
2596
2597 // we're supposed to always find something
2598 wxASSERT_MSG(renderer, wxT("Missing default cell renderer"));
2599
2600 return renderer;
2601 }
2602
2603 // same as above, except for s/renderer/editor/g
2604 wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const
2605 {
2606 wxGridCellEditor *editor = NULL;
2607
2608 if ( m_editor && this != m_defGridAttr )
2609 {
2610 // use the cells editor if it has one
2611 editor = m_editor;
2612 editor->IncRef();
2613 }
2614 else // no non default cell editor
2615 {
2616 // get default editor for the data type
2617 if ( grid )
2618 {
2619 // GetDefaultEditorForCell() will do IncRef() for us
2620 editor = grid->GetDefaultEditorForCell(row, col);
2621 }
2622
2623 if ( editor == NULL )
2624 {
2625 if ( (m_defGridAttr != NULL) && (m_defGridAttr != this) )
2626 {
2627 // if we still don't have one then use the grid default
2628 // (no need for IncRef() here neither)
2629 editor = m_defGridAttr->GetEditor(NULL, 0, 0);
2630 }
2631 else // default grid attr
2632 {
2633 // use m_editor which we had decided not to use initially
2634 editor = m_editor;
2635 if ( editor )
2636 editor->IncRef();
2637 }
2638 }
2639 }
2640
2641 // we're supposed to always find something
2642 wxASSERT_MSG(editor, wxT("Missing default cell editor"));
2643
2644 return editor;
2645 }
2646
2647 // ----------------------------------------------------------------------------
2648 // wxGridCellAttrData
2649 // ----------------------------------------------------------------------------
2650
2651 void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
2652 {
2653 // Note: contrary to wxGridRowOrColAttrData::SetAttr, we must not
2654 // touch attribute's reference counting explicitly, since this
2655 // is managed by class wxGridCellWithAttr
2656 int n = FindIndex(row, col);
2657 if ( n == wxNOT_FOUND )
2658 {
2659 if ( attr )
2660 {
2661 // add the attribute
2662 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
2663 }
2664 //else: nothing to do
2665 }
2666 else // we already have an attribute for this cell
2667 {
2668 if ( attr )
2669 {
2670 // change the attribute
2671 m_attrs[(size_t)n].ChangeAttr(attr);
2672 }
2673 else
2674 {
2675 // remove this attribute
2676 m_attrs.RemoveAt((size_t)n);
2677 }
2678 }
2679 }
2680
2681 wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
2682 {
2683 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2684
2685 int n = FindIndex(row, col);
2686 if ( n != wxNOT_FOUND )
2687 {
2688 attr = m_attrs[(size_t)n].attr;
2689 attr->IncRef();
2690 }
2691
2692 return attr;
2693 }
2694
2695 void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows )
2696 {
2697 size_t count = m_attrs.GetCount();
2698 for ( size_t n = 0; n < count; n++ )
2699 {
2700 wxGridCellCoords& coords = m_attrs[n].coords;
2701 wxCoord row = coords.GetRow();
2702 if ((size_t)row >= pos)
2703 {
2704 if (numRows > 0)
2705 {
2706 // If rows inserted, include row counter where necessary
2707 coords.SetRow(row + numRows);
2708 }
2709 else if (numRows < 0)
2710 {
2711 // If rows deleted ...
2712 if ((size_t)row >= pos - numRows)
2713 {
2714 // ...either decrement row counter (if row still exists)...
2715 coords.SetRow(row + numRows);
2716 }
2717 else
2718 {
2719 // ...or remove the attribute
2720 m_attrs.RemoveAt(n);
2721 n--;
2722 count--;
2723 }
2724 }
2725 }
2726 }
2727 }
2728
2729 void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols )
2730 {
2731 size_t count = m_attrs.GetCount();
2732 for ( size_t n = 0; n < count; n++ )
2733 {
2734 wxGridCellCoords& coords = m_attrs[n].coords;
2735 wxCoord col = coords.GetCol();
2736 if ( (size_t)col >= pos )
2737 {
2738 if ( numCols > 0 )
2739 {
2740 // If rows inserted, include row counter where necessary
2741 coords.SetCol(col + numCols);
2742 }
2743 else if (numCols < 0)
2744 {
2745 // If rows deleted ...
2746 if ((size_t)col >= pos - numCols)
2747 {
2748 // ...either decrement row counter (if row still exists)...
2749 coords.SetCol(col + numCols);
2750 }
2751 else
2752 {
2753 // ...or remove the attribute
2754 m_attrs.RemoveAt(n);
2755 n--;
2756 count--;
2757 }
2758 }
2759 }
2760 }
2761 }
2762
2763 int wxGridCellAttrData::FindIndex(int row, int col) const
2764 {
2765 size_t count = m_attrs.GetCount();
2766 for ( size_t n = 0; n < count; n++ )
2767 {
2768 const wxGridCellCoords& coords = m_attrs[n].coords;
2769 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
2770 {
2771 return n;
2772 }
2773 }
2774
2775 return wxNOT_FOUND;
2776 }
2777
2778 // ----------------------------------------------------------------------------
2779 // wxGridRowOrColAttrData
2780 // ----------------------------------------------------------------------------
2781
2782 wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
2783 {
2784 size_t count = m_attrs.Count();
2785 for ( size_t n = 0; n < count; n++ )
2786 {
2787 m_attrs[n]->DecRef();
2788 }
2789 }
2790
2791 wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
2792 {
2793 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2794
2795 int n = m_rowsOrCols.Index(rowOrCol);
2796 if ( n != wxNOT_FOUND )
2797 {
2798 attr = m_attrs[(size_t)n];
2799 attr->IncRef();
2800 }
2801
2802 return attr;
2803 }
2804
2805 void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
2806 {
2807 int i = m_rowsOrCols.Index(rowOrCol);
2808 if ( i == wxNOT_FOUND )
2809 {
2810 if ( attr )
2811 {
2812 // add the attribute - no need to do anything to reference count
2813 // since we take ownership of the attribute.
2814 m_rowsOrCols.Add(rowOrCol);
2815 m_attrs.Add(attr);
2816 }
2817 // nothing to remove
2818 }
2819 else
2820 {
2821 size_t n = (size_t)i;
2822 if ( m_attrs[n] == attr )
2823 // nothing to do
2824 return;
2825 if ( attr )
2826 {
2827 // change the attribute, handling reference count manually,
2828 // taking ownership of the new attribute.
2829 m_attrs[n]->DecRef();
2830 m_attrs[n] = attr;
2831 }
2832 else
2833 {
2834 // remove this attribute, handling reference count manually
2835 m_attrs[n]->DecRef();
2836 m_rowsOrCols.RemoveAt(n);
2837 m_attrs.RemoveAt(n);
2838 }
2839 }
2840 }
2841
2842 void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols )
2843 {
2844 size_t count = m_attrs.GetCount();
2845 for ( size_t n = 0; n < count; n++ )
2846 {
2847 int & rowOrCol = m_rowsOrCols[n];
2848 if ( (size_t)rowOrCol >= pos )
2849 {
2850 if ( numRowsOrCols > 0 )
2851 {
2852 // If rows inserted, include row counter where necessary
2853 rowOrCol += numRowsOrCols;
2854 }
2855 else if ( numRowsOrCols < 0)
2856 {
2857 // If rows deleted, either decrement row counter (if row still exists)
2858 if ((size_t)rowOrCol >= pos - numRowsOrCols)
2859 rowOrCol += numRowsOrCols;
2860 else
2861 {
2862 m_rowsOrCols.RemoveAt(n);
2863 m_attrs[n]->DecRef();
2864 m_attrs.RemoveAt(n);
2865 n--;
2866 count--;
2867 }
2868 }
2869 }
2870 }
2871 }
2872
2873 // ----------------------------------------------------------------------------
2874 // wxGridCellAttrProvider
2875 // ----------------------------------------------------------------------------
2876
2877 wxGridCellAttrProvider::wxGridCellAttrProvider()
2878 {
2879 m_data = (wxGridCellAttrProviderData *)NULL;
2880 }
2881
2882 wxGridCellAttrProvider::~wxGridCellAttrProvider()
2883 {
2884 delete m_data;
2885 }
2886
2887 void wxGridCellAttrProvider::InitData()
2888 {
2889 m_data = new wxGridCellAttrProviderData;
2890 }
2891
2892 wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col,
2893 wxGridCellAttr::wxAttrKind kind ) const
2894 {
2895 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2896 if ( m_data )
2897 {
2898 switch (kind)
2899 {
2900 case (wxGridCellAttr::Any):
2901 // Get cached merge attributes.
2902 // Currently not used as no cache implemented as not mutable
2903 // attr = m_data->m_mergeAttr.GetAttr(row, col);
2904 if (!attr)
2905 {
2906 // Basically implement old version.
2907 // Also check merge cache, so we don't have to re-merge every time..
2908 wxGridCellAttr *attrcell = m_data->m_cellAttrs.GetAttr(row, col);
2909 wxGridCellAttr *attrrow = m_data->m_rowAttrs.GetAttr(row);
2910 wxGridCellAttr *attrcol = m_data->m_colAttrs.GetAttr(col);
2911
2912 if ((attrcell != attrrow) && (attrrow != attrcol) && (attrcell != attrcol))
2913 {
2914 // Two or more are non NULL
2915 attr = new wxGridCellAttr;
2916 attr->SetKind(wxGridCellAttr::Merged);
2917
2918 // Order is important..
2919 if (attrcell)
2920 {
2921 attr->MergeWith(attrcell);
2922 attrcell->DecRef();
2923 }
2924 if (attrcol)
2925 {
2926 attr->MergeWith(attrcol);
2927 attrcol->DecRef();
2928 }
2929 if (attrrow)
2930 {
2931 attr->MergeWith(attrrow);
2932 attrrow->DecRef();
2933 }
2934
2935 // store merge attr if cache implemented
2936 //attr->IncRef();
2937 //m_data->m_mergeAttr.SetAttr(attr, row, col);
2938 }
2939 else
2940 {
2941 // one or none is non null return it or null.
2942 if (attrrow)
2943 attr = attrrow;
2944 if (attrcol)
2945 {
2946 if (attr)
2947 attr->DecRef();
2948 attr = attrcol;
2949 }
2950 if (attrcell)
2951 {
2952 if (attr)
2953 attr->DecRef();
2954 attr = attrcell;
2955 }
2956 }
2957 }
2958 break;
2959
2960 case (wxGridCellAttr::Cell):
2961 attr = m_data->m_cellAttrs.GetAttr(row, col);
2962 break;
2963
2964 case (wxGridCellAttr::Col):
2965 attr = m_data->m_colAttrs.GetAttr(col);
2966 break;
2967
2968 case (wxGridCellAttr::Row):
2969 attr = m_data->m_rowAttrs.GetAttr(row);
2970 break;
2971
2972 default:
2973 // unused as yet...
2974 // (wxGridCellAttr::Default):
2975 // (wxGridCellAttr::Merged):
2976 break;
2977 }
2978 }
2979
2980 return attr;
2981 }
2982
2983 void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
2984 int row, int col)
2985 {
2986 if ( !m_data )
2987 InitData();
2988
2989 m_data->m_cellAttrs.SetAttr(attr, row, col);
2990 }
2991
2992 void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
2993 {
2994 if ( !m_data )
2995 InitData();
2996
2997 m_data->m_rowAttrs.SetAttr(attr, row);
2998 }
2999
3000 void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
3001 {
3002 if ( !m_data )
3003 InitData();
3004
3005 m_data->m_colAttrs.SetAttr(attr, col);
3006 }
3007
3008 void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows )
3009 {
3010 if ( m_data )
3011 {
3012 m_data->m_cellAttrs.UpdateAttrRows( pos, numRows );
3013
3014 m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows );
3015 }
3016 }
3017
3018 void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols )
3019 {
3020 if ( m_data )
3021 {
3022 m_data->m_cellAttrs.UpdateAttrCols( pos, numCols );
3023
3024 m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols );
3025 }
3026 }
3027
3028 // ----------------------------------------------------------------------------
3029 // wxGridTypeRegistry
3030 // ----------------------------------------------------------------------------
3031
3032 wxGridTypeRegistry::~wxGridTypeRegistry()
3033 {
3034 size_t count = m_typeinfo.Count();
3035 for ( size_t i = 0; i < count; i++ )
3036 delete m_typeinfo[i];
3037 }
3038
3039 void wxGridTypeRegistry::RegisterDataType(const wxString& typeName,
3040 wxGridCellRenderer* renderer,
3041 wxGridCellEditor* editor)
3042 {
3043 wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor);
3044
3045 // is it already registered?
3046 int loc = FindRegisteredDataType(typeName);
3047 if ( loc != wxNOT_FOUND )
3048 {
3049 delete m_typeinfo[loc];
3050 m_typeinfo[loc] = info;
3051 }
3052 else
3053 {
3054 m_typeinfo.Add(info);
3055 }
3056 }
3057
3058 int wxGridTypeRegistry::FindRegisteredDataType(const wxString& typeName)
3059 {
3060 size_t count = m_typeinfo.GetCount();
3061 for ( size_t i = 0; i < count; i++ )
3062 {
3063 if ( typeName == m_typeinfo[i]->m_typeName )
3064 {
3065 return i;
3066 }
3067 }
3068
3069 return wxNOT_FOUND;
3070 }
3071
3072 int wxGridTypeRegistry::FindDataType(const wxString& typeName)
3073 {
3074 int index = FindRegisteredDataType(typeName);
3075 if ( index == wxNOT_FOUND )
3076 {
3077 // check whether this is one of the standard ones, in which case
3078 // register it "on the fly"
3079 #if wxUSE_TEXTCTRL
3080 if ( typeName == wxGRID_VALUE_STRING )
3081 {
3082 RegisterDataType(wxGRID_VALUE_STRING,
3083 new wxGridCellStringRenderer,
3084 new wxGridCellTextEditor);
3085 }
3086 else
3087 #endif // wxUSE_TEXTCTRL
3088 #if wxUSE_CHECKBOX
3089 if ( typeName == wxGRID_VALUE_BOOL )
3090 {
3091 RegisterDataType(wxGRID_VALUE_BOOL,
3092 new wxGridCellBoolRenderer,
3093 new wxGridCellBoolEditor);
3094 }
3095 else
3096 #endif // wxUSE_CHECKBOX
3097 #if wxUSE_TEXTCTRL
3098 if ( typeName == wxGRID_VALUE_NUMBER )
3099 {
3100 RegisterDataType(wxGRID_VALUE_NUMBER,
3101 new wxGridCellNumberRenderer,
3102 new wxGridCellNumberEditor);
3103 }
3104 else if ( typeName == wxGRID_VALUE_FLOAT )
3105 {
3106 RegisterDataType(wxGRID_VALUE_FLOAT,
3107 new wxGridCellFloatRenderer,
3108 new wxGridCellFloatEditor);
3109 }
3110 else
3111 #endif // wxUSE_TEXTCTRL
3112 #if wxUSE_COMBOBOX
3113 if ( typeName == wxGRID_VALUE_CHOICE )
3114 {
3115 RegisterDataType(wxGRID_VALUE_CHOICE,
3116 new wxGridCellStringRenderer,
3117 new wxGridCellChoiceEditor);
3118 }
3119 else
3120 #endif // wxUSE_COMBOBOX
3121 {
3122 return wxNOT_FOUND;
3123 }
3124
3125 // we get here only if just added the entry for this type, so return
3126 // the last index
3127 index = m_typeinfo.GetCount() - 1;
3128 }
3129
3130 return index;
3131 }
3132
3133 int wxGridTypeRegistry::FindOrCloneDataType(const wxString& typeName)
3134 {
3135 int index = FindDataType(typeName);
3136 if ( index == wxNOT_FOUND )
3137 {
3138 // the first part of the typename is the "real" type, anything after ':'
3139 // are the parameters for the renderer
3140 index = FindDataType(typeName.BeforeFirst(_T(':')));
3141 if ( index == wxNOT_FOUND )
3142 {
3143 return wxNOT_FOUND;
3144 }
3145
3146 wxGridCellRenderer *renderer = GetRenderer(index);
3147 wxGridCellRenderer *rendererOld = renderer;
3148 renderer = renderer->Clone();
3149 rendererOld->DecRef();
3150
3151 wxGridCellEditor *editor = GetEditor(index);
3152 wxGridCellEditor *editorOld = editor;
3153 editor = editor->Clone();
3154 editorOld->DecRef();
3155
3156 // do it even if there are no parameters to reset them to defaults
3157 wxString params = typeName.AfterFirst(_T(':'));
3158 renderer->SetParameters(params);
3159 editor->SetParameters(params);
3160
3161 // register the new typename
3162 RegisterDataType(typeName, renderer, editor);
3163
3164 // we just registered it, it's the last one
3165 index = m_typeinfo.GetCount() - 1;
3166 }
3167
3168 return index;
3169 }
3170
3171 wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index)
3172 {
3173 wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer;
3174 if (renderer)
3175 renderer->IncRef();
3176
3177 return renderer;
3178 }
3179
3180 wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
3181 {
3182 wxGridCellEditor* editor = m_typeinfo[index]->m_editor;
3183 if (editor)
3184 editor->IncRef();
3185
3186 return editor;
3187 }
3188
3189 // ----------------------------------------------------------------------------
3190 // wxGridTableBase
3191 // ----------------------------------------------------------------------------
3192
3193 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
3194
3195 wxGridTableBase::wxGridTableBase()
3196 {
3197 m_view = (wxGrid *) NULL;
3198 m_attrProvider = (wxGridCellAttrProvider *) NULL;
3199 }
3200
3201 wxGridTableBase::~wxGridTableBase()
3202 {
3203 delete m_attrProvider;
3204 }
3205
3206 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
3207 {
3208 delete m_attrProvider;
3209 m_attrProvider = attrProvider;
3210 }
3211
3212 bool wxGridTableBase::CanHaveAttributes()
3213 {
3214 if ( ! GetAttrProvider() )
3215 {
3216 // use the default attr provider by default
3217 SetAttrProvider(new wxGridCellAttrProvider);
3218 }
3219
3220 return true;
3221 }
3222
3223 wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind)
3224 {
3225 if ( m_attrProvider )
3226 return m_attrProvider->GetAttr(row, col, kind);
3227 else
3228 return (wxGridCellAttr *)NULL;
3229 }
3230
3231 void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
3232 {
3233 if ( m_attrProvider )
3234 {
3235 if ( attr )
3236 attr->SetKind(wxGridCellAttr::Cell);
3237 m_attrProvider->SetAttr(attr, row, col);
3238 }
3239 else
3240 {
3241 // as we take ownership of the pointer and don't store it, we must
3242 // free it now
3243 wxSafeDecRef(attr);
3244 }
3245 }
3246
3247 void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
3248 {
3249 if ( m_attrProvider )
3250 {
3251 attr->SetKind(wxGridCellAttr::Row);
3252 m_attrProvider->SetRowAttr(attr, row);
3253 }
3254 else
3255 {
3256 // as we take ownership of the pointer and don't store it, we must
3257 // free it now
3258 wxSafeDecRef(attr);
3259 }
3260 }
3261
3262 void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
3263 {
3264 if ( m_attrProvider )
3265 {
3266 attr->SetKind(wxGridCellAttr::Col);
3267 m_attrProvider->SetColAttr(attr, col);
3268 }
3269 else
3270 {
3271 // as we take ownership of the pointer and don't store it, we must
3272 // free it now
3273 wxSafeDecRef(attr);
3274 }
3275 }
3276
3277 bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos),
3278 size_t WXUNUSED(numRows) )
3279 {
3280 wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") );
3281
3282 return false;
3283 }
3284
3285 bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows) )
3286 {
3287 wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function"));
3288
3289 return false;
3290 }
3291
3292 bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos),
3293 size_t WXUNUSED(numRows) )
3294 {
3295 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function"));
3296
3297 return false;
3298 }
3299
3300 bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos),
3301 size_t WXUNUSED(numCols) )
3302 {
3303 wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function"));
3304
3305 return false;
3306 }
3307
3308 bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols) )
3309 {
3310 wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function"));
3311
3312 return false;
3313 }
3314
3315 bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos),
3316 size_t WXUNUSED(numCols) )
3317 {
3318 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function"));
3319
3320 return false;
3321 }
3322
3323 wxString wxGridTableBase::GetRowLabelValue( int row )
3324 {
3325 wxString s;
3326
3327 // RD: Starting the rows at zero confuses users,
3328 // no matter how much it makes sense to us geeks.
3329 s << row + 1;
3330
3331 return s;
3332 }
3333
3334 wxString wxGridTableBase::GetColLabelValue( int col )
3335 {
3336 // default col labels are:
3337 // cols 0 to 25 : A-Z
3338 // cols 26 to 675 : AA-ZZ
3339 // etc.
3340
3341 wxString s;
3342 unsigned int i, n;
3343 for ( n = 1; ; n++ )
3344 {
3345 s += (wxChar) (_T('A') + (wxChar)(col % 26));
3346 col = col / 26 - 1;
3347 if ( col < 0 )
3348 break;
3349 }
3350
3351 // reverse the string...
3352 wxString s2;
3353 for ( i = 0; i < n; i++ )
3354 {
3355 s2 += s[n - i - 1];
3356 }
3357
3358 return s2;
3359 }
3360
3361 wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) )
3362 {
3363 return wxGRID_VALUE_STRING;
3364 }
3365
3366 bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col),
3367 const wxString& typeName )
3368 {
3369 return typeName == wxGRID_VALUE_STRING;
3370 }
3371
3372 bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName )
3373 {
3374 return CanGetValueAs(row, col, typeName);
3375 }
3376
3377 long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) )
3378 {
3379 return 0;
3380 }
3381
3382 double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) )
3383 {
3384 return 0.0;
3385 }
3386
3387 bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) )
3388 {
3389 return false;
3390 }
3391
3392 void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col),
3393 long WXUNUSED(value) )
3394 {
3395 }
3396
3397 void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col),
3398 double WXUNUSED(value) )
3399 {
3400 }
3401
3402 void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col),
3403 bool WXUNUSED(value) )
3404 {
3405 }
3406
3407 void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
3408 const wxString& WXUNUSED(typeName) )
3409 {
3410 return NULL;
3411 }
3412
3413 void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
3414 const wxString& WXUNUSED(typeName),
3415 void* WXUNUSED(value) )
3416 {
3417 }
3418
3419 //////////////////////////////////////////////////////////////////////
3420 //
3421 // Message class for the grid table to send requests and notifications
3422 // to the grid view
3423 //
3424
3425 wxGridTableMessage::wxGridTableMessage()
3426 {
3427 m_table = (wxGridTableBase *) NULL;
3428 m_id = -1;
3429 m_comInt1 = -1;
3430 m_comInt2 = -1;
3431 }
3432
3433 wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
3434 int commandInt1, int commandInt2 )
3435 {
3436 m_table = table;
3437 m_id = id;
3438 m_comInt1 = commandInt1;
3439 m_comInt2 = commandInt2;
3440 }
3441
3442 //////////////////////////////////////////////////////////////////////
3443 //
3444 // A basic grid table for string data. An object of this class will
3445 // created by wxGrid if you don't specify an alternative table class.
3446 //
3447
3448 WX_DEFINE_OBJARRAY(wxGridStringArray)
3449
3450 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
3451
3452 wxGridStringTable::wxGridStringTable()
3453 : wxGridTableBase()
3454 {
3455 }
3456
3457 wxGridStringTable::wxGridStringTable( int numRows, int numCols )
3458 : wxGridTableBase()
3459 {
3460 m_data.Alloc( numRows );
3461
3462 wxArrayString sa;
3463 sa.Alloc( numCols );
3464 sa.Add( wxEmptyString, numCols );
3465
3466 m_data.Add( sa, numRows );
3467 }
3468
3469 wxGridStringTable::~wxGridStringTable()
3470 {
3471 }
3472
3473 int wxGridStringTable::GetNumberRows()
3474 {
3475 return m_data.GetCount();
3476 }
3477
3478 int wxGridStringTable::GetNumberCols()
3479 {
3480 if ( m_data.GetCount() > 0 )
3481 return m_data[0].GetCount();
3482 else
3483 return 0;
3484 }
3485
3486 wxString wxGridStringTable::GetValue( int row, int col )
3487 {
3488 wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
3489 wxEmptyString,
3490 _T("invalid row or column index in wxGridStringTable") );
3491
3492 return m_data[row][col];
3493 }
3494
3495 void wxGridStringTable::SetValue( int row, int col, const wxString& value )
3496 {
3497 wxCHECK_RET( (row < GetNumberRows()) && (col < GetNumberCols()),
3498 _T("invalid row or column index in wxGridStringTable") );
3499
3500 m_data[row][col] = value;
3501 }
3502
3503 bool wxGridStringTable::IsEmptyCell( int row, int col )
3504 {
3505 wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
3506 true,
3507 _T("invalid row or column index in wxGridStringTable") );
3508
3509 return (m_data[row][col] == wxEmptyString);
3510 }
3511
3512 void wxGridStringTable::Clear()
3513 {
3514 int row, col;
3515 int numRows, numCols;
3516
3517 numRows = m_data.GetCount();
3518 if ( numRows > 0 )
3519 {
3520 numCols = m_data[0].GetCount();
3521
3522 for ( row = 0; row < numRows; row++ )
3523 {
3524 for ( col = 0; col < numCols; col++ )
3525 {
3526 m_data[row][col] = wxEmptyString;
3527 }
3528 }
3529 }
3530 }
3531
3532 bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
3533 {
3534 size_t curNumRows = m_data.GetCount();
3535 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3536 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
3537
3538 if ( pos >= curNumRows )
3539 {
3540 return AppendRows( numRows );
3541 }
3542
3543 wxArrayString sa;
3544 sa.Alloc( curNumCols );
3545 sa.Add( wxEmptyString, curNumCols );
3546 m_data.Insert( sa, pos, numRows );
3547
3548 if ( GetView() )
3549 {
3550 wxGridTableMessage msg( this,
3551 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
3552 pos,
3553 numRows );
3554
3555 GetView()->ProcessTableMessage( msg );
3556 }
3557
3558 return true;
3559 }
3560
3561 bool wxGridStringTable::AppendRows( size_t numRows )
3562 {
3563 size_t curNumRows = m_data.GetCount();
3564 size_t curNumCols = ( curNumRows > 0
3565 ? m_data[0].GetCount()
3566 : ( GetView() ? GetView()->GetNumberCols() : 0 ) );
3567
3568 wxArrayString sa;
3569 if ( curNumCols > 0 )
3570 {
3571 sa.Alloc( curNumCols );
3572 sa.Add( wxEmptyString, curNumCols );
3573 }
3574
3575 m_data.Add( sa, numRows );
3576
3577 if ( GetView() )
3578 {
3579 wxGridTableMessage msg( this,
3580 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
3581 numRows );
3582
3583 GetView()->ProcessTableMessage( msg );
3584 }
3585
3586 return true;
3587 }
3588
3589 bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
3590 {
3591 size_t curNumRows = m_data.GetCount();
3592
3593 if ( pos >= curNumRows )
3594 {
3595 wxFAIL_MSG( wxString::Format
3596 (
3597 wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"),
3598 (unsigned long)pos,
3599 (unsigned long)numRows,
3600 (unsigned long)curNumRows
3601 ) );
3602
3603 return false;
3604 }
3605
3606 if ( numRows > curNumRows - pos )
3607 {
3608 numRows = curNumRows - pos;
3609 }
3610
3611 if ( numRows >= curNumRows )
3612 {
3613 m_data.Clear();
3614 }
3615 else
3616 {
3617 m_data.RemoveAt( pos, numRows );
3618 }
3619
3620 if ( GetView() )
3621 {
3622 wxGridTableMessage msg( this,
3623 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
3624 pos,
3625 numRows );
3626
3627 GetView()->ProcessTableMessage( msg );
3628 }
3629
3630 return true;
3631 }
3632
3633 bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
3634 {
3635 size_t row, col;
3636
3637 size_t curNumRows = m_data.GetCount();
3638 size_t curNumCols = ( curNumRows > 0
3639 ? m_data[0].GetCount()
3640 : ( GetView() ? GetView()->GetNumberCols() : 0 ) );
3641
3642 if ( pos >= curNumCols )
3643 {
3644 return AppendCols( numCols );
3645 }
3646
3647 if ( !m_colLabels.IsEmpty() )
3648 {
3649 m_colLabels.Insert( wxEmptyString, pos, numCols );
3650
3651 size_t i;
3652 for ( i = pos; i < pos + numCols; i++ )
3653 m_colLabels[i] = wxGridTableBase::GetColLabelValue( i );
3654 }
3655
3656 for ( row = 0; row < curNumRows; row++ )
3657 {
3658 for ( col = pos; col < pos + numCols; col++ )
3659 {
3660 m_data[row].Insert( wxEmptyString, col );
3661 }