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