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