]> git.saurik.com Git - wxWidgets.git/blob - src/generic/grid.cpp
signed/unsigned comparison warning fixed
[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 bool done = m_table->InsertRows( pos, numRows );
5773 m_numRows = m_table->GetNumberRows();
5774 return done;
5775
5776 // the table will have sent the results of the insert row
5777 // operation to this view object as a grid table message
5778 }
5779 return FALSE;
5780 }
5781
5782
5783 bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
5784 {
5785 // TODO: something with updateLabels flag
5786
5787 if ( !m_created )
5788 {
5789 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
5790 return FALSE;
5791 }
5792
5793 if ( m_table )
5794 {
5795 bool done = m_table && m_table->AppendRows( numRows );
5796 m_numRows = m_table->GetNumberRows();
5797 return done;
5798 // the table will have sent the results of the append row
5799 // operation to this view object as a grid table message
5800 }
5801 return FALSE;
5802 }
5803
5804
5805 bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
5806 {
5807 // TODO: something with updateLabels flag
5808
5809 if ( !m_created )
5810 {
5811 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
5812 return FALSE;
5813 }
5814
5815 if ( m_table )
5816 {
5817 if (IsCellEditControlEnabled())
5818 DisableCellEditControl();
5819
5820 bool done = m_table->DeleteRows( pos, numRows );
5821 m_numRows = m_table->GetNumberRows();
5822 return done;
5823 // the table will have sent the results of the delete row
5824 // operation to this view object as a grid table message
5825 }
5826 return FALSE;
5827 }
5828
5829
5830 bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
5831 {
5832 // TODO: something with updateLabels flag
5833
5834 if ( !m_created )
5835 {
5836 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
5837 return FALSE;
5838 }
5839
5840 if ( m_table )
5841 {
5842 if (IsCellEditControlEnabled())
5843 DisableCellEditControl();
5844
5845 bool done = m_table->InsertCols( pos, numCols );
5846 m_numCols = m_table->GetNumberCols();
5847 return done;
5848 // the table will have sent the results of the insert col
5849 // operation to this view object as a grid table message
5850 }
5851 return FALSE;
5852 }
5853
5854
5855 bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
5856 {
5857 // TODO: something with updateLabels flag
5858
5859 if ( !m_created )
5860 {
5861 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
5862 return FALSE;
5863 }
5864
5865 if ( m_table )
5866 {
5867 bool done = m_table->AppendCols( numCols );
5868 m_numCols = m_table->GetNumberCols();
5869 return done;
5870 // the table will have sent the results of the append col
5871 // operation to this view object as a grid table message
5872 }
5873 return FALSE;
5874 }
5875
5876
5877 bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
5878 {
5879 // TODO: something with updateLabels flag
5880
5881 if ( !m_created )
5882 {
5883 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
5884 return FALSE;
5885 }
5886
5887 if ( m_table )
5888 {
5889 if (IsCellEditControlEnabled())
5890 DisableCellEditControl();
5891
5892 bool done = m_table->DeleteCols( pos, numCols );
5893 m_numCols = m_table->GetNumberCols();
5894 return done;
5895 // the table will have sent the results of the delete col
5896 // operation to this view object as a grid table message
5897 }
5898 return FALSE;
5899 }
5900
5901
5902
5903 //
5904 // ----- event handlers
5905 //
5906
5907 // Generate a grid event based on a mouse event and
5908 // return the result of ProcessEvent()
5909 //
5910 int wxGrid::SendEvent( const wxEventType type,
5911 int row, int col,
5912 wxMouseEvent& mouseEv )
5913 {
5914 bool claimed;
5915 bool vetoed= FALSE;
5916
5917 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
5918 {
5919 int rowOrCol = (row == -1 ? col : row);
5920
5921 wxGridSizeEvent gridEvt( GetId(),
5922 type,
5923 this,
5924 rowOrCol,
5925 mouseEv.GetX() + GetRowLabelSize(),
5926 mouseEv.GetY() + GetColLabelSize(),
5927 mouseEv.ControlDown(),
5928 mouseEv.ShiftDown(),
5929 mouseEv.AltDown(),
5930 mouseEv.MetaDown() );
5931
5932 claimed = GetEventHandler()->ProcessEvent(gridEvt);
5933 vetoed = !gridEvt.IsAllowed();
5934 }
5935 else if ( type == wxEVT_GRID_RANGE_SELECT )
5936 {
5937 // Right now, it should _never_ end up here!
5938 wxGridRangeSelectEvent gridEvt( GetId(),
5939 type,
5940 this,
5941 m_selectingTopLeft,
5942 m_selectingBottomRight,
5943 TRUE,
5944 mouseEv.ControlDown(),
5945 mouseEv.ShiftDown(),
5946 mouseEv.AltDown(),
5947 mouseEv.MetaDown() );
5948
5949 claimed = GetEventHandler()->ProcessEvent(gridEvt);
5950 vetoed = !gridEvt.IsAllowed();
5951 }
5952 else
5953 {
5954 wxGridEvent gridEvt( GetId(),
5955 type,
5956 this,
5957 row, col,
5958 mouseEv.GetX() + GetRowLabelSize(),
5959 mouseEv.GetY() + GetColLabelSize(),
5960 FALSE,
5961 mouseEv.ControlDown(),
5962 mouseEv.ShiftDown(),
5963 mouseEv.AltDown(),
5964 mouseEv.MetaDown() );
5965 claimed = GetEventHandler()->ProcessEvent(gridEvt);
5966 vetoed = !gridEvt.IsAllowed();
5967 }
5968
5969 // A Veto'd event may not be `claimed' so test this first
5970 if (vetoed) return -1;
5971 return claimed ? 1 : 0;
5972 }
5973
5974
5975 // Generate a grid event of specified type and return the result
5976 // of ProcessEvent().
5977 //
5978 int wxGrid::SendEvent( const wxEventType type,
5979 int row, int col )
5980 {
5981 bool claimed;
5982 bool vetoed= FALSE;
5983
5984 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
5985 {
5986 int rowOrCol = (row == -1 ? col : row);
5987
5988 wxGridSizeEvent gridEvt( GetId(),
5989 type,
5990 this,
5991 rowOrCol );
5992
5993 claimed = GetEventHandler()->ProcessEvent(gridEvt);
5994 vetoed = !gridEvt.IsAllowed();
5995 }
5996 else
5997 {
5998 wxGridEvent gridEvt( GetId(),
5999 type,
6000 this,
6001 row, col );
6002
6003 claimed = GetEventHandler()->ProcessEvent(gridEvt);
6004 vetoed = !gridEvt.IsAllowed();
6005 }
6006
6007 // A Veto'd event may not be `claimed' so test this first
6008 if (vetoed) return -1;
6009 return claimed ? 1 : 0;
6010 }
6011
6012
6013 void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
6014 {
6015 wxPaintDC dc(this); // needed to prevent zillions of paint events on MSW
6016 }
6017
6018 void wxGrid::Refresh(bool eraseb, const wxRect* rect)
6019 {
6020 // Don't do anything if between Begin/EndBatch...
6021 // EndBatch() will do all this on the last nested one anyway.
6022 if (! GetBatchCount())
6023 {
6024 // Refresh to get correct scrolled position:
6025 wxScrolledWindow::Refresh(eraseb,rect);
6026
6027 if (rect)
6028 {
6029 int rect_x, rect_y, rectWidth, rectHeight;
6030 int width_label, width_cell, height_label, height_cell;
6031 int x, y;
6032
6033 //Copy rectangle can get scroll offsets..
6034 rect_x = rect->GetX();
6035 rect_y = rect->GetY();
6036 rectWidth = rect->GetWidth();
6037 rectHeight = rect->GetHeight();
6038
6039 width_label = m_rowLabelWidth - rect_x;
6040 if (width_label > rectWidth) width_label = rectWidth;
6041
6042 height_label = m_colLabelHeight - rect_y;
6043 if (height_label > rectHeight) height_label = rectHeight;
6044
6045 if (rect_x > m_rowLabelWidth)
6046 {
6047 x = rect_x - m_rowLabelWidth;
6048 width_cell = rectWidth;
6049 }
6050 else
6051 {
6052 x = 0;
6053 width_cell = rectWidth - (m_rowLabelWidth - rect_x);
6054 }
6055
6056 if (rect_y > m_colLabelHeight)
6057 {
6058 y = rect_y - m_colLabelHeight;
6059 height_cell = rectHeight;
6060 }
6061 else
6062 {
6063 y = 0;
6064 height_cell = rectHeight - (m_colLabelHeight - rect_y);
6065 }
6066
6067 // Paint corner label part intersecting rect.
6068 if ( width_label > 0 && height_label > 0 )
6069 {
6070 wxRect anotherrect(rect_x, rect_y, width_label, height_label);
6071 m_cornerLabelWin->Refresh(eraseb, &anotherrect);
6072 }
6073
6074 // Paint col labels part intersecting rect.
6075 if ( width_cell > 0 && height_label > 0 )
6076 {
6077 wxRect anotherrect(x, rect_y, width_cell, height_label);
6078 m_colLabelWin->Refresh(eraseb, &anotherrect);
6079 }
6080
6081 // Paint row labels part intersecting rect.
6082 if ( width_label > 0 && height_cell > 0 )
6083 {
6084 wxRect anotherrect(rect_x, y, width_label, height_cell);
6085 m_rowLabelWin->Refresh(eraseb, &anotherrect);
6086 }
6087
6088 // Paint cell area part intersecting rect.
6089 if ( width_cell > 0 && height_cell > 0 )
6090 {
6091 wxRect anotherrect(x, y, width_cell, height_cell);
6092 m_gridWin->Refresh(eraseb, &anotherrect);
6093 }
6094 }
6095 else
6096 {
6097 m_cornerLabelWin->Refresh(eraseb, NULL);
6098 m_colLabelWin->Refresh(eraseb, NULL);
6099 m_rowLabelWin->Refresh(eraseb, NULL);
6100 m_gridWin->Refresh(eraseb, NULL);
6101 }
6102 }
6103 }
6104
6105 void wxGrid::OnSize( wxSizeEvent& event )
6106 {
6107 // position the child windows
6108 CalcWindowSizes();
6109
6110 // don't call CalcDimensions() from here, the base class handles the size
6111 // changes itself
6112 event.Skip();
6113 }
6114
6115
6116 void wxGrid::OnKeyDown( wxKeyEvent& event )
6117 {
6118 if ( m_inOnKeyDown )
6119 {
6120 // shouldn't be here - we are going round in circles...
6121 //
6122 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") );
6123 }
6124
6125 m_inOnKeyDown = TRUE;
6126
6127 // propagate the event up and see if it gets processed
6128 //
6129 wxWindow *parent = GetParent();
6130 wxKeyEvent keyEvt( event );
6131 keyEvt.SetEventObject( parent );
6132
6133 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
6134 {
6135
6136 // try local handlers
6137 //
6138 switch ( event.GetKeyCode() )
6139 {
6140 case WXK_UP:
6141 if ( event.ControlDown() )
6142 {
6143 MoveCursorUpBlock( event.ShiftDown() );
6144 }
6145 else
6146 {
6147 MoveCursorUp( event.ShiftDown() );
6148 }
6149 break;
6150
6151 case WXK_DOWN:
6152 if ( event.ControlDown() )
6153 {
6154 MoveCursorDownBlock( event.ShiftDown() );
6155 }
6156 else
6157 {
6158 MoveCursorDown( event.ShiftDown() );
6159 }
6160 break;
6161
6162 case WXK_LEFT:
6163 if ( event.ControlDown() )
6164 {
6165 MoveCursorLeftBlock( event.ShiftDown() );
6166 }
6167 else
6168 {
6169 MoveCursorLeft( event.ShiftDown() );
6170 }
6171 break;
6172
6173 case WXK_RIGHT:
6174 if ( event.ControlDown() )
6175 {
6176 MoveCursorRightBlock( event.ShiftDown() );
6177 }
6178 else
6179 {
6180 MoveCursorRight( event.ShiftDown() );
6181 }
6182 break;
6183
6184 case WXK_RETURN:
6185 case WXK_NUMPAD_ENTER:
6186 if ( event.ControlDown() )
6187 {
6188 event.Skip(); // to let the edit control have the return
6189 }
6190 else
6191 {
6192 if ( GetGridCursorRow() < GetNumberRows()-1 )
6193 {
6194 MoveCursorDown( event.ShiftDown() );
6195 }
6196 else
6197 {
6198 // at the bottom of a column
6199 HideCellEditControl();
6200 SaveEditControlValue();
6201 }
6202 }
6203 break;
6204
6205 case WXK_ESCAPE:
6206 ClearSelection();
6207 break;
6208
6209 case WXK_TAB:
6210 if (event.ShiftDown())
6211 {
6212 if ( GetGridCursorCol() > 0 )
6213 {
6214 MoveCursorLeft( FALSE );
6215 }
6216 else
6217 {
6218 // at left of grid
6219 HideCellEditControl();
6220 SaveEditControlValue();
6221 }
6222 }
6223 else
6224 {
6225 if ( GetGridCursorCol() < GetNumberCols()-1 )
6226 {
6227 MoveCursorRight( FALSE );
6228 }
6229 else
6230 {
6231 // at right of grid
6232 HideCellEditControl();
6233 SaveEditControlValue();
6234 }
6235 }
6236 break;
6237
6238 case WXK_HOME:
6239 if ( event.ControlDown() )
6240 {
6241 MakeCellVisible( 0, 0 );
6242 SetCurrentCell( 0, 0 );
6243 }
6244 else
6245 {
6246 event.Skip();
6247 }
6248 break;
6249
6250 case WXK_END:
6251 if ( event.ControlDown() )
6252 {
6253 MakeCellVisible( m_numRows-1, m_numCols-1 );
6254 SetCurrentCell( m_numRows-1, m_numCols-1 );
6255 }
6256 else
6257 {
6258 event.Skip();
6259 }
6260 break;
6261
6262 case WXK_PRIOR:
6263 MovePageUp();
6264 break;
6265
6266 case WXK_NEXT:
6267 MovePageDown();
6268 break;
6269
6270 case WXK_SPACE:
6271 if ( event.ControlDown() )
6272 {
6273 if ( m_selection )
6274 {
6275 m_selection->ToggleCellSelection( m_currentCellCoords.GetRow(),
6276 m_currentCellCoords.GetCol(),
6277 event.ControlDown(),
6278 event.ShiftDown(),
6279 event.AltDown(),
6280 event.MetaDown() );
6281 }
6282 break;
6283 }
6284 if ( !IsEditable() )
6285 {
6286 MoveCursorRight( FALSE );
6287 break;
6288 }
6289 // Otherwise fall through to default
6290
6291 default:
6292 // is it possible to edit the current cell at all?
6293 if ( !IsCellEditControlEnabled() && CanEnableCellControl() )
6294 {
6295 // yes, now check whether the cells editor accepts the key
6296 int row = m_currentCellCoords.GetRow();
6297 int col = m_currentCellCoords.GetCol();
6298 wxGridCellAttr* attr = GetCellAttr(row, col);
6299 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
6300
6301 // <F2> is special and will always start editing, for
6302 // other keys - ask the editor itself
6303 if ( (event.GetKeyCode() == WXK_F2 && !event.HasModifiers())
6304 || editor->IsAcceptedKey(event) )
6305 {
6306 // ensure cell is visble
6307 MakeCellVisible(row, col);
6308 EnableCellEditControl();
6309
6310 // a problem can arise if the cell is not completely
6311 // visible (even after calling MakeCellVisible the
6312 // control is not created and calling StartingKey will
6313 // crash the app
6314 if( editor->IsCreated() && m_cellEditCtrlEnabled ) editor->StartingKey(event);
6315 }
6316 else
6317 {
6318 event.Skip();
6319 }
6320
6321 editor->DecRef();
6322 attr->DecRef();
6323 }
6324 else
6325 {
6326 // let others process char events with modifiers or all
6327 // char events for readonly cells
6328 event.Skip();
6329 }
6330 break;
6331 }
6332 }
6333
6334 m_inOnKeyDown = FALSE;
6335 }
6336
6337 void wxGrid::OnKeyUp( wxKeyEvent& event )
6338 {
6339 // try local handlers
6340 //
6341 if ( event.GetKeyCode() == WXK_SHIFT )
6342 {
6343 if ( m_selectingTopLeft != wxGridNoCellCoords &&
6344 m_selectingBottomRight != wxGridNoCellCoords )
6345 {
6346 if ( m_selection )
6347 {
6348 m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
6349 m_selectingTopLeft.GetCol(),
6350 m_selectingBottomRight.GetRow(),
6351 m_selectingBottomRight.GetCol(),
6352 event.ControlDown(),
6353 TRUE,
6354 event.AltDown(),
6355 event.MetaDown() );
6356 }
6357 }
6358
6359 m_selectingTopLeft = wxGridNoCellCoords;
6360 m_selectingBottomRight = wxGridNoCellCoords;
6361 m_selectingKeyboard = wxGridNoCellCoords;
6362 }
6363 }
6364
6365 void wxGrid::OnEraseBackground(wxEraseEvent&)
6366 {
6367 }
6368
6369 void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
6370 {
6371 if ( SendEvent( wxEVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
6372 {
6373 // the event has been intercepted - do nothing
6374 return;
6375 }
6376
6377 wxClientDC dc(m_gridWin);
6378 PrepareDC(dc);
6379
6380 if ( m_currentCellCoords != wxGridNoCellCoords )
6381 {
6382 HideCellEditControl();
6383 DisableCellEditControl();
6384
6385 if ( IsVisible( m_currentCellCoords, FALSE ) )
6386 {
6387 wxRect r;
6388 r = BlockToDeviceRect(m_currentCellCoords, m_currentCellCoords);
6389 if ( !m_gridLinesEnabled )
6390 {
6391 r.x--;
6392 r.y--;
6393 r.width++;
6394 r.height++;
6395 }
6396
6397 wxGridCellCoordsArray cells = CalcCellsExposed( r );
6398
6399 // Otherwise refresh redraws the highlight!
6400 m_currentCellCoords = coords;
6401
6402 DrawGridCellArea(dc,cells);
6403 DrawAllGridLines( dc, r );
6404 }
6405 }
6406
6407 m_currentCellCoords = coords;
6408
6409 wxGridCellAttr* attr = GetCellAttr(coords);
6410 DrawCellHighlight(dc, attr);
6411 attr->DecRef();
6412 }
6413
6414
6415 void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCol )
6416 {
6417 int temp;
6418 wxGridCellCoords updateTopLeft, updateBottomRight;
6419
6420 if ( m_selection )
6421 {
6422 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
6423 {
6424 leftCol = 0;
6425 rightCol = GetNumberCols() - 1;
6426 }
6427 else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
6428 {
6429 topRow = 0;
6430 bottomRow = GetNumberRows() - 1;
6431 }
6432 }
6433
6434 if ( topRow > bottomRow )
6435 {
6436 temp = topRow;
6437 topRow = bottomRow;
6438 bottomRow = temp;
6439 }
6440
6441 if ( leftCol > rightCol )
6442 {
6443 temp = leftCol;
6444 leftCol = rightCol;
6445 rightCol = temp;
6446 }
6447
6448 updateTopLeft = wxGridCellCoords( topRow, leftCol );
6449 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
6450
6451 // First the case that we selected a completely new area
6452 if ( m_selectingTopLeft == wxGridNoCellCoords ||
6453 m_selectingBottomRight == wxGridNoCellCoords )
6454 {
6455 wxRect rect;
6456 rect = BlockToDeviceRect( wxGridCellCoords ( topRow, leftCol ),
6457 wxGridCellCoords ( bottomRow, rightCol ) );
6458 m_gridWin->Refresh( FALSE, &rect );
6459 }
6460 // Now handle changing an existing selection area.
6461 else if ( m_selectingTopLeft != updateTopLeft ||
6462 m_selectingBottomRight != updateBottomRight )
6463 {
6464 // Compute two optimal update rectangles:
6465 // Either one rectangle is a real subset of the
6466 // other, or they are (almost) disjoint!
6467 wxRect rect[4];
6468 bool need_refresh[4];
6469 need_refresh[0] =
6470 need_refresh[1] =
6471 need_refresh[2] =
6472 need_refresh[3] = FALSE;
6473 int i;
6474
6475 // Store intermediate values
6476 wxCoord oldLeft = m_selectingTopLeft.GetCol();
6477 wxCoord oldTop = m_selectingTopLeft.GetRow();
6478 wxCoord oldRight = m_selectingBottomRight.GetCol();
6479 wxCoord oldBottom = m_selectingBottomRight.GetRow();
6480
6481 // Determine the outer/inner coordinates.
6482 if (oldLeft > leftCol)
6483 {
6484 temp = oldLeft;
6485 oldLeft = leftCol;
6486 leftCol = temp;
6487 }
6488 if (oldTop > topRow )
6489 {
6490 temp = oldTop;
6491 oldTop = topRow;
6492 topRow = temp;
6493 }
6494 if (oldRight < rightCol )
6495 {
6496 temp = oldRight;
6497 oldRight = rightCol;
6498 rightCol = temp;
6499 }
6500 if (oldBottom < bottomRow)
6501 {
6502 temp = oldBottom;
6503 oldBottom = bottomRow;
6504 bottomRow = temp;
6505 }
6506
6507 // Now, either the stuff marked old is the outer
6508 // rectangle or we don't have a situation where one
6509 // is contained in the other.
6510
6511 if ( oldLeft < leftCol )
6512 {
6513 // Refresh the newly selected or deselected
6514 // area to the left of the old or new selection.
6515 need_refresh[0] = TRUE;
6516 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
6517 oldLeft ),
6518 wxGridCellCoords ( oldBottom,
6519 leftCol - 1 ) );
6520 }
6521
6522 if ( oldTop < topRow )
6523 {
6524 // Refresh the newly selected or deselected
6525 // area above the old or new selection.
6526 need_refresh[1] = TRUE;
6527 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
6528 leftCol ),
6529 wxGridCellCoords ( topRow - 1,
6530 rightCol ) );
6531 }
6532
6533 if ( oldRight > rightCol )
6534 {
6535 // Refresh the newly selected or deselected
6536 // area to the right of the old or new selection.
6537 need_refresh[2] = TRUE;
6538 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
6539 rightCol + 1 ),
6540 wxGridCellCoords ( oldBottom,
6541 oldRight ) );
6542 }
6543
6544 if ( oldBottom > bottomRow )
6545 {
6546 // Refresh the newly selected or deselected
6547 // area below the old or new selection.
6548 need_refresh[3] = TRUE;
6549 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
6550 leftCol ),
6551 wxGridCellCoords ( oldBottom,
6552 rightCol ) );
6553 }
6554
6555 // various Refresh() calls
6556 for (i = 0; i < 4; i++ )
6557 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
6558 m_gridWin->Refresh( FALSE, &(rect[i]) );
6559 }
6560 // Change Selection
6561 m_selectingTopLeft = updateTopLeft;
6562 m_selectingBottomRight = updateBottomRight;
6563 }
6564
6565 //
6566 // ------ functions to get/send data (see also public functions)
6567 //
6568
6569 bool wxGrid::GetModelValues()
6570 {
6571 // Hide the editor, so it won't hide a changed value.
6572 HideCellEditControl();
6573
6574 if ( m_table )
6575 {
6576 // all we need to do is repaint the grid
6577 //
6578 m_gridWin->Refresh();
6579 return TRUE;
6580 }
6581
6582 return FALSE;
6583 }
6584
6585
6586 bool wxGrid::SetModelValues()
6587 {
6588 int row, col;
6589
6590 // Disable the editor, so it won't hide a changed value.
6591 // Do we also want to save the current value of the editor first?
6592 // I think so ...
6593 DisableCellEditControl();
6594
6595 if ( m_table )
6596 {
6597 for ( row = 0; row < m_numRows; row++ )
6598 {
6599 for ( col = 0; col < m_numCols; col++ )
6600 {
6601 m_table->SetValue( row, col, GetCellValue(row, col) );
6602 }
6603 }
6604
6605 return TRUE;
6606 }
6607
6608 return FALSE;
6609 }
6610
6611
6612
6613 // Note - this function only draws cells that are in the list of
6614 // exposed cells (usually set from the update region by
6615 // CalcExposedCells)
6616 //
6617 void wxGrid::DrawGridCellArea( wxDC& dc, const wxGridCellCoordsArray& cells )
6618 {
6619 if ( !m_numRows || !m_numCols ) return;
6620
6621 int i, numCells = cells.GetCount();
6622 int row, col, cell_rows, cell_cols;
6623 wxGridCellCoordsArray redrawCells;
6624
6625 for ( i = numCells-1; i >= 0; i-- )
6626 {
6627 row = cells[i].GetRow();
6628 col = cells[i].GetCol();
6629 GetCellSize( row, col, &cell_rows, &cell_cols );
6630
6631 // If this cell is part of a multicell block, find owner for repaint
6632 if ( cell_rows <= 0 || cell_cols <= 0 )
6633 {
6634 wxGridCellCoords cell(row+cell_rows, col+cell_cols);
6635 bool marked = FALSE;
6636 for ( int j = 0; j < numCells; j++ )
6637 {
6638 if ( cell == cells[j] )
6639 {
6640 marked = TRUE;
6641 break;
6642 }
6643 }
6644 if (!marked)
6645 {
6646 int count = redrawCells.GetCount();
6647 for (int j = 0; j < count; j++)
6648 {
6649 if ( cell == redrawCells[j] )
6650 {
6651 marked = TRUE;
6652 break;
6653 }
6654 }
6655 if (!marked) redrawCells.Add( cell );
6656 }
6657 continue; // don't bother drawing this cell
6658 }
6659
6660 // If this cell is empty, find cell to left that might want to overflow
6661 if (m_table && m_table->IsEmptyCell(row, col))
6662 {
6663 for ( int l = 0; l < cell_rows; l++ )
6664 {
6665 // find a cell in this row to left alreay marked for repaint
6666 int left = col;
6667 for (int k = 0; k < int(redrawCells.GetCount()); k++)
6668 if ((redrawCells[k].GetCol() < left) &&
6669 (redrawCells[k].GetRow() == row))
6670 left=redrawCells[k].GetCol();
6671
6672 if (left == col) left = 0; // oh well
6673
6674 for (int j = col-1; j >= left; j--)
6675 {
6676 if (!m_table->IsEmptyCell(row+l, j))
6677 {
6678 if (GetCellOverflow(row+l, j))
6679 {
6680 wxGridCellCoords cell(row+l, j);
6681 bool marked = FALSE;
6682
6683 for (int k = 0; k < numCells; k++)
6684 {
6685 if ( cell == cells[k] )
6686 {
6687 marked = TRUE;
6688 break;
6689 }
6690 }
6691 if (!marked)
6692 {
6693 int count = redrawCells.GetCount();
6694 for (int k = 0; k < count; k++)
6695 {
6696 if ( cell == redrawCells[k] )
6697 {
6698 marked = TRUE;
6699 break;
6700 }
6701 }
6702 if (!marked) redrawCells.Add( cell );
6703 }
6704 }
6705 break;
6706 }
6707 }
6708 }
6709 }
6710 DrawCell( dc, cells[i] );
6711 }
6712
6713 numCells = redrawCells.GetCount();
6714
6715 for ( i = numCells - 1; i >= 0; i-- )
6716 {
6717 DrawCell( dc, redrawCells[i] );
6718 }
6719 }
6720
6721
6722 void wxGrid::DrawGridSpace( wxDC& dc )
6723 {
6724 int cw, ch;
6725 m_gridWin->GetClientSize( &cw, &ch );
6726
6727 int right, bottom;
6728 CalcUnscrolledPosition( cw, ch, &right, &bottom );
6729
6730 int rightCol = m_numCols > 0 ? GetColRight(m_numCols - 1) : 0;
6731 int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0 ;
6732
6733 if ( right > rightCol || bottom > bottomRow )
6734 {
6735 int left, top;
6736 CalcUnscrolledPosition( 0, 0, &left, &top );
6737
6738 dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) );
6739 dc.SetPen( *wxTRANSPARENT_PEN );
6740
6741 if ( right > rightCol )
6742 {
6743 dc.DrawRectangle( rightCol, top, right - rightCol, ch);
6744 }
6745
6746 if ( bottom > bottomRow )
6747 {
6748 dc.DrawRectangle( left, bottomRow, cw, bottom - bottomRow);
6749 }
6750 }
6751 }
6752
6753
6754 void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
6755 {
6756 int row = coords.GetRow();
6757 int col = coords.GetCol();
6758
6759 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
6760 return;
6761
6762 // we draw the cell border ourselves
6763 #if !WXGRID_DRAW_LINES
6764 if ( m_gridLinesEnabled )
6765 DrawCellBorder( dc, coords );
6766 #endif
6767
6768 wxGridCellAttr* attr = GetCellAttr(row, col);
6769
6770 bool isCurrent = coords == m_currentCellCoords;
6771
6772 wxRect rect = CellToRect( row, col );
6773
6774 // if the editor is shown, we should use it and not the renderer
6775 // Note: However, only if it is really _shown_, i.e. not hidden!
6776 if ( isCurrent && IsCellEditControlShown() )
6777 {
6778 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
6779 editor->PaintBackground(rect, attr);
6780 editor->DecRef();
6781 }
6782 else
6783 {
6784 // but all the rest is drawn by the cell renderer and hence may be
6785 // customized
6786 wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col);
6787 renderer->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
6788 renderer->DecRef();
6789 }
6790
6791 attr->DecRef();
6792 }
6793
6794 void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr )
6795 {
6796 int row = m_currentCellCoords.GetRow();
6797 int col = m_currentCellCoords.GetCol();
6798
6799 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
6800 return;
6801
6802 wxRect rect = CellToRect(row, col);
6803
6804 // hmmm... what could we do here to show that the cell is disabled?
6805 // for now, I just draw a thinner border than for the other ones, but
6806 // it doesn't look really good
6807
6808 int penWidth = attr->IsReadOnly() ? m_cellHighlightROPenWidth : m_cellHighlightPenWidth;
6809
6810 if (penWidth > 0)
6811 {
6812 // The center of th drawn line is where the position/width/height of
6813 // the rectangle is actually at, (on wxMSW atr least,) so we will
6814 // reduce the size of the rectangle to compensate for the thickness of
6815 // the line. If this is too strange on non wxMSW platforms then
6816 // please #ifdef this appropriately.
6817 rect.x += penWidth/2;
6818 rect.y += penWidth/2;
6819 rect.width -= penWidth-1;
6820 rect.height -= penWidth-1;
6821
6822
6823 // Now draw the rectangle
6824 // use the cellHighlightColour if the cell is inside a selection, this
6825 // will ensure the cell is always visible.
6826 dc.SetPen(wxPen(IsInSelection(row,col)?m_selectionForeground:m_cellHighlightColour, penWidth, wxSOLID));
6827 dc.SetBrush(*wxTRANSPARENT_BRUSH);
6828 dc.DrawRectangle(rect);
6829 }
6830
6831 #if 0
6832 // VZ: my experiments with 3d borders...
6833
6834 // how to properly set colours for arbitrary bg?
6835 wxCoord x1 = rect.x,
6836 y1 = rect.y,
6837 x2 = rect.x + rect.width -1,
6838 y2 = rect.y + rect.height -1;
6839
6840 dc.SetPen(*wxWHITE_PEN);
6841 dc.DrawLine(x1, y1, x2, y1);
6842 dc.DrawLine(x1, y1, x1, y2);
6843
6844 dc.DrawLine(x1 + 1, y2 - 1, x2 - 1, y2 - 1);
6845 dc.DrawLine(x2 - 1, y1 + 1, x2 - 1, y2 );
6846
6847 dc.SetPen(*wxBLACK_PEN);
6848 dc.DrawLine(x1, y2, x2, y2);
6849 dc.DrawLine(x2, y1, x2, y2+1);
6850 #endif // 0
6851 }
6852
6853
6854 void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
6855 {
6856 int row = coords.GetRow();
6857 int col = coords.GetCol();
6858 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
6859 return;
6860
6861 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
6862
6863 wxRect rect = CellToRect( row, col );
6864
6865 // right hand border
6866 //
6867 dc.DrawLine( rect.x + rect.width, rect.y,
6868 rect.x + rect.width, rect.y + rect.height + 1 );
6869
6870 // bottom border
6871 //
6872 dc.DrawLine( rect.x, rect.y + rect.height,
6873 rect.x + rect.width, rect.y + rect.height);
6874 }
6875
6876 void wxGrid::DrawHighlight(wxDC& dc,const wxGridCellCoordsArray& cells)
6877 {
6878 // This if block was previously in wxGrid::OnPaint but that doesn't
6879 // seem to get called under wxGTK - MB
6880 //
6881 if ( m_currentCellCoords == wxGridNoCellCoords &&
6882 m_numRows && m_numCols )
6883 {
6884 m_currentCellCoords.Set(0, 0);
6885 }
6886
6887 if ( IsCellEditControlShown() )
6888 {
6889 // don't show highlight when the edit control is shown
6890 return;
6891 }
6892
6893 // if the active cell was repainted, repaint its highlight too because it
6894 // might have been damaged by the grid lines
6895 size_t count = cells.GetCount();
6896 for ( size_t n = 0; n < count; n++ )
6897 {
6898 if ( cells[n] == m_currentCellCoords )
6899 {
6900 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
6901 DrawCellHighlight(dc, attr);
6902 attr->DecRef();
6903
6904 break;
6905 }
6906 }
6907 }
6908
6909 // TODO: remove this ???
6910 // This is used to redraw all grid lines e.g. when the grid line colour
6911 // has been changed
6912 //
6913 void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) )
6914 {
6915 #if !WXGRID_DRAW_LINES
6916 return;
6917 #endif
6918
6919 if ( !m_gridLinesEnabled ||
6920 !m_numRows ||
6921 !m_numCols ) return;
6922
6923 int top, bottom, left, right;
6924
6925 #if 0 //#ifndef __WXGTK__
6926 if (reg.IsEmpty())
6927 {
6928 int cw, ch;
6929 m_gridWin->GetClientSize(&cw, &ch);
6930
6931 // virtual coords of visible area
6932 //
6933 CalcUnscrolledPosition( 0, 0, &left, &top );
6934 CalcUnscrolledPosition( cw, ch, &right, &bottom );
6935 }
6936 else
6937 {
6938 wxCoord x, y, w, h;
6939 reg.GetBox(x, y, w, h);
6940 CalcUnscrolledPosition( x, y, &left, &top );
6941 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
6942 }
6943 #else
6944 int cw, ch;
6945 m_gridWin->GetClientSize(&cw, &ch);
6946 CalcUnscrolledPosition( 0, 0, &left, &top );
6947 CalcUnscrolledPosition( cw, ch, &right, &bottom );
6948 #endif
6949
6950 // avoid drawing grid lines past the last row and col
6951 //
6952 right = wxMin( right, GetColRight(m_numCols - 1) );
6953 bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) );
6954
6955 // no gridlines inside multicells, clip them out
6956 int leftCol = internalXToCol(left);
6957 int topRow = internalYToRow(top);
6958 int rightCol = internalXToCol(right);
6959 int bottomRow = internalYToRow(bottom);
6960 wxRegion clippedcells(0, 0, cw, ch);
6961
6962
6963 int i, j, cell_rows, cell_cols;
6964 wxRect rect;
6965
6966 for (j=topRow; j<bottomRow; j++)
6967 {
6968 for (i=leftCol; i<rightCol; i++)
6969 {
6970 GetCellSize( j, i, &cell_rows, &cell_cols );
6971 if ((cell_rows > 1) || (cell_cols > 1))
6972 {
6973 rect = CellToRect(j,i);
6974 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
6975 clippedcells.Subtract(rect);
6976 }
6977 else if ((cell_rows < 0) || (cell_cols < 0))
6978 {
6979 rect = CellToRect(j+cell_rows, i+cell_cols);
6980 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
6981 clippedcells.Subtract(rect);
6982 }
6983 }
6984 }
6985 dc.SetClippingRegion( clippedcells );
6986
6987 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
6988
6989 // horizontal grid lines
6990 //
6991 // already declared above - int i;
6992 for ( i = internalYToRow(top); i < m_numRows; i++ )
6993 {
6994 int bot = GetRowBottom(i) - 1;
6995
6996 if ( bot > bottom )
6997 {
6998 break;
6999 }
7000
7001 if ( bot >= top )
7002 {
7003 dc.DrawLine( left, bot, right, bot );
7004 }
7005 }
7006
7007
7008 // vertical grid lines
7009 //
7010 for ( i = internalXToCol(left); i < m_numCols; i++ )
7011 {
7012 int colRight = GetColRight(i) - 1;
7013 if ( colRight > right )
7014 {
7015 break;
7016 }
7017
7018 if ( colRight >= left )
7019 {
7020 dc.DrawLine( colRight, top, colRight, bottom );
7021 }
7022 }
7023 dc.DestroyClippingRegion();
7024 }
7025
7026
7027 void wxGrid::DrawRowLabels( wxDC& dc ,const wxArrayInt& rows)
7028 {
7029 if ( !m_numRows ) return;
7030
7031 size_t i;
7032 size_t numLabels = rows.GetCount();
7033
7034 for ( i = 0; i < numLabels; i++ )
7035 {
7036 DrawRowLabel( dc, rows[i] );
7037 }
7038 }
7039
7040
7041 void wxGrid::DrawRowLabel( wxDC& dc, int row )
7042 {
7043 if ( GetRowHeight(row) <= 0 )
7044 return;
7045
7046 int rowTop = GetRowTop(row),
7047 rowBottom = GetRowBottom(row) - 1;
7048
7049 dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW),1, wxSOLID) );
7050 dc.DrawLine( m_rowLabelWidth-1, rowTop,
7051 m_rowLabelWidth-1, rowBottom );
7052
7053 dc.DrawLine( 0, rowTop, 0, rowBottom );
7054
7055 dc.DrawLine( 0, rowBottom, m_rowLabelWidth, rowBottom );
7056
7057 dc.SetPen( *wxWHITE_PEN );
7058 dc.DrawLine( 1, rowTop, 1, rowBottom );
7059 dc.DrawLine( 1, rowTop, m_rowLabelWidth-1, rowTop );
7060
7061 dc.SetBackgroundMode( wxTRANSPARENT );
7062 dc.SetTextForeground( GetLabelTextColour() );
7063 dc.SetFont( GetLabelFont() );
7064
7065 int hAlign, vAlign;
7066 GetRowLabelAlignment( &hAlign, &vAlign );
7067
7068 wxRect rect;
7069 rect.SetX( 2 );
7070 rect.SetY( GetRowTop(row) + 2 );
7071 rect.SetWidth( m_rowLabelWidth - 4 );
7072 rect.SetHeight( GetRowHeight(row) - 4 );
7073 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
7074 }
7075
7076
7077 void wxGrid::DrawColLabels( wxDC& dc,const wxArrayInt& cols )
7078 {
7079 if ( !m_numCols ) return;
7080
7081 size_t i;
7082 size_t numLabels = cols.GetCount();
7083
7084 for ( i = 0; i < numLabels; i++ )
7085 {
7086 DrawColLabel( dc, cols[i] );
7087 }
7088 }
7089
7090
7091 void wxGrid::DrawColLabel( wxDC& dc, int col )
7092 {
7093 if ( GetColWidth(col) <= 0 )
7094 return;
7095
7096 int colLeft = GetColLeft(col),
7097 colRight = GetColRight(col) - 1;
7098
7099 dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW),1, wxSOLID) );
7100 dc.DrawLine( colRight, 0,
7101 colRight, m_colLabelHeight-1 );
7102
7103 dc.DrawLine( colLeft, 0, colRight, 0 );
7104
7105 dc.DrawLine( colLeft, m_colLabelHeight-1,
7106 colRight+1, m_colLabelHeight-1 );
7107
7108 dc.SetPen( *wxWHITE_PEN );
7109 dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight-1 );
7110 dc.DrawLine( colLeft, 1, colRight, 1 );
7111
7112 dc.SetBackgroundMode( wxTRANSPARENT );
7113 dc.SetTextForeground( GetLabelTextColour() );
7114 dc.SetFont( GetLabelFont() );
7115
7116 int hAlign, vAlign, orient;
7117 GetColLabelAlignment( &hAlign, &vAlign );
7118 orient = GetColLabelTextOrientation();
7119
7120 wxRect rect;
7121 rect.SetX( colLeft + 2 );
7122 rect.SetY( 2 );
7123 rect.SetWidth( GetColWidth(col) - 4 );
7124 rect.SetHeight( m_colLabelHeight - 4 );
7125 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign, orient );
7126 }
7127
7128 void wxGrid::DrawTextRectangle( wxDC& dc,
7129 const wxString& value,
7130 const wxRect& rect,
7131 int horizAlign,
7132 int vertAlign,
7133 int textOrientation )
7134 {
7135 wxArrayString lines;
7136
7137 StringToLines( value, lines );
7138
7139
7140 //Forward to new API.
7141 DrawTextRectangle( dc,
7142 lines,
7143 rect,
7144 horizAlign,
7145 vertAlign,
7146 textOrientation );
7147
7148 }
7149
7150 void wxGrid::DrawTextRectangle( wxDC& dc,
7151 const wxArrayString& lines,
7152 const wxRect& rect,
7153 int horizAlign,
7154 int vertAlign,
7155 int textOrientation )
7156 {
7157 long textWidth, textHeight;
7158 long lineWidth, lineHeight;
7159 int nLines;
7160
7161 dc.SetClippingRegion( rect );
7162
7163 nLines = lines.GetCount();
7164 if( nLines > 0 )
7165 {
7166 int l;
7167 float x = 0.0, y = 0.0;
7168
7169 if( textOrientation == wxHORIZONTAL )
7170 GetTextBoxSize(dc, lines, &textWidth, &textHeight);
7171 else
7172 GetTextBoxSize( dc, lines, &textHeight, &textWidth );
7173
7174 switch( vertAlign )
7175 {
7176 case wxALIGN_BOTTOM:
7177 if( textOrientation == wxHORIZONTAL )
7178 y = rect.y + (rect.height - textHeight - 1);
7179 else
7180 x = rect.x + rect.width - textWidth;
7181 break;
7182
7183 case wxALIGN_CENTRE:
7184 if( textOrientation == wxHORIZONTAL )
7185 y = rect.y + ((rect.height - textHeight)/2);
7186 else
7187 x = rect.x + ((rect.width - textWidth)/2);
7188 break;
7189
7190 case wxALIGN_TOP:
7191 default:
7192 if( textOrientation == wxHORIZONTAL )
7193 y = rect.y + 1;
7194 else
7195 x = rect.x + 1;
7196 break;
7197 }
7198
7199 // Align each line of a multi-line label
7200 for( l = 0; l < nLines; l++ )
7201 {
7202 dc.GetTextExtent(lines[l], &lineWidth, &lineHeight);
7203
7204 switch( horizAlign )
7205 {
7206 case wxALIGN_RIGHT:
7207 if( textOrientation == wxHORIZONTAL )
7208 x = rect.x + (rect.width - lineWidth - 1);
7209 else
7210 y = rect.y + lineWidth + 1;
7211 break;
7212
7213 case wxALIGN_CENTRE:
7214 if( textOrientation == wxHORIZONTAL )
7215 x = rect.x + ((rect.width - lineWidth)/2);
7216 else
7217 y = rect.y + rect.height - ((rect.height - lineWidth)/2);
7218 break;
7219
7220 case wxALIGN_LEFT:
7221 default:
7222 if( textOrientation == wxHORIZONTAL )
7223 x = rect.x + 1;
7224 else
7225 y = rect.y + rect.height - 1;
7226 break;
7227 }
7228
7229 if( textOrientation == wxHORIZONTAL )
7230 {
7231 dc.DrawText( lines[l], (int)x, (int)y );
7232 y += lineHeight;
7233 }
7234 else
7235 {
7236 dc.DrawRotatedText( lines[l], (int)x, (int)y, 90.0 );
7237 x += lineHeight;
7238 }
7239 }
7240 }
7241 dc.DestroyClippingRegion();
7242 }
7243
7244
7245 // Split multi line text up into an array of strings. Any existing
7246 // contents of the string array are preserved.
7247 //
7248 void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
7249 {
7250 int startPos = 0;
7251 int pos;
7252 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
7253 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
7254
7255 while ( startPos < (int)tVal.Length() )
7256 {
7257 pos = tVal.Mid(startPos).Find( eol );
7258 if ( pos < 0 )
7259 {
7260 break;
7261 }
7262 else if ( pos == 0 )
7263 {
7264 lines.Add( wxEmptyString );
7265 }
7266 else
7267 {
7268 lines.Add( value.Mid(startPos, pos) );
7269 }
7270 startPos += pos+1;
7271 }
7272 if ( startPos < (int)value.Length() )
7273 {
7274 lines.Add( value.Mid( startPos ) );
7275 }
7276 }
7277
7278
7279 void wxGrid::GetTextBoxSize( wxDC& dc,
7280 const wxArrayString& lines,
7281 long *width, long *height )
7282 {
7283 long w = 0;
7284 long h = 0;
7285 long lineW, lineH;
7286
7287 size_t i;
7288 for ( i = 0; i < lines.GetCount(); i++ )
7289 {
7290 dc.GetTextExtent( lines[i], &lineW, &lineH );
7291 w = wxMax( w, lineW );
7292 h += lineH;
7293 }
7294
7295 *width = w;
7296 *height = h;
7297 }
7298
7299 //
7300 // ------ Batch processing.
7301 //
7302 void wxGrid::EndBatch()
7303 {
7304 if ( m_batchCount > 0 )
7305 {
7306 m_batchCount--;
7307 if ( !m_batchCount )
7308 {
7309 CalcDimensions();
7310 m_rowLabelWin->Refresh();
7311 m_colLabelWin->Refresh();
7312 m_cornerLabelWin->Refresh();
7313 m_gridWin->Refresh();
7314 }
7315 }
7316 }
7317
7318 // Use this, rather than wxWindow::Refresh(), to force an immediate
7319 // repainting of the grid. Has no effect if you are already inside a
7320 // BeginBatch / EndBatch block.
7321 //
7322 void wxGrid::ForceRefresh()
7323 {
7324 BeginBatch();
7325 EndBatch();
7326 }
7327
7328
7329 //
7330 // ------ Edit control functions
7331 //
7332
7333
7334 void wxGrid::EnableEditing( bool edit )
7335 {
7336 // TODO: improve this ?
7337 //
7338 if ( edit != m_editable )
7339 {
7340 if(!edit) EnableCellEditControl(edit);
7341 m_editable = edit;
7342 }
7343 }
7344
7345
7346 void wxGrid::EnableCellEditControl( bool enable )
7347 {
7348 if (! m_editable)
7349 return;
7350
7351 if ( m_currentCellCoords == wxGridNoCellCoords )
7352 SetCurrentCell( 0, 0 );
7353
7354 if ( enable != m_cellEditCtrlEnabled )
7355 {
7356 if ( enable )
7357 {
7358 if (SendEvent( wxEVT_GRID_EDITOR_SHOWN) <0)
7359 return;
7360
7361 // this should be checked by the caller!
7362 wxASSERT_MSG( CanEnableCellControl(),
7363 _T("can't enable editing for this cell!") );
7364
7365 // do it before ShowCellEditControl()
7366 m_cellEditCtrlEnabled = enable;
7367
7368 ShowCellEditControl();
7369 }
7370 else
7371 {
7372 //FIXME:add veto support
7373 SendEvent( wxEVT_GRID_EDITOR_HIDDEN);
7374
7375 HideCellEditControl();
7376 SaveEditControlValue();
7377
7378 // do it after HideCellEditControl()
7379 m_cellEditCtrlEnabled = enable;
7380 }
7381 }
7382 }
7383
7384 bool wxGrid::IsCurrentCellReadOnly() const
7385 {
7386 // const_cast
7387 wxGridCellAttr* attr = ((wxGrid *)this)->GetCellAttr(m_currentCellCoords);
7388 bool readonly = attr->IsReadOnly();
7389 attr->DecRef();
7390
7391 return readonly;
7392 }
7393
7394 bool wxGrid::CanEnableCellControl() const
7395 {
7396 return m_editable && !IsCurrentCellReadOnly();
7397 }
7398
7399 bool wxGrid::IsCellEditControlEnabled() const
7400 {
7401 // the cell edit control might be disable for all cells or just for the
7402 // current one if it's read only
7403 return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : FALSE;
7404 }
7405
7406 bool wxGrid::IsCellEditControlShown() const
7407 {
7408 bool isShown = FALSE;
7409
7410 if ( m_cellEditCtrlEnabled )
7411 {
7412 int row = m_currentCellCoords.GetRow();
7413 int col = m_currentCellCoords.GetCol();
7414 wxGridCellAttr* attr = GetCellAttr(row, col);
7415 wxGridCellEditor* editor = attr->GetEditor((wxGrid*) this, row, col);
7416 attr->DecRef();
7417
7418 if ( editor )
7419 {
7420 if ( editor->IsCreated() )
7421 {
7422 isShown = editor->GetControl()->IsShown();
7423 }
7424
7425 editor->DecRef();
7426 }
7427 }
7428
7429 return isShown;
7430 }
7431
7432 void wxGrid::ShowCellEditControl()
7433 {
7434 if ( IsCellEditControlEnabled() )
7435 {
7436 if ( !IsVisible( m_currentCellCoords ) )
7437 {
7438 m_cellEditCtrlEnabled = FALSE;
7439 return;
7440 }
7441 else
7442 {
7443 wxRect rect = CellToRect( m_currentCellCoords );
7444 int row = m_currentCellCoords.GetRow();
7445 int col = m_currentCellCoords.GetCol();
7446
7447 // if this is part of a multicell, find owner (topleft)
7448 int cell_rows, cell_cols;
7449 GetCellSize( row, col, &cell_rows, &cell_cols );
7450 if ( cell_rows <= 0 || cell_cols <= 0 )
7451 {
7452 row += cell_rows;
7453 col += cell_cols;
7454 m_currentCellCoords.SetRow( row );
7455 m_currentCellCoords.SetCol( col );
7456 }
7457
7458 // convert to scrolled coords
7459 //
7460 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
7461
7462 // done in PaintBackground()
7463 #if 0
7464 // erase the highlight and the cell contents because the editor
7465 // might not cover the entire cell
7466 wxClientDC dc( m_gridWin );
7467 PrepareDC( dc );
7468 dc.SetBrush(*wxLIGHT_GREY_BRUSH); //wxBrush(attr->GetBackgroundColour(), wxSOLID));
7469 dc.SetPen(*wxTRANSPARENT_PEN);
7470 dc.DrawRectangle(rect);
7471 #endif // 0
7472
7473 // cell is shifted by one pixel
7474 // However, don't allow x or y to become negative
7475 // since the SetSize() method interprets that as
7476 // "don't change."
7477 if (rect.x > 0)
7478 rect.x--;
7479 if (rect.y > 0)
7480 rect.y--;
7481
7482 wxGridCellAttr* attr = GetCellAttr(row, col);
7483 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
7484 if ( !editor->IsCreated() )
7485 {
7486 editor->Create(m_gridWin, -1,
7487 new wxGridCellEditorEvtHandler(this, editor));
7488
7489 wxGridEditorCreatedEvent evt(GetId(),
7490 wxEVT_GRID_EDITOR_CREATED,
7491 this,
7492 row,
7493 col,
7494 editor->GetControl());
7495 GetEventHandler()->ProcessEvent(evt);
7496 }
7497
7498
7499 // resize editor to overflow into righthand cells if allowed
7500 int maxWidth = rect.width;
7501 wxString value = GetCellValue(row, col);
7502 if ( (value != wxEmptyString) && (attr->GetOverflow()) )
7503 {
7504 int y;
7505 GetTextExtent(value, &maxWidth, &y,
7506 NULL, NULL, &attr->GetFont());
7507 if (maxWidth < rect.width) maxWidth = rect.width;
7508 }
7509 int client_right = m_gridWin->GetClientSize().GetWidth();
7510 if (rect.x+maxWidth > client_right)
7511 maxWidth = client_right - rect.x;
7512
7513 if ((maxWidth > rect.width) && (col < m_numCols) && m_table)
7514 {
7515 GetCellSize( row, col, &cell_rows, &cell_cols );
7516 // may have changed earlier
7517 for (int i = col+cell_cols; i < m_numCols; i++)
7518 {
7519 int c_rows, c_cols;
7520 GetCellSize( row, i, &c_rows, &c_cols );
7521 // looks weird going over a multicell
7522 if (m_table->IsEmptyCell(row,i) &&
7523 (rect.width < maxWidth) && (c_rows == 1))
7524 rect.width += GetColWidth(i);
7525 else
7526 break;
7527 }
7528 if (rect.GetRight() > client_right)
7529 rect.SetRight(client_right-1);
7530 }
7531
7532 editor->SetCellAttr(attr);
7533 editor->SetSize( rect );
7534 editor->Show( TRUE, attr );
7535
7536 // recalc dimensions in case we need to
7537 // expand the scrolled window to account for editor
7538 CalcDimensions();
7539
7540 editor->BeginEdit(row, col, this);
7541 editor->SetCellAttr(NULL);
7542
7543 editor->DecRef();
7544 attr->DecRef();
7545 }
7546 }
7547 }
7548
7549
7550 void wxGrid::HideCellEditControl()
7551 {
7552 if ( IsCellEditControlEnabled() )
7553 {
7554 int row = m_currentCellCoords.GetRow();
7555 int col = m_currentCellCoords.GetCol();
7556
7557 wxGridCellAttr* attr = GetCellAttr(row, col);
7558 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
7559 editor->Show( FALSE );
7560 editor->DecRef();
7561 attr->DecRef();
7562 m_gridWin->SetFocus();
7563 // refresh whole row to the right
7564 wxRect rect( CellToRect(row, col) );
7565 CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y );
7566 rect.width = m_gridWin->GetClientSize().GetWidth() - rect.x;
7567 m_gridWin->Refresh( FALSE, &rect );
7568 }
7569 }
7570
7571
7572 void wxGrid::SaveEditControlValue()
7573 {
7574 if ( IsCellEditControlEnabled() )
7575 {
7576 int row = m_currentCellCoords.GetRow();
7577 int col = m_currentCellCoords.GetCol();
7578
7579 wxString oldval = GetCellValue(row,col);
7580
7581 wxGridCellAttr* attr = GetCellAttr(row, col);
7582 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
7583 bool changed = editor->EndEdit(row, col, this);
7584
7585 editor->DecRef();
7586 attr->DecRef();
7587
7588 if (changed)
7589 {
7590 if ( SendEvent( wxEVT_GRID_CELL_CHANGE,
7591 m_currentCellCoords.GetRow(),
7592 m_currentCellCoords.GetCol() ) < 0 ) {
7593
7594 // Event has been vetoed, set the data back.
7595 SetCellValue(row,col,oldval);
7596 }
7597 }
7598 }
7599 }
7600
7601
7602 //
7603 // ------ Grid location functions
7604 // Note that all of these functions work with the logical coordinates of
7605 // grid cells and labels so you will need to convert from device
7606 // coordinates for mouse events etc.
7607 //
7608
7609 void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
7610 {
7611 int row = YToRow(y);
7612 int col = XToCol(x);
7613
7614 if ( row == -1 || col == -1 )
7615 {
7616 coords = wxGridNoCellCoords;
7617 }
7618 else
7619 {
7620 coords.Set( row, col );
7621 }
7622 }
7623
7624
7625 // Internal Helper function for computing row or column from some
7626 // (unscrolled) coordinate value, using either
7627 // m_defaultRowHeight/m_defaultColWidth or binary search on array
7628 // of m_rowBottoms/m_ColRights to speed up the search!
7629
7630 static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
7631 const wxArrayInt& BorderArray, int nMax,
7632 bool clipToMinMax)
7633 {
7634
7635 if (coord < 0)
7636 return clipToMinMax && (nMax > 0) ? 0 : -1;
7637
7638
7639 if (!defaultDist)
7640 defaultDist = 1;
7641
7642 size_t i_max = coord / defaultDist,
7643 i_min = 0;
7644
7645 if (BorderArray.IsEmpty())
7646 {
7647 if((int) i_max < nMax)
7648 return i_max;
7649 return clipToMinMax ? nMax - 1 : -1;
7650 }
7651
7652 if ( i_max >= BorderArray.GetCount())
7653 i_max = BorderArray.GetCount() - 1;
7654 else
7655 {
7656 if ( coord >= BorderArray[i_max])
7657 {
7658 i_min = i_max;
7659 i_max = coord / minDist;
7660 }
7661 if ( i_max >= BorderArray.GetCount())
7662 i_max = BorderArray.GetCount() - 1;
7663 }
7664 if ( coord >= BorderArray[i_max])
7665 return clipToMinMax ? (int)i_max : -1;
7666 if ( coord < BorderArray[0] )
7667 return 0;
7668
7669 while ( i_max - i_min > 0 )
7670 {
7671 wxCHECK_MSG(BorderArray[i_min] <= coord && coord < BorderArray[i_max],
7672 0, _T("wxGrid: internal error in CoordToRowOrCol"));
7673 if (coord >= BorderArray[ i_max - 1])
7674 return i_max;
7675 else
7676 i_max--;
7677 int median = i_min + (i_max - i_min + 1) / 2;
7678 if (coord < BorderArray[median])
7679 i_max = median;
7680 else
7681 i_min = median;
7682 }
7683 return i_max;
7684 }
7685
7686 int wxGrid::YToRow( int y )
7687 {
7688 return CoordToRowOrCol(y, m_defaultRowHeight,
7689 m_minAcceptableRowHeight, m_rowBottoms, m_numRows, FALSE);
7690 }
7691
7692
7693 int wxGrid::XToCol( int x )
7694 {
7695 return CoordToRowOrCol(x, m_defaultColWidth,
7696 m_minAcceptableColWidth, m_colRights, m_numCols, FALSE);
7697 }
7698
7699
7700 // return the row number that that the y coord is near the edge of, or
7701 // -1 if not near an edge
7702 //
7703 int wxGrid::YToEdgeOfRow( int y )
7704 {
7705 int i;
7706 i = internalYToRow(y);
7707
7708 if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE )
7709 {
7710 // We know that we are in row i, test whether we are
7711 // close enough to lower or upper border, respectively.
7712 if ( abs(GetRowBottom(i) - y) < WXGRID_LABEL_EDGE_ZONE )
7713 return i;
7714 else if( i > 0 && y - GetRowTop(i) < WXGRID_LABEL_EDGE_ZONE )
7715 return i - 1;
7716 }
7717
7718 return -1;
7719 }
7720
7721
7722 // return the col number that that the x coord is near the edge of, or
7723 // -1 if not near an edge
7724 //
7725 int wxGrid::XToEdgeOfCol( int x )
7726 {
7727 int i;
7728 i = internalXToCol(x);
7729
7730 if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE )
7731 {
7732 // We know that we are in column i, test whether we are
7733 // close enough to right or left border, respectively.
7734 if ( abs(GetColRight(i) - x) < WXGRID_LABEL_EDGE_ZONE )
7735 return i;
7736 else if( i > 0 && x - GetColLeft(i) < WXGRID_LABEL_EDGE_ZONE )
7737 return i - 1;
7738 }
7739
7740 return -1;
7741 }
7742
7743
7744 wxRect wxGrid::CellToRect( int row, int col )
7745 {
7746 wxRect rect( -1, -1, -1, -1 );
7747
7748 if ( row >= 0 && row < m_numRows &&
7749 col >= 0 && col < m_numCols )
7750 {
7751 int i, cell_rows, cell_cols;
7752 rect.width = rect.height = 0;
7753 GetCellSize( row, col, &cell_rows, &cell_cols );
7754 // if negative then find multicell owner
7755 if (cell_rows < 0) row += cell_rows;
7756 if (cell_cols < 0) col += cell_cols;
7757 GetCellSize( row, col, &cell_rows, &cell_cols );
7758
7759 rect.x = GetColLeft(col);
7760 rect.y = GetRowTop(row);
7761 for (i=col; i<col+cell_cols; i++)
7762 rect.width += GetColWidth(i);
7763 for (i=row; i<row+cell_rows; i++)
7764 rect.height += GetRowHeight(i);
7765 }
7766
7767 // if grid lines are enabled, then the area of the cell is a bit smaller
7768 if (m_gridLinesEnabled) {
7769 rect.width -= 1;
7770 rect.height -= 1;
7771 }
7772 return rect;
7773 }
7774
7775
7776 bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
7777 {
7778 // get the cell rectangle in logical coords
7779 //
7780 wxRect r( CellToRect( row, col ) );
7781
7782 // convert to device coords
7783 //
7784 int left, top, right, bottom;
7785 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
7786 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
7787
7788 // check against the client area of the grid window
7789 //
7790 int cw, ch;
7791 m_gridWin->GetClientSize( &cw, &ch );
7792
7793 if ( wholeCellVisible )
7794 {
7795 // is the cell wholly visible ?
7796 //
7797 return ( left >= 0 && right <= cw &&
7798 top >= 0 && bottom <= ch );
7799 }
7800 else
7801 {
7802 // is the cell partly visible ?
7803 //
7804 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
7805 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
7806 }
7807 }
7808
7809
7810 // make the specified cell location visible by doing a minimal amount
7811 // of scrolling
7812 //
7813 void wxGrid::MakeCellVisible( int row, int col )
7814 {
7815
7816 int i;
7817 int xpos = -1, ypos = -1;
7818
7819 if ( row >= 0 && row < m_numRows &&
7820 col >= 0 && col < m_numCols )
7821 {
7822 // get the cell rectangle in logical coords
7823 //
7824 wxRect r( CellToRect( row, col ) );
7825
7826 // convert to device coords
7827 //
7828 int left, top, right, bottom;
7829 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
7830 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
7831
7832 int cw, ch;
7833 m_gridWin->GetClientSize( &cw, &ch );
7834
7835 if ( top < 0 )
7836 {
7837 ypos = r.GetTop();
7838 }
7839 else if ( bottom > ch )
7840 {
7841 int h = r.GetHeight();
7842 ypos = r.GetTop();
7843 for ( i = row-1; i >= 0; i-- )
7844 {
7845 int rowHeight = GetRowHeight(i);
7846 if ( h + rowHeight > ch )
7847 break;
7848
7849 h += rowHeight;
7850 ypos -= rowHeight;
7851 }
7852
7853 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
7854 // have rounding errors (this is important, because if we do, we
7855 // might not scroll at all and some cells won't be redrawn)
7856 //
7857 // Sometimes GRID_SCROLL_LINE/2 is not enough, so just add a full
7858 // scroll unit...
7859 ypos += GRID_SCROLL_LINE_Y;
7860 }
7861
7862 if ( left < 0 )
7863 {
7864 xpos = r.GetLeft();
7865 }
7866 else if ( right > cw )
7867 {
7868 // position the view so that the cell is on the right
7869 int x0, y0;
7870 CalcUnscrolledPosition(0, 0, &x0, &y0);
7871 xpos = x0 + (right - cw);
7872
7873 // see comment for ypos above
7874 xpos += GRID_SCROLL_LINE_X;
7875 }
7876
7877 if ( xpos != -1 || ypos != -1 )
7878 {
7879 if ( xpos != -1 )
7880 xpos /= GRID_SCROLL_LINE_X;
7881 if ( ypos != -1 )
7882 ypos /= GRID_SCROLL_LINE_Y;
7883 Scroll( xpos, ypos );
7884 AdjustScrollbars();
7885 }
7886 }
7887 }
7888
7889
7890 //
7891 // ------ Grid cursor movement functions
7892 //
7893
7894 bool wxGrid::MoveCursorUp( bool expandSelection )
7895 {
7896 if ( m_currentCellCoords != wxGridNoCellCoords &&
7897 m_currentCellCoords.GetRow() >= 0 )
7898 {
7899 if ( expandSelection)
7900 {
7901 if ( m_selectingKeyboard == wxGridNoCellCoords )
7902 m_selectingKeyboard = m_currentCellCoords;
7903 if ( m_selectingKeyboard.GetRow() > 0 )
7904 {
7905 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() - 1 );
7906 MakeCellVisible( m_selectingKeyboard.GetRow(),
7907 m_selectingKeyboard.GetCol() );
7908 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
7909 }
7910 }
7911 else if ( m_currentCellCoords.GetRow() > 0 )
7912 {
7913 ClearSelection();
7914 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
7915 m_currentCellCoords.GetCol() );
7916 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
7917 m_currentCellCoords.GetCol() );
7918 }
7919 else
7920 return FALSE;
7921 return TRUE;
7922 }
7923
7924 return FALSE;
7925 }
7926
7927
7928 bool wxGrid::MoveCursorDown( bool expandSelection )
7929 {
7930 if ( m_currentCellCoords != wxGridNoCellCoords &&
7931 m_currentCellCoords.GetRow() < m_numRows )
7932 {
7933 if ( expandSelection )
7934 {
7935 if ( m_selectingKeyboard == wxGridNoCellCoords )
7936 m_selectingKeyboard = m_currentCellCoords;
7937 if ( m_selectingKeyboard.GetRow() < m_numRows-1 )
7938 {
7939 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() + 1 );
7940 MakeCellVisible( m_selectingKeyboard.GetRow(),
7941 m_selectingKeyboard.GetCol() );
7942 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
7943 }
7944 }
7945 else if ( m_currentCellCoords.GetRow() < m_numRows - 1 )
7946 {
7947 ClearSelection();
7948 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
7949 m_currentCellCoords.GetCol() );
7950 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
7951 m_currentCellCoords.GetCol() );
7952 }
7953 else
7954 return FALSE;
7955 return TRUE;
7956 }
7957
7958 return FALSE;
7959 }
7960
7961
7962 bool wxGrid::MoveCursorLeft( bool expandSelection )
7963 {
7964 if ( m_currentCellCoords != wxGridNoCellCoords &&
7965 m_currentCellCoords.GetCol() >= 0 )
7966 {
7967 if ( expandSelection )
7968 {
7969 if ( m_selectingKeyboard == wxGridNoCellCoords )
7970 m_selectingKeyboard = m_currentCellCoords;
7971 if ( m_selectingKeyboard.GetCol() > 0 )
7972 {
7973 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() - 1 );
7974 MakeCellVisible( m_selectingKeyboard.GetRow(),
7975 m_selectingKeyboard.GetCol() );
7976 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
7977 }
7978 }
7979 else if ( m_currentCellCoords.GetCol() > 0 )
7980 {
7981 ClearSelection();
7982 MakeCellVisible( m_currentCellCoords.GetRow(),
7983 m_currentCellCoords.GetCol() - 1 );
7984 SetCurrentCell( m_currentCellCoords.GetRow(),
7985 m_currentCellCoords.GetCol() - 1 );
7986 }
7987 else
7988 return FALSE;
7989 return TRUE;
7990 }
7991
7992 return FALSE;
7993 }
7994
7995
7996 bool wxGrid::MoveCursorRight( bool expandSelection )
7997 {
7998 if ( m_currentCellCoords != wxGridNoCellCoords &&
7999 m_currentCellCoords.GetCol() < m_numCols )
8000 {
8001 if ( expandSelection )
8002 {
8003 if ( m_selectingKeyboard == wxGridNoCellCoords )
8004 m_selectingKeyboard = m_currentCellCoords;
8005 if ( m_selectingKeyboard.GetCol() < m_numCols - 1 )
8006 {
8007 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() + 1 );
8008 MakeCellVisible( m_selectingKeyboard.GetRow(),
8009 m_selectingKeyboard.GetCol() );
8010 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
8011 }
8012 }
8013 else if ( m_currentCellCoords.GetCol() < m_numCols - 1 )
8014 {
8015 ClearSelection();
8016 MakeCellVisible( m_currentCellCoords.GetRow(),
8017 m_currentCellCoords.GetCol() + 1 );
8018 SetCurrentCell( m_currentCellCoords.GetRow(),
8019 m_currentCellCoords.GetCol() + 1 );
8020 }
8021 else
8022 return FALSE;
8023 return TRUE;
8024 }
8025
8026 return FALSE;
8027 }
8028
8029
8030 bool wxGrid::MovePageUp()
8031 {
8032 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
8033
8034 int row = m_currentCellCoords.GetRow();
8035 if ( row > 0 )
8036 {
8037 int cw, ch;
8038 m_gridWin->GetClientSize( &cw, &ch );
8039
8040 int y = GetRowTop(row);
8041 int newRow = internalYToRow( y - ch + 1 );
8042
8043 if ( newRow == row )
8044 {
8045 //row > 0 , so newrow can never be less than 0 here.
8046 newRow = row - 1;
8047 }
8048
8049 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
8050 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
8051
8052 return TRUE;
8053 }
8054
8055 return FALSE;
8056 }
8057
8058 bool wxGrid::MovePageDown()
8059 {
8060 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
8061
8062 int row = m_currentCellCoords.GetRow();
8063 if ( (row+1) < m_numRows )
8064 {
8065 int cw, ch;
8066 m_gridWin->GetClientSize( &cw, &ch );
8067
8068 int y = GetRowTop(row);
8069 int newRow = internalYToRow( y + ch );
8070 if ( newRow == row )
8071 {
8072 // row < m_numRows , so newrow can't overflow here.
8073 newRow = row + 1;
8074 }
8075
8076 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
8077 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
8078
8079 return TRUE;
8080 }
8081
8082 return FALSE;
8083 }
8084
8085 bool wxGrid::MoveCursorUpBlock( bool expandSelection )
8086 {
8087 if ( m_table &&
8088 m_currentCellCoords != wxGridNoCellCoords &&
8089 m_currentCellCoords.GetRow() > 0 )
8090 {
8091 int row = m_currentCellCoords.GetRow();
8092 int col = m_currentCellCoords.GetCol();
8093
8094 if ( m_table->IsEmptyCell(row, col) )
8095 {
8096 // starting in an empty cell: find the next block of
8097 // non-empty cells
8098 //
8099 while ( row > 0 )
8100 {
8101 row-- ;
8102 if ( !(m_table->IsEmptyCell(row, col)) ) break;
8103 }
8104 }
8105 else if ( m_table->IsEmptyCell(row-1, col) )
8106 {
8107 // starting at the top of a block: find the next block
8108 //
8109 row--;
8110 while ( row > 0 )
8111 {
8112 row-- ;
8113 if ( !(m_table->IsEmptyCell(row, col)) ) break;
8114 }
8115 }
8116 else
8117 {
8118 // starting within a block: find the top of the block
8119 //
8120 while ( row > 0 )
8121 {
8122 row-- ;
8123 if ( m_table->IsEmptyCell(row, col) )
8124 {
8125 row++ ;
8126 break;
8127 }
8128 }
8129 }
8130
8131 MakeCellVisible( row, col );
8132 if ( expandSelection )
8133 {
8134 m_selectingKeyboard = wxGridCellCoords( row, col );
8135 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
8136 }
8137 else
8138 {
8139 ClearSelection();
8140 SetCurrentCell( row, col );
8141 }
8142 return TRUE;
8143 }
8144
8145 return FALSE;
8146 }
8147
8148 bool wxGrid::MoveCursorDownBlock( bool expandSelection )
8149 {
8150 if ( m_table &&
8151 m_currentCellCoords != wxGridNoCellCoords &&
8152 m_currentCellCoords.GetRow() < m_numRows-1 )
8153 {
8154 int row = m_currentCellCoords.GetRow();
8155 int col = m_currentCellCoords.GetCol();
8156
8157 if ( m_table->IsEmptyCell(row, col) )
8158 {
8159 // starting in an empty cell: find the next block of
8160 // non-empty cells
8161 //
8162 while ( row < m_numRows-1 )
8163 {
8164 row++ ;
8165 if ( !(m_table->IsEmptyCell(row, col)) ) break;
8166 }
8167 }
8168 else if ( m_table->IsEmptyCell(row+1, col) )
8169 {
8170 // starting at the bottom of a block: find the next block
8171 //
8172 row++;
8173 while ( row < m_numRows-1 )
8174 {
8175 row++ ;
8176 if ( !(m_table->IsEmptyCell(row, col)) ) break;
8177 }
8178 }
8179 else
8180 {
8181 // starting within a block: find the bottom of the block
8182 //
8183 while ( row < m_numRows-1 )
8184 {
8185 row++ ;
8186 if ( m_table->IsEmptyCell(row, col) )
8187 {
8188 row-- ;
8189 break;
8190 }
8191 }
8192 }
8193
8194 MakeCellVisible( row, col );
8195 if ( expandSelection )
8196 {
8197 m_selectingKeyboard = wxGridCellCoords( row, col );
8198 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
8199 }
8200 else
8201 {
8202 ClearSelection();
8203 SetCurrentCell( row, col );
8204 }
8205
8206 return TRUE;
8207 }
8208
8209 return FALSE;
8210 }
8211
8212 bool wxGrid::MoveCursorLeftBlock( bool expandSelection )
8213 {
8214 if ( m_table &&
8215 m_currentCellCoords != wxGridNoCellCoords &&
8216 m_currentCellCoords.GetCol() > 0 )
8217 {
8218 int row = m_currentCellCoords.GetRow();
8219 int col = m_currentCellCoords.GetCol();
8220
8221 if ( m_table->IsEmptyCell(row, col) )
8222 {
8223 // starting in an empty cell: find the next block of
8224 // non-empty cells
8225 //
8226 while ( col > 0 )
8227 {
8228 col-- ;
8229 if ( !(m_table->IsEmptyCell(row, col)) ) break;
8230 }
8231 }
8232 else if ( m_table->IsEmptyCell(row, col-1) )
8233 {
8234 // starting at the left of a block: find the next block
8235 //
8236 col--;
8237 while ( col > 0 )
8238 {
8239 col-- ;
8240 if ( !(m_table->IsEmptyCell(row, col)) ) break;
8241 }
8242 }
8243 else
8244 {
8245 // starting within a block: find the left of the block
8246 //
8247 while ( col > 0 )
8248 {
8249 col-- ;
8250 if ( m_table->IsEmptyCell(row, col) )
8251 {
8252 col++ ;
8253 break;
8254 }
8255 }
8256 }
8257
8258 MakeCellVisible( row, col );
8259 if ( expandSelection )
8260 {
8261 m_selectingKeyboard = wxGridCellCoords( row, col );
8262 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
8263 }
8264 else
8265 {
8266 ClearSelection();
8267 SetCurrentCell( row, col );
8268 }
8269
8270 return TRUE;
8271 }
8272
8273 return FALSE;
8274 }
8275
8276 bool wxGrid::MoveCursorRightBlock( bool expandSelection )
8277 {
8278 if ( m_table &&
8279 m_currentCellCoords != wxGridNoCellCoords &&
8280 m_currentCellCoords.GetCol() < m_numCols-1 )
8281 {
8282 int row = m_currentCellCoords.GetRow();
8283 int col = m_currentCellCoords.GetCol();
8284
8285 if ( m_table->IsEmptyCell(row, col) )
8286 {
8287 // starting in an empty cell: find the next block of
8288 // non-empty cells
8289 //
8290 while ( col < m_numCols-1 )
8291 {
8292 col++ ;
8293 if ( !(m_table->IsEmptyCell(row, col)) ) break;
8294 }
8295 }
8296 else if ( m_table->IsEmptyCell(row, col+1) )
8297 {
8298 // starting at the right of a block: find the next block
8299 //
8300 col++;
8301 while ( col < m_numCols-1 )
8302 {
8303 col++ ;
8304 if ( !(m_table->IsEmptyCell(row, col)) ) break;
8305 }
8306 }
8307 else
8308 {
8309 // starting within a block: find the right of the block
8310 //
8311 while ( col < m_numCols-1 )
8312 {
8313 col++ ;
8314 if ( m_table->IsEmptyCell(row, col) )
8315 {
8316 col-- ;
8317 break;
8318 }
8319 }
8320 }
8321
8322 MakeCellVisible( row, col );
8323 if ( expandSelection )
8324 {
8325 m_selectingKeyboard = wxGridCellCoords( row, col );
8326 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
8327 }
8328 else
8329 {
8330 ClearSelection();
8331 SetCurrentCell( row, col );
8332 }
8333
8334 return TRUE;
8335 }
8336
8337 return FALSE;
8338 }
8339
8340
8341
8342 //
8343 // ------ Label values and formatting
8344 //
8345
8346 void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
8347 {
8348 *horiz = m_rowLabelHorizAlign;
8349 *vert = m_rowLabelVertAlign;
8350 }
8351
8352 void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
8353 {
8354 *horiz = m_colLabelHorizAlign;
8355 *vert = m_colLabelVertAlign;
8356 }
8357
8358 int wxGrid::GetColLabelTextOrientation()
8359 {
8360 return m_colLabelTextOrientation;
8361 }
8362
8363 wxString wxGrid::GetRowLabelValue( int row )
8364 {
8365 if ( m_table )
8366 {
8367 return m_table->GetRowLabelValue( row );
8368 }
8369 else
8370 {
8371 wxString s;
8372 s << row;
8373 return s;
8374 }
8375 }
8376
8377 wxString wxGrid::GetColLabelValue( int col )
8378 {
8379 if ( m_table )
8380 {
8381 return m_table->GetColLabelValue( col );
8382 }
8383 else
8384 {
8385 wxString s;
8386 s << col;
8387 return s;
8388 }
8389 }
8390
8391
8392 void wxGrid::SetRowLabelSize( int width )
8393 {
8394 width = wxMax( width, 0 );
8395 if ( width != m_rowLabelWidth )
8396 {
8397 if ( width == 0 )
8398 {
8399 m_rowLabelWin->Show( FALSE );
8400 m_cornerLabelWin->Show( FALSE );
8401 }
8402 else if ( m_rowLabelWidth == 0 )
8403 {
8404 m_rowLabelWin->Show( TRUE );
8405 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
8406 }
8407
8408 m_rowLabelWidth = width;
8409 CalcWindowSizes();
8410 wxScrolledWindow::Refresh( TRUE );
8411 }
8412 }
8413
8414
8415 void wxGrid::SetColLabelSize( int height )
8416 {
8417 height = wxMax( height, 0 );
8418 if ( height != m_colLabelHeight )
8419 {
8420 if ( height == 0 )
8421 {
8422 m_colLabelWin->Show( FALSE );
8423 m_cornerLabelWin->Show( FALSE );
8424 }
8425 else if ( m_colLabelHeight == 0 )
8426 {
8427 m_colLabelWin->Show( TRUE );
8428 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
8429 }
8430
8431 m_colLabelHeight = height;
8432 CalcWindowSizes();
8433 wxScrolledWindow::Refresh( TRUE );
8434 }
8435 }
8436
8437
8438 void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
8439 {
8440 if ( m_labelBackgroundColour != colour )
8441 {
8442 m_labelBackgroundColour = colour;
8443 m_rowLabelWin->SetBackgroundColour( colour );
8444 m_colLabelWin->SetBackgroundColour( colour );
8445 m_cornerLabelWin->SetBackgroundColour( colour );
8446
8447 if ( !GetBatchCount() )
8448 {
8449 m_rowLabelWin->Refresh();
8450 m_colLabelWin->Refresh();
8451 m_cornerLabelWin->Refresh();
8452 }
8453 }
8454 }
8455
8456 void wxGrid::SetLabelTextColour( const wxColour& colour )
8457 {
8458 if ( m_labelTextColour != colour )
8459 {
8460 m_labelTextColour = colour;
8461 if ( !GetBatchCount() )
8462 {
8463 m_rowLabelWin->Refresh();
8464 m_colLabelWin->Refresh();
8465 }
8466 }
8467 }
8468
8469 void wxGrid::SetLabelFont( const wxFont& font )
8470 {
8471 m_labelFont = font;
8472 if ( !GetBatchCount() )
8473 {
8474 m_rowLabelWin->Refresh();
8475 m_colLabelWin->Refresh();
8476 }
8477 }
8478
8479 void wxGrid::SetRowLabelAlignment( int horiz, int vert )
8480 {
8481 // allow old (incorrect) defs to be used
8482 switch ( horiz )
8483 {
8484 case wxLEFT: horiz = wxALIGN_LEFT; break;
8485 case wxRIGHT: horiz = wxALIGN_RIGHT; break;
8486 case wxCENTRE: horiz = wxALIGN_CENTRE; break;
8487 }
8488
8489 switch ( vert )
8490 {
8491 case wxTOP: vert = wxALIGN_TOP; break;
8492 case wxBOTTOM: vert = wxALIGN_BOTTOM; break;
8493 case wxCENTRE: vert = wxALIGN_CENTRE; break;
8494 }
8495
8496 if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT )
8497 {
8498 m_rowLabelHorizAlign = horiz;
8499 }
8500
8501 if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM )
8502 {
8503 m_rowLabelVertAlign = vert;
8504 }
8505
8506 if ( !GetBatchCount() )
8507 {
8508 m_rowLabelWin->Refresh();
8509 }
8510 }
8511
8512 void wxGrid::SetColLabelAlignment( int horiz, int vert )
8513 {
8514 // allow old (incorrect) defs to be used
8515 switch ( horiz )
8516 {
8517 case wxLEFT: horiz = wxALIGN_LEFT; break;
8518 case wxRIGHT: horiz = wxALIGN_RIGHT; break;
8519 case wxCENTRE: horiz = wxALIGN_CENTRE; break;
8520 }
8521
8522 switch ( vert )
8523 {
8524 case wxTOP: vert = wxALIGN_TOP; break;
8525 case wxBOTTOM: vert = wxALIGN_BOTTOM; break;
8526 case wxCENTRE: vert = wxALIGN_CENTRE; break;
8527 }
8528
8529 if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT )
8530 {
8531 m_colLabelHorizAlign = horiz;
8532 }
8533
8534 if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM )
8535 {
8536 m_colLabelVertAlign = vert;
8537 }
8538
8539 if ( !GetBatchCount() )
8540 {
8541 m_colLabelWin->Refresh();
8542 }
8543 }
8544
8545 // Note: under MSW, the default column label font must be changed because it
8546 // does not support vertical printing
8547 //
8548 // Example: wxFont font(9, wxSWISS, wxNORMAL, wxBOLD);
8549 // pGrid->SetLabelFont(font);
8550 // pGrid->SetColLabelTextOrientation(wxVERTICAL);
8551 //
8552 void wxGrid::SetColLabelTextOrientation( int textOrientation )
8553 {
8554 if( textOrientation == wxHORIZONTAL || textOrientation == wxVERTICAL )
8555 {
8556 m_colLabelTextOrientation = textOrientation;
8557 }
8558
8559 if ( !GetBatchCount() )
8560 {
8561 m_colLabelWin->Refresh();
8562 }
8563 }
8564
8565 void wxGrid::SetRowLabelValue( int row, const wxString& s )
8566 {
8567 if ( m_table )
8568 {
8569 m_table->SetRowLabelValue( row, s );
8570 if ( !GetBatchCount() )
8571 {
8572 wxRect rect = CellToRect( row, 0);
8573 if ( rect.height > 0 )
8574 {
8575 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
8576 rect.x = 0;
8577 rect.width = m_rowLabelWidth;
8578 m_rowLabelWin->Refresh( TRUE, &rect );
8579 }
8580 }
8581 }
8582 }
8583
8584 void wxGrid::SetColLabelValue( int col, const wxString& s )
8585 {
8586 if ( m_table )
8587 {
8588 m_table->SetColLabelValue( col, s );
8589 if ( !GetBatchCount() )
8590 {
8591 wxRect rect = CellToRect( 0, col );
8592 if ( rect.width > 0 )
8593 {
8594 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
8595 rect.y = 0;
8596 rect.height = m_colLabelHeight;
8597 m_colLabelWin->Refresh( TRUE, &rect );
8598 }
8599 }
8600 }
8601 }
8602
8603 void wxGrid::SetGridLineColour( const wxColour& colour )
8604 {
8605 if ( m_gridLineColour != colour )
8606 {
8607 m_gridLineColour = colour;
8608
8609 wxClientDC dc( m_gridWin );
8610 PrepareDC( dc );
8611 DrawAllGridLines( dc, wxRegion() );
8612 }
8613 }
8614
8615
8616 void wxGrid::SetCellHighlightColour( const wxColour& colour )
8617 {
8618 if ( m_cellHighlightColour != colour )
8619 {
8620 m_cellHighlightColour = colour;
8621
8622 wxClientDC dc( m_gridWin );
8623 PrepareDC( dc );
8624 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
8625 DrawCellHighlight(dc, attr);
8626 attr->DecRef();
8627 }
8628 }
8629
8630 void wxGrid::SetCellHighlightPenWidth(int width)
8631 {
8632 if (m_cellHighlightPenWidth != width) {
8633 m_cellHighlightPenWidth = width;
8634
8635 // Just redrawing the cell highlight is not enough since that won't
8636 // make any visible change if the the thickness is getting smaller.
8637 int row = m_currentCellCoords.GetRow();
8638 int col = m_currentCellCoords.GetCol();
8639 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
8640 return;
8641 wxRect rect = CellToRect(row, col);
8642 m_gridWin->Refresh(TRUE, &rect);
8643 }
8644 }
8645
8646 void wxGrid::SetCellHighlightROPenWidth(int width)
8647 {
8648 if (m_cellHighlightROPenWidth != width) {
8649 m_cellHighlightROPenWidth = width;
8650
8651 // Just redrawing the cell highlight is not enough since that won't
8652 // make any visible change if the the thickness is getting smaller.
8653 int row = m_currentCellCoords.GetRow();
8654 int col = m_currentCellCoords.GetCol();
8655 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
8656 return;
8657 wxRect rect = CellToRect(row, col);
8658 m_gridWin->Refresh(TRUE, &rect);
8659 }
8660 }
8661
8662 void wxGrid::EnableGridLines( bool enable )
8663 {
8664 if ( enable != m_gridLinesEnabled )
8665 {
8666 m_gridLinesEnabled = enable;
8667
8668 if ( !GetBatchCount() )
8669 {
8670 if ( enable )
8671 {
8672 wxClientDC dc( m_gridWin );
8673 PrepareDC( dc );
8674 DrawAllGridLines( dc, wxRegion() );
8675 }
8676 else
8677 {
8678 m_gridWin->Refresh();
8679 }
8680 }
8681 }
8682 }
8683
8684
8685 int wxGrid::GetDefaultRowSize()
8686 {
8687 return m_defaultRowHeight;
8688 }
8689
8690 int wxGrid::GetRowSize( int row )
8691 {
8692 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
8693
8694 return GetRowHeight(row);
8695 }
8696
8697 int wxGrid::GetDefaultColSize()
8698 {
8699 return m_defaultColWidth;
8700 }
8701
8702 int wxGrid::GetColSize( int col )
8703 {
8704 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
8705
8706 return GetColWidth(col);
8707 }
8708
8709 // ============================================================================
8710 // access to the grid attributes: each of them has a default value in the grid
8711 // itself and may be overidden on a per-cell basis
8712 // ============================================================================
8713
8714 // ----------------------------------------------------------------------------
8715 // setting default attributes
8716 // ----------------------------------------------------------------------------
8717
8718 void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
8719 {
8720 m_defaultCellAttr->SetBackgroundColour(col);
8721 #ifdef __WXGTK__
8722 m_gridWin->SetBackgroundColour(col);
8723 #endif
8724 }
8725
8726 void wxGrid::SetDefaultCellTextColour( const wxColour& col )
8727 {
8728 m_defaultCellAttr->SetTextColour(col);
8729 }
8730
8731 void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
8732 {
8733 m_defaultCellAttr->SetAlignment(horiz, vert);
8734 }
8735
8736 void wxGrid::SetDefaultCellOverflow( bool allow )
8737 {
8738 m_defaultCellAttr->SetOverflow(allow);
8739 }
8740
8741 void wxGrid::SetDefaultCellFont( const wxFont& font )
8742 {
8743 m_defaultCellAttr->SetFont(font);
8744 }
8745
8746 void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
8747 {
8748 m_defaultCellAttr->SetRenderer(renderer);
8749 }
8750
8751 void wxGrid::SetDefaultEditor(wxGridCellEditor *editor)
8752 {
8753 m_defaultCellAttr->SetEditor(editor);
8754 }
8755
8756 // ----------------------------------------------------------------------------
8757 // access to the default attrbiutes
8758 // ----------------------------------------------------------------------------
8759
8760 wxColour wxGrid::GetDefaultCellBackgroundColour()
8761 {
8762 return m_defaultCellAttr->GetBackgroundColour();
8763 }
8764
8765 wxColour wxGrid::GetDefaultCellTextColour()
8766 {
8767 return m_defaultCellAttr->GetTextColour();
8768 }
8769
8770 wxFont wxGrid::GetDefaultCellFont()
8771 {
8772 return m_defaultCellAttr->GetFont();
8773 }
8774
8775 void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
8776 {
8777 m_defaultCellAttr->GetAlignment(horiz, vert);
8778 }
8779
8780 bool wxGrid::GetDefaultCellOverflow()
8781 {
8782 return m_defaultCellAttr->GetOverflow();
8783 }
8784
8785 wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
8786 {
8787 return m_defaultCellAttr->GetRenderer(NULL, 0, 0);
8788 }
8789
8790 wxGridCellEditor *wxGrid::GetDefaultEditor() const
8791 {
8792 return m_defaultCellAttr->GetEditor(NULL,0,0);
8793 }
8794
8795 // ----------------------------------------------------------------------------
8796 // access to cell attributes
8797 // ----------------------------------------------------------------------------
8798
8799 wxColour wxGrid::GetCellBackgroundColour(int row, int col)
8800 {
8801 wxGridCellAttr *attr = GetCellAttr(row, col);
8802 wxColour colour = attr->GetBackgroundColour();
8803 attr->DecRef();
8804 return colour;
8805 }
8806
8807 wxColour wxGrid::GetCellTextColour( int row, int col )
8808 {
8809 wxGridCellAttr *attr = GetCellAttr(row, col);
8810 wxColour colour = attr->GetTextColour();
8811 attr->DecRef();
8812 return colour;
8813 }
8814
8815 wxFont wxGrid::GetCellFont( int row, int col )
8816 {
8817 wxGridCellAttr *attr = GetCellAttr(row, col);
8818 wxFont font = attr->GetFont();
8819 attr->DecRef();
8820 return font;
8821 }
8822
8823 void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
8824 {
8825 wxGridCellAttr *attr = GetCellAttr(row, col);
8826 attr->GetAlignment(horiz, vert);
8827 attr->DecRef();
8828 }
8829
8830 bool wxGrid::GetCellOverflow( int row, int col )
8831 {
8832 wxGridCellAttr *attr = GetCellAttr(row, col);
8833 bool allow = attr->GetOverflow();
8834 attr->DecRef();
8835 return allow;
8836 }
8837
8838 void wxGrid::GetCellSize( int row, int col, int *num_rows, int *num_cols )
8839 {
8840 wxGridCellAttr *attr = GetCellAttr(row, col);
8841 attr->GetSize( num_rows, num_cols );
8842 attr->DecRef();
8843 }
8844
8845 wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
8846 {
8847 wxGridCellAttr* attr = GetCellAttr(row, col);
8848 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
8849 attr->DecRef();
8850
8851 return renderer;
8852 }
8853
8854 wxGridCellEditor* wxGrid::GetCellEditor(int row, int col)
8855 {
8856 wxGridCellAttr* attr = GetCellAttr(row, col);
8857 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
8858 attr->DecRef();
8859
8860 return editor;
8861 }
8862
8863 bool wxGrid::IsReadOnly(int row, int col) const
8864 {
8865 wxGridCellAttr* attr = GetCellAttr(row, col);
8866 bool isReadOnly = attr->IsReadOnly();
8867 attr->DecRef();
8868 return isReadOnly;
8869 }
8870
8871 // ----------------------------------------------------------------------------
8872 // attribute support: cache, automatic provider creation, ...
8873 // ----------------------------------------------------------------------------
8874
8875 bool wxGrid::CanHaveAttributes()
8876 {
8877 if ( !m_table )
8878 {
8879 return FALSE;
8880 }
8881
8882 return m_table->CanHaveAttributes();
8883 }
8884
8885 void wxGrid::ClearAttrCache()
8886 {
8887 if ( m_attrCache.row != -1 )
8888 {
8889 wxSafeDecRef(m_attrCache.attr);
8890 m_attrCache.attr = NULL;
8891 m_attrCache.row = -1;
8892 }
8893 }
8894
8895 void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
8896 {
8897 if ( attr != NULL )
8898 {
8899 wxGrid *self = (wxGrid *)this; // const_cast
8900
8901 self->ClearAttrCache();
8902 self->m_attrCache.row = row;
8903 self->m_attrCache.col = col;
8904 self->m_attrCache.attr = attr;
8905 wxSafeIncRef(attr);
8906 }
8907 }
8908
8909 bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
8910 {
8911 if ( row == m_attrCache.row && col == m_attrCache.col )
8912 {
8913 *attr = m_attrCache.attr;
8914 wxSafeIncRef(m_attrCache.attr);
8915
8916 #ifdef DEBUG_ATTR_CACHE
8917 gs_nAttrCacheHits++;
8918 #endif
8919
8920 return TRUE;
8921 }
8922 else
8923 {
8924 #ifdef DEBUG_ATTR_CACHE
8925 gs_nAttrCacheMisses++;
8926 #endif
8927 return FALSE;
8928 }
8929 }
8930
8931 wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
8932 {
8933 wxGridCellAttr *attr = NULL;
8934 // Additional test to avoid looking at the cache e.g. for
8935 // wxNoCellCoords, as this will confuse memory management.
8936 if ( row >= 0 )
8937 {
8938 if ( !LookupAttr(row, col, &attr) )
8939 {
8940 attr = m_table ? m_table->GetAttr(row, col , wxGridCellAttr::Any)
8941 : (wxGridCellAttr *)NULL;
8942 CacheAttr(row, col, attr);
8943 }
8944 }
8945 if (attr)
8946 {
8947 attr->SetDefAttr(m_defaultCellAttr);
8948 }
8949 else
8950 {
8951 attr = m_defaultCellAttr;
8952 attr->IncRef();
8953 }
8954
8955 return attr;
8956 }
8957
8958 wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
8959 {
8960 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
8961
8962 wxCHECK_MSG( m_table, attr,
8963 _T("we may only be called if CanHaveAttributes() returned TRUE and then m_table should be !NULL") );
8964
8965 attr = m_table->GetAttr(row, col, wxGridCellAttr::Cell);
8966 if ( !attr )
8967 {
8968 attr = new wxGridCellAttr(m_defaultCellAttr);
8969
8970 // artificially inc the ref count to match DecRef() in caller
8971 attr->IncRef();
8972 m_table->SetAttr(attr, row, col);
8973 }
8974
8975 return attr;
8976 }
8977
8978 // ----------------------------------------------------------------------------
8979 // setting column attributes (wrappers around SetColAttr)
8980 // ----------------------------------------------------------------------------
8981
8982 void wxGrid::SetColFormatBool(int col)
8983 {
8984 SetColFormatCustom(col, wxGRID_VALUE_BOOL);
8985 }
8986
8987 void wxGrid::SetColFormatNumber(int col)
8988 {
8989 SetColFormatCustom(col, wxGRID_VALUE_NUMBER);
8990 }
8991
8992 void wxGrid::SetColFormatFloat(int col, int width, int precision)
8993 {
8994 wxString typeName = wxGRID_VALUE_FLOAT;
8995 if ( (width != -1) || (precision != -1) )
8996 {
8997 typeName << _T(':') << width << _T(',') << precision;
8998 }
8999
9000 SetColFormatCustom(col, typeName);
9001 }
9002
9003 void wxGrid::SetColFormatCustom(int col, const wxString& typeName)
9004 {
9005 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
9006
9007 attr = m_table->GetAttr(-1, col, wxGridCellAttr::Col );
9008 if(!attr)
9009 attr = new wxGridCellAttr;
9010 wxGridCellRenderer *renderer = GetDefaultRendererForType(typeName);
9011 attr->SetRenderer(renderer);
9012
9013 SetColAttr(col, attr);
9014
9015 }
9016
9017 // ----------------------------------------------------------------------------
9018 // setting cell attributes: this is forwarded to the table
9019 // ----------------------------------------------------------------------------
9020
9021 void wxGrid::SetAttr(int row, int col, wxGridCellAttr *attr)
9022 {
9023 if ( CanHaveAttributes() )
9024 {
9025 m_table->SetAttr(attr, row, col);
9026 ClearAttrCache();
9027 }
9028 else
9029 {
9030 wxSafeDecRef(attr);
9031 }
9032 }
9033
9034 void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
9035 {
9036 if ( CanHaveAttributes() )
9037 {
9038 m_table->SetRowAttr(attr, row);
9039 ClearAttrCache();
9040 }
9041 else
9042 {
9043 wxSafeDecRef(attr);
9044 }
9045 }
9046
9047 void wxGrid::SetColAttr(int col, wxGridCellAttr *attr)
9048 {
9049 if ( CanHaveAttributes() )
9050 {
9051 m_table->SetColAttr(attr, col);
9052 ClearAttrCache();
9053 }
9054 else
9055 {
9056 wxSafeDecRef(attr);
9057 }
9058 }
9059
9060 void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
9061 {
9062 if ( CanHaveAttributes() )
9063 {
9064 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
9065 attr->SetBackgroundColour(colour);
9066 attr->DecRef();
9067 }
9068 }
9069
9070 void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
9071 {
9072 if ( CanHaveAttributes() )
9073 {
9074 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
9075 attr->SetTextColour(colour);
9076 attr->DecRef();
9077 }
9078 }
9079
9080 void wxGrid::SetCellFont( int row, int col, const wxFont& font )
9081 {
9082 if ( CanHaveAttributes() )
9083 {
9084 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
9085 attr->SetFont(font);
9086 attr->DecRef();
9087 }
9088 }
9089
9090 void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
9091 {
9092 if ( CanHaveAttributes() )
9093 {
9094 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
9095 attr->SetAlignment(horiz, vert);
9096 attr->DecRef();
9097 }
9098 }
9099
9100 void wxGrid::SetCellOverflow( int row, int col, bool allow )
9101 {
9102 if ( CanHaveAttributes() )
9103 {
9104 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
9105 attr->SetOverflow(allow);
9106 attr->DecRef();
9107 }
9108 }
9109
9110 void wxGrid::SetCellSize( int row, int col, int num_rows, int num_cols )
9111 {
9112 if ( CanHaveAttributes() )
9113 {
9114 int cell_rows, cell_cols;
9115
9116 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
9117 attr->GetSize(&cell_rows, &cell_cols);
9118 attr->SetSize(num_rows, num_cols);
9119 attr->DecRef();
9120
9121 // Cannot set the size of a cell to 0 or negative values
9122 // While it is perfectly legal to do that, this function cannot
9123 // handle all the possibilies, do it by hand by getting the CellAttr.
9124 // You can only set the size of a cell to 1,1 or greater with this fn
9125 wxASSERT_MSG( !((cell_rows < 1) || (cell_cols < 1)),
9126 wxT("wxGrid::SetCellSize setting cell size that is already part of another cell"));
9127 wxASSERT_MSG( !((num_rows < 1) || (num_cols < 1)),
9128 wxT("wxGrid::SetCellSize setting cell size to < 1"));
9129
9130 // if this was already a multicell then "turn off" the other cells first
9131 if ((cell_rows > 1) || (cell_rows > 1))
9132 {
9133 int i, j;
9134 for (j=row; j<row+cell_rows; j++)
9135 {
9136 for (i=col; i<col+cell_cols; i++)
9137 {
9138 if ((i != col) || (j != row))
9139 {
9140 wxGridCellAttr *attr_stub = GetOrCreateCellAttr(j, i);
9141 attr_stub->SetSize( 1, 1 );
9142 attr_stub->DecRef();
9143 }
9144 }
9145 }
9146 }
9147
9148 // mark the cells that will be covered by this cell to
9149 // negative or zero values to point back at this cell
9150 if (((num_rows > 1) || (num_cols > 1)) && (num_rows >= 1) && (num_cols >= 1))
9151 {
9152 int i, j;
9153 for (j=row; j<row+num_rows; j++)
9154 {
9155 for (i=col; i<col+num_cols; i++)
9156 {
9157 if ((i != col) || (j != row))
9158 {
9159 wxGridCellAttr *attr_stub = GetOrCreateCellAttr(j, i);
9160 attr_stub->SetSize( row-j, col-i );
9161 attr_stub->DecRef();
9162 }
9163 }
9164 }
9165 }
9166 }
9167 }
9168
9169 void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
9170 {
9171 if ( CanHaveAttributes() )
9172 {
9173 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
9174 attr->SetRenderer(renderer);
9175 attr->DecRef();
9176 }
9177 }
9178
9179 void wxGrid::SetCellEditor(int row, int col, wxGridCellEditor* editor)
9180 {
9181 if ( CanHaveAttributes() )
9182 {
9183 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
9184 attr->SetEditor(editor);
9185 attr->DecRef();
9186 }
9187 }
9188
9189 void wxGrid::SetReadOnly(int row, int col, bool isReadOnly)
9190 {
9191 if ( CanHaveAttributes() )
9192 {
9193 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
9194 attr->SetReadOnly(isReadOnly);
9195 attr->DecRef();
9196 }
9197 }
9198
9199 // ----------------------------------------------------------------------------
9200 // Data type registration
9201 // ----------------------------------------------------------------------------
9202
9203 void wxGrid::RegisterDataType(const wxString& typeName,
9204 wxGridCellRenderer* renderer,
9205 wxGridCellEditor* editor)
9206 {
9207 m_typeRegistry->RegisterDataType(typeName, renderer, editor);
9208 }
9209
9210
9211 wxGridCellEditor* wxGrid::GetDefaultEditorForCell(int row, int col) const
9212 {
9213 wxString typeName = m_table->GetTypeName(row, col);
9214 return GetDefaultEditorForType(typeName);
9215 }
9216
9217 wxGridCellRenderer* wxGrid::GetDefaultRendererForCell(int row, int col) const
9218 {
9219 wxString typeName = m_table->GetTypeName(row, col);
9220 return GetDefaultRendererForType(typeName);
9221 }
9222
9223 wxGridCellEditor*
9224 wxGrid::GetDefaultEditorForType(const wxString& typeName) const
9225 {
9226 int index = m_typeRegistry->FindOrCloneDataType(typeName);
9227 if ( index == wxNOT_FOUND )
9228 {
9229 wxFAIL_MSG(wxT("Unknown data type name"));
9230
9231 return NULL;
9232 }
9233
9234 return m_typeRegistry->GetEditor(index);
9235 }
9236
9237 wxGridCellRenderer*
9238 wxGrid::GetDefaultRendererForType(const wxString& typeName) const
9239 {
9240 int index = m_typeRegistry->FindOrCloneDataType(typeName);
9241 if ( index == wxNOT_FOUND )
9242 {
9243 wxFAIL_MSG(wxT("Unknown data type name"));
9244
9245 return NULL;
9246 }
9247
9248 return m_typeRegistry->GetRenderer(index);
9249 }
9250
9251
9252 // ----------------------------------------------------------------------------
9253 // row/col size
9254 // ----------------------------------------------------------------------------
9255
9256 void wxGrid::EnableDragRowSize( bool enable )
9257 {
9258 m_canDragRowSize = enable;
9259 }
9260
9261
9262 void wxGrid::EnableDragColSize( bool enable )
9263 {
9264 m_canDragColSize = enable;
9265 }
9266
9267 void wxGrid::EnableDragGridSize( bool enable )
9268 {
9269 m_canDragGridSize = enable;
9270 }
9271
9272
9273 void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
9274 {
9275 m_defaultRowHeight = wxMax( height, m_minAcceptableRowHeight );
9276
9277 if ( resizeExistingRows )
9278 {
9279 // since we are resizing all rows to the default row size,
9280 // we can simply clear the row heights and row bottoms
9281 // arrays (which also allows us to take advantage of
9282 // some speed optimisations)
9283 m_rowHeights.Empty();
9284 m_rowBottoms.Empty();
9285 if ( !GetBatchCount() )
9286 CalcDimensions();
9287 }
9288 }
9289
9290 void wxGrid::SetRowSize( int row, int height )
9291 {
9292 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
9293
9294 // See comment in SetColSize
9295 if ( height < GetRowMinimalAcceptableHeight()) { return; }
9296
9297 if ( m_rowHeights.IsEmpty() )
9298 {
9299 // need to really create the array
9300 InitRowHeights();
9301 }
9302
9303 int h = wxMax( 0, height );
9304 int diff = h - m_rowHeights[row];
9305
9306 m_rowHeights[row] = h;
9307 int i;
9308 for ( i = row; i < m_numRows; i++ )
9309 {
9310 m_rowBottoms[i] += diff;
9311 }
9312 if ( !GetBatchCount() )
9313 CalcDimensions();
9314 }
9315
9316 void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
9317 {
9318 m_defaultColWidth = wxMax( width, m_minAcceptableColWidth );
9319
9320 if ( resizeExistingCols )
9321 {
9322 // since we are resizing all columns to the default column size,
9323 // we can simply clear the col widths and col rights
9324 // arrays (which also allows us to take advantage of
9325 // some speed optimisations)
9326 m_colWidths.Empty();
9327 m_colRights.Empty();
9328 if ( !GetBatchCount() )
9329 CalcDimensions();
9330 }
9331 }
9332
9333 void wxGrid::SetColSize( int col, int width )
9334 {
9335 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
9336
9337 // should we check that it's bigger than GetColMinimalWidth(col) here?
9338 // (VZ)
9339 // No, because it is reasonable to assume the library user know's
9340 // what he is doing. However whe should test against the weaker
9341 // constariant of minimalAcceptableWidth, as this breaks rendering
9342 //
9343 // This test then fixes sf.net bug #645734
9344
9345 if ( width < GetColMinimalAcceptableWidth()) { return; }
9346
9347 if ( m_colWidths.IsEmpty() )
9348 {
9349 // need to really create the array
9350 InitColWidths();
9351 }
9352
9353 // if < 0 calc new width from label
9354 if( width < 0 )
9355 {
9356 long w, h;
9357 wxArrayString lines;
9358 wxClientDC dc(m_colLabelWin);
9359 dc.SetFont(GetLabelFont());
9360 StringToLines(GetColLabelValue(col), lines);
9361 GetTextBoxSize(dc, lines, &w, &h);
9362 width = w + 6;
9363 }
9364 int w = wxMax( 0, width );
9365 int diff = w - m_colWidths[col];
9366 m_colWidths[col] = w;
9367
9368 int i;
9369 for ( i = col; i < m_numCols; i++ )
9370 {
9371 m_colRights[i] += diff;
9372 }
9373 if ( !GetBatchCount() )
9374 CalcDimensions();
9375 }
9376
9377
9378 void wxGrid::SetColMinimalWidth( int col, int width )
9379 {
9380 if (width > GetColMinimalAcceptableWidth()) {
9381 m_colMinWidths.Put(col, width);
9382 }
9383 }
9384
9385 void wxGrid::SetRowMinimalHeight( int row, int width )
9386 {
9387 if (width > GetRowMinimalAcceptableHeight()) {
9388 m_rowMinHeights.Put(row, width);
9389 }
9390 }
9391
9392 int wxGrid::GetColMinimalWidth(int col) const
9393 {
9394 long value = m_colMinWidths.Get(col);
9395 return value != wxNOT_FOUND ? (int)value : m_minAcceptableColWidth;
9396 }
9397
9398 int wxGrid::GetRowMinimalHeight(int row) const
9399 {
9400 long value = m_rowMinHeights.Get(row);
9401 return value != wxNOT_FOUND ? (int)value : m_minAcceptableRowHeight;
9402 }
9403
9404 void wxGrid::SetColMinimalAcceptableWidth( int width )
9405 {
9406 if ( width<1 )
9407 return;
9408 m_minAcceptableColWidth = width;
9409 }
9410
9411 void wxGrid::SetRowMinimalAcceptableHeight( int height )
9412 {
9413 if ( height<1 )
9414 return;
9415 m_minAcceptableRowHeight = height;
9416 };
9417
9418 int wxGrid::GetColMinimalAcceptableWidth() const
9419 {
9420 return m_minAcceptableColWidth;
9421 }
9422
9423 int wxGrid::GetRowMinimalAcceptableHeight() const
9424 {
9425 return m_minAcceptableRowHeight;
9426 }
9427
9428 // ----------------------------------------------------------------------------
9429 // auto sizing
9430 // ----------------------------------------------------------------------------
9431
9432 void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column )
9433 {
9434 wxClientDC dc(m_gridWin);
9435
9436 // init both of them to avoid compiler warnings, even if weo nly need one
9437 int row = -1,
9438 col = -1;
9439 if ( column )
9440 col = colOrRow;
9441 else
9442 row = colOrRow;
9443
9444 wxCoord extent, extentMax = 0;
9445 int max = column ? m_numRows : m_numCols;
9446 for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ )
9447 {
9448 if ( column )
9449 row = rowOrCol;
9450 else
9451 col = rowOrCol;
9452
9453 wxGridCellAttr* attr = GetCellAttr(row, col);
9454 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
9455 if ( renderer )
9456 {
9457 wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col);
9458 extent = column ? size.x : size.y;
9459 if ( extent > extentMax )
9460 {
9461 extentMax = extent;
9462 }
9463
9464 renderer->DecRef();
9465 }
9466
9467 attr->DecRef();
9468 }
9469
9470 // now also compare with the column label extent
9471 wxCoord w, h;
9472 dc.SetFont( GetLabelFont() );
9473
9474 if ( column )
9475 {
9476 dc.GetTextExtent( GetColLabelValue(col), &w, &h );
9477 if( GetColLabelTextOrientation() == wxVERTICAL )
9478 w = h;
9479 }
9480 else
9481 dc.GetTextExtent( GetRowLabelValue(row), &w, &h );
9482
9483 extent = column ? w : h;
9484 if ( extent > extentMax )
9485 {
9486 extentMax = extent;
9487 }
9488
9489 if ( !extentMax )
9490 {
9491 // empty column - give default extent (notice that if extentMax is less
9492 // than default extent but != 0, it's ok)
9493 extentMax = column ? m_defaultColWidth : m_defaultRowHeight;
9494 }
9495 else
9496 {
9497 if ( column )
9498 {
9499 // leave some space around text
9500 extentMax += 10;
9501 }
9502 else
9503 {
9504 extentMax += 6;
9505 }
9506 }
9507
9508 if ( column )
9509 {
9510 SetColSize(col, extentMax);
9511 if ( !GetBatchCount() )
9512 {
9513 int cw, ch, dummy;
9514 m_gridWin->GetClientSize( &cw, &ch );
9515 wxRect rect ( CellToRect( 0, col ) );
9516 rect.y = 0;
9517 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
9518 rect.width = cw - rect.x;
9519 rect.height = m_colLabelHeight;
9520 m_colLabelWin->Refresh( TRUE, &rect );
9521 }
9522 }
9523 else
9524 {
9525 SetRowSize(row, extentMax);
9526 if ( !GetBatchCount() )
9527 {
9528 int cw, ch, dummy;
9529 m_gridWin->GetClientSize( &cw, &ch );
9530 wxRect rect ( CellToRect( row, 0 ) );
9531 rect.x = 0;
9532 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
9533 rect.width = m_rowLabelWidth;
9534 rect.height = ch - rect.y;
9535 m_rowLabelWin->Refresh( TRUE, &rect );
9536 }
9537 }
9538 if ( setAsMin )
9539 {
9540 if ( column )
9541 SetColMinimalWidth(col, extentMax);
9542 else
9543 SetRowMinimalHeight(row, extentMax);
9544 }
9545 }
9546
9547 int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
9548 {
9549 int width = m_rowLabelWidth;
9550
9551 if ( !calcOnly )
9552 BeginBatch();
9553
9554 for ( int col = 0; col < m_numCols; col++ )
9555 {
9556 if ( !calcOnly )
9557 {
9558 AutoSizeColumn(col, setAsMin);
9559 }
9560
9561 width += GetColWidth(col);
9562 }
9563
9564 if ( !calcOnly )
9565 EndBatch();
9566
9567 return width;
9568 }
9569
9570 int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
9571 {
9572 int height = m_colLabelHeight;
9573
9574 if ( !calcOnly )
9575 BeginBatch();
9576
9577 for ( int row = 0; row < m_numRows; row++ )
9578 {
9579 if ( !calcOnly )
9580 {
9581 AutoSizeRow(row, setAsMin);
9582 }
9583
9584 height += GetRowHeight(row);
9585 }
9586
9587 if ( !calcOnly )
9588 EndBatch();
9589
9590 return height;
9591 }
9592
9593 void wxGrid::AutoSize()
9594 {
9595 BeginBatch();
9596
9597 wxSize size(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE));
9598
9599 // round up the size to a multiple of scroll step - this ensures that we
9600 // won't get the scrollbars if we're sized exactly to this width
9601 // CalcDimension adds m_extraWidth + 1 etc. to calculate the necessary
9602 // scrollbar steps
9603 wxSize sizeFit(GetScrollX(size.x + m_extraWidth + 1) * GRID_SCROLL_LINE_X,
9604 GetScrollY(size.y + m_extraHeight + 1) * GRID_SCROLL_LINE_Y);
9605
9606 // distribute the extra space between the columns/rows to avoid having
9607 // extra white space
9608
9609 // Remove the extra m_extraWidth + 1 added above
9610 wxCoord diff = sizeFit.x - size.x + (m_extraWidth + 1);
9611 if ( diff && m_numCols )
9612 {
9613 // try to resize the columns uniformly
9614 wxCoord diffPerCol = diff / m_numCols;
9615 if ( diffPerCol )
9616 {
9617 for ( int col = 0; col < m_numCols; col++ )
9618 {
9619 SetColSize(col, GetColWidth(col) + diffPerCol);
9620 }
9621 }
9622
9623 // add remaining amount to the last columns
9624 diff -= diffPerCol * m_numCols;
9625 if ( diff )
9626 {
9627 for ( int col = m_numCols - 1; col >= m_numCols - diff; col-- )
9628 {
9629 SetColSize(col, GetColWidth(col) + 1);
9630 }
9631 }
9632 }
9633
9634 // same for rows
9635 diff = sizeFit.y - size.y - (m_extraHeight + 1);
9636 if ( diff && m_numRows )
9637 {
9638 // try to resize the columns uniformly
9639 wxCoord diffPerRow = diff / m_numRows;
9640 if ( diffPerRow )
9641 {
9642 for ( int row = 0; row < m_numRows; row++ )
9643 {
9644 SetRowSize(row, GetRowHeight(row) + diffPerRow);
9645 }
9646 }
9647
9648 // add remaining amount to the last rows
9649 diff -= diffPerRow * m_numRows;
9650 if ( diff )
9651 {
9652 for ( int row = m_numRows - 1; row >= m_numRows - diff; row-- )
9653 {
9654 SetRowSize(row, GetRowHeight(row) + 1);
9655 }
9656 }
9657 }
9658
9659 EndBatch();
9660
9661 SetClientSize(sizeFit);
9662 }
9663
9664 void wxGrid::AutoSizeRowLabelSize( int row )
9665 {
9666 wxArrayString lines;
9667 long w, h;
9668
9669 // Hide the edit control, so it
9670 // won't interfer with drag-shrinking.
9671 if( IsCellEditControlShown() )
9672 {
9673 HideCellEditControl();
9674 SaveEditControlValue();
9675 }
9676
9677 // autosize row height depending on label text
9678 StringToLines( GetRowLabelValue( row ), lines );
9679 wxClientDC dc( m_rowLabelWin );
9680 GetTextBoxSize( dc, lines, &w, &h);
9681 if( h < m_defaultRowHeight )
9682 h = m_defaultRowHeight;
9683 SetRowSize(row, h);
9684 ForceRefresh();
9685 }
9686
9687 void wxGrid::AutoSizeColLabelSize( int col )
9688 {
9689 wxArrayString lines;
9690 long w, h;
9691
9692 // Hide the edit control, so it
9693 // won't interfer with drag-shrinking.
9694 if( IsCellEditControlShown() )
9695 {
9696 HideCellEditControl();
9697 SaveEditControlValue();
9698 }
9699
9700 // autosize column width depending on label text
9701 StringToLines( GetColLabelValue( col ), lines );
9702 wxClientDC dc( m_colLabelWin );
9703 if( GetColLabelTextOrientation() == wxHORIZONTAL )
9704 GetTextBoxSize( dc, lines, &w, &h);
9705 else
9706 GetTextBoxSize( dc, lines, &h, &w);
9707 if( w < m_defaultColWidth )
9708 w = m_defaultColWidth;
9709 SetColSize(col, w);
9710 ForceRefresh();
9711 }
9712
9713 wxSize wxGrid::DoGetBestSize() const
9714 {
9715 // don't set sizes, only calculate them
9716 wxGrid *self = (wxGrid *)this; // const_cast
9717
9718 int width, height;
9719 width = self->SetOrCalcColumnSizes(TRUE);
9720 height = self->SetOrCalcRowSizes(TRUE);
9721
9722 int maxwidth, maxheight;
9723 wxDisplaySize( & maxwidth, & maxheight );
9724
9725 if ( width > maxwidth ) width = maxwidth;
9726 if ( height > maxheight ) height = maxheight;
9727
9728 return wxSize( width, height );
9729 }
9730
9731 void wxGrid::Fit()
9732 {
9733 AutoSize();
9734 }
9735
9736
9737 wxPen& wxGrid::GetDividerPen() const
9738 {
9739 return wxNullPen;
9740 }
9741
9742 // ----------------------------------------------------------------------------
9743 // cell value accessor functions
9744 // ----------------------------------------------------------------------------
9745
9746 void wxGrid::SetCellValue( int row, int col, const wxString& s )
9747 {
9748 if ( m_table )
9749 {
9750 m_table->SetValue( row, col, s );
9751 if ( !GetBatchCount() )
9752 {
9753 int dummy;
9754 wxRect rect( CellToRect( row, col ) );
9755 rect.x = 0;
9756 rect.width = m_gridWin->GetClientSize().GetWidth();
9757 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
9758 m_gridWin->Refresh( FALSE, &rect );
9759 }
9760
9761 if ( m_currentCellCoords.GetRow() == row &&
9762 m_currentCellCoords.GetCol() == col &&
9763 IsCellEditControlShown())
9764 // Note: If we are using IsCellEditControlEnabled,
9765 // this interacts badly with calling SetCellValue from
9766 // an EVT_GRID_CELL_CHANGE handler.
9767 {
9768 HideCellEditControl();
9769 ShowCellEditControl(); // will reread data from table
9770 }
9771 }
9772 }
9773
9774
9775 //
9776 // ------ Block, row and col selection
9777 //
9778
9779 void wxGrid::SelectRow( int row, bool addToSelected )
9780 {
9781 if ( IsSelection() && !addToSelected )
9782 ClearSelection();
9783
9784 if ( m_selection )
9785 m_selection->SelectRow( row, FALSE, addToSelected );
9786 }
9787
9788
9789 void wxGrid::SelectCol( int col, bool addToSelected )
9790 {
9791 if ( IsSelection() && !addToSelected )
9792 ClearSelection();
9793
9794 if ( m_selection )
9795 m_selection->SelectCol( col, FALSE, addToSelected );
9796 }
9797
9798
9799 void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol,
9800 bool addToSelected )
9801 {
9802 if ( IsSelection() && !addToSelected )
9803 ClearSelection();
9804
9805 if ( m_selection )
9806 m_selection->SelectBlock( topRow, leftCol, bottomRow, rightCol,
9807 FALSE, addToSelected );
9808 }
9809
9810
9811 void wxGrid::SelectAll()
9812 {
9813 if ( m_numRows > 0 && m_numCols > 0 )
9814 {
9815 if ( m_selection )
9816 m_selection->SelectBlock( 0, 0, m_numRows-1, m_numCols-1 );
9817 }
9818 }
9819
9820 //
9821 // ------ Cell, row and col deselection
9822 //
9823
9824 void wxGrid::DeselectRow( int row )
9825 {
9826 if ( !m_selection )
9827 return;
9828
9829 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
9830 {
9831 if ( m_selection->IsInSelection(row, 0 ) )
9832 m_selection->ToggleCellSelection( row, 0);
9833 }
9834 else
9835 {
9836 int nCols = GetNumberCols();
9837 for ( int i = 0; i < nCols ; i++ )
9838 {
9839 if ( m_selection->IsInSelection(row, i ) )
9840 m_selection->ToggleCellSelection( row, i);
9841 }
9842 }
9843 }
9844
9845 void wxGrid::DeselectCol( int col )
9846 {
9847 if ( !m_selection )
9848 return;
9849
9850 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
9851 {
9852 if ( m_selection->IsInSelection(0, col ) )
9853 m_selection->ToggleCellSelection( 0, col);
9854 }
9855 else
9856 {
9857 int nRows = GetNumberRows();
9858 for ( int i = 0; i < nRows ; i++ )
9859 {
9860 if ( m_selection->IsInSelection(i, col ) )
9861 m_selection->ToggleCellSelection(i, col);
9862 }
9863 }
9864 }
9865
9866 void wxGrid::DeselectCell( int row, int col )
9867 {
9868 if ( m_selection && m_selection->IsInSelection(row, col) )
9869 m_selection->ToggleCellSelection(row, col);
9870 }
9871
9872 bool wxGrid::IsSelection()
9873 {
9874 return ( m_selection && (m_selection->IsSelection() ||
9875 ( m_selectingTopLeft != wxGridNoCellCoords &&
9876 m_selectingBottomRight != wxGridNoCellCoords) ) );
9877 }
9878
9879 bool wxGrid::IsInSelection( int row, int col ) const
9880 {
9881 return ( m_selection && (m_selection->IsInSelection( row, col ) ||
9882 ( row >= m_selectingTopLeft.GetRow() &&
9883 col >= m_selectingTopLeft.GetCol() &&
9884 row <= m_selectingBottomRight.GetRow() &&
9885 col <= m_selectingBottomRight.GetCol() )) );
9886 }
9887
9888 wxGridCellCoordsArray wxGrid::GetSelectedCells() const
9889 {
9890 if (!m_selection) { wxGridCellCoordsArray a; return a; }
9891 return m_selection->m_cellSelection;
9892 }
9893 wxGridCellCoordsArray wxGrid::GetSelectionBlockTopLeft() const
9894 {
9895 if (!m_selection) { wxGridCellCoordsArray a; return a; }
9896 return m_selection->m_blockSelectionTopLeft;
9897 }
9898 wxGridCellCoordsArray wxGrid::GetSelectionBlockBottomRight() const
9899 {
9900 if (!m_selection) { wxGridCellCoordsArray a; return a; }
9901 return m_selection->m_blockSelectionBottomRight;
9902 }
9903 wxArrayInt wxGrid::GetSelectedRows() const
9904 {
9905 if (!m_selection) { wxArrayInt a; return a; }
9906 return m_selection->m_rowSelection;
9907 }
9908 wxArrayInt wxGrid::GetSelectedCols() const
9909 {
9910 if (!m_selection) { wxArrayInt a; return a; }
9911 return m_selection->m_colSelection;
9912 }
9913
9914
9915 void wxGrid::ClearSelection()
9916 {
9917 m_selectingTopLeft = wxGridNoCellCoords;
9918 m_selectingBottomRight = wxGridNoCellCoords;
9919 if ( m_selection )
9920 m_selection->ClearSelection();
9921 }
9922
9923
9924 // This function returns the rectangle that encloses the given block
9925 // in device coords clipped to the client size of the grid window.
9926 //
9927 wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
9928 const wxGridCellCoords &bottomRight )
9929 {
9930 wxRect rect( wxGridNoCellRect );
9931 wxRect cellRect;
9932
9933 cellRect = CellToRect( topLeft );
9934 if ( cellRect != wxGridNoCellRect )
9935 {
9936 rect = cellRect;
9937 }
9938 else
9939 {
9940 rect = wxRect( 0, 0, 0, 0 );
9941 }
9942
9943 cellRect = CellToRect( bottomRight );
9944 if ( cellRect != wxGridNoCellRect )
9945 {
9946 rect += cellRect;
9947 }
9948 else
9949 {
9950 return wxGridNoCellRect;
9951 }
9952
9953 int i, j;
9954 int left = rect.GetLeft();
9955 int top = rect.GetTop();
9956 int right = rect.GetRight();
9957 int bottom = rect.GetBottom();
9958
9959 int leftCol = topLeft.GetCol();
9960 int topRow = topLeft.GetRow();
9961 int rightCol = bottomRight.GetCol();
9962 int bottomRow = bottomRight.GetRow();
9963
9964 if (left > right)
9965 {
9966 i = left;
9967 left = right;
9968 right = i;
9969 i = leftCol;
9970 leftCol=rightCol;
9971 rightCol = i;
9972 }
9973
9974 if (top > bottom)
9975 {
9976 i = top;
9977 top = bottom;
9978 bottom = i;
9979 i = topRow;
9980 topRow = bottomRow;
9981 bottomRow = i;
9982 }
9983
9984
9985 for ( j = topRow; j <= bottomRow; j++ )
9986 {
9987 for ( i = leftCol; i <= rightCol; i++ )
9988 {
9989 if ((j==topRow) || (j==bottomRow) || (i==leftCol) || (i==rightCol))
9990 {
9991 cellRect = CellToRect( j, i );
9992
9993 if (cellRect.x < left)
9994 left = cellRect.x;
9995 if (cellRect.y < top)
9996 top = cellRect.y;
9997 if (cellRect.x + cellRect.width > right)
9998 right = cellRect.x + cellRect.width;
9999 if (cellRect.y + cellRect.height > bottom)
10000 bottom = cellRect.y + cellRect.height;
10001 }
10002 else i = rightCol; // jump over inner cells.
10003 }
10004 }
10005
10006 // convert to scrolled coords
10007 //
10008 CalcScrolledPosition( left, top, &left, &top );
10009 CalcScrolledPosition( right, bottom, &right, &bottom );
10010
10011 int cw, ch;
10012 m_gridWin->GetClientSize( &cw, &ch );
10013
10014 if (right < 0 || bottom < 0 || left > cw || top > ch)
10015 return wxRect( 0, 0, 0, 0);
10016
10017 rect.SetLeft( wxMax(0, left) );
10018 rect.SetTop( wxMax(0, top) );
10019 rect.SetRight( wxMin(cw, right) );
10020 rect.SetBottom( wxMin(ch, bottom) );
10021
10022 return rect;
10023 }
10024
10025 //
10026 // ------ Grid event classes
10027 //
10028
10029 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxNotifyEvent )
10030
10031 wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
10032 int row, int col, int x, int y, bool sel,
10033 bool control, bool shift, bool alt, bool meta )
10034 : wxNotifyEvent( type, id )
10035 {
10036 m_row = row;
10037 m_col = col;
10038 m_x = x;
10039 m_y = y;
10040 m_selecting = sel;
10041 m_control = control;
10042 m_shift = shift;
10043 m_alt = alt;
10044 m_meta = meta;
10045
10046 SetEventObject(obj);
10047 }
10048
10049
10050 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxNotifyEvent )
10051
10052 wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
10053 int rowOrCol, int x, int y,
10054 bool control, bool shift, bool alt, bool meta )
10055 : wxNotifyEvent( type, id )
10056 {
10057 m_rowOrCol = rowOrCol;
10058 m_x = x;
10059 m_y = y;
10060 m_control = control;
10061 m_shift = shift;
10062 m_alt = alt;
10063 m_meta = meta;
10064
10065 SetEventObject(obj);
10066 }
10067
10068
10069 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxNotifyEvent )
10070
10071 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
10072 const wxGridCellCoords& topLeft,
10073 const wxGridCellCoords& bottomRight,
10074 bool sel, bool control,
10075 bool shift, bool alt, bool meta )
10076 : wxNotifyEvent( type, id )
10077 {
10078 m_topLeft = topLeft;
10079 m_bottomRight = bottomRight;
10080 m_selecting = sel;
10081 m_control = control;
10082 m_shift = shift;
10083 m_alt = alt;
10084 m_meta = meta;
10085
10086 SetEventObject(obj);
10087 }
10088
10089
10090 IMPLEMENT_DYNAMIC_CLASS(wxGridEditorCreatedEvent, wxCommandEvent)
10091
10092 wxGridEditorCreatedEvent::wxGridEditorCreatedEvent(int id, wxEventType type,
10093 wxObject* obj, int row,
10094 int col, wxControl* ctrl)
10095 : wxCommandEvent(type, id)
10096 {
10097 SetEventObject(obj);
10098 m_row = row;
10099 m_col = col;
10100 m_ctrl = ctrl;
10101 }
10102
10103 #endif // wxUSE_GRID
10104