]> git.saurik.com Git - wxWidgets.git/blob - src/generic/grid.cpp
Better behaviour on NT (no dialogs when searching drives)
[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 // ifdef'd out following patch from Paul Gammans
3821 #if 0
3822 // removed _all_ rows, in this case, we remove
3823 // all column attributes.
3824 // I hate to do this here, but the
3825 // needed data is not available inside UpdateAttrRows.
3826 if ( !GetNumberRows() )
3827 attrProvider->UpdateAttrCols( 0, -GetNumberCols() );
3828 #endif
3829 }
3830 if ( !GetBatchCount() )
3831 {
3832 CalcDimensions();
3833 m_rowLabelWin->Refresh();
3834 }
3835 }
3836 result = TRUE;
3837 break;
3838
3839 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
3840 {
3841 size_t pos = msg.GetCommandInt();
3842 int numCols = msg.GetCommandInt2();
3843 m_numCols += numCols;
3844
3845 if ( !m_colWidths.IsEmpty() )
3846 {
3847 for ( i = 0; i < numCols; i++ )
3848 {
3849 m_colWidths.Insert( m_defaultColWidth, pos );
3850 m_colRights.Insert( 0, pos );
3851 }
3852
3853 int right = 0;
3854 if ( pos > 0 ) right = m_colRights[pos-1];
3855
3856 for ( i = pos; i < m_numCols; i++ )
3857 {
3858 right += m_colWidths[i];
3859 m_colRights[i] = right;
3860 }
3861 }
3862 if ( m_currentCellCoords == wxGridNoCellCoords )
3863 {
3864 // if we have just inserted cols into an empty grid the current
3865 // cell will be undefined...
3866 //
3867 SetCurrentCell( 0, 0 );
3868 }
3869 m_selection->UpdateCols( pos, numCols );
3870 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
3871 if (attrProvider)
3872 attrProvider->UpdateAttrCols( pos, numCols );
3873 if ( !GetBatchCount() )
3874 {
3875 CalcDimensions();
3876 m_colLabelWin->Refresh();
3877 }
3878
3879 }
3880 result = TRUE;
3881 break;
3882
3883 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
3884 {
3885 int numCols = msg.GetCommandInt();
3886 int oldNumCols = m_numCols;
3887 m_numCols += numCols;
3888 if ( !m_colWidths.IsEmpty() )
3889 {
3890 for ( i = 0; i < numCols; i++ )
3891 {
3892 m_colWidths.Add( m_defaultColWidth );
3893 m_colRights.Add( 0 );
3894 }
3895
3896 int right = 0;
3897 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
3898
3899 for ( i = oldNumCols; i < m_numCols; i++ )
3900 {
3901 right += m_colWidths[i];
3902 m_colRights[i] = right;
3903 }
3904 }
3905 if ( m_currentCellCoords == wxGridNoCellCoords )
3906 {
3907 // if we have just inserted cols into an empty grid the current
3908 // cell will be undefined...
3909 //
3910 SetCurrentCell( 0, 0 );
3911 }
3912 if ( !GetBatchCount() )
3913 {
3914 CalcDimensions();
3915 m_colLabelWin->Refresh();
3916 }
3917 }
3918 result = TRUE;
3919 break;
3920
3921 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
3922 {
3923 size_t pos = msg.GetCommandInt();
3924 int numCols = msg.GetCommandInt2();
3925 m_numCols -= numCols;
3926
3927 if ( !m_colWidths.IsEmpty() )
3928 {
3929 for ( i = 0; i < numCols; i++ )
3930 {
3931 m_colWidths.Remove( pos );
3932 m_colRights.Remove( pos );
3933 }
3934
3935 int w = 0;
3936 for ( i = 0; i < m_numCols; i++ )
3937 {
3938 w += m_colWidths[i];
3939 m_colRights[i] = w;
3940 }
3941 }
3942 if ( !m_numCols )
3943 {
3944 m_currentCellCoords = wxGridNoCellCoords;
3945 }
3946 else
3947 {
3948 if ( m_currentCellCoords.GetCol() >= m_numCols )
3949 m_currentCellCoords.Set( 0, 0 );
3950 }
3951 m_selection->UpdateCols( pos, -((int)numCols) );
3952 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
3953 if (attrProvider) {
3954 attrProvider->UpdateAttrCols( pos, -((int)numCols) );
3955 // ifdef'd out following patch from Paul Gammans
3956 #if 0
3957 // No need to touch row attributes, unless we
3958 // removed _all_ columns, in this case, we remove
3959 // all row attributes.
3960 // I hate to do this here, but the
3961 // needed data is not available inside UpdateAttrCols.
3962 if ( !GetNumberCols() )
3963 attrProvider->UpdateAttrRows( 0, -GetNumberRows() );
3964 #endif
3965 }
3966 if ( !GetBatchCount() )
3967 {
3968 CalcDimensions();
3969 m_colLabelWin->Refresh();
3970 }
3971 return TRUE;
3972 }
3973 #if 0
3974 // There is no path to this code !!!!!!
3975 result = TRUE;
3976 break;
3977 #endif
3978 }
3979
3980 if (result && !GetBatchCount() )
3981 m_gridWin->Refresh();
3982 return result;
3983 }
3984
3985
3986 void wxGrid::CalcRowLabelsExposed( const wxRegion& reg )
3987 {
3988 wxRegionIterator iter( reg );
3989 wxRect r;
3990
3991 m_rowLabelsExposed.Empty();
3992
3993 int top, bottom;
3994 while ( iter )
3995 {
3996 r = iter.GetRect();
3997
3998 // TODO: remove this when we can...
3999 // There is a bug in wxMotif that gives garbage update
4000 // rectangles if you jump-scroll a long way by clicking the
4001 // scrollbar with middle button. This is a work-around
4002 //
4003 #if defined(__WXMOTIF__)
4004 int cw, ch;
4005 m_gridWin->GetClientSize( &cw, &ch );
4006 if ( r.GetTop() > ch ) r.SetTop( 0 );
4007 r.SetBottom( wxMin( r.GetBottom(), ch ) );
4008 #endif
4009
4010 // logical bounds of update region
4011 //
4012 int dummy;
4013 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
4014 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
4015
4016 // find the row labels within these bounds
4017 //
4018 int row;
4019 for ( row = 0; row < m_numRows; row++ )
4020 {
4021 if ( GetRowBottom(row) < top )
4022 continue;
4023
4024 if ( GetRowTop(row) > bottom )
4025 break;
4026
4027 m_rowLabelsExposed.Add( row );
4028 }
4029
4030 iter++ ;
4031 }
4032 }
4033
4034
4035 void wxGrid::CalcColLabelsExposed( const wxRegion& reg )
4036 {
4037 wxRegionIterator iter( reg );
4038 wxRect r;
4039
4040 m_colLabelsExposed.Empty();
4041
4042 int left, right;
4043 while ( iter )
4044 {
4045 r = iter.GetRect();
4046
4047 // TODO: remove this when we can...
4048 // There is a bug in wxMotif that gives garbage update
4049 // rectangles if you jump-scroll a long way by clicking the
4050 // scrollbar with middle button. This is a work-around
4051 //
4052 #if defined(__WXMOTIF__)
4053 int cw, ch;
4054 m_gridWin->GetClientSize( &cw, &ch );
4055 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
4056 r.SetRight( wxMin( r.GetRight(), cw ) );
4057 #endif
4058
4059 // logical bounds of update region
4060 //
4061 int dummy;
4062 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
4063 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
4064
4065 // find the cells within these bounds
4066 //
4067 int col;
4068 for ( col = 0; col < m_numCols; col++ )
4069 {
4070 if ( GetColRight(col) < left )
4071 continue;
4072
4073 if ( GetColLeft(col) > right )
4074 break;
4075
4076 m_colLabelsExposed.Add( col );
4077 }
4078
4079 iter++ ;
4080 }
4081 }
4082
4083
4084 void wxGrid::CalcCellsExposed( const wxRegion& reg )
4085 {
4086 wxRegionIterator iter( reg );
4087 wxRect r;
4088
4089 m_cellsExposed.Empty();
4090 m_rowsExposed.Empty();
4091 m_colsExposed.Empty();
4092
4093 int left, top, right, bottom;
4094 while ( iter )
4095 {
4096 r = iter.GetRect();
4097
4098 // TODO: remove this when we can...
4099 // There is a bug in wxMotif that gives garbage update
4100 // rectangles if you jump-scroll a long way by clicking the
4101 // scrollbar with middle button. This is a work-around
4102 //
4103 #if defined(__WXMOTIF__)
4104 int cw, ch;
4105 m_gridWin->GetClientSize( &cw, &ch );
4106 if ( r.GetTop() > ch ) r.SetTop( 0 );
4107 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
4108 r.SetRight( wxMin( r.GetRight(), cw ) );
4109 r.SetBottom( wxMin( r.GetBottom(), ch ) );
4110 #endif
4111
4112 // logical bounds of update region
4113 //
4114 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
4115 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
4116
4117 // find the cells within these bounds
4118 //
4119 int row, col;
4120 for ( row = 0; row < m_numRows; row++ )
4121 {
4122 if ( GetRowBottom(row) <= top )
4123 continue;
4124
4125 if ( GetRowTop(row) > bottom )
4126 break;
4127
4128 m_rowsExposed.Add( row );
4129
4130 for ( col = 0; col < m_numCols; col++ )
4131 {
4132 if ( GetColRight(col) <= left )
4133 continue;
4134
4135 if ( GetColLeft(col) > right )
4136 break;
4137
4138 if ( m_colsExposed.Index( col ) == wxNOT_FOUND )
4139 m_colsExposed.Add( col );
4140 m_cellsExposed.Add( wxGridCellCoords( row, col ) );
4141 }
4142 }
4143
4144 iter++;
4145 }
4146 }
4147
4148
4149 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
4150 {
4151 int x, y, row;
4152 wxPoint pos( event.GetPosition() );
4153 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
4154
4155 if ( event.Dragging() )
4156 {
4157 m_isDragging = TRUE;
4158
4159 if ( event.LeftIsDown() )
4160 {
4161 switch( m_cursorMode )
4162 {
4163 case WXGRID_CURSOR_RESIZE_ROW:
4164 {
4165 int cw, ch, left, dummy;
4166 m_gridWin->GetClientSize( &cw, &ch );
4167 CalcUnscrolledPosition( 0, 0, &left, &dummy );
4168
4169 wxClientDC dc( m_gridWin );
4170 PrepareDC( dc );
4171 y = wxMax( y,
4172 GetRowTop(m_dragRowOrCol) +
4173 GetRowMinimalHeight(m_dragRowOrCol) );
4174 dc.SetLogicalFunction(wxINVERT);
4175 if ( m_dragLastPos >= 0 )
4176 {
4177 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
4178 }
4179 dc.DrawLine( left, y, left+cw, y );
4180 m_dragLastPos = y;
4181 }
4182 break;
4183
4184 case WXGRID_CURSOR_SELECT_ROW:
4185 if ( (row = YToRow( y )) >= 0 )
4186 {
4187 m_selection->SelectRow( row,
4188 event.ControlDown(),
4189 event.ShiftDown(),
4190 event.AltDown(),
4191 event.MetaDown() );
4192 }
4193
4194 // default label to suppress warnings about "enumeration value
4195 // 'xxx' not handled in switch
4196 default:
4197 break;
4198 }
4199 }
4200 return;
4201 }
4202
4203 m_isDragging = FALSE;
4204
4205
4206 // ------------ Entering or leaving the window
4207 //
4208 if ( event.Entering() || event.Leaving() )
4209 {
4210 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
4211 }
4212
4213
4214 // ------------ Left button pressed
4215 //
4216 else if ( event.LeftDown() )
4217 {
4218 // don't send a label click event for a hit on the
4219 // edge of the row label - this is probably the user
4220 // wanting to resize the row
4221 //
4222 if ( YToEdgeOfRow(y) < 0 )
4223 {
4224 row = YToRow(y);
4225 if ( row >= 0 &&
4226 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
4227 {
4228 if ( !event.ShiftDown() && !event.ControlDown() )
4229 ClearSelection();
4230 if ( event.ShiftDown() )
4231 m_selection->SelectBlock( m_currentCellCoords.GetRow(),
4232 0,
4233 row,
4234 GetNumberCols() - 1,
4235 event.ControlDown(),
4236 event.ShiftDown(),
4237 event.AltDown(),
4238 event.MetaDown() );
4239 else
4240 m_selection->SelectRow( row,
4241 event.ControlDown(),
4242 event.ShiftDown(),
4243 event.AltDown(),
4244 event.MetaDown() );
4245 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
4246 }
4247 }
4248 else
4249 {
4250 // starting to drag-resize a row
4251 //
4252 if ( CanDragRowSize() )
4253 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
4254 }
4255 }
4256
4257
4258 // ------------ Left double click
4259 //
4260 else if (event.LeftDClick() )
4261 {
4262 if ( YToEdgeOfRow(y) < 0 )
4263 {
4264 row = YToRow(y);
4265 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
4266 }
4267 }
4268
4269
4270 // ------------ Left button released
4271 //
4272 else if ( event.LeftUp() )
4273 {
4274 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
4275 {
4276 DoEndDragResizeRow();
4277
4278 // Note: we are ending the event *after* doing
4279 // default processing in this case
4280 //
4281 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
4282 }
4283
4284 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
4285 m_dragLastPos = -1;
4286 }
4287
4288
4289 // ------------ Right button down
4290 //
4291 else if ( event.RightDown() )
4292 {
4293 row = YToRow(y);
4294 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
4295 {
4296 // no default action at the moment
4297 }
4298 }
4299
4300
4301 // ------------ Right double click
4302 //
4303 else if ( event.RightDClick() )
4304 {
4305 row = YToRow(y);
4306 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
4307 {
4308 // no default action at the moment
4309 }
4310 }
4311
4312
4313 // ------------ No buttons down and mouse moving
4314 //
4315 else if ( event.Moving() )
4316 {
4317 m_dragRowOrCol = YToEdgeOfRow( y );
4318 if ( m_dragRowOrCol >= 0 )
4319 {
4320 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4321 {
4322 // don't capture the mouse yet
4323 if ( CanDragRowSize() )
4324 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE);
4325 }
4326 }
4327 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
4328 {
4329 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, FALSE);
4330 }
4331 }
4332 }
4333
4334
4335 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
4336 {
4337 int x, y, col;
4338 wxPoint pos( event.GetPosition() );
4339 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
4340
4341 if ( event.Dragging() )
4342 {
4343 m_isDragging = TRUE;
4344
4345 if ( event.LeftIsDown() )
4346 {
4347 switch( m_cursorMode )
4348 {
4349 case WXGRID_CURSOR_RESIZE_COL:
4350 {
4351 int cw, ch, dummy, top;
4352 m_gridWin->GetClientSize( &cw, &ch );
4353 CalcUnscrolledPosition( 0, 0, &dummy, &top );
4354
4355 wxClientDC dc( m_gridWin );
4356 PrepareDC( dc );
4357
4358 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
4359 GetColMinimalWidth(m_dragRowOrCol));
4360 dc.SetLogicalFunction(wxINVERT);
4361 if ( m_dragLastPos >= 0 )
4362 {
4363 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
4364 }
4365 dc.DrawLine( x, top, x, top+ch );
4366 m_dragLastPos = x;
4367 }
4368 break;
4369
4370 case WXGRID_CURSOR_SELECT_COL:
4371 if ( (col = XToCol( x )) >= 0 )
4372 {
4373 m_selection->SelectCol( col,
4374 event.ControlDown(),
4375 event.ShiftDown(),
4376 event.AltDown(),
4377 event.MetaDown() );
4378 }
4379
4380 // default label to suppress warnings about "enumeration value
4381 // 'xxx' not handled in switch
4382 default:
4383 break;
4384 }
4385 }
4386 return;
4387 }
4388
4389 m_isDragging = FALSE;
4390
4391
4392 // ------------ Entering or leaving the window
4393 //
4394 if ( event.Entering() || event.Leaving() )
4395 {
4396 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
4397 }
4398
4399
4400 // ------------ Left button pressed
4401 //
4402 else if ( event.LeftDown() )
4403 {
4404 // don't send a label click event for a hit on the
4405 // edge of the col label - this is probably the user
4406 // wanting to resize the col
4407 //
4408 if ( XToEdgeOfCol(x) < 0 )
4409 {
4410 col = XToCol(x);
4411 if ( col >= 0 &&
4412 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
4413 {
4414 if ( !event.ShiftDown() && !event.ControlDown() )
4415 ClearSelection();
4416 if ( event.ShiftDown() )
4417 m_selection->SelectBlock( 0,
4418 m_currentCellCoords.GetCol(),
4419 GetNumberRows() - 1, col,
4420 event.ControlDown(),
4421 event.ShiftDown(),
4422 event.AltDown(),
4423 event.MetaDown() );
4424 else
4425 m_selection->SelectCol( col,
4426 event.ControlDown(),
4427 event.ShiftDown(),
4428 event.AltDown(),
4429 event.MetaDown() );
4430 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin);
4431 }
4432 }
4433 else
4434 {
4435 // starting to drag-resize a col
4436 //
4437 if ( CanDragColSize() )
4438 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
4439 }
4440 }
4441
4442
4443 // ------------ Left double click
4444 //
4445 if ( event.LeftDClick() )
4446 {
4447 if ( XToEdgeOfCol(x) < 0 )
4448 {
4449 col = XToCol(x);
4450 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
4451 }
4452 }
4453
4454
4455 // ------------ Left button released
4456 //
4457 else if ( event.LeftUp() )
4458 {
4459 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4460 {
4461 DoEndDragResizeCol();
4462
4463 // Note: we are ending the event *after* doing
4464 // default processing in this case
4465 //
4466 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
4467 }
4468
4469 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
4470 m_dragLastPos = -1;
4471 }
4472
4473
4474 // ------------ Right button down
4475 //
4476 else if ( event.RightDown() )
4477 {
4478 col = XToCol(x);
4479 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
4480 {
4481 // no default action at the moment
4482 }
4483 }
4484
4485
4486 // ------------ Right double click
4487 //
4488 else if ( event.RightDClick() )
4489 {
4490 col = XToCol(x);
4491 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
4492 {
4493 // no default action at the moment
4494 }
4495 }
4496
4497
4498 // ------------ No buttons down and mouse moving
4499 //
4500 else if ( event.Moving() )
4501 {
4502 m_dragRowOrCol = XToEdgeOfCol( x );
4503 if ( m_dragRowOrCol >= 0 )
4504 {
4505 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4506 {
4507 // don't capture the cursor yet
4508 if ( CanDragColSize() )
4509 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE);
4510 }
4511 }
4512 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
4513 {
4514 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, FALSE);
4515 }
4516 }
4517 }
4518
4519
4520 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
4521 {
4522 if ( event.LeftDown() )
4523 {
4524 // indicate corner label by having both row and
4525 // col args == -1
4526 //
4527 if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
4528 {
4529 SelectAll();
4530 }
4531 }
4532
4533 else if ( event.LeftDClick() )
4534 {
4535 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
4536 }
4537
4538 else if ( event.RightDown() )
4539 {
4540 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
4541 {
4542 // no default action at the moment
4543 }
4544 }
4545
4546 else if ( event.RightDClick() )
4547 {
4548 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
4549 {
4550 // no default action at the moment
4551 }
4552 }
4553 }
4554
4555 void wxGrid::ChangeCursorMode(CursorMode mode,
4556 wxWindow *win,
4557 bool captureMouse)
4558 {
4559 #ifdef __WXDEBUG__
4560 static const wxChar *cursorModes[] =
4561 {
4562 _T("SELECT_CELL"),
4563 _T("RESIZE_ROW"),
4564 _T("RESIZE_COL"),
4565 _T("SELECT_ROW"),
4566 _T("SELECT_COL")
4567 };
4568
4569 wxLogTrace(_T("grid"),
4570 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
4571 win == m_colLabelWin ? _T("colLabelWin")
4572 : win ? _T("rowLabelWin")
4573 : _T("gridWin"),
4574 cursorModes[m_cursorMode], cursorModes[mode]);
4575 #endif // __WXDEBUG__
4576
4577 if ( mode == m_cursorMode )
4578 return;
4579
4580 if ( !win )
4581 {
4582 // by default use the grid itself
4583 win = m_gridWin;
4584 }
4585
4586 if ( m_winCapture )
4587 {
4588 m_winCapture->ReleaseMouse();
4589 m_winCapture = (wxWindow *)NULL;
4590 }
4591
4592 m_cursorMode = mode;
4593
4594 switch ( m_cursorMode )
4595 {
4596 case WXGRID_CURSOR_RESIZE_ROW:
4597 win->SetCursor( m_rowResizeCursor );
4598 break;
4599
4600 case WXGRID_CURSOR_RESIZE_COL:
4601 win->SetCursor( m_colResizeCursor );
4602 break;
4603
4604 default:
4605 win->SetCursor( *wxSTANDARD_CURSOR );
4606 }
4607
4608 // we need to capture mouse when resizing
4609 bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
4610 m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
4611
4612 if ( captureMouse && resize )
4613 {
4614 win->CaptureMouse();
4615 m_winCapture = win;
4616 }
4617 }
4618
4619 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
4620 {
4621 int x, y;
4622 wxPoint pos( event.GetPosition() );
4623 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
4624
4625 wxGridCellCoords coords;
4626 XYToCell( x, y, coords );
4627
4628 if ( event.Dragging() )
4629 {
4630 //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol());
4631
4632 // Don't start doing anything until the mouse has been drug at
4633 // least 3 pixels in any direction...
4634 if (! m_isDragging)
4635 {
4636 if (m_startDragPos == wxDefaultPosition)
4637 {
4638 m_startDragPos = pos;
4639 return;
4640 }
4641 if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4)
4642 return;
4643 }
4644
4645 m_isDragging = TRUE;
4646 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4647 {
4648 // Hide the edit control, so it
4649 // won't interfer with drag-shrinking.
4650 if ( IsCellEditControlShown() )
4651 {
4652 HideCellEditControl();
4653 SaveEditControlValue();
4654 }
4655
4656 // Have we captured the mouse yet?
4657 if (! m_winCapture)
4658 {
4659 m_winCapture = m_gridWin;
4660 m_winCapture->CaptureMouse();
4661 }
4662
4663 if ( coords != wxGridNoCellCoords )
4664 {
4665 if ( event.ControlDown() )
4666 {
4667 if ( m_selectingKeyboard == wxGridNoCellCoords)
4668 m_selectingKeyboard = coords;
4669 SelectBlock ( m_selectingKeyboard, coords );
4670 }
4671 else
4672 {
4673 if ( !IsSelection() )
4674 {
4675 SelectBlock( coords, coords );
4676 }
4677 else
4678 {
4679 SelectBlock( m_currentCellCoords, coords );
4680 }
4681 }
4682
4683 if (! IsVisible(coords))
4684 {
4685 MakeCellVisible(coords);
4686 // TODO: need to introduce a delay or something here. The
4687 // scrolling is way to fast, at least on MSW - also on GTK.
4688 }
4689 }
4690 }
4691 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
4692 {
4693 int cw, ch, left, dummy;
4694 m_gridWin->GetClientSize( &cw, &ch );
4695 CalcUnscrolledPosition( 0, 0, &left, &dummy );
4696
4697 wxClientDC dc( m_gridWin );
4698 PrepareDC( dc );
4699 y = wxMax( y, GetRowTop(m_dragRowOrCol) +
4700 GetRowMinimalHeight(m_dragRowOrCol) );
4701 dc.SetLogicalFunction(wxINVERT);
4702 if ( m_dragLastPos >= 0 )
4703 {
4704 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
4705 }
4706 dc.DrawLine( left, y, left+cw, y );
4707 m_dragLastPos = y;
4708 }
4709 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4710 {
4711 int cw, ch, dummy, top;
4712 m_gridWin->GetClientSize( &cw, &ch );
4713 CalcUnscrolledPosition( 0, 0, &dummy, &top );
4714
4715 wxClientDC dc( m_gridWin );
4716 PrepareDC( dc );
4717 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
4718 GetColMinimalWidth(m_dragRowOrCol) );
4719 dc.SetLogicalFunction(wxINVERT);
4720 if ( m_dragLastPos >= 0 )
4721 {
4722 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
4723 }
4724 dc.DrawLine( x, top, x, top+ch );
4725 m_dragLastPos = x;
4726 }
4727
4728 return;
4729 }
4730
4731 m_isDragging = FALSE;
4732 m_startDragPos = wxDefaultPosition;
4733
4734 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
4735 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
4736 // wxGTK
4737 #if 0
4738 if ( event.Entering() || event.Leaving() )
4739 {
4740 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4741 m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
4742 }
4743 else
4744 #endif // 0
4745
4746 // ------------ Left button pressed
4747 //
4748 if ( event.LeftDown() && coords != wxGridNoCellCoords )
4749 {
4750 if ( !SendEvent( wxEVT_GRID_CELL_LEFT_CLICK,
4751 coords.GetRow(),
4752 coords.GetCol(),
4753 event ) )
4754 {
4755 if ( !event.ControlDown() )
4756 ClearSelection();
4757 if ( event.ShiftDown() )
4758 {
4759 m_selection->SelectBlock( m_currentCellCoords.GetRow(),
4760 m_currentCellCoords.GetCol(),
4761 coords.GetRow(),
4762 coords.GetCol(),
4763 event.ControlDown(),
4764 event.ShiftDown(),
4765 event.AltDown(),
4766 event.MetaDown() );
4767 }
4768 else if ( XToEdgeOfCol(x) < 0 &&
4769 YToEdgeOfRow(y) < 0 )
4770 {
4771 DisableCellEditControl();
4772 MakeCellVisible( coords );
4773
4774 // if this is the second click on this cell then start
4775 // the edit control
4776 if ( m_waitForSlowClick &&
4777 (coords == m_currentCellCoords) &&
4778 CanEnableCellControl())
4779 {
4780 EnableCellEditControl();
4781
4782 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
4783 wxGridCellEditor *editor = attr->GetEditor(this,
4784 coords.GetRow(),
4785 coords.GetCol());
4786 editor->StartingClick();
4787 editor->DecRef();
4788 attr->DecRef();
4789
4790 m_waitForSlowClick = FALSE;
4791 }
4792 else
4793 {
4794 if ( event.ControlDown() )
4795 {
4796 m_selection->ToggleCellSelection( coords.GetRow(),
4797 coords.GetCol(),
4798 event.ControlDown(),
4799 event.ShiftDown(),
4800 event.AltDown(),
4801 event.MetaDown() );
4802 m_selectingTopLeft = wxGridNoCellCoords;
4803 m_selectingBottomRight = wxGridNoCellCoords;
4804 m_selectingKeyboard = coords;
4805 }
4806 else
4807 {
4808 SetCurrentCell( coords );
4809 if ( m_selection->GetSelectionMode()
4810 != wxGrid::wxGridSelectCells)
4811 SelectBlock( coords, coords );
4812 }
4813 m_waitForSlowClick = TRUE;
4814 }
4815 }
4816 }
4817 }
4818
4819
4820 // ------------ Left double click
4821 //
4822 else if ( event.LeftDClick() && coords != wxGridNoCellCoords )
4823 {
4824 DisableCellEditControl();
4825
4826 if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 )
4827 {
4828 SendEvent( wxEVT_GRID_CELL_LEFT_DCLICK,
4829 coords.GetRow(),
4830 coords.GetCol(),
4831 event );
4832 }
4833 }
4834
4835
4836 // ------------ Left button released
4837 //
4838 else if ( event.LeftUp() )
4839 {
4840 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4841 {
4842 if ( m_selectingTopLeft != wxGridNoCellCoords &&
4843 m_selectingBottomRight != wxGridNoCellCoords )
4844 {
4845 if (m_winCapture)
4846 {
4847 m_winCapture->ReleaseMouse();
4848 m_winCapture = NULL;
4849 }
4850 m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
4851 m_selectingTopLeft.GetCol(),
4852 m_selectingBottomRight.GetRow(),
4853 m_selectingBottomRight.GetCol(),
4854 event.ControlDown(),
4855 event.ShiftDown(),
4856 event.AltDown(),
4857 event.MetaDown() );
4858 m_selectingTopLeft = wxGridNoCellCoords;
4859 m_selectingBottomRight = wxGridNoCellCoords;
4860 }
4861
4862 // Show the edit control, if it has been hidden for
4863 // drag-shrinking.
4864 ShowCellEditControl();
4865 }
4866 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
4867 {
4868 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4869 DoEndDragResizeRow();
4870
4871 // Note: we are ending the event *after* doing
4872 // default processing in this case
4873 //
4874 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
4875 }
4876 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4877 {
4878 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4879 DoEndDragResizeCol();
4880
4881 // Note: we are ending the event *after* doing
4882 // default processing in this case
4883 //
4884 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
4885 }
4886
4887 m_dragLastPos = -1;
4888 }
4889
4890
4891 // ------------ Right button down
4892 //
4893 else if ( event.RightDown() && coords != wxGridNoCellCoords )
4894 {
4895 DisableCellEditControl();
4896 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_CLICK,
4897 coords.GetRow(),
4898 coords.GetCol(),
4899 event ) )
4900 {
4901 // no default action at the moment
4902 }
4903 }
4904
4905
4906 // ------------ Right double click
4907 //
4908 else if ( event.RightDClick() && coords != wxGridNoCellCoords )
4909 {
4910 DisableCellEditControl();
4911 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_DCLICK,
4912 coords.GetRow(),
4913 coords.GetCol(),
4914 event ) )
4915 {
4916 // no default action at the moment
4917 }
4918 }
4919
4920 // ------------ Moving and no button action
4921 //
4922 else if ( event.Moving() && !event.IsButton() )
4923 {
4924 int dragRow = YToEdgeOfRow( y );
4925 int dragCol = XToEdgeOfCol( x );
4926
4927 // Dragging on the corner of a cell to resize in both
4928 // directions is not implemented yet...
4929 //
4930 if ( dragRow >= 0 && dragCol >= 0 )
4931 {
4932 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4933 return;
4934 }
4935
4936 if ( dragRow >= 0 )
4937 {
4938 m_dragRowOrCol = dragRow;
4939
4940 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4941 {
4942 if ( CanDragRowSize() && CanDragGridSize() )
4943 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
4944 }
4945
4946 if ( dragCol >= 0 )
4947 {
4948 m_dragRowOrCol = dragCol;
4949 }
4950
4951 return;
4952 }
4953
4954 if ( dragCol >= 0 )
4955 {
4956 m_dragRowOrCol = dragCol;
4957
4958 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4959 {
4960 if ( CanDragColSize() && CanDragGridSize() )
4961 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
4962 }
4963
4964 return;
4965 }
4966
4967 // Neither on a row or col edge
4968 //
4969 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
4970 {
4971 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4972 }
4973 }
4974 }
4975
4976
4977 void wxGrid::DoEndDragResizeRow()
4978 {
4979 if ( m_dragLastPos >= 0 )
4980 {
4981 // erase the last line and resize the row
4982 //
4983 int cw, ch, left, dummy;
4984 m_gridWin->GetClientSize( &cw, &ch );
4985 CalcUnscrolledPosition( 0, 0, &left, &dummy );
4986
4987 wxClientDC dc( m_gridWin );
4988 PrepareDC( dc );
4989 dc.SetLogicalFunction( wxINVERT );
4990 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
4991 HideCellEditControl();
4992 SaveEditControlValue();
4993
4994 int rowTop = GetRowTop(m_dragRowOrCol);
4995 SetRowSize( m_dragRowOrCol,
4996 wxMax( m_dragLastPos - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
4997
4998 if ( !GetBatchCount() )
4999 {
5000 // Only needed to get the correct rect.y:
5001 wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
5002 rect.x = 0;
5003 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
5004 rect.width = m_rowLabelWidth;
5005 rect.height = ch - rect.y;
5006 m_rowLabelWin->Refresh( TRUE, &rect );
5007 rect.width = cw;
5008 m_gridWin->Refresh( FALSE, &rect );
5009 }
5010
5011 ShowCellEditControl();
5012 }
5013 }
5014
5015
5016 void wxGrid::DoEndDragResizeCol()
5017 {
5018 if ( m_dragLastPos >= 0 )
5019 {
5020 // erase the last line and resize the col
5021 //
5022 int cw, ch, dummy, top;
5023 m_gridWin->GetClientSize( &cw, &ch );
5024 CalcUnscrolledPosition( 0, 0, &dummy, &top );
5025
5026 wxClientDC dc( m_gridWin );
5027 PrepareDC( dc );
5028 dc.SetLogicalFunction( wxINVERT );
5029 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
5030 HideCellEditControl();
5031 SaveEditControlValue();
5032
5033 int colLeft = GetColLeft(m_dragRowOrCol);
5034 SetColSize( m_dragRowOrCol,
5035 wxMax( m_dragLastPos - colLeft,
5036 GetColMinimalWidth(m_dragRowOrCol) ) );
5037
5038 if ( !GetBatchCount() )
5039 {
5040 // Only needed to get the correct rect.x:
5041 wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
5042 rect.y = 0;
5043 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
5044 rect.width = cw - rect.x;
5045 rect.height = m_colLabelHeight;
5046 m_colLabelWin->Refresh( TRUE, &rect );
5047 rect.height = ch;
5048 m_gridWin->Refresh( FALSE, &rect );
5049 }
5050
5051 ShowCellEditControl();
5052 }
5053 }
5054
5055
5056
5057 //
5058 // ------ interaction with data model
5059 //
5060 bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
5061 {
5062 switch ( msg.GetId() )
5063 {
5064 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
5065 return GetModelValues();
5066
5067 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
5068 return SetModelValues();
5069
5070 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
5071 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
5072 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
5073 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
5074 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
5075 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
5076 return Redimension( msg );
5077
5078 default:
5079 return FALSE;
5080 }
5081 }
5082
5083
5084
5085 // The behaviour of this function depends on the grid table class
5086 // Clear() function. For the default wxGridStringTable class the
5087 // behavious is to replace all cell contents with wxEmptyString but
5088 // not to change the number of rows or cols.
5089 //
5090 void wxGrid::ClearGrid()
5091 {
5092 if ( m_table )
5093 {
5094 if (IsCellEditControlEnabled())
5095 DisableCellEditControl();
5096
5097 m_table->Clear();
5098 if ( !GetBatchCount() ) m_gridWin->Refresh();
5099 }
5100 }
5101
5102
5103 bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
5104 {
5105 // TODO: something with updateLabels flag
5106
5107 if ( !m_created )
5108 {
5109 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
5110 return FALSE;
5111 }
5112
5113 if ( m_table )
5114 {
5115 if (IsCellEditControlEnabled())
5116 DisableCellEditControl();
5117
5118 return m_table->InsertRows( pos, numRows );
5119
5120 // the table will have sent the results of the insert row
5121 // operation to this view object as a grid table message
5122 }
5123 return FALSE;
5124 }
5125
5126
5127 bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
5128 {
5129 // TODO: something with updateLabels flag
5130
5131 if ( !m_created )
5132 {
5133 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
5134 return FALSE;
5135 }
5136
5137 return ( m_table && m_table->AppendRows( numRows ) );
5138 // the table will have sent the results of the append row
5139 // operation to this view object as a grid table message
5140 }
5141
5142
5143 bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
5144 {
5145 // TODO: something with updateLabels flag
5146
5147 if ( !m_created )
5148 {
5149 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
5150 return FALSE;
5151 }
5152
5153 if ( m_table )
5154 {
5155 if (IsCellEditControlEnabled())
5156 DisableCellEditControl();
5157
5158 return (m_table->DeleteRows( pos, numRows ));
5159 // the table will have sent the results of the delete row
5160 // operation to this view object as a grid table message
5161 }
5162 return FALSE;
5163 }
5164
5165
5166 bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
5167 {
5168 // TODO: something with updateLabels flag
5169
5170 if ( !m_created )
5171 {
5172 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
5173 return FALSE;
5174 }
5175
5176 if ( m_table )
5177 {
5178 if (IsCellEditControlEnabled())
5179 DisableCellEditControl();
5180
5181 return m_table->InsertCols( pos, numCols );
5182 // the table will have sent the results of the insert col
5183 // operation to this view object as a grid table message
5184 }
5185 return FALSE;
5186 }
5187
5188
5189 bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
5190 {
5191 // TODO: something with updateLabels flag
5192
5193 if ( !m_created )
5194 {
5195 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
5196 return FALSE;
5197 }
5198
5199 return ( m_table && m_table->AppendCols( numCols ) );
5200 // the table will have sent the results of the append col
5201 // operation to this view object as a grid table message
5202 }
5203
5204
5205 bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
5206 {
5207 // TODO: something with updateLabels flag
5208
5209 if ( !m_created )
5210 {
5211 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
5212 return FALSE;
5213 }
5214
5215 if ( m_table )
5216 {
5217 if (IsCellEditControlEnabled())
5218 DisableCellEditControl();
5219
5220 return ( m_table->DeleteCols( pos, numCols ) );
5221 // the table will have sent the results of the delete col
5222 // operation to this view object as a grid table message
5223 }
5224 return FALSE;
5225 }
5226
5227
5228
5229 //
5230 // ----- event handlers
5231 //
5232
5233 // Generate a grid event based on a mouse event and
5234 // return the result of ProcessEvent()
5235 //
5236 bool wxGrid::SendEvent( const wxEventType type,
5237 int row, int col,
5238 wxMouseEvent& mouseEv )
5239 {
5240 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
5241 {
5242 int rowOrCol = (row == -1 ? col : row);
5243
5244 wxGridSizeEvent gridEvt( GetId(),
5245 type,
5246 this,
5247 rowOrCol,
5248 mouseEv.GetX() + GetColLabelSize(),
5249 mouseEv.GetY() + GetRowLabelSize(),
5250 mouseEv.ControlDown(),
5251 mouseEv.ShiftDown(),
5252 mouseEv.AltDown(),
5253 mouseEv.MetaDown() );
5254
5255 return GetEventHandler()->ProcessEvent(gridEvt);
5256 }
5257 else if ( type == wxEVT_GRID_RANGE_SELECT )
5258 {
5259 // Right now, it should _never_ end up here!
5260 wxGridRangeSelectEvent gridEvt( GetId(),
5261 type,
5262 this,
5263 m_selectingTopLeft,
5264 m_selectingBottomRight,
5265 TRUE,
5266 mouseEv.ControlDown(),
5267 mouseEv.ShiftDown(),
5268 mouseEv.AltDown(),
5269 mouseEv.MetaDown() );
5270
5271 return GetEventHandler()->ProcessEvent(gridEvt);
5272 }
5273 else
5274 {
5275 wxGridEvent gridEvt( GetId(),
5276 type,
5277 this,
5278 row, col,
5279 mouseEv.GetX() + GetColLabelSize(),
5280 mouseEv.GetY() + GetRowLabelSize(),
5281 FALSE,
5282 mouseEv.ControlDown(),
5283 mouseEv.ShiftDown(),
5284 mouseEv.AltDown(),
5285 mouseEv.MetaDown() );
5286
5287 return GetEventHandler()->ProcessEvent(gridEvt);
5288 }
5289 }
5290
5291
5292 // Generate a grid event of specified type and return the result
5293 // of ProcessEvent().
5294 //
5295 bool wxGrid::SendEvent( const wxEventType type,
5296 int row, int col )
5297 {
5298 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
5299 {
5300 int rowOrCol = (row == -1 ? col : row);
5301
5302 wxGridSizeEvent gridEvt( GetId(),
5303 type,
5304 this,
5305 rowOrCol );
5306
5307 return GetEventHandler()->ProcessEvent(gridEvt);
5308 }
5309 else
5310 {
5311 wxGridEvent gridEvt( GetId(),
5312 type,
5313 this,
5314 row, col );
5315
5316 return GetEventHandler()->ProcessEvent(gridEvt);
5317 }
5318 }
5319
5320
5321 void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
5322 {
5323 wxPaintDC dc(this); // needed to prevent zillions of paint events on MSW
5324 }
5325
5326
5327 // This is just here to make sure that CalcDimensions gets called when
5328 // the grid view is resized... then the size event is skipped to allow
5329 // the box sizers to handle everything
5330 //
5331 void wxGrid::OnSize( wxSizeEvent& WXUNUSED(event) )
5332 {
5333 CalcWindowSizes();
5334 CalcDimensions();
5335 }
5336
5337
5338 void wxGrid::OnKeyDown( wxKeyEvent& event )
5339 {
5340 if ( m_inOnKeyDown )
5341 {
5342 // shouldn't be here - we are going round in circles...
5343 //
5344 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") );
5345 }
5346
5347 m_inOnKeyDown = TRUE;
5348
5349 // propagate the event up and see if it gets processed
5350 //
5351 wxWindow *parent = GetParent();
5352 wxKeyEvent keyEvt( event );
5353 keyEvt.SetEventObject( parent );
5354
5355 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
5356 {
5357
5358 // try local handlers
5359 //
5360 switch ( event.KeyCode() )
5361 {
5362 case WXK_UP:
5363 if ( event.ControlDown() )
5364 {
5365 MoveCursorUpBlock( event.ShiftDown() );
5366 }
5367 else
5368 {
5369 MoveCursorUp( event.ShiftDown() );
5370 }
5371 break;
5372
5373 case WXK_DOWN:
5374 if ( event.ControlDown() )
5375 {
5376 MoveCursorDownBlock( event.ShiftDown() );
5377 }
5378 else
5379 {
5380 MoveCursorDown( event.ShiftDown() );
5381 }
5382 break;
5383
5384 case WXK_LEFT:
5385 if ( event.ControlDown() )
5386 {
5387 MoveCursorLeftBlock( event.ShiftDown() );
5388 }
5389 else
5390 {
5391 MoveCursorLeft( event.ShiftDown() );
5392 }
5393 break;
5394
5395 case WXK_RIGHT:
5396 if ( event.ControlDown() )
5397 {
5398 MoveCursorRightBlock( event.ShiftDown() );
5399 }
5400 else
5401 {
5402 MoveCursorRight( event.ShiftDown() );
5403 }
5404 break;
5405
5406 case WXK_RETURN:
5407 if ( event.ControlDown() )
5408 {
5409 event.Skip(); // to let the edit control have the return
5410 }
5411 else
5412 {
5413 if ( GetGridCursorRow() < GetNumberRows()-1 )
5414 {
5415 MoveCursorDown( event.ShiftDown() );
5416 }
5417 else
5418 {
5419 // at the bottom of a column
5420 HideCellEditControl();
5421 SaveEditControlValue();
5422 }
5423 }
5424 break;
5425
5426 case WXK_ESCAPE:
5427 ClearSelection();
5428 break;
5429
5430 case WXK_TAB:
5431 if (event.ShiftDown())
5432 {
5433 if ( GetGridCursorCol() > 0 )
5434 {
5435 MoveCursorLeft( FALSE );
5436 }
5437 else
5438 {
5439 // at left of grid
5440 HideCellEditControl();
5441 SaveEditControlValue();
5442 }
5443 }
5444 else
5445 {
5446 if ( GetGridCursorCol() < GetNumberCols()-1 )
5447 {
5448 MoveCursorRight( FALSE );
5449 }
5450 else
5451 {
5452 // at right of grid
5453 HideCellEditControl();
5454 SaveEditControlValue();
5455 }
5456 }
5457 break;
5458
5459 case WXK_HOME:
5460 if ( event.ControlDown() )
5461 {
5462 MakeCellVisible( 0, 0 );
5463 SetCurrentCell( 0, 0 );
5464 }
5465 else
5466 {
5467 event.Skip();
5468 }
5469 break;
5470
5471 case WXK_END:
5472 if ( event.ControlDown() )
5473 {
5474 MakeCellVisible( m_numRows-1, m_numCols-1 );
5475 SetCurrentCell( m_numRows-1, m_numCols-1 );
5476 }
5477 else
5478 {
5479 event.Skip();
5480 }
5481 break;
5482
5483 case WXK_PRIOR:
5484 MovePageUp();
5485 break;
5486
5487 case WXK_NEXT:
5488 MovePageDown();
5489 break;
5490
5491 case WXK_SPACE:
5492 if ( event.ControlDown() )
5493 {
5494 m_selection->ToggleCellSelection( m_currentCellCoords.GetRow(),
5495 m_currentCellCoords.GetCol(),
5496 event.ControlDown(),
5497 event.ShiftDown(),
5498 event.AltDown(),
5499 event.MetaDown() );
5500 break;
5501 }
5502 if ( !IsEditable() )
5503 {
5504 MoveCursorRight( FALSE );
5505 break;
5506 }
5507 // Otherwise fall through to default
5508
5509 default:
5510 // is it possible to edit the current cell at all?
5511 if ( !IsCellEditControlEnabled() && CanEnableCellControl() )
5512 {
5513 // yes, now check whether the cells editor accepts the key
5514 int row = m_currentCellCoords.GetRow();
5515 int col = m_currentCellCoords.GetCol();
5516 wxGridCellAttr* attr = GetCellAttr(row, col);
5517 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
5518
5519 // <F2> is special and will always start editing, for
5520 // other keys - ask the editor itself
5521 if ( (event.KeyCode() == WXK_F2 && !event.HasModifiers())
5522 || editor->IsAcceptedKey(event) )
5523 {
5524 EnableCellEditControl();
5525 editor->StartingKey(event);
5526 }
5527 else
5528 {
5529 event.Skip();
5530 }
5531
5532 editor->DecRef();
5533 attr->DecRef();
5534 }
5535 else
5536 {
5537 // let others process char events with modifiers or all
5538 // char events for readonly cells
5539 event.Skip();
5540 }
5541 break;
5542 }
5543 }
5544
5545 m_inOnKeyDown = FALSE;
5546 }
5547
5548 void wxGrid::OnKeyUp( wxKeyEvent& event )
5549 {
5550 // try local handlers
5551 //
5552 if ( event.KeyCode() == WXK_SHIFT )
5553 {
5554 if ( m_selectingTopLeft != wxGridNoCellCoords &&
5555 m_selectingBottomRight != wxGridNoCellCoords )
5556 m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
5557 m_selectingTopLeft.GetCol(),
5558 m_selectingBottomRight.GetRow(),
5559 m_selectingBottomRight.GetCol(),
5560 event.ControlDown(),
5561 TRUE,
5562 event.AltDown(),
5563 event.MetaDown() );
5564 m_selectingTopLeft = wxGridNoCellCoords;
5565 m_selectingBottomRight = wxGridNoCellCoords;
5566 m_selectingKeyboard = wxGridNoCellCoords;
5567 }
5568 }
5569
5570 void wxGrid::OnEraseBackground(wxEraseEvent&)
5571 {
5572 }
5573
5574 void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
5575 {
5576 if ( SendEvent( wxEVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
5577 {
5578 // the event has been intercepted - do nothing
5579 return;
5580 }
5581
5582 wxClientDC dc(m_gridWin);
5583 PrepareDC(dc);
5584
5585 if ( m_currentCellCoords != wxGridNoCellCoords )
5586 {
5587 HideCellEditControl();
5588 DisableCellEditControl();
5589
5590 if ( IsVisible( m_currentCellCoords ) )
5591 {
5592 wxRect r;
5593 r = BlockToDeviceRect(m_currentCellCoords, m_currentCellCoords);
5594 if ( !m_gridLinesEnabled )
5595 {
5596 r.x--;
5597 r.y--;
5598 r.width++;
5599 r.height++;
5600 }
5601
5602 CalcCellsExposed( r );
5603
5604 // Otherwise refresh redraws the highlight!
5605 m_currentCellCoords = coords;
5606
5607 DrawGridCellArea(dc);
5608 DrawAllGridLines( dc, r );
5609 }
5610 }
5611
5612 m_currentCellCoords = coords;
5613
5614 wxGridCellAttr* attr = GetCellAttr(coords);
5615 DrawCellHighlight(dc, attr);
5616 attr->DecRef();
5617 }
5618
5619
5620 //
5621 // ------ functions to get/send data (see also public functions)
5622 //
5623
5624 bool wxGrid::GetModelValues()
5625 {
5626 if ( m_table )
5627 {
5628 // all we need to do is repaint the grid
5629 //
5630 m_gridWin->Refresh();
5631 return TRUE;
5632 }
5633
5634 return FALSE;
5635 }
5636
5637
5638 bool wxGrid::SetModelValues()
5639 {
5640 int row, col;
5641
5642 if ( m_table )
5643 {
5644 for ( row = 0; row < m_numRows; row++ )
5645 {
5646 for ( col = 0; col < m_numCols; col++ )
5647 {
5648 m_table->SetValue( row, col, GetCellValue(row, col) );
5649 }
5650 }
5651
5652 return TRUE;
5653 }
5654
5655 return FALSE;
5656 }
5657
5658
5659
5660 // Note - this function only draws cells that are in the list of
5661 // exposed cells (usually set from the update region by
5662 // CalcExposedCells)
5663 //
5664 void wxGrid::DrawGridCellArea( wxDC& dc )
5665 {
5666 if ( !m_numRows || !m_numCols ) return;
5667
5668 size_t i;
5669 size_t numCells = m_cellsExposed.GetCount();
5670
5671 for ( i = 0; i < numCells; i++ )
5672 {
5673 DrawCell( dc, m_cellsExposed[i] );
5674 }
5675 }
5676
5677
5678 void wxGrid::DrawGridSpace( wxDC& dc )
5679 {
5680 int cw, ch;
5681 m_gridWin->GetClientSize( &cw, &ch );
5682
5683 int right, bottom;
5684 CalcUnscrolledPosition( cw, ch, &right, &bottom );
5685
5686 int rightCol = m_numCols > 0 ? GetColRight(m_numCols - 1) : 0;
5687 int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0 ;
5688
5689 if ( right > rightCol || bottom > bottomRow )
5690 {
5691 int left, top;
5692 CalcUnscrolledPosition( 0, 0, &left, &top );
5693
5694 dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) );
5695 dc.SetPen( *wxTRANSPARENT_PEN );
5696
5697 if ( right > rightCol )
5698 {
5699 dc.DrawRectangle( rightCol, top, right - rightCol, ch);
5700 }
5701
5702 if ( bottom > bottomRow )
5703 {
5704 dc.DrawRectangle( left, bottomRow, cw, bottom - bottomRow);
5705 }
5706 }
5707 }
5708
5709
5710 void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
5711 {
5712 int row = coords.GetRow();
5713 int col = coords.GetCol();
5714
5715 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
5716 return;
5717
5718 // we draw the cell border ourselves
5719 #if !WXGRID_DRAW_LINES
5720 if ( m_gridLinesEnabled )
5721 DrawCellBorder( dc, coords );
5722 #endif
5723
5724 wxGridCellAttr* attr = GetCellAttr(row, col);
5725
5726 bool isCurrent = coords == m_currentCellCoords;
5727
5728 wxRect rect = CellToRect( row, col );
5729
5730 // if the editor is shown, we should use it and not the renderer
5731 // Note: However, only if it is really _shown_, i.e. not hidden!
5732 if ( isCurrent && IsCellEditControlShown() )
5733 {
5734 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
5735 editor->PaintBackground(rect, attr);
5736 editor->DecRef();
5737 }
5738 else
5739 {
5740 // but all the rest is drawn by the cell renderer and hence may be
5741 // customized
5742 wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col);
5743 renderer->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
5744 renderer->DecRef();
5745 }
5746
5747 attr->DecRef();
5748 }
5749
5750 void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr )
5751 {
5752 int row = m_currentCellCoords.GetRow();
5753 int col = m_currentCellCoords.GetCol();
5754
5755 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
5756 return;
5757
5758 wxRect rect = CellToRect(row, col);
5759
5760 // hmmm... what could we do here to show that the cell is disabled?
5761 // for now, I just draw a thinner border than for the other ones, but
5762 // it doesn't look really good
5763 dc.SetPen(wxPen(m_cellHighlightColour, attr->IsReadOnly() ? 1 : 3, wxSOLID));
5764 dc.SetBrush(*wxTRANSPARENT_BRUSH);
5765
5766 dc.DrawRectangle(rect);
5767
5768 #if 0
5769 // VZ: my experiments with 3d borders...
5770
5771 // how to properly set colours for arbitrary bg?
5772 wxCoord x1 = rect.x,
5773 y1 = rect.y,
5774 x2 = rect.x + rect.width -1,
5775 y2 = rect.y + rect.height -1;
5776
5777 dc.SetPen(*wxWHITE_PEN);
5778 dc.DrawLine(x1, y1, x2, y1);
5779 dc.DrawLine(x1, y1, x1, y2);
5780
5781 dc.DrawLine(x1 + 1, y2 - 1, x2 - 1, y2 - 1);
5782 dc.DrawLine(x2 - 1, y1 + 1, x2 - 1, y2 );
5783
5784 dc.SetPen(*wxBLACK_PEN);
5785 dc.DrawLine(x1, y2, x2, y2);
5786 dc.DrawLine(x2, y1, x2, y2+1);
5787 #endif // 0
5788 }
5789
5790
5791 void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
5792 {
5793 int row = coords.GetRow();
5794 int col = coords.GetCol();
5795 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
5796 return;
5797
5798 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
5799
5800 // right hand border
5801 //
5802 dc.DrawLine( GetColRight(col), GetRowTop(row),
5803 GetColRight(col), GetRowBottom(row) );
5804
5805 // bottom border
5806 //
5807 dc.DrawLine( GetColLeft(col), GetRowBottom(row),
5808 GetColRight(col), GetRowBottom(row) );
5809 }
5810
5811 void wxGrid::DrawHighlight(wxDC& dc)
5812 {
5813 // This if block was previously in wxGrid::OnPaint but that doesn't
5814 // seem to get called under wxGTK - MB
5815 //
5816 if ( m_currentCellCoords == wxGridNoCellCoords &&
5817 m_numRows && m_numCols )
5818 {
5819 m_currentCellCoords.Set(0, 0);
5820 }
5821
5822 if ( IsCellEditControlShown() )
5823 {
5824 // don't show highlight when the edit control is shown
5825 return;
5826 }
5827
5828 // if the active cell was repainted, repaint its highlight too because it
5829 // might have been damaged by the grid lines
5830 size_t count = m_cellsExposed.GetCount();
5831 for ( size_t n = 0; n < count; n++ )
5832 {
5833 if ( m_cellsExposed[n] == m_currentCellCoords )
5834 {
5835 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
5836 DrawCellHighlight(dc, attr);
5837 attr->DecRef();
5838
5839 break;
5840 }
5841 }
5842 }
5843
5844 // TODO: remove this ???
5845 // This is used to redraw all grid lines e.g. when the grid line colour
5846 // has been changed
5847 //
5848 void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED_GTK(reg) )
5849 {
5850 if ( !m_gridLinesEnabled ||
5851 !m_numRows ||
5852 !m_numCols ) return;
5853
5854 int top, bottom, left, right;
5855
5856 #if 0 //#ifndef __WXGTK__
5857 if (reg.IsEmpty())
5858 {
5859 int cw, ch;
5860 m_gridWin->GetClientSize(&cw, &ch);
5861
5862 // virtual coords of visible area
5863 //
5864 CalcUnscrolledPosition( 0, 0, &left, &top );
5865 CalcUnscrolledPosition( cw, ch, &right, &bottom );
5866 }
5867 else
5868 {
5869 wxCoord x, y, w, h;
5870 reg.GetBox(x, y, w, h);
5871 CalcUnscrolledPosition( x, y, &left, &top );
5872 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
5873 }
5874 #else
5875 int cw, ch;
5876 m_gridWin->GetClientSize(&cw, &ch);
5877 CalcUnscrolledPosition( 0, 0, &left, &top );
5878 CalcUnscrolledPosition( cw, ch, &right, &bottom );
5879 #endif
5880
5881 // avoid drawing grid lines past the last row and col
5882 //
5883 right = wxMin( right, GetColRight(m_numCols - 1) );
5884 bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) );
5885
5886 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
5887
5888 // horizontal grid lines
5889 //
5890 int i;
5891 for ( i = 0; i < m_numRows; i++ )
5892 {
5893 int bot = GetRowBottom(i) - 1;
5894
5895 if ( bot > bottom )
5896 {
5897 break;
5898 }
5899
5900 if ( bot >= top )
5901 {
5902 dc.DrawLine( left, bot, right, bot );
5903 }
5904 }
5905
5906
5907 // vertical grid lines
5908 //
5909 for ( i = 0; i < m_numCols; i++ )
5910 {
5911 int colRight = GetColRight(i) - 1;
5912 if ( colRight > right )
5913 {
5914 break;
5915 }
5916
5917 if ( colRight >= left )
5918 {
5919 dc.DrawLine( colRight, top, colRight, bottom );
5920 }
5921 }
5922 }
5923
5924
5925 void wxGrid::DrawRowLabels( wxDC& dc )
5926 {
5927 if ( !m_numRows ) return;
5928
5929 size_t i;
5930 size_t numLabels = m_rowLabelsExposed.GetCount();
5931
5932 for ( i = 0; i < numLabels; i++ )
5933 {
5934 DrawRowLabel( dc, m_rowLabelsExposed[i] );
5935 }
5936 }
5937
5938
5939 void wxGrid::DrawRowLabel( wxDC& dc, int row )
5940 {
5941 if ( GetRowHeight(row) <= 0 )
5942 return;
5943
5944 int rowTop = GetRowTop(row),
5945 rowBottom = GetRowBottom(row) - 1;
5946
5947 dc.SetPen( *wxBLACK_PEN );
5948 dc.DrawLine( m_rowLabelWidth-1, rowTop,
5949 m_rowLabelWidth-1, rowBottom );
5950
5951 dc.DrawLine( 0, rowBottom, m_rowLabelWidth-1, rowBottom );
5952
5953 dc.SetPen( *wxWHITE_PEN );
5954 dc.DrawLine( 0, rowTop, 0, rowBottom );
5955 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
5956
5957 dc.SetBackgroundMode( wxTRANSPARENT );
5958 dc.SetTextForeground( GetLabelTextColour() );
5959 dc.SetFont( GetLabelFont() );
5960
5961 int hAlign, vAlign;
5962 GetRowLabelAlignment( &hAlign, &vAlign );
5963
5964 wxRect rect;
5965 rect.SetX( 2 );
5966 rect.SetY( GetRowTop(row) + 2 );
5967 rect.SetWidth( m_rowLabelWidth - 4 );
5968 rect.SetHeight( GetRowHeight(row) - 4 );
5969 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
5970 }
5971
5972
5973 void wxGrid::DrawColLabels( wxDC& dc )
5974 {
5975 if ( !m_numCols ) return;
5976
5977 size_t i;
5978 size_t numLabels = m_colLabelsExposed.GetCount();
5979
5980 for ( i = 0; i < numLabels; i++ )
5981 {
5982 DrawColLabel( dc, m_colLabelsExposed[i] );
5983 }
5984 }
5985
5986
5987 void wxGrid::DrawColLabel( wxDC& dc, int col )
5988 {
5989 if ( GetColWidth(col) <= 0 )
5990 return;
5991
5992 int colLeft = GetColLeft(col),
5993 colRight = GetColRight(col) - 1;
5994
5995 dc.SetPen( *wxBLACK_PEN );
5996 dc.DrawLine( colRight, 0,
5997 colRight, m_colLabelHeight-1 );
5998
5999 dc.DrawLine( colLeft, m_colLabelHeight-1,
6000 colRight, m_colLabelHeight-1 );
6001
6002 dc.SetPen( *wxWHITE_PEN );
6003 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
6004 dc.DrawLine( colLeft, 0, colRight, 0 );
6005
6006 dc.SetBackgroundMode( wxTRANSPARENT );
6007 dc.SetTextForeground( GetLabelTextColour() );
6008 dc.SetFont( GetLabelFont() );
6009
6010 dc.SetBackgroundMode( wxTRANSPARENT );
6011 dc.SetTextForeground( GetLabelTextColour() );
6012 dc.SetFont( GetLabelFont() );
6013
6014 int hAlign, vAlign;
6015 GetColLabelAlignment( &hAlign, &vAlign );
6016
6017 wxRect rect;
6018 rect.SetX( colLeft + 2 );
6019 rect.SetY( 2 );
6020 rect.SetWidth( GetColWidth(col) - 4 );
6021 rect.SetHeight( m_colLabelHeight - 4 );
6022 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
6023 }
6024
6025
6026 void wxGrid::DrawTextRectangle( wxDC& dc,
6027 const wxString& value,
6028 const wxRect& rect,
6029 int horizAlign,
6030 int vertAlign )
6031 {
6032 long textWidth, textHeight;
6033 long lineWidth, lineHeight;
6034 wxArrayString lines;
6035
6036 dc.SetClippingRegion( rect );
6037 StringToLines( value, lines );
6038 if ( lines.GetCount() )
6039 {
6040 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
6041 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
6042
6043 float x, y;
6044 switch ( horizAlign )
6045 {
6046 case wxRIGHT:
6047 x = rect.x + (rect.width - textWidth - 1);
6048 break;
6049
6050 case wxCENTRE:
6051 x = rect.x + ((rect.width - textWidth)/2);
6052 break;
6053
6054 case wxLEFT:
6055 default:
6056 x = rect.x + 1;
6057 break;
6058 }
6059
6060 switch ( vertAlign )
6061 {
6062 case wxBOTTOM:
6063 y = rect.y + (rect.height - textHeight - 1);
6064 break;
6065
6066 case wxCENTRE:
6067 y = rect.y + ((rect.height - textHeight)/2);
6068 break;
6069
6070 case wxTOP:
6071 default:
6072 y = rect.y + 1;
6073 break;
6074 }
6075
6076 for ( size_t i = 0; i < lines.GetCount(); i++ )
6077 {
6078 dc.DrawText( lines[i], (int)x, (int)y );
6079 y += lineHeight;
6080 }
6081 }
6082
6083 dc.DestroyClippingRegion();
6084 }
6085
6086
6087 // Split multi line text up into an array of strings. Any existing
6088 // contents of the string array are preserved.
6089 //
6090 void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
6091 {
6092 int startPos = 0;
6093 int pos;
6094 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
6095 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
6096
6097 while ( startPos < (int)tVal.Length() )
6098 {
6099 pos = tVal.Mid(startPos).Find( eol );
6100 if ( pos < 0 )
6101 {
6102 break;
6103 }
6104 else if ( pos == 0 )
6105 {
6106 lines.Add( wxEmptyString );
6107 }
6108 else
6109 {
6110 lines.Add( value.Mid(startPos, pos) );
6111 }
6112 startPos += pos+1;
6113 }
6114 if ( startPos < (int)value.Length() )
6115 {
6116 lines.Add( value.Mid( startPos ) );
6117 }
6118 }
6119
6120
6121 void wxGrid::GetTextBoxSize( wxDC& dc,
6122 wxArrayString& lines,
6123 long *width, long *height )
6124 {
6125 long w = 0;
6126 long h = 0;
6127 long lineW, lineH;
6128
6129 size_t i;
6130 for ( i = 0; i < lines.GetCount(); i++ )
6131 {
6132 dc.GetTextExtent( lines[i], &lineW, &lineH );
6133 w = wxMax( w, lineW );
6134 h += lineH;
6135 }
6136
6137 *width = w;
6138 *height = h;
6139 }
6140
6141 //
6142 // ------ Batch processing.
6143 //
6144 void wxGrid::EndBatch()
6145 {
6146 if ( m_batchCount > 0 )
6147 {
6148 m_batchCount--;
6149 if ( !m_batchCount )
6150 {
6151 CalcDimensions();
6152 m_rowLabelWin->Refresh();
6153 m_colLabelWin->Refresh();
6154 m_cornerLabelWin->Refresh();
6155 m_gridWin->Refresh();
6156 }
6157 }
6158 }
6159
6160 // Use this, rather than wxWindow::Refresh(), to force an immediate
6161 // repainting of the grid. Has no effect if you are already inside a
6162 // BeginBatch / EndBatch block.
6163 //
6164 void wxGrid::ForceRefresh()
6165 {
6166 BeginBatch();
6167 EndBatch();
6168 }
6169
6170
6171 //
6172 // ------ Edit control functions
6173 //
6174
6175
6176 void wxGrid::EnableEditing( bool edit )
6177 {
6178 // TODO: improve this ?
6179 //
6180 if ( edit != m_editable )
6181 {
6182 if(!edit) EnableCellEditControl(edit);
6183 m_editable = edit;
6184 }
6185 }
6186
6187
6188 void wxGrid::EnableCellEditControl( bool enable )
6189 {
6190 if (! m_editable)
6191 return;
6192
6193 if ( m_currentCellCoords == wxGridNoCellCoords )
6194 SetCurrentCell( 0, 0 );
6195
6196 if ( enable != m_cellEditCtrlEnabled )
6197 {
6198 // TODO allow the app to Veto() this event?
6199 SendEvent(enable ? wxEVT_GRID_EDITOR_SHOWN : wxEVT_GRID_EDITOR_HIDDEN);
6200
6201 if ( enable )
6202 {
6203 // this should be checked by the caller!
6204 wxASSERT_MSG( CanEnableCellControl(),
6205 _T("can't enable editing for this cell!") );
6206
6207 // do it before ShowCellEditControl()
6208 m_cellEditCtrlEnabled = enable;
6209
6210 ShowCellEditControl();
6211 }
6212 else
6213 {
6214 HideCellEditControl();
6215 SaveEditControlValue();
6216
6217 // do it after HideCellEditControl()
6218 m_cellEditCtrlEnabled = enable;
6219 }
6220 }
6221 }
6222
6223 bool wxGrid::IsCurrentCellReadOnly() const
6224 {
6225 // const_cast
6226 wxGridCellAttr* attr = ((wxGrid *)this)->GetCellAttr(m_currentCellCoords);
6227 bool readonly = attr->IsReadOnly();
6228 attr->DecRef();
6229
6230 return readonly;
6231 }
6232
6233 bool wxGrid::CanEnableCellControl() const
6234 {
6235 return m_editable && !IsCurrentCellReadOnly();
6236 }
6237
6238 bool wxGrid::IsCellEditControlEnabled() const
6239 {
6240 // the cell edit control might be disable for all cells or just for the
6241 // current one if it's read only
6242 return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : FALSE;
6243 }
6244
6245 bool wxGrid::IsCellEditControlShown() const
6246 {
6247 bool isShown = FALSE;
6248
6249 if ( m_cellEditCtrlEnabled )
6250 {
6251 int row = m_currentCellCoords.GetRow();
6252 int col = m_currentCellCoords.GetCol();
6253 wxGridCellAttr* attr = GetCellAttr(row, col);
6254 wxGridCellEditor* editor = attr->GetEditor((wxGrid*) this, row, col);
6255 attr->DecRef();
6256
6257 if ( editor )
6258 {
6259 if ( editor->IsCreated() )
6260 {
6261 isShown = editor->GetControl()->IsShown();
6262 }
6263
6264 editor->DecRef();
6265 }
6266 }
6267
6268 return isShown;
6269 }
6270
6271 void wxGrid::ShowCellEditControl()
6272 {
6273 if ( IsCellEditControlEnabled() )
6274 {
6275 if ( !IsVisible( m_currentCellCoords ) )
6276 {
6277 m_cellEditCtrlEnabled = false;
6278 return;
6279 }
6280 else
6281 {
6282 wxRect rect = CellToRect( m_currentCellCoords );
6283 int row = m_currentCellCoords.GetRow();
6284 int col = m_currentCellCoords.GetCol();
6285
6286 // convert to scrolled coords
6287 //
6288 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
6289
6290 // done in PaintBackground()
6291 #if 0
6292 // erase the highlight and the cell contents because the editor
6293 // might not cover the entire cell
6294 wxClientDC dc( m_gridWin );
6295 PrepareDC( dc );
6296 dc.SetBrush(*wxLIGHT_GREY_BRUSH); //wxBrush(attr->GetBackgroundColour(), wxSOLID));
6297 dc.SetPen(*wxTRANSPARENT_PEN);
6298 dc.DrawRectangle(rect);
6299 #endif // 0
6300
6301 // cell is shifted by one pixel
6302 rect.x--;
6303 rect.y--;
6304
6305 wxGridCellAttr* attr = GetCellAttr(row, col);
6306 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
6307 if ( !editor->IsCreated() )
6308 {
6309 editor->Create(m_gridWin, -1,
6310 new wxGridCellEditorEvtHandler(this, editor));
6311 }
6312
6313 editor->Show( TRUE, attr );
6314
6315 editor->SetSize( rect );
6316
6317 editor->BeginEdit(row, col, this);
6318
6319 editor->DecRef();
6320 attr->DecRef();
6321 }
6322 }
6323 }
6324
6325
6326 void wxGrid::HideCellEditControl()
6327 {
6328 if ( IsCellEditControlEnabled() )
6329 {
6330 int row = m_currentCellCoords.GetRow();
6331 int col = m_currentCellCoords.GetCol();
6332
6333 wxGridCellAttr* attr = GetCellAttr(row, col);
6334 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
6335 editor->Show( FALSE );
6336 editor->DecRef();
6337 attr->DecRef();
6338 m_gridWin->SetFocus();
6339 wxRect rect( CellToRect( row, col ) );
6340 m_gridWin->Refresh( FALSE, &rect );
6341 }
6342 }
6343
6344
6345 void wxGrid::SaveEditControlValue()
6346 {
6347 if ( IsCellEditControlEnabled() )
6348 {
6349 int row = m_currentCellCoords.GetRow();
6350 int col = m_currentCellCoords.GetCol();
6351
6352 wxGridCellAttr* attr = GetCellAttr(row, col);
6353 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
6354 bool changed = editor->EndEdit(row, col, this);
6355
6356 editor->DecRef();
6357 attr->DecRef();
6358
6359 if (changed)
6360 {
6361 SendEvent( wxEVT_GRID_CELL_CHANGE,
6362 m_currentCellCoords.GetRow(),
6363 m_currentCellCoords.GetCol() );
6364 }
6365 }
6366 }
6367
6368
6369 //
6370 // ------ Grid location functions
6371 // Note that all of these functions work with the logical coordinates of
6372 // grid cells and labels so you will need to convert from device
6373 // coordinates for mouse events etc.
6374 //
6375
6376 void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
6377 {
6378 int row = YToRow(y);
6379 int col = XToCol(x);
6380
6381 if ( row == -1 || col == -1 )
6382 {
6383 coords = wxGridNoCellCoords;
6384 }
6385 else
6386 {
6387 coords.Set( row, col );
6388 }
6389 }
6390
6391
6392 int wxGrid::YToRow( int y )
6393 {
6394 int i;
6395
6396 for ( i = 0; i < m_numRows; i++ )
6397 {
6398 if ( y < GetRowBottom(i) )
6399 return i;
6400 }
6401
6402 return -1;
6403 }
6404
6405
6406 int wxGrid::XToCol( int x )
6407 {
6408 int i;
6409
6410 for ( i = 0; i < m_numCols; i++ )
6411 {
6412 if ( x < GetColRight(i) )
6413 return i;
6414 }
6415
6416 return -1;
6417 }
6418
6419
6420 // return the row number that that the y coord is near the edge of, or
6421 // -1 if not near an edge
6422 //
6423 int wxGrid::YToEdgeOfRow( int y )
6424 {
6425 int i, d;
6426
6427 for ( i = 0; i < m_numRows; i++ )
6428 {
6429 if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE )
6430 {
6431 d = abs( y - GetRowBottom(i) );
6432 if ( d < WXGRID_LABEL_EDGE_ZONE )
6433 return i;
6434 }
6435 }
6436
6437 return -1;
6438 }
6439
6440
6441 // return the col number that that the x coord is near the edge of, or
6442 // -1 if not near an edge
6443 //
6444 int wxGrid::XToEdgeOfCol( int x )
6445 {
6446 int i, d;
6447
6448 for ( i = 0; i < m_numCols; i++ )
6449 {
6450 if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE )
6451 {
6452 d = abs( x - GetColRight(i) );
6453 if ( d < WXGRID_LABEL_EDGE_ZONE )
6454 return i;
6455 }
6456 }
6457
6458 return -1;
6459 }
6460
6461
6462 wxRect wxGrid::CellToRect( int row, int col )
6463 {
6464 wxRect rect( -1, -1, -1, -1 );
6465
6466 if ( row >= 0 && row < m_numRows &&
6467 col >= 0 && col < m_numCols )
6468 {
6469 rect.x = GetColLeft(col);
6470 rect.y = GetRowTop(row);
6471 rect.width = GetColWidth(col);
6472 rect.height = GetRowHeight(row);
6473 }
6474
6475 // if grid lines are enabled, then the area of the cell is a bit smaller
6476 if (m_gridLinesEnabled) {
6477 rect.width -= 1;
6478 rect.height -= 1;
6479 }
6480 return rect;
6481 }
6482
6483
6484 bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
6485 {
6486 // get the cell rectangle in logical coords
6487 //
6488 wxRect r( CellToRect( row, col ) );
6489
6490 // convert to device coords
6491 //
6492 int left, top, right, bottom;
6493 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
6494 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
6495
6496 // check against the client area of the grid window
6497 //
6498 int cw, ch;
6499 m_gridWin->GetClientSize( &cw, &ch );
6500
6501 if ( wholeCellVisible )
6502 {
6503 // is the cell wholly visible ?
6504 //
6505 return ( left >= 0 && right <= cw &&
6506 top >= 0 && bottom <= ch );
6507 }
6508 else
6509 {
6510 // is the cell partly visible ?
6511 //
6512 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
6513 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
6514 }
6515 }
6516
6517
6518 // make the specified cell location visible by doing a minimal amount
6519 // of scrolling
6520 //
6521 void wxGrid::MakeCellVisible( int row, int col )
6522 {
6523 int i;
6524 int xpos = -1, ypos = -1;
6525
6526 if ( row >= 0 && row < m_numRows &&
6527 col >= 0 && col < m_numCols )
6528 {
6529 // get the cell rectangle in logical coords
6530 //
6531 wxRect r( CellToRect( row, col ) );
6532
6533 // convert to device coords
6534 //
6535 int left, top, right, bottom;
6536 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
6537 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
6538
6539 int cw, ch;
6540 m_gridWin->GetClientSize( &cw, &ch );
6541
6542 if ( top < 0 )
6543 {
6544 ypos = r.GetTop();
6545 }
6546 else if ( bottom > ch )
6547 {
6548 int h = r.GetHeight();
6549 ypos = r.GetTop();
6550 for ( i = row-1; i >= 0; i-- )
6551 {
6552 int rowHeight = GetRowHeight(i);
6553 if ( h + rowHeight > ch )
6554 break;
6555
6556 h += rowHeight;
6557 ypos -= rowHeight;
6558 }
6559
6560 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
6561 // have rounding errors (this is important, because if we do, we
6562 // might not scroll at all and some cells won't be redrawn)
6563 ypos += GRID_SCROLL_LINE / 2;
6564 }
6565
6566 if ( left < 0 )
6567 {
6568 xpos = r.GetLeft();
6569 }
6570 else if ( right > cw )
6571 {
6572 int w = r.GetWidth();
6573 xpos = r.GetLeft();
6574 for ( i = col-1; i >= 0; i-- )
6575 {
6576 int colWidth = GetColWidth(i);
6577 if ( w + colWidth > cw )
6578 break;
6579
6580 w += colWidth;
6581 xpos -= colWidth;
6582 }
6583
6584 // see comment for ypos above
6585 xpos += GRID_SCROLL_LINE / 2;
6586 }
6587
6588 if ( xpos != -1 || ypos != -1 )
6589 {
6590 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
6591 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
6592 Scroll( xpos, ypos );
6593 AdjustScrollbars();
6594 }
6595 }
6596 }
6597
6598
6599 //
6600 // ------ Grid cursor movement functions
6601 //
6602
6603 bool wxGrid::MoveCursorUp( bool expandSelection )
6604 {
6605 if ( m_currentCellCoords != wxGridNoCellCoords &&
6606 m_currentCellCoords.GetRow() >= 0 )
6607 {
6608 if ( expandSelection)
6609 {
6610 if ( m_selectingKeyboard == wxGridNoCellCoords )
6611 m_selectingKeyboard = m_currentCellCoords;
6612 if ( m_selectingKeyboard.GetRow() > 0 )
6613 {
6614 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() - 1 );
6615 MakeCellVisible( m_selectingKeyboard.GetRow(),
6616 m_selectingKeyboard.GetCol() );
6617 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6618 }
6619 }
6620 else if ( m_currentCellCoords.GetRow() > 0 )
6621 {
6622 ClearSelection();
6623 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
6624 m_currentCellCoords.GetCol() );
6625 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
6626 m_currentCellCoords.GetCol() );
6627 }
6628 else
6629 return FALSE;
6630 return TRUE;
6631 }
6632
6633 return FALSE;
6634 }
6635
6636
6637 bool wxGrid::MoveCursorDown( bool expandSelection )
6638 {
6639 if ( m_currentCellCoords != wxGridNoCellCoords &&
6640 m_currentCellCoords.GetRow() < m_numRows )
6641 {
6642 if ( expandSelection )
6643 {
6644 if ( m_selectingKeyboard == wxGridNoCellCoords )
6645 m_selectingKeyboard = m_currentCellCoords;
6646 if ( m_selectingKeyboard.GetRow() < m_numRows-1 )
6647 {
6648 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() + 1 );
6649 MakeCellVisible( m_selectingKeyboard.GetRow(),
6650 m_selectingKeyboard.GetCol() );
6651 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6652 }
6653 }
6654 else if ( m_currentCellCoords.GetRow() < m_numRows - 1 )
6655 {
6656 ClearSelection();
6657 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
6658 m_currentCellCoords.GetCol() );
6659 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
6660 m_currentCellCoords.GetCol() );
6661 }
6662 else
6663 return FALSE;
6664 return TRUE;
6665 }
6666
6667 return FALSE;
6668 }
6669
6670
6671 bool wxGrid::MoveCursorLeft( bool expandSelection )
6672 {
6673 if ( m_currentCellCoords != wxGridNoCellCoords &&
6674 m_currentCellCoords.GetCol() >= 0 )
6675 {
6676 if ( expandSelection )
6677 {
6678 if ( m_selectingKeyboard == wxGridNoCellCoords )
6679 m_selectingKeyboard = m_currentCellCoords;
6680 if ( m_selectingKeyboard.GetCol() > 0 )
6681 {
6682 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() - 1 );
6683 MakeCellVisible( m_selectingKeyboard.GetRow(),
6684 m_selectingKeyboard.GetCol() );
6685 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6686 }
6687 }
6688 else if ( m_currentCellCoords.GetCol() > 0 )
6689 {
6690 ClearSelection();
6691 MakeCellVisible( m_currentCellCoords.GetRow(),
6692 m_currentCellCoords.GetCol() - 1 );
6693 SetCurrentCell( m_currentCellCoords.GetRow(),
6694 m_currentCellCoords.GetCol() - 1 );
6695 }
6696 else
6697 return FALSE;
6698 return TRUE;
6699 }
6700
6701 return FALSE;
6702 }
6703
6704
6705 bool wxGrid::MoveCursorRight( bool expandSelection )
6706 {
6707 if ( m_currentCellCoords != wxGridNoCellCoords &&
6708 m_currentCellCoords.GetCol() < m_numCols )
6709 {
6710 if ( expandSelection )
6711 {
6712 if ( m_selectingKeyboard == wxGridNoCellCoords )
6713 m_selectingKeyboard = m_currentCellCoords;
6714 if ( m_selectingKeyboard.GetCol() < m_numCols - 1 )
6715 {
6716 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() + 1 );
6717 MakeCellVisible( m_selectingKeyboard.GetRow(),
6718 m_selectingKeyboard.GetCol() );
6719 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6720 }
6721 }
6722 else if ( m_currentCellCoords.GetCol() < m_numCols - 1 )
6723 {
6724 ClearSelection();
6725 MakeCellVisible( m_currentCellCoords.GetRow(),
6726 m_currentCellCoords.GetCol() + 1 );
6727 SetCurrentCell( m_currentCellCoords.GetRow(),
6728 m_currentCellCoords.GetCol() + 1 );
6729 }
6730 else
6731 return FALSE;
6732 return TRUE;
6733 }
6734
6735 return FALSE;
6736 }
6737
6738
6739 bool wxGrid::MovePageUp()
6740 {
6741 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
6742
6743 int row = m_currentCellCoords.GetRow();
6744 if ( row > 0 )
6745 {
6746 int cw, ch;
6747 m_gridWin->GetClientSize( &cw, &ch );
6748
6749 int y = GetRowTop(row);
6750 int newRow = YToRow( y - ch + 1 );
6751 if ( newRow == -1 )
6752 {
6753 newRow = 0;
6754 }
6755 else if ( newRow == row )
6756 {
6757 newRow = row - 1;
6758 }
6759
6760 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
6761 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
6762
6763 return TRUE;
6764 }
6765
6766 return FALSE;
6767 }
6768
6769 bool wxGrid::MovePageDown()
6770 {
6771 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
6772
6773 int row = m_currentCellCoords.GetRow();
6774 if ( row < m_numRows )
6775 {
6776 int cw, ch;
6777 m_gridWin->GetClientSize( &cw, &ch );
6778
6779 int y = GetRowTop(row);
6780 int newRow = YToRow( y + ch );
6781 if ( newRow == -1 )
6782 {
6783 newRow = m_numRows - 1;
6784 }
6785 else if ( newRow == row )
6786 {
6787 newRow = row + 1;
6788 }
6789
6790 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
6791 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
6792
6793 return TRUE;
6794 }
6795
6796 return FALSE;
6797 }
6798
6799 bool wxGrid::MoveCursorUpBlock( bool expandSelection )
6800 {
6801 if ( m_table &&
6802 m_currentCellCoords != wxGridNoCellCoords &&
6803 m_currentCellCoords.GetRow() > 0 )
6804 {
6805 int row = m_currentCellCoords.GetRow();
6806 int col = m_currentCellCoords.GetCol();
6807
6808 if ( m_table->IsEmptyCell(row, col) )
6809 {
6810 // starting in an empty cell: find the next block of
6811 // non-empty cells
6812 //
6813 while ( row > 0 )
6814 {
6815 row-- ;
6816 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6817 }
6818 }
6819 else if ( m_table->IsEmptyCell(row-1, col) )
6820 {
6821 // starting at the top of a block: find the next block
6822 //
6823 row--;
6824 while ( row > 0 )
6825 {
6826 row-- ;
6827 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6828 }
6829 }
6830 else
6831 {
6832 // starting within a block: find the top of the block
6833 //
6834 while ( row > 0 )
6835 {
6836 row-- ;
6837 if ( m_table->IsEmptyCell(row, col) )
6838 {
6839 row++ ;
6840 break;
6841 }
6842 }
6843 }
6844
6845 MakeCellVisible( row, col );
6846 if ( expandSelection )
6847 {
6848 m_selectingKeyboard = wxGridCellCoords( row, col );
6849 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6850 }
6851 else
6852 {
6853 ClearSelection();
6854 SetCurrentCell( row, col );
6855 }
6856 return TRUE;
6857 }
6858
6859 return FALSE;
6860 }
6861
6862 bool wxGrid::MoveCursorDownBlock( bool expandSelection )
6863 {
6864 if ( m_table &&
6865 m_currentCellCoords != wxGridNoCellCoords &&
6866 m_currentCellCoords.GetRow() < m_numRows-1 )
6867 {
6868 int row = m_currentCellCoords.GetRow();
6869 int col = m_currentCellCoords.GetCol();
6870
6871 if ( m_table->IsEmptyCell(row, col) )
6872 {
6873 // starting in an empty cell: find the next block of
6874 // non-empty cells
6875 //
6876 while ( row < m_numRows-1 )
6877 {
6878 row++ ;
6879 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6880 }
6881 }
6882 else if ( m_table->IsEmptyCell(row+1, col) )
6883 {
6884 // starting at the bottom of a block: find the next block
6885 //
6886 row++;
6887 while ( row < m_numRows-1 )
6888 {
6889 row++ ;
6890 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6891 }
6892 }
6893 else
6894 {
6895 // starting within a block: find the bottom of the block
6896 //
6897 while ( row < m_numRows-1 )
6898 {
6899 row++ ;
6900 if ( m_table->IsEmptyCell(row, col) )
6901 {
6902 row-- ;
6903 break;
6904 }
6905 }
6906 }
6907
6908 MakeCellVisible( row, col );
6909 if ( expandSelection )
6910 {
6911 m_selectingKeyboard = wxGridCellCoords( row, col );
6912 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6913 }
6914 else
6915 {
6916 ClearSelection();
6917 SetCurrentCell( row, col );
6918 }
6919
6920 return TRUE;
6921 }
6922
6923 return FALSE;
6924 }
6925
6926 bool wxGrid::MoveCursorLeftBlock( bool expandSelection )
6927 {
6928 if ( m_table &&
6929 m_currentCellCoords != wxGridNoCellCoords &&
6930 m_currentCellCoords.GetCol() > 0 )
6931 {
6932 int row = m_currentCellCoords.GetRow();
6933 int col = m_currentCellCoords.GetCol();
6934
6935 if ( m_table->IsEmptyCell(row, col) )
6936 {
6937 // starting in an empty cell: find the next block of
6938 // non-empty cells
6939 //
6940 while ( col > 0 )
6941 {
6942 col-- ;
6943 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6944 }
6945 }
6946 else if ( m_table->IsEmptyCell(row, col-1) )
6947 {
6948 // starting at the left of a block: find the next block
6949 //
6950 col--;
6951 while ( col > 0 )
6952 {
6953 col-- ;
6954 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6955 }
6956 }
6957 else
6958 {
6959 // starting within a block: find the left of the block
6960 //
6961 while ( col > 0 )
6962 {
6963 col-- ;
6964 if ( m_table->IsEmptyCell(row, col) )
6965 {
6966 col++ ;
6967 break;
6968 }
6969 }
6970 }
6971
6972 MakeCellVisible( row, col );
6973 if ( expandSelection )
6974 {
6975 m_selectingKeyboard = wxGridCellCoords( row, col );
6976 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
6977 }
6978 else
6979 {
6980 ClearSelection();
6981 SetCurrentCell( row, col );
6982 }
6983
6984 return TRUE;
6985 }
6986
6987 return FALSE;
6988 }
6989
6990 bool wxGrid::MoveCursorRightBlock( bool expandSelection )
6991 {
6992 if ( m_table &&
6993 m_currentCellCoords != wxGridNoCellCoords &&
6994 m_currentCellCoords.GetCol() < m_numCols-1 )
6995 {
6996 int row = m_currentCellCoords.GetRow();
6997 int col = m_currentCellCoords.GetCol();
6998
6999 if ( m_table->IsEmptyCell(row, col) )
7000 {
7001 // starting in an empty cell: find the next block of
7002 // non-empty cells
7003 //
7004 while ( col < m_numCols-1 )
7005 {
7006 col++ ;
7007 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7008 }
7009 }
7010 else if ( m_table->IsEmptyCell(row, col+1) )
7011 {
7012 // starting at the right of a block: find the next block
7013 //
7014 col++;
7015 while ( col < m_numCols-1 )
7016 {
7017 col++ ;
7018 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7019 }
7020 }
7021 else
7022 {
7023 // starting within a block: find the right of the block
7024 //
7025 while ( col < m_numCols-1 )
7026 {
7027 col++ ;
7028 if ( m_table->IsEmptyCell(row, col) )
7029 {
7030 col-- ;
7031 break;
7032 }
7033 }
7034 }
7035
7036 MakeCellVisible( row, col );
7037 if ( expandSelection )
7038 {
7039 m_selectingKeyboard = wxGridCellCoords( row, col );
7040 SelectBlock( m_currentCellCoords, m_selectingKeyboard );
7041 }
7042 else
7043 {
7044 ClearSelection();
7045 SetCurrentCell( row, col );
7046 }
7047
7048 return TRUE;
7049 }
7050
7051 return FALSE;
7052 }
7053
7054
7055
7056 //
7057 // ------ Label values and formatting
7058 //
7059
7060 void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
7061 {
7062 *horiz = m_rowLabelHorizAlign;
7063 *vert = m_rowLabelVertAlign;
7064 }
7065
7066 void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
7067 {
7068 *horiz = m_colLabelHorizAlign;
7069 *vert = m_colLabelVertAlign;
7070 }
7071
7072 wxString wxGrid::GetRowLabelValue( int row )
7073 {
7074 if ( m_table )
7075 {
7076 return m_table->GetRowLabelValue( row );
7077 }
7078 else
7079 {
7080 wxString s;
7081 s << row;
7082 return s;
7083 }
7084 }
7085
7086 wxString wxGrid::GetColLabelValue( int col )
7087 {
7088 if ( m_table )
7089 {
7090 return m_table->GetColLabelValue( col );
7091 }
7092 else
7093 {
7094 wxString s;
7095 s << col;
7096 return s;
7097 }
7098 }
7099
7100
7101 void wxGrid::SetRowLabelSize( int width )
7102 {
7103 width = wxMax( width, 0 );
7104 if ( width != m_rowLabelWidth )
7105 {
7106 if ( width == 0 )
7107 {
7108 m_rowLabelWin->Show( FALSE );
7109 m_cornerLabelWin->Show( FALSE );
7110 }
7111 else if ( m_rowLabelWidth == 0 )
7112 {
7113 m_rowLabelWin->Show( TRUE );
7114 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
7115 }
7116
7117 m_rowLabelWidth = width;
7118 CalcWindowSizes();
7119 Refresh( TRUE );
7120 }
7121 }
7122
7123
7124 void wxGrid::SetColLabelSize( int height )
7125 {
7126 height = wxMax( height, 0 );
7127 if ( height != m_colLabelHeight )
7128 {
7129 if ( height == 0 )
7130 {
7131 m_colLabelWin->Show( FALSE );
7132 m_cornerLabelWin->Show( FALSE );
7133 }
7134 else if ( m_colLabelHeight == 0 )
7135 {
7136 m_colLabelWin->Show( TRUE );
7137 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
7138 }
7139
7140 m_colLabelHeight = height;
7141 CalcWindowSizes();
7142 Refresh( TRUE );
7143 }
7144 }
7145
7146
7147 void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
7148 {
7149 if ( m_labelBackgroundColour != colour )
7150 {
7151 m_labelBackgroundColour = colour;
7152 m_rowLabelWin->SetBackgroundColour( colour );
7153 m_colLabelWin->SetBackgroundColour( colour );
7154 m_cornerLabelWin->SetBackgroundColour( colour );
7155
7156 if ( !GetBatchCount() )
7157 {
7158 m_rowLabelWin->Refresh();
7159 m_colLabelWin->Refresh();
7160 m_cornerLabelWin->Refresh();
7161 }
7162 }
7163 }
7164
7165 void wxGrid::SetLabelTextColour( const wxColour& colour )
7166 {
7167 if ( m_labelTextColour != colour )
7168 {
7169 m_labelTextColour = colour;
7170 if ( !GetBatchCount() )
7171 {
7172 m_rowLabelWin->Refresh();
7173 m_colLabelWin->Refresh();
7174 }
7175 }
7176 }
7177
7178 void wxGrid::SetLabelFont( const wxFont& font )
7179 {
7180 m_labelFont = font;
7181 if ( !GetBatchCount() )
7182 {
7183 m_rowLabelWin->Refresh();
7184 m_colLabelWin->Refresh();
7185 }
7186 }
7187
7188 void wxGrid::SetRowLabelAlignment( int horiz, int vert )
7189 {
7190 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
7191 {
7192 m_rowLabelHorizAlign = horiz;
7193 }
7194
7195 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
7196 {
7197 m_rowLabelVertAlign = vert;
7198 }
7199
7200 if ( !GetBatchCount() )
7201 {
7202 m_rowLabelWin->Refresh();
7203 }
7204 }
7205
7206 void wxGrid::SetColLabelAlignment( int horiz, int vert )
7207 {
7208 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
7209 {
7210 m_colLabelHorizAlign = horiz;
7211 }
7212
7213 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
7214 {
7215 m_colLabelVertAlign = vert;
7216 }
7217
7218 if ( !GetBatchCount() )
7219 {
7220 m_colLabelWin->Refresh();
7221 }
7222 }
7223
7224 void wxGrid::SetRowLabelValue( int row, const wxString& s )
7225 {
7226 if ( m_table )
7227 {
7228 m_table->SetRowLabelValue( row, s );
7229 if ( !GetBatchCount() )
7230 {
7231 wxRect rect = CellToRect( row, 0);
7232 if ( rect.height > 0 )
7233 {
7234 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
7235 rect.x = m_left;
7236 rect.width = m_rowLabelWidth;
7237 m_rowLabelWin->Refresh( TRUE, &rect );
7238 }
7239 }
7240 }
7241 }
7242
7243 void wxGrid::SetColLabelValue( int col, const wxString& s )
7244 {
7245 if ( m_table )
7246 {
7247 m_table->SetColLabelValue( col, s );
7248 if ( !GetBatchCount() )
7249 {
7250 wxRect rect = CellToRect( 0, col );
7251 if ( rect.width > 0 )
7252 {
7253 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
7254 rect.y = m_top;
7255 rect.height = m_colLabelHeight;
7256 m_colLabelWin->Refresh( TRUE, &rect );
7257 }
7258 }
7259 }
7260 }
7261
7262 void wxGrid::SetGridLineColour( const wxColour& colour )
7263 {
7264 if ( m_gridLineColour != colour )
7265 {
7266 m_gridLineColour = colour;
7267
7268 wxClientDC dc( m_gridWin );
7269 PrepareDC( dc );
7270 DrawAllGridLines( dc, wxRegion() );
7271 }
7272 }
7273
7274
7275 void wxGrid::SetCellHighlightColour( const wxColour& colour )
7276 {
7277 if ( m_cellHighlightColour != colour )
7278 {
7279 m_cellHighlightColour = colour;
7280
7281 wxClientDC dc( m_gridWin );
7282 PrepareDC( dc );
7283 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
7284 DrawCellHighlight(dc, attr);
7285 attr->DecRef();
7286 }
7287 }
7288
7289 void wxGrid::EnableGridLines( bool enable )
7290 {
7291 if ( enable != m_gridLinesEnabled )
7292 {
7293 m_gridLinesEnabled = enable;
7294
7295 if ( !GetBatchCount() )
7296 {
7297 if ( enable )
7298 {
7299 wxClientDC dc( m_gridWin );
7300 PrepareDC( dc );
7301 DrawAllGridLines( dc, wxRegion() );
7302 }
7303 else
7304 {
7305 m_gridWin->Refresh();
7306 }
7307 }
7308 }
7309 }
7310
7311
7312 int wxGrid::GetDefaultRowSize()
7313 {
7314 return m_defaultRowHeight;
7315 }
7316
7317 int wxGrid::GetRowSize( int row )
7318 {
7319 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
7320
7321 return GetRowHeight(row);
7322 }
7323
7324 int wxGrid::GetDefaultColSize()
7325 {
7326 return m_defaultColWidth;
7327 }
7328
7329 int wxGrid::GetColSize( int col )
7330 {
7331 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
7332
7333 return GetColWidth(col);
7334 }
7335
7336 // ============================================================================
7337 // access to the grid attributes: each of them has a default value in the grid
7338 // itself and may be overidden on a per-cell basis
7339 // ============================================================================
7340
7341 // ----------------------------------------------------------------------------
7342 // setting default attributes
7343 // ----------------------------------------------------------------------------
7344
7345 void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
7346 {
7347 m_defaultCellAttr->SetBackgroundColour(col);
7348 #ifdef __WXGTK__
7349 m_gridWin->SetBackgroundColour(col);
7350 #endif
7351 }
7352
7353 void wxGrid::SetDefaultCellTextColour( const wxColour& col )
7354 {
7355 m_defaultCellAttr->SetTextColour(col);
7356 }
7357
7358 void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
7359 {
7360 m_defaultCellAttr->SetAlignment(horiz, vert);
7361 }
7362
7363 void wxGrid::SetDefaultCellFont( const wxFont& font )
7364 {
7365 m_defaultCellAttr->SetFont(font);
7366 }
7367
7368 void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
7369 {
7370 m_defaultCellAttr->SetRenderer(renderer);
7371 }
7372
7373 void wxGrid::SetDefaultEditor(wxGridCellEditor *editor)
7374 {
7375 m_defaultCellAttr->SetEditor(editor);
7376 }
7377
7378 // ----------------------------------------------------------------------------
7379 // access to the default attrbiutes
7380 // ----------------------------------------------------------------------------
7381
7382 wxColour wxGrid::GetDefaultCellBackgroundColour()
7383 {
7384 return m_defaultCellAttr->GetBackgroundColour();
7385 }
7386
7387 wxColour wxGrid::GetDefaultCellTextColour()
7388 {
7389 return m_defaultCellAttr->GetTextColour();
7390 }
7391
7392 wxFont wxGrid::GetDefaultCellFont()
7393 {
7394 return m_defaultCellAttr->GetFont();
7395 }
7396
7397 void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
7398 {
7399 m_defaultCellAttr->GetAlignment(horiz, vert);
7400 }
7401
7402 wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
7403 {
7404 return m_defaultCellAttr->GetRenderer(NULL, 0, 0);
7405 }
7406
7407 wxGridCellEditor *wxGrid::GetDefaultEditor() const
7408 {
7409 return m_defaultCellAttr->GetEditor(NULL,0,0);
7410 }
7411
7412 // ----------------------------------------------------------------------------
7413 // access to cell attributes
7414 // ----------------------------------------------------------------------------
7415
7416 wxColour wxGrid::GetCellBackgroundColour(int row, int col)
7417 {
7418 wxGridCellAttr *attr = GetCellAttr(row, col);
7419 wxColour colour = attr->GetBackgroundColour();
7420 attr->DecRef();
7421 return colour;
7422 }
7423
7424 wxColour wxGrid::GetCellTextColour( int row, int col )
7425 {
7426 wxGridCellAttr *attr = GetCellAttr(row, col);
7427 wxColour colour = attr->GetTextColour();
7428 attr->DecRef();
7429 return colour;
7430 }
7431
7432 wxFont wxGrid::GetCellFont( int row, int col )
7433 {
7434 wxGridCellAttr *attr = GetCellAttr(row, col);
7435 wxFont font = attr->GetFont();
7436 attr->DecRef();
7437 return font;
7438 }
7439
7440 void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
7441 {
7442 wxGridCellAttr *attr = GetCellAttr(row, col);
7443 attr->GetAlignment(horiz, vert);
7444 attr->DecRef();
7445 }
7446
7447 wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
7448 {
7449 wxGridCellAttr* attr = GetCellAttr(row, col);
7450 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
7451 attr->DecRef();
7452
7453 return renderer;
7454 }
7455
7456 wxGridCellEditor* wxGrid::GetCellEditor(int row, int col)
7457 {
7458 wxGridCellAttr* attr = GetCellAttr(row, col);
7459 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
7460 attr->DecRef();
7461
7462 return editor;
7463 }
7464
7465 bool wxGrid::IsReadOnly(int row, int col) const
7466 {
7467 wxGridCellAttr* attr = GetCellAttr(row, col);
7468 bool isReadOnly = attr->IsReadOnly();
7469 attr->DecRef();
7470 return isReadOnly;
7471 }
7472
7473 // ----------------------------------------------------------------------------
7474 // attribute support: cache, automatic provider creation, ...
7475 // ----------------------------------------------------------------------------
7476
7477 bool wxGrid::CanHaveAttributes()
7478 {
7479 if ( !m_table )
7480 {
7481 return FALSE;
7482 }
7483
7484 return m_table->CanHaveAttributes();
7485 }
7486
7487 void wxGrid::ClearAttrCache()
7488 {
7489 if ( m_attrCache.row != -1 )
7490 {
7491 wxSafeDecRef(m_attrCache.attr);
7492 m_attrCache.row = -1;
7493 }
7494 }
7495
7496 void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
7497 {
7498 wxGrid *self = (wxGrid *)this; // const_cast
7499
7500 self->ClearAttrCache();
7501 self->m_attrCache.row = row;
7502 self->m_attrCache.col = col;
7503 self->m_attrCache.attr = attr;
7504 wxSafeIncRef(attr);
7505 }
7506
7507 bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
7508 {
7509 if ( row == m_attrCache.row && col == m_attrCache.col )
7510 {
7511 *attr = m_attrCache.attr;
7512 wxSafeIncRef(m_attrCache.attr);
7513
7514 #ifdef DEBUG_ATTR_CACHE
7515 gs_nAttrCacheHits++;
7516 #endif
7517
7518 return TRUE;
7519 }
7520 else
7521 {
7522 #ifdef DEBUG_ATTR_CACHE
7523 gs_nAttrCacheMisses++;
7524 #endif
7525 return FALSE;
7526 }
7527 }
7528
7529 wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
7530 {
7531 wxGridCellAttr *attr;
7532 if ( !LookupAttr(row, col, &attr) )
7533 {
7534 attr = m_table ? m_table->GetAttr(row, col) : (wxGridCellAttr *)NULL;
7535 CacheAttr(row, col, attr);
7536 }
7537 if (attr)
7538 {
7539 attr->SetDefAttr(m_defaultCellAttr);
7540 }
7541 else
7542 {
7543 attr = m_defaultCellAttr;
7544 attr->IncRef();
7545 }
7546
7547 return attr;
7548 }
7549
7550 wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
7551 {
7552 wxGridCellAttr *attr;
7553 if ( !LookupAttr(row, col, &attr) || !attr )
7554 {
7555 wxASSERT_MSG( m_table,
7556 _T("we may only be called if CanHaveAttributes() returned TRUE and then m_table should be !NULL") );
7557
7558 attr = m_table->GetAttr(row, col);
7559 if ( !attr )
7560 {
7561 attr = new wxGridCellAttr;
7562
7563 // artificially inc the ref count to match DecRef() in caller
7564 attr->IncRef();
7565
7566 m_table->SetAttr(attr, row, col);
7567 }
7568
7569 CacheAttr(row, col, attr);
7570 }
7571 attr->SetDefAttr(m_defaultCellAttr);
7572 return attr;
7573 }
7574
7575 // ----------------------------------------------------------------------------
7576 // setting column attributes (wrappers around SetColAttr)
7577 // ----------------------------------------------------------------------------
7578
7579 void wxGrid::SetColFormatBool(int col)
7580 {
7581 SetColFormatCustom(col, wxGRID_VALUE_BOOL);
7582 }
7583
7584 void wxGrid::SetColFormatNumber(int col)
7585 {
7586 SetColFormatCustom(col, wxGRID_VALUE_NUMBER);
7587 }
7588
7589 void wxGrid::SetColFormatFloat(int col, int width, int precision)
7590 {
7591 wxString typeName = wxGRID_VALUE_FLOAT;
7592 if ( (width != -1) || (precision != -1) )
7593 {
7594 typeName << _T(':') << width << _T(',') << precision;
7595 }
7596
7597 SetColFormatCustom(col, typeName);
7598 }
7599
7600 void wxGrid::SetColFormatCustom(int col, const wxString& typeName)
7601 {
7602 wxGridCellAttr *attr = new wxGridCellAttr;
7603 wxGridCellRenderer *renderer = GetDefaultRendererForType(typeName);
7604 attr->SetRenderer(renderer);
7605
7606 SetColAttr(col, attr);
7607 }
7608
7609 // ----------------------------------------------------------------------------
7610 // setting cell attributes: this is forwarded to the table
7611 // ----------------------------------------------------------------------------
7612
7613 void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
7614 {
7615 if ( CanHaveAttributes() )
7616 {
7617 m_table->SetRowAttr(attr, row);
7618 }
7619 else
7620 {
7621 wxSafeDecRef(attr);
7622 }
7623 }
7624
7625 void wxGrid::SetColAttr(int col, wxGridCellAttr *attr)
7626 {
7627 if ( CanHaveAttributes() )
7628 {
7629 m_table->SetColAttr(attr, col);
7630 }
7631 else
7632 {
7633 wxSafeDecRef(attr);
7634 }
7635 }
7636
7637 void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
7638 {
7639 if ( CanHaveAttributes() )
7640 {
7641 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7642 attr->SetBackgroundColour(colour);
7643 attr->DecRef();
7644 }
7645 }
7646
7647 void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
7648 {
7649 if ( CanHaveAttributes() )
7650 {
7651 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7652 attr->SetTextColour(colour);
7653 attr->DecRef();
7654 }
7655 }
7656
7657 void wxGrid::SetCellFont( int row, int col, const wxFont& font )
7658 {
7659 if ( CanHaveAttributes() )
7660 {
7661 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7662 attr->SetFont(font);
7663 attr->DecRef();
7664 }
7665 }
7666
7667 void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
7668 {
7669 if ( CanHaveAttributes() )
7670 {
7671 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7672 attr->SetAlignment(horiz, vert);
7673 attr->DecRef();
7674 }
7675 }
7676
7677 void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
7678 {
7679 if ( CanHaveAttributes() )
7680 {
7681 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7682 attr->SetRenderer(renderer);
7683 attr->DecRef();
7684 }
7685 }
7686
7687 void wxGrid::SetCellEditor(int row, int col, wxGridCellEditor* editor)
7688 {
7689 if ( CanHaveAttributes() )
7690 {
7691 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7692 attr->SetEditor(editor);
7693 attr->DecRef();
7694 }
7695 }
7696
7697 void wxGrid::SetReadOnly(int row, int col, bool isReadOnly)
7698 {
7699 if ( CanHaveAttributes() )
7700 {
7701 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
7702 attr->SetReadOnly(isReadOnly);
7703 attr->DecRef();
7704 }
7705 }
7706
7707 // ----------------------------------------------------------------------------
7708 // Data type registration
7709 // ----------------------------------------------------------------------------
7710
7711 void wxGrid::RegisterDataType(const wxString& typeName,
7712 wxGridCellRenderer* renderer,
7713 wxGridCellEditor* editor)
7714 {
7715 m_typeRegistry->RegisterDataType(typeName, renderer, editor);
7716 }
7717
7718
7719 wxGridCellEditor* wxGrid::GetDefaultEditorForCell(int row, int col) const
7720 {
7721 wxString typeName = m_table->GetTypeName(row, col);
7722 return GetDefaultEditorForType(typeName);
7723 }
7724
7725 wxGridCellRenderer* wxGrid::GetDefaultRendererForCell(int row, int col) const
7726 {
7727 wxString typeName = m_table->GetTypeName(row, col);
7728 return GetDefaultRendererForType(typeName);
7729 }
7730
7731 wxGridCellEditor*
7732 wxGrid::GetDefaultEditorForType(const wxString& typeName) const
7733 {
7734 int index = m_typeRegistry->FindOrCloneDataType(typeName);
7735 if ( index == wxNOT_FOUND )
7736 {
7737 wxFAIL_MSG(wxT("Unknown data type name"));
7738
7739 return NULL;
7740 }
7741
7742 return m_typeRegistry->GetEditor(index);
7743 }
7744
7745 wxGridCellRenderer*
7746 wxGrid::GetDefaultRendererForType(const wxString& typeName) const
7747 {
7748 int index = m_typeRegistry->FindOrCloneDataType(typeName);
7749 if ( index == wxNOT_FOUND )
7750 {
7751 wxFAIL_MSG(wxT("Unknown data type name"));
7752
7753 return NULL;
7754 }
7755
7756 return m_typeRegistry->GetRenderer(index);
7757 }
7758
7759
7760 // ----------------------------------------------------------------------------
7761 // row/col size
7762 // ----------------------------------------------------------------------------
7763
7764 void wxGrid::EnableDragRowSize( bool enable )
7765 {
7766 m_canDragRowSize = enable;
7767 }
7768
7769
7770 void wxGrid::EnableDragColSize( bool enable )
7771 {
7772 m_canDragColSize = enable;
7773 }
7774
7775 void wxGrid::EnableDragGridSize( bool enable )
7776 {
7777 m_canDragGridSize = enable;
7778 }
7779
7780
7781 void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
7782 {
7783 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
7784
7785 if ( resizeExistingRows )
7786 {
7787 InitRowHeights();
7788
7789 CalcDimensions();
7790 }
7791 }
7792
7793 void wxGrid::SetRowSize( int row, int height )
7794 {
7795 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
7796
7797 if ( m_rowHeights.IsEmpty() )
7798 {
7799 // need to really create the array
7800 InitRowHeights();
7801 }
7802
7803 int h = wxMax( 0, height );
7804 int diff = h - m_rowHeights[row];
7805
7806 m_rowHeights[row] = h;
7807 int i;
7808 for ( i = row; i < m_numRows; i++ )
7809 {
7810 m_rowBottoms[i] += diff;
7811 }
7812 CalcDimensions();
7813 }
7814
7815 void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
7816 {
7817 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
7818
7819 if ( resizeExistingCols )
7820 {
7821 InitColWidths();
7822
7823 CalcDimensions();
7824 }
7825 }
7826
7827 void wxGrid::SetColSize( int col, int width )
7828 {
7829 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
7830
7831 // should we check that it's bigger than GetColMinimalWidth(col) here?
7832
7833 if ( m_colWidths.IsEmpty() )
7834 {
7835 // need to really create the array
7836 InitColWidths();
7837 }
7838
7839 int w = wxMax( 0, width );
7840 int diff = w - m_colWidths[col];
7841 m_colWidths[col] = w;
7842
7843 int i;
7844 for ( i = col; i < m_numCols; i++ )
7845 {
7846 m_colRights[i] += diff;
7847 }
7848 CalcDimensions();
7849 }
7850
7851
7852 void wxGrid::SetColMinimalWidth( int col, int width )
7853 {
7854 m_colMinWidths.Put(col, width);
7855 }
7856
7857 void wxGrid::SetRowMinimalHeight( int row, int width )
7858 {
7859 m_rowMinHeights.Put(row, width);
7860 }
7861
7862 int wxGrid::GetColMinimalWidth(int col) const
7863 {
7864 long value = m_colMinWidths.Get(col);
7865 return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_COL_WIDTH;
7866 }
7867
7868 int wxGrid::GetRowMinimalHeight(int row) const
7869 {
7870 long value = m_rowMinHeights.Get(row);
7871 return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_ROW_HEIGHT;
7872 }
7873
7874 // ----------------------------------------------------------------------------
7875 // auto sizing
7876 // ----------------------------------------------------------------------------
7877
7878 void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column )
7879 {
7880 wxClientDC dc(m_gridWin);
7881
7882 // init both of them to avoid compiler warnings, even if weo nly need one
7883 int row = -1,
7884 col = -1;
7885 if ( column )
7886 col = colOrRow;
7887 else
7888 row = colOrRow;
7889
7890 wxCoord extent, extentMax = 0;
7891 int max = column ? m_numRows : m_numCols;
7892 for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ )
7893 {
7894 if ( column )
7895 row = rowOrCol;
7896 else
7897 col = rowOrCol;
7898
7899 wxGridCellAttr* attr = GetCellAttr(row, col);
7900 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
7901 if ( renderer )
7902 {
7903 wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col);
7904 extent = column ? size.x : size.y;
7905 if ( extent > extentMax )
7906 {
7907 extentMax = extent;
7908 }
7909
7910 renderer->DecRef();
7911 }
7912
7913 attr->DecRef();
7914 }
7915
7916 // now also compare with the column label extent
7917 wxCoord w, h;
7918 dc.SetFont( GetLabelFont() );
7919
7920 if ( column )
7921 dc.GetTextExtent( GetColLabelValue(col), &w, &h );
7922 else
7923 dc.GetTextExtent( GetRowLabelValue(col), &w, &h );
7924
7925 extent = column ? w : h;
7926 if ( extent > extentMax )
7927 {
7928 extentMax = extent;
7929 }
7930
7931 if ( !extentMax )
7932 {
7933 // empty column - give default extent (notice that if extentMax is less
7934 // than default extent but != 0, it's ok)
7935 extentMax = column ? m_defaultColWidth : m_defaultRowHeight;
7936 }
7937 else
7938 {
7939 if ( column )
7940 {
7941 // leave some space around text
7942 extentMax += 10;
7943 }
7944 else
7945 {
7946 extentMax += 6;
7947 }
7948 }
7949
7950 if ( column )
7951 SetColSize(col, extentMax);
7952 else
7953 SetRowSize(row, extentMax);
7954
7955 if ( setAsMin )
7956 {
7957 if ( column )
7958 SetColMinimalWidth(col, extentMax);
7959 else
7960 SetRowMinimalHeight(row, extentMax);
7961 }
7962 }
7963
7964 int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
7965 {
7966 int width = m_rowLabelWidth;
7967
7968 for ( int col = 0; col < m_numCols; col++ )
7969 {
7970 if ( !calcOnly )
7971 {
7972 AutoSizeColumn(col, setAsMin);
7973 }
7974
7975 width += GetColWidth(col);
7976 }
7977
7978 return width;
7979 }
7980
7981 int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
7982 {
7983 int height = m_colLabelHeight;
7984
7985 for ( int row = 0; row < m_numRows; row++ )
7986 {
7987 if ( !calcOnly )
7988 {
7989 AutoSizeRow(row, setAsMin);
7990 }
7991
7992 height += GetRowHeight(row);
7993 }
7994
7995 return height;
7996 }
7997
7998 void wxGrid::AutoSize()
7999 {
8000 // set the size too
8001 SetSize(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE));
8002 }
8003
8004 wxSize wxGrid::DoGetBestSize() const
8005 {
8006 // don't set sizes, only calculate them
8007 wxGrid *self = (wxGrid *)this; // const_cast
8008
8009 return wxSize(self->SetOrCalcColumnSizes(TRUE),
8010 self->SetOrCalcRowSizes(TRUE));
8011 }
8012
8013 void wxGrid::Fit()
8014 {
8015 AutoSize();
8016 }
8017
8018
8019 wxPen& wxGrid::GetDividerPen() const
8020 {
8021 return wxNullPen;
8022 }
8023
8024 // ----------------------------------------------------------------------------
8025 // cell value accessor functions
8026 // ----------------------------------------------------------------------------
8027
8028 void wxGrid::SetCellValue( int row, int col, const wxString& s )
8029 {
8030 if ( m_table )
8031 {
8032 m_table->SetValue( row, col, s );
8033 if ( !GetBatchCount() )
8034 {
8035 wxClientDC dc( m_gridWin );
8036 PrepareDC( dc );
8037 DrawCell( dc, wxGridCellCoords(row, col) );
8038 }
8039
8040 if ( m_currentCellCoords.GetRow() == row &&
8041 m_currentCellCoords.GetCol() == col &&
8042 IsCellEditControlShown())
8043 // Note: If we are using IsCellEditControlEnabled,
8044 // this interacts badly with calling SetCellValue from
8045 // an EVT_GRID_CELL_CHANGE handler.
8046 {
8047 HideCellEditControl();
8048 ShowCellEditControl(); // will reread data from table
8049 }
8050 }
8051 }
8052
8053
8054 //
8055 // ------ Block, row and col selection
8056 //
8057
8058 void wxGrid::SelectRow( int row, bool addToSelected )
8059 {
8060 if ( IsSelection() && !addToSelected )
8061 ClearSelection();
8062
8063 m_selection->SelectRow( row, FALSE, addToSelected );
8064 }
8065
8066
8067 void wxGrid::SelectCol( int col, bool addToSelected )
8068 {
8069 if ( IsSelection() && !addToSelected )
8070 ClearSelection();
8071
8072 m_selection->SelectCol( col, FALSE, addToSelected );
8073 }
8074
8075
8076 void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
8077 {
8078 int temp;
8079 wxGridCellCoords updateTopLeft, updateBottomRight;
8080
8081 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
8082 {
8083 leftCol = 0;
8084 rightCol = GetNumberCols() - 1;
8085 }
8086 else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
8087 {
8088 topRow = 0;
8089 bottomRow = GetNumberRows() - 1;
8090 }
8091 if ( topRow > bottomRow )
8092 {
8093 temp = topRow;
8094 topRow = bottomRow;
8095 bottomRow = temp;
8096 }
8097
8098 if ( leftCol > rightCol )
8099 {
8100 temp = leftCol;
8101 leftCol = rightCol;
8102 rightCol = temp;
8103 }
8104
8105 updateTopLeft = wxGridCellCoords( topRow, leftCol );
8106 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
8107
8108 if ( m_selectingTopLeft != updateTopLeft ||
8109 m_selectingBottomRight != updateBottomRight )
8110 {
8111 // Compute two optimal update rectangles:
8112 // Either one rectangle is a real subset of the
8113 // other, or they are (almost) disjoint!
8114 wxRect rect[4];
8115 bool need_refresh[4];
8116 need_refresh[0] =
8117 need_refresh[1] =
8118 need_refresh[2] =
8119 need_refresh[3] = FALSE;
8120 int i;
8121
8122 // Store intermediate values
8123 wxCoord oldLeft = m_selectingTopLeft.GetCol();
8124 wxCoord oldTop = m_selectingTopLeft.GetRow();
8125 wxCoord oldRight = m_selectingBottomRight.GetCol();
8126 wxCoord oldBottom = m_selectingBottomRight.GetRow();
8127
8128 // Determine the outer/inner coordinates.
8129 if (oldLeft > leftCol)
8130 {
8131 temp = oldLeft;
8132 oldLeft = leftCol;
8133 leftCol = temp;
8134 }
8135 if (oldTop > topRow )
8136 {
8137 temp = oldTop;
8138 oldTop = topRow;
8139 topRow = temp;
8140 }
8141 if (oldRight < rightCol )
8142 {
8143 temp = oldRight;
8144 oldRight = rightCol;
8145 rightCol = temp;
8146 }
8147 if (oldBottom < bottomRow)
8148 {
8149 temp = oldBottom;
8150 oldBottom = bottomRow;
8151 bottomRow = temp;
8152 }
8153
8154 // Now, either the stuff marked old is the outer
8155 // rectangle or we don't have a situation where one
8156 // is contained in the other.
8157
8158 if ( oldLeft < leftCol )
8159 {
8160 need_refresh[0] = TRUE;
8161 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
8162 oldLeft ),
8163 wxGridCellCoords ( oldBottom,
8164 leftCol - 1 ) );
8165 }
8166
8167 if ( oldTop < topRow )
8168 {
8169 need_refresh[1] = TRUE;
8170 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
8171 leftCol ),
8172 wxGridCellCoords ( topRow - 1,
8173 rightCol ) );
8174 }
8175
8176 if ( oldRight > rightCol )
8177 {
8178 need_refresh[2] = TRUE;
8179 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
8180 rightCol + 1 ),
8181 wxGridCellCoords ( oldBottom,
8182 oldRight ) );
8183 }
8184
8185 if ( oldBottom > bottomRow )
8186 {
8187 need_refresh[3] = TRUE;
8188 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
8189 leftCol ),
8190 wxGridCellCoords ( oldBottom,
8191 rightCol ) );
8192 }
8193
8194
8195 // Change Selection
8196 m_selectingTopLeft = updateTopLeft;
8197 m_selectingBottomRight = updateBottomRight;
8198
8199 // various Refresh() calls
8200 for (i = 0; i < 4; i++ )
8201 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
8202 m_gridWin->Refresh( FALSE, &(rect[i]) );
8203 }
8204
8205 // never generate an event as it will be generated from
8206 // wxGridSelection::SelectBlock!
8207 }
8208
8209 void wxGrid::SelectAll()
8210 {
8211 m_selection->SelectBlock( 0, 0, m_numRows-1, m_numCols-1 );
8212 }
8213
8214 bool wxGrid::IsSelection()
8215 {
8216 return ( m_selection->IsSelection() ||
8217 ( m_selectingTopLeft != wxGridNoCellCoords &&
8218 m_selectingBottomRight != wxGridNoCellCoords ) );
8219 }
8220
8221 bool wxGrid::IsInSelection( int row, int col )
8222 {
8223 return ( m_selection->IsInSelection( row, col ) ||
8224 ( row >= m_selectingTopLeft.GetRow() &&
8225 col >= m_selectingTopLeft.GetCol() &&
8226 row <= m_selectingBottomRight.GetRow() &&
8227 col <= m_selectingBottomRight.GetCol() ) );
8228 }
8229
8230 void wxGrid::ClearSelection()
8231 {
8232 m_selectingTopLeft = wxGridNoCellCoords;
8233 m_selectingBottomRight = wxGridNoCellCoords;
8234 m_selection->ClearSelection();
8235 }
8236
8237
8238 // This function returns the rectangle that encloses the given block
8239 // in device coords clipped to the client size of the grid window.
8240 //
8241 wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
8242 const wxGridCellCoords &bottomRight )
8243 {
8244 wxRect rect( wxGridNoCellRect );
8245 wxRect cellRect;
8246
8247 cellRect = CellToRect( topLeft );
8248 if ( cellRect != wxGridNoCellRect )
8249 {
8250 rect = cellRect;
8251 }
8252 else
8253 {
8254 rect = wxRect( 0, 0, 0, 0 );
8255 }
8256
8257 cellRect = CellToRect( bottomRight );
8258 if ( cellRect != wxGridNoCellRect )
8259 {
8260 rect += cellRect;
8261 }
8262 else
8263 {
8264 return wxGridNoCellRect;
8265 }
8266
8267 // convert to scrolled coords
8268 //
8269 int left, top, right, bottom;
8270 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
8271 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
8272
8273 int cw, ch;
8274 m_gridWin->GetClientSize( &cw, &ch );
8275
8276 if (right < 0 || bottom < 0 || left > cw || top > ch)
8277 return wxRect( 0, 0, 0, 0);
8278
8279 rect.SetLeft( wxMax(0, left) );
8280 rect.SetTop( wxMax(0, top) );
8281 rect.SetRight( wxMin(cw, right) );
8282 rect.SetBottom( wxMin(ch, bottom) );
8283
8284 return rect;
8285 }
8286
8287
8288
8289 //
8290 // ------ Grid event classes
8291 //
8292
8293 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
8294
8295 wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
8296 int row, int col, int x, int y, bool sel,
8297 bool control, bool shift, bool alt, bool meta )
8298 : wxNotifyEvent( type, id )
8299 {
8300 m_row = row;
8301 m_col = col;
8302 m_x = x;
8303 m_y = y;
8304 m_selecting = sel;
8305 m_control = control;
8306 m_shift = shift;
8307 m_alt = alt;
8308 m_meta = meta;
8309
8310 SetEventObject(obj);
8311 }
8312
8313
8314 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
8315
8316 wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
8317 int rowOrCol, int x, int y,
8318 bool control, bool shift, bool alt, bool meta )
8319 : wxNotifyEvent( type, id )
8320 {
8321 m_rowOrCol = rowOrCol;
8322 m_x = x;
8323 m_y = y;
8324 m_control = control;
8325 m_shift = shift;
8326 m_alt = alt;
8327 m_meta = meta;
8328
8329 SetEventObject(obj);
8330 }
8331
8332
8333 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
8334
8335 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
8336 const wxGridCellCoords& topLeft,
8337 const wxGridCellCoords& bottomRight,
8338 bool sel, bool control,
8339 bool shift, bool alt, bool meta )
8340 : wxNotifyEvent( type, id )
8341 {
8342 m_topLeft = topLeft;
8343 m_bottomRight = bottomRight;
8344 m_selecting = sel;
8345 m_control = control;
8346 m_shift = shift;
8347 m_alt = alt;
8348 m_meta = meta;
8349
8350 SetEventObject(obj);
8351 }
8352
8353
8354 #endif // ifndef wxUSE_NEW_GRID