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