]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/grid.cpp
More updates to the Debian packaging for wxPython, unicode and
[wxWidgets.git] / src / generic / grid.cpp
... / ...
Content-type: text/html ]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/grid.cpp


500 - Internal Server Error

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