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