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