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