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