]> git.saurik.com Git - wxWidgets.git/blob - src/generic/grid.cpp
1b31ef10db6a5def3afa46ef71c5f19202971b97
[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(), mouseEv.GetY(),
5244 mouseEv.ControlDown(),
5245 mouseEv.ShiftDown(),
5246 mouseEv.AltDown(),
5247 mouseEv.MetaDown() );
5248
5249 return GetEventHandler()->ProcessEvent(gridEvt);
5250 }
5251 else if ( type == wxEVT_GRID_RANGE_SELECT )
5252 {
5253 // Right now, it should _never_ end up here!
5254 wxGridRangeSelectEvent gridEvt( GetId(),
5255 type,
5256 this,
5257 m_selectingTopLeft,
5258 m_selectingBottomRight,
5259 TRUE,
5260 mouseEv.ControlDown(),
5261 mouseEv.ShiftDown(),
5262 mouseEv.AltDown(),
5263 mouseEv.MetaDown() );
5264
5265 return GetEventHandler()->ProcessEvent(gridEvt);
5266 }
5267 else
5268 {
5269 wxGridEvent gridEvt( GetId(),
5270 type,
5271 this,
5272 row, col,
5273 mouseEv.GetX(), mouseEv.GetY(),
5274 FALSE,
5275 mouseEv.ControlDown(),
5276 mouseEv.ShiftDown(),
5277 mouseEv.AltDown(),
5278 mouseEv.MetaDown() );
5279
5280 return GetEventHandler()->ProcessEvent(gridEvt);
5281 }
5282 }
5283
5284
5285 // Generate a grid event of specified type and return the result
5286 // of ProcessEvent().
5287 //
5288 bool wxGrid::SendEvent( const wxEventType type,
5289 int row, int col )
5290 {
5291 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
5292 {
5293 int rowOrCol = (row == -1 ? col : row);
5294
5295 wxGridSizeEvent gridEvt( GetId(),
5296 type,
5297 this,
5298 rowOrCol );
5299
5300 return GetEventHandler()->ProcessEvent(gridEvt);
5301 }
5302 else
5303 {
5304 wxGridEvent gridEvt( GetId(),
5305 type,
5306 this,
5307 row, col );
5308
5309 return GetEventHandler()->ProcessEvent(gridEvt);
5310 }
5311 }
5312
5313
5314 void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
5315 {
5316 wxPaintDC dc(this); // needed to prevent zillions of paint events on MSW
5317 }
5318
5319
5320 // This is just here to make sure that CalcDimensions gets called when
5321 // the grid view is resized... then the size event is skipped to allow
5322 // the box sizers to handle everything
5323 //
5324 void wxGrid::OnSize( wxSizeEvent& WXUNUSED(event) )
5325 {
5326 CalcWindowSizes();
5327 CalcDimensions();
5328 }
5329
5330
5331 void wxGrid::OnKeyDown( wxKeyEvent& event )
5332 {
5333 if ( m_inOnKeyDown )
5334 {
5335 // shouldn't be here - we are going round in circles...
5336 //
5337 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") );
5338 }
5339
5340 m_inOnKeyDown = TRUE;
5341
5342 // propagate the event up and see if it gets processed
5343 //
5344 wxWindow *parent = GetParent();
5345 wxKeyEvent keyEvt( event );
5346 keyEvt.SetEventObject( parent );
5347
5348 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
5349 {
5350
5351 // try local handlers
5352 //
5353 switch ( event.KeyCode() )
5354 {
5355 case WXK_UP:
5356 if ( event.ControlDown() )
5357 {
5358 MoveCursorUpBlock( event.ShiftDown() );
5359 }
5360 else
5361 {
5362 MoveCursorUp( event.ShiftDown() );
5363 }
5364 break;
5365
5366 case WXK_DOWN:
5367 if ( event.ControlDown() )
5368 {
5369 MoveCursorDownBlock( event.ShiftDown() );
5370 }
5371 else
5372 {
5373 MoveCursorDown( event.ShiftDown() );
5374 }
5375 break;
5376
5377 case WXK_LEFT:
5378 if ( event.ControlDown() )
5379 {
5380 MoveCursorLeftBlock( event.ShiftDown() );
5381 }
5382 else
5383 {
5384 MoveCursorLeft( event.ShiftDown() );
5385 }
5386 break;
5387
5388 case WXK_RIGHT:
5389 if ( event.ControlDown() )
5390 {
5391 MoveCursorRightBlock( event.ShiftDown() );
5392 }
5393 else
5394 {
5395 MoveCursorRight( event.ShiftDown() );
5396 }
5397 break;
5398
5399 case WXK_RETURN:
5400 if ( event.ControlDown() )
5401 {
5402 event.Skip(); // to let the edit control have the return
5403 }
5404 else
5405 {
5406 if ( GetGridCursorRow() < GetNumberRows()-1 )
5407 {
5408 MoveCursorDown( event.ShiftDown() );
5409 }
5410 else
5411 {
5412 // at the bottom of a column
5413 HideCellEditControl();
5414 SaveEditControlValue();
5415 }
5416 }
5417 break;
5418
5419 case WXK_ESCAPE:
5420 ClearSelection();
5421 break;
5422
5423 case WXK_TAB:
5424 if (event.ShiftDown())
5425 {
5426 if ( GetGridCursorCol() > 0 )
5427 {
5428 MoveCursorLeft( FALSE );
5429 }
5430 else
5431 {
5432 // at left of grid
5433 HideCellEditControl();
5434 SaveEditControlValue();
5435 }
5436 }
5437 else
5438 {
5439 if ( GetGridCursorCol() < GetNumberCols()-1 )
5440 {
5441 MoveCursorRight( FALSE );
5442 }
5443 else
5444 {
5445 // at right of grid
5446 HideCellEditControl();
5447 SaveEditControlValue();
5448 }
5449 }
5450 break;
5451
5452 case WXK_HOME:
5453 if ( event.ControlDown() )
5454 {
5455 MakeCellVisible( 0, 0 );
5456 SetCurrentCell( 0, 0 );
5457 }
5458 else
5459 {
5460 event.Skip();
5461 }
5462 break;
5463
5464 case WXK_END:
5465 if ( event.ControlDown() )
5466 {
5467 MakeCellVisible( m_numRows-1, m_numCols-1 );
5468 SetCurrentCell( m_numRows-1, m_numCols-1 );
5469 }
5470 else
5471 {
5472 event.Skip();
5473 }
5474 break;
5475
5476 case WXK_PRIOR:
5477 MovePageUp();
5478 break;
5479
5480 case WXK_NEXT:
5481 MovePageDown();
5482 break;
5483
5484 case WXK_SPACE:
5485 if ( event.ControlDown() )
5486 {
5487 m_selection->ToggleCellSelection( m_currentCellCoords.GetRow(),
5488 m_currentCellCoords.GetCol(),
5489 event.ControlDown(),
5490 event.ShiftDown(),
5491 event.AltDown(),
5492 event.MetaDown() );
5493 break;
5494 }
5495 if ( !IsEditable() )
5496 {
5497 MoveCursorRight( FALSE );
5498 break;
5499 }
5500 // Otherwise fall through to default
5501
5502 default:
5503 // is it possible to edit the current cell at all?
5504 if ( !IsCellEditControlEnabled() && CanEnableCellControl() )
5505 {
5506 // yes, now check whether the cells editor accepts the key
5507 int row = m_currentCellCoords.GetRow();
5508 int col = m_currentCellCoords.GetCol();
5509 wxGridCellAttr* attr = GetCellAttr(row, col);
5510 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
5511
5512 // <F2> is special and will always start editing, for
5513 // other keys - ask the editor itself
5514 if ( (event.KeyCode() == WXK_F2 && !event.HasModifiers())
5515 || editor->IsAcceptedKey(event) )
5516 {
5517 EnableCellEditControl();
5518 editor->StartingKey(event);
5519 }
5520 else
5521 {
5522 event.Skip();
5523 }
5524
5525 editor->DecRef();
5526 attr->DecRef();
5527 }
5528 else
5529 {
5530 // let others process char events with modifiers or all
5531 // char events for readonly cells
5532 event.Skip();
5533 }
5534 break;
5535 }
5536 }
5537
5538 m_inOnKeyDown = FALSE;
5539 }
5540
5541 void wxGrid::OnKeyUp( wxKeyEvent& event )
5542 {
5543 // try local handlers
5544 //
5545 if ( event.KeyCode() == WXK_SHIFT )
5546 {
5547 if ( m_selectingTopLeft != wxGridNoCellCoords &&
5548 m_selectingBottomRight != wxGridNoCellCoords )
5549 m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
5550 m_selectingTopLeft.GetCol(),
5551 m_selectingBottomRight.GetRow(),
5552 m_selectingBottomRight.GetCol(),
5553 event.ControlDown(),
5554 TRUE,
5555 event.AltDown(),
5556 event.MetaDown() );
5557 m_selectingTopLeft = wxGridNoCellCoords;
5558 m_selectingBottomRight = wxGridNoCellCoords;
5559 m_selectingKeyboard = wxGridNoCellCoords;
5560 }
5561 }
5562
5563 void wxGrid::OnEraseBackground(wxEraseEvent&)
5564 {
5565 }
5566
5567 void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
5568 {
5569 if ( SendEvent( wxEVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
5570 {
5571 // the event has been intercepted - do nothing
5572 return;
5573 }
5574
5575 wxClientDC dc(m_gridWin);
5576 PrepareDC(dc);
5577
5578 if ( m_currentCellCoords != wxGridNoCellCoords )
5579 {
5580 HideCellEditControl();
5581 DisableCellEditControl();
5582
5583 if ( IsVisible( m_currentCellCoords ) )
5584 {
5585 wxRect r;
5586 r = BlockToDeviceRect(m_currentCellCoords, m_currentCellCoords);
5587 if ( !m_gridLinesEnabled )
5588 {
5589 r.x--;
5590 r.y--;
5591 r.width++;
5592 r.height++;
5593 }
5594
5595 CalcCellsExposed( r );
5596
5597 // Otherwise refresh redraws the highlight!
5598 m_currentCellCoords = coords;
5599
5600 DrawGridCellArea(dc);
5601 DrawAllGridLines( dc, r );
5602 }
5603 }
5604
5605 m_currentCellCoords = coords;
5606
5607 wxGridCellAttr* attr = GetCellAttr(coords);
5608 DrawCellHighlight(dc, attr);
5609 attr->DecRef();
5610 }
5611
5612
5613 //
5614 // ------ functions to get/send data (see also public functions)
5615 //
5616
5617 bool wxGrid::GetModelValues()
5618 {
5619 if ( m_table )
5620 {
5621 // all we need to do is repaint the grid
5622 //
5623 m_gridWin->Refresh();
5624 return TRUE;
5625 }
5626
5627 return FALSE;
5628 }
5629
5630
5631 bool wxGrid::SetModelValues()
5632 {
5633 int row, col;
5634
5635 if ( m_table )
5636 {
5637 for ( row = 0; row < m_numRows; row++ )
5638 {
5639 for ( col = 0; col < m_numCols; col++ )
5640 {
5641 m_table->SetValue( row, col, GetCellValue(row, col) );
5642 }
5643 }
5644
5645 return TRUE;
5646 }
5647
5648 return FALSE;
5649 }
5650
5651
5652
5653 // Note - this function only draws cells that are in the list of
5654 // exposed cells (usually set from the update region by
5655 // CalcExposedCells)
5656 //
5657 void wxGrid::DrawGridCellArea( wxDC& dc )
5658 {
5659 if ( !m_numRows || !m_numCols ) return;
5660
5661 size_t i;
5662 size_t numCells = m_cellsExposed.GetCount();
5663
5664 for ( i = 0; i < numCells; i++ )
5665 {
5666 DrawCell( dc, m_cellsExposed[i] );
5667 }
5668 }
5669
5670
5671 void wxGrid::DrawGridSpace( wxDC& dc )
5672 {
5673 int cw, ch;
5674 m_gridWin->GetClientSize( &cw, &ch );
5675
5676 int right, bottom;
5677 CalcUnscrolledPosition( cw, ch, &right, &bottom );
5678
5679 int rightCol = m_numCols > 0 ? GetColRight(m_numCols - 1) : 0;
5680 int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0 ;
5681
5682 if ( right > rightCol || bottom > bottomRow )
5683 {
5684 int left, top;
5685 CalcUnscrolledPosition( 0, 0, &left, &top );
5686
5687 dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) );
5688 dc.SetPen( *wxTRANSPARENT_PEN );
5689
5690 if ( right > rightCol )
5691 {
5692 dc.DrawRectangle( rightCol, top, right - rightCol, ch);
5693 }
5694
5695 if ( bottom > bottomRow )
5696 {
5697 dc.DrawRectangle( left, bottomRow, cw, bottom - bottomRow);
5698 }
5699 }
5700 }
5701
5702
5703 void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
5704 {
5705 int row = coords.GetRow();
5706 int col = coords.GetCol();
5707
5708 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
5709 return;
5710
5711 // we draw the cell border ourselves
5712 #if !WXGRID_DRAW_LINES
5713 if ( m_gridLinesEnabled )
5714 DrawCellBorder( dc, coords );
5715 #endif
5716
5717 wxGridCellAttr* attr = GetCellAttr(row, col);
5718
5719 bool isCurrent = coords == m_currentCellCoords;
5720
5721 wxRect rect = CellToRect( row, col );
5722
5723 // if the editor is shown, we should use it and not the renderer
5724 // Note: However, only if it is really _shown_, i.e. not hidden!
5725 if ( isCurrent && IsCellEditControlShown() )
5726 {
5727 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
5728 editor->PaintBackground(rect, attr);
5729 editor->DecRef();
5730 }
5731 else
5732 {
5733 // but all the rest is drawn by the cell renderer and hence may be
5734 // customized
5735 wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col);
5736 renderer->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
5737 renderer->DecRef();
5738 }
5739
5740 attr->DecRef();
5741 }
5742
5743 void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr )
5744 {
5745 int row = m_currentCellCoords.GetRow();
5746 int col = m_currentCellCoords.GetCol();
5747
5748 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
5749 return;
5750
5751 wxRect rect = CellToRect(row, col);
5752
5753 // hmmm... what could we do here to show that the cell is disabled?
5754 // for now, I just draw a thinner border than for the other ones, but
5755 // it doesn't look really good
5756 dc.SetPen(wxPen(m_cellHighlightColour, attr->IsReadOnly() ? 1 : 3, wxSOLID));
5757 dc.SetBrush(*wxTRANSPARENT_BRUSH);
5758
5759 dc.DrawRectangle(rect);
5760
5761 #if 0
5762 // VZ: my experiments with 3d borders...
5763
5764 // how to properly set colours for arbitrary bg?
5765 wxCoord x1 = rect.x,
5766 y1 = rect.y,
5767 x2 = rect.x + rect.width -1,
5768 y2 = rect.y + rect.height -1;
5769
5770 dc.SetPen(*wxWHITE_PEN);
5771 dc.DrawLine(x1, y1, x2, y1);
5772 dc.DrawLine(x1, y1, x1, y2);
5773
5774 dc.DrawLine(x1 + 1, y2 - 1, x2 - 1, y2 - 1);
5775 dc.DrawLine(x2 - 1, y1 + 1, x2 - 1, y2 );
5776
5777 dc.SetPen(*wxBLACK_PEN);
5778 dc.DrawLine(x1, y2, x2, y2);
5779 dc.DrawLine(x2, y1, x2, y2+1);
5780 #endif // 0
5781 }
5782
5783
5784 void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
5785 {
5786 int row = coords.GetRow();
5787 int col = coords.GetCol();
5788 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
5789 return;
5790
5791 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
5792
5793 // right hand border
5794 //
5795 dc.DrawLine( GetColRight(col), GetRowTop(row),
5796 GetColRight(col), GetRowBottom(row) );
5797
5798 // bottom border
5799 //
5800 dc.DrawLine( GetColLeft(col), GetRowBottom(row),
5801 GetColRight(col), GetRowBottom(row) );
5802 }
5803
5804 void wxGrid::DrawHighlight(wxDC& dc)
5805 {
5806 // This if block was previously in wxGrid::OnPaint but that doesn't
5807 // seem to get called under wxGTK - MB
5808 //
5809 if ( m_currentCellCoords == wxGridNoCellCoords &&
5810 m_numRows && m_numCols )
5811 {
5812 m_currentCellCoords.Set(0, 0);
5813 }
5814
5815 if ( IsCellEditControlShown() )
5816 {
5817 // don't show highlight when the edit control is shown
5818 return;
5819 }
5820
5821 // if the active cell was repainted, repaint its highlight too because it
5822 // might have been damaged by the grid lines
5823 size_t count = m_cellsExposed.GetCount();
5824 for ( size_t n = 0; n < count; n++ )
5825 {
5826 if ( m_cellsExposed[n] == m_currentCellCoords )
5827 {
5828 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
5829 DrawCellHighlight(dc, attr);
5830 attr->DecRef();
5831
5832 break;
5833 }
5834 }
5835 }
5836
5837 // TODO: remove this ???
5838 // This is used to redraw all grid lines e.g. when the grid line colour
5839 // has been changed
5840 //
5841 void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED_GTK(reg) )
5842 {
5843 if ( !m_gridLinesEnabled ||
5844 !m_numRows ||
5845 !m_numCols ) return;
5846
5847 int top, bottom, left, right;
5848
5849 #if 0 //#ifndef __WXGTK__
5850 if (reg.IsEmpty())
5851 {
5852 int cw, ch;
5853 m_gridWin->GetClientSize(&cw, &ch);
5854
5855 // virtual coords of visible area
5856 //
5857 CalcUnscrolledPosition( 0, 0, &left, &top );
5858 CalcUnscrolledPosition( cw, ch, &right, &bottom );
5859 }
5860 else
5861 {
5862 wxCoord x, y, w, h;
5863 reg.GetBox(x, y, w, h);
5864 CalcUnscrolledPosition( x, y, &left, &top );
5865 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
5866 }
5867 #else
5868 int cw, ch;
5869 m_gridWin->GetClientSize(&cw, &ch);
5870 CalcUnscrolledPosition( 0, 0, &left, &top );
5871 CalcUnscrolledPosition( cw, ch, &right, &bottom );
5872 #endif
5873
5874 // avoid drawing grid lines past the last row and col
5875 //
5876 right = wxMin( right, GetColRight(m_numCols - 1) );
5877 bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) );
5878
5879 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
5880
5881 // horizontal grid lines
5882 //
5883 int i;
5884 for ( i = 0; i < m_numRows; i++ )
5885 {
5886 int bot = GetRowBottom(i) - 1;
5887
5888 if ( bot > bottom )
5889 {
5890 break;
5891 }
5892
5893 if ( bot >= top )
5894 {
5895 dc.DrawLine( left, bot, right, bot );
5896 }
5897 }
5898
5899
5900 // vertical grid lines
5901 //
5902 for ( i = 0; i < m_numCols; i++ )
5903 {
5904 int colRight = GetColRight(i) - 1;
5905 if ( colRight > right )
5906 {
5907 break;
5908 }
5909
5910 if ( colRight >= left )
5911 {
5912 dc.DrawLine( colRight, top, colRight, bottom );
5913 }
5914 }
5915 }
5916
5917
5918 void wxGrid::DrawRowLabels( wxDC& dc )
5919 {
5920 if ( !m_numRows ) return;
5921
5922 size_t i;
5923 size_t numLabels = m_rowLabelsExposed.GetCount();
5924
5925 for ( i = 0; i < numLabels; i++ )
5926 {
5927 DrawRowLabel( dc, m_rowLabelsExposed[i] );
5928 }
5929 }
5930
5931
5932 void wxGrid::DrawRowLabel( wxDC& dc, int row )
5933 {
5934 if ( GetRowHeight(row) <= 0 )
5935 return;
5936
5937 int rowTop = GetRowTop(row),
5938 rowBottom = GetRowBottom(row) - 1;
5939
5940 dc.SetPen( *wxBLACK_PEN );
5941 dc.DrawLine( m_rowLabelWidth-1, rowTop,
5942 m_rowLabelWidth-1, rowBottom );
5943
5944 dc.DrawLine( 0, rowBottom, m_rowLabelWidth-1, rowBottom );
5945
5946 dc.SetPen( *wxWHITE_PEN );
5947 dc.DrawLine( 0, rowTop, 0, rowBottom );
5948 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
5949
5950 dc.SetBackgroundMode( wxTRANSPARENT );
5951 dc.SetTextForeground( GetLabelTextColour() );
5952 dc.SetFont( GetLabelFont() );
5953
5954 int hAlign, vAlign;
5955 GetRowLabelAlignment( &hAlign, &vAlign );
5956
5957 wxRect rect;
5958 rect.SetX( 2 );
5959 rect.SetY( GetRowTop(row) + 2 );
5960 rect.SetWidth( m_rowLabelWidth - 4 );
5961 rect.SetHeight( GetRowHeight(row) - 4 );
5962 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
5963 }
5964
5965
5966 void wxGrid::DrawColLabels( wxDC& dc )
5967 {
5968 if ( !m_numCols ) return;
5969
5970 size_t i;
5971 size_t numLabels = m_colLabelsExposed.GetCount();
5972
5973 for ( i = 0; i < numLabels; i++ )
5974 {
5975 DrawColLabel( dc, m_colLabelsExposed[i] );
5976 }
5977 }
5978
5979
5980 void wxGrid::DrawColLabel( wxDC& dc, int col )
5981 {
5982 if ( GetColWidth(col) <= 0 )
5983 return;
5984
5985 int colLeft = GetColLeft(col),
5986 colRight = GetColRight(col) - 1;
5987
5988 dc.SetPen( *wxBLACK_PEN );
5989 dc.DrawLine( colRight, 0,
5990 colRight, m_colLabelHeight-1 );
5991
5992 dc.DrawLine( colLeft, m_colLabelHeight-1,
5993 colRight, m_colLabelHeight-1 );
5994
5995 dc.SetPen( *wxWHITE_PEN );
5996 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
5997 dc.DrawLine( colLeft, 0, colRight, 0 );
5998
5999 dc.SetBackgroundMode( wxTRANSPARENT );
6000 dc.SetTextForeground( GetLabelTextColour() );
6001 dc.SetFont( GetLabelFont() );
6002
6003 dc.SetBackgroundMode( wxTRANSPARENT );
6004 dc.SetTextForeground( GetLabelTextColour() );
6005 dc.SetFont( GetLabelFont() );
6006
6007 int hAlign, vAlign;
6008 GetColLabelAlignment( &hAlign, &vAlign );
6009
6010 wxRect rect;
6011 rect.SetX( colLeft + 2 );
6012 rect.SetY( 2 );
6013 rect.SetWidth( GetColWidth(col) - 4 );
6014 rect.SetHeight( m_colLabelHeight - 4 );
6015 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
6016 }
6017
6018
6019 void wxGrid::DrawTextRectangle( wxDC& dc,
6020 const wxString& value,
6021 const wxRect& rect,
6022 int horizAlign,
6023 int vertAlign )
6024 {
6025 long textWidth, textHeight;
6026 long lineWidth, lineHeight;
6027 wxArrayString lines;
6028
6029 dc.SetClippingRegion( rect );
6030 StringToLines( value, lines );
6031 if ( lines.GetCount() )
6032 {
6033 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
6034 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
6035
6036 float x, y;
6037 switch ( horizAlign )
6038 {
6039 case wxRIGHT:
6040 x = rect.x + (rect.width - textWidth - 1);
6041 break;
6042
6043 case wxCENTRE:
6044 x = rect.x + ((rect.width - textWidth)/2);
6045 break;
6046
6047 case wxLEFT:
6048 default:
6049 x = rect.x + 1;
6050 break;
6051 }
6052
6053 switch ( vertAlign )
6054 {
6055 case wxBOTTOM:
6056 y = rect.y + (rect.height - textHeight - 1);
6057 break;
6058
6059 case wxCENTRE:
6060 y = rect.y + ((rect.height - textHeight)/2);
6061 break;
6062
6063 case wxTOP:
6064 default:
6065 y = rect.y + 1;
6066 break;
6067 }
6068
6069 for ( size_t i = 0; i < lines.GetCount(); i++ )
6070 {
6071 dc.DrawText( lines[i], (int)x, (int)y );
6072 y += lineHeight;
6073 }
6074 }
6075
6076 dc.DestroyClippingRegion();
6077 }
6078
6079
6080 // Split multi line text up into an array of strings. Any existing
6081 // contents of the string array are preserved.
6082 //
6083 void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
6084 {
6085 int startPos = 0;
6086 int pos;
6087 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
6088 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
6089
6090 while ( startPos < (int)tVal.Length() )
6091 {
6092 pos = tVal.Mid(startPos).Find( eol );
6093 if ( pos < 0 )
6094 {
6095 break;
6096 }
6097 else if ( pos == 0 )
6098 {
6099 lines.Add( wxEmptyString );
6100 }
6101 else
6102 {
6103 lines.Add( value.Mid(startPos, pos) );
6104 }
6105 startPos += pos+1;
6106 }
6107 if ( startPos < (int)value.Length() )
6108 {
6109 lines.Add( value.Mid( startPos ) );
6110 }
6111 }
6112
6113
6114 void wxGrid::GetTextBoxSize( wxDC& dc,
6115 wxArrayString& lines,
6116 long *width, long *height )
6117 {
6118 long w = 0;
6119 long h = 0;
6120 long lineW, lineH;
6121
6122 size_t i;
6123 for ( i = 0; i < lines.GetCount(); i++ )
6124 {
6125 dc.GetTextExtent( lines[i], &lineW, &lineH );
6126 w = wxMax( w, lineW );
6127 h += lineH;
6128 }
6129
6130 *width = w;
6131 *height = h;
6132 }
6133
6134 //
6135 // ------ Batch processing.
6136 //
6137 void wxGrid::EndBatch()
6138 {
6139 if ( m_batchCount > 0 )
6140 {
6141 m_batchCount--;
6142 if ( !m_batchCount )
6143 {
6144 CalcDimensions();
6145 m_rowLabelWin->Refresh();
6146 m_colLabelWin->Refresh();
6147 m_cornerLabelWin->Refresh();
6148 m_gridWin->Refresh();
6149 }
6150 }
6151 }
6152
6153 //
6154 // ------ Edit control functions
6155 //
6156
6157
6158 void wxGrid::EnableEditing( bool edit )
6159 {
6160 // TODO: improve this ?
6161 //
6162 if ( edit != m_editable )
6163 {
6164 m_editable = edit;
6165
6166 // FIXME IMHO this won't disable the edit control if edit == FALSE
6167 // because of the check in the beginning of
6168 // EnableCellEditControl() just below (VZ)
6169 EnableCellEditControl(m_editable);
6170 }
6171 }
6172
6173
6174 void wxGrid::EnableCellEditControl( bool enable )
6175 {
6176 if (! m_editable)
6177 return;
6178
6179 if ( m_currentCellCoords == wxGridNoCellCoords )
6180 SetCurrentCell( 0, 0 );
6181
6182 if ( enable != m_cellEditCtrlEnabled )
6183 {
6184 // TODO allow the app to Veto() this event?
6185 SendEvent(enable ? wxEVT_GRID_EDITOR_SHOWN : wxEVT_GRID_EDITOR_HIDDEN);
6186
6187 if ( enable )
6188 {
6189 // this should be checked by the caller!
6190 wxASSERT_MSG( CanEnableCellControl(),
6191 _T("can't enable editing for this cell!") );
6192
6193 // do it before ShowCellEditControl()
6194 m_cellEditCtrlEnabled = enable;
6195
6196 ShowCellEditControl();
6197 }
6198 else
6199 {
6200 HideCellEditControl();
6201 SaveEditControlValue();
6202
6203 // do it after HideCellEditControl()
6204 m_cellEditCtrlEnabled = enable;
6205 }
6206 }
6207 }
6208
6209 bool wxGrid::IsCurrentCellReadOnly() const
6210 {
6211 // const_cast
6212 wxGridCellAttr* attr = ((wxGrid *)this)->GetCellAttr(m_currentCellCoords);
6213 bool readonly = attr->IsReadOnly();
6214 attr->DecRef();
6215
6216 return readonly;
6217 }
6218
6219 bool wxGrid::CanEnableCellControl() const
6220 {
6221 return m_editable && !IsCurrentCellReadOnly();
6222 }
6223
6224 bool wxGrid::IsCellEditControlEnabled() const
6225 {
6226 // the cell edit control might be disable for all cells or just for the
6227 // current one if it's read only
6228 return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : FALSE;
6229 }
6230
6231 bool wxGrid::IsCellEditControlShown() const
6232 {
6233 bool isShown = FALSE;
6234
6235 if ( m_cellEditCtrlEnabled )
6236 {
6237 int row = m_currentCellCoords.GetRow();
6238 int col = m_currentCellCoords.GetCol();
6239 wxGridCellAttr* attr = GetCellAttr(row, col);
6240 wxGridCellEditor* editor = attr->GetEditor((wxGrid*) this, row, col);
6241 attr->DecRef();
6242
6243 if ( editor )
6244 {
6245 if ( editor->IsCreated() )
6246 {
6247 isShown = editor->GetControl()->IsShown();
6248 }
6249
6250 editor->DecRef();
6251 }
6252 }
6253
6254 return isShown;
6255 }
6256
6257 void wxGrid::ShowCellEditControl()
6258 {
6259 if ( IsCellEditControlEnabled() )
6260 {
6261 if ( !IsVisible( m_currentCellCoords ) )
6262 {
6263 return;
6264 }
6265 else
6266 {
6267 wxRect rect = CellToRect( m_currentCellCoords );
6268 int row = m_currentCellCoords.GetRow();
6269 int col = m_currentCellCoords.GetCol();
6270
6271 // convert to scrolled coords
6272 //
6273 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
6274
6275 // done in PaintBackground()
6276 #if 0
6277 // erase the highlight and the cell contents because the editor
6278 // might not cover the entire cell
6279 wxClientDC dc( m_gridWin );
6280 PrepareDC( dc );
6281 dc.SetBrush(*wxLIGHT_GREY_BRUSH); //wxBrush(attr->GetBackgroundColour(), wxSOLID));
6282 dc.SetPen(*wxTRANSPARENT_PEN);
6283 dc.DrawRectangle(rect);
6284 #endif // 0
6285
6286 // cell is shifted by one pixel
6287 rect.x--;
6288 rect.y--;
6289
6290 wxGridCellAttr* attr = GetCellAttr(row, col);
6291 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
6292 if ( !editor->IsCreated() )
6293 {
6294 editor->Create(m_gridWin, -1,
6295 new wxGridCellEditorEvtHandler(this, editor));
6296 }
6297
6298 editor->Show( TRUE, attr );
6299
6300 editor->SetSize( rect );
6301
6302 editor->BeginEdit(row, col, this);
6303
6304 editor->DecRef();
6305 attr->DecRef();
6306 }
6307 }
6308 }
6309
6310
6311 void wxGrid::HideCellEditControl()
6312 {
6313 if ( IsCellEditControlEnabled() )
6314 {
6315 int row = m_currentCellCoords.GetRow();
6316 int col = m_currentCellCoords.GetCol();
6317
6318 wxGridCellAttr* attr = GetCellAttr(row, col);
6319 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
6320 editor->Show( FALSE );
6321 editor->DecRef();
6322 attr->DecRef();
6323 m_gridWin->SetFocus();
6324 wxRect rect( CellToRect( row, col ) );
6325 m_gridWin->Refresh( FALSE, &rect );
6326 }
6327 }
6328
6329
6330 void wxGrid::SaveEditControlValue()
6331 {
6332 if ( IsCellEditControlEnabled() )
6333 {
6334 int row = m_currentCellCoords.GetRow();
6335 int col = m_currentCellCoords.GetCol();
6336
6337 wxGridCellAttr* attr = GetCellAttr(row, col);
6338 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
6339 bool changed = editor->EndEdit(row, col, this);
6340
6341 editor->DecRef();
6342 attr->DecRef();
6343
6344 if (changed)
6345 {
6346 SendEvent( wxEVT_GRID_CELL_CHANGE,
6347 m_currentCellCoords.GetRow(),
6348 m_currentCellCoords.GetCol() );
6349 }
6350 }
6351 }
6352
6353
6354 //
6355 // ------ Grid location functions
6356 // Note that all of these functions work with the logical coordinates of
6357 // grid cells and labels so you will need to convert from device
6358 // coordinates for mouse events etc.
6359 //
6360
6361 void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
6362 {
6363 int row = YToRow(y);
6364 int col = XToCol(x);
6365
6366 if ( row == -1 || col == -1 )
6367 {
6368 coords = wxGridNoCellCoords;
6369 }
6370 else
6371 {
6372 coords.Set( row, col );
6373 }
6374 }
6375
6376
6377 int wxGrid::YToRow( int y )
6378 {
6379 int i;
6380
6381 for ( i = 0; i < m_numRows; i++ )
6382 {
6383 if ( y < GetRowBottom(i) )
6384 return i;
6385 }
6386
6387 return -1;
6388 }
6389
6390
6391 int wxGrid::XToCol( int x )
6392 {
6393 int i;
6394
6395 for ( i = 0; i < m_numCols; i++ )
6396 {
6397 if ( x < GetColRight(i) )
6398 return i;
6399 }
6400
6401 return -1;
6402 }
6403
6404
6405 // return the row number that that the y coord is near the edge of, or
6406 // -1 if not near an edge
6407 //
6408 int wxGrid::YToEdgeOfRow( int y )
6409 {
6410 int i, d;
6411
6412 for ( i = 0; i < m_numRows; i++ )
6413 {
6414 if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE )
6415 {
6416 d = abs( y - GetRowBottom(i) );
6417 if ( d < WXGRID_LABEL_EDGE_ZONE )
6418 return i;
6419 }
6420 }
6421
6422 return -1;
6423 }
6424
6425
6426 // return the col number that that the x coord is near the edge of, or
6427 // -1 if not near an edge
6428 //
6429 int wxGrid::XToEdgeOfCol( int x )
6430 {
6431 int i, d;
6432
6433 for ( i = 0; i < m_numCols; i++ )
6434 {
6435 if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE )
6436 {
6437 d = abs( x - GetColRight(i) );
6438 if ( d < WXGRID_LABEL_EDGE_ZONE )
6439 return i;
6440 }
6441 }
6442
6443 return -1;
6444 }
6445
6446
6447 wxRect wxGrid::CellToRect( int row, int col )
6448 {
6449 wxRect rect( -1, -1, -1, -1 );
6450
6451 if ( row >= 0 && row < m_numRows &&
6452 col >= 0 && col < m_numCols )
6453 {
6454 rect.x = GetColLeft(col);
6455 rect.y = GetRowTop(row);
6456 rect.width = GetColWidth(col);
6457 rect.height = GetRowHeight(row);
6458 }
6459
6460 // if grid lines are enabled, then the area of the cell is a bit smaller
6461 if (m_gridLinesEnabled) {
6462 rect.width -= 1;
6463 rect.height -= 1;
6464 }
6465 return rect;
6466 }
6467
6468
6469 bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
6470 {
6471 // get the cell rectangle in logical coords
6472 //
6473 wxRect r( CellToRect( row, col ) );
6474
6475 // convert to device coords
6476 //
6477 int left, top, right, bottom;
6478 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
6479 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
6480
6481 // check against the client area of the grid window
6482 //
6483 int cw, ch;
6484 m_gridWin->GetClientSize( &cw, &ch );
6485
6486 if ( wholeCellVisible )
6487 {
6488 // is the cell wholly visible ?
6489 //
6490 return ( left >= 0 && right <= cw &&
6491 top >= 0 && bottom <= ch );
6492 }
6493 else
6494 {
6495 // is the cell partly visible ?
6496 //
6497 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
6498 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
6499 }
6500 }
6501
6502
6503 // make the specified cell location visible by doing a minimal amount
6504 // of scrolling
6505 //
6506 void wxGrid::MakeCellVisible( int row, int col )
6507 {
6508 int i;
6509 int xpos = -1, ypos = -1;
6510
6511 if ( row >= 0 && row < m_numRows &&
6512 col >= 0 && col < m_numCols )
6513 {
6514 // get the cell rectangle in logical coords
6515 //
6516 wxRect r( CellToRect( row, col ) );
6517
6518 // convert to device coords
6519 //
6520 int left, top, right, bottom;
6521 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
6522 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
6523
6524 int cw, ch;
6525 m_gridWin->GetClientSize( &cw, &ch );
6526
6527 if ( top < 0 )
6528 {
6529 ypos = r.GetTop();
6530 }
6531 else if ( bottom > ch )
6532 {
6533 int h = r.GetHeight();
6534 ypos = r.GetTop();
6535 for ( i = row-1; i >= 0; i-- )
6536 {
6537 int rowHeight = GetRowHeight(i);
6538 if ( h + rowHeight > ch )
6539 break;
6540
6541 h += rowHeight;
6542 ypos -= rowHeight;
6543 }
6544
6545 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
6546 // have rounding errors (this is important, because if we do, we
6547 // might not scroll at all and some cells won't be redrawn)
6548 ypos += GRID_SCROLL_LINE / 2;
6549 }
6550
6551 if ( left < 0 )
6552 {
6553 xpos = r.GetLeft();
6554 }
6555 else if ( right > cw )
6556 {
6557 int w = r.GetWidth();
6558 xpos = r.GetLeft();
6559 for ( i = col-1; i >= 0; i-- )
6560 {
6561 int colWidth = GetColWidth(i);
6562 if ( w + colWidth > cw )
6563 break;
6564
6565 w += colWidth;
6566 xpos -= colWidth;
6567 }
6568
6569 // see comment for ypos above
6570 xpos += GRID_SCROLL_LINE / 2;
6571 }
6572
6573 if ( xpos != -1 || ypos != -1 )
6574 {
6575 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
6576 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
6577 Scroll( xpos, ypos );
6578 AdjustScrollbars();
6579 }
6580 }
6581 }
6582
6583
6584 //
6585 // ------ Grid cursor movement functions
6586 //
6587
6588 bool wxGrid::MoveCursorUp( bool expandSelection )
6589 {
6590 if ( m_currentCellCoords != wxGridNoCellCoords &&
6591 m_currentCellCoords.GetRow() >= 0 )
6592 {
6593 if ( expandSelection)
6594 {
6595 if ( m_selectingKeyboard == wxGridNoCellCoords )
6596 m_selectingKeyboard = m_currentCellCoords;
6597 if ( m_selectingKeyboard.GetRow() > 0 )
6598 {
6599 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() - 1 );
6600 MakeCellVisible( m_selectingKeyboard.GetRow(),
6601 m_selectingKeyboard.GetCol() );
6602 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6603 }
6604 }
6605 else if ( m_currentCellCoords.GetRow() > 0 )
6606 {
6607 ClearSelection();
6608 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
6609 m_currentCellCoords.GetCol() );
6610 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
6611 m_currentCellCoords.GetCol() );
6612 }
6613 else
6614 return FALSE;
6615 return TRUE;
6616 }
6617
6618 return FALSE;
6619 }
6620
6621
6622 bool wxGrid::MoveCursorDown( bool expandSelection )
6623 {
6624 if ( m_currentCellCoords != wxGridNoCellCoords &&
6625 m_currentCellCoords.GetRow() < m_numRows )
6626 {
6627 if ( expandSelection )
6628 {
6629 if ( m_selectingKeyboard == wxGridNoCellCoords )
6630 m_selectingKeyboard = m_currentCellCoords;
6631 if ( m_selectingKeyboard.GetRow() < m_numRows-1 )
6632 {
6633 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() + 1 );
6634 MakeCellVisible( m_selectingKeyboard.GetRow(),
6635 m_selectingKeyboard.GetCol() );
6636 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6637 }
6638 }
6639 else if ( m_currentCellCoords.GetRow() < m_numRows - 1 )
6640 {
6641 ClearSelection();
6642 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
6643 m_currentCellCoords.GetCol() );
6644 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
6645 m_currentCellCoords.GetCol() );
6646 }
6647 else
6648 return FALSE;
6649 return TRUE;
6650 }
6651
6652 return FALSE;
6653 }
6654
6655
6656 bool wxGrid::MoveCursorLeft( bool expandSelection )
6657 {
6658 if ( m_currentCellCoords != wxGridNoCellCoords &&
6659 m_currentCellCoords.GetCol() >= 0 )
6660 {
6661 if ( expandSelection )
6662 {
6663 if ( m_selectingKeyboard == wxGridNoCellCoords )
6664 m_selectingKeyboard = m_currentCellCoords;
6665 if ( m_selectingKeyboard.GetCol() > 0 )
6666 {
6667 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() - 1 );
6668 MakeCellVisible( m_selectingKeyboard.GetRow(),
6669 m_selectingKeyboard.GetCol() );
6670 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6671 }
6672 }
6673 else if ( m_currentCellCoords.GetCol() > 0 )
6674 {
6675 ClearSelection();
6676 MakeCellVisible( m_currentCellCoords.GetRow(),
6677 m_currentCellCoords.GetCol() - 1 );
6678 SetCurrentCell( m_currentCellCoords.GetRow(),
6679 m_currentCellCoords.GetCol() - 1 );
6680 }
6681 else
6682 return FALSE;
6683 return TRUE;
6684 }
6685
6686 return FALSE;
6687 }
6688
6689
6690 bool wxGrid::MoveCursorRight( bool expandSelection )
6691 {
6692 if ( m_currentCellCoords != wxGridNoCellCoords &&
6693 m_currentCellCoords.GetCol() < m_numCols )
6694 {
6695 if ( expandSelection )
6696 {
6697 if ( m_selectingKeyboard == wxGridNoCellCoords )
6698 m_selectingKeyboard = m_currentCellCoords;
6699 if ( m_selectingKeyboard.GetCol() < m_numCols - 1 )
6700 {
6701 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() + 1 );
6702 MakeCellVisible( m_selectingKeyboard.GetRow(),
6703 m_selectingKeyboard.GetCol() );
6704 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6705 }
6706 }
6707 else if ( m_currentCellCoords.GetCol() < m_numCols - 1 )
6708 {
6709 ClearSelection();
6710 MakeCellVisible( m_currentCellCoords.GetRow(),
6711 m_currentCellCoords.GetCol() + 1 );
6712 SetCurrentCell( m_currentCellCoords.GetRow(),
6713 m_currentCellCoords.GetCol() + 1 );
6714 }
6715 else
6716 return FALSE;
6717 return TRUE;
6718 }
6719
6720 return FALSE;
6721 }
6722
6723
6724 bool wxGrid::MovePageUp()
6725 {
6726 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
6727
6728 int row = m_currentCellCoords.GetRow();
6729 if ( row > 0 )
6730 {
6731 int cw, ch;
6732 m_gridWin->GetClientSize( &cw, &ch );
6733
6734 int y = GetRowTop(row);
6735 int newRow = YToRow( y - ch + 1 );
6736 if ( newRow == -1 )
6737 {
6738 newRow = 0;
6739 }
6740 else if ( newRow == row )
6741 {
6742 newRow = row - 1;
6743 }
6744
6745 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
6746 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
6747
6748 return TRUE;
6749 }
6750
6751 return FALSE;
6752 }
6753
6754 bool wxGrid::MovePageDown()
6755 {
6756 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
6757
6758 int row = m_currentCellCoords.GetRow();
6759 if ( row < m_numRows )
6760 {
6761 int cw, ch;
6762 m_gridWin->GetClientSize( &cw, &ch );
6763
6764 int y = GetRowTop(row);
6765 int newRow = YToRow( y + ch );
6766 if ( newRow == -1 )
6767 {
6768 newRow = m_numRows - 1;
6769 }
6770 else if ( newRow == row )
6771 {
6772 newRow = row + 1;
6773 }
6774
6775 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
6776 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
6777
6778 return TRUE;
6779 }
6780
6781 return FALSE;
6782 }
6783
6784 bool wxGrid::MoveCursorUpBlock( bool expandSelection )
6785 {
6786 if ( m_table &&
6787 m_currentCellCoords != wxGridNoCellCoords &&
6788 m_currentCellCoords.GetRow() > 0 )
6789 {
6790 int row = m_currentCellCoords.GetRow();
6791 int col = m_currentCellCoords.GetCol();
6792
6793 if ( m_table->IsEmptyCell(row, col) )
6794 {
6795 // starting in an empty cell: find the next block of
6796 // non-empty cells
6797 //
6798 while ( row > 0 )
6799 {
6800 row-- ;
6801 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6802 }
6803 }
6804 else if ( m_table->IsEmptyCell(row-1, col) )
6805 {
6806 // starting at the top of a block: find the next block
6807 //
6808 row--;
6809 while ( row > 0 )
6810 {
6811 row-- ;
6812 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6813 }
6814 }
6815 else
6816 {
6817 // starting within a block: find the top of the block
6818 //
6819 while ( row > 0 )
6820 {
6821 row-- ;
6822 if ( m_table->IsEmptyCell(row, col) )
6823 {
6824 row++ ;
6825 break;
6826 }
6827 }
6828 }
6829
6830 MakeCellVisible( row, col );
6831 if ( expandSelection )
6832 {
6833 m_selectingKeyboard = wxGridCellCoords( row, col );
6834 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6835 }
6836 else
6837 {
6838 ClearSelection();
6839 SetCurrentCell( row, col );
6840 }
6841 return TRUE;
6842 }
6843
6844 return FALSE;
6845 }
6846
6847 bool wxGrid::MoveCursorDownBlock( bool expandSelection )
6848 {
6849 if ( m_table &&
6850 m_currentCellCoords != wxGridNoCellCoords &&
6851 m_currentCellCoords.GetRow() < m_numRows-1 )
6852 {
6853 int row = m_currentCellCoords.GetRow();
6854 int col = m_currentCellCoords.GetCol();
6855
6856 if ( m_table->IsEmptyCell(row, col) )
6857 {
6858 // starting in an empty cell: find the next block of
6859 // non-empty cells
6860 //
6861 while ( row < m_numRows-1 )
6862 {
6863 row++ ;
6864 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6865 }
6866 }
6867 else if ( m_table->IsEmptyCell(row+1, col) )
6868 {
6869 // starting at the bottom of a block: find the next block
6870 //
6871 row++;
6872 while ( row < m_numRows-1 )
6873 {
6874 row++ ;
6875 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6876 }
6877 }
6878 else
6879 {
6880 // starting within a block: find the bottom of the block
6881 //
6882 while ( row < m_numRows-1 )
6883 {
6884 row++ ;
6885 if ( m_table->IsEmptyCell(row, col) )
6886 {
6887 row-- ;
6888 break;
6889 }
6890 }
6891 }
6892
6893 MakeCellVisible( row, col );
6894 if ( expandSelection )
6895 {
6896 m_selectingKeyboard = wxGridCellCoords( row, col );
6897 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6898 }
6899 else
6900 {
6901 ClearSelection();
6902 SetCurrentCell( row, col );
6903 }
6904
6905 return TRUE;
6906 }
6907
6908 return FALSE;
6909 }
6910
6911 bool wxGrid::MoveCursorLeftBlock( bool expandSelection )
6912 {
6913 if ( m_table &&
6914 m_currentCellCoords != wxGridNoCellCoords &&
6915 m_currentCellCoords.GetCol() > 0 )
6916 {
6917 int row = m_currentCellCoords.GetRow();
6918 int col = m_currentCellCoords.GetCol();
6919
6920 if ( m_table->IsEmptyCell(row, col) )
6921 {
6922 // starting in an empty cell: find the next block of
6923 // non-empty cells
6924 //
6925 while ( col > 0 )
6926 {
6927 col-- ;
6928 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6929 }
6930 }
6931 else if ( m_table->IsEmptyCell(row, col-1) )
6932 {
6933 // starting at the left of a block: find the next block
6934 //
6935 col--;
6936 while ( col > 0 )
6937 {
6938 col-- ;
6939 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6940 }
6941 }
6942 else
6943 {
6944 // starting within a block: find the left of the block
6945 //
6946 while ( col > 0 )
6947 {
6948 col-- ;
6949 if ( m_table->IsEmptyCell(row, col) )
6950 {
6951 col++ ;
6952 break;
6953 }
6954 }
6955 }
6956
6957 MakeCellVisible( row, col );
6958 if ( expandSelection )
6959 {
6960 m_selectingKeyboard = wxGridCellCoords( row, col );
6961 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6962 }
6963 else
6964 {
6965 ClearSelection();
6966 SetCurrentCell( row, col );
6967 }
6968
6969 return TRUE;
6970 }
6971
6972 return FALSE;
6973 }
6974
6975 bool wxGrid::MoveCursorRightBlock( bool expandSelection )
6976 {
6977 if ( m_table &&
6978 m_currentCellCoords != wxGridNoCellCoords &&
6979 m_currentCellCoords.GetCol() < m_numCols-1 )
6980 {
6981 int row = m_currentCellCoords.GetRow();
6982 int col = m_currentCellCoords.GetCol();
6983
6984 if ( m_table->IsEmptyCell(row, col) )
6985 {
6986 // starting in an empty cell: find the next block of
6987 // non-empty cells
6988 //
6989 while ( col < m_numCols-1 )
6990 {
6991 col++ ;
6992 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6993 }
6994 }
6995 else if ( m_table->IsEmptyCell(row, col+1) )
6996 {
6997 // starting at the right of a block: find the next block
6998 //
6999 col++;
7000 while ( col < m_numCols-1 )
7001 {
7002 col++ ;
7003 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7004 }
7005 }
7006 else
7007 {
7008 // starting within a block: find the right of the block
7009 //
7010 while ( col < m_numCols-1 )
7011 {
7012 col++ ;
7013 if ( m_table->IsEmptyCell(row, col) )
7014 {
7015 col-- ;
7016 break;
7017 }
7018 }
7019 }
7020
7021 MakeCellVisible( row, col );
7022 if ( expandSelection )
7023 {
7024 m_selectingKeyboard = wxGridCellCoords( row, col );
7025 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
7026 }
7027 else
7028 {
7029 ClearSelection();
7030 SetCurrentCell( row, col );
7031 }
7032
7033 return TRUE;
7034 }
7035
7036 return FALSE;
7037 }
7038
7039
7040
7041 //
7042 // ------ Label values and formatting
7043 //
7044
7045 void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
7046 {
7047 *horiz = m_rowLabelHorizAlign;
7048 *vert = m_rowLabelVertAlign;
7049 }
7050
7051 void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
7052 {
7053 *horiz = m_colLabelHorizAlign;
7054 *vert = m_colLabelVertAlign;
7055 }
7056
7057 wxString wxGrid::GetRowLabelValue( int row )
7058 {
7059 if ( m_table )
7060 {
7061 return m_table->GetRowLabelValue( row );
7062 }
7063 else
7064 {
7065 wxString s;
7066 s << row;
7067 return s;
7068 }
7069 }
7070
7071 wxString wxGrid::GetColLabelValue( int col )
7072 {
7073 if ( m_table )
7074 {
7075 return m_table->GetColLabelValue( col );
7076 }
7077 else
7078 {
7079 wxString s;
7080 s << col;
7081 return s;
7082 }
7083 }
7084
7085
7086 void wxGrid::SetRowLabelSize( int width )
7087 {
7088 width = wxMax( width, 0 );
7089 if ( width != m_rowLabelWidth )
7090 {
7091 if ( width == 0 )
7092 {
7093 m_rowLabelWin->Show( FALSE );
7094 m_cornerLabelWin->Show( FALSE );
7095 }
7096 else if ( m_rowLabelWidth == 0 )
7097 {
7098 m_rowLabelWin->Show( TRUE );
7099 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
7100 }
7101
7102 m_rowLabelWidth = width;
7103 CalcWindowSizes();
7104 Refresh( TRUE );
7105 }
7106 }
7107
7108
7109 void wxGrid::SetColLabelSize( int height )
7110 {
7111 height = wxMax( height, 0 );
7112 if ( height != m_colLabelHeight )
7113 {
7114 if ( height == 0 )
7115 {
7116 m_colLabelWin->Show( FALSE );
7117 m_cornerLabelWin->Show( FALSE );
7118 }
7119 else if ( m_colLabelHeight == 0 )
7120 {
7121 m_colLabelWin->Show( TRUE );
7122 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
7123 }
7124
7125 m_colLabelHeight = height;
7126 CalcWindowSizes();
7127 Refresh( TRUE );
7128 }
7129 }
7130
7131
7132 void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
7133 {
7134 if ( m_labelBackgroundColour != colour )
7135 {
7136 m_labelBackgroundColour = colour;
7137 m_rowLabelWin->SetBackgroundColour( colour );
7138 m_colLabelWin->SetBackgroundColour( colour );
7139 m_cornerLabelWin->SetBackgroundColour( colour );
7140
7141 if ( !GetBatchCount() )
7142 {
7143 m_rowLabelWin->Refresh();
7144 m_colLabelWin->Refresh();
7145 m_cornerLabelWin->Refresh();
7146 }
7147 }
7148 }
7149
7150 void wxGrid::SetLabelTextColour( const wxColour& colour )
7151 {
7152 if ( m_labelTextColour != colour )
7153 {
7154 m_labelTextColour = colour;
7155 if ( !GetBatchCount() )
7156 {
7157 m_rowLabelWin->Refresh();
7158 m_colLabelWin->Refresh();
7159 }
7160 }
7161 }
7162
7163 void wxGrid::SetLabelFont( const wxFont& font )
7164 {
7165 m_labelFont = font;
7166 if ( !GetBatchCount() )
7167 {
7168 m_rowLabelWin->Refresh();
7169 m_colLabelWin->Refresh();
7170 }
7171 }
7172
7173 void wxGrid::SetRowLabelAlignment( int horiz, int vert )
7174 {
7175 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
7176 {
7177 m_rowLabelHorizAlign = horiz;
7178 }
7179
7180 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
7181 {
7182 m_rowLabelVertAlign = vert;
7183 }
7184
7185 if ( !GetBatchCount() )
7186 {
7187 m_rowLabelWin->Refresh();
7188 }
7189 }
7190
7191 void wxGrid::SetColLabelAlignment( int horiz, int vert )
7192 {
7193 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
7194 {
7195 m_colLabelHorizAlign = horiz;
7196 }
7197
7198 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
7199 {
7200 m_colLabelVertAlign = vert;
7201 }
7202
7203 if ( !GetBatchCount() )
7204 {
7205 m_colLabelWin->Refresh();
7206 }
7207 }
7208
7209 void wxGrid::SetRowLabelValue( int row, const wxString& s )
7210 {
7211 if ( m_table )
7212 {
7213 m_table->SetRowLabelValue( row, s );
7214 if ( !GetBatchCount() )
7215 {
7216 wxRect rect = CellToRect( row, 0);
7217 if ( rect.height > 0 )
7218 {
7219 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
7220 rect.x = m_left;
7221 rect.width = m_rowLabelWidth;
7222 m_rowLabelWin->Refresh( TRUE, &rect );
7223 }
7224 }
7225 }
7226 }
7227
7228 void wxGrid::SetColLabelValue( int col, const wxString& s )
7229 {
7230 if ( m_table )
7231 {
7232 m_table->SetColLabelValue( col, s );
7233 if ( !GetBatchCount() )
7234 {
7235 wxRect rect = CellToRect( 0, col );
7236 if ( rect.width > 0 )
7237 {
7238 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
7239 rect.y = m_top;
7240 rect.height = m_colLabelHeight;
7241 m_colLabelWin->Refresh( TRUE, &rect );
7242 }
7243 }
7244 }
7245 }
7246
7247 void wxGrid::SetGridLineColour( const wxColour& colour )
7248 {
7249 if ( m_gridLineColour != colour )
7250 {
7251 m_gridLineColour = colour;
7252
7253 wxClientDC dc( m_gridWin );
7254 PrepareDC( dc );
7255 DrawAllGridLines( dc, wxRegion() );
7256 }
7257 }
7258
7259
7260 void wxGrid::SetCellHighlightColour( const wxColour& colour )
7261 {
7262 if ( m_cellHighlightColour != colour )
7263 {
7264 m_cellHighlightColour = colour;
7265
7266 wxClientDC dc( m_gridWin );
7267 PrepareDC( dc );
7268 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
7269 DrawCellHighlight(dc, attr);
7270 attr->DecRef();
7271 }
7272 }
7273
7274 void wxGrid::EnableGridLines( bool enable )
7275 {
7276 if ( enable != m_gridLinesEnabled )
7277 {
7278 m_gridLinesEnabled = enable;
7279
7280 if ( !GetBatchCount() )
7281 {
7282 if ( enable )
7283 {
7284 wxClientDC dc( m_gridWin );
7285 PrepareDC( dc );
7286 DrawAllGridLines( dc, wxRegion() );
7287 }
7288 else
7289 {
7290 m_gridWin->Refresh();
7291 }
7292 }
7293 }
7294 }
7295
7296
7297 int wxGrid::GetDefaultRowSize()
7298 {
7299 return m_defaultRowHeight;
7300 }
7301
7302 int wxGrid::GetRowSize( int row )
7303 {
7304 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
7305
7306 return GetRowHeight(row);
7307 }
7308
7309 int wxGrid::GetDefaultColSize()
7310 {
7311 return m_defaultColWidth;
7312 }
7313
7314 int wxGrid::GetColSize( int col )
7315 {
7316 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
7317
7318 return GetColWidth(col);
7319 }
7320
7321 // ============================================================================
7322 // access to the grid attributes: each of them has a default value in the grid
7323 // itself and may be overidden on a per-cell basis
7324 // ============================================================================
7325
7326 // ----------------------------------------------------------------------------
7327 // setting default attributes
7328 // ----------------------------------------------------------------------------
7329
7330 void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
7331 {
7332 m_defaultCellAttr->SetBackgroundColour(col);
7333 #ifdef __WXGTK__
7334 m_gridWin->SetBackgroundColour(col);
7335 #endif
7336 }
7337
7338 void wxGrid::SetDefaultCellTextColour( const wxColour& col )
7339 {
7340 m_defaultCellAttr->SetTextColour(col);
7341 }
7342
7343 void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
7344 {
7345 m_defaultCellAttr->SetAlignment(horiz, vert);
7346 }
7347
7348 void wxGrid::SetDefaultCellFont( const wxFont& font )
7349 {
7350 m_defaultCellAttr->SetFont(font);
7351 }
7352
7353 void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
7354 {
7355 m_defaultCellAttr->SetRenderer(renderer);
7356 }
7357
7358 void wxGrid::SetDefaultEditor(wxGridCellEditor *editor)
7359 {
7360 m_defaultCellAttr->SetEditor(editor);
7361 }
7362
7363 // ----------------------------------------------------------------------------
7364 // access to the default attrbiutes
7365 // ----------------------------------------------------------------------------
7366
7367 wxColour wxGrid::GetDefaultCellBackgroundColour()
7368 {
7369 return m_defaultCellAttr->GetBackgroundColour();
7370 }
7371
7372 wxColour wxGrid::GetDefaultCellTextColour()
7373 {
7374 return m_defaultCellAttr->GetTextColour();
7375 }
7376
7377 wxFont wxGrid::GetDefaultCellFont()
7378 {
7379 return m_defaultCellAttr->GetFont();
7380 }
7381
7382 void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
7383 {
7384 m_defaultCellAttr->GetAlignment(horiz, vert);
7385 }
7386
7387 wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
7388 {
7389 return m_defaultCellAttr->GetRenderer(NULL, 0, 0);
7390 }
7391
7392 wxGridCellEditor *wxGrid::GetDefaultEditor() const
7393 {
7394 return m_defaultCellAttr->GetEditor(NULL,0,0);
7395 }
7396
7397 // ----------------------------------------------------------------------------
7398 // access to cell attributes
7399 // ----------------------------------------------------------------------------
7400
7401 wxColour wxGrid::GetCellBackgroundColour(int row, int col)
7402 {
7403 wxGridCellAttr *attr = GetCellAttr(row, col);
7404 wxColour colour = attr->GetBackgroundColour();
7405 attr->DecRef();
7406 return colour;
7407 }
7408
7409 wxColour wxGrid::GetCellTextColour( int row, int col )
7410 {
7411 wxGridCellAttr *attr = GetCellAttr(row, col);
7412 wxColour colour = attr->GetTextColour();
7413 attr->DecRef();
7414 return colour;
7415 }
7416
7417 wxFont wxGrid::GetCellFont( int row, int col )
7418 {
7419 wxGridCellAttr *attr = GetCellAttr(row, col);
7420 wxFont font = attr->GetFont();
7421 attr->DecRef();
7422 return font;
7423 }
7424
7425 void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
7426 {
7427 wxGridCellAttr *attr = GetCellAttr(row, col);
7428 attr->GetAlignment(horiz, vert);
7429 attr->DecRef();
7430 }
7431
7432 wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
7433 {
7434 wxGridCellAttr* attr = GetCellAttr(row, col);
7435 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
7436 attr->DecRef();
7437
7438 return renderer;
7439 }
7440
7441 wxGridCellEditor* wxGrid::GetCellEditor(int row, int col)
7442 {
7443 wxGridCellAttr* attr = GetCellAttr(row, col);
7444 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
7445 attr->DecRef();
7446
7447 return editor;
7448 }
7449
7450 bool wxGrid::IsReadOnly(int row, int col) const
7451 {
7452 wxGridCellAttr* attr = GetCellAttr(row, col);
7453 bool isReadOnly = attr->IsReadOnly();
7454 attr->DecRef();
7455 return isReadOnly;
7456 }
7457
7458 // ----------------------------------------------------------------------------
7459 // attribute support: cache, automatic provider creation, ...
7460 // ----------------------------------------------------------------------------
7461
7462 bool wxGrid::CanHaveAttributes()
7463 {
7464 if ( !m_table )
7465 {
7466 return FALSE;
7467 }
7468
7469 return m_table->CanHaveAttributes();
7470 }
7471
7472 void wxGrid::ClearAttrCache()
7473 {
7474 if ( m_attrCache.row != -1 )
7475 {
7476 wxSafeDecRef(m_attrCache.attr);
7477 m_attrCache.row = -1;
7478 }
7479 }
7480
7481 void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
7482 {
7483 wxGrid *self = (wxGrid *)this; // const_cast
7484
7485 self->ClearAttrCache();
7486 self->m_attrCache.row = row;
7487 self->m_attrCache.col = col;
7488 self->m_attrCache.attr = attr;
7489 wxSafeIncRef(attr);
7490 }
7491
7492 bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
7493 {
7494 if ( row == m_attrCache.row && col == m_attrCache.col )
7495 {
7496 *attr = m_attrCache.attr;
7497 wxSafeIncRef(m_attrCache.attr);
7498
7499 #ifdef DEBUG_ATTR_CACHE
7500 gs_nAttrCacheHits++;
7501 #endif
7502
7503 return TRUE;
7504 }
7505 else
7506 {
7507 #ifdef DEBUG_ATTR_CACHE
7508 gs_nAttrCacheMisses++;
7509 #endif
7510 return FALSE;
7511 }
7512 }
7513
7514 wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
7515 {
7516 wxGridCellAttr *attr;
7517 if ( !LookupAttr(row, col, &attr) )
7518 {
7519 attr = m_table ? m_table->GetAttr(row, col) : (wxGridCellAttr *)NULL;
7520 CacheAttr(row, col, attr);
7521 }
7522 if (attr)
7523 {
7524 attr->SetDefAttr(m_defaultCellAttr);
7525 }
7526 else
7527 {
7528 attr = m_defaultCellAttr;
7529 attr->IncRef();
7530 }
7531
7532 return attr;
7533 }
7534
7535 wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
7536 {
7537 wxGridCellAttr *attr;
7538 if ( !LookupAttr(row, col, &attr) || !attr )
7539 {
7540 wxASSERT_MSG( m_table,
7541 _T("we may only be called if CanHaveAttributes() returned TRUE and then m_table should be !NULL") );
7542
7543 attr = m_table->GetAttr(row, col);
7544 if ( !attr )
7545 {
7546 attr = new wxGridCellAttr;
7547
7548 // artificially inc the ref count to match DecRef() in caller
7549 attr->IncRef();
7550
7551 m_table->SetAttr(attr, row, col);
7552 }
7553
7554 CacheAttr(row, col, attr);
7555 }
7556 attr->SetDefAttr(m_defaultCellAttr);
7557 return attr;
7558 }
7559
7560 // ----------------------------------------------------------------------------
7561 // setting column attributes (wrappers around SetColAttr)
7562 // ----------------------------------------------------------------------------
7563
7564 void wxGrid::SetColFormatBool(int col)
7565 {
7566 SetColFormatCustom(col, wxGRID_VALUE_BOOL);
7567 }
7568
7569 void wxGrid::SetColFormatNumber(int col)
7570 {
7571 SetColFormatCustom(col, wxGRID_VALUE_NUMBER);
7572 }
7573
7574 void wxGrid::SetColFormatFloat(int col, int width, int precision)
7575 {
7576 wxString typeName = wxGRID_VALUE_FLOAT;
7577 if ( (width != -1) || (precision != -1) )
7578 {
7579 typeName << _T(':') << width << _T(',') << precision;
7580 }
7581
7582 SetColFormatCustom(col, typeName);
7583 }
7584
7585 void wxGrid::SetColFormatCustom(int col, const wxString& typeName)
7586 {
7587 wxGridCellAttr *attr = new wxGridCellAttr;
7588 wxGridCellRenderer *renderer = GetDefaultRendererForType(typeName);
7589 attr->SetRenderer(renderer);
7590
7591 SetColAttr(col, attr);
7592 }
7593
7594 // ----------------------------------------------------------------------------
7595 // setting cell attributes: this is forwarded to the table
7596 // ----------------------------------------------------------------------------
7597
7598 void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
7599 {
7600 if ( CanHaveAttributes() )
7601 {
7602 m_table->SetRowAttr(attr, row);
7603 }
7604 else
7605 {
7606 wxSafeDecRef(attr);
7607 }
7608 }
7609
7610 void wxGrid::SetColAttr(int col, wxGridCellAttr *attr)
7611 {
7612 if ( CanHaveAttributes() )
7613 {
7614 m_table->SetColAttr(attr, col);
7615 }
7616 else
7617 {
7618 wxSafeDecRef(attr);
7619 }
7620 }
7621
7622 void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
7623 {
7624 if ( CanHaveAttributes() )
7625 {
7626 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7627 attr->SetBackgroundColour(colour);
7628 attr->DecRef();
7629 }
7630 }
7631
7632 void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
7633 {
7634 if ( CanHaveAttributes() )
7635 {
7636 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7637 attr->SetTextColour(colour);
7638 attr->DecRef();
7639 }
7640 }
7641
7642 void wxGrid::SetCellFont( int row, int col, const wxFont& font )
7643 {
7644 if ( CanHaveAttributes() )
7645 {
7646 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7647 attr->SetFont(font);
7648 attr->DecRef();
7649 }
7650 }
7651
7652 void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
7653 {
7654 if ( CanHaveAttributes() )
7655 {
7656 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7657 attr->SetAlignment(horiz, vert);
7658 attr->DecRef();
7659 }
7660 }
7661
7662 void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
7663 {
7664 if ( CanHaveAttributes() )
7665 {
7666 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7667 attr->SetRenderer(renderer);
7668 attr->DecRef();
7669 }
7670 }
7671
7672 void wxGrid::SetCellEditor(int row, int col, wxGridCellEditor* editor)
7673 {
7674 if ( CanHaveAttributes() )
7675 {
7676 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7677 attr->SetEditor(editor);
7678 attr->DecRef();
7679 }
7680 }
7681
7682 void wxGrid::SetReadOnly(int row, int col, bool isReadOnly)
7683 {
7684 if ( CanHaveAttributes() )
7685 {
7686 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7687 attr->SetReadOnly(isReadOnly);
7688 attr->DecRef();
7689 }
7690 }
7691
7692 // ----------------------------------------------------------------------------
7693 // Data type registration
7694 // ----------------------------------------------------------------------------
7695
7696 void wxGrid::RegisterDataType(const wxString& typeName,
7697 wxGridCellRenderer* renderer,
7698 wxGridCellEditor* editor)
7699 {
7700 m_typeRegistry->RegisterDataType(typeName, renderer, editor);
7701 }
7702
7703
7704 wxGridCellEditor* wxGrid::GetDefaultEditorForCell(int row, int col) const
7705 {
7706 wxString typeName = m_table->GetTypeName(row, col);
7707 return GetDefaultEditorForType(typeName);
7708 }
7709
7710 wxGridCellRenderer* wxGrid::GetDefaultRendererForCell(int row, int col) const
7711 {
7712 wxString typeName = m_table->GetTypeName(row, col);
7713 return GetDefaultRendererForType(typeName);
7714 }
7715
7716 wxGridCellEditor*
7717 wxGrid::GetDefaultEditorForType(const wxString& typeName) const
7718 {
7719 int index = m_typeRegistry->FindOrCloneDataType(typeName);
7720 if ( index == wxNOT_FOUND )
7721 {
7722 wxFAIL_MSG(wxT("Unknown data type name"));
7723
7724 return NULL;
7725 }
7726
7727 return m_typeRegistry->GetEditor(index);
7728 }
7729
7730 wxGridCellRenderer*
7731 wxGrid::GetDefaultRendererForType(const wxString& typeName) const
7732 {
7733 int index = m_typeRegistry->FindOrCloneDataType(typeName);
7734 if ( index == wxNOT_FOUND )
7735 {
7736 wxFAIL_MSG(wxT("Unknown data type name"));
7737
7738 return NULL;
7739 }
7740
7741 return m_typeRegistry->GetRenderer(index);
7742 }
7743
7744
7745 // ----------------------------------------------------------------------------
7746 // row/col size
7747 // ----------------------------------------------------------------------------
7748
7749 void wxGrid::EnableDragRowSize( bool enable )
7750 {
7751 m_canDragRowSize = enable;
7752 }
7753
7754
7755 void wxGrid::EnableDragColSize( bool enable )
7756 {
7757 m_canDragColSize = enable;
7758 }
7759
7760 void wxGrid::EnableDragGridSize( bool enable )
7761 {
7762 m_canDragGridSize = enable;
7763 }
7764
7765
7766 void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
7767 {
7768 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
7769
7770 if ( resizeExistingRows )
7771 {
7772 InitRowHeights();
7773
7774 CalcDimensions();
7775 }
7776 }
7777
7778 void wxGrid::SetRowSize( int row, int height )
7779 {
7780 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
7781
7782 if ( m_rowHeights.IsEmpty() )
7783 {
7784 // need to really create the array
7785 InitRowHeights();
7786 }
7787
7788 int h = wxMax( 0, height );
7789 int diff = h - m_rowHeights[row];
7790
7791 m_rowHeights[row] = h;
7792 int i;
7793 for ( i = row; i < m_numRows; i++ )
7794 {
7795 m_rowBottoms[i] += diff;
7796 }
7797 CalcDimensions();
7798 }
7799
7800 void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
7801 {
7802 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
7803
7804 if ( resizeExistingCols )
7805 {
7806 InitColWidths();
7807
7808 CalcDimensions();
7809 }
7810 }
7811
7812 void wxGrid::SetColSize( int col, int width )
7813 {
7814 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
7815
7816 // should we check that it's bigger than GetColMinimalWidth(col) here?
7817
7818 if ( m_colWidths.IsEmpty() )
7819 {
7820 // need to really create the array
7821 InitColWidths();
7822 }
7823
7824 int w = wxMax( 0, width );
7825 int diff = w - m_colWidths[col];
7826 m_colWidths[col] = w;
7827
7828 int i;
7829 for ( i = col; i < m_numCols; i++ )
7830 {
7831 m_colRights[i] += diff;
7832 }
7833 CalcDimensions();
7834 }
7835
7836
7837 void wxGrid::SetColMinimalWidth( int col, int width )
7838 {
7839 m_colMinWidths.Put(col, width);
7840 }
7841
7842 void wxGrid::SetRowMinimalHeight( int row, int width )
7843 {
7844 m_rowMinHeights.Put(row, width);
7845 }
7846
7847 int wxGrid::GetColMinimalWidth(int col) const
7848 {
7849 long value = m_colMinWidths.Get(col);
7850 return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_COL_WIDTH;
7851 }
7852
7853 int wxGrid::GetRowMinimalHeight(int row) const
7854 {
7855 long value = m_rowMinHeights.Get(row);
7856 return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_ROW_HEIGHT;
7857 }
7858
7859 // ----------------------------------------------------------------------------
7860 // auto sizing
7861 // ----------------------------------------------------------------------------
7862
7863 void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column )
7864 {
7865 wxClientDC dc(m_gridWin);
7866
7867 // init both of them to avoid compiler warnings, even if weo nly need one
7868 int row = -1,
7869 col = -1;
7870 if ( column )
7871 col = colOrRow;
7872 else
7873 row = colOrRow;
7874
7875 wxCoord extent, extentMax = 0;
7876 int max = column ? m_numRows : m_numCols;
7877 for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ )
7878 {
7879 if ( column )
7880 row = rowOrCol;
7881 else
7882 col = rowOrCol;
7883
7884 wxGridCellAttr* attr = GetCellAttr(row, col);
7885 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
7886 if ( renderer )
7887 {
7888 wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col);
7889 extent = column ? size.x : size.y;
7890 if ( extent > extentMax )
7891 {
7892 extentMax = extent;
7893 }
7894
7895 renderer->DecRef();
7896 }
7897
7898 attr->DecRef();
7899 }
7900
7901 // now also compare with the column label extent
7902 wxCoord w, h;
7903 dc.SetFont( GetLabelFont() );
7904
7905 if ( column )
7906 dc.GetTextExtent( GetColLabelValue(col), &w, &h );
7907 else
7908 dc.GetTextExtent( GetRowLabelValue(col), &w, &h );
7909
7910 extent = column ? w : h;
7911 if ( extent > extentMax )
7912 {
7913 extentMax = extent;
7914 }
7915
7916 if ( !extentMax )
7917 {
7918 // empty column - give default extent (notice that if extentMax is less
7919 // than default extent but != 0, it's ok)
7920 extentMax = column ? m_defaultColWidth : m_defaultRowHeight;
7921 }
7922 else
7923 {
7924 if ( column )
7925 {
7926 // leave some space around text
7927 extentMax += 10;
7928 }
7929 else
7930 {
7931 extentMax += 6;
7932 }
7933 }
7934
7935 if ( column )
7936 SetColSize(col, extentMax);
7937 else
7938 SetRowSize(row, extentMax);
7939
7940 if ( setAsMin )
7941 {
7942 if ( column )
7943 SetColMinimalWidth(col, extentMax);
7944 else
7945 SetRowMinimalHeight(row, extentMax);
7946 }
7947 }
7948
7949 int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
7950 {
7951 int width = m_rowLabelWidth;
7952
7953 for ( int col = 0; col < m_numCols; col++ )
7954 {
7955 if ( !calcOnly )
7956 {
7957 AutoSizeColumn(col, setAsMin);
7958 }
7959
7960 width += GetColWidth(col);
7961 }
7962
7963 return width;
7964 }
7965
7966 int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
7967 {
7968 int height = m_colLabelHeight;
7969
7970 for ( int row = 0; row < m_numRows; row++ )
7971 {
7972 if ( !calcOnly )
7973 {
7974 AutoSizeRow(row, setAsMin);
7975 }
7976
7977 height += GetRowHeight(row);
7978 }
7979
7980 return height;
7981 }
7982
7983 void wxGrid::AutoSize()
7984 {
7985 // set the size too
7986 SetSize(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE));
7987 }
7988
7989 wxSize wxGrid::DoGetBestSize() const
7990 {
7991 // don't set sizes, only calculate them
7992 wxGrid *self = (wxGrid *)this; // const_cast
7993
7994 return wxSize(self->SetOrCalcColumnSizes(TRUE),
7995 self->SetOrCalcRowSizes(TRUE));
7996 }
7997
7998 void wxGrid::Fit()
7999 {
8000 AutoSize();
8001 }
8002
8003
8004 wxPen& wxGrid::GetDividerPen() const
8005 {
8006 return wxNullPen;
8007 }
8008
8009 // ----------------------------------------------------------------------------
8010 // cell value accessor functions
8011 // ----------------------------------------------------------------------------
8012
8013 void wxGrid::SetCellValue( int row, int col, const wxString& s )
8014 {
8015 if ( m_table )
8016 {
8017 m_table->SetValue( row, col, s );
8018 if ( !GetBatchCount() )
8019 {
8020 wxClientDC dc( m_gridWin );
8021 PrepareDC( dc );
8022 DrawCell( dc, wxGridCellCoords(row, col) );
8023 }
8024
8025 if ( m_currentCellCoords.GetRow() == row &&
8026 m_currentCellCoords.GetCol() == col &&
8027 IsCellEditControlShown())
8028 // Note: If we are using IsCellEditControlEnabled,
8029 // this interacts badly with calling SetCellValue from
8030 // an EVT_GRID_CELL_CHANGE handler.
8031 {
8032 HideCellEditControl();
8033 ShowCellEditControl(); // will reread data from table
8034 }
8035 }
8036 }
8037
8038
8039 //
8040 // ------ Block, row and col selection
8041 //
8042
8043 void wxGrid::SelectRow( int row, bool addToSelected )
8044 {
8045 if ( IsSelection() && !addToSelected )
8046 ClearSelection();
8047
8048 m_selection->SelectRow( row, FALSE, addToSelected );
8049 }
8050
8051
8052 void wxGrid::SelectCol( int col, bool addToSelected )
8053 {
8054 if ( IsSelection() && !addToSelected )
8055 ClearSelection();
8056
8057 m_selection->SelectCol( col, FALSE, addToSelected );
8058 }
8059
8060
8061 void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
8062 {
8063 int temp;
8064 wxGridCellCoords updateTopLeft, updateBottomRight;
8065
8066 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
8067 {
8068 leftCol = 0;
8069 rightCol = GetNumberCols() - 1;
8070 }
8071 else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
8072 {
8073 topRow = 0;
8074 bottomRow = GetNumberRows() - 1;
8075 }
8076 if ( topRow > bottomRow )
8077 {
8078 temp = topRow;
8079 topRow = bottomRow;
8080 bottomRow = temp;
8081 }
8082
8083 if ( leftCol > rightCol )
8084 {
8085 temp = leftCol;
8086 leftCol = rightCol;
8087 rightCol = temp;
8088 }
8089
8090 updateTopLeft = wxGridCellCoords( topRow, leftCol );
8091 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
8092
8093 if ( m_selectingTopLeft != updateTopLeft ||
8094 m_selectingBottomRight != updateBottomRight )
8095 {
8096 // Compute two optimal update rectangles:
8097 // Either one rectangle is a real subset of the
8098 // other, or they are (almost) disjoint!
8099 wxRect rect[4];
8100 bool need_refresh[4];
8101 need_refresh[0] =
8102 need_refresh[1] =
8103 need_refresh[2] =
8104 need_refresh[3] = FALSE;
8105 int i;
8106
8107 // Store intermediate values
8108 wxCoord oldLeft = m_selectingTopLeft.GetCol();
8109 wxCoord oldTop = m_selectingTopLeft.GetRow();
8110 wxCoord oldRight = m_selectingBottomRight.GetCol();
8111 wxCoord oldBottom = m_selectingBottomRight.GetRow();
8112
8113 // Determine the outer/inner coordinates.
8114 if (oldLeft > leftCol)
8115 {
8116 temp = oldLeft;
8117 oldLeft = leftCol;
8118 leftCol = temp;
8119 }
8120 if (oldTop > topRow )
8121 {
8122 temp = oldTop;
8123 oldTop = topRow;
8124 topRow = temp;
8125 }
8126 if (oldRight < rightCol )
8127 {
8128 temp = oldRight;
8129 oldRight = rightCol;
8130 rightCol = temp;
8131 }
8132 if (oldBottom < bottomRow)
8133 {
8134 temp = oldBottom;
8135 oldBottom = bottomRow;
8136 bottomRow = temp;
8137 }
8138
8139 // Now, either the stuff marked old is the outer
8140 // rectangle or we don't have a situation where one
8141 // is contained in the other.
8142
8143 if ( oldLeft < leftCol )
8144 {
8145 need_refresh[0] = TRUE;
8146 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
8147 oldLeft ),
8148 wxGridCellCoords ( oldBottom,
8149 leftCol - 1 ) );
8150 }
8151
8152 if ( oldTop < topRow )
8153 {
8154 need_refresh[1] = TRUE;
8155 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
8156 leftCol ),
8157 wxGridCellCoords ( topRow - 1,
8158 rightCol ) );
8159 }
8160
8161 if ( oldRight > rightCol )
8162 {
8163 need_refresh[2] = TRUE;
8164 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
8165 rightCol + 1 ),
8166 wxGridCellCoords ( oldBottom,
8167 oldRight ) );
8168 }
8169
8170 if ( oldBottom > bottomRow )
8171 {
8172 need_refresh[3] = TRUE;
8173 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
8174 leftCol ),
8175 wxGridCellCoords ( oldBottom,
8176 rightCol ) );
8177 }
8178
8179
8180 // Change Selection
8181 m_selectingTopLeft = updateTopLeft;
8182 m_selectingBottomRight = updateBottomRight;
8183
8184 // various Refresh() calls
8185 for (i = 0; i < 4; i++ )
8186 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
8187 m_gridWin->Refresh( FALSE, &(rect[i]) );
8188 }
8189
8190 // never generate an event as it will be generated from
8191 // wxGridSelection::SelectBlock!
8192 }
8193
8194 void wxGrid::SelectAll()
8195 {
8196 m_selection->SelectBlock( 0, 0, m_numRows-1, m_numCols-1 );
8197 }
8198
8199 bool wxGrid::IsSelection()
8200 {
8201 return ( m_selection->IsSelection() ||
8202 ( m_selectingTopLeft != wxGridNoCellCoords &&
8203 m_selectingBottomRight != wxGridNoCellCoords ) );
8204 }
8205
8206 bool wxGrid::IsInSelection( int row, int col )
8207 {
8208 return ( m_selection->IsInSelection( row, col ) ||
8209 ( row >= m_selectingTopLeft.GetRow() &&
8210 col >= m_selectingTopLeft.GetCol() &&
8211 row <= m_selectingBottomRight.GetRow() &&
8212 col <= m_selectingBottomRight.GetCol() ) );
8213 }
8214
8215 void wxGrid::ClearSelection()
8216 {
8217 m_selectingTopLeft = wxGridNoCellCoords;
8218 m_selectingBottomRight = wxGridNoCellCoords;
8219 m_selection->ClearSelection();
8220 }
8221
8222
8223 // This function returns the rectangle that encloses the given block
8224 // in device coords clipped to the client size of the grid window.
8225 //
8226 wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
8227 const wxGridCellCoords &bottomRight )
8228 {
8229 wxRect rect( wxGridNoCellRect );
8230 wxRect cellRect;
8231
8232 cellRect = CellToRect( topLeft );
8233 if ( cellRect != wxGridNoCellRect )
8234 {
8235 rect = cellRect;
8236 }
8237 else
8238 {
8239 rect = wxRect( 0, 0, 0, 0 );
8240 }
8241
8242 cellRect = CellToRect( bottomRight );
8243 if ( cellRect != wxGridNoCellRect )
8244 {
8245 rect += cellRect;
8246 }
8247 else
8248 {
8249 return wxGridNoCellRect;
8250 }
8251
8252 // convert to scrolled coords
8253 //
8254 int left, top, right, bottom;
8255 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
8256 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
8257
8258 int cw, ch;
8259 m_gridWin->GetClientSize( &cw, &ch );
8260
8261 if (right < 0 || bottom < 0 || left > cw || top > ch)
8262 return wxRect( 0, 0, 0, 0);
8263
8264 rect.SetLeft( wxMax(0, left) );
8265 rect.SetTop( wxMax(0, top) );
8266 rect.SetRight( wxMin(cw, right) );
8267 rect.SetBottom( wxMin(ch, bottom) );
8268
8269 return rect;
8270 }
8271
8272
8273
8274 //
8275 // ------ Grid event classes
8276 //
8277
8278 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
8279
8280 wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
8281 int row, int col, int x, int y, bool sel,
8282 bool control, bool shift, bool alt, bool meta )
8283 : wxNotifyEvent( type, id )
8284 {
8285 m_row = row;
8286 m_col = col;
8287 m_x = x;
8288 m_y = y;
8289 m_selecting = sel;
8290 m_control = control;
8291 m_shift = shift;
8292 m_alt = alt;
8293 m_meta = meta;
8294
8295 SetEventObject(obj);
8296 }
8297
8298
8299 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
8300
8301 wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
8302 int rowOrCol, int x, int y,
8303 bool control, bool shift, bool alt, bool meta )
8304 : wxNotifyEvent( type, id )
8305 {
8306 m_rowOrCol = rowOrCol;
8307 m_x = x;
8308 m_y = y;
8309 m_control = control;
8310 m_shift = shift;
8311 m_alt = alt;
8312 m_meta = meta;
8313
8314 SetEventObject(obj);
8315 }
8316
8317
8318 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
8319
8320 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
8321 const wxGridCellCoords& topLeft,
8322 const wxGridCellCoords& bottomRight,
8323 bool sel, bool control,
8324 bool shift, bool alt, bool meta )
8325 : wxNotifyEvent( type, id )
8326 {
8327 m_topLeft = topLeft;
8328 m_bottomRight = bottomRight;
8329 m_selecting = sel;
8330 m_control = control;
8331 m_shift = shift;
8332 m_alt = alt;
8333 m_meta = meta;
8334
8335 SetEventObject(obj);
8336 }
8337
8338
8339 #endif // ifndef wxUSE_NEW_GRID