Added ForceRefresh() to request immediate repainting of a grid.
[wxWidgets.git] / src / generic / grid.cpp
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:
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 #ifdef __GNUG__
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 !defined(wxUSE_NEW_GRID) || !(wxUSE_NEW_GRID)
34 #include "gridg.cpp"
35 #else
36
37 #ifndef WX_PRECOMP
38 #include "wx/utils.h"
39 #include "wx/dcclient.h"
40 #include "wx/settings.h"
41 #include "wx/log.h"
42 #include "wx/textctrl.h"
43 #include "wx/checkbox.h"
44 #include "wx/combobox.h"
45 #include "wx/valtext.h"
46 #endif
47
48 #include "wx/textfile.h"
49 #include "wx/spinctrl.h"
50 #include "wx/tokenzr.h"
51
52 #include "wx/grid.h"
53 #include "wx/generic/gridsel.h"
54
55 #if defined(__WXMOTIF__)
56 #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier)
57 #else
58 #define WXUNUSED_MOTIF(identifier) identifier
59 #endif
60
61 #if defined(__WXGTK__)
62 #define WXUNUSED_GTK(identifier) WXUNUSED(identifier)
63 #else
64 #define WXUNUSED_GTK(identifier) identifier
65 #endif
66
67 // Required for wxIs... functions
68 #include <ctype.h>
69
70 // ----------------------------------------------------------------------------
71 // array classes
72 // ----------------------------------------------------------------------------
73
74 WX_DEFINE_EXPORTED_ARRAY(wxGridCellAttr *, wxArrayAttrs);
75
76 struct 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
92 WX_DECLARE_EXPORTED_OBJARRAY(wxGridCellWithAttr, wxGridCellWithAttrArray);
93
94 #include "wx/arrimpl.cpp"
95
96 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
97 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
98
99 // ----------------------------------------------------------------------------
100 // private classes
101 // ----------------------------------------------------------------------------
102
103 class WXDLLEXPORT wxGridRowLabelWindow : public wxWindow
104 {
105 public:
106 wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; }
107 wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
108 const wxPoint &pos, const wxSize &size );
109
110 private:
111 wxGrid *m_owner;
112
113 void OnPaint( wxPaintEvent& event );
114 void OnMouseEvent( wxMouseEvent& event );
115 void OnKeyDown( wxKeyEvent& event );
116 void OnKeyUp( wxKeyEvent& );
117
118 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
119 DECLARE_EVENT_TABLE()
120 };
121
122
123 class WXDLLEXPORT wxGridColLabelWindow : public wxWindow
124 {
125 public:
126 wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; }
127 wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
128 const wxPoint &pos, const wxSize &size );
129
130 private:
131 wxGrid *m_owner;
132
133 void OnPaint( wxPaintEvent &event );
134 void OnMouseEvent( wxMouseEvent& event );
135 void OnKeyDown( wxKeyEvent& event );
136 void OnKeyUp( wxKeyEvent& );
137
138 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
139 DECLARE_EVENT_TABLE()
140 };
141
142
143 class WXDLLEXPORT wxGridCornerLabelWindow : public wxWindow
144 {
145 public:
146 wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; }
147 wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
148 const wxPoint &pos, const wxSize &size );
149
150 private:
151 wxGrid *m_owner;
152
153 void OnMouseEvent( wxMouseEvent& event );
154 void OnKeyDown( wxKeyEvent& event );
155 void OnKeyUp( wxKeyEvent& );
156 void OnPaint( wxPaintEvent& event );
157
158 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
159 DECLARE_EVENT_TABLE()
160 };
161
162 class WXDLLEXPORT wxGridWindow : public wxPanel
163 {
164 public:
165 wxGridWindow()
166 {
167 m_owner = (wxGrid *)NULL;
168 m_rowLabelWin = (wxGridRowLabelWindow *)NULL;
169 m_colLabelWin = (wxGridColLabelWindow *)NULL;
170 }
171
172 wxGridWindow( wxGrid *parent,
173 wxGridRowLabelWindow *rowLblWin,
174 wxGridColLabelWindow *colLblWin,
175 wxWindowID id, const wxPoint &pos, const wxSize &size );
176 ~wxGridWindow();
177
178 void ScrollWindow( int dx, int dy, const wxRect *rect );
179
180 private:
181 wxGrid *m_owner;
182 wxGridRowLabelWindow *m_rowLabelWin;
183 wxGridColLabelWindow *m_colLabelWin;
184
185 void OnPaint( wxPaintEvent &event );
186 void OnMouseEvent( wxMouseEvent& event );
187 void OnKeyDown( wxKeyEvent& );
188 void OnKeyUp( wxKeyEvent& );
189 void OnEraseBackground( wxEraseEvent& );
190
191
192 DECLARE_DYNAMIC_CLASS(wxGridWindow)
193 DECLARE_EVENT_TABLE()
194 };
195
196
197
198 class wxGridCellEditorEvtHandler : public wxEvtHandler
199 {
200 public:
201 wxGridCellEditorEvtHandler()
202 : m_grid(0), m_editor(0)
203 { }
204 wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor)
205 : m_grid(grid), m_editor(editor)
206 { }
207
208 void OnKeyDown(wxKeyEvent& event);
209 void OnChar(wxKeyEvent& event);
210
211 private:
212 wxGrid* m_grid;
213 wxGridCellEditor* m_editor;
214 DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler)
215 DECLARE_EVENT_TABLE()
216 };
217
218
219 IMPLEMENT_DYNAMIC_CLASS( wxGridCellEditorEvtHandler, wxEvtHandler )
220 BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler )
221 EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown )
222 EVT_CHAR( wxGridCellEditorEvtHandler::OnChar )
223 END_EVENT_TABLE()
224
225
226
227 // ----------------------------------------------------------------------------
228 // the internal data representation used by wxGridCellAttrProvider
229 // ----------------------------------------------------------------------------
230
231 // this class stores attributes set for cells
232 class WXDLLEXPORT wxGridCellAttrData
233 {
234 public:
235 void SetAttr(wxGridCellAttr *attr, int row, int col);
236 wxGridCellAttr *GetAttr(int row, int col) const;
237 void UpdateAttrRows( size_t pos, int numRows );
238 void UpdateAttrCols( size_t pos, int numCols );
239
240 private:
241 // searches for the attr for given cell, returns wxNOT_FOUND if not found
242 int FindIndex(int row, int col) const;
243
244 wxGridCellWithAttrArray m_attrs;
245 };
246
247 // this class stores attributes set for rows or columns
248 class WXDLLEXPORT wxGridRowOrColAttrData
249 {
250 public:
251 // empty ctor to suppress warnings
252 wxGridRowOrColAttrData() { }
253 ~wxGridRowOrColAttrData();
254
255 void SetAttr(wxGridCellAttr *attr, int rowOrCol);
256 wxGridCellAttr *GetAttr(int rowOrCol) const;
257 void UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols );
258
259 private:
260 wxArrayInt m_rowsOrCols;
261 wxArrayAttrs m_attrs;
262 };
263
264 // NB: this is just a wrapper around 3 objects: one which stores cell
265 // attributes, and 2 others for row/col ones
266 class WXDLLEXPORT wxGridCellAttrProviderData
267 {
268 public:
269 wxGridCellAttrData m_cellAttrs;
270 wxGridRowOrColAttrData m_rowAttrs,
271 m_colAttrs;
272 };
273
274
275 // ----------------------------------------------------------------------------
276 // data structures used for the data type registry
277 // ----------------------------------------------------------------------------
278
279 struct wxGridDataTypeInfo
280 {
281 wxGridDataTypeInfo(const wxString& typeName,
282 wxGridCellRenderer* renderer,
283 wxGridCellEditor* editor)
284 : m_typeName(typeName), m_renderer(renderer), m_editor(editor)
285 { }
286
287 ~wxGridDataTypeInfo()
288 {
289 wxSafeDecRef(m_renderer);
290 wxSafeDecRef(m_editor);
291 }
292
293 wxString m_typeName;
294 wxGridCellRenderer* m_renderer;
295 wxGridCellEditor* m_editor;
296 };
297
298
299 WX_DEFINE_EXPORTED_ARRAY(wxGridDataTypeInfo*, wxGridDataTypeInfoArray);
300
301
302 class WXDLLEXPORT wxGridTypeRegistry
303 {
304 public:
305 wxGridTypeRegistry() {}
306 ~wxGridTypeRegistry();
307
308 void RegisterDataType(const wxString& typeName,
309 wxGridCellRenderer* renderer,
310 wxGridCellEditor* editor);
311
312 // find one of already registered data types
313 int FindRegisteredDataType(const wxString& typeName);
314
315 // try to FindRegisteredDataType(), if this fails and typeName is one of
316 // standard typenames, register it and return its index
317 int FindDataType(const wxString& typeName);
318
319 // try to FindDataType(), if it fails see if it is not one of already
320 // registered data types with some params in which case clone the
321 // registered data type and set params for it
322 int FindOrCloneDataType(const wxString& typeName);
323
324 wxGridCellRenderer* GetRenderer(int index);
325 wxGridCellEditor* GetEditor(int index);
326
327 private:
328 wxGridDataTypeInfoArray m_typeinfo;
329 };
330
331 // ----------------------------------------------------------------------------
332 // conditional compilation
333 // ----------------------------------------------------------------------------
334
335 #ifndef WXGRID_DRAW_LINES
336 #define WXGRID_DRAW_LINES 1
337 #endif
338
339 // ----------------------------------------------------------------------------
340 // globals
341 // ----------------------------------------------------------------------------
342
343 //#define DEBUG_ATTR_CACHE
344 #ifdef DEBUG_ATTR_CACHE
345 static size_t gs_nAttrCacheHits = 0;
346 static size_t gs_nAttrCacheMisses = 0;
347 #endif // DEBUG_ATTR_CACHE
348
349 // ----------------------------------------------------------------------------
350 // constants
351 // ----------------------------------------------------------------------------
352
353 wxGridCellCoords wxGridNoCellCoords( -1, -1 );
354 wxRect wxGridNoCellRect( -1, -1, -1, -1 );
355
356 // scroll line size
357 // TODO: fixed so far - make configurable later (and also different for x/y)
358 static const size_t GRID_SCROLL_LINE = 10;
359
360 // the size of hash tables used a bit everywhere (the max number of elements
361 // in these hash tables is the number of rows/columns)
362 static const int GRID_HASH_SIZE = 100;
363
364 // ============================================================================
365 // implementation
366 // ============================================================================
367
368 // ----------------------------------------------------------------------------
369 // wxGridCellEditor
370 // ----------------------------------------------------------------------------
371
372 wxGridCellEditor::wxGridCellEditor()
373 {
374 m_control = NULL;
375 }
376
377
378 wxGridCellEditor::~wxGridCellEditor()
379 {
380 Destroy();
381 }
382
383 void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
384 wxWindowID WXUNUSED(id),
385 wxEvtHandler* evtHandler)
386 {
387 if ( evtHandler )
388 m_control->PushEventHandler(evtHandler);
389 }
390
391 void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
392 wxGridCellAttr *attr)
393 {
394 // erase the background because we might not fill the cell
395 wxClientDC dc(m_control->GetParent());
396 dc.SetPen(*wxTRANSPARENT_PEN);
397 dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
398 dc.DrawRectangle(rectCell);
399
400 // redraw the control we just painted over
401 m_control->Refresh();
402 }
403
404 void wxGridCellEditor::Destroy()
405 {
406 if (m_control)
407 {
408 m_control->PopEventHandler(TRUE /* delete it*/);
409
410 m_control->Destroy();
411 m_control = NULL;
412 }
413 }
414
415 void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
416 {
417 wxASSERT_MSG(m_control,
418 wxT("The wxGridCellEditor must be Created first!"));
419 m_control->Show(show);
420
421 if ( show )
422 {
423 // set the colours/fonts if we have any
424 if ( attr )
425 {
426 m_colFgOld = m_control->GetForegroundColour();
427 m_control->SetForegroundColour(attr->GetTextColour());
428
429 m_colBgOld = m_control->GetBackgroundColour();
430 m_control->SetBackgroundColour(attr->GetBackgroundColour());
431
432 m_fontOld = m_control->GetFont();
433 m_control->SetFont(attr->GetFont());
434
435 // can't do anything more in the base class version, the other
436 // attributes may only be used by the derived classes
437 }
438 }
439 else
440 {
441 // restore the standard colours fonts
442 if ( m_colFgOld.Ok() )
443 {
444 m_control->SetForegroundColour(m_colFgOld);
445 m_colFgOld = wxNullColour;
446 }
447
448 if ( m_colBgOld.Ok() )
449 {
450 m_control->SetBackgroundColour(m_colBgOld);
451 m_colBgOld = wxNullColour;
452 }
453
454 if ( m_fontOld.Ok() )
455 {
456 m_control->SetFont(m_fontOld);
457 m_fontOld = wxNullFont;
458 }
459 }
460 }
461
462 void wxGridCellEditor::SetSize(const wxRect& rect)
463 {
464 wxASSERT_MSG(m_control,
465 wxT("The wxGridCellEditor must be Created first!"));
466 m_control->SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
467 }
468
469 void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
470 {
471 event.Skip();
472 }
473
474 bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event)
475 {
476 // accept the simple key presses, not anything with Ctrl/Alt/Meta
477 return !event.HasModifiers();
478 }
479
480 void wxGridCellEditor::StartingKey(wxKeyEvent& event)
481 {
482 event.Skip();
483 }
484
485 void wxGridCellEditor::StartingClick()
486 {
487 }
488
489 // ----------------------------------------------------------------------------
490 // wxGridCellTextEditor
491 // ----------------------------------------------------------------------------
492
493 wxGridCellTextEditor::wxGridCellTextEditor()
494 {
495 m_maxChars = 0;
496 }
497
498 void wxGridCellTextEditor::Create(wxWindow* parent,
499 wxWindowID id,
500 wxEvtHandler* evtHandler)
501 {
502 m_control = new wxTextCtrl(parent, id, wxEmptyString,
503 wxDefaultPosition, wxDefaultSize
504 #if defined(__WXMSW__)
505 , wxTE_MULTILINE | wxTE_NO_VSCROLL | wxTE_AUTO_SCROLL
506 #endif
507 );
508
509 // TODO: use m_maxChars
510
511 wxGridCellEditor::Create(parent, id, evtHandler);
512 }
513
514 void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell),
515 wxGridCellAttr * WXUNUSED(attr))
516 {
517 // as we fill the entire client area, don't do anything here to minimize
518 // flicker
519 }
520
521 void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
522 {
523 wxRect rect(rectOrig);
524
525 // Make the edit control large enough to allow for internal
526 // margins
527 //
528 // TODO: remove this if the text ctrl sizing is improved esp. for
529 // unix
530 //
531 #if defined(__WXGTK__)
532 if (rect.x != 0)
533 {
534 rect.x += 1;
535 rect.y += 1;
536 rect.width -= 1;
537 rect.height -= 1;
538 }
539 #else // !GTK
540 int extra_x = ( rect.x > 2 )? 2 : 1;
541 int extra_y = ( rect.y > 2 )? 2 : 1;
542 #if defined(__WXMOTIF__)
543 extra_x *= 2;
544 extra_y *= 2;
545 #endif
546 rect.SetLeft( wxMax(0, rect.x - extra_x) );
547 rect.SetTop( wxMax(0, rect.y - extra_y) );
548 rect.SetRight( rect.GetRight() + 2*extra_x );
549 rect.SetBottom( rect.GetBottom() + 2*extra_y );
550 #endif // GTK/!GTK
551
552 wxGridCellEditor::SetSize(rect);
553 }
554
555 void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid)
556 {
557 wxASSERT_MSG(m_control,
558 wxT("The wxGridCellEditor must be Created first!"));
559
560 m_startValue = grid->GetTable()->GetValue(row, col);
561
562 DoBeginEdit(m_startValue);
563 }
564
565 void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
566 {
567 Text()->SetValue(startValue);
568 Text()->SetInsertionPointEnd();
569 Text()->SetFocus();
570 }
571
572 bool wxGridCellTextEditor::EndEdit(int row, int col,
573 wxGrid* grid)
574 {
575 wxASSERT_MSG(m_control,
576 wxT("The wxGridCellEditor must be Created first!"));
577
578 bool changed = FALSE;
579 wxString value = Text()->GetValue();
580 if (value != m_startValue)
581 changed = TRUE;
582
583 if (changed)
584 grid->GetTable()->SetValue(row, col, value);
585
586 m_startValue = wxEmptyString;
587 Text()->SetValue(m_startValue);
588
589 return changed;
590 }
591
592
593 void wxGridCellTextEditor::Reset()
594 {
595 wxASSERT_MSG(m_control,
596 wxT("The wxGridCellEditor must be Created first!"));
597
598 DoReset(m_startValue);
599 }
600
601 void wxGridCellTextEditor::DoReset(const wxString& startValue)
602 {
603 Text()->SetValue(startValue);
604 Text()->SetInsertionPointEnd();
605 }
606
607 bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event)
608 {
609 if ( wxGridCellEditor::IsAcceptedKey(event) )
610 {
611 int keycode = event.GetKeyCode();
612 switch ( keycode )
613 {
614 case WXK_NUMPAD0:
615 case WXK_NUMPAD1:
616 case WXK_NUMPAD2:
617 case WXK_NUMPAD3:
618 case WXK_NUMPAD4:
619 case WXK_NUMPAD5:
620 case WXK_NUMPAD6:
621 case WXK_NUMPAD7:
622 case WXK_NUMPAD8:
623 case WXK_NUMPAD9:
624 case WXK_MULTIPLY:
625 case WXK_NUMPAD_MULTIPLY:
626 case WXK_ADD:
627 case WXK_NUMPAD_ADD:
628 case WXK_SUBTRACT:
629 case WXK_NUMPAD_SUBTRACT:
630 case WXK_DECIMAL:
631 case WXK_NUMPAD_DECIMAL:
632 case WXK_DIVIDE:
633 case WXK_NUMPAD_DIVIDE:
634 return TRUE;
635
636 default:
637 // accept 8 bit chars too if isprint() agrees
638 if ( (keycode < 255) && (isprint(keycode)) )
639 return TRUE;
640 }
641 }
642
643 return FALSE;
644 }
645
646 void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
647 {
648 // we don't check for !HasModifiers() because IsAcceptedKey() did it
649
650 // insert the key in the control
651 wxChar ch;
652 int keycode = event.GetKeyCode();
653 switch ( keycode )
654 {
655 case WXK_NUMPAD0:
656 case WXK_NUMPAD1:
657 case WXK_NUMPAD2:
658 case WXK_NUMPAD3:
659 case WXK_NUMPAD4:
660 case WXK_NUMPAD5:
661 case WXK_NUMPAD6:
662 case WXK_NUMPAD7:
663 case WXK_NUMPAD8:
664 case WXK_NUMPAD9:
665 ch = _T('0') + keycode - WXK_NUMPAD0;
666 break;
667
668 case WXK_MULTIPLY:
669 case WXK_NUMPAD_MULTIPLY:
670 ch = _T('*');
671 break;
672
673 case WXK_ADD:
674 case WXK_NUMPAD_ADD:
675 ch = _T('+');
676 break;
677
678 case WXK_SUBTRACT:
679 case WXK_NUMPAD_SUBTRACT:
680 ch = _T('-');
681 break;
682
683 case WXK_DECIMAL:
684 case WXK_NUMPAD_DECIMAL:
685 ch = _T('.');
686 break;
687
688 case WXK_DIVIDE:
689 case WXK_NUMPAD_DIVIDE:
690 ch = _T('/');
691 break;
692
693 default:
694 if ( keycode < 256 && keycode >= 0 && isprint(keycode) )
695 {
696 // FIXME this is not going to work for non letters...
697 if ( !event.ShiftDown() )
698 {
699 keycode = tolower(keycode);
700 }
701
702 ch = (wxChar)keycode;
703 }
704 else
705 {
706 ch = _T('\0');
707 }
708 }
709
710 if ( ch )
711 {
712 Text()->AppendText(ch);
713 }
714 else
715 {
716 event.Skip();
717 }
718 }
719
720 void wxGridCellTextEditor::HandleReturn( wxKeyEvent&
721 WXUNUSED_GTK(WXUNUSED_MOTIF(event)) )
722 {
723 #if defined(__WXMOTIF__) || defined(__WXGTK__)
724 // wxMotif needs a little extra help...
725 size_t pos = (size_t)( Text()->GetInsertionPoint() );
726 wxString s( Text()->GetValue() );
727 s = s.Left(pos) + "\n" + s.Mid(pos);
728 Text()->SetValue(s);
729 Text()->SetInsertionPoint( pos );
730 #else
731 // the other ports can handle a Return key press
732 //
733 event.Skip();
734 #endif
735 }
736
737 void wxGridCellTextEditor::SetParameters(const wxString& params)
738 {
739 if ( !params )
740 {
741 // reset to default
742 m_maxChars = 0;
743 }
744 else
745 {
746 long tmp;
747 if ( !params.ToLong(&tmp) )
748 {
749 wxLogDebug(_T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str());
750 }
751 else
752 {
753 m_maxChars = (size_t)tmp;
754 }
755 }
756 }
757
758 // ----------------------------------------------------------------------------
759 // wxGridCellNumberEditor
760 // ----------------------------------------------------------------------------
761
762 wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max)
763 {
764 m_min = min;
765 m_max = max;
766 }
767
768 void wxGridCellNumberEditor::Create(wxWindow* parent,
769 wxWindowID id,
770 wxEvtHandler* evtHandler)
771 {
772 if ( HasRange() )
773 {
774 // create a spin ctrl
775 m_control = new wxSpinCtrl(parent, -1, wxEmptyString,
776 wxDefaultPosition, wxDefaultSize,
777 wxSP_ARROW_KEYS,
778 m_min, m_max);
779
780 wxGridCellEditor::Create(parent, id, evtHandler);
781 }
782 else
783 {
784 // just a text control
785 wxGridCellTextEditor::Create(parent, id, evtHandler);
786
787 #if wxUSE_VALIDATORS
788 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
789 #endif // wxUSE_VALIDATORS
790 }
791 }
792
793 void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
794 {
795 // first get the value
796 wxGridTableBase *table = grid->GetTable();
797 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
798 {
799 m_valueOld = table->GetValueAsLong(row, col);
800 }
801 else
802 {
803 wxString sValue = table->GetValue(row, col);
804 if (! sValue.ToLong(&m_valueOld))
805 {
806 wxFAIL_MSG( _T("this cell doesn't have numeric value") );
807 return;
808 }
809 }
810
811 if ( HasRange() )
812 {
813 Spin()->SetValue((int)m_valueOld);
814 Spin()->SetFocus();
815 }
816 else
817 {
818 DoBeginEdit(GetString());
819 }
820 }
821
822 bool wxGridCellNumberEditor::EndEdit(int row, int col,
823 wxGrid* grid)
824 {
825 bool changed;
826 long value;
827
828 if ( HasRange() )
829 {
830 value = Spin()->GetValue();
831 changed = value != m_valueOld;
832 }
833 else
834 {
835 changed = Text()->GetValue().ToLong(&value) && (value != m_valueOld);
836 }
837
838 if ( changed )
839 {
840 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
841 grid->GetTable()->SetValueAsLong(row, col, value);
842 else
843 grid->GetTable()->SetValue(row, col, wxString::Format(wxT("%ld"), value));
844 }
845
846 return changed;
847 }
848
849 void wxGridCellNumberEditor::Reset()
850 {
851 if ( HasRange() )
852 {
853 Spin()->SetValue((int)m_valueOld);
854 }
855 else
856 {
857 DoReset(GetString());
858 }
859 }
860
861 bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent& event)
862 {
863 if ( wxGridCellEditor::IsAcceptedKey(event) )
864 {
865 int keycode = event.GetKeyCode();
866 switch ( keycode )
867 {
868 case WXK_NUMPAD0:
869 case WXK_NUMPAD1:
870 case WXK_NUMPAD2:
871 case WXK_NUMPAD3:
872 case WXK_NUMPAD4:
873 case WXK_NUMPAD5:
874 case WXK_NUMPAD6:
875 case WXK_NUMPAD7:
876 case WXK_NUMPAD8:
877 case WXK_NUMPAD9:
878 case WXK_ADD:
879 case WXK_NUMPAD_ADD:
880 case WXK_SUBTRACT:
881 case WXK_NUMPAD_SUBTRACT:
882 case WXK_UP:
883 case WXK_DOWN:
884 return TRUE;
885
886 default:
887 if ( (keycode < 128) && isdigit(keycode) )
888 return TRUE;
889 }
890 }
891
892 return FALSE;
893 }
894
895 void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event)
896 {
897 if ( !HasRange() )
898 {
899 int keycode = (int) event.KeyCode();
900 if ( isdigit(keycode) || keycode == '+' || keycode == '-' )
901 {
902 wxGridCellTextEditor::StartingKey(event);
903
904 // skip Skip() below
905 return;
906 }
907 }
908
909 event.Skip();
910 }
911
912 void wxGridCellNumberEditor::SetParameters(const wxString& params)
913 {
914 if ( !params )
915 {
916 // reset to default
917 m_min =
918 m_max = -1;
919 }
920 else
921 {
922 long tmp;
923 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
924 {
925 m_min = (int)tmp;
926
927 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
928 {
929 m_max = (int)tmp;
930
931 // skip the error message below
932 return;
933 }
934 }
935
936 wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str());
937 }
938 }
939
940 // ----------------------------------------------------------------------------
941 // wxGridCellFloatEditor
942 // ----------------------------------------------------------------------------
943
944 wxGridCellFloatEditor::wxGridCellFloatEditor(int width, int precision)
945 {
946 m_width = width;
947 m_precision = precision;
948 }
949
950 void wxGridCellFloatEditor::Create(wxWindow* parent,
951 wxWindowID id,
952 wxEvtHandler* evtHandler)
953 {
954 wxGridCellTextEditor::Create(parent, id, evtHandler);
955
956 #if wxUSE_VALIDATORS
957 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
958 #endif // wxUSE_VALIDATORS
959 }
960
961 void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid)
962 {
963 // first get the value
964 wxGridTableBase *table = grid->GetTable();
965 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
966 {
967 m_valueOld = table->GetValueAsDouble(row, col);
968 }
969 else
970 {
971 wxString sValue = table->GetValue(row, col);
972 if (! sValue.ToDouble(&m_valueOld))
973 {
974 wxFAIL_MSG( _T("this cell doesn't have float value") );
975 return;
976 }
977 }
978
979 DoBeginEdit(GetString());
980 }
981
982 bool wxGridCellFloatEditor::EndEdit(int row, int col,
983 wxGrid* grid)
984 {
985 double value;
986 if ( Text()->GetValue().ToDouble(&value) && (value != m_valueOld) )
987 {
988 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT))
989 grid->GetTable()->SetValueAsDouble(row, col, value);
990 else
991 grid->GetTable()->SetValue(row, col, wxString::Format(wxT("%f"), value));
992
993 return TRUE;
994 }
995 else
996 {
997 return FALSE;
998 }
999 }
1000
1001 void wxGridCellFloatEditor::Reset()
1002 {
1003 DoReset(GetString());
1004 }
1005
1006 void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
1007 {
1008 int keycode = (int)event.KeyCode();
1009 if ( isdigit(keycode) ||
1010 keycode == '+' || keycode == '-' || keycode == '.' )
1011 {
1012 wxGridCellTextEditor::StartingKey(event);
1013
1014 // skip Skip() below
1015 return;
1016 }
1017
1018 event.Skip();
1019 }
1020
1021 void wxGridCellFloatEditor::SetParameters(const wxString& params)
1022 {
1023 if ( !params )
1024 {
1025 // reset to default
1026 m_width =
1027 m_precision = -1;
1028 }
1029 else
1030 {
1031 long tmp;
1032 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
1033 {
1034 m_width = (int)tmp;
1035
1036 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
1037 {
1038 m_precision = (int)tmp;
1039
1040 // skip the error message below
1041 return;
1042 }
1043 }
1044
1045 wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params.c_str());
1046 }
1047 }
1048
1049 wxString wxGridCellFloatEditor::GetString() const
1050 {
1051 wxString fmt;
1052 if ( m_width == -1 )
1053 {
1054 // default width/precision
1055 fmt = _T("%g");
1056 }
1057 else if ( m_precision == -1 )
1058 {
1059 // default precision
1060 fmt.Printf(_T("%%%d.g"), m_width);
1061 }
1062 else
1063 {
1064 fmt.Printf(_T("%%%d.%dg"), m_width, m_precision);
1065 }
1066
1067 return wxString::Format(fmt, m_valueOld);
1068 }
1069
1070 bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event)
1071 {
1072 if ( wxGridCellEditor::IsAcceptedKey(event) )
1073 {
1074 int keycode = event.GetKeyCode();
1075 switch ( keycode )
1076 {
1077 case WXK_NUMPAD0:
1078 case WXK_NUMPAD1:
1079 case WXK_NUMPAD2:
1080 case WXK_NUMPAD3:
1081 case WXK_NUMPAD4:
1082 case WXK_NUMPAD5:
1083 case WXK_NUMPAD6:
1084 case WXK_NUMPAD7:
1085 case WXK_NUMPAD8:
1086 case WXK_NUMPAD9:
1087 case WXK_ADD:
1088 case WXK_NUMPAD_ADD:
1089 case WXK_SUBTRACT:
1090 case WXK_NUMPAD_SUBTRACT:
1091 case WXK_DECIMAL:
1092 case WXK_NUMPAD_DECIMAL:
1093 return TRUE;
1094
1095 default:
1096 // additionally accept 'e' as in '1e+6'
1097 if ( (keycode < 128) &&
1098 (isdigit(keycode) || tolower(keycode) == 'e') )
1099 return TRUE;
1100 }
1101 }
1102
1103 return FALSE;
1104 }
1105
1106 // ----------------------------------------------------------------------------
1107 // wxGridCellBoolEditor
1108 // ----------------------------------------------------------------------------
1109
1110 void wxGridCellBoolEditor::Create(wxWindow* parent,
1111 wxWindowID id,
1112 wxEvtHandler* evtHandler)
1113 {
1114 m_control = new wxCheckBox(parent, id, wxEmptyString,
1115 wxDefaultPosition, wxDefaultSize,
1116 wxNO_BORDER);
1117
1118 wxGridCellEditor::Create(parent, id, evtHandler);
1119 }
1120
1121 void wxGridCellBoolEditor::SetSize(const wxRect& r)
1122 {
1123 bool resize = FALSE;
1124 wxSize size = m_control->GetSize();
1125 wxCoord minSize = wxMin(r.width, r.height);
1126
1127 // check if the checkbox is not too big/small for this cell
1128 wxSize sizeBest = m_control->GetBestSize();
1129 if ( !(size == sizeBest) )
1130 {
1131 // reset to default size if it had been made smaller
1132 size = sizeBest;
1133
1134 resize = TRUE;
1135 }
1136
1137 if ( size.x >= minSize || size.y >= minSize )
1138 {
1139 // leave 1 pixel margin
1140 size.x = size.y = minSize - 2;
1141
1142 resize = TRUE;
1143 }
1144
1145 if ( resize )
1146 {
1147 m_control->SetSize(size);
1148 }
1149
1150 // position it in the centre of the rectangle (TODO: support alignment?)
1151
1152 #if defined(__WXGTK__) || defined (__WXMOTIF__)
1153 // the checkbox without label still has some space to the right in wxGTK,
1154 // so shift it to the right
1155 size.x -= 8;
1156 #elif defined(__WXMSW__)
1157 // here too, but in other way
1158 size.x += 1;
1159 size.y -= 2;
1160 #endif
1161
1162 m_control->Move(r.x + r.width/2 - size.x/2, r.y + r.height/2 - size.y/2);
1163 }
1164
1165 void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
1166 {
1167 m_control->Show(show);
1168
1169 if ( show )
1170 {
1171 wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
1172 CBox()->SetBackgroundColour(colBg);
1173 }
1174 }
1175
1176 void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid)
1177 {
1178 wxASSERT_MSG(m_control,
1179 wxT("The wxGridCellEditor must be Created first!"));
1180
1181 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
1182 m_startValue = grid->GetTable()->GetValueAsBool(row, col);
1183 else
1184 m_startValue = !!grid->GetTable()->GetValue(row, col);
1185 CBox()->SetValue(m_startValue);
1186 CBox()->SetFocus();
1187 }
1188
1189 bool wxGridCellBoolEditor::EndEdit(int row, int col,
1190 wxGrid* grid)
1191 {
1192 wxASSERT_MSG(m_control,
1193 wxT("The wxGridCellEditor must be Created first!"));
1194
1195 bool changed = FALSE;
1196 bool value = CBox()->GetValue();
1197 if ( value != m_startValue )
1198 changed = TRUE;
1199
1200 if ( changed )
1201 {
1202 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
1203 grid->GetTable()->SetValueAsBool(row, col, value);
1204 else
1205 grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString);
1206 }
1207
1208 return changed;
1209 }
1210
1211 void wxGridCellBoolEditor::Reset()
1212 {
1213 wxASSERT_MSG(m_control,
1214 wxT("The wxGridCellEditor must be Created first!"));
1215
1216 CBox()->SetValue(m_startValue);
1217 }
1218
1219 void wxGridCellBoolEditor::StartingClick()
1220 {
1221 CBox()->SetValue(!CBox()->GetValue());
1222 }
1223
1224 bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent& event)
1225 {
1226 if ( wxGridCellEditor::IsAcceptedKey(event) )
1227 {
1228 int keycode = event.GetKeyCode();
1229 switch ( keycode )
1230 {
1231 case WXK_MULTIPLY:
1232 case WXK_NUMPAD_MULTIPLY:
1233 case WXK_ADD:
1234 case WXK_NUMPAD_ADD:
1235 case WXK_SUBTRACT:
1236 case WXK_NUMPAD_SUBTRACT:
1237 case WXK_SPACE:
1238 case '+':
1239 case '-':
1240 return TRUE;
1241 }
1242 }
1243
1244 return FALSE;
1245 }
1246
1247 // ----------------------------------------------------------------------------
1248 // wxGridCellChoiceEditor
1249 // ----------------------------------------------------------------------------
1250
1251 wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count,
1252 const wxString choices[],
1253 bool allowOthers)
1254 : m_allowOthers(allowOthers)
1255 {
1256 if ( count )
1257 {
1258 m_choices.Alloc(count);
1259 for ( size_t n = 0; n < count; n++ )
1260 {
1261 m_choices.Add(choices[n]);
1262 }
1263 }
1264 }
1265
1266 wxGridCellEditor *wxGridCellChoiceEditor::Clone() const
1267 {
1268 wxGridCellChoiceEditor *editor = new wxGridCellChoiceEditor;
1269 editor->m_allowOthers = m_allowOthers;
1270 editor->m_choices = m_choices;
1271
1272 return editor;
1273 }
1274
1275 void wxGridCellChoiceEditor::Create(wxWindow* parent,
1276 wxWindowID id,
1277 wxEvtHandler* evtHandler)
1278 {
1279 size_t count = m_choices.GetCount();
1280 wxString *choices = new wxString[count];
1281 for ( size_t n = 0; n < count; n++ )
1282 {
1283 choices[n] = m_choices[n];
1284 }
1285
1286 m_control = new wxComboBox(parent, id, wxEmptyString,
1287 wxDefaultPosition, wxDefaultSize,
1288 count, choices,
1289 m_allowOthers ? 0 : wxCB_READONLY);
1290
1291 delete [] choices;
1292
1293 wxGridCellEditor::Create(parent, id, evtHandler);
1294 }
1295
1296 void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
1297 wxGridCellAttr * attr)
1298 {
1299 // as we fill the entire client area, don't do anything here to minimize
1300 // flicker
1301
1302 // TODO: It doesn't actually fill the client area since the height of a
1303 // combo always defaults to the standard... Until someone has time to
1304 // figure out the right rectangle to paint, just do it the normal way...
1305 wxGridCellEditor::PaintBackground(rectCell, attr);
1306 }
1307
1308 void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
1309 {
1310 wxASSERT_MSG(m_control,
1311 wxT("The wxGridCellEditor must be Created first!"));
1312
1313 m_startValue = grid->GetTable()->GetValue(row, col);
1314
1315 Combo()->SetValue(m_startValue);
1316 size_t count = m_choices.GetCount();
1317 for (size_t i=0; i<count; i++)
1318 {
1319 if (m_startValue == m_choices[i])
1320 {
1321 Combo()->SetSelection(i);
1322 break;
1323 }
1324 }
1325 Combo()->SetInsertionPointEnd();
1326 Combo()->SetFocus();
1327 }
1328
1329 bool wxGridCellChoiceEditor::EndEdit(int row, int col,
1330 wxGrid* grid)
1331 {
1332 wxString value = Combo()->GetValue();
1333 bool changed = value != m_startValue;
1334
1335 if ( changed )
1336 grid->GetTable()->SetValue(row, col, value);
1337
1338 m_startValue = wxEmptyString;
1339 Combo()->SetValue(m_startValue);
1340
1341 return changed;
1342 }
1343
1344 void wxGridCellChoiceEditor::Reset()
1345 {
1346 Combo()->SetValue(m_startValue);
1347 Combo()->SetInsertionPointEnd();
1348 }
1349
1350 void wxGridCellChoiceEditor::SetParameters(const wxString& params)
1351 {
1352 if ( !params )
1353 {
1354 // what can we do?
1355 return;
1356 }
1357
1358 m_choices.Empty();
1359
1360 wxStringTokenizer tk(params, _T(','));
1361 while ( tk.HasMoreTokens() )
1362 {
1363 m_choices.Add(tk.GetNextToken());
1364 }
1365 }
1366
1367 // ----------------------------------------------------------------------------
1368 // wxGridCellEditorEvtHandler
1369 // ----------------------------------------------------------------------------
1370
1371 void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
1372 {
1373 switch ( event.KeyCode() )
1374 {
1375 case WXK_ESCAPE:
1376 m_editor->Reset();
1377 m_grid->DisableCellEditControl();
1378 break;
1379
1380 case WXK_TAB:
1381 event.Skip( m_grid->ProcessEvent( event ) );
1382 break;
1383
1384 case WXK_RETURN:
1385 if (!m_grid->ProcessEvent(event))
1386 m_editor->HandleReturn(event);
1387 break;
1388
1389
1390 default:
1391 event.Skip();
1392 }
1393 }
1394
1395 void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event)
1396 {
1397 switch ( event.KeyCode() )
1398 {
1399 case WXK_ESCAPE:
1400 case WXK_TAB:
1401 case WXK_RETURN:
1402 break;
1403
1404 default:
1405 event.Skip();
1406 }
1407 }
1408
1409 // ----------------------------------------------------------------------------
1410 // wxGridCellWorker is an (almost) empty common base class for
1411 // wxGridCellRenderer and wxGridCellEditor managing ref counting
1412 // ----------------------------------------------------------------------------
1413
1414 void wxGridCellWorker::SetParameters(const wxString& WXUNUSED(params))
1415 {
1416 // nothing to do
1417 }
1418
1419 wxGridCellWorker::~wxGridCellWorker()
1420 {
1421 }
1422
1423 // ============================================================================
1424 // renderer classes
1425 // ============================================================================
1426
1427 // ----------------------------------------------------------------------------
1428 // wxGridCellRenderer
1429 // ----------------------------------------------------------------------------
1430
1431 void wxGridCellRenderer::Draw(wxGrid& grid,
1432 wxGridCellAttr& attr,
1433 wxDC& dc,
1434 const wxRect& rect,
1435 int WXUNUSED(row), int WXUNUSED(col),
1436 bool isSelected)
1437 {
1438 dc.SetBackgroundMode( wxSOLID );
1439
1440 if ( isSelected )
1441 {
1442 dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) );
1443 }
1444 else
1445 {
1446 dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) );
1447 }
1448
1449 dc.SetPen( *wxTRANSPARENT_PEN );
1450 dc.DrawRectangle(rect);
1451 }
1452
1453 // ----------------------------------------------------------------------------
1454 // wxGridCellStringRenderer
1455 // ----------------------------------------------------------------------------
1456
1457 void wxGridCellStringRenderer::SetTextColoursAndFont(wxGrid& grid,
1458 wxGridCellAttr& attr,
1459 wxDC& dc,
1460 bool isSelected)
1461 {
1462 dc.SetBackgroundMode( wxTRANSPARENT );
1463
1464 // TODO some special colours for attr.IsReadOnly() case?
1465
1466 if ( isSelected )
1467 {
1468 dc.SetTextBackground( grid.GetSelectionBackground() );
1469 dc.SetTextForeground( grid.GetSelectionForeground() );
1470 }
1471 else
1472 {
1473 dc.SetTextBackground( attr.GetBackgroundColour() );
1474 dc.SetTextForeground( attr.GetTextColour() );
1475 }
1476
1477 dc.SetFont( attr.GetFont() );
1478 }
1479
1480 wxSize wxGridCellStringRenderer::DoGetBestSize(wxGridCellAttr& attr,
1481 wxDC& dc,
1482 const wxString& text)
1483 {
1484 wxCoord x = 0, y = 0, max_x = 0;
1485 dc.SetFont(attr.GetFont());
1486 wxStringTokenizer tk(text, _T('\n'));
1487 while ( tk.HasMoreTokens() )
1488 {
1489 dc.GetTextExtent(tk.GetNextToken(), &x, &y);
1490 max_x = wxMax(max_x, x);
1491 }
1492
1493 y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines.
1494
1495 return wxSize(max_x, y);
1496 }
1497
1498 wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
1499 wxGridCellAttr& attr,
1500 wxDC& dc,
1501 int row, int col)
1502 {
1503 return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
1504 }
1505
1506 void wxGridCellStringRenderer::Draw(wxGrid& grid,
1507 wxGridCellAttr& attr,
1508 wxDC& dc,
1509 const wxRect& rectCell,
1510 int row, int col,
1511 bool isSelected)
1512 {
1513 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1514
1515 // now we only have to draw the text
1516 SetTextColoursAndFont(grid, attr, dc, isSelected);
1517
1518 int hAlign, vAlign;
1519 attr.GetAlignment(&hAlign, &vAlign);
1520
1521 wxRect rect = rectCell;
1522 rect.Inflate(-1);
1523
1524 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
1525 rect, hAlign, vAlign);
1526 }
1527
1528 // ----------------------------------------------------------------------------
1529 // wxGridCellNumberRenderer
1530 // ----------------------------------------------------------------------------
1531
1532 wxString wxGridCellNumberRenderer::GetString(wxGrid& grid, int row, int col)
1533 {
1534 wxGridTableBase *table = grid.GetTable();
1535 wxString text;
1536 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
1537 {
1538 text.Printf(_T("%ld"), table->GetValueAsLong(row, col));
1539 }
1540 else
1541 {
1542 text = table->GetValue(row, col);
1543 }
1544
1545 return text;
1546 }
1547
1548 void wxGridCellNumberRenderer::Draw(wxGrid& grid,
1549 wxGridCellAttr& attr,
1550 wxDC& dc,
1551 const wxRect& rectCell,
1552 int row, int col,
1553 bool isSelected)
1554 {
1555 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1556
1557 SetTextColoursAndFont(grid, attr, dc, isSelected);
1558
1559 // draw the text right aligned by default
1560 int hAlign, vAlign;
1561 attr.GetAlignment(&hAlign, &vAlign);
1562 hAlign = wxRIGHT;
1563
1564 wxRect rect = rectCell;
1565 rect.Inflate(-1);
1566
1567 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
1568 }
1569
1570 wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
1571 wxGridCellAttr& attr,
1572 wxDC& dc,
1573 int row, int col)
1574 {
1575 return DoGetBestSize(attr, dc, GetString(grid, row, col));
1576 }
1577
1578 // ----------------------------------------------------------------------------
1579 // wxGridCellFloatRenderer
1580 // ----------------------------------------------------------------------------
1581
1582 wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision)
1583 {
1584 SetWidth(width);
1585 SetPrecision(precision);
1586 }
1587
1588 wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
1589 {
1590 wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
1591 renderer->m_width = m_width;
1592 renderer->m_precision = m_precision;
1593 renderer->m_format = m_format;
1594
1595 return renderer;
1596 }
1597
1598 wxString wxGridCellFloatRenderer::GetString(wxGrid& grid, int row, int col)
1599 {
1600 wxGridTableBase *table = grid.GetTable();
1601
1602 bool hasDouble;
1603 double val;
1604 wxString text;
1605 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
1606 {
1607 val = table->GetValueAsDouble(row, col);
1608 hasDouble = TRUE;
1609 }
1610 else
1611 {
1612 text = table->GetValue(row, col);
1613 hasDouble = text.ToDouble(&val);
1614 }
1615
1616 if ( hasDouble )
1617 {
1618 if ( !m_format )
1619 {
1620 if ( m_width == -1 )
1621 {
1622 // default width/precision
1623 m_format = _T("%f");
1624 }
1625 else if ( m_precision == -1 )
1626 {
1627 // default precision
1628 m_format.Printf(_T("%%%d.f"), m_width);
1629 }
1630 else
1631 {
1632 m_format.Printf(_T("%%%d.%df"), m_width, m_precision);
1633 }
1634 }
1635
1636 text.Printf(m_format, val);
1637 }
1638 //else: text already contains the string
1639
1640 return text;
1641 }
1642
1643 void wxGridCellFloatRenderer::Draw(wxGrid& grid,
1644 wxGridCellAttr& attr,
1645 wxDC& dc,
1646 const wxRect& rectCell,
1647 int row, int col,
1648 bool isSelected)
1649 {
1650 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1651
1652 SetTextColoursAndFont(grid, attr, dc, isSelected);
1653
1654 // draw the text right aligned by default
1655 int hAlign, vAlign;
1656 attr.GetAlignment(&hAlign, &vAlign);
1657 hAlign = wxRIGHT;
1658
1659 wxRect rect = rectCell;
1660 rect.Inflate(-1);
1661
1662 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
1663 }
1664
1665 wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
1666 wxGridCellAttr& attr,
1667 wxDC& dc,
1668 int row, int col)
1669 {
1670 return DoGetBestSize(attr, dc, GetString(grid, row, col));
1671 }
1672
1673 void wxGridCellFloatRenderer::SetParameters(const wxString& params)
1674 {
1675 bool ok = TRUE;
1676
1677 if ( !params )
1678 {
1679 // reset to defaults
1680 SetWidth(-1);
1681 SetPrecision(-1);
1682 }
1683 else
1684 {
1685 wxString tmp = params.BeforeFirst(_T(','));
1686 if ( !!tmp )
1687 {
1688 long width;
1689 if ( !tmp.ToLong(&width) )
1690 {
1691 ok = FALSE;
1692 }
1693 else
1694 {
1695 SetWidth((int)width);
1696
1697 tmp = params.AfterFirst(_T(','));
1698 if ( !!tmp )
1699 {
1700 long precision;
1701 if ( !tmp.ToLong(&precision) )
1702 {
1703 ok = FALSE;
1704 }
1705 else
1706 {
1707 SetPrecision((int)precision);
1708 }
1709 }
1710 }
1711 }
1712
1713 if ( !ok )
1714 {
1715 wxLogDebug(_T("Invalid wxGridCellFloatRenderer parameter string '%s ignored"), params.c_str());
1716 }
1717 }
1718 }
1719
1720 // ----------------------------------------------------------------------------
1721 // wxGridCellBoolRenderer
1722 // ----------------------------------------------------------------------------
1723
1724 wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
1725
1726 // FIXME these checkbox size calculations are really ugly...
1727
1728 // between checkmark and box
1729 static const wxCoord wxGRID_CHECKMARK_MARGIN = 2;
1730
1731 wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
1732 wxGridCellAttr& WXUNUSED(attr),
1733 wxDC& WXUNUSED(dc),
1734 int WXUNUSED(row),
1735 int WXUNUSED(col))
1736 {
1737 // compute it only once (no locks for MT safeness in GUI thread...)
1738 if ( !ms_sizeCheckMark.x )
1739 {
1740 // get checkbox size
1741 wxCoord checkSize = 0;
1742 wxCheckBox *checkbox = new wxCheckBox(&grid, -1, wxEmptyString);
1743 wxSize size = checkbox->GetBestSize();
1744 checkSize = size.y + 2*wxGRID_CHECKMARK_MARGIN;
1745
1746 // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
1747 #if defined(__WXGTK__) || defined(__WXMOTIF__)
1748 checkSize -= size.y / 2;
1749 #endif
1750
1751 delete checkbox;
1752
1753 ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize;
1754 }
1755
1756 return ms_sizeCheckMark;
1757 }
1758
1759 void wxGridCellBoolRenderer::Draw(wxGrid& grid,
1760 wxGridCellAttr& attr,
1761 wxDC& dc,
1762 const wxRect& rect,
1763 int row, int col,
1764 bool isSelected)
1765 {
1766 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
1767
1768 // draw a check mark in the centre (ignoring alignment - TODO)
1769 wxSize size = GetBestSize(grid, attr, dc, row, col);
1770
1771 // don't draw outside the cell
1772 wxCoord minSize = wxMin(rect.width, rect.height);
1773 if ( size.x >= minSize || size.y >= minSize )
1774 {
1775 // and even leave (at least) 1 pixel margin
1776 size.x = size.y = minSize - 2;
1777 }
1778
1779 // draw a border around checkmark
1780 wxRect rectBorder;
1781 rectBorder.x = rect.x + rect.width/2 - size.x/2;
1782 rectBorder.y = rect.y + rect.height/2 - size.y/2;
1783 rectBorder.width = size.x;
1784 rectBorder.height = size.y;
1785
1786 bool value;
1787 if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
1788 value = grid.GetTable()->GetValueAsBool(row, col);
1789 else
1790 value = !!grid.GetTable()->GetValue(row, col);
1791
1792 if ( value )
1793 {
1794 wxRect rectMark = rectBorder;
1795 #ifdef __WXMSW__
1796 // MSW DrawCheckMark() is weird (and should probably be changed...)
1797 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN/2);
1798 rectMark.x++;
1799 rectMark.y++;
1800 #else // !MSW
1801 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN);
1802 #endif // MSW/!MSW
1803
1804 dc.SetTextForeground(attr.GetTextColour());
1805 dc.DrawCheckMark(rectMark);
1806 }
1807
1808 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1809 dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID));
1810 dc.DrawRectangle(rectBorder);
1811 }
1812
1813 // ----------------------------------------------------------------------------
1814 // wxGridCellAttr
1815 // ----------------------------------------------------------------------------
1816
1817 wxGridCellAttr *wxGridCellAttr::Clone() const
1818 {
1819 wxGridCellAttr *attr = new wxGridCellAttr;
1820 if ( HasTextColour() )
1821 attr->SetTextColour(GetTextColour());
1822 if ( HasBackgroundColour() )
1823 attr->SetBackgroundColour(GetBackgroundColour());
1824 if ( HasFont() )
1825 attr->SetFont(GetFont());
1826 if ( HasAlignment() )
1827 attr->SetAlignment(m_hAlign, m_vAlign);
1828
1829 if ( m_renderer )
1830 {
1831 attr->SetRenderer(m_renderer);
1832 m_renderer->IncRef();
1833 }
1834 if ( m_editor )
1835 {
1836 attr->SetEditor(m_editor);
1837 m_editor->IncRef();
1838 }
1839
1840 if ( IsReadOnly() )
1841 attr->SetReadOnly();
1842
1843 attr->SetDefAttr(m_defGridAttr);
1844
1845 return attr;
1846 }
1847
1848 const wxColour& wxGridCellAttr::GetTextColour() const
1849 {
1850 if (HasTextColour())
1851 {
1852 return m_colText;
1853 }
1854 else if (m_defGridAttr != this)
1855 {
1856 return m_defGridAttr->GetTextColour();
1857 }
1858 else
1859 {
1860 wxFAIL_MSG(wxT("Missing default cell attribute"));
1861 return wxNullColour;
1862 }
1863 }
1864
1865
1866 const wxColour& wxGridCellAttr::GetBackgroundColour() const
1867 {
1868 if (HasBackgroundColour())
1869 return m_colBack;
1870 else if (m_defGridAttr != this)
1871 return m_defGridAttr->GetBackgroundColour();
1872 else
1873 {
1874 wxFAIL_MSG(wxT("Missing default cell attribute"));
1875 return wxNullColour;
1876 }
1877 }
1878
1879
1880 const wxFont& wxGridCellAttr::GetFont() const
1881 {
1882 if (HasFont())
1883 return m_font;
1884 else if (m_defGridAttr != this)
1885 return m_defGridAttr->GetFont();
1886 else
1887 {
1888 wxFAIL_MSG(wxT("Missing default cell attribute"));
1889 return wxNullFont;
1890 }
1891 }
1892
1893
1894 void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
1895 {
1896 if (HasAlignment())
1897 {
1898 if ( hAlign ) *hAlign = m_hAlign;
1899 if ( vAlign ) *vAlign = m_vAlign;
1900 }
1901 else if (m_defGridAttr != this)
1902 m_defGridAttr->GetAlignment(hAlign, vAlign);
1903 else
1904 {
1905 wxFAIL_MSG(wxT("Missing default cell attribute"));
1906 }
1907 }
1908
1909
1910 // GetRenderer and GetEditor use a slightly different decision path about
1911 // which attribute to use. If a non-default attr object has one then it is
1912 // used, otherwise the default editor or renderer is fetched from the grid and
1913 // used. It should be the default for the data type of the cell. If it is
1914 // NULL (because the table has a type that the grid does not have in its
1915 // registry,) then the grid's default editor or renderer is used.
1916
1917 wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const
1918 {
1919 wxGridCellRenderer* renderer = NULL;
1920
1921 if ( m_defGridAttr != this || grid == NULL )
1922 {
1923 renderer = m_renderer; // use local attribute
1924 if ( renderer )
1925 renderer->IncRef();
1926 }
1927
1928 if ( !renderer && grid ) // get renderer for the data type
1929 {
1930 // GetDefaultRendererForCell() will do IncRef() for us
1931 renderer = grid->GetDefaultRendererForCell(row, col);
1932 }
1933
1934 if ( !renderer )
1935 {
1936 // if we still don't have one then use the grid default
1937 // (no need for IncRef() here neither)
1938 renderer = m_defGridAttr->GetRenderer(NULL,0,0);
1939 }
1940
1941 if ( !renderer)
1942 {
1943 wxFAIL_MSG(wxT("Missing default cell attribute"));
1944 }
1945
1946 return renderer;
1947 }
1948
1949 wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const
1950 {
1951 wxGridCellEditor* editor = NULL;
1952
1953 if ( m_defGridAttr != this || grid == NULL )
1954 {
1955 editor = m_editor; // use local attribute
1956 if ( editor )
1957 editor->IncRef();
1958 }
1959
1960 if ( !editor && grid ) // get renderer for the data type
1961 editor = grid->GetDefaultEditorForCell(row, col);
1962
1963 if ( !editor )
1964 // if we still don't have one then use the grid default
1965 editor = m_defGridAttr->GetEditor(NULL,0,0);
1966
1967 if ( !editor )
1968 {
1969 wxFAIL_MSG(wxT("Missing default cell attribute"));
1970 }
1971
1972 return editor;
1973 }
1974
1975 // ----------------------------------------------------------------------------
1976 // wxGridCellAttrData
1977 // ----------------------------------------------------------------------------
1978
1979 void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
1980 {
1981 int n = FindIndex(row, col);
1982 if ( n == wxNOT_FOUND )
1983 {
1984 // add the attribute
1985 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
1986 }
1987 else
1988 {
1989 if ( attr )
1990 {
1991 // change the attribute
1992 m_attrs[(size_t)n].attr = attr;
1993 }
1994 else
1995 {
1996 // remove this attribute
1997 m_attrs.RemoveAt((size_t)n);
1998 }
1999 }
2000 }
2001
2002 wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
2003 {
2004 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2005
2006 int n = FindIndex(row, col);
2007 if ( n != wxNOT_FOUND )
2008 {
2009 attr = m_attrs[(size_t)n].attr;
2010 attr->IncRef();
2011 }
2012
2013 return attr;
2014 }
2015
2016 void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows )
2017 {
2018 size_t count = m_attrs.GetCount();
2019 for ( size_t n = 0; n < count; n++ )
2020 {
2021 wxGridCellCoords& coords = m_attrs[n].coords;
2022 wxCoord row = coords.GetRow();
2023 if ((size_t)row >= pos)
2024 {
2025 if (numRows > 0)
2026 {
2027 // If rows inserted, include row counter where necessary
2028 coords.SetRow(row + numRows);
2029 }
2030 else if (numRows < 0)
2031 {
2032 // If rows deleted ...
2033 if ((size_t)row >= pos - numRows)
2034 {
2035 // ...either decrement row counter (if row still exists)...
2036 coords.SetRow(row + numRows);
2037 }
2038 else
2039 {
2040 // ...or remove the attribute
2041 m_attrs.RemoveAt((size_t)n);
2042 n--; count--;
2043 }
2044 }
2045 }
2046 }
2047 }
2048
2049 void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols )
2050 {
2051 size_t count = m_attrs.GetCount();
2052 for ( size_t n = 0; n < count; n++ )
2053 {
2054 wxGridCellCoords& coords = m_attrs[n].coords;
2055 wxCoord col = coords.GetCol();
2056 if ( (size_t)col >= pos )
2057 {
2058 if ( numCols > 0 )
2059 {
2060 // If rows inserted, include row counter where necessary
2061 coords.SetCol(col + numCols);
2062 }
2063 else if (numCols < 0)
2064 {
2065 // If rows deleted ...
2066 if ((size_t)col >= pos - numCols)
2067 {
2068 // ...either decrement row counter (if row still exists)...
2069 coords.SetCol(col + numCols);
2070 }
2071 else
2072 {
2073 // ...or remove the attribute
2074 m_attrs.RemoveAt((size_t)n);
2075 n--; count--;
2076 }
2077 }
2078 }
2079 }
2080 }
2081
2082 int wxGridCellAttrData::FindIndex(int row, int col) const
2083 {
2084 size_t count = m_attrs.GetCount();
2085 for ( size_t n = 0; n < count; n++ )
2086 {
2087 const wxGridCellCoords& coords = m_attrs[n].coords;
2088 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
2089 {
2090 return n;
2091 }
2092 }
2093
2094 return wxNOT_FOUND;
2095 }
2096
2097 // ----------------------------------------------------------------------------
2098 // wxGridRowOrColAttrData
2099 // ----------------------------------------------------------------------------
2100
2101 wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
2102 {
2103 size_t count = m_attrs.Count();
2104 for ( size_t n = 0; n < count; n++ )
2105 {
2106 m_attrs[n]->DecRef();
2107 }
2108 }
2109
2110 wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
2111 {
2112 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2113
2114 int n = m_rowsOrCols.Index(rowOrCol);
2115 if ( n != wxNOT_FOUND )
2116 {
2117 attr = m_attrs[(size_t)n];
2118 attr->IncRef();
2119 }
2120
2121 return attr;
2122 }
2123
2124 void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
2125 {
2126 int i = m_rowsOrCols.Index(rowOrCol);
2127 if ( i == wxNOT_FOUND )
2128 {
2129 // add the attribute
2130 m_rowsOrCols.Add(rowOrCol);
2131 m_attrs.Add(attr);
2132 }
2133 else
2134 {
2135 size_t n = (size_t)i;
2136 if ( attr )
2137 {
2138 // change the attribute
2139 m_attrs[n]->DecRef();
2140 m_attrs[n] = attr;
2141 }
2142 else
2143 {
2144 // remove this attribute
2145 m_attrs[n]->DecRef();
2146 m_rowsOrCols.RemoveAt(n);
2147 m_attrs.RemoveAt(n);
2148 }
2149 }
2150 }
2151
2152 void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols )
2153 {
2154 size_t count = m_attrs.GetCount();
2155 for ( size_t n = 0; n < count; n++ )
2156 {
2157 int & rowOrCol = m_rowsOrCols[n];
2158 if ( (size_t)rowOrCol >= pos )
2159 {
2160 if ( numRowsOrCols > 0 )
2161 {
2162 // If rows inserted, include row counter where necessary
2163 rowOrCol += numRowsOrCols;
2164 }
2165 else if ( numRowsOrCols < 0)
2166 {
2167 // If rows deleted, either decrement row counter (if row still exists)
2168 if ((size_t)rowOrCol >= pos - numRowsOrCols)
2169 rowOrCol += numRowsOrCols;
2170 else
2171 {
2172 m_rowsOrCols.RemoveAt((size_t)n);
2173 m_attrs.RemoveAt((size_t)n);
2174 n--; count--;
2175 }
2176 }
2177 }
2178 }
2179 }
2180
2181 // ----------------------------------------------------------------------------
2182 // wxGridCellAttrProvider
2183 // ----------------------------------------------------------------------------
2184
2185 wxGridCellAttrProvider::wxGridCellAttrProvider()
2186 {
2187 m_data = (wxGridCellAttrProviderData *)NULL;
2188 }
2189
2190 wxGridCellAttrProvider::~wxGridCellAttrProvider()
2191 {
2192 delete m_data;
2193 }
2194
2195 void wxGridCellAttrProvider::InitData()
2196 {
2197 m_data = new wxGridCellAttrProviderData;
2198 }
2199
2200 wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col) const
2201 {
2202 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2203 if ( m_data )
2204 {
2205 // first look for the attribute of this specific cell
2206 attr = m_data->m_cellAttrs.GetAttr(row, col);
2207
2208 if ( !attr )
2209 {
2210 // then look for the col attr (col attributes are more common than
2211 // the row ones, hence they have priority)
2212 attr = m_data->m_colAttrs.GetAttr(col);
2213 }
2214
2215 if ( !attr )
2216 {
2217 // finally try the row attributes
2218 attr = m_data->m_rowAttrs.GetAttr(row);
2219 }
2220 }
2221
2222 return attr;
2223 }
2224
2225 void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
2226 int row, int col)
2227 {
2228 if ( !m_data )
2229 InitData();
2230
2231 m_data->m_cellAttrs.SetAttr(attr, row, col);
2232 }
2233
2234 void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
2235 {
2236 if ( !m_data )
2237 InitData();
2238
2239 m_data->m_rowAttrs.SetAttr(attr, row);
2240 }
2241
2242 void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
2243 {
2244 if ( !m_data )
2245 InitData();
2246
2247 m_data->m_colAttrs.SetAttr(attr, col);
2248 }
2249
2250 void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows )
2251 {
2252 if ( m_data )
2253 {
2254 m_data->m_cellAttrs.UpdateAttrRows( pos, numRows );
2255
2256 m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows );
2257 }
2258 }
2259
2260 void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols )
2261 {
2262 if ( m_data )
2263 {
2264 m_data->m_cellAttrs.UpdateAttrCols( pos, numCols );
2265
2266 m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols );
2267 }
2268 }
2269
2270 // ----------------------------------------------------------------------------
2271 // wxGridTypeRegistry
2272 // ----------------------------------------------------------------------------
2273
2274 wxGridTypeRegistry::~wxGridTypeRegistry()
2275 {
2276 size_t count = m_typeinfo.Count();
2277 for ( size_t i = 0; i < count; i++ )
2278 delete m_typeinfo[i];
2279 }
2280
2281
2282 void wxGridTypeRegistry::RegisterDataType(const wxString& typeName,
2283 wxGridCellRenderer* renderer,
2284 wxGridCellEditor* editor)
2285 {
2286 wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor);
2287
2288 // is it already registered?
2289 int loc = FindRegisteredDataType(typeName);
2290 if ( loc != wxNOT_FOUND )
2291 {
2292 delete m_typeinfo[loc];
2293 m_typeinfo[loc] = info;
2294 }
2295 else
2296 {
2297 m_typeinfo.Add(info);
2298 }
2299 }
2300
2301 int wxGridTypeRegistry::FindRegisteredDataType(const wxString& typeName)
2302 {
2303 size_t count = m_typeinfo.GetCount();
2304 for ( size_t i = 0; i < count; i++ )
2305 {
2306 if ( typeName == m_typeinfo[i]->m_typeName )
2307 {
2308 return i;
2309 }
2310 }
2311
2312 return wxNOT_FOUND;
2313 }
2314
2315 int wxGridTypeRegistry::FindDataType(const wxString& typeName)
2316 {
2317 int index = FindRegisteredDataType(typeName);
2318 if ( index == wxNOT_FOUND )
2319 {
2320 // check whether this is one of the standard ones, in which case
2321 // register it "on the fly"
2322 if ( typeName == wxGRID_VALUE_STRING )
2323 {
2324 RegisterDataType(wxGRID_VALUE_STRING,
2325 new wxGridCellStringRenderer,
2326 new wxGridCellTextEditor);
2327 }
2328 else if ( typeName == wxGRID_VALUE_BOOL )
2329 {
2330 RegisterDataType(wxGRID_VALUE_BOOL,
2331 new wxGridCellBoolRenderer,
2332 new wxGridCellBoolEditor);
2333 }
2334 else if ( typeName == wxGRID_VALUE_NUMBER )
2335 {
2336 RegisterDataType(wxGRID_VALUE_NUMBER,
2337 new wxGridCellNumberRenderer,
2338 new wxGridCellNumberEditor);
2339 }
2340 else if ( typeName == wxGRID_VALUE_FLOAT )
2341 {
2342 RegisterDataType(wxGRID_VALUE_FLOAT,
2343 new wxGridCellFloatRenderer,
2344 new wxGridCellFloatEditor);
2345 }
2346 else if ( typeName == wxGRID_VALUE_CHOICE )
2347 {
2348 RegisterDataType(wxGRID_VALUE_CHOICE,
2349 new wxGridCellStringRenderer,
2350 new wxGridCellChoiceEditor);
2351 }
2352 else
2353 {
2354 return wxNOT_FOUND;
2355 }
2356
2357 // we get here only if just added the entry for this type, so return
2358 // the last index
2359 index = m_typeinfo.GetCount() - 1;
2360 }
2361
2362 return index;
2363 }
2364
2365 int wxGridTypeRegistry::FindOrCloneDataType(const wxString& typeName)
2366 {
2367 int index = FindDataType(typeName);
2368 if ( index == wxNOT_FOUND )
2369 {
2370 // the first part of the typename is the "real" type, anything after ':'
2371 // are the parameters for the renderer
2372 index = FindDataType(typeName.BeforeFirst(_T(':')));
2373 if ( index == wxNOT_FOUND )
2374 {
2375 return wxNOT_FOUND;
2376 }
2377
2378 wxGridCellRenderer *renderer = GetRenderer(index);
2379 wxGridCellRenderer *rendererOld = renderer;
2380 renderer = renderer->Clone();
2381 rendererOld->DecRef();
2382
2383 wxGridCellEditor *editor = GetEditor(index);
2384 wxGridCellEditor *editorOld = editor;
2385 editor = editor->Clone();
2386 editorOld->DecRef();
2387
2388 // do it even if there are no parameters to reset them to defaults
2389 wxString params = typeName.AfterFirst(_T(':'));
2390 renderer->SetParameters(params);
2391 editor->SetParameters(params);
2392
2393 // register the new typename
2394 RegisterDataType(typeName, renderer, editor);
2395
2396 // we just registered it, it's the last one
2397 index = m_typeinfo.GetCount() - 1;
2398 }
2399
2400 return index;
2401 }
2402
2403 wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index)
2404 {
2405 wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer;
2406 renderer->IncRef();
2407 return renderer;
2408 }
2409
2410 wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
2411 {
2412 wxGridCellEditor* editor = m_typeinfo[index]->m_editor;
2413 editor->IncRef();
2414 return editor;
2415 }
2416
2417 // ----------------------------------------------------------------------------
2418 // wxGridTableBase
2419 // ----------------------------------------------------------------------------
2420
2421 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
2422
2423
2424 wxGridTableBase::wxGridTableBase()
2425 {
2426 m_view = (wxGrid *) NULL;
2427 m_attrProvider = (wxGridCellAttrProvider *) NULL;
2428 }
2429
2430 wxGridTableBase::~wxGridTableBase()
2431 {
2432 delete m_attrProvider;
2433 }
2434
2435 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
2436 {
2437 delete m_attrProvider;
2438 m_attrProvider = attrProvider;
2439 }
2440
2441 bool wxGridTableBase::CanHaveAttributes()
2442 {
2443 if ( ! GetAttrProvider() )
2444 {
2445 // use the default attr provider by default
2446 SetAttrProvider(new wxGridCellAttrProvider);
2447 }
2448 return TRUE;
2449 }
2450
2451 wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col)
2452 {
2453 if ( m_attrProvider )
2454 return m_attrProvider->GetAttr(row, col);
2455 else
2456 return (wxGridCellAttr *)NULL;
2457 }
2458
2459 void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
2460 {
2461 if ( m_attrProvider )
2462 {
2463 m_attrProvider->SetAttr(attr, row, col);
2464 }
2465 else
2466 {
2467 // as we take ownership of the pointer and don't store it, we must
2468 // free it now
2469 wxSafeDecRef(attr);
2470 }
2471 }
2472
2473 void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
2474 {
2475 if ( m_attrProvider )
2476 {
2477 m_attrProvider->SetRowAttr(attr, row);
2478 }
2479 else
2480 {
2481 // as we take ownership of the pointer and don't store it, we must
2482 // free it now
2483 wxSafeDecRef(attr);
2484 }
2485 }
2486
2487 void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
2488 {
2489 if ( m_attrProvider )
2490 {
2491 m_attrProvider->SetColAttr(attr, col);
2492 }
2493 else
2494 {
2495 // as we take ownership of the pointer and don't store it, we must
2496 // free it now
2497 wxSafeDecRef(attr);
2498 }
2499 }
2500
2501 bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos),
2502 size_t WXUNUSED(numRows) )
2503 {
2504 wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") );
2505
2506 return FALSE;
2507 }
2508
2509 bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows) )
2510 {
2511 wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function"));
2512
2513 return FALSE;
2514 }
2515
2516 bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos),
2517 size_t WXUNUSED(numRows) )
2518 {
2519 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function"));
2520
2521 return FALSE;
2522 }
2523
2524 bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos),
2525 size_t WXUNUSED(numCols) )
2526 {
2527 wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function"));
2528
2529 return FALSE;
2530 }
2531
2532 bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols) )
2533 {
2534 wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function"));
2535
2536 return FALSE;
2537 }
2538
2539 bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos),
2540 size_t WXUNUSED(numCols) )
2541 {
2542 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function"));
2543
2544 return FALSE;
2545 }
2546
2547
2548 wxString wxGridTableBase::GetRowLabelValue( int row )
2549 {
2550 wxString s;
2551 s << row + 1; // RD: Starting the rows at zero confuses users, no matter
2552 // how much it makes sense to us geeks.
2553 return s;
2554 }
2555
2556 wxString wxGridTableBase::GetColLabelValue( int col )
2557 {
2558 // default col labels are:
2559 // cols 0 to 25 : A-Z
2560 // cols 26 to 675 : AA-ZZ
2561 // etc.
2562
2563 wxString s;
2564 unsigned int i, n;
2565 for ( n = 1; ; n++ )
2566 {
2567 s += (_T('A') + (wxChar)( col%26 ));
2568 col = col/26 - 1;
2569 if ( col < 0 ) break;
2570 }
2571
2572 // reverse the string...
2573 wxString s2;
2574 for ( i = 0; i < n; i++ )
2575 {
2576 s2 += s[n-i-1];
2577 }
2578
2579 return s2;
2580 }
2581
2582
2583 wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) )
2584 {
2585 return wxGRID_VALUE_STRING;
2586 }
2587
2588 bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col),
2589 const wxString& typeName )
2590 {
2591 return typeName == wxGRID_VALUE_STRING;
2592 }
2593
2594 bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName )
2595 {
2596 return CanGetValueAs(row, col, typeName);
2597 }
2598
2599 long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) )
2600 {
2601 return 0;
2602 }
2603
2604 double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) )
2605 {
2606 return 0.0;
2607 }
2608
2609 bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) )
2610 {
2611 return FALSE;
2612 }
2613
2614 void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col),
2615 long WXUNUSED(value) )
2616 {
2617 }
2618
2619 void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col),
2620 double WXUNUSED(value) )
2621 {
2622 }
2623
2624 void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col),
2625 bool WXUNUSED(value) )
2626 {
2627 }
2628
2629
2630 void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
2631 const wxString& WXUNUSED(typeName) )
2632 {
2633 return NULL;
2634 }
2635
2636 void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
2637 const wxString& WXUNUSED(typeName),
2638 void* WXUNUSED(value) )
2639 {
2640 }
2641
2642 //////////////////////////////////////////////////////////////////////
2643 //
2644 // Message class for the grid table to send requests and notifications
2645 // to the grid view
2646 //
2647
2648 wxGridTableMessage::wxGridTableMessage()
2649 {
2650 m_table = (wxGridTableBase *) NULL;
2651 m_id = -1;
2652 m_comInt1 = -1;
2653 m_comInt2 = -1;
2654 }
2655
2656 wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
2657 int commandInt1, int commandInt2 )
2658 {
2659 m_table = table;
2660 m_id = id;
2661 m_comInt1 = commandInt1;
2662 m_comInt2 = commandInt2;
2663 }
2664
2665
2666
2667 //////////////////////////////////////////////////////////////////////
2668 //
2669 // A basic grid table for string data. An object of this class will
2670 // created by wxGrid if you don't specify an alternative table class.
2671 //
2672
2673 WX_DEFINE_OBJARRAY(wxGridStringArray)
2674
2675 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
2676
2677 wxGridStringTable::wxGridStringTable()
2678 : wxGridTableBase()
2679 {
2680 }
2681
2682 wxGridStringTable::wxGridStringTable( int numRows, int numCols )
2683 : wxGridTableBase()
2684 {
2685 int row, col;
2686
2687 m_data.Alloc( numRows );
2688
2689 wxArrayString sa;
2690 sa.Alloc( numCols );
2691 for ( col = 0; col < numCols; col++ )
2692 {
2693 sa.Add( wxEmptyString );
2694 }
2695
2696 for ( row = 0; row < numRows; row++ )
2697 {
2698 m_data.Add( sa );
2699 }
2700 }
2701
2702 wxGridStringTable::~wxGridStringTable()
2703 {
2704 }
2705
2706 int wxGridStringTable::GetNumberRows()
2707 {
2708 return m_data.GetCount();
2709 }
2710
2711 int wxGridStringTable::GetNumberCols()
2712 {
2713 if ( m_data.GetCount() > 0 )
2714 return m_data[0].GetCount();
2715 else
2716 return 0;
2717 }
2718
2719 wxString wxGridStringTable::GetValue( int row, int col )
2720 {
2721 wxASSERT_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
2722 _T("invalid row or column index in wxGridStringTable") );
2723
2724 return m_data[row][col];
2725 }
2726
2727 void wxGridStringTable::SetValue( int row, int col, const wxString& value )
2728 {
2729 wxASSERT_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
2730 _T("invalid row or column index in wxGridStringTable") );
2731
2732 m_data[row][col] = value;
2733 }
2734
2735 bool wxGridStringTable::IsEmptyCell( int row, int col )
2736 {
2737 wxASSERT_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
2738 _T("invalid row or column index in wxGridStringTable") );
2739
2740 return (m_data[row][col] == wxEmptyString);
2741 }
2742
2743 void wxGridStringTable::Clear()
2744 {
2745 int row, col;
2746 int numRows, numCols;
2747
2748 numRows = m_data.GetCount();
2749 if ( numRows > 0 )
2750 {
2751 numCols = m_data[0].GetCount();
2752
2753 for ( row = 0; row < numRows; row++ )
2754 {
2755 for ( col = 0; col < numCols; col++ )
2756 {
2757 m_data[row][col] = wxEmptyString;
2758 }
2759 }
2760 }
2761 }
2762
2763
2764 bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
2765 {
2766 size_t row, col;
2767
2768 size_t curNumRows = m_data.GetCount();
2769 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
2770 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
2771
2772 if ( pos >= curNumRows )
2773 {
2774 return AppendRows( numRows );
2775 }
2776
2777 wxArrayString sa;
2778 sa.Alloc( curNumCols );
2779 for ( col = 0; col < curNumCols; col++ )
2780 {
2781 sa.Add( wxEmptyString );
2782 }
2783
2784 for ( row = pos; row < pos + numRows; row++ )
2785 {
2786 m_data.Insert( sa, row );
2787 }
2788 if ( GetView() )
2789 {
2790 wxGridTableMessage msg( this,
2791 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
2792 pos,
2793 numRows );
2794
2795 GetView()->ProcessTableMessage( msg );
2796 }
2797
2798 return TRUE;
2799 }
2800
2801 bool wxGridStringTable::AppendRows( size_t numRows )
2802 {
2803 size_t row, col;
2804
2805 size_t curNumRows = m_data.GetCount();
2806 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
2807 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
2808
2809 wxArrayString sa;
2810 if ( curNumCols > 0 )
2811 {
2812 sa.Alloc( curNumCols );
2813 for ( col = 0; col < curNumCols; col++ )
2814 {
2815 sa.Add( wxEmptyString );
2816 }
2817 }
2818
2819 for ( row = 0; row < numRows; row++ )
2820 {
2821 m_data.Add( sa );
2822 }
2823
2824 if ( GetView() )
2825 {
2826 wxGridTableMessage msg( this,
2827 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
2828 numRows );
2829
2830 GetView()->ProcessTableMessage( msg );
2831 }
2832
2833 return TRUE;
2834 }
2835
2836 bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
2837 {
2838 size_t n;
2839
2840 size_t curNumRows = m_data.GetCount();
2841
2842 if ( pos >= curNumRows )
2843 {
2844 wxString errmsg;
2845 errmsg.Printf(wxT("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)\nPos value is invalid for present table with %d rows"),
2846 pos, numRows, curNumRows );
2847 wxFAIL_MSG( errmsg );
2848 return FALSE;
2849 }
2850
2851 if ( numRows > curNumRows - pos )
2852 {
2853 numRows = curNumRows - pos;
2854 }
2855
2856 if ( numRows >= curNumRows )
2857 {
2858 m_data.Empty(); // don't release memory just yet
2859 }
2860 else
2861 {
2862 for ( n = 0; n < numRows; n++ )
2863 {
2864 m_data.Remove( pos );
2865 }
2866 }
2867 if ( GetView() )
2868 {
2869 wxGridTableMessage msg( this,
2870 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
2871 pos,
2872 numRows );
2873
2874 GetView()->ProcessTableMessage( msg );
2875 }
2876
2877 return TRUE;
2878 }
2879
2880 bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
2881 {
2882 size_t row, col;
2883
2884 size_t curNumRows = m_data.GetCount();
2885 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
2886 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
2887
2888 if ( pos >= curNumCols )
2889 {
2890 return AppendCols( numCols );
2891 }
2892
2893 for ( row = 0; row < curNumRows; row++ )
2894 {
2895 for ( col = pos; col < pos + numCols; col++ )
2896 {
2897 m_data[row].Insert( wxEmptyString, col );
2898 }
2899 }
2900 if ( GetView() )
2901 {
2902 wxGridTableMessage msg( this,
2903 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
2904 pos,
2905 numCols );
2906
2907 GetView()->ProcessTableMessage( msg );
2908 }
2909
2910 return TRUE;
2911 }
2912
2913 bool wxGridStringTable::AppendCols( size_t numCols )
2914 {
2915 size_t row, n;
2916
2917 size_t curNumRows = m_data.GetCount();
2918 #if 0
2919 if ( !curNumRows )
2920 {
2921 // TODO: something better than this ?
2922 //
2923 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\nCall AppendRows() first") );
2924 return FALSE;
2925 }
2926 #endif
2927
2928 for ( row = 0; row < curNumRows; row++ )
2929 {
2930 for ( n = 0; n < numCols; n++ )
2931 {
2932 m_data[row].Add( wxEmptyString );
2933 }
2934 }
2935
2936 if ( GetView() )
2937 {
2938 wxGridTableMessage msg( this,
2939 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
2940 numCols );
2941
2942 GetView()->ProcessTableMessage( msg );
2943 }
2944
2945 return TRUE;
2946 }
2947
2948 bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
2949 {
2950 size_t row, n;
2951
2952 size_t curNumRows = m_data.GetCount();
2953 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
2954 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
2955
2956 if ( pos >= curNumCols )
2957 {
2958 wxString errmsg;
2959 errmsg.Printf( wxT("Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\nPos value is invalid for present table with %d cols"),
2960 pos, numCols, curNumCols );
2961 wxFAIL_MSG( errmsg );
2962 return FALSE;
2963 }
2964
2965 if ( numCols > curNumCols - pos )
2966 {
2967 numCols = curNumCols - pos;
2968 }
2969
2970 for ( row = 0; row < curNumRows; row++ )
2971 {
2972 if ( numCols >= curNumCols )
2973 {
2974 m_data[row].Clear();
2975 }
2976 else
2977 {
2978 for ( n = 0; n < numCols; n++ )
2979 {
2980 m_data[row].Remove( pos );
2981 }
2982 }
2983 }
2984 if ( GetView() )
2985 {
2986 wxGridTableMessage msg( this,
2987 wxGRIDTABLE_NOTIFY_COLS_DELETED,
2988 pos,
2989 numCols );
2990
2991 GetView()->ProcessTableMessage( msg );
2992 }
2993
2994 return TRUE;
2995 }
2996
2997 wxString wxGridStringTable::GetRowLabelValue( int row )
2998 {
2999 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
3000 {
3001 // using default label
3002 //
3003 return wxGridTableBase::GetRowLabelValue( row );
3004 }
3005 else
3006 {
3007 return m_rowLabels[ row ];
3008 }
3009 }
3010
3011 wxString wxGridStringTable::GetColLabelValue( int col )
3012 {
3013 if ( col > (int)(m_colLabels.GetCount()) - 1 )
3014 {
3015 // using default label
3016 //
3017 return wxGridTableBase::GetColLabelValue( col );
3018 }
3019 else
3020 {
3021 return m_colLabels[ col ];
3022 }
3023 }
3024
3025 void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
3026 {
3027 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
3028 {
3029 int n = m_rowLabels.GetCount();
3030 int i;
3031 for ( i = n; i <= row; i++ )
3032 {
3033 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
3034 }
3035 }
3036
3037 m_rowLabels[row] = value;
3038 }
3039
3040 void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
3041 {
3042 if ( col > (int)(m_colLabels.GetCount()) - 1 )
3043 {
3044 int n = m_colLabels.GetCount();
3045 int i;
3046 for ( i = n; i <= col; i++ )
3047 {
3048 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
3049 }
3050 }
3051
3052 m_colLabels[col] = value;
3053 }
3054
3055
3056
3057 //////////////////////////////////////////////////////////////////////
3058 //////////////////////////////////////////////////////////////////////
3059
3060 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
3061
3062 BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
3063 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
3064 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
3065 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
3066 EVT_KEY_UP( wxGridRowLabelWindow::OnKeyUp )
3067 END_EVENT_TABLE()
3068
3069 wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
3070 wxWindowID id,
3071 const wxPoint &pos, const wxSize &size )
3072 : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
3073 {
3074 m_owner = parent;
3075 }
3076
3077 void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
3078 {
3079 wxPaintDC dc(this);
3080
3081 // NO - don't do this because it will set both the x and y origin
3082 // coords to match the parent scrolled window and we just want to
3083 // set the y coord - MB
3084 //
3085 // m_owner->PrepareDC( dc );
3086
3087 int x, y;
3088 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
3089 dc.SetDeviceOrigin( 0, -y );
3090
3091 m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
3092 m_owner->DrawRowLabels( dc );
3093 }
3094
3095
3096 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
3097 {
3098 m_owner->ProcessRowLabelMouseEvent( event );
3099 }
3100
3101
3102 // This seems to be required for wxMotif otherwise the mouse
3103 // cursor must be in the cell edit control to get key events
3104 //
3105 void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
3106 {
3107 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
3108 }
3109
3110 void wxGridRowLabelWindow::OnKeyUp( wxKeyEvent& event )
3111 {
3112 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
3113 }
3114
3115
3116
3117 //////////////////////////////////////////////////////////////////////
3118
3119 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
3120
3121 BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
3122 EVT_PAINT( wxGridColLabelWindow::OnPaint )
3123 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
3124 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
3125 EVT_KEY_UP( wxGridColLabelWindow::OnKeyUp )
3126 END_EVENT_TABLE()
3127
3128 wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
3129 wxWindowID id,
3130 const wxPoint &pos, const wxSize &size )
3131 : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
3132 {
3133 m_owner = parent;
3134 }
3135
3136 void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
3137 {
3138 wxPaintDC dc(this);
3139
3140 // NO - don't do this because it will set both the x and y origin
3141 // coords to match the parent scrolled window and we just want to
3142 // set the x coord - MB
3143 //
3144 // m_owner->PrepareDC( dc );
3145
3146 int x, y;
3147 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
3148 dc.SetDeviceOrigin( -x, 0 );
3149
3150 m_owner->CalcColLabelsExposed( GetUpdateRegion() );
3151 m_owner->DrawColLabels( dc );
3152 }
3153
3154
3155 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
3156 {
3157 m_owner->ProcessColLabelMouseEvent( event );
3158 }
3159
3160
3161 // This seems to be required for wxMotif otherwise the mouse
3162 // cursor must be in the cell edit control to get key events
3163 //
3164 void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
3165 {
3166 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
3167 }
3168
3169 void wxGridColLabelWindow::OnKeyUp( wxKeyEvent& event )
3170 {
3171 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
3172 }
3173
3174
3175
3176 //////////////////////////////////////////////////////////////////////
3177
3178 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
3179
3180 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
3181 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
3182 EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
3183 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
3184 EVT_KEY_UP( wxGridCornerLabelWindow::OnKeyUp )
3185 END_EVENT_TABLE()
3186
3187 wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
3188 wxWindowID id,
3189 const wxPoint &pos, const wxSize &size )
3190 : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
3191 {
3192 m_owner = parent;
3193 }
3194
3195 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
3196 {
3197 wxPaintDC dc(this);
3198
3199 int client_height = 0;
3200 int client_width = 0;
3201 GetClientSize( &client_width, &client_height );
3202
3203 dc.SetPen( *wxBLACK_PEN );
3204 dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
3205 dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
3206
3207 dc.SetPen( *wxWHITE_PEN );
3208 dc.DrawLine( 0, 0, client_width, 0 );
3209 dc.DrawLine( 0, 0, 0, client_height );
3210 }
3211
3212
3213 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
3214 {
3215 m_owner->ProcessCornerLabelMouseEvent( event );
3216 }
3217
3218
3219 // This seems to be required for wxMotif otherwise the mouse
3220 // cursor must be in the cell edit control to get key events
3221 //
3222 void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
3223 {
3224 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
3225 }
3226
3227 void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event )
3228 {
3229 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
3230 }
3231
3232
3233
3234 //////////////////////////////////////////////////////////////////////
3235
3236 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxPanel )
3237
3238 BEGIN_EVENT_TABLE( wxGridWindow, wxPanel )
3239 EVT_PAINT( wxGridWindow::OnPaint )
3240 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
3241 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
3242 EVT_KEY_UP( wxGridWindow::OnKeyUp )
3243 EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground )
3244 END_EVENT_TABLE()
3245
3246 wxGridWindow::wxGridWindow( wxGrid *parent,
3247 wxGridRowLabelWindow *rowLblWin,
3248 wxGridColLabelWindow *colLblWin,
3249 wxWindowID id, const wxPoint &pos, const wxSize &size )
3250 : wxPanel( parent, id, pos, size, wxWANTS_CHARS, "grid window" )
3251 {
3252 m_owner = parent;
3253 m_rowLabelWin = rowLblWin;
3254 m_colLabelWin = colLblWin;
3255 SetBackgroundColour( "WHITE" );
3256 }
3257
3258
3259 wxGridWindow::~wxGridWindow()
3260 {
3261 }
3262
3263
3264 void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
3265 {
3266 wxPaintDC dc( this );
3267 m_owner->PrepareDC( dc );
3268 wxRegion reg = GetUpdateRegion();
3269 m_owner->CalcCellsExposed( reg );
3270 m_owner->DrawGridCellArea( dc );
3271 #if WXGRID_DRAW_LINES
3272 m_owner->DrawAllGridLines( dc, reg );
3273 #endif
3274 m_owner->DrawGridSpace( dc );
3275 m_owner->DrawHighlight( dc );
3276 }
3277
3278
3279 void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
3280 {
3281 wxPanel::ScrollWindow( dx, dy, rect );
3282 m_rowLabelWin->ScrollWindow( 0, dy, rect );
3283 m_colLabelWin->ScrollWindow( dx, 0, rect );
3284 }
3285
3286
3287 void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
3288 {
3289 m_owner->ProcessGridCellMouseEvent( event );
3290 }
3291
3292
3293 // This seems to be required for wxMotif/wxGTK otherwise the mouse
3294 // cursor must be in the cell edit control to get key events
3295 //
3296 void wxGridWindow::OnKeyDown( wxKeyEvent& event )
3297 {
3298 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
3299 }
3300
3301 void wxGridWindow::OnKeyUp( wxKeyEvent& event )
3302 {
3303 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
3304 }
3305
3306 void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) )
3307 {
3308 }
3309
3310
3311 //////////////////////////////////////////////////////////////////////
3312
3313
3314 IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
3315
3316 BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
3317 EVT_PAINT( wxGrid::OnPaint )
3318 EVT_SIZE( wxGrid::OnSize )
3319 EVT_KEY_DOWN( wxGrid::OnKeyDown )
3320 EVT_KEY_UP( wxGrid::OnKeyUp )
3321 EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground )
3322 END_EVENT_TABLE()
3323
3324 wxGrid::wxGrid( wxWindow *parent,
3325 wxWindowID id,
3326 const wxPoint& pos,
3327 const wxSize& size,
3328 long style,
3329 const wxString& name )
3330 : wxScrolledWindow( parent, id, pos, size, (style | wxWANTS_CHARS), name ),
3331 m_colMinWidths(GRID_HASH_SIZE),
3332 m_rowMinHeights(GRID_HASH_SIZE)
3333 {
3334 Create();
3335 }
3336
3337
3338 wxGrid::~wxGrid()
3339 {
3340 ClearAttrCache();
3341 wxSafeDecRef(m_defaultCellAttr);
3342
3343 #ifdef DEBUG_ATTR_CACHE
3344 size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses;
3345 wxPrintf(_T("wxGrid attribute cache statistics: "
3346 "total: %u, hits: %u (%u%%)\n"),
3347 total, gs_nAttrCacheHits,
3348 total ? (gs_nAttrCacheHits*100) / total : 0);
3349 #endif
3350
3351 if (m_ownTable)
3352 delete m_table;
3353
3354 delete m_typeRegistry;
3355 delete m_selection;
3356 }
3357
3358
3359 //
3360 // ----- internal init and update functions
3361 //
3362
3363 void wxGrid::Create()
3364 {
3365 m_created = FALSE; // set to TRUE by CreateGrid
3366
3367 m_table = (wxGridTableBase *) NULL;
3368 m_ownTable = FALSE;
3369
3370 m_cellEditCtrlEnabled = FALSE;
3371
3372 m_defaultCellAttr = new wxGridCellAttr;
3373 m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
3374
3375 // Set default cell attributes
3376 m_defaultCellAttr->SetFont(GetFont());
3377 m_defaultCellAttr->SetAlignment(wxLEFT, wxTOP);
3378 m_defaultCellAttr->SetTextColour(
3379 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT));
3380 m_defaultCellAttr->SetBackgroundColour(
3381 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
3382 m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer);
3383 m_defaultCellAttr->SetEditor(new wxGridCellTextEditor);
3384
3385
3386 m_numRows = 0;
3387 m_numCols = 0;
3388 m_currentCellCoords = wxGridNoCellCoords;
3389
3390 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
3391 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
3392
3393 // create the type registry
3394 m_typeRegistry = new wxGridTypeRegistry;
3395 m_selection = 0;
3396 // subwindow components that make up the wxGrid
3397 m_cornerLabelWin = new wxGridCornerLabelWindow( this,
3398 -1,
3399 wxDefaultPosition,
3400 wxDefaultSize );
3401
3402 m_rowLabelWin = new wxGridRowLabelWindow( this,
3403 -1,
3404 wxDefaultPosition,
3405 wxDefaultSize );
3406
3407 m_colLabelWin = new wxGridColLabelWindow( this,
3408 -1,
3409 wxDefaultPosition,
3410 wxDefaultSize );
3411
3412 m_gridWin = new wxGridWindow( this,
3413 m_rowLabelWin,
3414 m_colLabelWin,
3415 -1,
3416 wxDefaultPosition,
3417 wxDefaultSize );
3418
3419 SetTargetWindow( m_gridWin );
3420 }
3421
3422
3423 bool wxGrid::CreateGrid( int numRows, int numCols,
3424 wxGrid::wxGridSelectionModes selmode )
3425 {
3426 wxCHECK_MSG( !m_created,
3427 FALSE,
3428 wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
3429
3430 m_numRows = numRows;
3431 m_numCols = numCols;
3432
3433 m_table = new wxGridStringTable( m_numRows, m_numCols );
3434 m_table->SetView( this );
3435 m_ownTable = TRUE;
3436 m_selection = new wxGridSelection( this, selmode );
3437 Init();
3438 m_created = TRUE;
3439
3440 return m_created;
3441 }
3442
3443 void wxGrid::SetSelectionMode(wxGrid::wxGridSelectionModes selmode)
3444 {
3445 if ( !m_created )
3446 {
3447 wxFAIL_MSG( wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") );
3448 }
3449 else
3450 m_selection->SetSelectionMode( selmode );
3451 }
3452
3453 bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership,
3454 wxGrid::wxGridSelectionModes selmode )
3455 {
3456 if ( m_created )
3457 {
3458 // RD: Actually, this should probably be allowed. I think it would be
3459 // nice to be able to switch multiple Tables in and out of a single
3460 // View at runtime. Is there anything in the implmentation that would
3461 // prevent this?
3462
3463 // At least, you now have to cope with m_selection
3464 wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
3465 return FALSE;
3466 }
3467 else
3468 {
3469 m_numRows = table->GetNumberRows();
3470 m_numCols = table->GetNumberCols();
3471
3472 m_table = table;
3473 m_table->SetView( this );
3474 if (takeOwnership)
3475 m_ownTable = TRUE;
3476 m_selection = new wxGridSelection( this, selmode );
3477 Init();
3478 m_created = TRUE;
3479 }
3480
3481 return m_created;
3482 }
3483
3484
3485 void wxGrid::Init()
3486 {
3487 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
3488 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
3489
3490 if ( m_rowLabelWin )
3491 {
3492 m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
3493 }
3494 else
3495 {
3496 m_labelBackgroundColour = wxColour( _T("WHITE") );
3497 }
3498
3499 m_labelTextColour = wxColour( _T("BLACK") );
3500
3501 // init attr cache
3502 m_attrCache.row = -1;
3503
3504 // TODO: something better than this ?
3505 //
3506 m_labelFont = this->GetFont();
3507 m_labelFont.SetWeight( m_labelFont.GetWeight() + 2 );
3508
3509 m_rowLabelHorizAlign = wxLEFT;
3510 m_rowLabelVertAlign = wxCENTRE;
3511
3512 m_colLabelHorizAlign = wxCENTRE;
3513 m_colLabelVertAlign = wxTOP;
3514
3515 m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH;
3516 m_defaultRowHeight = m_gridWin->GetCharHeight();
3517
3518 #if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
3519 m_defaultRowHeight += 8;
3520 #else
3521 m_defaultRowHeight += 4;
3522 #endif
3523
3524 m_gridLineColour = wxColour( 128, 128, 255 );
3525 m_gridLinesEnabled = TRUE;
3526 m_cellHighlightColour = m_gridLineColour;
3527
3528 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
3529 m_winCapture = (wxWindow *)NULL;
3530 m_canDragRowSize = TRUE;
3531 m_canDragColSize = TRUE;
3532 m_canDragGridSize = TRUE;
3533 m_dragLastPos = -1;
3534 m_dragRowOrCol = -1;
3535 m_isDragging = FALSE;
3536 m_startDragPos = wxDefaultPosition;
3537
3538 m_waitForSlowClick = FALSE;
3539
3540 m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
3541 m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
3542
3543 m_currentCellCoords = wxGridNoCellCoords;
3544
3545 m_selectingTopLeft = wxGridNoCellCoords;
3546 m_selectingBottomRight = wxGridNoCellCoords;
3547 m_selectionBackground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT);
3548 m_selectionForeground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
3549
3550 m_editable = TRUE; // default for whole grid
3551
3552 m_inOnKeyDown = FALSE;
3553 m_batchCount = 0;
3554
3555 m_extraWidth =
3556 m_extraHeight = 50;
3557
3558 CalcDimensions();
3559 }
3560
3561 // ----------------------------------------------------------------------------
3562 // the idea is to call these functions only when necessary because they create
3563 // quite big arrays which eat memory mostly unnecessary - in particular, if
3564 // default widths/heights are used for all rows/columns, we may not use these
3565 // arrays at all
3566 //
3567 // with some extra code, it should be possible to only store the
3568 // widths/heights different from default ones but this will be done later...
3569 // ----------------------------------------------------------------------------
3570
3571 void wxGrid::InitRowHeights()
3572 {
3573 m_rowHeights.Empty();
3574 m_rowBottoms.Empty();
3575
3576 m_rowHeights.Alloc( m_numRows );
3577 m_rowBottoms.Alloc( m_numRows );
3578
3579 int rowBottom = 0;
3580 for ( int i = 0; i < m_numRows; i++ )
3581 {
3582 m_rowHeights.Add( m_defaultRowHeight );
3583 rowBottom += m_defaultRowHeight;
3584 m_rowBottoms.Add( rowBottom );
3585 }
3586 }
3587
3588 void wxGrid::InitColWidths()
3589 {
3590 m_colWidths.Empty();
3591 m_colRights.Empty();
3592
3593 m_colWidths.Alloc( m_numCols );
3594 m_colRights.Alloc( m_numCols );
3595 int colRight = 0;
3596 for ( int i = 0; i < m_numCols; i++ )
3597 {
3598 m_colWidths.Add( m_defaultColWidth );
3599 colRight += m_defaultColWidth;
3600 m_colRights.Add( colRight );
3601 }
3602 }
3603
3604 int wxGrid::GetColWidth(int col) const
3605 {
3606 return m_colWidths.IsEmpty() ? m_defaultColWidth : m_colWidths[col];
3607 }
3608
3609 int wxGrid::GetColLeft(int col) const
3610 {
3611 return m_colRights.IsEmpty() ? col * m_defaultColWidth
3612 : m_colRights[col] - m_colWidths[col];
3613 }
3614
3615 int wxGrid::GetColRight(int col) const
3616 {
3617 return m_colRights.IsEmpty() ? (col + 1) * m_defaultColWidth
3618 : m_colRights[col];
3619 }
3620
3621 int wxGrid::GetRowHeight(int row) const
3622 {
3623 return m_rowHeights.IsEmpty() ? m_defaultRowHeight : m_rowHeights[row];
3624 }
3625
3626 int wxGrid::GetRowTop(int row) const
3627 {
3628 return m_rowBottoms.IsEmpty() ? row * m_defaultRowHeight
3629 : m_rowBottoms[row] - m_rowHeights[row];
3630 }
3631
3632 int wxGrid::GetRowBottom(int row) const
3633 {
3634 return m_rowBottoms.IsEmpty() ? (row + 1) * m_defaultRowHeight
3635 : m_rowBottoms[row];
3636 }
3637
3638 void wxGrid::CalcDimensions()
3639 {
3640 int cw, ch;
3641 GetClientSize( &cw, &ch );
3642
3643 if ( m_numRows > 0 || m_numCols > 0 )
3644 {
3645 int right = m_numCols > 0 ? GetColRight( m_numCols-1 ) + m_extraWidth : 0;
3646 int bottom = m_numRows > 0 ? GetRowBottom( m_numRows-1 ) + m_extraHeight : 0;
3647
3648 // TODO: restore the scroll position that we had before sizing
3649 //
3650 int x, y;
3651 GetViewStart( &x, &y );
3652 SetScrollbars( GRID_SCROLL_LINE, GRID_SCROLL_LINE,
3653 right/GRID_SCROLL_LINE, bottom/GRID_SCROLL_LINE,
3654 x, y );
3655 }
3656 }
3657
3658
3659 void wxGrid::CalcWindowSizes()
3660 {
3661 int cw, ch;
3662 GetClientSize( &cw, &ch );
3663
3664 if ( m_cornerLabelWin->IsShown() )
3665 m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
3666
3667 if ( m_colLabelWin->IsShown() )
3668 m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw-m_rowLabelWidth, m_colLabelHeight);
3669
3670 if ( m_rowLabelWin->IsShown() )
3671 m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch-m_colLabelHeight);
3672
3673 if ( m_gridWin->IsShown() )
3674 m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw-m_rowLabelWidth, ch-m_colLabelHeight);
3675 }
3676
3677
3678 // this is called when the grid table sends a message to say that it
3679 // has been redimensioned
3680 //
3681 bool wxGrid::Redimension( wxGridTableMessage& msg )
3682 {
3683 int i;
3684 bool result = FALSE;
3685
3686 #if 0
3687 // if we were using the default widths/heights so far, we must change them
3688 // now
3689 if ( m_colWidths.IsEmpty() )
3690 {
3691 InitColWidths();
3692 }
3693
3694 if ( m_rowHeights.IsEmpty() )
3695 {
3696 InitRowHeights();
3697 }
3698 #endif
3699
3700 switch ( msg.GetId() )
3701 {
3702 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
3703 {
3704 size_t pos = msg.GetCommandInt();
3705 int numRows = msg.GetCommandInt2();
3706
3707 m_numRows += numRows;
3708
3709 if ( !m_rowHeights.IsEmpty() )
3710 {
3711 for ( i = 0; i < numRows; i++ )
3712 {
3713 m_rowHeights.Insert( m_defaultRowHeight, pos );
3714 m_rowBottoms.Insert( 0, pos );
3715 }
3716
3717 int bottom = 0;
3718 if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
3719
3720 for ( i = pos; i < m_numRows; i++ )
3721 {
3722 bottom += m_rowHeights[i];
3723 m_rowBottoms[i] = bottom;
3724 }
3725 }
3726 if ( m_currentCellCoords == wxGridNoCellCoords )
3727 {
3728 // if we have just inserted cols into an empty grid the current
3729 // cell will be undefined...
3730 //
3731 SetCurrentCell( 0, 0 );
3732 }
3733 m_selection->UpdateRows( pos, numRows );
3734 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
3735 if (attrProvider)
3736 attrProvider->UpdateAttrRows( pos, numRows );
3737
3738 if ( !GetBatchCount() )
3739 {
3740 CalcDimensions();
3741 m_rowLabelWin->Refresh();
3742 }
3743 }
3744 result = TRUE;
3745 break;
3746
3747 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
3748 {
3749 int numRows = msg.GetCommandInt();
3750 int oldNumRows = m_numRows;
3751 m_numRows += numRows;
3752
3753 if ( !m_rowHeights.IsEmpty() )
3754 {
3755 for ( i = 0; i < numRows; i++ )
3756 {
3757 m_rowHeights.Add( m_defaultRowHeight );
3758 m_rowBottoms.Add( 0 );
3759 }
3760
3761 int bottom = 0;
3762 if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
3763
3764 for ( i = oldNumRows; i < m_numRows; i++ )
3765 {
3766 bottom += m_rowHeights[i];
3767 m_rowBottoms[i] = bottom;
3768 }
3769 }
3770 if ( m_currentCellCoords == wxGridNoCellCoords )
3771 {
3772 // if we have just inserted cols into an empty grid the current
3773 // cell will be undefined...
3774 //
3775 SetCurrentCell( 0, 0 );
3776 }
3777 if ( !GetBatchCount() )
3778 {
3779 CalcDimensions();
3780 m_rowLabelWin->Refresh();
3781 }
3782 }
3783 result = TRUE;
3784 break;
3785
3786 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
3787 {
3788 size_t pos = msg.GetCommandInt();
3789 int numRows = msg.GetCommandInt2();
3790 m_numRows -= numRows;
3791
3792 if ( !m_rowHeights.IsEmpty() )
3793 {
3794 for ( i = 0; i < numRows; i++ )
3795 {
3796 m_rowHeights.Remove( pos );
3797 m_rowBottoms.Remove( pos );
3798 }
3799
3800 int h = 0;
3801 for ( i = 0; i < m_numRows; i++ )
3802 {
3803 h += m_rowHeights[i];
3804 m_rowBottoms[i] = h;
3805 }
3806 }
3807 if ( !m_numRows )
3808 {
3809 m_currentCellCoords = wxGridNoCellCoords;
3810 }
3811 else
3812 {
3813 if ( m_currentCellCoords.GetRow() >= m_numRows )
3814 m_currentCellCoords.Set( 0, 0 );
3815 }
3816 m_selection->UpdateRows( pos, -((int)numRows) );
3817 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
3818 if (attrProvider) {
3819 attrProvider->UpdateAttrRows( pos, -((int)numRows) );
3820 // No need to touch column attributes, unless we
3821 // removed _all_ rows, in this case, we remove
3822 // all column attributes.
3823 // I hate to do this here, but the
3824 // needed data is not available inside UpdateAttrRows.
3825 if ( !GetNumberRows() )
3826 attrProvider->UpdateAttrCols( 0, -GetNumberCols() );
3827 }
3828 if ( !GetBatchCount() )
3829 {
3830 CalcDimensions();
3831 m_rowLabelWin->Refresh();
3832 }
3833 }
3834 result = TRUE;
3835 break;
3836
3837 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
3838 {
3839 size_t pos = msg.GetCommandInt();
3840 int numCols = msg.GetCommandInt2();
3841 m_numCols += numCols;
3842
3843 if ( !m_colWidths.IsEmpty() )
3844 {
3845 for ( i = 0; i < numCols; i++ )
3846 {
3847 m_colWidths.Insert( m_defaultColWidth, pos );
3848 m_colRights.Insert( 0, pos );
3849 }
3850
3851 int right = 0;
3852 if ( pos > 0 ) right = m_colRights[pos-1];
3853
3854 for ( i = pos; i < m_numCols; i++ )
3855 {
3856 right += m_colWidths[i];
3857 m_colRights[i] = right;
3858 }
3859 }
3860 if ( m_currentCellCoords == wxGridNoCellCoords )
3861 {
3862 // if we have just inserted cols into an empty grid the current
3863 // cell will be undefined...
3864 //
3865 SetCurrentCell( 0, 0 );
3866 }
3867 m_selection->UpdateCols( pos, numCols );
3868 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
3869 if (attrProvider)
3870 attrProvider->UpdateAttrCols( pos, numCols );
3871 if ( !GetBatchCount() )
3872 {
3873 CalcDimensions();
3874 m_colLabelWin->Refresh();
3875 }
3876
3877 }
3878 result = TRUE;
3879 break;
3880
3881 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
3882 {
3883 int numCols = msg.GetCommandInt();
3884 int oldNumCols = m_numCols;
3885 m_numCols += numCols;
3886 if ( !m_colWidths.IsEmpty() )
3887 {
3888 for ( i = 0; i < numCols; i++ )
3889 {
3890 m_colWidths.Add( m_defaultColWidth );
3891 m_colRights.Add( 0 );
3892 }
3893
3894 int right = 0;
3895 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
3896
3897 for ( i = oldNumCols; i < m_numCols; i++ )
3898 {
3899 right += m_colWidths[i];
3900 m_colRights[i] = right;
3901 }
3902 }
3903 if ( m_currentCellCoords == wxGridNoCellCoords )
3904 {
3905 // if we have just inserted cols into an empty grid the current
3906 // cell will be undefined...
3907 //
3908 SetCurrentCell( 0, 0 );
3909 }
3910 if ( !GetBatchCount() )
3911 {
3912 CalcDimensions();
3913 m_colLabelWin->Refresh();
3914 }
3915 }
3916 result = TRUE;
3917 break;
3918
3919 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
3920 {
3921 size_t pos = msg.GetCommandInt();
3922 int numCols = msg.GetCommandInt2();
3923 m_numCols -= numCols;
3924
3925 if ( !m_colWidths.IsEmpty() )
3926 {
3927 for ( i = 0; i < numCols; i++ )
3928 {
3929 m_colWidths.Remove( pos );
3930 m_colRights.Remove( pos );
3931 }
3932
3933 int w = 0;
3934 for ( i = 0; i < m_numCols; i++ )
3935 {
3936 w += m_colWidths[i];
3937 m_colRights[i] = w;
3938 }
3939 }
3940 if ( !m_numCols )
3941 {
3942 m_currentCellCoords = wxGridNoCellCoords;
3943 }
3944 else
3945 {
3946 if ( m_currentCellCoords.GetCol() >= m_numCols )
3947 m_currentCellCoords.Set( 0, 0 );
3948 }
3949 m_selection->UpdateCols( pos, -((int)numCols) );
3950 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
3951 if (attrProvider) {
3952 attrProvider->UpdateAttrCols( pos, -((int)numCols) );
3953 // No need to touch row attributes, unless we
3954 // removed _all_ columns, in this case, we remove
3955 // all row attributes.
3956 // I hate to do this here, but the
3957 // needed data is not available inside UpdateAttrCols.
3958 if ( !GetNumberCols() )
3959 attrProvider->UpdateAttrRows( 0, -GetNumberRows() );
3960 }
3961 if ( !GetBatchCount() )
3962 {
3963 CalcDimensions();
3964 m_colLabelWin->Refresh();
3965 }
3966 return TRUE;
3967 }
3968 #if 0
3969 // There is no path to this code !!!!!!
3970 result = TRUE;
3971 break;
3972 #endif
3973 }
3974
3975 if (result && !GetBatchCount() )
3976 m_gridWin->Refresh();
3977 return result;
3978 }
3979
3980
3981 void wxGrid::CalcRowLabelsExposed( const wxRegion& reg )
3982 {
3983 wxRegionIterator iter( reg );
3984 wxRect r;
3985
3986 m_rowLabelsExposed.Empty();
3987
3988 int top, bottom;
3989 while ( iter )
3990 {
3991 r = iter.GetRect();
3992
3993 // TODO: remove this when we can...
3994 // There is a bug in wxMotif that gives garbage update
3995 // rectangles if you jump-scroll a long way by clicking the
3996 // scrollbar with middle button. This is a work-around
3997 //
3998 #if defined(__WXMOTIF__)
3999 int cw, ch;
4000 m_gridWin->GetClientSize( &cw, &ch );
4001 if ( r.GetTop() > ch ) r.SetTop( 0 );
4002 r.SetBottom( wxMin( r.GetBottom(), ch ) );
4003 #endif
4004
4005 // logical bounds of update region
4006 //
4007 int dummy;
4008 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
4009 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
4010
4011 // find the row labels within these bounds
4012 //
4013 int row;
4014 for ( row = 0; row < m_numRows; row++ )
4015 {
4016 if ( GetRowBottom(row) < top )
4017 continue;
4018
4019 if ( GetRowTop(row) > bottom )
4020 break;
4021
4022 m_rowLabelsExposed.Add( row );
4023 }
4024
4025 iter++ ;
4026 }
4027 }
4028
4029
4030 void wxGrid::CalcColLabelsExposed( const wxRegion& reg )
4031 {
4032 wxRegionIterator iter( reg );
4033 wxRect r;
4034
4035 m_colLabelsExposed.Empty();
4036
4037 int left, right;
4038 while ( iter )
4039 {
4040 r = iter.GetRect();
4041
4042 // TODO: remove this when we can...
4043 // There is a bug in wxMotif that gives garbage update
4044 // rectangles if you jump-scroll a long way by clicking the
4045 // scrollbar with middle button. This is a work-around
4046 //
4047 #if defined(__WXMOTIF__)
4048 int cw, ch;
4049 m_gridWin->GetClientSize( &cw, &ch );
4050 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
4051 r.SetRight( wxMin( r.GetRight(), cw ) );
4052 #endif
4053
4054 // logical bounds of update region
4055 //
4056 int dummy;
4057 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
4058 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
4059
4060 // find the cells within these bounds
4061 //
4062 int col;
4063 for ( col = 0; col < m_numCols; col++ )
4064 {
4065 if ( GetColRight(col) < left )
4066 continue;
4067
4068 if ( GetColLeft(col) > right )
4069 break;
4070
4071 m_colLabelsExposed.Add( col );
4072 }
4073
4074 iter++ ;
4075 }
4076 }
4077
4078
4079 void wxGrid::CalcCellsExposed( const wxRegion& reg )
4080 {
4081 wxRegionIterator iter( reg );
4082 wxRect r;
4083
4084 m_cellsExposed.Empty();
4085 m_rowsExposed.Empty();
4086 m_colsExposed.Empty();
4087
4088 int left, top, right, bottom;
4089 while ( iter )
4090 {
4091 r = iter.GetRect();
4092
4093 // TODO: remove this when we can...
4094 // There is a bug in wxMotif that gives garbage update
4095 // rectangles if you jump-scroll a long way by clicking the
4096 // scrollbar with middle button. This is a work-around
4097 //
4098 #if defined(__WXMOTIF__)
4099 int cw, ch;
4100 m_gridWin->GetClientSize( &cw, &ch );
4101 if ( r.GetTop() > ch ) r.SetTop( 0 );
4102 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
4103 r.SetRight( wxMin( r.GetRight(), cw ) );
4104 r.SetBottom( wxMin( r.GetBottom(), ch ) );
4105 #endif
4106
4107 // logical bounds of update region
4108 //
4109 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
4110 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
4111
4112 // find the cells within these bounds
4113 //
4114 int row, col;
4115 for ( row = 0; row < m_numRows; row++ )
4116 {
4117 if ( GetRowBottom(row) <= top )
4118 continue;
4119
4120 if ( GetRowTop(row) > bottom )
4121 break;
4122
4123 m_rowsExposed.Add( row );
4124
4125 for ( col = 0; col < m_numCols; col++ )
4126 {
4127 if ( GetColRight(col) <= left )
4128 continue;
4129
4130 if ( GetColLeft(col) > right )
4131 break;
4132
4133 if ( m_colsExposed.Index( col ) == wxNOT_FOUND )
4134 m_colsExposed.Add( col );
4135 m_cellsExposed.Add( wxGridCellCoords( row, col ) );
4136 }
4137 }
4138
4139 iter++;
4140 }
4141 }
4142
4143
4144 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
4145 {
4146 int x, y, row;
4147 wxPoint pos( event.GetPosition() );
4148 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
4149
4150 if ( event.Dragging() )
4151 {
4152 m_isDragging = TRUE;
4153
4154 if ( event.LeftIsDown() )
4155 {
4156 switch( m_cursorMode )
4157 {
4158 case WXGRID_CURSOR_RESIZE_ROW:
4159 {
4160 int cw, ch, left, dummy;
4161 m_gridWin->GetClientSize( &cw, &ch );
4162 CalcUnscrolledPosition( 0, 0, &left, &dummy );
4163
4164 wxClientDC dc( m_gridWin );
4165 PrepareDC( dc );
4166 y = wxMax( y,
4167 GetRowTop(m_dragRowOrCol) +
4168 GetRowMinimalHeight(m_dragRowOrCol) );
4169 dc.SetLogicalFunction(wxINVERT);
4170 if ( m_dragLastPos >= 0 )
4171 {
4172 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
4173 }
4174 dc.DrawLine( left, y, left+cw, y );
4175 m_dragLastPos = y;
4176 }
4177 break;
4178
4179 case WXGRID_CURSOR_SELECT_ROW:
4180 if ( (row = YToRow( y )) >= 0 )
4181 {
4182 m_selection->SelectRow( row,
4183 event.ControlDown(),
4184 event.ShiftDown(),
4185 event.AltDown(),
4186 event.MetaDown() );
4187 }
4188
4189 // default label to suppress warnings about "enumeration value
4190 // 'xxx' not handled in switch
4191 default:
4192 break;
4193 }
4194 }
4195 return;
4196 }
4197
4198 m_isDragging = FALSE;
4199
4200
4201 // ------------ Entering or leaving the window
4202 //
4203 if ( event.Entering() || event.Leaving() )
4204 {
4205 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
4206 }
4207
4208
4209 // ------------ Left button pressed
4210 //
4211 else if ( event.LeftDown() )
4212 {
4213 // don't send a label click event for a hit on the
4214 // edge of the row label - this is probably the user
4215 // wanting to resize the row
4216 //
4217 if ( YToEdgeOfRow(y) < 0 )
4218 {
4219 row = YToRow(y);
4220 if ( row >= 0 &&
4221 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
4222 {
4223 if ( !event.ShiftDown() && !event.ControlDown() )
4224 ClearSelection();
4225 if ( event.ShiftDown() )
4226 m_selection->SelectBlock( m_currentCellCoords.GetRow(),
4227 0,
4228 row,
4229 GetNumberCols() - 1,
4230 event.ControlDown(),
4231 event.ShiftDown(),
4232 event.AltDown(),
4233 event.MetaDown() );
4234 else
4235 m_selection->SelectRow( row,
4236 event.ControlDown(),
4237 event.ShiftDown(),
4238 event.AltDown(),
4239 event.MetaDown() );
4240 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
4241 }
4242 }
4243 else
4244 {
4245 // starting to drag-resize a row
4246 //
4247 if ( CanDragRowSize() )
4248 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
4249 }
4250 }
4251
4252
4253 // ------------ Left double click
4254 //
4255 else if (event.LeftDClick() )
4256 {
4257 if ( YToEdgeOfRow(y) < 0 )
4258 {
4259 row = YToRow(y);
4260 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
4261 }
4262 }
4263
4264
4265 // ------------ Left button released
4266 //
4267 else if ( event.LeftUp() )
4268 {
4269 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
4270 {
4271 DoEndDragResizeRow();
4272
4273 // Note: we are ending the event *after* doing
4274 // default processing in this case
4275 //
4276 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
4277 }
4278
4279 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
4280 m_dragLastPos = -1;
4281 }
4282
4283
4284 // ------------ Right button down
4285 //
4286 else if ( event.RightDown() )
4287 {
4288 row = YToRow(y);
4289 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
4290 {
4291 // no default action at the moment
4292 }
4293 }
4294
4295
4296 // ------------ Right double click
4297 //
4298 else if ( event.RightDClick() )
4299 {
4300 row = YToRow(y);
4301 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
4302 {
4303 // no default action at the moment
4304 }
4305 }
4306
4307
4308 // ------------ No buttons down and mouse moving
4309 //
4310 else if ( event.Moving() )
4311 {
4312 m_dragRowOrCol = YToEdgeOfRow( y );
4313 if ( m_dragRowOrCol >= 0 )
4314 {
4315 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4316 {
4317 // don't capture the mouse yet
4318 if ( CanDragRowSize() )
4319 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE);
4320 }
4321 }
4322 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
4323 {
4324 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, FALSE);
4325 }
4326 }
4327 }
4328
4329
4330 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
4331 {
4332 int x, y, col;
4333 wxPoint pos( event.GetPosition() );
4334 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
4335
4336 if ( event.Dragging() )
4337 {
4338 m_isDragging = TRUE;
4339
4340 if ( event.LeftIsDown() )
4341 {
4342 switch( m_cursorMode )
4343 {
4344 case WXGRID_CURSOR_RESIZE_COL:
4345 {
4346 int cw, ch, dummy, top;
4347 m_gridWin->GetClientSize( &cw, &ch );
4348 CalcUnscrolledPosition( 0, 0, &dummy, &top );
4349
4350 wxClientDC dc( m_gridWin );
4351 PrepareDC( dc );
4352
4353 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
4354 GetColMinimalWidth(m_dragRowOrCol));
4355 dc.SetLogicalFunction(wxINVERT);
4356 if ( m_dragLastPos >= 0 )
4357 {
4358 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
4359 }
4360 dc.DrawLine( x, top, x, top+ch );
4361 m_dragLastPos = x;
4362 }
4363 break;
4364
4365 case WXGRID_CURSOR_SELECT_COL:
4366 if ( (col = XToCol( x )) >= 0 )
4367 {
4368 m_selection->SelectCol( col,
4369 event.ControlDown(),
4370 event.ShiftDown(),
4371 event.AltDown(),
4372 event.MetaDown() );
4373 }
4374
4375 // default label to suppress warnings about "enumeration value
4376 // 'xxx' not handled in switch
4377 default:
4378 break;
4379 }
4380 }
4381 return;
4382 }
4383
4384 m_isDragging = FALSE;
4385
4386
4387 // ------------ Entering or leaving the window
4388 //
4389 if ( event.Entering() || event.Leaving() )
4390 {
4391 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
4392 }
4393
4394
4395 // ------------ Left button pressed
4396 //
4397 else if ( event.LeftDown() )
4398 {
4399 // don't send a label click event for a hit on the
4400 // edge of the col label - this is probably the user
4401 // wanting to resize the col
4402 //
4403 if ( XToEdgeOfCol(x) < 0 )
4404 {
4405 col = XToCol(x);
4406 if ( col >= 0 &&
4407 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
4408 {
4409 if ( !event.ShiftDown() && !event.ControlDown() )
4410 ClearSelection();
4411 if ( event.ShiftDown() )
4412 m_selection->SelectBlock( 0,
4413 m_currentCellCoords.GetCol(),
4414 GetNumberRows() - 1, col,
4415 event.ControlDown(),
4416 event.ShiftDown(),
4417 event.AltDown(),
4418 event.MetaDown() );
4419 else
4420 m_selection->SelectCol( col,
4421 event.ControlDown(),
4422 event.ShiftDown(),
4423 event.AltDown(),
4424 event.MetaDown() );
4425 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin);
4426 }
4427 }
4428 else
4429 {
4430 // starting to drag-resize a col
4431 //
4432 if ( CanDragColSize() )
4433 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
4434 }
4435 }
4436
4437
4438 // ------------ Left double click
4439 //
4440 if ( event.LeftDClick() )
4441 {
4442 if ( XToEdgeOfCol(x) < 0 )
4443 {
4444 col = XToCol(x);
4445 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
4446 }
4447 }
4448
4449
4450 // ------------ Left button released
4451 //
4452 else if ( event.LeftUp() )
4453 {
4454 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4455 {
4456 DoEndDragResizeCol();
4457
4458 // Note: we are ending the event *after* doing
4459 // default processing in this case
4460 //
4461 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
4462 }
4463
4464 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
4465 m_dragLastPos = -1;
4466 }
4467
4468
4469 // ------------ Right button down
4470 //
4471 else if ( event.RightDown() )
4472 {
4473 col = XToCol(x);
4474 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
4475 {
4476 // no default action at the moment
4477 }
4478 }
4479
4480
4481 // ------------ Right double click
4482 //
4483 else if ( event.RightDClick() )
4484 {
4485 col = XToCol(x);
4486 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
4487 {
4488 // no default action at the moment
4489 }
4490 }
4491
4492
4493 // ------------ No buttons down and mouse moving
4494 //
4495 else if ( event.Moving() )
4496 {
4497 m_dragRowOrCol = XToEdgeOfCol( x );
4498 if ( m_dragRowOrCol >= 0 )
4499 {
4500 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4501 {
4502 // don't capture the cursor yet
4503 if ( CanDragColSize() )
4504 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE);
4505 }
4506 }
4507 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
4508 {
4509 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, FALSE);
4510 }
4511 }
4512 }
4513
4514
4515 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
4516 {
4517 if ( event.LeftDown() )
4518 {
4519 // indicate corner label by having both row and
4520 // col args == -1
4521 //
4522 if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
4523 {
4524 SelectAll();
4525 }
4526 }
4527
4528 else if ( event.LeftDClick() )
4529 {
4530 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
4531 }
4532
4533 else if ( event.RightDown() )
4534 {
4535 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
4536 {
4537 // no default action at the moment
4538 }
4539 }
4540
4541 else if ( event.RightDClick() )
4542 {
4543 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
4544 {
4545 // no default action at the moment
4546 }
4547 }
4548 }
4549
4550 void wxGrid::ChangeCursorMode(CursorMode mode,
4551 wxWindow *win,
4552 bool captureMouse)
4553 {
4554 #ifdef __WXDEBUG__
4555 static const wxChar *cursorModes[] =
4556 {
4557 _T("SELECT_CELL"),
4558 _T("RESIZE_ROW"),
4559 _T("RESIZE_COL"),
4560 _T("SELECT_ROW"),
4561 _T("SELECT_COL")
4562 };
4563
4564 wxLogTrace(_T("grid"),
4565 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
4566 win == m_colLabelWin ? _T("colLabelWin")
4567 : win ? _T("rowLabelWin")
4568 : _T("gridWin"),
4569 cursorModes[m_cursorMode], cursorModes[mode]);
4570 #endif // __WXDEBUG__
4571
4572 if ( mode == m_cursorMode )
4573 return;
4574
4575 if ( !win )
4576 {
4577 // by default use the grid itself
4578 win = m_gridWin;
4579 }
4580
4581 if ( m_winCapture )
4582 {
4583 m_winCapture->ReleaseMouse();
4584 m_winCapture = (wxWindow *)NULL;
4585 }
4586
4587 m_cursorMode = mode;
4588
4589 switch ( m_cursorMode )
4590 {
4591 case WXGRID_CURSOR_RESIZE_ROW:
4592 win->SetCursor( m_rowResizeCursor );
4593 break;
4594
4595 case WXGRID_CURSOR_RESIZE_COL:
4596 win->SetCursor( m_colResizeCursor );
4597 break;
4598
4599 default:
4600 win->SetCursor( *wxSTANDARD_CURSOR );
4601 }
4602
4603 // we need to capture mouse when resizing
4604 bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
4605 m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
4606
4607 if ( captureMouse && resize )
4608 {
4609 win->CaptureMouse();
4610 m_winCapture = win;
4611 }
4612 }
4613
4614 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
4615 {
4616 int x, y;
4617 wxPoint pos( event.GetPosition() );
4618 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
4619
4620 wxGridCellCoords coords;
4621 XYToCell( x, y, coords );
4622
4623 if ( event.Dragging() )
4624 {
4625 //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol());
4626
4627 // Don't start doing anything until the mouse has been drug at
4628 // least 3 pixels in any direction...
4629 if (! m_isDragging)
4630 {
4631 if (m_startDragPos == wxDefaultPosition)
4632 {
4633 m_startDragPos = pos;
4634 return;
4635 }
4636 if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4)
4637 return;
4638 }
4639
4640 m_isDragging = TRUE;
4641 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4642 {
4643 // Hide the edit control, so it
4644 // won't interfer with drag-shrinking.
4645 if ( IsCellEditControlShown() )
4646 {
4647 HideCellEditControl();
4648 SaveEditControlValue();
4649 }
4650
4651 // Have we captured the mouse yet?
4652 if (! m_winCapture)
4653 {
4654 m_winCapture = m_gridWin;
4655 m_winCapture->CaptureMouse();
4656 }
4657
4658 if ( coords != wxGridNoCellCoords )
4659 {
4660 if ( event.ControlDown() )
4661 {
4662 if ( m_selectingKeyboard == wxGridNoCellCoords)
4663 m_selectingKeyboard = coords;
4664 SelectBlock ( m_selectingKeyboard, coords );
4665 }
4666 else
4667 {
4668 if ( !IsSelection() )
4669 {
4670 SelectBlock( coords, coords );
4671 }
4672 else
4673 {
4674 SelectBlock( m_currentCellCoords, coords );
4675 }
4676 }
4677
4678 if (! IsVisible(coords))
4679 {
4680 MakeCellVisible(coords);
4681 // TODO: need to introduce a delay or something here. The
4682 // scrolling is way to fast, at least on MSW - also on GTK.
4683 }
4684 }
4685 }
4686 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
4687 {
4688 int cw, ch, left, dummy;
4689 m_gridWin->GetClientSize( &cw, &ch );
4690 CalcUnscrolledPosition( 0, 0, &left, &dummy );
4691
4692 wxClientDC dc( m_gridWin );
4693 PrepareDC( dc );
4694 y = wxMax( y, GetRowTop(m_dragRowOrCol) +
4695 GetRowMinimalHeight(m_dragRowOrCol) );
4696 dc.SetLogicalFunction(wxINVERT);
4697 if ( m_dragLastPos >= 0 )
4698 {
4699 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
4700 }
4701 dc.DrawLine( left, y, left+cw, y );
4702 m_dragLastPos = y;
4703 }
4704 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4705 {
4706 int cw, ch, dummy, top;
4707 m_gridWin->GetClientSize( &cw, &ch );
4708 CalcUnscrolledPosition( 0, 0, &dummy, &top );
4709
4710 wxClientDC dc( m_gridWin );
4711 PrepareDC( dc );
4712 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
4713 GetColMinimalWidth(m_dragRowOrCol) );
4714 dc.SetLogicalFunction(wxINVERT);
4715 if ( m_dragLastPos >= 0 )
4716 {
4717 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
4718 }
4719 dc.DrawLine( x, top, x, top+ch );
4720 m_dragLastPos = x;
4721 }
4722
4723 return;
4724 }
4725
4726 m_isDragging = FALSE;
4727 m_startDragPos = wxDefaultPosition;
4728
4729 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
4730 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
4731 // wxGTK
4732 #if 0
4733 if ( event.Entering() || event.Leaving() )
4734 {
4735 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4736 m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
4737 }
4738 else
4739 #endif // 0
4740
4741 // ------------ Left button pressed
4742 //
4743 if ( event.LeftDown() && coords != wxGridNoCellCoords )
4744 {
4745 if ( !SendEvent( wxEVT_GRID_CELL_LEFT_CLICK,
4746 coords.GetRow(),
4747 coords.GetCol(),
4748 event ) )
4749 {
4750 if ( !event.ControlDown() )
4751 ClearSelection();
4752 if ( event.ShiftDown() )
4753 {
4754 m_selection->SelectBlock( m_currentCellCoords.GetRow(),
4755 m_currentCellCoords.GetCol(),
4756 coords.GetRow(),
4757 coords.GetCol(),
4758 event.ControlDown(),
4759 event.ShiftDown(),
4760 event.AltDown(),
4761 event.MetaDown() );
4762 }
4763 else if ( XToEdgeOfCol(x) < 0 &&
4764 YToEdgeOfRow(y) < 0 )
4765 {
4766 DisableCellEditControl();
4767 MakeCellVisible( coords );
4768
4769 // if this is the second click on this cell then start
4770 // the edit control
4771 if ( m_waitForSlowClick &&
4772 (coords == m_currentCellCoords) &&
4773 CanEnableCellControl())
4774 {
4775 EnableCellEditControl();
4776
4777 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
4778 wxGridCellEditor *editor = attr->GetEditor(this,
4779 coords.GetRow(),
4780 coords.GetCol());
4781 editor->StartingClick();
4782 editor->DecRef();
4783 attr->DecRef();
4784
4785 m_waitForSlowClick = FALSE;
4786 }
4787 else
4788 {
4789 if ( event.ControlDown() )
4790 {
4791 m_selection->ToggleCellSelection( coords.GetRow(),
4792 coords.GetCol(),
4793 event.ControlDown(),
4794 event.ShiftDown(),
4795 event.AltDown(),
4796 event.MetaDown() );
4797 m_selectingTopLeft = wxGridNoCellCoords;
4798 m_selectingBottomRight = wxGridNoCellCoords;
4799 m_selectingKeyboard = coords;
4800 }
4801 else
4802 {
4803 SetCurrentCell( coords );
4804 if ( m_selection->GetSelectionMode()
4805 != wxGrid::wxGridSelectCells)
4806 SelectBlock( coords, coords );
4807 }
4808 m_waitForSlowClick = TRUE;
4809 }
4810 }
4811 }
4812 }
4813
4814
4815 // ------------ Left double click
4816 //
4817 else if ( event.LeftDClick() && coords != wxGridNoCellCoords )
4818 {
4819 DisableCellEditControl();
4820
4821 if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 )
4822 {
4823 SendEvent( wxEVT_GRID_CELL_LEFT_DCLICK,
4824 coords.GetRow(),
4825 coords.GetCol(),
4826 event );
4827 }
4828 }
4829
4830
4831 // ------------ Left button released
4832 //
4833 else if ( event.LeftUp() )
4834 {
4835 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4836 {
4837 if ( m_selectingTopLeft != wxGridNoCellCoords &&
4838 m_selectingBottomRight != wxGridNoCellCoords )
4839 {
4840 if (m_winCapture)
4841 {
4842 m_winCapture->ReleaseMouse();
4843 m_winCapture = NULL;
4844 }
4845 m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
4846 m_selectingTopLeft.GetCol(),
4847 m_selectingBottomRight.GetRow(),
4848 m_selectingBottomRight.GetCol(),
4849 event.ControlDown(),
4850 event.ShiftDown(),
4851 event.AltDown(),
4852 event.MetaDown() );
4853 m_selectingTopLeft = wxGridNoCellCoords;
4854 m_selectingBottomRight = wxGridNoCellCoords;
4855 }
4856
4857 // Show the edit control, if it has been hidden for
4858 // drag-shrinking.
4859 ShowCellEditControl();
4860 }
4861 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
4862 {
4863 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4864 DoEndDragResizeRow();
4865
4866 // Note: we are ending the event *after* doing
4867 // default processing in this case
4868 //
4869 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
4870 }
4871 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4872 {
4873 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4874 DoEndDragResizeCol();
4875
4876 // Note: we are ending the event *after* doing
4877 // default processing in this case
4878 //
4879 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
4880 }
4881
4882 m_dragLastPos = -1;
4883 }
4884
4885
4886 // ------------ Right button down
4887 //
4888 else if ( event.RightDown() && coords != wxGridNoCellCoords )
4889 {
4890 DisableCellEditControl();
4891 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_CLICK,
4892 coords.GetRow(),
4893 coords.GetCol(),
4894 event ) )
4895 {
4896 // no default action at the moment
4897 }
4898 }
4899
4900
4901 // ------------ Right double click
4902 //
4903 else if ( event.RightDClick() && coords != wxGridNoCellCoords )
4904 {
4905 DisableCellEditControl();
4906 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_DCLICK,
4907 coords.GetRow(),
4908 coords.GetCol(),
4909 event ) )
4910 {
4911 // no default action at the moment
4912 }
4913 }
4914
4915 // ------------ Moving and no button action
4916 //
4917 else if ( event.Moving() && !event.IsButton() )
4918 {
4919 int dragRow = YToEdgeOfRow( y );
4920 int dragCol = XToEdgeOfCol( x );
4921
4922 // Dragging on the corner of a cell to resize in both
4923 // directions is not implemented yet...
4924 //
4925 if ( dragRow >= 0 && dragCol >= 0 )
4926 {
4927 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4928 return;
4929 }
4930
4931 if ( dragRow >= 0 )
4932 {
4933 m_dragRowOrCol = dragRow;
4934
4935 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4936 {
4937 if ( CanDragRowSize() && CanDragGridSize() )
4938 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
4939 }
4940
4941 if ( dragCol >= 0 )
4942 {
4943 m_dragRowOrCol = dragCol;
4944 }
4945
4946 return;
4947 }
4948
4949 if ( dragCol >= 0 )
4950 {
4951 m_dragRowOrCol = dragCol;
4952
4953 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4954 {
4955 if ( CanDragColSize() && CanDragGridSize() )
4956 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
4957 }
4958
4959 return;
4960 }
4961
4962 // Neither on a row or col edge
4963 //
4964 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
4965 {
4966 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4967 }
4968 }
4969 }
4970
4971
4972 void wxGrid::DoEndDragResizeRow()
4973 {
4974 if ( m_dragLastPos >= 0 )
4975 {
4976 // erase the last line and resize the row
4977 //
4978 int cw, ch, left, dummy;
4979 m_gridWin->GetClientSize( &cw, &ch );
4980 CalcUnscrolledPosition( 0, 0, &left, &dummy );
4981
4982 wxClientDC dc( m_gridWin );
4983 PrepareDC( dc );
4984 dc.SetLogicalFunction( wxINVERT );
4985 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
4986 HideCellEditControl();
4987 SaveEditControlValue();
4988
4989 int rowTop = GetRowTop(m_dragRowOrCol);
4990 SetRowSize( m_dragRowOrCol,
4991 wxMax( m_dragLastPos - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
4992
4993 if ( !GetBatchCount() )
4994 {
4995 // Only needed to get the correct rect.y:
4996 wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
4997 rect.x = 0;
4998 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
4999 rect.width = m_rowLabelWidth;
5000 rect.height = ch - rect.y;
5001 m_rowLabelWin->Refresh( TRUE, &rect );
5002 rect.width = cw;
5003 m_gridWin->Refresh( FALSE, &rect );
5004 }
5005
5006 ShowCellEditControl();
5007 }
5008 }
5009
5010
5011 void wxGrid::DoEndDragResizeCol()
5012 {
5013 if ( m_dragLastPos >= 0 )
5014 {
5015 // erase the last line and resize the col
5016 //
5017 int cw, ch, dummy, top;
5018 m_gridWin->GetClientSize( &cw, &ch );
5019 CalcUnscrolledPosition( 0, 0, &dummy, &top );
5020
5021 wxClientDC dc( m_gridWin );
5022 PrepareDC( dc );
5023 dc.SetLogicalFunction( wxINVERT );
5024 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
5025 HideCellEditControl();
5026 SaveEditControlValue();
5027
5028 int colLeft = GetColLeft(m_dragRowOrCol);
5029 SetColSize( m_dragRowOrCol,
5030 wxMax( m_dragLastPos - colLeft,
5031 GetColMinimalWidth(m_dragRowOrCol) ) );
5032
5033 if ( !GetBatchCount() )
5034 {
5035 // Only needed to get the correct rect.x:
5036 wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
5037 rect.y = 0;
5038 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
5039 rect.width = cw - rect.x;
5040 rect.height = m_colLabelHeight;
5041 m_colLabelWin->Refresh( TRUE, &rect );
5042 rect.height = ch;
5043 m_gridWin->Refresh( FALSE, &rect );
5044 }
5045
5046 ShowCellEditControl();
5047 }
5048 }
5049
5050
5051
5052 //
5053 // ------ interaction with data model
5054 //
5055 bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
5056 {
5057 switch ( msg.GetId() )
5058 {
5059 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
5060 return GetModelValues();
5061
5062 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
5063 return SetModelValues();
5064
5065 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
5066 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
5067 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
5068 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
5069 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
5070 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
5071 return Redimension( msg );
5072
5073 default:
5074 return FALSE;
5075 }
5076 }
5077
5078
5079
5080 // The behaviour of this function depends on the grid table class
5081 // Clear() function. For the default wxGridStringTable class the
5082 // behavious is to replace all cell contents with wxEmptyString but
5083 // not to change the number of rows or cols.
5084 //
5085 void wxGrid::ClearGrid()
5086 {
5087 if ( m_table )
5088 {
5089 if (IsCellEditControlEnabled())
5090 DisableCellEditControl();
5091
5092 m_table->Clear();
5093 if ( !GetBatchCount() ) m_gridWin->Refresh();
5094 }
5095 }
5096
5097
5098 bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
5099 {
5100 // TODO: something with updateLabels flag
5101
5102 if ( !m_created )
5103 {
5104 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
5105 return FALSE;
5106 }
5107
5108 if ( m_table )
5109 {
5110 if (IsCellEditControlEnabled())
5111 DisableCellEditControl();
5112
5113 return m_table->InsertRows( pos, numRows );
5114
5115 // the table will have sent the results of the insert row
5116 // operation to this view object as a grid table message
5117 }
5118 return FALSE;
5119 }
5120
5121
5122 bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
5123 {
5124 // TODO: something with updateLabels flag
5125
5126 if ( !m_created )
5127 {
5128 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
5129 return FALSE;
5130 }
5131
5132 return ( m_table && m_table->AppendRows( numRows ) );
5133 // the table will have sent the results of the append row
5134 // operation to this view object as a grid table message
5135 }
5136
5137
5138 bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
5139 {
5140 // TODO: something with updateLabels flag
5141
5142 if ( !m_created )
5143 {
5144 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
5145 return FALSE;
5146 }
5147
5148 if ( m_table )
5149 {
5150 if (IsCellEditControlEnabled())
5151 DisableCellEditControl();
5152
5153 return (m_table->DeleteRows( pos, numRows ));
5154 // the table will have sent the results of the delete row
5155 // operation to this view object as a grid table message
5156 }
5157 return FALSE;
5158 }
5159
5160
5161 bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
5162 {
5163 // TODO: something with updateLabels flag
5164
5165 if ( !m_created )
5166 {
5167 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
5168 return FALSE;
5169 }
5170
5171 if ( m_table )
5172 {
5173 if (IsCellEditControlEnabled())
5174 DisableCellEditControl();
5175
5176 return m_table->InsertCols( pos, numCols );
5177 // the table will have sent the results of the insert col
5178 // operation to this view object as a grid table message
5179 }
5180 return FALSE;
5181 }
5182
5183
5184 bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
5185 {
5186 // TODO: something with updateLabels flag
5187
5188 if ( !m_created )
5189 {
5190 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
5191 return FALSE;
5192 }
5193
5194 return ( m_table && m_table->AppendCols( numCols ) );
5195 // the table will have sent the results of the append col
5196 // operation to this view object as a grid table message
5197 }
5198
5199
5200 bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
5201 {
5202 // TODO: something with updateLabels flag
5203
5204 if ( !m_created )
5205 {
5206 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
5207 return FALSE;
5208 }
5209
5210 if ( m_table )
5211 {
5212 if (IsCellEditControlEnabled())
5213 DisableCellEditControl();
5214
5215 return ( m_table->DeleteCols( pos, numCols ) );
5216 // the table will have sent the results of the delete col
5217 // operation to this view object as a grid table message
5218 }
5219 return FALSE;
5220 }
5221
5222
5223
5224 //
5225 // ----- event handlers
5226 //
5227
5228 // Generate a grid event based on a mouse event and
5229 // return the result of ProcessEvent()
5230 //
5231 bool wxGrid::SendEvent( const wxEventType type,
5232 int row, int col,
5233 wxMouseEvent& mouseEv )
5234 {
5235 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
5236 {
5237 int rowOrCol = (row == -1 ? col : row);
5238
5239 wxGridSizeEvent gridEvt( GetId(),
5240 type,
5241 this,
5242 rowOrCol,
5243 mouseEv.GetX() + GetColLabelSize(),
5244 mouseEv.GetY() + GetRowLabelSize(),
5245 mouseEv.ControlDown(),
5246 mouseEv.ShiftDown(),
5247 mouseEv.AltDown(),
5248 mouseEv.MetaDown() );
5249
5250 return GetEventHandler()->ProcessEvent(gridEvt);
5251 }
5252 else if ( type == wxEVT_GRID_RANGE_SELECT )
5253 {
5254 // Right now, it should _never_ end up here!
5255 wxGridRangeSelectEvent gridEvt( GetId(),
5256 type,
5257 this,
5258 m_selectingTopLeft,
5259 m_selectingBottomRight,
5260 TRUE,
5261 mouseEv.ControlDown(),
5262 mouseEv.ShiftDown(),
5263 mouseEv.AltDown(),
5264 mouseEv.MetaDown() );
5265
5266 return GetEventHandler()->ProcessEvent(gridEvt);
5267 }
5268 else
5269 {
5270 wxGridEvent gridEvt( GetId(),
5271 type,
5272 this,
5273 row, col,
5274 mouseEv.GetX() + GetColLabelSize(),
5275 mouseEv.GetY() + GetRowLabelSize(),
5276 FALSE,
5277 mouseEv.ControlDown(),
5278 mouseEv.ShiftDown(),
5279 mouseEv.AltDown(),
5280 mouseEv.MetaDown() );
5281
5282 return GetEventHandler()->ProcessEvent(gridEvt);
5283 }
5284 }
5285
5286
5287 // Generate a grid event of specified type and return the result
5288 // of ProcessEvent().
5289 //
5290 bool wxGrid::SendEvent( const wxEventType type,
5291 int row, int col )
5292 {
5293 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
5294 {
5295 int rowOrCol = (row == -1 ? col : row);
5296
5297 wxGridSizeEvent gridEvt( GetId(),
5298 type,
5299 this,
5300 rowOrCol );
5301
5302 return GetEventHandler()->ProcessEvent(gridEvt);
5303 }
5304 else
5305 {
5306 wxGridEvent gridEvt( GetId(),
5307 type,
5308 this,
5309 row, col );
5310
5311 return GetEventHandler()->ProcessEvent(gridEvt);
5312 }
5313 }
5314
5315
5316 void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
5317 {
5318 wxPaintDC dc(this); // needed to prevent zillions of paint events on MSW
5319 }
5320
5321
5322 // This is just here to make sure that CalcDimensions gets called when
5323 // the grid view is resized... then the size event is skipped to allow
5324 // the box sizers to handle everything
5325 //
5326 void wxGrid::OnSize( wxSizeEvent& WXUNUSED(event) )
5327 {
5328 CalcWindowSizes();
5329 CalcDimensions();
5330 }
5331
5332
5333 void wxGrid::OnKeyDown( wxKeyEvent& event )
5334 {
5335 if ( m_inOnKeyDown )
5336 {
5337 // shouldn't be here - we are going round in circles...
5338 //
5339 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") );
5340 }
5341
5342 m_inOnKeyDown = TRUE;
5343
5344 // propagate the event up and see if it gets processed
5345 //
5346 wxWindow *parent = GetParent();
5347 wxKeyEvent keyEvt( event );
5348 keyEvt.SetEventObject( parent );
5349
5350 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
5351 {
5352
5353 // try local handlers
5354 //
5355 switch ( event.KeyCode() )
5356 {
5357 case WXK_UP:
5358 if ( event.ControlDown() )
5359 {
5360 MoveCursorUpBlock( event.ShiftDown() );
5361 }
5362 else
5363 {
5364 MoveCursorUp( event.ShiftDown() );
5365 }
5366 break;
5367
5368 case WXK_DOWN:
5369 if ( event.ControlDown() )
5370 {
5371 MoveCursorDownBlock( event.ShiftDown() );
5372 }
5373 else
5374 {
5375 MoveCursorDown( event.ShiftDown() );
5376 }
5377 break;
5378
5379 case WXK_LEFT:
5380 if ( event.ControlDown() )
5381 {
5382 MoveCursorLeftBlock( event.ShiftDown() );
5383 }
5384 else
5385 {
5386 MoveCursorLeft( event.ShiftDown() );
5387 }
5388 break;
5389
5390 case WXK_RIGHT:
5391 if ( event.ControlDown() )
5392 {
5393 MoveCursorRightBlock( event.ShiftDown() );
5394 }
5395 else
5396 {
5397 MoveCursorRight( event.ShiftDown() );
5398 }
5399 break;
5400
5401 case WXK_RETURN:
5402 if ( event.ControlDown() )
5403 {
5404 event.Skip(); // to let the edit control have the return
5405 }
5406 else
5407 {
5408 if ( GetGridCursorRow() < GetNumberRows()-1 )
5409 {
5410 MoveCursorDown( event.ShiftDown() );
5411 }
5412 else
5413 {
5414 // at the bottom of a column
5415 HideCellEditControl();
5416 SaveEditControlValue();
5417 }
5418 }
5419 break;
5420
5421 case WXK_ESCAPE:
5422 ClearSelection();
5423 break;
5424
5425 case WXK_TAB:
5426 if (event.ShiftDown())
5427 {
5428 if ( GetGridCursorCol() > 0 )
5429 {
5430 MoveCursorLeft( FALSE );
5431 }
5432 else
5433 {
5434 // at left of grid
5435 HideCellEditControl();
5436 SaveEditControlValue();
5437 }
5438 }
5439 else
5440 {
5441 if ( GetGridCursorCol() < GetNumberCols()-1 )
5442 {
5443 MoveCursorRight( FALSE );
5444 }
5445 else
5446 {
5447 // at right of grid
5448 HideCellEditControl();
5449 SaveEditControlValue();
5450 }
5451 }
5452 break;
5453
5454 case WXK_HOME:
5455 if ( event.ControlDown() )
5456 {
5457 MakeCellVisible( 0, 0 );
5458 SetCurrentCell( 0, 0 );
5459 }
5460 else
5461 {
5462 event.Skip();
5463 }
5464 break;
5465
5466 case WXK_END:
5467 if ( event.ControlDown() )
5468 {
5469 MakeCellVisible( m_numRows-1, m_numCols-1 );
5470 SetCurrentCell( m_numRows-1, m_numCols-1 );
5471 }
5472 else
5473 {
5474 event.Skip();
5475 }
5476 break;
5477
5478 case WXK_PRIOR:
5479 MovePageUp();
5480 break;
5481
5482 case WXK_NEXT:
5483 MovePageDown();
5484 break;
5485
5486 case WXK_SPACE:
5487 if ( event.ControlDown() )
5488 {
5489 m_selection->ToggleCellSelection( m_currentCellCoords.GetRow(),
5490 m_currentCellCoords.GetCol(),
5491 event.ControlDown(),
5492 event.ShiftDown(),
5493 event.AltDown(),
5494 event.MetaDown() );
5495 break;
5496 }
5497 if ( !IsEditable() )
5498 {
5499 MoveCursorRight( FALSE );
5500 break;
5501 }
5502 // Otherwise fall through to default
5503
5504 default:
5505 // is it possible to edit the current cell at all?
5506 if ( !IsCellEditControlEnabled() && CanEnableCellControl() )
5507 {
5508 // yes, now check whether the cells editor accepts the key
5509 int row = m_currentCellCoords.GetRow();
5510 int col = m_currentCellCoords.GetCol();
5511 wxGridCellAttr* attr = GetCellAttr(row, col);
5512 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
5513
5514 // <F2> is special and will always start editing, for
5515 // other keys - ask the editor itself
5516 if ( (event.KeyCode() == WXK_F2 && !event.HasModifiers())
5517 || editor->IsAcceptedKey(event) )
5518 {
5519 EnableCellEditControl();
5520 editor->StartingKey(event);
5521 }
5522 else
5523 {
5524 event.Skip();
5525 }
5526
5527 editor->DecRef();
5528 attr->DecRef();
5529 }
5530 else
5531 {
5532 // let others process char events with modifiers or all
5533 // char events for readonly cells
5534 event.Skip();
5535 }
5536 break;
5537 }
5538 }
5539
5540 m_inOnKeyDown = FALSE;
5541 }
5542
5543 void wxGrid::OnKeyUp( wxKeyEvent& event )
5544 {
5545 // try local handlers
5546 //
5547 if ( event.KeyCode() == WXK_SHIFT )
5548 {
5549 if ( m_selectingTopLeft != wxGridNoCellCoords &&
5550 m_selectingBottomRight != wxGridNoCellCoords )
5551 m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
5552 m_selectingTopLeft.GetCol(),
5553 m_selectingBottomRight.GetRow(),
5554 m_selectingBottomRight.GetCol(),
5555 event.ControlDown(),
5556 TRUE,
5557 event.AltDown(),
5558 event.MetaDown() );
5559 m_selectingTopLeft = wxGridNoCellCoords;
5560 m_selectingBottomRight = wxGridNoCellCoords;
5561 m_selectingKeyboard = wxGridNoCellCoords;
5562 }
5563 }
5564
5565 void wxGrid::OnEraseBackground(wxEraseEvent&)
5566 {
5567 }
5568
5569 void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
5570 {
5571 if ( SendEvent( wxEVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
5572 {
5573 // the event has been intercepted - do nothing
5574 return;
5575 }
5576
5577 wxClientDC dc(m_gridWin);
5578 PrepareDC(dc);
5579
5580 if ( m_currentCellCoords != wxGridNoCellCoords )
5581 {
5582 HideCellEditControl();
5583 DisableCellEditControl();
5584
5585 if ( IsVisible( m_currentCellCoords ) )
5586 {
5587 wxRect r;
5588 r = BlockToDeviceRect(m_currentCellCoords, m_currentCellCoords);
5589 if ( !m_gridLinesEnabled )
5590 {
5591 r.x--;
5592 r.y--;
5593 r.width++;
5594 r.height++;
5595 }
5596
5597 CalcCellsExposed( r );
5598
5599 // Otherwise refresh redraws the highlight!
5600 m_currentCellCoords = coords;
5601
5602 DrawGridCellArea(dc);
5603 DrawAllGridLines( dc, r );
5604 }
5605 }
5606
5607 m_currentCellCoords = coords;
5608
5609 wxGridCellAttr* attr = GetCellAttr(coords);
5610 DrawCellHighlight(dc, attr);
5611 attr->DecRef();
5612 }
5613
5614
5615 //
5616 // ------ functions to get/send data (see also public functions)
5617 //
5618
5619 bool wxGrid::GetModelValues()
5620 {
5621 if ( m_table )
5622 {
5623 // all we need to do is repaint the grid
5624 //
5625 m_gridWin->Refresh();
5626 return TRUE;
5627 }
5628
5629 return FALSE;
5630 }
5631
5632
5633 bool wxGrid::SetModelValues()
5634 {
5635 int row, col;
5636
5637 if ( m_table )
5638 {
5639 for ( row = 0; row < m_numRows; row++ )
5640 {
5641 for ( col = 0; col < m_numCols; col++ )
5642 {
5643 m_table->SetValue( row, col, GetCellValue(row, col) );
5644 }
5645 }
5646
5647 return TRUE;
5648 }
5649
5650 return FALSE;
5651 }
5652
5653
5654
5655 // Note - this function only draws cells that are in the list of
5656 // exposed cells (usually set from the update region by
5657 // CalcExposedCells)
5658 //
5659 void wxGrid::DrawGridCellArea( wxDC& dc )
5660 {
5661 if ( !m_numRows || !m_numCols ) return;
5662
5663 size_t i;
5664 size_t numCells = m_cellsExposed.GetCount();
5665
5666 for ( i = 0; i < numCells; i++ )
5667 {
5668 DrawCell( dc, m_cellsExposed[i] );
5669 }
5670 }
5671
5672
5673 void wxGrid::DrawGridSpace( wxDC& dc )
5674 {
5675 int cw, ch;
5676 m_gridWin->GetClientSize( &cw, &ch );
5677
5678 int right, bottom;
5679 CalcUnscrolledPosition( cw, ch, &right, &bottom );
5680
5681 int rightCol = m_numCols > 0 ? GetColRight(m_numCols - 1) : 0;
5682 int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0 ;
5683
5684 if ( right > rightCol || bottom > bottomRow )
5685 {
5686 int left, top;
5687 CalcUnscrolledPosition( 0, 0, &left, &top );
5688
5689 dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) );
5690 dc.SetPen( *wxTRANSPARENT_PEN );
5691
5692 if ( right > rightCol )
5693 {
5694 dc.DrawRectangle( rightCol, top, right - rightCol, ch);
5695 }
5696
5697 if ( bottom > bottomRow )
5698 {
5699 dc.DrawRectangle( left, bottomRow, cw, bottom - bottomRow);
5700 }
5701 }
5702 }
5703
5704
5705 void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
5706 {
5707 int row = coords.GetRow();
5708 int col = coords.GetCol();
5709
5710 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
5711 return;
5712
5713 // we draw the cell border ourselves
5714 #if !WXGRID_DRAW_LINES
5715 if ( m_gridLinesEnabled )
5716 DrawCellBorder( dc, coords );
5717 #endif
5718
5719 wxGridCellAttr* attr = GetCellAttr(row, col);
5720
5721 bool isCurrent = coords == m_currentCellCoords;
5722
5723 wxRect rect = CellToRect( row, col );
5724
5725 // if the editor is shown, we should use it and not the renderer
5726 // Note: However, only if it is really _shown_, i.e. not hidden!
5727 if ( isCurrent && IsCellEditControlShown() )
5728 {
5729 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
5730 editor->PaintBackground(rect, attr);
5731 editor->DecRef();
5732 }
5733 else
5734 {
5735 // but all the rest is drawn by the cell renderer and hence may be
5736 // customized
5737 wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col);
5738 renderer->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
5739 renderer->DecRef();
5740 }
5741
5742 attr->DecRef();
5743 }
5744
5745 void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr )
5746 {
5747 int row = m_currentCellCoords.GetRow();
5748 int col = m_currentCellCoords.GetCol();
5749
5750 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
5751 return;
5752
5753 wxRect rect = CellToRect(row, col);
5754
5755 // hmmm... what could we do here to show that the cell is disabled?
5756 // for now, I just draw a thinner border than for the other ones, but
5757 // it doesn't look really good
5758 dc.SetPen(wxPen(m_cellHighlightColour, attr->IsReadOnly() ? 1 : 3, wxSOLID));
5759 dc.SetBrush(*wxTRANSPARENT_BRUSH);
5760
5761 dc.DrawRectangle(rect);
5762
5763 #if 0
5764 // VZ: my experiments with 3d borders...
5765
5766 // how to properly set colours for arbitrary bg?
5767 wxCoord x1 = rect.x,
5768 y1 = rect.y,
5769 x2 = rect.x + rect.width -1,
5770 y2 = rect.y + rect.height -1;
5771
5772 dc.SetPen(*wxWHITE_PEN);
5773 dc.DrawLine(x1, y1, x2, y1);
5774 dc.DrawLine(x1, y1, x1, y2);
5775
5776 dc.DrawLine(x1 + 1, y2 - 1, x2 - 1, y2 - 1);
5777 dc.DrawLine(x2 - 1, y1 + 1, x2 - 1, y2 );
5778
5779 dc.SetPen(*wxBLACK_PEN);
5780 dc.DrawLine(x1, y2, x2, y2);
5781 dc.DrawLine(x2, y1, x2, y2+1);
5782 #endif // 0
5783 }
5784
5785
5786 void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
5787 {
5788 int row = coords.GetRow();
5789 int col = coords.GetCol();
5790 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
5791 return;
5792
5793 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
5794
5795 // right hand border
5796 //
5797 dc.DrawLine( GetColRight(col), GetRowTop(row),
5798 GetColRight(col), GetRowBottom(row) );
5799
5800 // bottom border
5801 //
5802 dc.DrawLine( GetColLeft(col), GetRowBottom(row),
5803 GetColRight(col), GetRowBottom(row) );
5804 }
5805
5806 void wxGrid::DrawHighlight(wxDC& dc)
5807 {
5808 // This if block was previously in wxGrid::OnPaint but that doesn't
5809 // seem to get called under wxGTK - MB
5810 //
5811 if ( m_currentCellCoords == wxGridNoCellCoords &&
5812 m_numRows && m_numCols )
5813 {
5814 m_currentCellCoords.Set(0, 0);
5815 }
5816
5817 if ( IsCellEditControlShown() )
5818 {
5819 // don't show highlight when the edit control is shown
5820 return;
5821 }
5822
5823 // if the active cell was repainted, repaint its highlight too because it
5824 // might have been damaged by the grid lines
5825 size_t count = m_cellsExposed.GetCount();
5826 for ( size_t n = 0; n < count; n++ )
5827 {
5828 if ( m_cellsExposed[n] == m_currentCellCoords )
5829 {
5830 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
5831 DrawCellHighlight(dc, attr);
5832 attr->DecRef();
5833
5834 break;
5835 }
5836 }
5837 }
5838
5839 // TODO: remove this ???
5840 // This is used to redraw all grid lines e.g. when the grid line colour
5841 // has been changed
5842 //
5843 void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED_GTK(reg) )
5844 {
5845 if ( !m_gridLinesEnabled ||
5846 !m_numRows ||
5847 !m_numCols ) return;
5848
5849 int top, bottom, left, right;
5850
5851 #if 0 //#ifndef __WXGTK__
5852 if (reg.IsEmpty())
5853 {
5854 int cw, ch;
5855 m_gridWin->GetClientSize(&cw, &ch);
5856
5857 // virtual coords of visible area
5858 //
5859 CalcUnscrolledPosition( 0, 0, &left, &top );
5860 CalcUnscrolledPosition( cw, ch, &right, &bottom );
5861 }
5862 else
5863 {
5864 wxCoord x, y, w, h;
5865 reg.GetBox(x, y, w, h);
5866 CalcUnscrolledPosition( x, y, &left, &top );
5867 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
5868 }
5869 #else
5870 int cw, ch;
5871 m_gridWin->GetClientSize(&cw, &ch);
5872 CalcUnscrolledPosition( 0, 0, &left, &top );
5873 CalcUnscrolledPosition( cw, ch, &right, &bottom );
5874 #endif
5875
5876 // avoid drawing grid lines past the last row and col
5877 //
5878 right = wxMin( right, GetColRight(m_numCols - 1) );
5879 bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) );
5880
5881 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
5882
5883 // horizontal grid lines
5884 //
5885 int i;
5886 for ( i = 0; i < m_numRows; i++ )
5887 {
5888 int bot = GetRowBottom(i) - 1;
5889
5890 if ( bot > bottom )
5891 {
5892 break;
5893 }
5894
5895 if ( bot >= top )
5896 {
5897 dc.DrawLine( left, bot, right, bot );
5898 }
5899 }
5900
5901
5902 // vertical grid lines
5903 //
5904 for ( i = 0; i < m_numCols; i++ )
5905 {
5906 int colRight = GetColRight(i) - 1;
5907 if ( colRight > right )
5908 {
5909 break;
5910 }
5911
5912 if ( colRight >= left )
5913 {
5914 dc.DrawLine( colRight, top, colRight, bottom );
5915 }
5916 }
5917 }
5918
5919
5920 void wxGrid::DrawRowLabels( wxDC& dc )
5921 {
5922 if ( !m_numRows ) return;
5923
5924 size_t i;
5925 size_t numLabels = m_rowLabelsExposed.GetCount();
5926
5927 for ( i = 0; i < numLabels; i++ )
5928 {
5929 DrawRowLabel( dc, m_rowLabelsExposed[i] );
5930 }
5931 }
5932
5933
5934 void wxGrid::DrawRowLabel( wxDC& dc, int row )
5935 {
5936 if ( GetRowHeight(row) <= 0 )
5937 return;
5938
5939 int rowTop = GetRowTop(row),
5940 rowBottom = GetRowBottom(row) - 1;
5941
5942 dc.SetPen( *wxBLACK_PEN );
5943 dc.DrawLine( m_rowLabelWidth-1, rowTop,
5944 m_rowLabelWidth-1, rowBottom );
5945
5946 dc.DrawLine( 0, rowBottom, m_rowLabelWidth-1, rowBottom );
5947
5948 dc.SetPen( *wxWHITE_PEN );
5949 dc.DrawLine( 0, rowTop, 0, rowBottom );
5950 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
5951
5952 dc.SetBackgroundMode( wxTRANSPARENT );
5953 dc.SetTextForeground( GetLabelTextColour() );
5954 dc.SetFont( GetLabelFont() );
5955
5956 int hAlign, vAlign;
5957 GetRowLabelAlignment( &hAlign, &vAlign );
5958
5959 wxRect rect;
5960 rect.SetX( 2 );
5961 rect.SetY( GetRowTop(row) + 2 );
5962 rect.SetWidth( m_rowLabelWidth - 4 );
5963 rect.SetHeight( GetRowHeight(row) - 4 );
5964 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
5965 }
5966
5967
5968 void wxGrid::DrawColLabels( wxDC& dc )
5969 {
5970 if ( !m_numCols ) return;
5971
5972 size_t i;
5973 size_t numLabels = m_colLabelsExposed.GetCount();
5974
5975 for ( i = 0; i < numLabels; i++ )
5976 {
5977 DrawColLabel( dc, m_colLabelsExposed[i] );
5978 }
5979 }
5980
5981
5982 void wxGrid::DrawColLabel( wxDC& dc, int col )
5983 {
5984 if ( GetColWidth(col) <= 0 )
5985 return;
5986
5987 int colLeft = GetColLeft(col),
5988 colRight = GetColRight(col) - 1;
5989
5990 dc.SetPen( *wxBLACK_PEN );
5991 dc.DrawLine( colRight, 0,
5992 colRight, m_colLabelHeight-1 );
5993
5994 dc.DrawLine( colLeft, m_colLabelHeight-1,
5995 colRight, m_colLabelHeight-1 );
5996
5997 dc.SetPen( *wxWHITE_PEN );
5998 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
5999 dc.DrawLine( colLeft, 0, colRight, 0 );
6000
6001 dc.SetBackgroundMode( wxTRANSPARENT );
6002 dc.SetTextForeground( GetLabelTextColour() );
6003 dc.SetFont( GetLabelFont() );
6004
6005 dc.SetBackgroundMode( wxTRANSPARENT );
6006 dc.SetTextForeground( GetLabelTextColour() );
6007 dc.SetFont( GetLabelFont() );
6008
6009 int hAlign, vAlign;
6010 GetColLabelAlignment( &hAlign, &vAlign );
6011
6012 wxRect rect;
6013 rect.SetX( colLeft + 2 );
6014 rect.SetY( 2 );
6015 rect.SetWidth( GetColWidth(col) - 4 );
6016 rect.SetHeight( m_colLabelHeight - 4 );
6017 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
6018 }
6019
6020
6021 void wxGrid::DrawTextRectangle( wxDC& dc,
6022 const wxString& value,
6023 const wxRect& rect,
6024 int horizAlign,
6025 int vertAlign )
6026 {
6027 long textWidth, textHeight;
6028 long lineWidth, lineHeight;
6029 wxArrayString lines;
6030
6031 dc.SetClippingRegion( rect );
6032 StringToLines( value, lines );
6033 if ( lines.GetCount() )
6034 {
6035 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
6036 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
6037
6038 float x, y;
6039 switch ( horizAlign )
6040 {
6041 case wxRIGHT:
6042 x = rect.x + (rect.width - textWidth - 1);
6043 break;
6044
6045 case wxCENTRE:
6046 x = rect.x + ((rect.width - textWidth)/2);
6047 break;
6048
6049 case wxLEFT:
6050 default:
6051 x = rect.x + 1;
6052 break;
6053 }
6054
6055 switch ( vertAlign )
6056 {
6057 case wxBOTTOM:
6058 y = rect.y + (rect.height - textHeight - 1);
6059 break;
6060
6061 case wxCENTRE:
6062 y = rect.y + ((rect.height - textHeight)/2);
6063 break;
6064
6065 case wxTOP:
6066 default:
6067 y = rect.y + 1;
6068 break;
6069 }
6070
6071 for ( size_t i = 0; i < lines.GetCount(); i++ )
6072 {
6073 dc.DrawText( lines[i], (int)x, (int)y );
6074 y += lineHeight;
6075 }
6076 }
6077
6078 dc.DestroyClippingRegion();
6079 }
6080
6081
6082 // Split multi line text up into an array of strings. Any existing
6083 // contents of the string array are preserved.
6084 //
6085 void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
6086 {
6087 int startPos = 0;
6088 int pos;
6089 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
6090 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
6091
6092 while ( startPos < (int)tVal.Length() )
6093 {
6094 pos = tVal.Mid(startPos).Find( eol );
6095 if ( pos < 0 )
6096 {
6097 break;
6098 }
6099 else if ( pos == 0 )
6100 {
6101 lines.Add( wxEmptyString );
6102 }
6103 else
6104 {
6105 lines.Add( value.Mid(startPos, pos) );
6106 }
6107 startPos += pos+1;
6108 }
6109 if ( startPos < (int)value.Length() )
6110 {
6111 lines.Add( value.Mid( startPos ) );
6112 }
6113 }
6114
6115
6116 void wxGrid::GetTextBoxSize( wxDC& dc,
6117 wxArrayString& lines,
6118 long *width, long *height )
6119 {
6120 long w = 0;
6121 long h = 0;
6122 long lineW, lineH;
6123
6124 size_t i;
6125 for ( i = 0; i < lines.GetCount(); i++ )
6126 {
6127 dc.GetTextExtent( lines[i], &lineW, &lineH );
6128 w = wxMax( w, lineW );
6129 h += lineH;
6130 }
6131
6132 *width = w;
6133 *height = h;
6134 }
6135
6136 //
6137 // ------ Batch processing.
6138 //
6139 void wxGrid::EndBatch()
6140 {
6141 if ( m_batchCount > 0 )
6142 {
6143 m_batchCount--;
6144 if ( !m_batchCount )
6145 {
6146 CalcDimensions();
6147 m_rowLabelWin->Refresh();
6148 m_colLabelWin->Refresh();
6149 m_cornerLabelWin->Refresh();
6150 m_gridWin->Refresh();
6151 }
6152 }
6153 }
6154
6155 // Use this, rather than wxWindow::Refresh(), to force an immediate
6156 // repainting of the grid. Has no effect if you are already inside a
6157 // BeginBatch / EndBatch block.
6158 //
6159 void wxGrid::ForceRefresh()
6160 {
6161 BeginBatch();
6162 EndBatch();
6163 }
6164
6165
6166 //
6167 // ------ Edit control functions
6168 //
6169
6170
6171 void wxGrid::EnableEditing( bool edit )
6172 {
6173 // TODO: improve this ?
6174 //
6175 if ( edit != m_editable )
6176 {
6177 m_editable = edit;
6178
6179 // FIXME IMHO this won't disable the edit control if edit == FALSE
6180 // because of the check in the beginning of
6181 // EnableCellEditControl() just below (VZ)
6182 EnableCellEditControl(m_editable);
6183 }
6184 }
6185
6186
6187 void wxGrid::EnableCellEditControl( bool enable )
6188 {
6189 if (! m_editable)
6190 return;
6191
6192 if ( m_currentCellCoords == wxGridNoCellCoords )
6193 SetCurrentCell( 0, 0 );
6194
6195 if ( enable != m_cellEditCtrlEnabled )
6196 {
6197 // TODO allow the app to Veto() this event?
6198 SendEvent(enable ? wxEVT_GRID_EDITOR_SHOWN : wxEVT_GRID_EDITOR_HIDDEN);
6199
6200 if ( enable )
6201 {
6202 // this should be checked by the caller!
6203 wxASSERT_MSG( CanEnableCellControl(),
6204 _T("can't enable editing for this cell!") );
6205
6206 // do it before ShowCellEditControl()
6207 m_cellEditCtrlEnabled = enable;
6208
6209 ShowCellEditControl();
6210 }
6211 else
6212 {
6213 HideCellEditControl();
6214 SaveEditControlValue();
6215
6216 // do it after HideCellEditControl()
6217 m_cellEditCtrlEnabled = enable;
6218 }
6219 }
6220 }
6221
6222 bool wxGrid::IsCurrentCellReadOnly() const
6223 {
6224 // const_cast
6225 wxGridCellAttr* attr = ((wxGrid *)this)->GetCellAttr(m_currentCellCoords);
6226 bool readonly = attr->IsReadOnly();
6227 attr->DecRef();
6228
6229 return readonly;
6230 }
6231
6232 bool wxGrid::CanEnableCellControl() const
6233 {
6234 return m_editable && !IsCurrentCellReadOnly();
6235 }
6236
6237 bool wxGrid::IsCellEditControlEnabled() const
6238 {
6239 // the cell edit control might be disable for all cells or just for the
6240 // current one if it's read only
6241 return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : FALSE;
6242 }
6243
6244 bool wxGrid::IsCellEditControlShown() const
6245 {
6246 bool isShown = FALSE;
6247
6248 if ( m_cellEditCtrlEnabled )
6249 {
6250 int row = m_currentCellCoords.GetRow();
6251 int col = m_currentCellCoords.GetCol();
6252 wxGridCellAttr* attr = GetCellAttr(row, col);
6253 wxGridCellEditor* editor = attr->GetEditor((wxGrid*) this, row, col);
6254 attr->DecRef();
6255
6256 if ( editor )
6257 {
6258 if ( editor->IsCreated() )
6259 {
6260 isShown = editor->GetControl()->IsShown();
6261 }
6262
6263 editor->DecRef();
6264 }
6265 }
6266
6267 return isShown;
6268 }
6269
6270 void wxGrid::ShowCellEditControl()
6271 {
6272 if ( IsCellEditControlEnabled() )
6273 {
6274 if ( !IsVisible( m_currentCellCoords ) )
6275 {
6276 return;
6277 }
6278 else
6279 {
6280 wxRect rect = CellToRect( m_currentCellCoords );
6281 int row = m_currentCellCoords.GetRow();
6282 int col = m_currentCellCoords.GetCol();
6283
6284 // convert to scrolled coords
6285 //
6286 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
6287
6288 // done in PaintBackground()
6289 #if 0
6290 // erase the highlight and the cell contents because the editor
6291 // might not cover the entire cell
6292 wxClientDC dc( m_gridWin );
6293 PrepareDC( dc );
6294 dc.SetBrush(*wxLIGHT_GREY_BRUSH); //wxBrush(attr->GetBackgroundColour(), wxSOLID));
6295 dc.SetPen(*wxTRANSPARENT_PEN);
6296 dc.DrawRectangle(rect);
6297 #endif // 0
6298
6299 // cell is shifted by one pixel
6300 rect.x--;
6301 rect.y--;
6302
6303 wxGridCellAttr* attr = GetCellAttr(row, col);
6304 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
6305 if ( !editor->IsCreated() )
6306 {
6307 editor->Create(m_gridWin, -1,
6308 new wxGridCellEditorEvtHandler(this, editor));
6309 }
6310
6311 editor->Show( TRUE, attr );
6312
6313 editor->SetSize( rect );
6314
6315 editor->BeginEdit(row, col, this);
6316
6317 editor->DecRef();
6318 attr->DecRef();
6319 }
6320 }
6321 }
6322
6323
6324 void wxGrid::HideCellEditControl()
6325 {
6326 if ( IsCellEditControlEnabled() )
6327 {
6328 int row = m_currentCellCoords.GetRow();
6329 int col = m_currentCellCoords.GetCol();
6330
6331 wxGridCellAttr* attr = GetCellAttr(row, col);
6332 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
6333 editor->Show( FALSE );
6334 editor->DecRef();
6335 attr->DecRef();
6336 m_gridWin->SetFocus();
6337 wxRect rect( CellToRect( row, col ) );
6338 m_gridWin->Refresh( FALSE, &rect );
6339 }
6340 }
6341
6342
6343 void wxGrid::SaveEditControlValue()
6344 {
6345 if ( IsCellEditControlEnabled() )
6346 {
6347 int row = m_currentCellCoords.GetRow();
6348 int col = m_currentCellCoords.GetCol();
6349
6350 wxGridCellAttr* attr = GetCellAttr(row, col);
6351 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
6352 bool changed = editor->EndEdit(row, col, this);
6353
6354 editor->DecRef();
6355 attr->DecRef();
6356
6357 if (changed)
6358 {
6359 SendEvent( wxEVT_GRID_CELL_CHANGE,
6360 m_currentCellCoords.GetRow(),
6361 m_currentCellCoords.GetCol() );
6362 }
6363 }
6364 }
6365
6366
6367 //
6368 // ------ Grid location functions
6369 // Note that all of these functions work with the logical coordinates of
6370 // grid cells and labels so you will need to convert from device
6371 // coordinates for mouse events etc.
6372 //
6373
6374 void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
6375 {
6376 int row = YToRow(y);
6377 int col = XToCol(x);
6378
6379 if ( row == -1 || col == -1 )
6380 {
6381 coords = wxGridNoCellCoords;
6382 }
6383 else
6384 {
6385 coords.Set( row, col );
6386 }
6387 }
6388
6389
6390 int wxGrid::YToRow( int y )
6391 {
6392 int i;
6393
6394 for ( i = 0; i < m_numRows; i++ )
6395 {
6396 if ( y < GetRowBottom(i) )
6397 return i;
6398 }
6399
6400 return -1;
6401 }
6402
6403
6404 int wxGrid::XToCol( int x )
6405 {
6406 int i;
6407
6408 for ( i = 0; i < m_numCols; i++ )
6409 {
6410 if ( x < GetColRight(i) )
6411 return i;
6412 }
6413
6414 return -1;
6415 }
6416
6417
6418 // return the row number that that the y coord is near the edge of, or
6419 // -1 if not near an edge
6420 //
6421 int wxGrid::YToEdgeOfRow( int y )
6422 {
6423 int i, d;
6424
6425 for ( i = 0; i < m_numRows; i++ )
6426 {
6427 if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE )
6428 {
6429 d = abs( y - GetRowBottom(i) );
6430 if ( d < WXGRID_LABEL_EDGE_ZONE )
6431 return i;
6432 }
6433 }
6434
6435 return -1;
6436 }
6437
6438
6439 // return the col number that that the x coord is near the edge of, or
6440 // -1 if not near an edge
6441 //
6442 int wxGrid::XToEdgeOfCol( int x )
6443 {
6444 int i, d;
6445
6446 for ( i = 0; i < m_numCols; i++ )
6447 {
6448 if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE )
6449 {
6450 d = abs( x - GetColRight(i) );
6451 if ( d < WXGRID_LABEL_EDGE_ZONE )
6452 return i;
6453 }
6454 }
6455
6456 return -1;
6457 }
6458
6459
6460 wxRect wxGrid::CellToRect( int row, int col )
6461 {
6462 wxRect rect( -1, -1, -1, -1 );
6463
6464 if ( row >= 0 && row < m_numRows &&
6465 col >= 0 && col < m_numCols )
6466 {
6467 rect.x = GetColLeft(col);
6468 rect.y = GetRowTop(row);
6469 rect.width = GetColWidth(col);
6470 rect.height = GetRowHeight(row);
6471 }
6472
6473 // if grid lines are enabled, then the area of the cell is a bit smaller
6474 if (m_gridLinesEnabled) {
6475 rect.width -= 1;
6476 rect.height -= 1;
6477 }
6478 return rect;
6479 }
6480
6481
6482 bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
6483 {
6484 // get the cell rectangle in logical coords
6485 //
6486 wxRect r( CellToRect( row, col ) );
6487
6488 // convert to device coords
6489 //
6490 int left, top, right, bottom;
6491 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
6492 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
6493
6494 // check against the client area of the grid window
6495 //
6496 int cw, ch;
6497 m_gridWin->GetClientSize( &cw, &ch );
6498
6499 if ( wholeCellVisible )
6500 {
6501 // is the cell wholly visible ?
6502 //
6503 return ( left >= 0 && right <= cw &&
6504 top >= 0 && bottom <= ch );
6505 }
6506 else
6507 {
6508 // is the cell partly visible ?
6509 //
6510 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
6511 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
6512 }
6513 }
6514
6515
6516 // make the specified cell location visible by doing a minimal amount
6517 // of scrolling
6518 //
6519 void wxGrid::MakeCellVisible( int row, int col )
6520 {
6521 int i;
6522 int xpos = -1, ypos = -1;
6523
6524 if ( row >= 0 && row < m_numRows &&
6525 col >= 0 && col < m_numCols )
6526 {
6527 // get the cell rectangle in logical coords
6528 //
6529 wxRect r( CellToRect( row, col ) );
6530
6531 // convert to device coords
6532 //
6533 int left, top, right, bottom;
6534 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
6535 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
6536
6537 int cw, ch;
6538 m_gridWin->GetClientSize( &cw, &ch );
6539
6540 if ( top < 0 )
6541 {
6542 ypos = r.GetTop();
6543 }
6544 else if ( bottom > ch )
6545 {
6546 int h = r.GetHeight();
6547 ypos = r.GetTop();
6548 for ( i = row-1; i >= 0; i-- )
6549 {
6550 int rowHeight = GetRowHeight(i);
6551 if ( h + rowHeight > ch )
6552 break;
6553
6554 h += rowHeight;
6555 ypos -= rowHeight;
6556 }
6557
6558 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
6559 // have rounding errors (this is important, because if we do, we
6560 // might not scroll at all and some cells won't be redrawn)
6561 ypos += GRID_SCROLL_LINE / 2;
6562 }
6563
6564 if ( left < 0 )
6565 {
6566 xpos = r.GetLeft();
6567 }
6568 else if ( right > cw )
6569 {
6570 int w = r.GetWidth();
6571 xpos = r.GetLeft();
6572 for ( i = col-1; i >= 0; i-- )
6573 {
6574 int colWidth = GetColWidth(i);
6575 if ( w + colWidth > cw )
6576 break;
6577
6578 w += colWidth;
6579 xpos -= colWidth;
6580 }
6581
6582 // see comment for ypos above
6583 xpos += GRID_SCROLL_LINE / 2;
6584 }
6585
6586 if ( xpos != -1 || ypos != -1 )
6587 {
6588 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
6589 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
6590 Scroll( xpos, ypos );
6591 AdjustScrollbars();
6592 }
6593 }
6594 }
6595
6596
6597 //
6598 // ------ Grid cursor movement functions
6599 //
6600
6601 bool wxGrid::MoveCursorUp( bool expandSelection )
6602 {
6603 if ( m_currentCellCoords != wxGridNoCellCoords &&
6604 m_currentCellCoords.GetRow() >= 0 )
6605 {
6606 if ( expandSelection)
6607 {
6608 if ( m_selectingKeyboard == wxGridNoCellCoords )
6609 m_selectingKeyboard = m_currentCellCoords;
6610 if ( m_selectingKeyboard.GetRow() > 0 )
6611 {
6612 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() - 1 );
6613 MakeCellVisible( m_selectingKeyboard.GetRow(),
6614 m_selectingKeyboard.GetCol() );
6615 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6616 }
6617 }
6618 else if ( m_currentCellCoords.GetRow() > 0 )
6619 {
6620 ClearSelection();
6621 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
6622 m_currentCellCoords.GetCol() );
6623 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
6624 m_currentCellCoords.GetCol() );
6625 }
6626 else
6627 return FALSE;
6628 return TRUE;
6629 }
6630
6631 return FALSE;
6632 }
6633
6634
6635 bool wxGrid::MoveCursorDown( bool expandSelection )
6636 {
6637 if ( m_currentCellCoords != wxGridNoCellCoords &&
6638 m_currentCellCoords.GetRow() < m_numRows )
6639 {
6640 if ( expandSelection )
6641 {
6642 if ( m_selectingKeyboard == wxGridNoCellCoords )
6643 m_selectingKeyboard = m_currentCellCoords;
6644 if ( m_selectingKeyboard.GetRow() < m_numRows-1 )
6645 {
6646 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() + 1 );
6647 MakeCellVisible( m_selectingKeyboard.GetRow(),
6648 m_selectingKeyboard.GetCol() );
6649 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6650 }
6651 }
6652 else if ( m_currentCellCoords.GetRow() < m_numRows - 1 )
6653 {
6654 ClearSelection();
6655 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
6656 m_currentCellCoords.GetCol() );
6657 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
6658 m_currentCellCoords.GetCol() );
6659 }
6660 else
6661 return FALSE;
6662 return TRUE;
6663 }
6664
6665 return FALSE;
6666 }
6667
6668
6669 bool wxGrid::MoveCursorLeft( bool expandSelection )
6670 {
6671 if ( m_currentCellCoords != wxGridNoCellCoords &&
6672 m_currentCellCoords.GetCol() >= 0 )
6673 {
6674 if ( expandSelection )
6675 {
6676 if ( m_selectingKeyboard == wxGridNoCellCoords )
6677 m_selectingKeyboard = m_currentCellCoords;
6678 if ( m_selectingKeyboard.GetCol() > 0 )
6679 {
6680 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() - 1 );
6681 MakeCellVisible( m_selectingKeyboard.GetRow(),
6682 m_selectingKeyboard.GetCol() );
6683 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6684 }
6685 }
6686 else if ( m_currentCellCoords.GetCol() > 0 )
6687 {
6688 ClearSelection();
6689 MakeCellVisible( m_currentCellCoords.GetRow(),
6690 m_currentCellCoords.GetCol() - 1 );
6691 SetCurrentCell( m_currentCellCoords.GetRow(),
6692 m_currentCellCoords.GetCol() - 1 );
6693 }
6694 else
6695 return FALSE;
6696 return TRUE;
6697 }
6698
6699 return FALSE;
6700 }
6701
6702
6703 bool wxGrid::MoveCursorRight( bool expandSelection )
6704 {
6705 if ( m_currentCellCoords != wxGridNoCellCoords &&
6706 m_currentCellCoords.GetCol() < m_numCols )
6707 {
6708 if ( expandSelection )
6709 {
6710 if ( m_selectingKeyboard == wxGridNoCellCoords )
6711 m_selectingKeyboard = m_currentCellCoords;
6712 if ( m_selectingKeyboard.GetCol() < m_numCols - 1 )
6713 {
6714 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() + 1 );
6715 MakeCellVisible( m_selectingKeyboard.GetRow(),
6716 m_selectingKeyboard.GetCol() );
6717 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6718 }
6719 }
6720 else if ( m_currentCellCoords.GetCol() < m_numCols - 1 )
6721 {
6722 ClearSelection();
6723 MakeCellVisible( m_currentCellCoords.GetRow(),
6724 m_currentCellCoords.GetCol() + 1 );
6725 SetCurrentCell( m_currentCellCoords.GetRow(),
6726 m_currentCellCoords.GetCol() + 1 );
6727 }
6728 else
6729 return FALSE;
6730 return TRUE;
6731 }
6732
6733 return FALSE;
6734 }
6735
6736
6737 bool wxGrid::MovePageUp()
6738 {
6739 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
6740
6741 int row = m_currentCellCoords.GetRow();
6742 if ( row > 0 )
6743 {
6744 int cw, ch;
6745 m_gridWin->GetClientSize( &cw, &ch );
6746
6747 int y = GetRowTop(row);
6748 int newRow = YToRow( y - ch + 1 );
6749 if ( newRow == -1 )
6750 {
6751 newRow = 0;
6752 }
6753 else if ( newRow == row )
6754 {
6755 newRow = row - 1;
6756 }
6757
6758 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
6759 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
6760
6761 return TRUE;
6762 }
6763
6764 return FALSE;
6765 }
6766
6767 bool wxGrid::MovePageDown()
6768 {
6769 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
6770
6771 int row = m_currentCellCoords.GetRow();
6772 if ( row < m_numRows )
6773 {
6774 int cw, ch;
6775 m_gridWin->GetClientSize( &cw, &ch );
6776
6777 int y = GetRowTop(row);
6778 int newRow = YToRow( y + ch );
6779 if ( newRow == -1 )
6780 {
6781 newRow = m_numRows - 1;
6782 }
6783 else if ( newRow == row )
6784 {
6785 newRow = row + 1;
6786 }
6787
6788 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
6789 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
6790
6791 return TRUE;
6792 }
6793
6794 return FALSE;
6795 }
6796
6797 bool wxGrid::MoveCursorUpBlock( bool expandSelection )
6798 {
6799 if ( m_table &&
6800 m_currentCellCoords != wxGridNoCellCoords &&
6801 m_currentCellCoords.GetRow() > 0 )
6802 {
6803 int row = m_currentCellCoords.GetRow();
6804 int col = m_currentCellCoords.GetCol();
6805
6806 if ( m_table->IsEmptyCell(row, col) )
6807 {
6808 // starting in an empty cell: find the next block of
6809 // non-empty cells
6810 //
6811 while ( row > 0 )
6812 {
6813 row-- ;
6814 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6815 }
6816 }
6817 else if ( m_table->IsEmptyCell(row-1, col) )
6818 {
6819 // starting at the top of a block: find the next block
6820 //
6821 row--;
6822 while ( row > 0 )
6823 {
6824 row-- ;
6825 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6826 }
6827 }
6828 else
6829 {
6830 // starting within a block: find the top of the block
6831 //
6832 while ( row > 0 )
6833 {
6834 row-- ;
6835 if ( m_table->IsEmptyCell(row, col) )
6836 {
6837 row++ ;
6838 break;
6839 }
6840 }
6841 }
6842
6843 MakeCellVisible( row, col );
6844 if ( expandSelection )
6845 {
6846 m_selectingKeyboard = wxGridCellCoords( row, col );
6847 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6848 }
6849 else
6850 {
6851 ClearSelection();
6852 SetCurrentCell( row, col );
6853 }
6854 return TRUE;
6855 }
6856
6857 return FALSE;
6858 }
6859
6860 bool wxGrid::MoveCursorDownBlock( bool expandSelection )
6861 {
6862 if ( m_table &&
6863 m_currentCellCoords != wxGridNoCellCoords &&
6864 m_currentCellCoords.GetRow() < m_numRows-1 )
6865 {
6866 int row = m_currentCellCoords.GetRow();
6867 int col = m_currentCellCoords.GetCol();
6868
6869 if ( m_table->IsEmptyCell(row, col) )
6870 {
6871 // starting in an empty cell: find the next block of
6872 // non-empty cells
6873 //
6874 while ( row < m_numRows-1 )
6875 {
6876 row++ ;
6877 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6878 }
6879 }
6880 else if ( m_table->IsEmptyCell(row+1, col) )
6881 {
6882 // starting at the bottom of a block: find the next block
6883 //
6884 row++;
6885 while ( row < m_numRows-1 )
6886 {
6887 row++ ;
6888 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6889 }
6890 }
6891 else
6892 {
6893 // starting within a block: find the bottom of the block
6894 //
6895 while ( row < m_numRows-1 )
6896 {
6897 row++ ;
6898 if ( m_table->IsEmptyCell(row, col) )
6899 {
6900 row-- ;
6901 break;
6902 }
6903 }
6904 }
6905
6906 MakeCellVisible( row, col );
6907 if ( expandSelection )
6908 {
6909 m_selectingKeyboard = wxGridCellCoords( row, col );
6910 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6911 }
6912 else
6913 {
6914 ClearSelection();
6915 SetCurrentCell( row, col );
6916 }
6917
6918 return TRUE;
6919 }
6920
6921 return FALSE;
6922 }
6923
6924 bool wxGrid::MoveCursorLeftBlock( bool expandSelection )
6925 {
6926 if ( m_table &&
6927 m_currentCellCoords != wxGridNoCellCoords &&
6928 m_currentCellCoords.GetCol() > 0 )
6929 {
6930 int row = m_currentCellCoords.GetRow();
6931 int col = m_currentCellCoords.GetCol();
6932
6933 if ( m_table->IsEmptyCell(row, col) )
6934 {
6935 // starting in an empty cell: find the next block of
6936 // non-empty cells
6937 //
6938 while ( col > 0 )
6939 {
6940 col-- ;
6941 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6942 }
6943 }
6944 else if ( m_table->IsEmptyCell(row, col-1) )
6945 {
6946 // starting at the left of a block: find the next block
6947 //
6948 col--;
6949 while ( col > 0 )
6950 {
6951 col-- ;
6952 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6953 }
6954 }
6955 else
6956 {
6957 // starting within a block: find the left of the block
6958 //
6959 while ( col > 0 )
6960 {
6961 col-- ;
6962 if ( m_table->IsEmptyCell(row, col) )
6963 {
6964 col++ ;
6965 break;
6966 }
6967 }
6968 }
6969
6970 MakeCellVisible( row, col );
6971 if ( expandSelection )
6972 {
6973 m_selectingKeyboard = wxGridCellCoords( row, col );
6974 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6975 }
6976 else
6977 {
6978 ClearSelection();
6979 SetCurrentCell( row, col );
6980 }
6981
6982 return TRUE;
6983 }
6984
6985 return FALSE;
6986 }
6987
6988 bool wxGrid::MoveCursorRightBlock( bool expandSelection )
6989 {
6990 if ( m_table &&
6991 m_currentCellCoords != wxGridNoCellCoords &&
6992 m_currentCellCoords.GetCol() < m_numCols-1 )
6993 {
6994 int row = m_currentCellCoords.GetRow();
6995 int col = m_currentCellCoords.GetCol();
6996
6997 if ( m_table->IsEmptyCell(row, col) )
6998 {
6999 // starting in an empty cell: find the next block of
7000 // non-empty cells
7001 //
7002 while ( col < m_numCols-1 )
7003 {
7004 col++ ;
7005 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7006 }
7007 }
7008 else if ( m_table->IsEmptyCell(row, col+1) )
7009 {
7010 // starting at the right of a block: find the next block
7011 //
7012 col++;
7013 while ( col < m_numCols-1 )
7014 {
7015 col++ ;
7016 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7017 }
7018 }
7019 else
7020 {
7021 // starting within a block: find the right of the block
7022 //
7023 while ( col < m_numCols-1 )
7024 {
7025 col++ ;
7026 if ( m_table->IsEmptyCell(row, col) )
7027 {
7028 col-- ;
7029 break;
7030 }
7031 }
7032 }
7033
7034 MakeCellVisible( row, col );
7035 if ( expandSelection )
7036 {
7037 m_selectingKeyboard = wxGridCellCoords( row, col );
7038 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
7039 }
7040 else
7041 {
7042 ClearSelection();
7043 SetCurrentCell( row, col );
7044 }
7045
7046 return TRUE;
7047 }
7048
7049 return FALSE;
7050 }
7051
7052
7053
7054 //
7055 // ------ Label values and formatting
7056 //
7057
7058 void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
7059 {
7060 *horiz = m_rowLabelHorizAlign;
7061 *vert = m_rowLabelVertAlign;
7062 }
7063
7064 void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
7065 {
7066 *horiz = m_colLabelHorizAlign;
7067 *vert = m_colLabelVertAlign;
7068 }
7069
7070 wxString wxGrid::GetRowLabelValue( int row )
7071 {
7072 if ( m_table )
7073 {
7074 return m_table->GetRowLabelValue( row );
7075 }
7076 else
7077 {
7078 wxString s;
7079 s << row;
7080 return s;
7081 }
7082 }
7083
7084 wxString wxGrid::GetColLabelValue( int col )
7085 {
7086 if ( m_table )
7087 {
7088 return m_table->GetColLabelValue( col );
7089 }
7090 else
7091 {
7092 wxString s;
7093 s << col;
7094 return s;
7095 }
7096 }
7097
7098
7099 void wxGrid::SetRowLabelSize( int width )
7100 {
7101 width = wxMax( width, 0 );
7102 if ( width != m_rowLabelWidth )
7103 {
7104 if ( width == 0 )
7105 {
7106 m_rowLabelWin->Show( FALSE );
7107 m_cornerLabelWin->Show( FALSE );
7108 }
7109 else if ( m_rowLabelWidth == 0 )
7110 {
7111 m_rowLabelWin->Show( TRUE );
7112 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
7113 }
7114
7115 m_rowLabelWidth = width;
7116 CalcWindowSizes();
7117 Refresh( TRUE );
7118 }
7119 }
7120
7121
7122 void wxGrid::SetColLabelSize( int height )
7123 {
7124 height = wxMax( height, 0 );
7125 if ( height != m_colLabelHeight )
7126 {
7127 if ( height == 0 )
7128 {
7129 m_colLabelWin->Show( FALSE );
7130 m_cornerLabelWin->Show( FALSE );
7131 }
7132 else if ( m_colLabelHeight == 0 )
7133 {
7134 m_colLabelWin->Show( TRUE );
7135 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
7136 }
7137
7138 m_colLabelHeight = height;
7139 CalcWindowSizes();
7140 Refresh( TRUE );
7141 }
7142 }
7143
7144
7145 void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
7146 {
7147 if ( m_labelBackgroundColour != colour )
7148 {
7149 m_labelBackgroundColour = colour;
7150 m_rowLabelWin->SetBackgroundColour( colour );
7151 m_colLabelWin->SetBackgroundColour( colour );
7152 m_cornerLabelWin->SetBackgroundColour( colour );
7153
7154 if ( !GetBatchCount() )
7155 {
7156 m_rowLabelWin->Refresh();
7157 m_colLabelWin->Refresh();
7158 m_cornerLabelWin->Refresh();
7159 }
7160 }
7161 }
7162
7163 void wxGrid::SetLabelTextColour( const wxColour& colour )
7164 {
7165 if ( m_labelTextColour != colour )
7166 {
7167 m_labelTextColour = colour;
7168 if ( !GetBatchCount() )
7169 {
7170 m_rowLabelWin->Refresh();
7171 m_colLabelWin->Refresh();
7172 }
7173 }
7174 }
7175
7176 void wxGrid::SetLabelFont( const wxFont& font )
7177 {
7178 m_labelFont = font;
7179 if ( !GetBatchCount() )
7180 {
7181 m_rowLabelWin->Refresh();
7182 m_colLabelWin->Refresh();
7183 }
7184 }
7185
7186 void wxGrid::SetRowLabelAlignment( int horiz, int vert )
7187 {
7188 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
7189 {
7190 m_rowLabelHorizAlign = horiz;
7191 }
7192
7193 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
7194 {
7195 m_rowLabelVertAlign = vert;
7196 }
7197
7198 if ( !GetBatchCount() )
7199 {
7200 m_rowLabelWin->Refresh();
7201 }
7202 }
7203
7204 void wxGrid::SetColLabelAlignment( int horiz, int vert )
7205 {
7206 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
7207 {
7208 m_colLabelHorizAlign = horiz;
7209 }
7210
7211 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
7212 {
7213 m_colLabelVertAlign = vert;
7214 }
7215
7216 if ( !GetBatchCount() )
7217 {
7218 m_colLabelWin->Refresh();
7219 }
7220 }
7221
7222 void wxGrid::SetRowLabelValue( int row, const wxString& s )
7223 {
7224 if ( m_table )
7225 {
7226 m_table->SetRowLabelValue( row, s );
7227 if ( !GetBatchCount() )
7228 {
7229 wxRect rect = CellToRect( row, 0);
7230 if ( rect.height > 0 )
7231 {
7232 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
7233 rect.x = m_left;
7234 rect.width = m_rowLabelWidth;
7235 m_rowLabelWin->Refresh( TRUE, &rect );
7236 }
7237 }
7238 }
7239 }
7240
7241 void wxGrid::SetColLabelValue( int col, const wxString& s )
7242 {
7243 if ( m_table )
7244 {
7245 m_table->SetColLabelValue( col, s );
7246 if ( !GetBatchCount() )
7247 {
7248 wxRect rect = CellToRect( 0, col );
7249 if ( rect.width > 0 )
7250 {
7251 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
7252 rect.y = m_top;
7253 rect.height = m_colLabelHeight;
7254 m_colLabelWin->Refresh( TRUE, &rect );
7255 }
7256 }
7257 }
7258 }
7259
7260 void wxGrid::SetGridLineColour( const wxColour& colour )
7261 {
7262 if ( m_gridLineColour != colour )
7263 {
7264 m_gridLineColour = colour;
7265
7266 wxClientDC dc( m_gridWin );
7267 PrepareDC( dc );
7268 DrawAllGridLines( dc, wxRegion() );
7269 }
7270 }
7271
7272
7273 void wxGrid::SetCellHighlightColour( const wxColour& colour )
7274 {
7275 if ( m_cellHighlightColour != colour )
7276 {
7277 m_cellHighlightColour = colour;
7278
7279 wxClientDC dc( m_gridWin );
7280 PrepareDC( dc );
7281 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
7282 DrawCellHighlight(dc, attr);
7283 attr->DecRef();
7284 }
7285 }
7286
7287 void wxGrid::EnableGridLines( bool enable )
7288 {
7289 if ( enable != m_gridLinesEnabled )
7290 {
7291 m_gridLinesEnabled = enable;
7292
7293 if ( !GetBatchCount() )
7294 {
7295 if ( enable )
7296 {
7297 wxClientDC dc( m_gridWin );
7298 PrepareDC( dc );
7299 DrawAllGridLines( dc, wxRegion() );
7300 }
7301 else
7302 {
7303 m_gridWin->Refresh();
7304 }
7305 }
7306 }
7307 }
7308
7309
7310 int wxGrid::GetDefaultRowSize()
7311 {
7312 return m_defaultRowHeight;
7313 }
7314
7315 int wxGrid::GetRowSize( int row )
7316 {
7317 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
7318
7319 return GetRowHeight(row);
7320 }
7321
7322 int wxGrid::GetDefaultColSize()
7323 {
7324 return m_defaultColWidth;
7325 }
7326
7327 int wxGrid::GetColSize( int col )
7328 {
7329 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
7330
7331 return GetColWidth(col);
7332 }
7333
7334 // ============================================================================
7335 // access to the grid attributes: each of them has a default value in the grid
7336 // itself and may be overidden on a per-cell basis
7337 // ============================================================================
7338
7339 // ----------------------------------------------------------------------------
7340 // setting default attributes
7341 // ----------------------------------------------------------------------------
7342
7343 void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
7344 {
7345 m_defaultCellAttr->SetBackgroundColour(col);
7346 #ifdef __WXGTK__
7347 m_gridWin->SetBackgroundColour(col);
7348 #endif
7349 }
7350
7351 void wxGrid::SetDefaultCellTextColour( const wxColour& col )
7352 {
7353 m_defaultCellAttr->SetTextColour(col);
7354 }
7355
7356 void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
7357 {
7358 m_defaultCellAttr->SetAlignment(horiz, vert);
7359 }
7360
7361 void wxGrid::SetDefaultCellFont( const wxFont& font )
7362 {
7363 m_defaultCellAttr->SetFont(font);
7364 }
7365
7366 void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
7367 {
7368 m_defaultCellAttr->SetRenderer(renderer);
7369 }
7370
7371 void wxGrid::SetDefaultEditor(wxGridCellEditor *editor)
7372 {
7373 m_defaultCellAttr->SetEditor(editor);
7374 }
7375
7376 // ----------------------------------------------------------------------------
7377 // access to the default attrbiutes
7378 // ----------------------------------------------------------------------------
7379
7380 wxColour wxGrid::GetDefaultCellBackgroundColour()
7381 {
7382 return m_defaultCellAttr->GetBackgroundColour();
7383 }
7384
7385 wxColour wxGrid::GetDefaultCellTextColour()
7386 {
7387 return m_defaultCellAttr->GetTextColour();
7388 }
7389
7390 wxFont wxGrid::GetDefaultCellFont()
7391 {
7392 return m_defaultCellAttr->GetFont();
7393 }
7394
7395 void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
7396 {
7397 m_defaultCellAttr->GetAlignment(horiz, vert);
7398 }
7399
7400 wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
7401 {
7402 return m_defaultCellAttr->GetRenderer(NULL, 0, 0);
7403 }
7404
7405 wxGridCellEditor *wxGrid::GetDefaultEditor() const
7406 {
7407 return m_defaultCellAttr->GetEditor(NULL,0,0);
7408 }
7409
7410 // ----------------------------------------------------------------------------
7411 // access to cell attributes
7412 // ----------------------------------------------------------------------------
7413
7414 wxColour wxGrid::GetCellBackgroundColour(int row, int col)
7415 {
7416 wxGridCellAttr *attr = GetCellAttr(row, col);
7417 wxColour colour = attr->GetBackgroundColour();
7418 attr->DecRef();
7419 return colour;
7420 }
7421
7422 wxColour wxGrid::GetCellTextColour( int row, int col )
7423 {
7424 wxGridCellAttr *attr = GetCellAttr(row, col);
7425 wxColour colour = attr->GetTextColour();
7426 attr->DecRef();
7427 return colour;
7428 }
7429
7430 wxFont wxGrid::GetCellFont( int row, int col )
7431 {
7432 wxGridCellAttr *attr = GetCellAttr(row, col);
7433 wxFont font = attr->GetFont();
7434 attr->DecRef();
7435 return font;
7436 }
7437
7438 void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
7439 {
7440 wxGridCellAttr *attr = GetCellAttr(row, col);
7441 attr->GetAlignment(horiz, vert);
7442 attr->DecRef();
7443 }
7444
7445 wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
7446 {
7447 wxGridCellAttr* attr = GetCellAttr(row, col);
7448 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
7449 attr->DecRef();
7450
7451 return renderer;
7452 }
7453
7454 wxGridCellEditor* wxGrid::GetCellEditor(int row, int col)
7455 {
7456 wxGridCellAttr* attr = GetCellAttr(row, col);
7457 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
7458 attr->DecRef();
7459
7460 return editor;
7461 }
7462
7463 bool wxGrid::IsReadOnly(int row, int col) const
7464 {
7465 wxGridCellAttr* attr = GetCellAttr(row, col);
7466 bool isReadOnly = attr->IsReadOnly();
7467 attr->DecRef();
7468 return isReadOnly;
7469 }
7470
7471 // ----------------------------------------------------------------------------
7472 // attribute support: cache, automatic provider creation, ...
7473 // ----------------------------------------------------------------------------
7474
7475 bool wxGrid::CanHaveAttributes()
7476 {
7477 if ( !m_table )
7478 {
7479 return FALSE;
7480 }
7481
7482 return m_table->CanHaveAttributes();
7483 }
7484
7485 void wxGrid::ClearAttrCache()
7486 {
7487 if ( m_attrCache.row != -1 )
7488 {
7489 wxSafeDecRef(m_attrCache.attr);
7490 m_attrCache.row = -1;
7491 }
7492 }
7493
7494 void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
7495 {
7496 wxGrid *self = (wxGrid *)this; // const_cast
7497
7498 self->ClearAttrCache();
7499 self->m_attrCache.row = row;
7500 self->m_attrCache.col = col;
7501 self->m_attrCache.attr = attr;
7502 wxSafeIncRef(attr);
7503 }
7504
7505 bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
7506 {
7507 if ( row == m_attrCache.row && col == m_attrCache.col )
7508 {
7509 *attr = m_attrCache.attr;
7510 wxSafeIncRef(m_attrCache.attr);
7511
7512 #ifdef DEBUG_ATTR_CACHE
7513 gs_nAttrCacheHits++;
7514 #endif
7515
7516 return TRUE;
7517 }
7518 else
7519 {
7520 #ifdef DEBUG_ATTR_CACHE
7521 gs_nAttrCacheMisses++;
7522 #endif
7523 return FALSE;
7524 }
7525 }
7526
7527 wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
7528 {
7529 wxGridCellAttr *attr;
7530 if ( !LookupAttr(row, col, &attr) )
7531 {
7532 attr = m_table ? m_table->GetAttr(row, col) : (wxGridCellAttr *)NULL;
7533 CacheAttr(row, col, attr);
7534 }
7535 if (attr)
7536 {
7537 attr->SetDefAttr(m_defaultCellAttr);
7538 }
7539 else
7540 {
7541 attr = m_defaultCellAttr;
7542 attr->IncRef();
7543 }
7544
7545 return attr;
7546 }
7547
7548 wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
7549 {
7550 wxGridCellAttr *attr;
7551 if ( !LookupAttr(row, col, &attr) || !attr )
7552 {
7553 wxASSERT_MSG( m_table,
7554 _T("we may only be called if CanHaveAttributes() returned TRUE and then m_table should be !NULL") );
7555
7556 attr = m_table->GetAttr(row, col);
7557 if ( !attr )
7558 {
7559 attr = new wxGridCellAttr;
7560
7561 // artificially inc the ref count to match DecRef() in caller
7562 attr->IncRef();
7563
7564 m_table->SetAttr(attr, row, col);
7565 }
7566
7567 CacheAttr(row, col, attr);
7568 }
7569 attr->SetDefAttr(m_defaultCellAttr);
7570 return attr;
7571 }
7572
7573 // ----------------------------------------------------------------------------
7574 // setting column attributes (wrappers around SetColAttr)
7575 // ----------------------------------------------------------------------------
7576
7577 void wxGrid::SetColFormatBool(int col)
7578 {
7579 SetColFormatCustom(col, wxGRID_VALUE_BOOL);
7580 }
7581
7582 void wxGrid::SetColFormatNumber(int col)
7583 {
7584 SetColFormatCustom(col, wxGRID_VALUE_NUMBER);
7585 }
7586
7587 void wxGrid::SetColFormatFloat(int col, int width, int precision)
7588 {
7589 wxString typeName = wxGRID_VALUE_FLOAT;
7590 if ( (width != -1) || (precision != -1) )
7591 {
7592 typeName << _T(':') << width << _T(',') << precision;
7593 }
7594
7595 SetColFormatCustom(col, typeName);
7596 }
7597
7598 void wxGrid::SetColFormatCustom(int col, const wxString& typeName)
7599 {
7600 wxGridCellAttr *attr = new wxGridCellAttr;
7601 wxGridCellRenderer *renderer = GetDefaultRendererForType(typeName);
7602 attr->SetRenderer(renderer);
7603
7604 SetColAttr(col, attr);
7605 }
7606
7607 // ----------------------------------------------------------------------------
7608 // setting cell attributes: this is forwarded to the table
7609 // ----------------------------------------------------------------------------
7610
7611 void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
7612 {
7613 if ( CanHaveAttributes() )
7614 {
7615 m_table->SetRowAttr(attr, row);
7616 }
7617 else
7618 {
7619 wxSafeDecRef(attr);
7620 }
7621 }
7622
7623 void wxGrid::SetColAttr(int col, wxGridCellAttr *attr)
7624 {
7625 if ( CanHaveAttributes() )
7626 {
7627 m_table->SetColAttr(attr, col);
7628 }
7629 else
7630 {
7631 wxSafeDecRef(attr);
7632 }
7633 }
7634
7635 void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
7636 {
7637 if ( CanHaveAttributes() )
7638 {
7639 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7640 attr->SetBackgroundColour(colour);
7641 attr->DecRef();
7642 }
7643 }
7644
7645 void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
7646 {
7647 if ( CanHaveAttributes() )
7648 {
7649 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7650 attr->SetTextColour(colour);
7651 attr->DecRef();
7652 }
7653 }
7654
7655 void wxGrid::SetCellFont( int row, int col, const wxFont& font )
7656 {
7657 if ( CanHaveAttributes() )
7658 {
7659 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7660 attr->SetFont(font);
7661 attr->DecRef();
7662 }
7663 }
7664
7665 void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
7666 {
7667 if ( CanHaveAttributes() )
7668 {
7669 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7670 attr->SetAlignment(horiz, vert);
7671 attr->DecRef();
7672 }
7673 }
7674
7675 void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
7676 {
7677 if ( CanHaveAttributes() )
7678 {
7679 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7680 attr->SetRenderer(renderer);
7681 attr->DecRef();
7682 }
7683 }
7684
7685 void wxGrid::SetCellEditor(int row, int col, wxGridCellEditor* editor)
7686 {
7687 if ( CanHaveAttributes() )
7688 {
7689 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7690 attr->SetEditor(editor);
7691 attr->DecRef();
7692 }
7693 }
7694
7695 void wxGrid::SetReadOnly(int row, int col, bool isReadOnly)
7696 {
7697 if ( CanHaveAttributes() )
7698 {
7699 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7700 attr->SetReadOnly(isReadOnly);
7701 attr->DecRef();
7702 }
7703 }
7704
7705 // ----------------------------------------------------------------------------
7706 // Data type registration
7707 // ----------------------------------------------------------------------------
7708
7709 void wxGrid::RegisterDataType(const wxString& typeName,
7710 wxGridCellRenderer* renderer,
7711 wxGridCellEditor* editor)
7712 {
7713 m_typeRegistry->RegisterDataType(typeName, renderer, editor);
7714 }
7715
7716
7717 wxGridCellEditor* wxGrid::GetDefaultEditorForCell(int row, int col) const
7718 {
7719 wxString typeName = m_table->GetTypeName(row, col);
7720 return GetDefaultEditorForType(typeName);
7721 }
7722
7723 wxGridCellRenderer* wxGrid::GetDefaultRendererForCell(int row, int col) const
7724 {
7725 wxString typeName = m_table->GetTypeName(row, col);
7726 return GetDefaultRendererForType(typeName);
7727 }
7728
7729 wxGridCellEditor*
7730 wxGrid::GetDefaultEditorForType(const wxString& typeName) const
7731 {
7732 int index = m_typeRegistry->FindOrCloneDataType(typeName);
7733 if ( index == wxNOT_FOUND )
7734 {
7735 wxFAIL_MSG(wxT("Unknown data type name"));
7736
7737 return NULL;
7738 }
7739
7740 return m_typeRegistry->GetEditor(index);
7741 }
7742
7743 wxGridCellRenderer*
7744 wxGrid::GetDefaultRendererForType(const wxString& typeName) const
7745 {
7746 int index = m_typeRegistry->FindOrCloneDataType(typeName);
7747 if ( index == wxNOT_FOUND )
7748 {
7749 wxFAIL_MSG(wxT("Unknown data type name"));
7750
7751 return NULL;
7752 }
7753
7754 return m_typeRegistry->GetRenderer(index);
7755 }
7756
7757
7758 // ----------------------------------------------------------------------------
7759 // row/col size
7760 // ----------------------------------------------------------------------------
7761
7762 void wxGrid::EnableDragRowSize( bool enable )
7763 {
7764 m_canDragRowSize = enable;
7765 }
7766
7767
7768 void wxGrid::EnableDragColSize( bool enable )
7769 {
7770 m_canDragColSize = enable;
7771 }
7772
7773 void wxGrid::EnableDragGridSize( bool enable )
7774 {
7775 m_canDragGridSize = enable;
7776 }
7777
7778
7779 void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
7780 {
7781 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
7782
7783 if ( resizeExistingRows )
7784 {
7785 InitRowHeights();
7786
7787 CalcDimensions();
7788 }
7789 }
7790
7791 void wxGrid::SetRowSize( int row, int height )
7792 {
7793 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
7794
7795 if ( m_rowHeights.IsEmpty() )
7796 {
7797 // need to really create the array
7798 InitRowHeights();
7799 }
7800
7801 int h = wxMax( 0, height );
7802 int diff = h - m_rowHeights[row];
7803
7804 m_rowHeights[row] = h;
7805 int i;
7806 for ( i = row; i < m_numRows; i++ )
7807 {
7808 m_rowBottoms[i] += diff;
7809 }
7810 CalcDimensions();
7811 }
7812
7813 void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
7814 {
7815 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
7816
7817 if ( resizeExistingCols )
7818 {
7819 InitColWidths();
7820
7821 CalcDimensions();
7822 }
7823 }
7824
7825 void wxGrid::SetColSize( int col, int width )
7826 {
7827 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
7828
7829 // should we check that it's bigger than GetColMinimalWidth(col) here?
7830
7831 if ( m_colWidths.IsEmpty() )
7832 {
7833 // need to really create the array
7834 InitColWidths();
7835 }
7836
7837 int w = wxMax( 0, width );
7838 int diff = w - m_colWidths[col];
7839 m_colWidths[col] = w;
7840
7841 int i;
7842 for ( i = col; i < m_numCols; i++ )
7843 {
7844 m_colRights[i] += diff;
7845 }
7846 CalcDimensions();
7847 }
7848
7849
7850 void wxGrid::SetColMinimalWidth( int col, int width )
7851 {
7852 m_colMinWidths.Put(col, width);
7853 }
7854
7855 void wxGrid::SetRowMinimalHeight( int row, int width )
7856 {
7857 m_rowMinHeights.Put(row, width);
7858 }
7859
7860 int wxGrid::GetColMinimalWidth(int col) const
7861 {
7862 long value = m_colMinWidths.Get(col);
7863 return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_COL_WIDTH;
7864 }
7865
7866 int wxGrid::GetRowMinimalHeight(int row) const
7867 {
7868 long value = m_rowMinHeights.Get(row);
7869 return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_ROW_HEIGHT;
7870 }
7871
7872 // ----------------------------------------------------------------------------
7873 // auto sizing
7874 // ----------------------------------------------------------------------------
7875
7876 void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column )
7877 {
7878 wxClientDC dc(m_gridWin);
7879
7880 // init both of them to avoid compiler warnings, even if weo nly need one
7881 int row = -1,
7882 col = -1;
7883 if ( column )
7884 col = colOrRow;
7885 else
7886 row = colOrRow;
7887
7888 wxCoord extent, extentMax = 0;
7889 int max = column ? m_numRows : m_numCols;
7890 for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ )
7891 {
7892 if ( column )
7893 row = rowOrCol;
7894 else
7895 col = rowOrCol;
7896
7897 wxGridCellAttr* attr = GetCellAttr(row, col);
7898 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
7899 if ( renderer )
7900 {
7901 wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col);
7902 extent = column ? size.x : size.y;
7903 if ( extent > extentMax )
7904 {
7905 extentMax = extent;
7906 }
7907
7908 renderer->DecRef();
7909 }
7910
7911 attr->DecRef();
7912 }
7913
7914 // now also compare with the column label extent
7915 wxCoord w, h;
7916 dc.SetFont( GetLabelFont() );
7917
7918 if ( column )
7919 dc.GetTextExtent( GetColLabelValue(col), &w, &h );
7920 else
7921 dc.GetTextExtent( GetRowLabelValue(col), &w, &h );
7922
7923 extent = column ? w : h;
7924 if ( extent > extentMax )
7925 {
7926 extentMax = extent;
7927 }
7928
7929 if ( !extentMax )
7930 {
7931 // empty column - give default extent (notice that if extentMax is less
7932 // than default extent but != 0, it's ok)
7933 extentMax = column ? m_defaultColWidth : m_defaultRowHeight;
7934 }
7935 else
7936 {
7937 if ( column )
7938 {
7939 // leave some space around text
7940 extentMax += 10;
7941 }
7942 else
7943 {
7944 extentMax += 6;
7945 }
7946 }
7947
7948 if ( column )
7949 SetColSize(col, extentMax);
7950 else
7951 SetRowSize(row, extentMax);
7952
7953 if ( setAsMin )
7954 {
7955 if ( column )
7956 SetColMinimalWidth(col, extentMax);
7957 else
7958 SetRowMinimalHeight(row, extentMax);
7959 }
7960 }
7961
7962 int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
7963 {
7964 int width = m_rowLabelWidth;
7965
7966 for ( int col = 0; col < m_numCols; col++ )
7967 {
7968 if ( !calcOnly )
7969 {
7970 AutoSizeColumn(col, setAsMin);
7971 }
7972
7973 width += GetColWidth(col);
7974 }
7975
7976 return width;
7977 }
7978
7979 int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
7980 {
7981 int height = m_colLabelHeight;
7982
7983 for ( int row = 0; row < m_numRows; row++ )
7984 {
7985 if ( !calcOnly )
7986 {
7987 AutoSizeRow(row, setAsMin);
7988 }
7989
7990 height += GetRowHeight(row);
7991 }
7992
7993 return height;
7994 }
7995
7996 void wxGrid::AutoSize()
7997 {
7998 // set the size too
7999 SetSize(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE));
8000 }
8001
8002 wxSize wxGrid::DoGetBestSize() const
8003 {
8004 // don't set sizes, only calculate them
8005 wxGrid *self = (wxGrid *)this; // const_cast
8006
8007 return wxSize(self->SetOrCalcColumnSizes(TRUE),
8008 self->SetOrCalcRowSizes(TRUE));
8009 }
8010
8011 void wxGrid::Fit()
8012 {
8013 AutoSize();
8014 }
8015
8016
8017 wxPen& wxGrid::GetDividerPen() const
8018 {
8019 return wxNullPen;
8020 }
8021
8022 // ----------------------------------------------------------------------------
8023 // cell value accessor functions
8024 // ----------------------------------------------------------------------------
8025
8026 void wxGrid::SetCellValue( int row, int col, const wxString& s )
8027 {
8028 if ( m_table )
8029 {
8030 m_table->SetValue( row, col, s );
8031 if ( !GetBatchCount() )
8032 {
8033 wxClientDC dc( m_gridWin );
8034 PrepareDC( dc );
8035 DrawCell( dc, wxGridCellCoords(row, col) );
8036 }
8037
8038 if ( m_currentCellCoords.GetRow() == row &&
8039 m_currentCellCoords.GetCol() == col &&
8040 IsCellEditControlShown())
8041 // Note: If we are using IsCellEditControlEnabled,
8042 // this interacts badly with calling SetCellValue from
8043 // an EVT_GRID_CELL_CHANGE handler.
8044 {
8045 HideCellEditControl();
8046 ShowCellEditControl(); // will reread data from table
8047 }
8048 }
8049 }
8050
8051
8052 //
8053 // ------ Block, row and col selection
8054 //
8055
8056 void wxGrid::SelectRow( int row, bool addToSelected )
8057 {
8058 if ( IsSelection() && !addToSelected )
8059 ClearSelection();
8060
8061 m_selection->SelectRow( row, FALSE, addToSelected );
8062 }
8063
8064
8065 void wxGrid::SelectCol( int col, bool addToSelected )
8066 {
8067 if ( IsSelection() && !addToSelected )
8068 ClearSelection();
8069
8070 m_selection->SelectCol( col, FALSE, addToSelected );
8071 }
8072
8073
8074 void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
8075 {
8076 int temp;
8077 wxGridCellCoords updateTopLeft, updateBottomRight;
8078
8079 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
8080 {
8081 leftCol = 0;
8082 rightCol = GetNumberCols() - 1;
8083 }
8084 else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
8085 {
8086 topRow = 0;
8087 bottomRow = GetNumberRows() - 1;
8088 }
8089 if ( topRow > bottomRow )
8090 {
8091 temp = topRow;
8092 topRow = bottomRow;
8093 bottomRow = temp;
8094 }
8095
8096 if ( leftCol > rightCol )
8097 {
8098 temp = leftCol;
8099 leftCol = rightCol;
8100 rightCol = temp;
8101 }
8102
8103 updateTopLeft = wxGridCellCoords( topRow, leftCol );
8104 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
8105
8106 if ( m_selectingTopLeft != updateTopLeft ||
8107 m_selectingBottomRight != updateBottomRight )
8108 {
8109 // Compute two optimal update rectangles:
8110 // Either one rectangle is a real subset of the
8111 // other, or they are (almost) disjoint!
8112 wxRect rect[4];
8113 bool need_refresh[4];
8114 need_refresh[0] =
8115 need_refresh[1] =
8116 need_refresh[2] =
8117 need_refresh[3] = FALSE;
8118 int i;
8119
8120 // Store intermediate values
8121 wxCoord oldLeft = m_selectingTopLeft.GetCol();
8122 wxCoord oldTop = m_selectingTopLeft.GetRow();
8123 wxCoord oldRight = m_selectingBottomRight.GetCol();
8124 wxCoord oldBottom = m_selectingBottomRight.GetRow();
8125
8126 // Determine the outer/inner coordinates.
8127 if (oldLeft > leftCol)
8128 {
8129 temp = oldLeft;
8130 oldLeft = leftCol;
8131 leftCol = temp;
8132 }
8133 if (oldTop > topRow )
8134 {
8135 temp = oldTop;
8136 oldTop = topRow;
8137 topRow = temp;
8138 }
8139 if (oldRight < rightCol )
8140 {
8141 temp = oldRight;
8142 oldRight = rightCol;
8143 rightCol = temp;
8144 }
8145 if (oldBottom < bottomRow)
8146 {
8147 temp = oldBottom;
8148 oldBottom = bottomRow;
8149 bottomRow = temp;
8150 }
8151
8152 // Now, either the stuff marked old is the outer
8153 // rectangle or we don't have a situation where one
8154 // is contained in the other.
8155
8156 if ( oldLeft < leftCol )
8157 {
8158 need_refresh[0] = TRUE;
8159 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
8160 oldLeft ),
8161 wxGridCellCoords ( oldBottom,
8162 leftCol - 1 ) );
8163 }
8164
8165 if ( oldTop < topRow )
8166 {
8167 need_refresh[1] = TRUE;
8168 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
8169 leftCol ),
8170 wxGridCellCoords ( topRow - 1,
8171 rightCol ) );
8172 }
8173
8174 if ( oldRight > rightCol )
8175 {
8176 need_refresh[2] = TRUE;
8177 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
8178 rightCol + 1 ),
8179 wxGridCellCoords ( oldBottom,
8180 oldRight ) );
8181 }
8182
8183 if ( oldBottom > bottomRow )
8184 {
8185 need_refresh[3] = TRUE;
8186 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
8187 leftCol ),
8188 wxGridCellCoords ( oldBottom,
8189 rightCol ) );
8190 }
8191
8192
8193 // Change Selection
8194 m_selectingTopLeft = updateTopLeft;
8195 m_selectingBottomRight = updateBottomRight;
8196
8197 // various Refresh() calls
8198 for (i = 0; i < 4; i++ )
8199 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
8200 m_gridWin->Refresh( FALSE, &(rect[i]) );
8201 }
8202
8203 // never generate an event as it will be generated from
8204 // wxGridSelection::SelectBlock!
8205 }
8206
8207 void wxGrid::SelectAll()
8208 {
8209 m_selection->SelectBlock( 0, 0, m_numRows-1, m_numCols-1 );
8210 }
8211
8212 bool wxGrid::IsSelection()
8213 {
8214 return ( m_selection->IsSelection() ||
8215 ( m_selectingTopLeft != wxGridNoCellCoords &&
8216 m_selectingBottomRight != wxGridNoCellCoords ) );
8217 }
8218
8219 bool wxGrid::IsInSelection( int row, int col )
8220 {
8221 return ( m_selection->IsInSelection( row, col ) ||
8222 ( row >= m_selectingTopLeft.GetRow() &&
8223 col >= m_selectingTopLeft.GetCol() &&
8224 row <= m_selectingBottomRight.GetRow() &&
8225 col <= m_selectingBottomRight.GetCol() ) );
8226 }
8227
8228 void wxGrid::ClearSelection()
8229 {
8230 m_selectingTopLeft = wxGridNoCellCoords;
8231 m_selectingBottomRight = wxGridNoCellCoords;
8232 m_selection->ClearSelection();
8233 }
8234
8235
8236 // This function returns the rectangle that encloses the given block
8237 // in device coords clipped to the client size of the grid window.
8238 //
8239 wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
8240 const wxGridCellCoords &bottomRight )
8241 {
8242 wxRect rect( wxGridNoCellRect );
8243 wxRect cellRect;
8244
8245 cellRect = CellToRect( topLeft );
8246 if ( cellRect != wxGridNoCellRect )
8247 {
8248 rect = cellRect;
8249 }
8250 else
8251 {
8252 rect = wxRect( 0, 0, 0, 0 );
8253 }
8254
8255 cellRect = CellToRect( bottomRight );
8256 if ( cellRect != wxGridNoCellRect )
8257 {
8258 rect += cellRect;
8259 }
8260 else
8261 {
8262 return wxGridNoCellRect;
8263 }
8264
8265 // convert to scrolled coords
8266 //
8267 int left, top, right, bottom;
8268 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
8269 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
8270
8271 int cw, ch;
8272 m_gridWin->GetClientSize( &cw, &ch );
8273
8274 if (right < 0 || bottom < 0 || left > cw || top > ch)
8275 return wxRect( 0, 0, 0, 0);
8276
8277 rect.SetLeft( wxMax(0, left) );
8278 rect.SetTop( wxMax(0, top) );
8279 rect.SetRight( wxMin(cw, right) );
8280 rect.SetBottom( wxMin(ch, bottom) );
8281
8282 return rect;
8283 }
8284
8285
8286
8287 //
8288 // ------ Grid event classes
8289 //
8290
8291 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
8292
8293 wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
8294 int row, int col, int x, int y, bool sel,
8295 bool control, bool shift, bool alt, bool meta )
8296 : wxNotifyEvent( type, id )
8297 {
8298 m_row = row;
8299 m_col = col;
8300 m_x = x;
8301 m_y = y;
8302 m_selecting = sel;
8303 m_control = control;
8304 m_shift = shift;
8305 m_alt = alt;
8306 m_meta = meta;
8307
8308 SetEventObject(obj);
8309 }
8310
8311
8312 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
8313
8314 wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
8315 int rowOrCol, int x, int y,
8316 bool control, bool shift, bool alt, bool meta )
8317 : wxNotifyEvent( type, id )
8318 {
8319 m_rowOrCol = rowOrCol;
8320 m_x = x;
8321 m_y = y;
8322 m_control = control;
8323 m_shift = shift;
8324 m_alt = alt;
8325 m_meta = meta;
8326
8327 SetEventObject(obj);
8328 }
8329
8330
8331 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
8332
8333 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
8334 const wxGridCellCoords& topLeft,
8335 const wxGridCellCoords& bottomRight,
8336 bool sel, bool control,
8337 bool shift, bool alt, bool meta )
8338 : wxNotifyEvent( type, id )
8339 {
8340 m_topLeft = topLeft;
8341 m_bottomRight = bottomRight;
8342 m_selecting = sel;
8343 m_control = control;
8344 m_shift = shift;
8345 m_alt = alt;
8346 m_meta = meta;
8347
8348 SetEventObject(obj);
8349 }
8350
8351
8352 #endif // ifndef wxUSE_NEW_GRID