1. added range checks in wxGridStringTable
[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:
6 // Created: 1/08/1999
7 // RCS-ID: $Id$
8 // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "grid.h"
22 #endif
23
24 // For compilers that support precompilation, 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 !defined(wxUSE_NEW_GRID) || !(wxUSE_NEW_GRID)
34 #include "gridg.cpp"
35 #else
36
37 #ifndef WX_PRECOMP
38 #include "wx/utils.h"
39 #include "wx/dcclient.h"
40 #include "wx/settings.h"
41 #include "wx/log.h"
42 #include "wx/textctrl.h"
43 #include "wx/checkbox.h"
44 #include "wx/combobox.h"
45 #include "wx/valtext.h"
46 #endif
47
48 #include "wx/textfile.h"
49 #include "wx/spinctrl.h"
50
51 #include "wx/grid.h"
52
53 // ----------------------------------------------------------------------------
54 // array classes
55 // ----------------------------------------------------------------------------
56
57 WX_DEFINE_ARRAY(wxGridCellAttr *, wxArrayAttrs);
58
59 struct wxGridCellWithAttr
60 {
61 wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_)
62 : coords(row, col), attr(attr_)
63 {
64 }
65
66 ~wxGridCellWithAttr()
67 {
68 attr->DecRef();
69 }
70
71 wxGridCellCoords coords;
72 wxGridCellAttr *attr;
73 };
74
75 WX_DECLARE_OBJARRAY(wxGridCellWithAttr, wxGridCellWithAttrArray);
76
77 #include "wx/arrimpl.cpp"
78
79 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
80 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
81
82 // ----------------------------------------------------------------------------
83 // private classes
84 // ----------------------------------------------------------------------------
85
86 class WXDLLEXPORT wxGridRowLabelWindow : public wxWindow
87 {
88 public:
89 wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; }
90 wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
91 const wxPoint &pos, const wxSize &size );
92
93 private:
94 wxGrid *m_owner;
95
96 void OnPaint( wxPaintEvent& event );
97 void OnMouseEvent( wxMouseEvent& event );
98 void OnKeyDown( wxKeyEvent& event );
99
100 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
101 DECLARE_EVENT_TABLE()
102 };
103
104
105 class WXDLLEXPORT wxGridColLabelWindow : public wxWindow
106 {
107 public:
108 wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; }
109 wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
110 const wxPoint &pos, const wxSize &size );
111
112 private:
113 wxGrid *m_owner;
114
115 void OnPaint( wxPaintEvent &event );
116 void OnMouseEvent( wxMouseEvent& event );
117 void OnKeyDown( wxKeyEvent& event );
118
119 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
120 DECLARE_EVENT_TABLE()
121 };
122
123
124 class WXDLLEXPORT wxGridCornerLabelWindow : public wxWindow
125 {
126 public:
127 wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; }
128 wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
129 const wxPoint &pos, const wxSize &size );
130
131 private:
132 wxGrid *m_owner;
133
134 void OnMouseEvent( wxMouseEvent& event );
135 void OnKeyDown( wxKeyEvent& event );
136 void OnPaint( wxPaintEvent& event );
137
138 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
139 DECLARE_EVENT_TABLE()
140 };
141
142 class WXDLLEXPORT wxGridWindow : public wxPanel
143 {
144 public:
145 wxGridWindow()
146 {
147 m_owner = (wxGrid *)NULL;
148 m_rowLabelWin = (wxGridRowLabelWindow *)NULL;
149 m_colLabelWin = (wxGridColLabelWindow *)NULL;
150 }
151
152 wxGridWindow( wxGrid *parent,
153 wxGridRowLabelWindow *rowLblWin,
154 wxGridColLabelWindow *colLblWin,
155 wxWindowID id, const wxPoint &pos, const wxSize &size );
156 ~wxGridWindow();
157
158 void ScrollWindow( int dx, int dy, const wxRect *rect );
159
160 private:
161 wxGrid *m_owner;
162 wxGridRowLabelWindow *m_rowLabelWin;
163 wxGridColLabelWindow *m_colLabelWin;
164
165 void OnPaint( wxPaintEvent &event );
166 void OnMouseEvent( wxMouseEvent& event );
167 void OnKeyDown( wxKeyEvent& );
168 void OnEraseBackground( wxEraseEvent& );
169
170
171 DECLARE_DYNAMIC_CLASS(wxGridWindow)
172 DECLARE_EVENT_TABLE()
173 };
174
175
176
177 class wxGridCellEditorEvtHandler : public wxEvtHandler
178 {
179 public:
180 wxGridCellEditorEvtHandler()
181 : m_grid(0), m_editor(0)
182 { }
183 wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor)
184 : m_grid(grid), m_editor(editor)
185 { }
186
187 void OnKeyDown(wxKeyEvent& event);
188 void OnChar(wxKeyEvent& event);
189
190 private:
191 wxGrid* m_grid;
192 wxGridCellEditor* m_editor;
193 DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler)
194 DECLARE_EVENT_TABLE()
195 };
196
197
198 IMPLEMENT_DYNAMIC_CLASS( wxGridCellEditorEvtHandler, wxEvtHandler )
199 BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler )
200 EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown )
201 EVT_CHAR( wxGridCellEditorEvtHandler::OnChar )
202 END_EVENT_TABLE()
203
204
205
206 // ----------------------------------------------------------------------------
207 // the internal data representation used by wxGridCellAttrProvider
208 // ----------------------------------------------------------------------------
209
210 // this class stores attributes set for cells
211 class WXDLLEXPORT wxGridCellAttrData
212 {
213 public:
214 void SetAttr(wxGridCellAttr *attr, int row, int col);
215 wxGridCellAttr *GetAttr(int row, int col) const;
216 void UpdateAttrRows( size_t pos, int numRows );
217 void UpdateAttrCols( size_t pos, int numCols );
218
219 private:
220 // searches for the attr for given cell, returns wxNOT_FOUND if not found
221 int FindIndex(int row, int col) const;
222
223 wxGridCellWithAttrArray m_attrs;
224 };
225
226 // this class stores attributes set for rows or columns
227 class WXDLLEXPORT wxGridRowOrColAttrData
228 {
229 public:
230 // empty ctor to suppress warnings
231 wxGridRowOrColAttrData() { }
232 ~wxGridRowOrColAttrData();
233
234 void SetAttr(wxGridCellAttr *attr, int rowOrCol);
235 wxGridCellAttr *GetAttr(int rowOrCol) const;
236 void UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols );
237
238 private:
239 wxArrayInt m_rowsOrCols;
240 wxArrayAttrs m_attrs;
241 };
242
243 // NB: this is just a wrapper around 3 objects: one which stores cell
244 // attributes, and 2 others for row/col ones
245 class WXDLLEXPORT wxGridCellAttrProviderData
246 {
247 public:
248 wxGridCellAttrData m_cellAttrs;
249 wxGridRowOrColAttrData m_rowAttrs,
250 m_colAttrs;
251 };
252
253
254 // ----------------------------------------------------------------------------
255 // data structures used for the data type registry
256 // ----------------------------------------------------------------------------
257
258 struct wxGridDataTypeInfo
259 {
260 wxGridDataTypeInfo(const wxString& typeName,
261 wxGridCellRenderer* renderer,
262 wxGridCellEditor* editor)
263 : m_typeName(typeName), m_renderer(renderer), m_editor(editor)
264 { }
265
266 ~wxGridDataTypeInfo() { delete m_renderer; delete m_editor; }
267
268 wxString m_typeName;
269 wxGridCellRenderer* m_renderer;
270 wxGridCellEditor* m_editor;
271 };
272
273
274 WX_DEFINE_ARRAY(wxGridDataTypeInfo*, wxGridDataTypeInfoArray);
275
276
277 class WXDLLEXPORT wxGridTypeRegistry
278 {
279 public:
280 ~wxGridTypeRegistry();
281
282 void RegisterDataType(const wxString& typeName,
283 wxGridCellRenderer* renderer,
284 wxGridCellEditor* editor);
285 int FindDataType(const wxString& typeName);
286 wxGridCellRenderer* GetRenderer(int index);
287 wxGridCellEditor* GetEditor(int index);
288
289 private:
290 wxGridDataTypeInfoArray m_typeinfo;
291 };
292
293 // ----------------------------------------------------------------------------
294 // conditional compilation
295 // ----------------------------------------------------------------------------
296
297 #ifndef WXGRID_DRAW_LINES
298 #define WXGRID_DRAW_LINES 1
299 #endif
300
301 // ----------------------------------------------------------------------------
302 // globals
303 // ----------------------------------------------------------------------------
304
305 //#define DEBUG_ATTR_CACHE
306 #ifdef DEBUG_ATTR_CACHE
307 static size_t gs_nAttrCacheHits = 0;
308 static size_t gs_nAttrCacheMisses = 0;
309 #endif // DEBUG_ATTR_CACHE
310
311 // ----------------------------------------------------------------------------
312 // constants
313 // ----------------------------------------------------------------------------
314
315 wxGridCellCoords wxGridNoCellCoords( -1, -1 );
316 wxRect wxGridNoCellRect( -1, -1, -1, -1 );
317
318 // scroll line size
319 // TODO: fixed so far - make configurable later (and also different for x/y)
320 static const size_t GRID_SCROLL_LINE = 10;
321
322 // the size of hash tables used a bit everywhere (the max number of elements
323 // in these hash tables is the number of rows/columns)
324 static const int GRID_HASH_SIZE = 100;
325
326 // ============================================================================
327 // implementation
328 // ============================================================================
329
330 // ----------------------------------------------------------------------------
331 // wxGridCellEditor
332 // ----------------------------------------------------------------------------
333
334 wxGridCellEditor::wxGridCellEditor()
335 {
336 m_control = NULL;
337 }
338
339
340 wxGridCellEditor::~wxGridCellEditor()
341 {
342 Destroy();
343 }
344
345 void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
346 wxWindowID WXUNUSED(id),
347 wxEvtHandler* evtHandler)
348 {
349 if ( evtHandler )
350 m_control->PushEventHandler(evtHandler);
351 }
352
353 void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
354 wxGridCellAttr *attr)
355 {
356 // erase the background because we might not fill the cell
357 wxClientDC dc(m_control->GetParent());
358 dc.SetPen(*wxTRANSPARENT_PEN);
359 dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
360 dc.DrawRectangle(rectCell);
361
362 // redraw the control we just painted over
363 m_control->Refresh();
364 }
365
366 void wxGridCellEditor::Destroy()
367 {
368 if (m_control)
369 {
370 m_control->PopEventHandler(TRUE /* delete it*/);
371
372 m_control->Destroy();
373 m_control = NULL;
374 }
375 }
376
377 void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
378 {
379 wxASSERT_MSG(m_control,
380 wxT("The wxGridCellEditor must be Created first!"));
381 m_control->Show(show);
382
383 if ( show )
384 {
385 // set the colours/fonts if we have any
386 if ( attr )
387 {
388 m_colFgOld = m_control->GetForegroundColour();
389 m_control->SetForegroundColour(attr->GetTextColour());
390
391 m_colBgOld = m_control->GetBackgroundColour();
392 m_control->SetBackgroundColour(attr->GetBackgroundColour());
393
394 m_fontOld = m_control->GetFont();
395 m_control->SetFont(attr->GetFont());
396
397 // can't do anything more in the base class version, the other
398 // attributes may only be used by the derived classes
399 }
400 }
401 else
402 {
403 // restore the standard colours fonts
404 if ( m_colFgOld.Ok() )
405 {
406 m_control->SetForegroundColour(m_colFgOld);
407 m_colFgOld = wxNullColour;
408 }
409
410 if ( m_colBgOld.Ok() )
411 {
412 m_control->SetBackgroundColour(m_colBgOld);
413 m_colBgOld = wxNullColour;
414 }
415
416 if ( m_fontOld.Ok() )
417 {
418 m_control->SetFont(m_fontOld);
419 m_fontOld = wxNullFont;
420 }
421 }
422 }
423
424 void wxGridCellEditor::SetSize(const wxRect& rect)
425 {
426 wxASSERT_MSG(m_control,
427 wxT("The wxGridCellEditor must be Created first!"));
428 m_control->SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
429 }
430
431 void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
432 {
433 event.Skip();
434 }
435
436
437 void wxGridCellEditor::StartingKey(wxKeyEvent& event)
438 {
439 event.Skip();
440 }
441
442 void wxGridCellEditor::StartingClick()
443 {
444 }
445
446 // ----------------------------------------------------------------------------
447 // wxGridCellTextEditor
448 // ----------------------------------------------------------------------------
449
450 wxGridCellTextEditor::wxGridCellTextEditor()
451 {
452 }
453
454 void wxGridCellTextEditor::Create(wxWindow* parent,
455 wxWindowID id,
456 wxEvtHandler* evtHandler)
457 {
458 m_control = new wxTextCtrl(parent, id, wxEmptyString,
459 wxDefaultPosition, wxDefaultSize
460 #if defined(__WXMSW__)
461 , wxTE_MULTILINE | wxTE_NO_VSCROLL // necessary ???
462 #endif
463 );
464
465 wxGridCellEditor::Create(parent, id, evtHandler);
466 }
467
468 void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell),
469 wxGridCellAttr * WXUNUSED(attr))
470 {
471 // as we fill the entire client area, don't do anything here to minimize
472 // flicker
473 }
474
475 void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
476 {
477 wxRect rect(rectOrig);
478
479 // Make the edit control large enough to allow for internal
480 // margins
481 //
482 // TODO: remove this if the text ctrl sizing is improved esp. for
483 // unix
484 //
485 #if defined(__WXGTK__)
486 if (rect.x != 0)
487 {
488 rect.x += 1;
489 rect.y += 1;
490 rect.width -= 1;
491 rect.height -= 1;
492 }
493 #else // !GTK
494 int extra_x = ( rect.x > 2 )? 2 : 1;
495 int extra_y = ( rect.y > 2 )? 2 : 1;
496 #if defined(__WXMOTIF__)
497 extra_x *= 2;
498 extra_y *= 2;
499 #endif
500 rect.SetLeft( wxMax(0, rect.x - extra_x) );
501 rect.SetTop( wxMax(0, rect.y - extra_y) );
502 rect.SetRight( rect.GetRight() + 2*extra_x );
503 rect.SetBottom( rect.GetBottom() + 2*extra_y );
504 #endif // GTK/!GTK
505
506 wxGridCellEditor::SetSize(rect);
507 }
508
509 void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid)
510 {
511 wxASSERT_MSG(m_control,
512 wxT("The wxGridCellEditor must be Created first!"));
513
514 m_startValue = grid->GetTable()->GetValue(row, col);
515
516 DoBeginEdit(m_startValue);
517 }
518
519 void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
520 {
521 Text()->SetValue(startValue);
522 Text()->SetInsertionPointEnd();
523 Text()->SetFocus();
524 }
525
526 bool wxGridCellTextEditor::EndEdit(int row, int col,
527 wxGrid* grid)
528 {
529 wxASSERT_MSG(m_control,
530 wxT("The wxGridCellEditor must be Created first!"));
531
532 bool changed = FALSE;
533 wxString value = Text()->GetValue();
534 if (value != m_startValue)
535 changed = TRUE;
536
537 if (changed)
538 grid->GetTable()->SetValue(row, col, value);
539
540 m_startValue = wxEmptyString;
541 Text()->SetValue(m_startValue);
542
543 return changed;
544 }
545
546
547 void wxGridCellTextEditor::Reset()
548 {
549 wxASSERT_MSG(m_control,
550 wxT("The wxGridCellEditor must be Created first!"));
551
552 DoReset(m_startValue);
553 }
554
555 void wxGridCellTextEditor::DoReset(const wxString& startValue)
556 {
557 Text()->SetValue(startValue);
558 Text()->SetInsertionPointEnd();
559 }
560
561 void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
562 {
563 if ( !event.AltDown() && !event.MetaDown() && !event.ControlDown() )
564 {
565 // insert the key in the control
566 long keycode = event.KeyCode();
567 if ( isprint(keycode) )
568 {
569 // FIXME this is not going to work for non letters...
570 if ( !event.ShiftDown() )
571 {
572 keycode = tolower(keycode);
573 }
574
575 Text()->AppendText((wxChar)keycode);
576
577 return;
578 }
579
580 }
581
582 event.Skip();
583 }
584
585 void wxGridCellTextEditor::HandleReturn(wxKeyEvent& event)
586 {
587 #if defined(__WXMOTIF__) || defined(__WXGTK__)
588 // wxMotif needs a little extra help...
589 int pos = Text()->GetInsertionPoint();
590 wxString s( Text()->GetValue() );
591 s = s.Left(pos) + "\n" + s.Mid(pos);
592 Text()->SetValue(s);
593 Text()->SetInsertionPoint( pos );
594 #else
595 // the other ports can handle a Return key press
596 //
597 event.Skip();
598 #endif
599 }
600
601 // ----------------------------------------------------------------------------
602 // wxGridCellNumberEditor
603 // ----------------------------------------------------------------------------
604
605 wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max)
606 {
607 m_min = min;
608 m_max = max;
609 }
610
611 void wxGridCellNumberEditor::Create(wxWindow* parent,
612 wxWindowID id,
613 wxEvtHandler* evtHandler)
614 {
615 if ( HasRange() )
616 {
617 // create a spin ctrl
618 m_control = new wxSpinCtrl(parent, -1, wxEmptyString,
619 wxDefaultPosition, wxDefaultSize,
620 wxSP_ARROW_KEYS,
621 m_min, m_max);
622
623 wxGridCellEditor::Create(parent, id, evtHandler);
624 }
625 else
626 {
627 // just a text control
628 wxGridCellTextEditor::Create(parent, id, evtHandler);
629
630 #if wxUSE_VALIDATORS
631 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
632 #endif // wxUSE_VALIDATORS
633 }
634 }
635
636 void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
637 {
638 // first get the value
639 wxGridTableBase *table = grid->GetTable();
640 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
641 {
642 m_valueOld = table->GetValueAsLong(row, col);
643 }
644 else
645 {
646 wxString sValue = table->GetValue(row, col);
647 if (! sValue.ToLong(&m_valueOld))
648 {
649 wxFAIL_MSG( _T("this cell doesn't have numeric value") );
650 return;
651 }
652 }
653
654 if ( HasRange() )
655 {
656 Spin()->SetValue(m_valueOld);
657 }
658 else
659 {
660 DoBeginEdit(GetString());
661 }
662 }
663
664 bool wxGridCellNumberEditor::EndEdit(int row, int col,
665 wxGrid* grid)
666 {
667 bool changed;
668 long value;
669
670 if ( HasRange() )
671 {
672 value = Spin()->GetValue();
673 changed = value != m_valueOld;
674 }
675 else
676 {
677 changed = Text()->GetValue().ToLong(&value) && (value != m_valueOld);
678 }
679
680 if ( changed )
681 {
682 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
683 grid->GetTable()->SetValueAsLong(row, col, value);
684 else
685 grid->GetTable()->SetValue(row, col, wxString::Format("%ld", value));
686 }
687
688 return changed;
689 }
690
691 void wxGridCellNumberEditor::Reset()
692 {
693 if ( HasRange() )
694 {
695 Spin()->SetValue(m_valueOld);
696 }
697 else
698 {
699 DoReset(GetString());
700 }
701 }
702
703 void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event)
704 {
705 if ( !HasRange() )
706 {
707 long keycode = event.KeyCode();
708 if ( isdigit(keycode) || keycode == '+' || keycode == '-' )
709 {
710 wxGridCellTextEditor::StartingKey(event);
711
712 // skip Skip() below
713 return;
714 }
715 }
716
717 event.Skip();
718 }
719
720 // ----------------------------------------------------------------------------
721 // wxGridCellFloatEditor
722 // ----------------------------------------------------------------------------
723
724 void wxGridCellFloatEditor::Create(wxWindow* parent,
725 wxWindowID id,
726 wxEvtHandler* evtHandler)
727 {
728 wxGridCellTextEditor::Create(parent, id, evtHandler);
729
730 #if wxUSE_VALIDATORS
731 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
732 #endif // wxUSE_VALIDATORS
733 }
734
735 void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid)
736 {
737 // first get the value
738 wxGridTableBase *table = grid->GetTable();
739 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
740 {
741 m_valueOld = table->GetValueAsDouble(row, col);
742 }
743 else
744 {
745 wxString sValue = table->GetValue(row, col);
746 if (! sValue.ToDouble(&m_valueOld))
747 {
748 wxFAIL_MSG( _T("this cell doesn't have float value") );
749 return;
750 }
751 }
752
753 DoBeginEdit(GetString());
754 }
755
756 bool wxGridCellFloatEditor::EndEdit(int row, int col,
757 wxGrid* grid)
758 {
759 double value;
760 if ( Text()->GetValue().ToDouble(&value) && (value != m_valueOld) )
761 {
762 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT))
763 grid->GetTable()->SetValueAsDouble(row, col, value);
764 else
765 grid->GetTable()->SetValue(row, col, wxString::Format("%f", value));
766
767 return TRUE;
768 }
769 else
770 {
771 return FALSE;
772 }
773 }
774
775 void wxGridCellFloatEditor::Reset()
776 {
777 DoReset(GetString());
778 }
779
780 void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
781 {
782 long keycode = event.KeyCode();
783 if ( isdigit(keycode) ||
784 keycode == '+' || keycode == '-' || keycode == '.' )
785 {
786 wxGridCellTextEditor::StartingKey(event);
787
788 // skip Skip() below
789 return;
790 }
791
792 event.Skip();
793 }
794
795 // ----------------------------------------------------------------------------
796 // wxGridCellBoolEditor
797 // ----------------------------------------------------------------------------
798
799 void wxGridCellBoolEditor::Create(wxWindow* parent,
800 wxWindowID id,
801 wxEvtHandler* evtHandler)
802 {
803 m_control = new wxCheckBox(parent, id, wxEmptyString,
804 wxDefaultPosition, wxDefaultSize,
805 wxNO_BORDER);
806
807 wxGridCellEditor::Create(parent, id, evtHandler);
808 }
809
810 void wxGridCellBoolEditor::SetSize(const wxRect& r)
811 {
812 bool resize = FALSE;
813 wxSize size = m_control->GetSize();
814 wxCoord minSize = wxMin(r.width, r.height);
815
816 // check if the checkbox is not too big/small for this cell
817 wxSize sizeBest = m_control->GetBestSize();
818 if ( !(size == sizeBest) )
819 {
820 // reset to default size if it had been made smaller
821 size = sizeBest;
822
823 resize = TRUE;
824 }
825
826 if ( size.x >= minSize || size.y >= minSize )
827 {
828 // leave 1 pixel margin
829 size.x = size.y = minSize - 2;
830
831 resize = TRUE;
832 }
833
834 if ( resize )
835 {
836 m_control->SetSize(size);
837 }
838
839 // position it in the centre of the rectangle (TODO: support alignment?)
840
841 #if defined(__WXGTK__) || defined (__WXMOTIF__)
842 // the checkbox without label still has some space to the right in wxGTK,
843 // so shift it to the right
844 size.x -= 8;
845 #elif defined(__WXMSW__)
846 // here too...
847 size.x -= 6;
848 size.y -= 2;
849 #endif
850
851 m_control->Move(r.x + r.width/2 - size.x/2, r.y + r.height/2 - size.y/2);
852 }
853
854 void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
855 {
856 m_control->Show(show);
857
858 if ( show )
859 {
860 wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
861 CBox()->SetBackgroundColour(colBg);
862 }
863 }
864
865 void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid)
866 {
867 wxASSERT_MSG(m_control,
868 wxT("The wxGridCellEditor must be Created first!"));
869
870 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
871 m_startValue = grid->GetTable()->GetValueAsBool(row, col);
872 else
873 m_startValue = !!grid->GetTable()->GetValue(row, col);
874 CBox()->SetValue(m_startValue);
875 CBox()->SetFocus();
876 }
877
878 bool wxGridCellBoolEditor::EndEdit(int row, int col,
879 wxGrid* grid)
880 {
881 wxASSERT_MSG(m_control,
882 wxT("The wxGridCellEditor must be Created first!"));
883
884 bool changed = FALSE;
885 bool value = CBox()->GetValue();
886 if ( value != m_startValue )
887 changed = TRUE;
888
889 if ( changed )
890 {
891 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
892 grid->GetTable()->SetValueAsBool(row, col, value);
893 else
894 grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString);
895 }
896
897 return changed;
898 }
899
900 void wxGridCellBoolEditor::Reset()
901 {
902 wxASSERT_MSG(m_control,
903 wxT("The wxGridCellEditor must be Created first!"));
904
905 CBox()->SetValue(m_startValue);
906 }
907
908 void wxGridCellBoolEditor::StartingClick()
909 {
910 CBox()->SetValue(!CBox()->GetValue());
911 }
912
913 // ----------------------------------------------------------------------------
914 // wxGridCellChoiceEditor
915 // ----------------------------------------------------------------------------
916
917 wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count,
918 const wxChar* choices[],
919 bool allowOthers)
920 : m_allowOthers(allowOthers)
921 {
922 m_choices.Alloc(count);
923 for ( size_t n = 0; n < count; n++ )
924 {
925 m_choices.Add(choices[n]);
926 }
927 }
928
929 void wxGridCellChoiceEditor::Create(wxWindow* parent,
930 wxWindowID id,
931 wxEvtHandler* evtHandler)
932 {
933 size_t count = m_choices.GetCount();
934 wxString *choices = new wxString[count];
935 for ( size_t n = 0; n < count; n++ )
936 {
937 choices[n] = m_choices[n];
938 }
939
940 m_control = new wxComboBox(parent, id, wxEmptyString,
941 wxDefaultPosition, wxDefaultSize,
942 count, choices,
943 m_allowOthers ? 0 : wxCB_READONLY);
944
945 delete [] choices;
946
947 wxGridCellEditor::Create(parent, id, evtHandler);
948 }
949
950 void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
951 wxGridCellAttr * attr)
952 {
953 // as we fill the entire client area, don't do anything here to minimize
954 // flicker
955
956 // TODO: It doesn't actually fill the client area since the height of a
957 // combo always defaults to the standard... Until someone has time to
958 // figure out the right rectangle to paint, just do it the normal way...
959 wxGridCellEditor::PaintBackground(rectCell, attr);
960 }
961
962 void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
963 {
964 wxASSERT_MSG(m_control,
965 wxT("The wxGridCellEditor must be Created first!"));
966
967 m_startValue = grid->GetTable()->GetValue(row, col);
968
969 Combo()->SetValue(m_startValue);
970 size_t count = m_choices.GetCount();
971 for (size_t i=0; i<count; i++)
972 {
973 if (m_startValue == m_choices[i])
974 {
975 Combo()->SetSelection(i);
976 break;
977 }
978 }
979 Combo()->SetInsertionPointEnd();
980 Combo()->SetFocus();
981 }
982
983 bool wxGridCellChoiceEditor::EndEdit(int row, int col,
984 wxGrid* grid)
985 {
986 wxString value = Combo()->GetValue();
987 bool changed = value != m_startValue;
988
989 if ( changed )
990 grid->GetTable()->SetValue(row, col, value);
991
992 m_startValue = wxEmptyString;
993 Combo()->SetValue(m_startValue);
994
995 return changed;
996 }
997
998 void wxGridCellChoiceEditor::Reset()
999 {
1000 Combo()->SetValue(m_startValue);
1001 Combo()->SetInsertionPointEnd();
1002 }
1003
1004 // ----------------------------------------------------------------------------
1005 // wxGridCellEditorEvtHandler
1006 // ----------------------------------------------------------------------------
1007
1008 void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
1009 {
1010 switch ( event.KeyCode() )
1011 {
1012 case WXK_ESCAPE:
1013 m_editor->Reset();
1014 m_grid->DisableCellEditControl();
1015 break;
1016
1017 case WXK_TAB:
1018 event.Skip( m_grid->ProcessEvent( event ) );
1019 break;
1020
1021 case WXK_RETURN:
1022 if (!m_grid->ProcessEvent(event))
1023 m_editor->HandleReturn(event);
1024 break;
1025
1026
1027 default:
1028 event.Skip();
1029 }
1030 }
1031
1032 void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event)
1033 {
1034 switch ( event.KeyCode() )
1035 {
1036 case WXK_ESCAPE:
1037 case WXK_TAB:
1038 case WXK_RETURN:
1039 break;
1040
1041 default:
1042 event.Skip();
1043 }
1044 }
1045
1046 // ============================================================================
1047 // renderer classes
1048 // ============================================================================
1049
1050 // ----------------------------------------------------------------------------
1051 // wxGridCellRenderer
1052 // ----------------------------------------------------------------------------
1053
1054 void wxGridCellRenderer::Draw(wxGrid& grid,
1055 wxGridCellAttr& attr,
1056 wxDC& dc,
1057 const wxRect& rect,
1058 int row, int col,
1059 bool isSelected)
1060 {
1061 dc.SetBackgroundMode( wxSOLID );
1062
1063 if ( isSelected )
1064 {
1065 dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) );
1066 }
1067 else
1068 {
1069 dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) );
1070 }
1071
1072 dc.SetPen( *wxTRANSPARENT_PEN );
1073 dc.DrawRectangle(rect);
1074 }
1075
1076 wxGridCellRenderer::~wxGridCellRenderer()
1077 {
1078 }
1079
1080 // ----------------------------------------------------------------------------
1081 // wxGridCellStringRenderer
1082 // ----------------------------------------------------------------------------
1083
1084 void wxGridCellStringRenderer::SetTextColoursAndFont(wxGrid& grid,
1085 wxGridCellAttr& attr,
1086 wxDC& dc,
1087 bool isSelected)
1088 {
1089 dc.SetBackgroundMode( wxTRANSPARENT );
1090
1091 // TODO some special colours for attr.IsReadOnly() case?
1092
1093 if ( isSelected )
1094 {
1095 dc.SetTextBackground( grid.GetSelectionBackground() );
1096 dc.SetTextForeground( grid.GetSelectionForeground() );
1097 }
1098 else
1099 {
1100 dc.SetTextBackground( attr.GetBackgroundColour() );
1101 dc.SetTextForeground( attr.GetTextColour() );
1102 }
1103
1104 dc.SetFont( attr.GetFont() );
1105 }
1106
1107 wxSize wxGridCellStringRenderer::DoGetBestSize(wxGridCellAttr& attr,
1108 wxDC& dc,
1109 const wxString& text)
1110 {
1111 wxCoord x, y;
1112 dc.SetFont(attr.GetFont());
1113 dc.GetTextExtent(text, &x, &y);
1114
1115 return wxSize(x, y);
1116 }
1117
1118 wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
1119 wxGridCellAttr& attr,
1120 wxDC& dc,
1121 int row, int col)
1122 {
1123 return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
1124 }
1125
1126 void wxGridCellStringRenderer::Draw(wxGrid& grid,
1127 wxGridCellAttr& attr,
1128 wxDC& dc,
1129 const wxRect& rectCell,
1130 int row, int col,
1131 bool isSelected)
1132 {
1133 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1134
1135 // now we only have to draw the text
1136 SetTextColoursAndFont(grid, attr, dc, isSelected);
1137
1138 int hAlign, vAlign;
1139 attr.GetAlignment(&hAlign, &vAlign);
1140
1141 wxRect rect = rectCell;
1142 rect.Inflate(-1);
1143
1144 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
1145 rect, hAlign, vAlign);
1146 }
1147
1148 // ----------------------------------------------------------------------------
1149 // wxGridCellNumberRenderer
1150 // ----------------------------------------------------------------------------
1151
1152 wxString wxGridCellNumberRenderer::GetString(wxGrid& grid, int row, int col)
1153 {
1154 wxGridTableBase *table = grid.GetTable();
1155 wxString text;
1156 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
1157 {
1158 text.Printf(_T("%ld"), table->GetValueAsLong(row, col));
1159 }
1160 else
1161 {
1162 text = table->GetValue(row, col);
1163 }
1164
1165 return text;
1166 }
1167
1168 void wxGridCellNumberRenderer::Draw(wxGrid& grid,
1169 wxGridCellAttr& attr,
1170 wxDC& dc,
1171 const wxRect& rectCell,
1172 int row, int col,
1173 bool isSelected)
1174 {
1175 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1176
1177 SetTextColoursAndFont(grid, attr, dc, isSelected);
1178
1179 // draw the text right aligned by default
1180 int hAlign, vAlign;
1181 attr.GetAlignment(&hAlign, &vAlign);
1182 hAlign = wxRIGHT;
1183
1184 wxRect rect = rectCell;
1185 rect.Inflate(-1);
1186
1187 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
1188 }
1189
1190 wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
1191 wxGridCellAttr& attr,
1192 wxDC& dc,
1193 int row, int col)
1194 {
1195 return DoGetBestSize(attr, dc, GetString(grid, row, col));
1196 }
1197
1198 // ----------------------------------------------------------------------------
1199 // wxGridCellFloatRenderer
1200 // ----------------------------------------------------------------------------
1201
1202 wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision)
1203 {
1204 SetWidth(width);
1205 SetPrecision(precision);
1206 }
1207
1208 wxString wxGridCellFloatRenderer::GetString(wxGrid& grid, int row, int col)
1209 {
1210 wxGridTableBase *table = grid.GetTable();
1211 wxString text;
1212 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
1213 {
1214 if ( !m_format )
1215 {
1216 m_format.Printf(_T("%%%d.%d%%f"), m_width, m_precision);
1217 }
1218
1219 text.Printf(m_format, table->GetValueAsDouble(row, col));
1220 }
1221 else
1222 {
1223 text = table->GetValue(row, col);
1224 }
1225
1226 return text;
1227 }
1228
1229 void wxGridCellFloatRenderer::Draw(wxGrid& grid,
1230 wxGridCellAttr& attr,
1231 wxDC& dc,
1232 const wxRect& rectCell,
1233 int row, int col,
1234 bool isSelected)
1235 {
1236 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1237
1238 SetTextColoursAndFont(grid, attr, dc, isSelected);
1239
1240 // draw the text right aligned by default
1241 int hAlign, vAlign;
1242 attr.GetAlignment(&hAlign, &vAlign);
1243 hAlign = wxRIGHT;
1244
1245 wxRect rect = rectCell;
1246 rect.Inflate(-1);
1247
1248 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
1249 }
1250
1251 wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
1252 wxGridCellAttr& attr,
1253 wxDC& dc,
1254 int row, int col)
1255 {
1256 return DoGetBestSize(attr, dc, GetString(grid, row, col));
1257 }
1258
1259 // ----------------------------------------------------------------------------
1260 // wxGridCellBoolRenderer
1261 // ----------------------------------------------------------------------------
1262
1263 wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
1264
1265 // FIXME these checkbox size calculations are really ugly...
1266
1267 // between checkmark and box
1268 #ifdef __WXGTK__
1269 static const wxCoord wxGRID_CHECKMARK_MARGIN = 4;
1270 #else
1271 static const wxCoord wxGRID_CHECKMARK_MARGIN = 2;
1272 #endif
1273
1274 wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
1275 wxGridCellAttr& WXUNUSED(attr),
1276 wxDC& WXUNUSED(dc),
1277 int WXUNUSED(row),
1278 int WXUNUSED(col))
1279 {
1280 // compute it only once (no locks for MT safeness in GUI thread...)
1281 if ( !ms_sizeCheckMark.x )
1282 {
1283 // get checkbox size
1284 wxCoord checkSize = 0;
1285 wxCheckBox *checkbox = new wxCheckBox(&grid, -1, wxEmptyString);
1286 wxSize size = checkbox->GetBestSize();
1287 checkSize = size.y + wxGRID_CHECKMARK_MARGIN;
1288
1289 // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
1290 #if defined(__WXGTK__) || defined(__WXMOTIF__)
1291 checkSize -= size.y / 2;
1292 #endif
1293
1294 delete checkbox;
1295
1296 ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize;
1297 }
1298
1299 return ms_sizeCheckMark;
1300 }
1301
1302 void wxGridCellBoolRenderer::Draw(wxGrid& grid,
1303 wxGridCellAttr& attr,
1304 wxDC& dc,
1305 const wxRect& rect,
1306 int row, int col,
1307 bool isSelected)
1308 {
1309 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
1310
1311 // draw a check mark in the centre (ignoring alignment - TODO)
1312 wxSize size = GetBestSize(grid, attr, dc, row, col);
1313
1314 // don't draw outside the cell
1315 wxCoord minSize = wxMin(rect.width, rect.height);
1316 if ( size.x >= minSize || size.y >= minSize )
1317 {
1318 // and even leave (at least) 1 pixel margin
1319 size.x = size.y = minSize - 2;
1320 }
1321
1322 // draw a border around checkmark
1323 wxRect rectMark;
1324 rectMark.x = rect.x + rect.width/2 - size.x/2;
1325 rectMark.y = rect.y + rect.height/2 - size.y/2;
1326 rectMark.width = size.x;
1327 rectMark.height = size.y;
1328
1329 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1330 dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID));
1331 dc.DrawRectangle(rectMark);
1332
1333 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN);
1334
1335 #ifdef __WXMSW__
1336 // looks nicer under MSW
1337 rectMark.x++;
1338 #endif // MSW
1339
1340 bool value;
1341 if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
1342 value = grid.GetTable()->GetValueAsBool(row, col);
1343 else
1344 value = !!grid.GetTable()->GetValue(row, col);
1345
1346 if ( value )
1347 {
1348 dc.SetTextForeground(attr.GetTextColour());
1349 dc.DrawCheckMark(rectMark);
1350 }
1351 }
1352
1353 // ----------------------------------------------------------------------------
1354 // wxGridCellAttr
1355 // ----------------------------------------------------------------------------
1356
1357 wxGridCellAttr *wxGridCellAttr::Clone()
1358 {
1359 wxGridCellAttr *attr = new wxGridCellAttr;
1360 if ( HasTextColour() )
1361 attr->SetTextColour(GetTextColour());
1362 if ( HasBackgroundColour() )
1363 attr->SetBackgroundColour(GetBackgroundColour());
1364 if ( HasFont() )
1365 attr->SetFont(GetFont());
1366 if ( HasAlignment() )
1367 attr->SetAlignment(m_hAlign, m_vAlign);
1368
1369 if ( m_renderer )
1370 {
1371 attr->SetRenderer(m_renderer);
1372 m_renderer = NULL;
1373 }
1374 if ( m_editor )
1375 {
1376 attr->SetEditor(m_editor);
1377 m_editor = NULL;
1378 }
1379
1380 if ( IsReadOnly() )
1381 attr->SetReadOnly();
1382
1383 attr->SetDefAttr(m_defGridAttr);
1384
1385 return attr;
1386 }
1387
1388 const wxColour& wxGridCellAttr::GetTextColour() const
1389 {
1390 if (HasTextColour())
1391 {
1392 return m_colText;
1393 }
1394 else if (m_defGridAttr != this)
1395 {
1396 return m_defGridAttr->GetTextColour();
1397 }
1398 else
1399 {
1400 wxFAIL_MSG(wxT("Missing default cell attribute"));
1401 return wxNullColour;
1402 }
1403 }
1404
1405
1406 const wxColour& wxGridCellAttr::GetBackgroundColour() const
1407 {
1408 if (HasBackgroundColour())
1409 return m_colBack;
1410 else if (m_defGridAttr != this)
1411 return m_defGridAttr->GetBackgroundColour();
1412 else
1413 {
1414 wxFAIL_MSG(wxT("Missing default cell attribute"));
1415 return wxNullColour;
1416 }
1417 }
1418
1419
1420 const wxFont& wxGridCellAttr::GetFont() const
1421 {
1422 if (HasFont())
1423 return m_font;
1424 else if (m_defGridAttr != this)
1425 return m_defGridAttr->GetFont();
1426 else
1427 {
1428 wxFAIL_MSG(wxT("Missing default cell attribute"));
1429 return wxNullFont;
1430 }
1431 }
1432
1433
1434 void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
1435 {
1436 if (HasAlignment())
1437 {
1438 if ( hAlign ) *hAlign = m_hAlign;
1439 if ( vAlign ) *vAlign = m_vAlign;
1440 }
1441 else if (m_defGridAttr != this)
1442 m_defGridAttr->GetAlignment(hAlign, vAlign);
1443 else
1444 {
1445 wxFAIL_MSG(wxT("Missing default cell attribute"));
1446 }
1447 }
1448
1449
1450 // GetRenderer and GetEditor use a slightly different decision path about
1451 // which attribute to use. If a non-default attr object has one then it is
1452 // used, otherwise the default editor or renderer is fetched from the grid and
1453 // used. It should be the default for the data type of the cell. If it is
1454 // NULL (because the table has a type that the grid does not have in its
1455 // registry,) then the grid's default editor or renderer is used.
1456
1457 wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const
1458 {
1459 if ((m_defGridAttr != this || grid == NULL) && HasRenderer())
1460 return m_renderer; // use local attribute
1461
1462 wxGridCellRenderer* renderer = NULL;
1463 if (grid) // get renderer for the data type
1464 renderer = grid->GetDefaultRendererForCell(row, col);
1465
1466 if (! renderer)
1467 // if we still don't have one then use the grid default
1468 renderer = m_defGridAttr->GetRenderer(NULL,0,0);
1469
1470 if (! renderer)
1471 wxFAIL_MSG(wxT("Missing default cell attribute"));
1472
1473 return renderer;
1474 }
1475
1476 wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const
1477 {
1478 if ((m_defGridAttr != this || grid == NULL) && HasEditor())
1479 return m_editor; // use local attribute
1480
1481 wxGridCellEditor* editor = NULL;
1482 if (grid) // get renderer for the data type
1483 editor = grid->GetDefaultEditorForCell(row, col);
1484
1485 if (! editor)
1486 // if we still don't have one then use the grid default
1487 editor = m_defGridAttr->GetEditor(NULL,0,0);
1488
1489 if (! editor)
1490 wxFAIL_MSG(wxT("Missing default cell attribute"));
1491
1492 return editor;
1493 }
1494
1495 // ----------------------------------------------------------------------------
1496 // wxGridCellAttrData
1497 // ----------------------------------------------------------------------------
1498
1499 void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
1500 {
1501 int n = FindIndex(row, col);
1502 if ( n == wxNOT_FOUND )
1503 {
1504 // add the attribute
1505 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
1506 }
1507 else
1508 {
1509 if ( attr )
1510 {
1511 // change the attribute
1512 m_attrs[(size_t)n].attr = attr;
1513 }
1514 else
1515 {
1516 // remove this attribute
1517 m_attrs.RemoveAt((size_t)n);
1518 }
1519 }
1520 }
1521
1522 wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
1523 {
1524 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
1525
1526 int n = FindIndex(row, col);
1527 if ( n != wxNOT_FOUND )
1528 {
1529 attr = m_attrs[(size_t)n].attr;
1530 attr->IncRef();
1531 }
1532
1533 return attr;
1534 }
1535
1536 void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows )
1537 {
1538 size_t count = m_attrs.GetCount();
1539 for ( size_t n = 0; n < count; n++ )
1540 {
1541 wxGridCellCoords& coords = m_attrs[n].coords;
1542 wxCoord row = coords.GetRow();
1543 if ((size_t)row >= pos)
1544 {
1545 if (numRows > 0)
1546 {
1547 // If rows inserted, include row counter where necessary
1548 coords.SetRow(row + numRows);
1549 }
1550 else if (numRows < 0)
1551 {
1552 // If rows deleted ...
1553 if ((size_t)row >= pos - numRows)
1554 {
1555 // ...either decrement row counter (if row still exists)...
1556 coords.SetRow(row + numRows);
1557 }
1558 else
1559 {
1560 // ...or remove the attribute
1561 m_attrs.RemoveAt((size_t)n);
1562 n--; count--;
1563 }
1564 }
1565 }
1566 }
1567 }
1568
1569 void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols )
1570 {
1571 size_t count = m_attrs.GetCount();
1572 for ( size_t n = 0; n < count; n++ )
1573 {
1574 wxGridCellCoords& coords = m_attrs[n].coords;
1575 wxCoord col = coords.GetCol();
1576 if ( (size_t)col >= pos )
1577 {
1578 if ( numCols > 0 )
1579 {
1580 // If rows inserted, include row counter where necessary
1581 coords.SetCol(col + numCols);
1582 }
1583 else if (numCols < 0)
1584 {
1585 // If rows deleted ...
1586 if ((size_t)col >= pos - numCols)
1587 {
1588 // ...either decrement row counter (if row still exists)...
1589 coords.SetCol(col + numCols);
1590 }
1591 else
1592 {
1593 // ...or remove the attribute
1594 m_attrs.RemoveAt((size_t)n);
1595 n--; count--;
1596 }
1597 }
1598 }
1599 }
1600 }
1601
1602 int wxGridCellAttrData::FindIndex(int row, int col) const
1603 {
1604 size_t count = m_attrs.GetCount();
1605 for ( size_t n = 0; n < count; n++ )
1606 {
1607 const wxGridCellCoords& coords = m_attrs[n].coords;
1608 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
1609 {
1610 return n;
1611 }
1612 }
1613
1614 return wxNOT_FOUND;
1615 }
1616
1617 // ----------------------------------------------------------------------------
1618 // wxGridRowOrColAttrData
1619 // ----------------------------------------------------------------------------
1620
1621 wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
1622 {
1623 size_t count = m_attrs.Count();
1624 for ( size_t n = 0; n < count; n++ )
1625 {
1626 m_attrs[n]->DecRef();
1627 }
1628 }
1629
1630 wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
1631 {
1632 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
1633
1634 int n = m_rowsOrCols.Index(rowOrCol);
1635 if ( n != wxNOT_FOUND )
1636 {
1637 attr = m_attrs[(size_t)n];
1638 attr->IncRef();
1639 }
1640
1641 return attr;
1642 }
1643
1644 void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
1645 {
1646 int n = m_rowsOrCols.Index(rowOrCol);
1647 if ( n == wxNOT_FOUND )
1648 {
1649 // add the attribute
1650 m_rowsOrCols.Add(rowOrCol);
1651 m_attrs.Add(attr);
1652 }
1653 else
1654 {
1655 if ( attr )
1656 {
1657 // change the attribute
1658 m_attrs[(size_t)n] = attr;
1659 }
1660 else
1661 {
1662 // remove this attribute
1663 m_attrs[(size_t)n]->DecRef();
1664 m_rowsOrCols.RemoveAt((size_t)n);
1665 m_attrs.RemoveAt((size_t)n);
1666 }
1667 }
1668 }
1669
1670 void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols )
1671 {
1672 size_t count = m_attrs.GetCount();
1673 for ( size_t n = 0; n < count; n++ )
1674 {
1675 int & rowOrCol = m_rowsOrCols[n];
1676 if ( (size_t)rowOrCol >= pos )
1677 {
1678 if ( numRowsOrCols > 0 )
1679 {
1680 // If rows inserted, include row counter where necessary
1681 rowOrCol += numRowsOrCols;
1682 }
1683 else if ( numRowsOrCols < 0)
1684 {
1685 // If rows deleted, either decrement row counter (if row still exists)
1686 if ((size_t)rowOrCol >= pos - numRowsOrCols)
1687 rowOrCol += numRowsOrCols;
1688 else
1689 {
1690 m_rowsOrCols.RemoveAt((size_t)n);
1691 m_attrs.RemoveAt((size_t)n);
1692 n--; count--;
1693 }
1694 }
1695 }
1696 }
1697 }
1698
1699 // ----------------------------------------------------------------------------
1700 // wxGridCellAttrProvider
1701 // ----------------------------------------------------------------------------
1702
1703 wxGridCellAttrProvider::wxGridCellAttrProvider()
1704 {
1705 m_data = (wxGridCellAttrProviderData *)NULL;
1706 }
1707
1708 wxGridCellAttrProvider::~wxGridCellAttrProvider()
1709 {
1710 delete m_data;
1711 }
1712
1713 void wxGridCellAttrProvider::InitData()
1714 {
1715 m_data = new wxGridCellAttrProviderData;
1716 }
1717
1718 wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col) const
1719 {
1720 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
1721 if ( m_data )
1722 {
1723 // first look for the attribute of this specific cell
1724 attr = m_data->m_cellAttrs.GetAttr(row, col);
1725
1726 if ( !attr )
1727 {
1728 // then look for the col attr (col attributes are more common than
1729 // the row ones, hence they have priority)
1730 attr = m_data->m_colAttrs.GetAttr(col);
1731 }
1732
1733 if ( !attr )
1734 {
1735 // finally try the row attributes
1736 attr = m_data->m_rowAttrs.GetAttr(row);
1737 }
1738 }
1739
1740 return attr;
1741 }
1742
1743 void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
1744 int row, int col)
1745 {
1746 if ( !m_data )
1747 InitData();
1748
1749 m_data->m_cellAttrs.SetAttr(attr, row, col);
1750 }
1751
1752 void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
1753 {
1754 if ( !m_data )
1755 InitData();
1756
1757 m_data->m_rowAttrs.SetAttr(attr, row);
1758 }
1759
1760 void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
1761 {
1762 if ( !m_data )
1763 InitData();
1764
1765 m_data->m_colAttrs.SetAttr(attr, col);
1766 }
1767
1768 void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows )
1769 {
1770 if ( m_data )
1771 {
1772 m_data->m_cellAttrs.UpdateAttrRows( pos, numRows );
1773
1774 m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows );
1775 }
1776 }
1777
1778 void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols )
1779 {
1780 if ( m_data )
1781 {
1782 m_data->m_cellAttrs.UpdateAttrCols( pos, numCols );
1783
1784 m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols );
1785 }
1786 }
1787
1788 // ----------------------------------------------------------------------------
1789 // wxGridTypeRegistry
1790 // ----------------------------------------------------------------------------
1791
1792 wxGridTypeRegistry::~wxGridTypeRegistry()
1793 {
1794 size_t count = m_typeinfo.Count();
1795 for ( size_t i = 0; i < count; i++ )
1796 delete m_typeinfo[i];
1797 }
1798
1799
1800 void wxGridTypeRegistry::RegisterDataType(const wxString& typeName,
1801 wxGridCellRenderer* renderer,
1802 wxGridCellEditor* editor)
1803 {
1804 int loc;
1805 wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor);
1806
1807 // is it already registered?
1808 if ((loc = FindDataType(typeName)) != -1) {
1809 delete m_typeinfo[loc];
1810 m_typeinfo[loc] = info;
1811 }
1812 else {
1813 m_typeinfo.Add(info);
1814 }
1815 }
1816
1817 int wxGridTypeRegistry::FindDataType(const wxString& typeName)
1818 {
1819 int found = -1;
1820
1821 for (size_t i=0; i<m_typeinfo.Count(); i++) {
1822 if (typeName == m_typeinfo[i]->m_typeName) {
1823 found = i;
1824 break;
1825 }
1826 }
1827
1828 return found;
1829 }
1830
1831 wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index)
1832 {
1833 wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer;
1834 return renderer;
1835 }
1836
1837 wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
1838 {
1839 wxGridCellEditor* editor = m_typeinfo[index]->m_editor;
1840 return editor;
1841 }
1842
1843 // ----------------------------------------------------------------------------
1844 // wxGridTableBase
1845 // ----------------------------------------------------------------------------
1846
1847 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
1848
1849
1850 wxGridTableBase::wxGridTableBase()
1851 {
1852 m_view = (wxGrid *) NULL;
1853 m_attrProvider = (wxGridCellAttrProvider *) NULL;
1854 }
1855
1856 wxGridTableBase::~wxGridTableBase()
1857 {
1858 delete m_attrProvider;
1859 }
1860
1861 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
1862 {
1863 delete m_attrProvider;
1864 m_attrProvider = attrProvider;
1865 }
1866
1867 bool wxGridTableBase::CanHaveAttributes()
1868 {
1869 if ( ! GetAttrProvider() )
1870 {
1871 // use the default attr provider by default
1872 SetAttrProvider(new wxGridCellAttrProvider);
1873 }
1874 return TRUE;
1875 }
1876
1877 wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col)
1878 {
1879 if ( m_attrProvider )
1880 return m_attrProvider->GetAttr(row, col);
1881 else
1882 return (wxGridCellAttr *)NULL;
1883 }
1884
1885 void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
1886 {
1887 if ( m_attrProvider )
1888 {
1889 m_attrProvider->SetAttr(attr, row, col);
1890 }
1891 else
1892 {
1893 // as we take ownership of the pointer and don't store it, we must
1894 // free it now
1895 attr->SafeDecRef();
1896 }
1897 }
1898
1899 void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
1900 {
1901 if ( m_attrProvider )
1902 {
1903 m_attrProvider->SetRowAttr(attr, row);
1904 }
1905 else
1906 {
1907 // as we take ownership of the pointer and don't store it, we must
1908 // free it now
1909 attr->SafeDecRef();
1910 }
1911 }
1912
1913 void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
1914 {
1915 if ( m_attrProvider )
1916 {
1917 m_attrProvider->SetColAttr(attr, col);
1918 }
1919 else
1920 {
1921 // as we take ownership of the pointer and don't store it, we must
1922 // free it now
1923 attr->SafeDecRef();
1924 }
1925 }
1926
1927 void wxGridTableBase::UpdateAttrRows( size_t pos, int numRows )
1928 {
1929 if ( m_attrProvider )
1930 {
1931 m_attrProvider->UpdateAttrRows( pos, numRows );
1932 }
1933 }
1934
1935 void wxGridTableBase::UpdateAttrCols( size_t pos, int numCols )
1936 {
1937 if ( m_attrProvider )
1938 {
1939 m_attrProvider->UpdateAttrCols( pos, numCols );
1940 }
1941 }
1942
1943 bool wxGridTableBase::InsertRows( size_t pos, size_t numRows )
1944 {
1945 wxFAIL_MSG( wxT("Called grid table class function InsertRows\n"
1946 "but your derived table class does not override this function") );
1947
1948 return FALSE;
1949 }
1950
1951 bool wxGridTableBase::AppendRows( size_t numRows )
1952 {
1953 wxFAIL_MSG( wxT("Called grid table class function AppendRows\n"
1954 "but your derived table class does not override this function"));
1955
1956 return FALSE;
1957 }
1958
1959 bool wxGridTableBase::DeleteRows( size_t pos, size_t numRows )
1960 {
1961 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\n"
1962 "but your derived table class does not override this function"));
1963
1964 return FALSE;
1965 }
1966
1967 bool wxGridTableBase::InsertCols( size_t pos, size_t numCols )
1968 {
1969 wxFAIL_MSG( wxT("Called grid table class function InsertCols\n"
1970 "but your derived table class does not override this function"));
1971
1972 return FALSE;
1973 }
1974
1975 bool wxGridTableBase::AppendCols( size_t numCols )
1976 {
1977 wxFAIL_MSG(wxT("Called grid table class function AppendCols\n"
1978 "but your derived table class does not override this function"));
1979
1980 return FALSE;
1981 }
1982
1983 bool wxGridTableBase::DeleteCols( size_t pos, size_t numCols )
1984 {
1985 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\n"
1986 "but your derived table class does not override this function"));
1987
1988 return FALSE;
1989 }
1990
1991
1992 wxString wxGridTableBase::GetRowLabelValue( int row )
1993 {
1994 wxString s;
1995 s << row + 1; // RD: Starting the rows at zero confuses users, no matter
1996 // how much it makes sense to us geeks.
1997 return s;
1998 }
1999
2000 wxString wxGridTableBase::GetColLabelValue( int col )
2001 {
2002 // default col labels are:
2003 // cols 0 to 25 : A-Z
2004 // cols 26 to 675 : AA-ZZ
2005 // etc.
2006
2007 wxString s;
2008 unsigned int i, n;
2009 for ( n = 1; ; n++ )
2010 {
2011 s += (_T('A') + (wxChar)( col%26 ));
2012 col = col/26 - 1;
2013 if ( col < 0 ) break;
2014 }
2015
2016 // reverse the string...
2017 wxString s2;
2018 for ( i = 0; i < n; i++ )
2019 {
2020 s2 += s[n-i-1];
2021 }
2022
2023 return s2;
2024 }
2025
2026
2027 wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) )
2028 {
2029 return wxGRID_VALUE_STRING;
2030 }
2031
2032 bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col),
2033 const wxString& typeName )
2034 {
2035 return typeName == wxGRID_VALUE_STRING;
2036 }
2037
2038 bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName )
2039 {
2040 return CanGetValueAs(row, col, typeName);
2041 }
2042
2043 long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) )
2044 {
2045 return 0;
2046 }
2047
2048 double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) )
2049 {
2050 return 0.0;
2051 }
2052
2053 bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) )
2054 {
2055 return FALSE;
2056 }
2057
2058 void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col),
2059 long WXUNUSED(value) )
2060 {
2061 }
2062
2063 void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col),
2064 double WXUNUSED(value) )
2065 {
2066 }
2067
2068 void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col),
2069 bool WXUNUSED(value) )
2070 {
2071 }
2072
2073
2074 void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
2075 const wxString& WXUNUSED(typeName) )
2076 {
2077 return NULL;
2078 }
2079
2080 void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
2081 const wxString& WXUNUSED(typeName),
2082 void* WXUNUSED(value) )
2083 {
2084 }
2085
2086
2087 //////////////////////////////////////////////////////////////////////
2088 //
2089 // Message class for the grid table to send requests and notifications
2090 // to the grid view
2091 //
2092
2093 wxGridTableMessage::wxGridTableMessage()
2094 {
2095 m_table = (wxGridTableBase *) NULL;
2096 m_id = -1;
2097 m_comInt1 = -1;
2098 m_comInt2 = -1;
2099 }
2100
2101 wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
2102 int commandInt1, int commandInt2 )
2103 {
2104 m_table = table;
2105 m_id = id;
2106 m_comInt1 = commandInt1;
2107 m_comInt2 = commandInt2;
2108 }
2109
2110
2111
2112 //////////////////////////////////////////////////////////////////////
2113 //
2114 // A basic grid table for string data. An object of this class will
2115 // created by wxGrid if you don't specify an alternative table class.
2116 //
2117
2118 WX_DEFINE_OBJARRAY(wxGridStringArray)
2119
2120 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
2121
2122 wxGridStringTable::wxGridStringTable()
2123 : wxGridTableBase()
2124 {
2125 }
2126
2127 wxGridStringTable::wxGridStringTable( int numRows, int numCols )
2128 : wxGridTableBase()
2129 {
2130 int row, col;
2131
2132 m_data.Alloc( numRows );
2133
2134 wxArrayString sa;
2135 sa.Alloc( numCols );
2136 for ( col = 0; col < numCols; col++ )
2137 {
2138 sa.Add( wxEmptyString );
2139 }
2140
2141 for ( row = 0; row < numRows; row++ )
2142 {
2143 m_data.Add( sa );
2144 }
2145 }
2146
2147 wxGridStringTable::~wxGridStringTable()
2148 {
2149 }
2150
2151 long wxGridStringTable::GetNumberRows()
2152 {
2153 return m_data.GetCount();
2154 }
2155
2156 long wxGridStringTable::GetNumberCols()
2157 {
2158 if ( m_data.GetCount() > 0 )
2159 return m_data[0].GetCount();
2160 else
2161 return 0;
2162 }
2163
2164 wxString wxGridStringTable::GetValue( int row, int col )
2165 {
2166 wxASSERT_MSG( (row < GetNumberCols()) && (col < GetNumberCols()),
2167 _T("invalid row or column index in wxGridStringTable") );
2168
2169 return m_data[row][col];
2170 }
2171
2172 void wxGridStringTable::SetValue( int row, int col, const wxString& value )
2173 {
2174 wxASSERT_MSG( (row < GetNumberCols()) && (col < GetNumberCols()),
2175 _T("invalid row or column index in wxGridStringTable") );
2176
2177 m_data[row][col] = value;
2178 }
2179
2180 bool wxGridStringTable::IsEmptyCell( int row, int col )
2181 {
2182 wxASSERT_MSG( (row < GetNumberCols()) && (col < GetNumberCols()),
2183 _T("invalid row or column index in wxGridStringTable") );
2184
2185 return (m_data[row][col] == wxEmptyString);
2186 }
2187
2188 void wxGridStringTable::Clear()
2189 {
2190 int row, col;
2191 int numRows, numCols;
2192
2193 numRows = m_data.GetCount();
2194 if ( numRows > 0 )
2195 {
2196 numCols = m_data[0].GetCount();
2197
2198 for ( row = 0; row < numRows; row++ )
2199 {
2200 for ( col = 0; col < numCols; col++ )
2201 {
2202 m_data[row][col] = wxEmptyString;
2203 }
2204 }
2205 }
2206 }
2207
2208
2209 bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
2210 {
2211 size_t row, col;
2212
2213 size_t curNumRows = m_data.GetCount();
2214 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
2215
2216 if ( pos >= curNumRows )
2217 {
2218 return AppendRows( numRows );
2219 }
2220
2221 wxArrayString sa;
2222 sa.Alloc( curNumCols );
2223 for ( col = 0; col < curNumCols; col++ )
2224 {
2225 sa.Add( wxEmptyString );
2226 }
2227
2228 for ( row = pos; row < pos + numRows; row++ )
2229 {
2230 m_data.Insert( sa, row );
2231 }
2232 UpdateAttrRows( pos, numRows );
2233 if ( GetView() )
2234 {
2235 wxGridTableMessage msg( this,
2236 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
2237 pos,
2238 numRows );
2239
2240 GetView()->ProcessTableMessage( msg );
2241 }
2242
2243 return TRUE;
2244 }
2245
2246 bool wxGridStringTable::AppendRows( size_t numRows )
2247 {
2248 size_t row, col;
2249
2250 size_t curNumRows = m_data.GetCount();
2251 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
2252
2253 wxArrayString sa;
2254 if ( curNumCols > 0 )
2255 {
2256 sa.Alloc( curNumCols );
2257 for ( col = 0; col < curNumCols; col++ )
2258 {
2259 sa.Add( wxEmptyString );
2260 }
2261 }
2262
2263 for ( row = 0; row < numRows; row++ )
2264 {
2265 m_data.Add( sa );
2266 }
2267
2268 if ( GetView() )
2269 {
2270 wxGridTableMessage msg( this,
2271 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
2272 numRows );
2273
2274 GetView()->ProcessTableMessage( msg );
2275 }
2276
2277 return TRUE;
2278 }
2279
2280 bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
2281 {
2282 size_t n;
2283
2284 size_t curNumRows = m_data.GetCount();
2285
2286 if ( pos >= curNumRows )
2287 {
2288 wxString errmsg;
2289 errmsg.Printf("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)\n"
2290 "Pos value is invalid for present table with %d rows",
2291 pos, numRows, curNumRows );
2292 wxFAIL_MSG( wxT(errmsg) );
2293 return FALSE;
2294 }
2295
2296 if ( numRows > curNumRows - pos )
2297 {
2298 numRows = curNumRows - pos;
2299 }
2300
2301 if ( numRows >= curNumRows )
2302 {
2303 m_data.Empty(); // don't release memory just yet
2304 }
2305 else
2306 {
2307 for ( n = 0; n < numRows; n++ )
2308 {
2309 m_data.Remove( pos );
2310 }
2311 }
2312 UpdateAttrRows( pos, -((int)numRows) );
2313 if ( GetView() )
2314 {
2315 wxGridTableMessage msg( this,
2316 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
2317 pos,
2318 numRows );
2319
2320 GetView()->ProcessTableMessage( msg );
2321 }
2322
2323 return TRUE;
2324 }
2325
2326 bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
2327 {
2328 size_t row, col;
2329
2330 size_t curNumRows = m_data.GetCount();
2331 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
2332
2333 if ( pos >= curNumCols )
2334 {
2335 return AppendCols( numCols );
2336 }
2337
2338 for ( row = 0; row < curNumRows; row++ )
2339 {
2340 for ( col = pos; col < pos + numCols; col++ )
2341 {
2342 m_data[row].Insert( wxEmptyString, col );
2343 }
2344 }
2345 UpdateAttrCols( pos, numCols );
2346 if ( GetView() )
2347 {
2348 wxGridTableMessage msg( this,
2349 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
2350 pos,
2351 numCols );
2352
2353 GetView()->ProcessTableMessage( msg );
2354 }
2355
2356 return TRUE;
2357 }
2358
2359 bool wxGridStringTable::AppendCols( size_t numCols )
2360 {
2361 size_t row, n;
2362
2363 size_t curNumRows = m_data.GetCount();
2364 if ( !curNumRows )
2365 {
2366 // TODO: something better than this ?
2367 //
2368 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\n"
2369 "Call AppendRows() first") );
2370 return FALSE;
2371 }
2372
2373 for ( row = 0; row < curNumRows; row++ )
2374 {
2375 for ( n = 0; n < numCols; n++ )
2376 {
2377 m_data[row].Add( wxEmptyString );
2378 }
2379 }
2380
2381 if ( GetView() )
2382 {
2383 wxGridTableMessage msg( this,
2384 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
2385 numCols );
2386
2387 GetView()->ProcessTableMessage( msg );
2388 }
2389
2390 return TRUE;
2391 }
2392
2393 bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
2394 {
2395 size_t row, n;
2396
2397 size_t curNumRows = m_data.GetCount();
2398 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
2399
2400 if ( pos >= curNumCols )
2401 {
2402 wxString errmsg;
2403 errmsg.Printf( "Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n"
2404 "Pos value is invalid for present table with %d cols",
2405 pos, numCols, curNumCols );
2406 wxFAIL_MSG( wxT( errmsg ) );
2407 return FALSE;
2408 }
2409
2410 if ( numCols > curNumCols - pos )
2411 {
2412 numCols = curNumCols - pos;
2413 }
2414
2415 for ( row = 0; row < curNumRows; row++ )
2416 {
2417 if ( numCols >= curNumCols )
2418 {
2419 m_data[row].Clear();
2420 }
2421 else
2422 {
2423 for ( n = 0; n < numCols; n++ )
2424 {
2425 m_data[row].Remove( pos );
2426 }
2427 }
2428 }
2429 UpdateAttrCols( pos, -((int)numCols) );
2430 if ( GetView() )
2431 {
2432 wxGridTableMessage msg( this,
2433 wxGRIDTABLE_NOTIFY_COLS_DELETED,
2434 pos,
2435 numCols );
2436
2437 GetView()->ProcessTableMessage( msg );
2438 }
2439
2440 return TRUE;
2441 }
2442
2443 wxString wxGridStringTable::GetRowLabelValue( int row )
2444 {
2445 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
2446 {
2447 // using default label
2448 //
2449 return wxGridTableBase::GetRowLabelValue( row );
2450 }
2451 else
2452 {
2453 return m_rowLabels[ row ];
2454 }
2455 }
2456
2457 wxString wxGridStringTable::GetColLabelValue( int col )
2458 {
2459 if ( col > (int)(m_colLabels.GetCount()) - 1 )
2460 {
2461 // using default label
2462 //
2463 return wxGridTableBase::GetColLabelValue( col );
2464 }
2465 else
2466 {
2467 return m_colLabels[ col ];
2468 }
2469 }
2470
2471 void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
2472 {
2473 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
2474 {
2475 int n = m_rowLabels.GetCount();
2476 int i;
2477 for ( i = n; i <= row; i++ )
2478 {
2479 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
2480 }
2481 }
2482
2483 m_rowLabels[row] = value;
2484 }
2485
2486 void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
2487 {
2488 if ( col > (int)(m_colLabels.GetCount()) - 1 )
2489 {
2490 int n = m_colLabels.GetCount();
2491 int i;
2492 for ( i = n; i <= col; i++ )
2493 {
2494 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
2495 }
2496 }
2497
2498 m_colLabels[col] = value;
2499 }
2500
2501
2502
2503 //////////////////////////////////////////////////////////////////////
2504 //////////////////////////////////////////////////////////////////////
2505
2506 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
2507
2508 BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
2509 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
2510 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
2511 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
2512 END_EVENT_TABLE()
2513
2514 wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
2515 wxWindowID id,
2516 const wxPoint &pos, const wxSize &size )
2517 : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
2518 {
2519 m_owner = parent;
2520 }
2521
2522 void wxGridRowLabelWindow::OnPaint( wxPaintEvent &event )
2523 {
2524 wxPaintDC dc(this);
2525
2526 // NO - don't do this because it will set both the x and y origin
2527 // coords to match the parent scrolled window and we just want to
2528 // set the y coord - MB
2529 //
2530 // m_owner->PrepareDC( dc );
2531
2532 int x, y;
2533 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
2534 dc.SetDeviceOrigin( 0, -y );
2535
2536 m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
2537 m_owner->DrawRowLabels( dc );
2538 }
2539
2540
2541 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
2542 {
2543 m_owner->ProcessRowLabelMouseEvent( event );
2544 }
2545
2546
2547 // This seems to be required for wxMotif otherwise the mouse
2548 // cursor must be in the cell edit control to get key events
2549 //
2550 void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
2551 {
2552 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
2553 }
2554
2555
2556
2557 //////////////////////////////////////////////////////////////////////
2558
2559 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
2560
2561 BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
2562 EVT_PAINT( wxGridColLabelWindow::OnPaint )
2563 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
2564 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
2565 END_EVENT_TABLE()
2566
2567 wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
2568 wxWindowID id,
2569 const wxPoint &pos, const wxSize &size )
2570 : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
2571 {
2572 m_owner = parent;
2573 }
2574
2575 void wxGridColLabelWindow::OnPaint( wxPaintEvent &event )
2576 {
2577 wxPaintDC dc(this);
2578
2579 // NO - don't do this because it will set both the x and y origin
2580 // coords to match the parent scrolled window and we just want to
2581 // set the x coord - MB
2582 //
2583 // m_owner->PrepareDC( dc );
2584
2585 int x, y;
2586 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
2587 dc.SetDeviceOrigin( -x, 0 );
2588
2589 m_owner->CalcColLabelsExposed( GetUpdateRegion() );
2590 m_owner->DrawColLabels( dc );
2591 }
2592
2593
2594 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
2595 {
2596 m_owner->ProcessColLabelMouseEvent( event );
2597 }
2598
2599
2600 // This seems to be required for wxMotif otherwise the mouse
2601 // cursor must be in the cell edit control to get key events
2602 //
2603 void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
2604 {
2605 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
2606 }
2607
2608
2609
2610 //////////////////////////////////////////////////////////////////////
2611
2612 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
2613
2614 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
2615 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
2616 EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
2617 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
2618 END_EVENT_TABLE()
2619
2620 wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
2621 wxWindowID id,
2622 const wxPoint &pos, const wxSize &size )
2623 : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
2624 {
2625 m_owner = parent;
2626 }
2627
2628 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
2629 {
2630 wxPaintDC dc(this);
2631
2632 int client_height = 0;
2633 int client_width = 0;
2634 GetClientSize( &client_width, &client_height );
2635
2636 dc.SetPen( *wxBLACK_PEN );
2637 dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
2638 dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
2639
2640 dc.SetPen( *wxWHITE_PEN );
2641 dc.DrawLine( 0, 0, client_width, 0 );
2642 dc.DrawLine( 0, 0, 0, client_height );
2643 }
2644
2645
2646 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
2647 {
2648 m_owner->ProcessCornerLabelMouseEvent( event );
2649 }
2650
2651
2652 // This seems to be required for wxMotif otherwise the mouse
2653 // cursor must be in the cell edit control to get key events
2654 //
2655 void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
2656 {
2657 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
2658 }
2659
2660
2661
2662 //////////////////////////////////////////////////////////////////////
2663
2664 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxPanel )
2665
2666 BEGIN_EVENT_TABLE( wxGridWindow, wxPanel )
2667 EVT_PAINT( wxGridWindow::OnPaint )
2668 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
2669 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
2670 EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground )
2671 END_EVENT_TABLE()
2672
2673 wxGridWindow::wxGridWindow( wxGrid *parent,
2674 wxGridRowLabelWindow *rowLblWin,
2675 wxGridColLabelWindow *colLblWin,
2676 wxWindowID id, const wxPoint &pos, const wxSize &size )
2677 : wxPanel( parent, id, pos, size, wxWANTS_CHARS, "grid window" )
2678 {
2679 m_owner = parent;
2680 m_rowLabelWin = rowLblWin;
2681 m_colLabelWin = colLblWin;
2682 SetBackgroundColour( "WHITE" );
2683 }
2684
2685
2686 wxGridWindow::~wxGridWindow()
2687 {
2688 }
2689
2690
2691 void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
2692 {
2693 wxPaintDC dc( this );
2694 m_owner->PrepareDC( dc );
2695 wxRegion reg = GetUpdateRegion();
2696 m_owner->CalcCellsExposed( reg );
2697 m_owner->DrawGridCellArea( dc );
2698 #if WXGRID_DRAW_LINES
2699 m_owner->DrawAllGridLines( dc, reg );
2700 #endif
2701 m_owner->DrawGridSpace( dc );
2702 m_owner->DrawHighlight( dc );
2703 }
2704
2705
2706 void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
2707 {
2708 wxPanel::ScrollWindow( dx, dy, rect );
2709 m_rowLabelWin->ScrollWindow( 0, dy, rect );
2710 m_colLabelWin->ScrollWindow( dx, 0, rect );
2711 }
2712
2713
2714 void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
2715 {
2716 m_owner->ProcessGridCellMouseEvent( event );
2717 }
2718
2719
2720 // This seems to be required for wxMotif otherwise the mouse
2721 // cursor must be in the cell edit control to get key events
2722 //
2723 void wxGridWindow::OnKeyDown( wxKeyEvent& event )
2724 {
2725 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
2726 }
2727
2728
2729 void wxGridWindow::OnEraseBackground(wxEraseEvent& event)
2730 {
2731 }
2732
2733
2734 //////////////////////////////////////////////////////////////////////
2735
2736
2737 IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
2738
2739 BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
2740 EVT_PAINT( wxGrid::OnPaint )
2741 EVT_SIZE( wxGrid::OnSize )
2742 EVT_KEY_DOWN( wxGrid::OnKeyDown )
2743 EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground )
2744 END_EVENT_TABLE()
2745
2746 wxGrid::wxGrid( wxWindow *parent,
2747 wxWindowID id,
2748 const wxPoint& pos,
2749 const wxSize& size,
2750 long style,
2751 const wxString& name )
2752 : wxScrolledWindow( parent, id, pos, size, (style | wxWANTS_CHARS), name ),
2753 m_colMinWidths(GRID_HASH_SIZE),
2754 m_rowMinHeights(GRID_HASH_SIZE)
2755 {
2756 Create();
2757 }
2758
2759
2760 wxGrid::~wxGrid()
2761 {
2762 ClearAttrCache();
2763 m_defaultCellAttr->SafeDecRef();
2764
2765 #ifdef DEBUG_ATTR_CACHE
2766 size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses;
2767 wxPrintf(_T("wxGrid attribute cache statistics: "
2768 "total: %u, hits: %u (%u%%)\n"),
2769 total, gs_nAttrCacheHits,
2770 total ? (gs_nAttrCacheHits*100) / total : 0);
2771 #endif
2772
2773 if (m_ownTable)
2774 delete m_table;
2775
2776 delete m_typeRegistry;
2777 }
2778
2779
2780 //
2781 // ----- internal init and update functions
2782 //
2783
2784 void wxGrid::Create()
2785 {
2786 m_created = FALSE; // set to TRUE by CreateGrid
2787 m_displayed = TRUE; // FALSE; // set to TRUE by OnPaint
2788
2789 m_table = (wxGridTableBase *) NULL;
2790 m_ownTable = FALSE;
2791
2792 m_cellEditCtrlEnabled = FALSE;
2793
2794 m_defaultCellAttr = new wxGridCellAttr;
2795 m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
2796
2797 // Set default cell attributes
2798 m_defaultCellAttr->SetFont(GetFont());
2799 m_defaultCellAttr->SetAlignment(wxLEFT, wxTOP);
2800 m_defaultCellAttr->SetTextColour(
2801 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT));
2802 m_defaultCellAttr->SetBackgroundColour(
2803 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
2804 m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer);
2805 m_defaultCellAttr->SetEditor(new wxGridCellTextEditor);
2806
2807
2808 m_numRows = 0;
2809 m_numCols = 0;
2810 m_currentCellCoords = wxGridNoCellCoords;
2811
2812 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
2813 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
2814
2815 // data type registration: register all standard data types
2816 // TODO: may be allow the app to selectively disable some of them?
2817 m_typeRegistry = new wxGridTypeRegistry;
2818 RegisterDataType(wxGRID_VALUE_STRING,
2819 new wxGridCellStringRenderer,
2820 new wxGridCellTextEditor);
2821 RegisterDataType(wxGRID_VALUE_BOOL,
2822 new wxGridCellBoolRenderer,
2823 new wxGridCellBoolEditor);
2824 RegisterDataType(wxGRID_VALUE_NUMBER,
2825 new wxGridCellNumberRenderer,
2826 new wxGridCellNumberEditor);
2827
2828 // subwindow components that make up the wxGrid
2829 m_cornerLabelWin = new wxGridCornerLabelWindow( this,
2830 -1,
2831 wxDefaultPosition,
2832 wxDefaultSize );
2833
2834 m_rowLabelWin = new wxGridRowLabelWindow( this,
2835 -1,
2836 wxDefaultPosition,
2837 wxDefaultSize );
2838
2839 m_colLabelWin = new wxGridColLabelWindow( this,
2840 -1,
2841 wxDefaultPosition,
2842 wxDefaultSize );
2843
2844 m_gridWin = new wxGridWindow( this,
2845 m_rowLabelWin,
2846 m_colLabelWin,
2847 -1,
2848 wxDefaultPosition,
2849 wxDefaultSize );
2850
2851 SetTargetWindow( m_gridWin );
2852 }
2853
2854
2855 bool wxGrid::CreateGrid( int numRows, int numCols )
2856 {
2857 if ( m_created )
2858 {
2859 wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
2860 return FALSE;
2861 }
2862 else
2863 {
2864 m_numRows = numRows;
2865 m_numCols = numCols;
2866
2867 m_table = new wxGridStringTable( m_numRows, m_numCols );
2868 m_table->SetView( this );
2869 m_ownTable = TRUE;
2870 Init();
2871 m_created = TRUE;
2872 }
2873
2874 return m_created;
2875 }
2876
2877 bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership )
2878 {
2879 if ( m_created )
2880 {
2881 // RD: Actually, this should probably be allowed. I think it would be
2882 // nice to be able to switch multiple Tables in and out of a single
2883 // View at runtime. Is there anything in the implmentation that would
2884 // prevent this?
2885
2886 wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
2887 return FALSE;
2888 }
2889 else
2890 {
2891 m_numRows = table->GetNumberRows();
2892 m_numCols = table->GetNumberCols();
2893
2894 m_table = table;
2895 m_table->SetView( this );
2896 if (takeOwnership)
2897 m_ownTable = TRUE;
2898 Init();
2899 m_created = TRUE;
2900 }
2901
2902 return m_created;
2903 }
2904
2905
2906 void wxGrid::Init()
2907 {
2908 if ( m_numRows <= 0 )
2909 m_numRows = WXGRID_DEFAULT_NUMBER_ROWS;
2910
2911 if ( m_numCols <= 0 )
2912 m_numCols = WXGRID_DEFAULT_NUMBER_COLS;
2913
2914 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
2915 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
2916
2917 if ( m_rowLabelWin )
2918 {
2919 m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
2920 }
2921 else
2922 {
2923 m_labelBackgroundColour = wxColour( _T("WHITE") );
2924 }
2925
2926 m_labelTextColour = wxColour( _T("BLACK") );
2927
2928 // init attr cache
2929 m_attrCache.row = -1;
2930
2931 // TODO: something better than this ?
2932 //
2933 m_labelFont = this->GetFont();
2934 m_labelFont.SetWeight( m_labelFont.GetWeight() + 2 );
2935
2936 m_rowLabelHorizAlign = wxLEFT;
2937 m_rowLabelVertAlign = wxCENTRE;
2938
2939 m_colLabelHorizAlign = wxCENTRE;
2940 m_colLabelVertAlign = wxTOP;
2941
2942 m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH;
2943 m_defaultRowHeight = m_gridWin->GetCharHeight();
2944
2945 #if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
2946 m_defaultRowHeight += 8;
2947 #else
2948 m_defaultRowHeight += 4;
2949 #endif
2950
2951 m_gridLineColour = wxColour( 128, 128, 255 );
2952 m_gridLinesEnabled = TRUE;
2953
2954 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
2955 m_winCapture = (wxWindow *)NULL;
2956 m_canDragRowSize = TRUE;
2957 m_canDragColSize = TRUE;
2958 m_canDragGridSize = TRUE;
2959 m_dragLastPos = -1;
2960 m_dragRowOrCol = -1;
2961 m_isDragging = FALSE;
2962 m_startDragPos = wxDefaultPosition;
2963
2964 m_waitForSlowClick = FALSE;
2965
2966 m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
2967 m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
2968
2969 m_currentCellCoords = wxGridNoCellCoords;
2970
2971 m_selectedTopLeft = wxGridNoCellCoords;
2972 m_selectedBottomRight = wxGridNoCellCoords;
2973 m_selectionBackground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT);
2974 m_selectionForeground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
2975
2976 m_editable = TRUE; // default for whole grid
2977
2978 m_inOnKeyDown = FALSE;
2979 m_batchCount = 0;
2980
2981 m_extraWidth =
2982 m_extraHeight = 50;
2983
2984 CalcDimensions();
2985 }
2986
2987 // ----------------------------------------------------------------------------
2988 // the idea is to call these functions only when necessary because they create
2989 // quite big arrays which eat memory mostly unnecessary - in particular, if
2990 // default widths/heights are used for all rows/columns, we may not use these
2991 // arrays at all
2992 //
2993 // with some extra code, it should be possible to only store the
2994 // widths/heights different from default ones but this will be done later...
2995 // ----------------------------------------------------------------------------
2996
2997 void wxGrid::InitRowHeights()
2998 {
2999 m_rowHeights.Empty();
3000 m_rowBottoms.Empty();
3001
3002 m_rowHeights.Alloc( m_numRows );
3003 m_rowBottoms.Alloc( m_numRows );
3004
3005 int rowBottom = 0;
3006 for ( int i = 0; i < m_numRows; i++ )
3007 {
3008 m_rowHeights.Add( m_defaultRowHeight );
3009 rowBottom += m_defaultRowHeight;
3010 m_rowBottoms.Add( rowBottom );
3011 }
3012 }
3013
3014 void wxGrid::InitColWidths()
3015 {
3016 m_colWidths.Empty();
3017 m_colRights.Empty();
3018
3019 m_colWidths.Alloc( m_numCols );
3020 m_colRights.Alloc( m_numCols );
3021 int colRight = 0;
3022 for ( int i = 0; i < m_numCols; i++ )
3023 {
3024 m_colWidths.Add( m_defaultColWidth );
3025 colRight += m_defaultColWidth;
3026 m_colRights.Add( colRight );
3027 }
3028 }
3029
3030 int wxGrid::GetColWidth(int col) const
3031 {
3032 return m_colWidths.IsEmpty() ? m_defaultColWidth : m_colWidths[col];
3033 }
3034
3035 int wxGrid::GetColLeft(int col) const
3036 {
3037 return m_colRights.IsEmpty() ? col * m_defaultColWidth
3038 : m_colRights[col] - m_colWidths[col];
3039 }
3040
3041 int wxGrid::GetColRight(int col) const
3042 {
3043 return m_colRights.IsEmpty() ? (col + 1) * m_defaultColWidth
3044 : m_colRights[col];
3045 }
3046
3047 int wxGrid::GetRowHeight(int row) const
3048 {
3049 return m_rowHeights.IsEmpty() ? m_defaultRowHeight : m_rowHeights[row];
3050 }
3051
3052 int wxGrid::GetRowTop(int row) const
3053 {
3054 return m_rowBottoms.IsEmpty() ? row * m_defaultRowHeight
3055 : m_rowBottoms[row] - m_rowHeights[row];
3056 }
3057
3058 int wxGrid::GetRowBottom(int row) const
3059 {
3060 return m_rowBottoms.IsEmpty() ? (row + 1) * m_defaultRowHeight
3061 : m_rowBottoms[row];
3062 }
3063
3064 void wxGrid::CalcDimensions()
3065 {
3066 int cw, ch;
3067 GetClientSize( &cw, &ch );
3068
3069 if ( m_numRows > 0 && m_numCols > 0 )
3070 {
3071 int right = GetColRight( m_numCols-1 ) + m_extraWidth;
3072 int bottom = GetRowBottom( m_numRows-1 ) + m_extraHeight;
3073
3074 // TODO: restore the scroll position that we had before sizing
3075 //
3076 int x, y;
3077 GetViewStart( &x, &y );
3078 SetScrollbars( GRID_SCROLL_LINE, GRID_SCROLL_LINE,
3079 right/GRID_SCROLL_LINE, bottom/GRID_SCROLL_LINE,
3080 x, y );
3081 }
3082 }
3083
3084
3085 void wxGrid::CalcWindowSizes()
3086 {
3087 int cw, ch;
3088 GetClientSize( &cw, &ch );
3089
3090 if ( m_cornerLabelWin->IsShown() )
3091 m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
3092
3093 if ( m_colLabelWin->IsShown() )
3094 m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw-m_rowLabelWidth, m_colLabelHeight);
3095
3096 if ( m_rowLabelWin->IsShown() )
3097 m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch-m_colLabelHeight);
3098
3099 if ( m_gridWin->IsShown() )
3100 m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw-m_rowLabelWidth, ch-m_colLabelHeight);
3101 }
3102
3103
3104 // this is called when the grid table sends a message to say that it
3105 // has been redimensioned
3106 //
3107 bool wxGrid::Redimension( wxGridTableMessage& msg )
3108 {
3109 int i;
3110
3111 // if we were using the default widths/heights so far, we must change them
3112 // now
3113 if ( m_colWidths.IsEmpty() )
3114 {
3115 InitColWidths();
3116 }
3117
3118 if ( m_rowHeights.IsEmpty() )
3119 {
3120 InitRowHeights();
3121 }
3122
3123 switch ( msg.GetId() )
3124 {
3125 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
3126 {
3127 size_t pos = msg.GetCommandInt();
3128 int numRows = msg.GetCommandInt2();
3129 for ( i = 0; i < numRows; i++ )
3130 {
3131 m_rowHeights.Insert( m_defaultRowHeight, pos );
3132 m_rowBottoms.Insert( 0, pos );
3133 }
3134 m_numRows += numRows;
3135
3136 int bottom = 0;
3137 if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
3138
3139 for ( i = pos; i < m_numRows; i++ )
3140 {
3141 bottom += m_rowHeights[i];
3142 m_rowBottoms[i] = bottom;
3143 }
3144 CalcDimensions();
3145 }
3146 return TRUE;
3147
3148 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
3149 {
3150 int numRows = msg.GetCommandInt();
3151 for ( i = 0; i < numRows; i++ )
3152 {
3153 m_rowHeights.Add( m_defaultRowHeight );
3154 m_rowBottoms.Add( 0 );
3155 }
3156
3157 int oldNumRows = m_numRows;
3158 m_numRows += numRows;
3159
3160 int bottom = 0;
3161 if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
3162
3163 for ( i = oldNumRows; i < m_numRows; i++ )
3164 {
3165 bottom += m_rowHeights[i];
3166 m_rowBottoms[i] = bottom;
3167 }
3168 CalcDimensions();
3169 }
3170 return TRUE;
3171
3172 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
3173 {
3174 size_t pos = msg.GetCommandInt();
3175 int numRows = msg.GetCommandInt2();
3176 for ( i = 0; i < numRows; i++ )
3177 {
3178 m_rowHeights.Remove( pos );
3179 m_rowBottoms.Remove( pos );
3180 }
3181 m_numRows -= numRows;
3182
3183 if ( !m_numRows )
3184 {
3185 m_numCols = 0;
3186 m_colWidths.Clear();
3187 m_colRights.Clear();
3188 m_currentCellCoords = wxGridNoCellCoords;
3189 }
3190 else
3191 {
3192 if ( m_currentCellCoords.GetRow() >= m_numRows )
3193 m_currentCellCoords.Set( 0, 0 );
3194
3195 int h = 0;
3196 for ( i = 0; i < m_numRows; i++ )
3197 {
3198 h += m_rowHeights[i];
3199 m_rowBottoms[i] = h;
3200 }
3201 }
3202
3203 CalcDimensions();
3204 }
3205 return TRUE;
3206
3207 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
3208 {
3209 size_t pos = msg.GetCommandInt();
3210 int numCols = msg.GetCommandInt2();
3211 for ( i = 0; i < numCols; i++ )
3212 {
3213 m_colWidths.Insert( m_defaultColWidth, pos );
3214 m_colRights.Insert( 0, pos );
3215 }
3216 m_numCols += numCols;
3217
3218 int right = 0;
3219 if ( pos > 0 ) right = m_colRights[pos-1];
3220
3221 for ( i = pos; i < m_numCols; i++ )
3222 {
3223 right += m_colWidths[i];
3224 m_colRights[i] = right;
3225 }
3226 CalcDimensions();
3227 }
3228 return TRUE;
3229
3230 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
3231 {
3232 int numCols = msg.GetCommandInt();
3233 for ( i = 0; i < numCols; i++ )
3234 {
3235 m_colWidths.Add( m_defaultColWidth );
3236 m_colRights.Add( 0 );
3237 }
3238
3239 int oldNumCols = m_numCols;
3240 m_numCols += numCols;
3241
3242 int right = 0;
3243 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
3244
3245 for ( i = oldNumCols; i < m_numCols; i++ )
3246 {
3247 right += m_colWidths[i];
3248 m_colRights[i] = right;
3249 }
3250 CalcDimensions();
3251 }
3252 return TRUE;
3253
3254 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
3255 {
3256 size_t pos = msg.GetCommandInt();
3257 int numCols = msg.GetCommandInt2();
3258 for ( i = 0; i < numCols; i++ )
3259 {
3260 m_colWidths.Remove( pos );
3261 m_colRights.Remove( pos );
3262 }
3263 m_numCols -= numCols;
3264
3265 if ( !m_numCols )
3266 {
3267 #if 0 // leave the row alone here so that AppendCols will work subsequently
3268 m_numRows = 0;
3269 m_rowHeights.Clear();
3270 m_rowBottoms.Clear();
3271 #endif
3272 m_currentCellCoords = wxGridNoCellCoords;
3273 }
3274 else
3275 {
3276 if ( m_currentCellCoords.GetCol() >= m_numCols )
3277 m_currentCellCoords.Set( 0, 0 );
3278
3279 int w = 0;
3280 for ( i = 0; i < m_numCols; i++ )
3281 {
3282 w += m_colWidths[i];
3283 m_colRights[i] = w;
3284 }
3285 }
3286 CalcDimensions();
3287 }
3288 return TRUE;
3289 }
3290
3291 return FALSE;
3292 }
3293
3294
3295 void wxGrid::CalcRowLabelsExposed( wxRegion& reg )
3296 {
3297 wxRegionIterator iter( reg );
3298 wxRect r;
3299
3300 m_rowLabelsExposed.Empty();
3301
3302 int top, bottom;
3303 while ( iter )
3304 {
3305 r = iter.GetRect();
3306
3307 // TODO: remove this when we can...
3308 // There is a bug in wxMotif that gives garbage update
3309 // rectangles if you jump-scroll a long way by clicking the
3310 // scrollbar with middle button. This is a work-around
3311 //
3312 #if defined(__WXMOTIF__)
3313 int cw, ch;
3314 m_gridWin->GetClientSize( &cw, &ch );
3315 if ( r.GetTop() > ch ) r.SetTop( 0 );
3316 r.SetBottom( wxMin( r.GetBottom(), ch ) );
3317 #endif
3318
3319 // logical bounds of update region
3320 //
3321 int dummy;
3322 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
3323 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
3324
3325 // find the row labels within these bounds
3326 //
3327 int row;
3328 for ( row = 0; row < m_numRows; row++ )
3329 {
3330 if ( GetRowBottom(row) < top )
3331 continue;
3332
3333 if ( GetRowTop(row) > bottom )
3334 break;
3335
3336 m_rowLabelsExposed.Add( row );
3337 }
3338
3339 iter++ ;
3340 }
3341 }
3342
3343
3344 void wxGrid::CalcColLabelsExposed( wxRegion& reg )
3345 {
3346 wxRegionIterator iter( reg );
3347 wxRect r;
3348
3349 m_colLabelsExposed.Empty();
3350
3351 int left, right;
3352 while ( iter )
3353 {
3354 r = iter.GetRect();
3355
3356 // TODO: remove this when we can...
3357 // There is a bug in wxMotif that gives garbage update
3358 // rectangles if you jump-scroll a long way by clicking the
3359 // scrollbar with middle button. This is a work-around
3360 //
3361 #if defined(__WXMOTIF__)
3362 int cw, ch;
3363 m_gridWin->GetClientSize( &cw, &ch );
3364 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
3365 r.SetRight( wxMin( r.GetRight(), cw ) );
3366 #endif
3367
3368 // logical bounds of update region
3369 //
3370 int dummy;
3371 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
3372 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
3373
3374 // find the cells within these bounds
3375 //
3376 int col;
3377 for ( col = 0; col < m_numCols; col++ )
3378 {
3379 if ( GetColRight(col) < left )
3380 continue;
3381
3382 if ( GetColLeft(col) > right )
3383 break;
3384
3385 m_colLabelsExposed.Add( col );
3386 }
3387
3388 iter++ ;
3389 }
3390 }
3391
3392
3393 void wxGrid::CalcCellsExposed( wxRegion& reg )
3394 {
3395 wxRegionIterator iter( reg );
3396 wxRect r;
3397
3398 m_cellsExposed.Empty();
3399 m_rowsExposed.Empty();
3400 m_colsExposed.Empty();
3401
3402 int left, top, right, bottom;
3403 while ( iter )
3404 {
3405 r = iter.GetRect();
3406
3407 // TODO: remove this when we can...
3408 // There is a bug in wxMotif that gives garbage update
3409 // rectangles if you jump-scroll a long way by clicking the
3410 // scrollbar with middle button. This is a work-around
3411 //
3412 #if defined(__WXMOTIF__)
3413 int cw, ch;
3414 m_gridWin->GetClientSize( &cw, &ch );
3415 if ( r.GetTop() > ch ) r.SetTop( 0 );
3416 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
3417 r.SetRight( wxMin( r.GetRight(), cw ) );
3418 r.SetBottom( wxMin( r.GetBottom(), ch ) );
3419 #endif
3420
3421 // logical bounds of update region
3422 //
3423 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3424 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
3425
3426 // find the cells within these bounds
3427 //
3428 int row, col;
3429 for ( row = 0; row < m_numRows; row++ )
3430 {
3431 if ( GetRowBottom(row) <= top )
3432 continue;
3433
3434 if ( GetRowTop(row) > bottom )
3435 break;
3436
3437 m_rowsExposed.Add( row );
3438
3439 for ( col = 0; col < m_numCols; col++ )
3440 {
3441 if ( GetColRight(col) <= left )
3442 continue;
3443
3444 if ( GetColLeft(col) > right )
3445 break;
3446
3447 if ( m_colsExposed.Index( col ) == wxNOT_FOUND )
3448 m_colsExposed.Add( col );
3449 m_cellsExposed.Add( wxGridCellCoords( row, col ) );
3450 }
3451 }
3452
3453 iter++;
3454 }
3455 }
3456
3457
3458 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
3459 {
3460 int x, y, row;
3461 wxPoint pos( event.GetPosition() );
3462 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
3463
3464 if ( event.Dragging() )
3465 {
3466 m_isDragging = TRUE;
3467
3468 if ( event.LeftIsDown() )
3469 {
3470 switch( m_cursorMode )
3471 {
3472 case WXGRID_CURSOR_RESIZE_ROW:
3473 {
3474 int cw, ch, left, dummy;
3475 m_gridWin->GetClientSize( &cw, &ch );
3476 CalcUnscrolledPosition( 0, 0, &left, &dummy );
3477
3478 wxClientDC dc( m_gridWin );
3479 PrepareDC( dc );
3480 y = wxMax( y,
3481 GetRowTop(m_dragRowOrCol) +
3482 GetRowMinimalHeight(m_dragRowOrCol) );
3483 dc.SetLogicalFunction(wxINVERT);
3484 if ( m_dragLastPos >= 0 )
3485 {
3486 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
3487 }
3488 dc.DrawLine( left, y, left+cw, y );
3489 m_dragLastPos = y;
3490 }
3491 break;
3492
3493 case WXGRID_CURSOR_SELECT_ROW:
3494 if ( (row = YToRow( y )) >= 0 &&
3495 !IsInSelection( row, 0 ) )
3496 {
3497 SelectRow( row, TRUE );
3498 }
3499
3500 // default label to suppress warnings about "enumeration value
3501 // 'xxx' not handled in switch
3502 default:
3503 break;
3504 }
3505 }
3506 return;
3507 }
3508
3509 m_isDragging = FALSE;
3510
3511
3512 // ------------ Entering or leaving the window
3513 //
3514 if ( event.Entering() || event.Leaving() )
3515 {
3516 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
3517 }
3518
3519
3520 // ------------ Left button pressed
3521 //
3522 else if ( event.LeftDown() )
3523 {
3524 // don't send a label click event for a hit on the
3525 // edge of the row label - this is probably the user
3526 // wanting to resize the row
3527 //
3528 if ( YToEdgeOfRow(y) < 0 )
3529 {
3530 row = YToRow(y);
3531 if ( row >= 0 &&
3532 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
3533 {
3534 SelectRow( row, event.ShiftDown() );
3535 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
3536 }
3537 }
3538 else
3539 {
3540 // starting to drag-resize a row
3541 //
3542 if ( CanDragRowSize() )
3543 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
3544 }
3545 }
3546
3547
3548 // ------------ Left double click
3549 //
3550 else if (event.LeftDClick() )
3551 {
3552 if ( YToEdgeOfRow(y) < 0 )
3553 {
3554 row = YToRow(y);
3555 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
3556 }
3557 }
3558
3559
3560 // ------------ Left button released
3561 //
3562 else if ( event.LeftUp() )
3563 {
3564 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
3565 {
3566 DoEndDragResizeRow();
3567
3568 // Note: we are ending the event *after* doing
3569 // default processing in this case
3570 //
3571 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
3572 }
3573
3574 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
3575 m_dragLastPos = -1;
3576 }
3577
3578
3579 // ------------ Right button down
3580 //
3581 else if ( event.RightDown() )
3582 {
3583 row = YToRow(y);
3584 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
3585 {
3586 // no default action at the moment
3587 }
3588 }
3589
3590
3591 // ------------ Right double click
3592 //
3593 else if ( event.RightDClick() )
3594 {
3595 row = YToRow(y);
3596 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
3597 {
3598 // no default action at the moment
3599 }
3600 }
3601
3602
3603 // ------------ No buttons down and mouse moving
3604 //
3605 else if ( event.Moving() )
3606 {
3607 m_dragRowOrCol = YToEdgeOfRow( y );
3608 if ( m_dragRowOrCol >= 0 )
3609 {
3610 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
3611 {
3612 // don't capture the mouse yet
3613 if ( CanDragRowSize() )
3614 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE);
3615 }
3616 }
3617 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
3618 {
3619 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, FALSE);
3620 }
3621 }
3622 }
3623
3624
3625 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
3626 {
3627 int x, y, col;
3628 wxPoint pos( event.GetPosition() );
3629 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
3630
3631 if ( event.Dragging() )
3632 {
3633 m_isDragging = TRUE;
3634
3635 if ( event.LeftIsDown() )
3636 {
3637 switch( m_cursorMode )
3638 {
3639 case WXGRID_CURSOR_RESIZE_COL:
3640 {
3641 int cw, ch, dummy, top;
3642 m_gridWin->GetClientSize( &cw, &ch );
3643 CalcUnscrolledPosition( 0, 0, &dummy, &top );
3644
3645 wxClientDC dc( m_gridWin );
3646 PrepareDC( dc );
3647
3648 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
3649 GetColMinimalWidth(m_dragRowOrCol));
3650 dc.SetLogicalFunction(wxINVERT);
3651 if ( m_dragLastPos >= 0 )
3652 {
3653 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
3654 }
3655 dc.DrawLine( x, top, x, top+ch );
3656 m_dragLastPos = x;
3657 }
3658 break;
3659
3660 case WXGRID_CURSOR_SELECT_COL:
3661 if ( (col = XToCol( x )) >= 0 &&
3662 !IsInSelection( 0, col ) )
3663 {
3664 SelectCol( col, TRUE );
3665 }
3666
3667 // default label to suppress warnings about "enumeration value
3668 // 'xxx' not handled in switch
3669 default:
3670 break;
3671 }
3672 }
3673 return;
3674 }
3675
3676 m_isDragging = FALSE;
3677
3678
3679 // ------------ Entering or leaving the window
3680 //
3681 if ( event.Entering() || event.Leaving() )
3682 {
3683 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
3684 }
3685
3686
3687 // ------------ Left button pressed
3688 //
3689 else if ( event.LeftDown() )
3690 {
3691 // don't send a label click event for a hit on the
3692 // edge of the col label - this is probably the user
3693 // wanting to resize the col
3694 //
3695 if ( XToEdgeOfCol(x) < 0 )
3696 {
3697 col = XToCol(x);
3698 if ( col >= 0 &&
3699 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
3700 {
3701 SelectCol( col, event.ShiftDown() );
3702 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin);
3703 }
3704 }
3705 else
3706 {
3707 // starting to drag-resize a col
3708 //
3709 if ( CanDragColSize() )
3710 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
3711 }
3712 }
3713
3714
3715 // ------------ Left double click
3716 //
3717 if ( event.LeftDClick() )
3718 {
3719 if ( XToEdgeOfCol(x) < 0 )
3720 {
3721 col = XToCol(x);
3722 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
3723 }
3724 }
3725
3726
3727 // ------------ Left button released
3728 //
3729 else if ( event.LeftUp() )
3730 {
3731 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
3732 {
3733 DoEndDragResizeCol();
3734
3735 // Note: we are ending the event *after* doing
3736 // default processing in this case
3737 //
3738 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
3739 }
3740
3741 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
3742 m_dragLastPos = -1;
3743 }
3744
3745
3746 // ------------ Right button down
3747 //
3748 else if ( event.RightDown() )
3749 {
3750 col = XToCol(x);
3751 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
3752 {
3753 // no default action at the moment
3754 }
3755 }
3756
3757
3758 // ------------ Right double click
3759 //
3760 else if ( event.RightDClick() )
3761 {
3762 col = XToCol(x);
3763 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
3764 {
3765 // no default action at the moment
3766 }
3767 }
3768
3769
3770 // ------------ No buttons down and mouse moving
3771 //
3772 else if ( event.Moving() )
3773 {
3774 m_dragRowOrCol = XToEdgeOfCol( x );
3775 if ( m_dragRowOrCol >= 0 )
3776 {
3777 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
3778 {
3779 // don't capture the cursor yet
3780 if ( CanDragColSize() )
3781 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE);
3782 }
3783 }
3784 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
3785 {
3786 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, FALSE);
3787 }
3788 }
3789 }
3790
3791
3792 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
3793 {
3794 if ( event.LeftDown() )
3795 {
3796 // indicate corner label by having both row and
3797 // col args == -1
3798 //
3799 if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
3800 {
3801 SelectAll();
3802 }
3803 }
3804
3805 else if ( event.LeftDClick() )
3806 {
3807 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
3808 }
3809
3810 else if ( event.RightDown() )
3811 {
3812 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
3813 {
3814 // no default action at the moment
3815 }
3816 }
3817
3818 else if ( event.RightDClick() )
3819 {
3820 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
3821 {
3822 // no default action at the moment
3823 }
3824 }
3825 }
3826
3827 void wxGrid::ChangeCursorMode(CursorMode mode,
3828 wxWindow *win,
3829 bool captureMouse)
3830 {
3831 #ifdef __WXDEBUG__
3832 static const wxChar *cursorModes[] =
3833 {
3834 _T("SELECT_CELL"),
3835 _T("RESIZE_ROW"),
3836 _T("RESIZE_COL"),
3837 _T("SELECT_ROW"),
3838 _T("SELECT_COL")
3839 };
3840
3841 wxLogTrace(_T("grid"),
3842 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
3843 win == m_colLabelWin ? _T("colLabelWin")
3844 : win ? _T("rowLabelWin")
3845 : _T("gridWin"),
3846 cursorModes[m_cursorMode], cursorModes[mode]);
3847 #endif // __WXDEBUG__
3848
3849 if ( mode == m_cursorMode )
3850 return;
3851
3852 if ( !win )
3853 {
3854 // by default use the grid itself
3855 win = m_gridWin;
3856 }
3857
3858 if ( m_winCapture )
3859 {
3860 m_winCapture->ReleaseMouse();
3861 m_winCapture = (wxWindow *)NULL;
3862 }
3863
3864 m_cursorMode = mode;
3865
3866 switch ( m_cursorMode )
3867 {
3868 case WXGRID_CURSOR_RESIZE_ROW:
3869 win->SetCursor( m_rowResizeCursor );
3870 break;
3871
3872 case WXGRID_CURSOR_RESIZE_COL:
3873 win->SetCursor( m_colResizeCursor );
3874 break;
3875
3876 default:
3877 win->SetCursor( *wxSTANDARD_CURSOR );
3878 }
3879
3880 // we need to capture mouse when resizing
3881 bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
3882 m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
3883
3884 if ( captureMouse && resize )
3885 {
3886 win->CaptureMouse();
3887 m_winCapture = win;
3888 }
3889 }
3890
3891 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
3892 {
3893 int x, y;
3894 wxPoint pos( event.GetPosition() );
3895 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
3896
3897 wxGridCellCoords coords;
3898 XYToCell( x, y, coords );
3899
3900 if ( event.Dragging() )
3901 {
3902 //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol());
3903
3904 // Don't start doing anything until the mouse has been drug at
3905 // least 3 pixels in any direction...
3906 if (! m_isDragging)
3907 {
3908 if (m_startDragPos == wxDefaultPosition)
3909 {
3910 m_startDragPos = pos;
3911 return;
3912 }
3913 if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4)
3914 return;
3915 }
3916
3917 m_isDragging = TRUE;
3918 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
3919 {
3920 // Hide the edit control, so it
3921 // won't interfer with drag-shrinking.
3922 if ( IsCellEditControlEnabled() )
3923 {
3924 HideCellEditControl();
3925 SaveEditControlValue();
3926 }
3927
3928 // Have we captured the mouse yet?
3929 if (! m_winCapture)
3930 {
3931 m_winCapture = m_gridWin;
3932 m_winCapture->CaptureMouse();
3933 }
3934
3935 if ( coords != wxGridNoCellCoords )
3936 {
3937 if ( !IsSelection() )
3938 {
3939 SelectBlock( coords, coords );
3940 }
3941 else
3942 {
3943 SelectBlock( m_currentCellCoords, coords );
3944 }
3945
3946 if (! IsVisible(coords))
3947 {
3948 MakeCellVisible(coords);
3949 // TODO: need to introduce a delay or something here. The
3950 // scrolling is way to fast, at least on MSW.
3951 }
3952 }
3953 }
3954 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
3955 {
3956 int cw, ch, left, dummy;
3957 m_gridWin->GetClientSize( &cw, &ch );
3958 CalcUnscrolledPosition( 0, 0, &left, &dummy );
3959
3960 wxClientDC dc( m_gridWin );
3961 PrepareDC( dc );
3962 y = wxMax( y, GetRowTop(m_dragRowOrCol) + WXGRID_MIN_ROW_HEIGHT );
3963 dc.SetLogicalFunction(wxINVERT);
3964 if ( m_dragLastPos >= 0 )
3965 {
3966 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
3967 }
3968 dc.DrawLine( left, y, left+cw, y );
3969 m_dragLastPos = y;
3970 }
3971 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
3972 {
3973 int cw, ch, dummy, top;
3974 m_gridWin->GetClientSize( &cw, &ch );
3975 CalcUnscrolledPosition( 0, 0, &dummy, &top );
3976
3977 wxClientDC dc( m_gridWin );
3978 PrepareDC( dc );
3979 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
3980 GetColMinimalWidth(m_dragRowOrCol) );
3981 dc.SetLogicalFunction(wxINVERT);
3982 if ( m_dragLastPos >= 0 )
3983 {
3984 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
3985 }
3986 dc.DrawLine( x, top, x, top+ch );
3987 m_dragLastPos = x;
3988 }
3989
3990 return;
3991 }
3992
3993 m_isDragging = FALSE;
3994 m_startDragPos = wxDefaultPosition;
3995
3996 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
3997 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
3998 // wxGTK
3999 #if 0
4000 if ( event.Entering() || event.Leaving() )
4001 {
4002 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4003 m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
4004 }
4005 else
4006 #endif // 0
4007
4008 // ------------ Left button pressed
4009 //
4010 if ( event.LeftDown() && coords != wxGridNoCellCoords )
4011 {
4012 if ( event.ShiftDown() )
4013 {
4014 SelectBlock( m_currentCellCoords, coords );
4015 }
4016 else if ( XToEdgeOfCol(x) < 0 &&
4017 YToEdgeOfRow(y) < 0 )
4018 {
4019 if ( !SendEvent( wxEVT_GRID_CELL_LEFT_CLICK,
4020 coords.GetRow(),
4021 coords.GetCol(),
4022 event ) )
4023 {
4024 DisableCellEditControl();
4025 MakeCellVisible( coords );
4026
4027 // if this is the second click on this cell then start
4028 // the edit control
4029 if ( m_waitForSlowClick &&
4030 (coords == m_currentCellCoords) &&
4031 CanEnableCellControl())
4032 {
4033 EnableCellEditControl();
4034
4035 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
4036 attr->GetEditor(this, coords.GetRow(), coords.GetCol())->StartingClick();
4037 attr->DecRef();
4038
4039 m_waitForSlowClick = FALSE;
4040 }
4041 else
4042 {
4043 SetCurrentCell( coords );
4044 m_waitForSlowClick = TRUE;
4045 }
4046 }
4047 }
4048 }
4049
4050
4051 // ------------ Left double click
4052 //
4053 else if ( event.LeftDClick() && coords != wxGridNoCellCoords )
4054 {
4055 DisableCellEditControl();
4056
4057 if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 )
4058 {
4059 SendEvent( wxEVT_GRID_CELL_LEFT_DCLICK,
4060 coords.GetRow(),
4061 coords.GetCol(),
4062 event );
4063 }
4064 }
4065
4066
4067 // ------------ Left button released
4068 //
4069 else if ( event.LeftUp() )
4070 {
4071 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4072 {
4073 if ( IsSelection() )
4074 {
4075 if (m_winCapture)
4076 {
4077 m_winCapture->ReleaseMouse();
4078 m_winCapture = NULL;
4079 }
4080 SendEvent( wxEVT_GRID_RANGE_SELECT, -1, -1, event );
4081 }
4082
4083 // Show the edit control, if it has been hidden for
4084 // drag-shrinking.
4085 ShowCellEditControl();
4086 }
4087 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
4088 {
4089 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4090 DoEndDragResizeRow();
4091
4092 // Note: we are ending the event *after* doing
4093 // default processing in this case
4094 //
4095 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
4096 }
4097 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4098 {
4099 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4100 DoEndDragResizeCol();
4101
4102 // Note: we are ending the event *after* doing
4103 // default processing in this case
4104 //
4105 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
4106 }
4107
4108 m_dragLastPos = -1;
4109 }
4110
4111
4112 // ------------ Right button down
4113 //
4114 else if ( event.RightDown() && coords != wxGridNoCellCoords )
4115 {
4116 DisableCellEditControl();
4117 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_CLICK,
4118 coords.GetRow(),
4119 coords.GetCol(),
4120 event ) )
4121 {
4122 // no default action at the moment
4123 }
4124 }
4125
4126
4127 // ------------ Right double click
4128 //
4129 else if ( event.RightDClick() && coords != wxGridNoCellCoords )
4130 {
4131 DisableCellEditControl();
4132 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_DCLICK,
4133 coords.GetRow(),
4134 coords.GetCol(),
4135 event ) )
4136 {
4137 // no default action at the moment
4138 }
4139 }
4140
4141 // ------------ Moving and no button action
4142 //
4143 else if ( event.Moving() && !event.IsButton() )
4144 {
4145 int dragRow = YToEdgeOfRow( y );
4146 int dragCol = XToEdgeOfCol( x );
4147
4148 // Dragging on the corner of a cell to resize in both
4149 // directions is not implemented yet...
4150 //
4151 if ( dragRow >= 0 && dragCol >= 0 )
4152 {
4153 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4154 return;
4155 }
4156
4157 if ( dragRow >= 0 )
4158 {
4159 m_dragRowOrCol = dragRow;
4160
4161 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4162 {
4163 if ( CanDragRowSize() && CanDragGridSize() )
4164 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
4165 }
4166
4167 if ( dragCol >= 0 )
4168 {
4169 m_dragRowOrCol = dragCol;
4170 }
4171
4172 return;
4173 }
4174
4175 if ( dragCol >= 0 )
4176 {
4177 m_dragRowOrCol = dragCol;
4178
4179 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4180 {
4181 if ( CanDragColSize() && CanDragGridSize() )
4182 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
4183 }
4184
4185 return;
4186 }
4187
4188 // Neither on a row or col edge
4189 //
4190 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
4191 {
4192 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4193 }
4194 }
4195 }
4196
4197
4198 void wxGrid::DoEndDragResizeRow()
4199 {
4200 if ( m_dragLastPos >= 0 )
4201 {
4202 // erase the last line and resize the row
4203 //
4204 int cw, ch, left, dummy;
4205 m_gridWin->GetClientSize( &cw, &ch );
4206 CalcUnscrolledPosition( 0, 0, &left, &dummy );
4207
4208 wxClientDC dc( m_gridWin );
4209 PrepareDC( dc );
4210 dc.SetLogicalFunction( wxINVERT );
4211 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
4212 HideCellEditControl();
4213 SaveEditControlValue();
4214
4215 int rowTop = GetRowTop(m_dragRowOrCol);
4216 SetRowSize( m_dragRowOrCol,
4217 wxMax( m_dragLastPos - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
4218
4219 if ( !GetBatchCount() )
4220 {
4221 // Only needed to get the correct rect.y:
4222 wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
4223 rect.x = 0;
4224 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
4225 rect.width = m_rowLabelWidth;
4226 rect.height = ch - rect.y;
4227 m_rowLabelWin->Refresh( TRUE, &rect );
4228 rect.width = cw;
4229 m_gridWin->Refresh( FALSE, &rect );
4230 }
4231
4232 ShowCellEditControl();
4233 }
4234 }
4235
4236
4237 void wxGrid::DoEndDragResizeCol()
4238 {
4239 if ( m_dragLastPos >= 0 )
4240 {
4241 // erase the last line and resize the col
4242 //
4243 int cw, ch, dummy, top;
4244 m_gridWin->GetClientSize( &cw, &ch );
4245 CalcUnscrolledPosition( 0, 0, &dummy, &top );
4246
4247 wxClientDC dc( m_gridWin );
4248 PrepareDC( dc );
4249 dc.SetLogicalFunction( wxINVERT );
4250 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
4251 HideCellEditControl();
4252 SaveEditControlValue();
4253
4254 int colLeft = GetColLeft(m_dragRowOrCol);
4255 SetColSize( m_dragRowOrCol,
4256 wxMax( m_dragLastPos - colLeft,
4257 GetColMinimalWidth(m_dragRowOrCol) ) );
4258
4259 if ( !GetBatchCount() )
4260 {
4261 // Only needed to get the correct rect.x:
4262 wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
4263 rect.y = 0;
4264 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
4265 rect.width = cw - rect.x;
4266 rect.height = m_colLabelHeight;
4267 m_colLabelWin->Refresh( TRUE, &rect );
4268 rect.height = ch;
4269 m_gridWin->Refresh( FALSE, &rect );
4270 }
4271
4272 ShowCellEditControl();
4273 }
4274 }
4275
4276
4277
4278 //
4279 // ------ interaction with data model
4280 //
4281 bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
4282 {
4283 switch ( msg.GetId() )
4284 {
4285 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
4286 return GetModelValues();
4287
4288 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
4289 return SetModelValues();
4290
4291 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
4292 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
4293 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
4294 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
4295 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
4296 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
4297 return Redimension( msg );
4298
4299 default:
4300 return FALSE;
4301 }
4302 }
4303
4304
4305
4306 // The behaviour of this function depends on the grid table class
4307 // Clear() function. For the default wxGridStringTable class the
4308 // behavious is to replace all cell contents with wxEmptyString but
4309 // not to change the number of rows or cols.
4310 //
4311 void wxGrid::ClearGrid()
4312 {
4313 if ( m_table )
4314 {
4315 if (IsCellEditControlEnabled())
4316 DisableCellEditControl();
4317
4318 m_table->Clear();
4319 if ( !GetBatchCount() ) m_gridWin->Refresh();
4320 }
4321 }
4322
4323
4324 bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
4325 {
4326 // TODO: something with updateLabels flag
4327
4328 if ( !m_created )
4329 {
4330 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
4331 return FALSE;
4332 }
4333
4334 if ( m_table )
4335 {
4336 if (IsCellEditControlEnabled())
4337 DisableCellEditControl();
4338
4339 bool ok = m_table->InsertRows( pos, numRows );
4340
4341 // the table will have sent the results of the insert row
4342 // operation to this view object as a grid table message
4343 //
4344 if ( ok )
4345 {
4346 if ( m_numCols == 0 )
4347 {
4348 m_table->AppendCols( WXGRID_DEFAULT_NUMBER_COLS );
4349 //
4350 // TODO: perhaps instead of appending the default number of cols
4351 // we should remember what the last non-zero number of cols was ?
4352 //
4353 }
4354
4355 if ( m_currentCellCoords == wxGridNoCellCoords )
4356 {
4357 // if we have just inserted cols into an empty grid the current
4358 // cell will be undefined...
4359 //
4360 SetCurrentCell( 0, 0 );
4361 }
4362
4363 ClearSelection();
4364 if ( !GetBatchCount() ) Refresh();
4365 }
4366
4367 return ok;
4368 }
4369 else
4370 {
4371 return FALSE;
4372 }
4373 }
4374
4375
4376 bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
4377 {
4378 // TODO: something with updateLabels flag
4379
4380 if ( !m_created )
4381 {
4382 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
4383 return FALSE;
4384 }
4385
4386 if ( m_table && m_table->AppendRows( numRows ) )
4387 {
4388 if ( m_currentCellCoords == wxGridNoCellCoords )
4389 {
4390 // if we have just inserted cols into an empty grid the current
4391 // cell will be undefined...
4392 //
4393 SetCurrentCell( 0, 0 );
4394 }
4395
4396 // the table will have sent the results of the append row
4397 // operation to this view object as a grid table message
4398 //
4399 ClearSelection();
4400 if ( !GetBatchCount() ) Refresh();
4401 return TRUE;
4402 }
4403 else
4404 {
4405 return FALSE;
4406 }
4407 }
4408
4409
4410 bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
4411 {
4412 // TODO: something with updateLabels flag
4413
4414 if ( !m_created )
4415 {
4416 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
4417 return FALSE;
4418 }
4419
4420 if ( m_table )
4421 {
4422 if (IsCellEditControlEnabled())
4423 DisableCellEditControl();
4424
4425 if (m_table->DeleteRows( pos, numRows ))
4426 {
4427
4428 // the table will have sent the results of the delete row
4429 // operation to this view object as a grid table message
4430 //
4431 ClearSelection();
4432 if ( !GetBatchCount() ) Refresh();
4433 return TRUE;
4434 }
4435 }
4436 return FALSE;
4437 }
4438
4439
4440 bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
4441 {
4442 // TODO: something with updateLabels flag
4443
4444 if ( !m_created )
4445 {
4446 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
4447 return FALSE;
4448 }
4449
4450 if ( m_table )
4451 {
4452 if (IsCellEditControlEnabled())
4453 DisableCellEditControl();
4454
4455 bool ok = m_table->InsertCols( pos, numCols );
4456
4457 // the table will have sent the results of the insert col
4458 // operation to this view object as a grid table message
4459 //
4460 if ( ok )
4461 {
4462 if ( m_currentCellCoords == wxGridNoCellCoords )
4463 {
4464 // if we have just inserted cols into an empty grid the current
4465 // cell will be undefined...
4466 //
4467 SetCurrentCell( 0, 0 );
4468 }
4469
4470 ClearSelection();
4471 if ( !GetBatchCount() ) Refresh();
4472 }
4473
4474 return ok;
4475 }
4476 else
4477 {
4478 return FALSE;
4479 }
4480 }
4481
4482
4483 bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
4484 {
4485 // TODO: something with updateLabels flag
4486
4487 if ( !m_created )
4488 {
4489 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
4490 return FALSE;
4491 }
4492
4493 if ( m_table && m_table->AppendCols( numCols ) )
4494 {
4495 // the table will have sent the results of the append col
4496 // operation to this view object as a grid table message
4497 //
4498 if ( m_currentCellCoords == wxGridNoCellCoords )
4499 {
4500 // if we have just inserted cols into an empty grid the current
4501 // cell will be undefined...
4502 //
4503 SetCurrentCell( 0, 0 );
4504 }
4505
4506 ClearSelection();
4507 if ( !GetBatchCount() ) Refresh();
4508 return TRUE;
4509 }
4510 else
4511 {
4512 return FALSE;
4513 }
4514 }
4515
4516
4517 bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
4518 {
4519 // TODO: something with updateLabels flag
4520
4521 if ( !m_created )
4522 {
4523 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
4524 return FALSE;
4525 }
4526
4527 if ( m_table )
4528 {
4529 if (IsCellEditControlEnabled())
4530 DisableCellEditControl();
4531
4532 if ( m_table->DeleteCols( pos, numCols ) )
4533 {
4534 // the table will have sent the results of the delete col
4535 // operation to this view object as a grid table message
4536 //
4537 ClearSelection();
4538 if ( !GetBatchCount() ) Refresh();
4539 return TRUE;
4540 }
4541 }
4542 return FALSE;
4543 }
4544
4545
4546
4547 //
4548 // ----- event handlers
4549 //
4550
4551 // Generate a grid event based on a mouse event and
4552 // return the result of ProcessEvent()
4553 //
4554 bool wxGrid::SendEvent( const wxEventType type,
4555 int row, int col,
4556 wxMouseEvent& mouseEv )
4557 {
4558 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
4559 {
4560 int rowOrCol = (row == -1 ? col : row);
4561
4562 wxGridSizeEvent gridEvt( GetId(),
4563 type,
4564 this,
4565 rowOrCol,
4566 mouseEv.GetX(), mouseEv.GetY(),
4567 mouseEv.ControlDown(),
4568 mouseEv.ShiftDown(),
4569 mouseEv.AltDown(),
4570 mouseEv.MetaDown() );
4571
4572 return GetEventHandler()->ProcessEvent(gridEvt);
4573 }
4574 else if ( type == wxEVT_GRID_RANGE_SELECT )
4575 {
4576 wxGridRangeSelectEvent gridEvt( GetId(),
4577 type,
4578 this,
4579 m_selectedTopLeft,
4580 m_selectedBottomRight,
4581 mouseEv.ControlDown(),
4582 mouseEv.ShiftDown(),
4583 mouseEv.AltDown(),
4584 mouseEv.MetaDown() );
4585
4586 return GetEventHandler()->ProcessEvent(gridEvt);
4587 }
4588 else
4589 {
4590 wxGridEvent gridEvt( GetId(),
4591 type,
4592 this,
4593 row, col,
4594 mouseEv.GetX(), mouseEv.GetY(),
4595 mouseEv.ControlDown(),
4596 mouseEv.ShiftDown(),
4597 mouseEv.AltDown(),
4598 mouseEv.MetaDown() );
4599
4600 return GetEventHandler()->ProcessEvent(gridEvt);
4601 }
4602 }
4603
4604
4605 // Generate a grid event of specified type and return the result
4606 // of ProcessEvent().
4607 //
4608 bool wxGrid::SendEvent( const wxEventType type,
4609 int row, int col )
4610 {
4611 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
4612 {
4613 int rowOrCol = (row == -1 ? col : row);
4614
4615 wxGridSizeEvent gridEvt( GetId(),
4616 type,
4617 this,
4618 rowOrCol );
4619
4620 return GetEventHandler()->ProcessEvent(gridEvt);
4621 }
4622 else
4623 {
4624 wxGridEvent gridEvt( GetId(),
4625 type,
4626 this,
4627 row, col );
4628
4629 return GetEventHandler()->ProcessEvent(gridEvt);
4630 }
4631 }
4632
4633
4634 void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
4635 {
4636 wxPaintDC dc( this );
4637
4638 if ( m_currentCellCoords == wxGridNoCellCoords &&
4639 m_numRows && m_numCols )
4640 {
4641 m_currentCellCoords.Set(0, 0);
4642 ShowCellEditControl();
4643 }
4644
4645 m_displayed = TRUE;
4646 }
4647
4648
4649 // This is just here to make sure that CalcDimensions gets called when
4650 // the grid view is resized... then the size event is skipped to allow
4651 // the box sizers to handle everything
4652 //
4653 void wxGrid::OnSize( wxSizeEvent& event )
4654 {
4655 CalcWindowSizes();
4656 CalcDimensions();
4657 }
4658
4659
4660 void wxGrid::OnKeyDown( wxKeyEvent& event )
4661 {
4662 if ( m_inOnKeyDown )
4663 {
4664 // shouldn't be here - we are going round in circles...
4665 //
4666 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") );
4667 }
4668
4669 m_inOnKeyDown = TRUE;
4670
4671 // propagate the event up and see if it gets processed
4672 //
4673 wxWindow *parent = GetParent();
4674 wxKeyEvent keyEvt( event );
4675 keyEvt.SetEventObject( parent );
4676
4677 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
4678 {
4679
4680 // TODO: Should also support Shift-cursor keys for
4681 // extending the selection. Maybe add a flag to
4682 // MoveCursorXXX() and MoveCursorXXXBlock() and
4683 // just send event.ShiftDown().
4684
4685 // try local handlers
4686 //
4687 switch ( event.KeyCode() )
4688 {
4689 case WXK_UP:
4690 if ( event.ControlDown() )
4691 {
4692 MoveCursorUpBlock();
4693 }
4694 else
4695 {
4696 MoveCursorUp();
4697 }
4698 break;
4699
4700 case WXK_DOWN:
4701 if ( event.ControlDown() )
4702 {
4703 MoveCursorDownBlock();
4704 }
4705 else
4706 {
4707 MoveCursorDown();
4708 }
4709 break;
4710
4711 case WXK_LEFT:
4712 if ( event.ControlDown() )
4713 {
4714 MoveCursorLeftBlock();
4715 }
4716 else
4717 {
4718 MoveCursorLeft();
4719 }
4720 break;
4721
4722 case WXK_RIGHT:
4723 if ( event.ControlDown() )
4724 {
4725 MoveCursorRightBlock();
4726 }
4727 else
4728 {
4729 MoveCursorRight();
4730 }
4731 break;
4732
4733 case WXK_RETURN:
4734 if ( event.ControlDown() )
4735 {
4736 event.Skip(); // to let the edit control have the return
4737 }
4738 else
4739 {
4740 MoveCursorDown();
4741 }
4742 break;
4743
4744 case WXK_TAB:
4745 if (event.ShiftDown())
4746 MoveCursorLeft();
4747 else
4748 MoveCursorRight();
4749 break;
4750
4751 case WXK_HOME:
4752 if ( event.ControlDown() )
4753 {
4754 MakeCellVisible( 0, 0 );
4755 SetCurrentCell( 0, 0 );
4756 }
4757 else
4758 {
4759 event.Skip();
4760 }
4761 break;
4762
4763 case WXK_END:
4764 if ( event.ControlDown() )
4765 {
4766 MakeCellVisible( m_numRows-1, m_numCols-1 );
4767 SetCurrentCell( m_numRows-1, m_numCols-1 );
4768 }
4769 else
4770 {
4771 event.Skip();
4772 }
4773 break;
4774
4775 case WXK_PRIOR:
4776 MovePageUp();
4777 break;
4778
4779 case WXK_NEXT:
4780 MovePageDown();
4781 break;
4782
4783 case WXK_SPACE:
4784 if ( !IsEditable() )
4785 {
4786 MoveCursorRight();
4787 break;
4788 }
4789 // Otherwise fall through to default
4790
4791 default:
4792 // alphanumeric keys or F2 (special key just for this) enable
4793 // the cell edit control
4794 if ( !(event.AltDown() ||
4795 event.MetaDown() ||
4796 event.ControlDown()) &&
4797 (isalnum(event.KeyCode()) || event.KeyCode() == WXK_F2) &&
4798 !IsCellEditControlEnabled() &&
4799 CanEnableCellControl() )
4800 {
4801 EnableCellEditControl();
4802 int row = m_currentCellCoords.GetRow();
4803 int col = m_currentCellCoords.GetCol();
4804 wxGridCellAttr* attr = GetCellAttr(row, col);
4805 attr->GetEditor(this, row, col)->StartingKey(event);
4806 attr->DecRef();
4807 }
4808 else
4809 {
4810 // let others process char events with modifiers or all
4811 // char events for readonly cells
4812 event.Skip();
4813 }
4814 break;
4815 }
4816 }
4817
4818 m_inOnKeyDown = FALSE;
4819 }
4820
4821
4822 void wxGrid::OnEraseBackground(wxEraseEvent&)
4823 {
4824 }
4825
4826 void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
4827 {
4828 if ( SendEvent( wxEVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
4829 {
4830 // the event has been intercepted - do nothing
4831 return;
4832 }
4833
4834 if ( m_displayed &&
4835 m_currentCellCoords != wxGridNoCellCoords )
4836 {
4837 HideCellEditControl();
4838 DisableCellEditControl();
4839
4840 // Clear the old current cell highlight
4841 wxRect r = BlockToDeviceRect(m_currentCellCoords, m_currentCellCoords);
4842
4843 // Otherwise refresh redraws the highlight!
4844 m_currentCellCoords = coords;
4845
4846 m_gridWin->Refresh( FALSE, &r );
4847 }
4848
4849 m_currentCellCoords = coords;
4850
4851 if ( m_displayed )
4852 {
4853 wxClientDC dc(m_gridWin);
4854 PrepareDC(dc);
4855
4856 wxGridCellAttr* attr = GetCellAttr(coords);
4857 DrawCellHighlight(dc, attr);
4858 attr->DecRef();
4859
4860 if ( IsSelection() )
4861 {
4862 wxRect r( SelectionToDeviceRect() );
4863 ClearSelection();
4864 if ( !GetBatchCount() ) m_gridWin->Refresh( FALSE, &r );
4865 }
4866 }
4867 }
4868
4869
4870 //
4871 // ------ functions to get/send data (see also public functions)
4872 //
4873
4874 bool wxGrid::GetModelValues()
4875 {
4876 if ( m_table )
4877 {
4878 // all we need to do is repaint the grid
4879 //
4880 m_gridWin->Refresh();
4881 return TRUE;
4882 }
4883
4884 return FALSE;
4885 }
4886
4887
4888 bool wxGrid::SetModelValues()
4889 {
4890 int row, col;
4891
4892 if ( m_table )
4893 {
4894 for ( row = 0; row < m_numRows; row++ )
4895 {
4896 for ( col = 0; col < m_numCols; col++ )
4897 {
4898 m_table->SetValue( row, col, GetCellValue(row, col) );
4899 }
4900 }
4901
4902 return TRUE;
4903 }
4904
4905 return FALSE;
4906 }
4907
4908
4909
4910 // Note - this function only draws cells that are in the list of
4911 // exposed cells (usually set from the update region by
4912 // CalcExposedCells)
4913 //
4914 void wxGrid::DrawGridCellArea( wxDC& dc )
4915 {
4916 if ( !m_numRows || !m_numCols ) return;
4917
4918 size_t i;
4919 size_t numCells = m_cellsExposed.GetCount();
4920
4921 for ( i = 0; i < numCells; i++ )
4922 {
4923 DrawCell( dc, m_cellsExposed[i] );
4924 }
4925 }
4926
4927
4928 void wxGrid::DrawGridSpace( wxDC& dc )
4929 {
4930 if ( m_numRows && m_numCols )
4931 {
4932 int cw, ch;
4933 m_gridWin->GetClientSize( &cw, &ch );
4934
4935 int right, bottom;
4936 CalcUnscrolledPosition( cw, ch, &right, &bottom );
4937
4938 if ( right > GetColRight(m_numCols-1) ||
4939 bottom > GetRowBottom(m_numRows-1) )
4940 {
4941 int left, top;
4942 CalcUnscrolledPosition( 0, 0, &left, &top );
4943
4944 dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) );
4945 dc.SetPen( *wxTRANSPARENT_PEN );
4946
4947 if ( right > GetColRight(m_numCols-1) )
4948 dc.DrawRectangle( GetColRight(m_numCols-1), top,
4949 right - GetColRight(m_numCols-1), ch );
4950
4951 if ( bottom > GetRowBottom(m_numRows-1) )
4952 dc.DrawRectangle( left, GetRowBottom(m_numRows-1),
4953 cw, bottom - GetRowBottom(m_numRows-1) );
4954 }
4955 }
4956 }
4957
4958
4959 void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
4960 {
4961 int row = coords.GetRow();
4962 int col = coords.GetCol();
4963
4964 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
4965 return;
4966
4967 // we draw the cell border ourselves
4968 #if !WXGRID_DRAW_LINES
4969 if ( m_gridLinesEnabled )
4970 DrawCellBorder( dc, coords );
4971 #endif
4972
4973 wxGridCellAttr* attr = GetCellAttr(row, col);
4974
4975 bool isCurrent = coords == m_currentCellCoords;
4976
4977 wxRect rect;
4978 rect.x = GetColLeft(col);
4979 rect.y = GetRowTop(row);
4980 rect.width = GetColWidth(col) - 1;
4981 rect.height = GetRowHeight(row) - 1;
4982
4983 // if the editor is shown, we should use it and not the renderer
4984 if ( isCurrent && IsCellEditControlEnabled() )
4985 {
4986 attr->GetEditor(this, row, col)->PaintBackground(rect, attr);
4987 }
4988 else
4989 {
4990 // but all the rest is drawn by the cell renderer and hence may be
4991 // customized
4992 attr->GetRenderer(this, row, col)->
4993 Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
4994
4995 }
4996
4997 attr->DecRef();
4998 }
4999
5000 void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr )
5001 {
5002 int row = m_currentCellCoords.GetRow();
5003 int col = m_currentCellCoords.GetCol();
5004
5005 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
5006 return;
5007
5008 wxRect rect;
5009 rect.x = GetColLeft(col);
5010 rect.y = GetRowTop(row);
5011 rect.width = GetColWidth(col) - 1;
5012 rect.height = GetRowHeight(row) - 1;
5013
5014 // hmmm... what could we do here to show that the cell is disabled?
5015 // for now, I just draw a thinner border than for the other ones, but
5016 // it doesn't look really good
5017 dc.SetPen(wxPen(m_gridLineColour, attr->IsReadOnly() ? 1 : 3, wxSOLID));
5018 dc.SetBrush(*wxTRANSPARENT_BRUSH);
5019
5020 dc.DrawRectangle(rect);
5021
5022 #if 0
5023 // VZ: my experiments with 3d borders...
5024
5025 // how to properly set colours for arbitrary bg?
5026 wxCoord x1 = rect.x,
5027 y1 = rect.y,
5028 x2 = rect.x + rect.width -1,
5029 y2 = rect.y + rect.height -1;
5030
5031 dc.SetPen(*wxWHITE_PEN);
5032 dc.DrawLine(x1, y1, x2, y1);
5033 dc.DrawLine(x1, y1, x1, y2);
5034
5035 dc.DrawLine(x1 + 1, y2 - 1, x2 - 1, y2 - 1);
5036 dc.DrawLine(x2 - 1, y1 + 1, x2 - 1, y2 );
5037
5038 dc.SetPen(*wxBLACK_PEN);
5039 dc.DrawLine(x1, y2, x2, y2);
5040 dc.DrawLine(x2, y1, x2, y2+1);
5041 #endif // 0
5042 }
5043
5044
5045 void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
5046 {
5047 int row = coords.GetRow();
5048 int col = coords.GetCol();
5049 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
5050 return;
5051
5052 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
5053
5054 // right hand border
5055 //
5056 dc.DrawLine( GetColRight(col), GetRowTop(row),
5057 GetColRight(col), GetRowBottom(row) );
5058
5059 // bottom border
5060 //
5061 dc.DrawLine( GetColLeft(col), GetRowBottom(row),
5062 GetColRight(col), GetRowBottom(row) );
5063 }
5064
5065 void wxGrid::DrawHighlight(wxDC& dc)
5066 {
5067 if ( IsCellEditControlEnabled() )
5068 {
5069 // don't show highlight when the edit control is shown
5070 return;
5071 }
5072
5073 // if the active cell was repainted, repaint its highlight too because it
5074 // might have been damaged by the grid lines
5075 size_t count = m_cellsExposed.GetCount();
5076 for ( size_t n = 0; n < count; n++ )
5077 {
5078 if ( m_cellsExposed[n] == m_currentCellCoords )
5079 {
5080 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
5081 DrawCellHighlight(dc, attr);
5082 attr->DecRef();
5083
5084 break;
5085 }
5086 }
5087 }
5088
5089 // TODO: remove this ???
5090 // This is used to redraw all grid lines e.g. when the grid line colour
5091 // has been changed
5092 //
5093 void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & reg )
5094 {
5095 if ( !m_gridLinesEnabled ||
5096 !m_numRows ||
5097 !m_numCols ) return;
5098
5099 int top, bottom, left, right;
5100
5101 #ifndef __WXGTK__
5102 if (reg.IsEmpty())
5103 {
5104 int cw, ch;
5105 m_gridWin->GetClientSize(&cw, &ch);
5106
5107 // virtual coords of visible area
5108 //
5109 CalcUnscrolledPosition( 0, 0, &left, &top );
5110 CalcUnscrolledPosition( cw, ch, &right, &bottom );
5111 }
5112 else
5113 {
5114 wxCoord x, y, w, h;
5115 reg.GetBox(x, y, w, h);
5116 CalcUnscrolledPosition( x, y, &left, &top );
5117 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
5118 }
5119 #else
5120 int cw, ch;
5121 m_gridWin->GetClientSize(&cw, &ch);
5122 CalcUnscrolledPosition( 0, 0, &left, &top );
5123 CalcUnscrolledPosition( cw, ch, &right, &bottom );
5124 #endif
5125
5126 // avoid drawing grid lines past the last row and col
5127 //
5128 right = wxMin( right, GetColRight(m_numCols - 1) );
5129 bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) );
5130
5131 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
5132
5133 // horizontal grid lines
5134 //
5135 int i;
5136 for ( i = 0; i < m_numRows; i++ )
5137 {
5138 int bot = GetRowBottom(i) - 1;
5139
5140 if ( bot > bottom )
5141 {
5142 break;
5143 }
5144
5145 if ( bot >= top )
5146 {
5147 dc.DrawLine( left, bot, right, bot );
5148 }
5149 }
5150
5151
5152 // vertical grid lines
5153 //
5154 for ( i = 0; i < m_numCols; i++ )
5155 {
5156 int colRight = GetColRight(i) - 1;
5157 if ( colRight > right )
5158 {
5159 break;
5160 }
5161
5162 if ( colRight >= left )
5163 {
5164 dc.DrawLine( colRight, top, colRight, bottom );
5165 }
5166 }
5167 }
5168
5169
5170 void wxGrid::DrawRowLabels( wxDC& dc )
5171 {
5172 if ( !m_numRows || !m_numCols ) return;
5173
5174 size_t i;
5175 size_t numLabels = m_rowLabelsExposed.GetCount();
5176
5177 for ( i = 0; i < numLabels; i++ )
5178 {
5179 DrawRowLabel( dc, m_rowLabelsExposed[i] );
5180 }
5181 }
5182
5183
5184 void wxGrid::DrawRowLabel( wxDC& dc, int row )
5185 {
5186 if ( GetRowHeight(row) <= 0 )
5187 return;
5188
5189 int rowTop = GetRowTop(row),
5190 rowBottom = GetRowBottom(row) - 1;
5191
5192 dc.SetPen( *wxBLACK_PEN );
5193 dc.DrawLine( m_rowLabelWidth-1, rowTop,
5194 m_rowLabelWidth-1, rowBottom );
5195
5196 dc.DrawLine( 0, rowBottom, m_rowLabelWidth-1, rowBottom );
5197
5198 dc.SetPen( *wxWHITE_PEN );
5199 dc.DrawLine( 0, rowTop, 0, rowBottom );
5200 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
5201
5202 dc.SetBackgroundMode( wxTRANSPARENT );
5203 dc.SetTextForeground( GetLabelTextColour() );
5204 dc.SetFont( GetLabelFont() );
5205
5206 int hAlign, vAlign;
5207 GetRowLabelAlignment( &hAlign, &vAlign );
5208
5209 wxRect rect;
5210 rect.SetX( 2 );
5211 rect.SetY( GetRowTop(row) + 2 );
5212 rect.SetWidth( m_rowLabelWidth - 4 );
5213 rect.SetHeight( GetRowHeight(row) - 4 );
5214 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
5215 }
5216
5217
5218 void wxGrid::DrawColLabels( wxDC& dc )
5219 {
5220 if ( !m_numRows || !m_numCols ) return;
5221
5222 size_t i;
5223 size_t numLabels = m_colLabelsExposed.GetCount();
5224
5225 for ( i = 0; i < numLabels; i++ )
5226 {
5227 DrawColLabel( dc, m_colLabelsExposed[i] );
5228 }
5229 }
5230
5231
5232 void wxGrid::DrawColLabel( wxDC& dc, int col )
5233 {
5234 if ( GetColWidth(col) <= 0 )
5235 return;
5236
5237 int colLeft = GetColLeft(col),
5238 colRight = GetColRight(col) - 1;
5239
5240 dc.SetPen( *wxBLACK_PEN );
5241 dc.DrawLine( colRight, 0,
5242 colRight, m_colLabelHeight-1 );
5243
5244 dc.DrawLine( colLeft, m_colLabelHeight-1,
5245 colRight, m_colLabelHeight-1 );
5246
5247 dc.SetPen( *wxWHITE_PEN );
5248 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
5249 dc.DrawLine( colLeft, 0, colRight, 0 );
5250
5251 dc.SetBackgroundMode( wxTRANSPARENT );
5252 dc.SetTextForeground( GetLabelTextColour() );
5253 dc.SetFont( GetLabelFont() );
5254
5255 dc.SetBackgroundMode( wxTRANSPARENT );
5256 dc.SetTextForeground( GetLabelTextColour() );
5257 dc.SetFont( GetLabelFont() );
5258
5259 int hAlign, vAlign;
5260 GetColLabelAlignment( &hAlign, &vAlign );
5261
5262 wxRect rect;
5263 rect.SetX( colLeft + 2 );
5264 rect.SetY( 2 );
5265 rect.SetWidth( GetColWidth(col) - 4 );
5266 rect.SetHeight( m_colLabelHeight - 4 );
5267 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
5268 }
5269
5270
5271 void wxGrid::DrawTextRectangle( wxDC& dc,
5272 const wxString& value,
5273 const wxRect& rect,
5274 int horizAlign,
5275 int vertAlign )
5276 {
5277 long textWidth, textHeight;
5278 long lineWidth, lineHeight;
5279 wxArrayString lines;
5280
5281 dc.SetClippingRegion( rect );
5282 StringToLines( value, lines );
5283 if ( lines.GetCount() )
5284 {
5285 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
5286 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
5287
5288 float x, y;
5289 switch ( horizAlign )
5290 {
5291 case wxRIGHT:
5292 x = rect.x + (rect.width - textWidth - 1);
5293 break;
5294
5295 case wxCENTRE:
5296 x = rect.x + ((rect.width - textWidth)/2);
5297 break;
5298
5299 case wxLEFT:
5300 default:
5301 x = rect.x + 1;
5302 break;
5303 }
5304
5305 switch ( vertAlign )
5306 {
5307 case wxBOTTOM:
5308 y = rect.y + (rect.height - textHeight - 1);
5309 break;
5310
5311 case wxCENTRE:
5312 y = rect.y + ((rect.height - textHeight)/2);
5313 break;
5314
5315 case wxTOP:
5316 default:
5317 y = rect.y + 1;
5318 break;
5319 }
5320
5321 for ( size_t i = 0; i < lines.GetCount(); i++ )
5322 {
5323 dc.DrawText( lines[i], (long)x, (long)y );
5324 y += lineHeight;
5325 }
5326 }
5327
5328 dc.DestroyClippingRegion();
5329 }
5330
5331
5332 // Split multi line text up into an array of strings. Any existing
5333 // contents of the string array are preserved.
5334 //
5335 void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
5336 {
5337 int startPos = 0;
5338 int pos;
5339 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
5340 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
5341
5342 while ( startPos < (int)tVal.Length() )
5343 {
5344 pos = tVal.Mid(startPos).Find( eol );
5345 if ( pos < 0 )
5346 {
5347 break;
5348 }
5349 else if ( pos == 0 )
5350 {
5351 lines.Add( wxEmptyString );
5352 }
5353 else
5354 {
5355 lines.Add( value.Mid(startPos, pos) );
5356 }
5357 startPos += pos+1;
5358 }
5359 if ( startPos < (int)value.Length() )
5360 {
5361 lines.Add( value.Mid( startPos ) );
5362 }
5363 }
5364
5365
5366 void wxGrid::GetTextBoxSize( wxDC& dc,
5367 wxArrayString& lines,
5368 long *width, long *height )
5369 {
5370 long w = 0;
5371 long h = 0;
5372 long lineW, lineH;
5373
5374 size_t i;
5375 for ( i = 0; i < lines.GetCount(); i++ )
5376 {
5377 dc.GetTextExtent( lines[i], &lineW, &lineH );
5378 w = wxMax( w, lineW );
5379 h += lineH;
5380 }
5381
5382 *width = w;
5383 *height = h;
5384 }
5385
5386
5387 //
5388 // ------ Edit control functions
5389 //
5390
5391
5392 void wxGrid::EnableEditing( bool edit )
5393 {
5394 // TODO: improve this ?
5395 //
5396 if ( edit != m_editable )
5397 {
5398 m_editable = edit;
5399
5400 // FIXME IMHO this won't disable the edit control if edit == FALSE
5401 // because of the check in the beginning of
5402 // EnableCellEditControl() just below (VZ)
5403 EnableCellEditControl(m_editable);
5404 }
5405 }
5406
5407
5408 void wxGrid::EnableCellEditControl( bool enable )
5409 {
5410 if (! m_editable)
5411 return;
5412
5413 if ( m_currentCellCoords == wxGridNoCellCoords )
5414 SetCurrentCell( 0, 0 );
5415
5416 if ( enable != m_cellEditCtrlEnabled )
5417 {
5418 // TODO allow the app to Veto() this event?
5419 SendEvent(enable ? wxEVT_GRID_EDITOR_SHOWN : wxEVT_GRID_EDITOR_HIDDEN);
5420
5421 if ( enable )
5422 {
5423 // this should be checked by the caller!
5424 wxASSERT_MSG( CanEnableCellControl(),
5425 _T("can't enable editing for this cell!") );
5426
5427 // do it before ShowCellEditControl()
5428 m_cellEditCtrlEnabled = enable;
5429
5430 ShowCellEditControl();
5431 }
5432 else
5433 {
5434 HideCellEditControl();
5435 SaveEditControlValue();
5436
5437 // do it after HideCellEditControl()
5438 m_cellEditCtrlEnabled = enable;
5439 }
5440 }
5441 }
5442
5443 bool wxGrid::IsCurrentCellReadOnly() const
5444 {
5445 // const_cast
5446 wxGridCellAttr* attr = ((wxGrid *)this)->GetCellAttr(m_currentCellCoords);
5447 bool readonly = attr->IsReadOnly();
5448 attr->DecRef();
5449
5450 return readonly;
5451 }
5452
5453 bool wxGrid::CanEnableCellControl() const
5454 {
5455 return m_editable && !IsCurrentCellReadOnly();
5456 }
5457
5458 bool wxGrid::IsCellEditControlEnabled() const
5459 {
5460 // the cell edit control might be disable for all cells or just for the
5461 // current one if it's read only
5462 return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : FALSE;
5463 }
5464
5465 void wxGrid::ShowCellEditControl()
5466 {
5467 if ( IsCellEditControlEnabled() )
5468 {
5469 if ( !IsVisible( m_currentCellCoords ) )
5470 {
5471 return;
5472 }
5473 else
5474 {
5475 wxRect rect = CellToRect( m_currentCellCoords );
5476 int row = m_currentCellCoords.GetRow();
5477 int col = m_currentCellCoords.GetCol();
5478
5479 // convert to scrolled coords
5480 //
5481 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
5482
5483 // done in PaintBackground()
5484 #if 0
5485 // erase the highlight and the cell contents because the editor
5486 // might not cover the entire cell
5487 wxClientDC dc( m_gridWin );
5488 PrepareDC( dc );
5489 dc.SetBrush(*wxLIGHT_GREY_BRUSH); //wxBrush(attr->GetBackgroundColour(), wxSOLID));
5490 dc.SetPen(*wxTRANSPARENT_PEN);
5491 dc.DrawRectangle(rect);
5492 #endif // 0
5493
5494 // cell is shifted by one pixel
5495 rect.x--;
5496 rect.y--;
5497
5498 wxGridCellAttr* attr = GetCellAttr(row, col);
5499 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
5500 if ( !editor->IsCreated() )
5501 {
5502 editor->Create(m_gridWin, -1,
5503 new wxGridCellEditorEvtHandler(this, editor));
5504 }
5505
5506 editor->Show( TRUE, attr );
5507
5508 editor->SetSize( rect );
5509
5510 editor->BeginEdit(row, col, this);
5511 attr->DecRef();
5512 }
5513 }
5514 }
5515
5516
5517 void wxGrid::HideCellEditControl()
5518 {
5519 if ( IsCellEditControlEnabled() )
5520 {
5521 int row = m_currentCellCoords.GetRow();
5522 int col = m_currentCellCoords.GetCol();
5523
5524 wxGridCellAttr* attr = GetCellAttr(row, col);
5525 attr->GetEditor(this, row, col)->Show( FALSE );
5526 attr->DecRef();
5527 m_gridWin->SetFocus();
5528 }
5529 }
5530
5531
5532 void wxGrid::SaveEditControlValue()
5533 {
5534 if ( IsCellEditControlEnabled() )
5535 {
5536 int row = m_currentCellCoords.GetRow();
5537 int col = m_currentCellCoords.GetCol();
5538
5539 wxGridCellAttr* attr = GetCellAttr(row, col);
5540 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
5541 bool changed = editor->EndEdit(row, col, this);
5542
5543 attr->DecRef();
5544
5545 if (changed)
5546 {
5547 SendEvent( wxEVT_GRID_CELL_CHANGE,
5548 m_currentCellCoords.GetRow(),
5549 m_currentCellCoords.GetCol() );
5550 }
5551 }
5552 }
5553
5554
5555 //
5556 // ------ Grid location functions
5557 // Note that all of these functions work with the logical coordinates of
5558 // grid cells and labels so you will need to convert from device
5559 // coordinates for mouse events etc.
5560 //
5561
5562 void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
5563 {
5564 int row = YToRow(y);
5565 int col = XToCol(x);
5566
5567 if ( row == -1 || col == -1 )
5568 {
5569 coords = wxGridNoCellCoords;
5570 }
5571 else
5572 {
5573 coords.Set( row, col );
5574 }
5575 }
5576
5577
5578 int wxGrid::YToRow( int y )
5579 {
5580 int i;
5581
5582 for ( i = 0; i < m_numRows; i++ )
5583 {
5584 if ( y < GetRowBottom(i) )
5585 return i;
5586 }
5587
5588 return -1;
5589 }
5590
5591
5592 int wxGrid::XToCol( int x )
5593 {
5594 int i;
5595
5596 for ( i = 0; i < m_numCols; i++ )
5597 {
5598 if ( x < GetColRight(i) )
5599 return i;
5600 }
5601
5602 return -1;
5603 }
5604
5605
5606 // return the row number that that the y coord is near the edge of, or
5607 // -1 if not near an edge
5608 //
5609 int wxGrid::YToEdgeOfRow( int y )
5610 {
5611 int i, d;
5612
5613 for ( i = 0; i < m_numRows; i++ )
5614 {
5615 if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE )
5616 {
5617 d = abs( y - GetRowBottom(i) );
5618 if ( d < WXGRID_LABEL_EDGE_ZONE )
5619 return i;
5620 }
5621 }
5622
5623 return -1;
5624 }
5625
5626
5627 // return the col number that that the x coord is near the edge of, or
5628 // -1 if not near an edge
5629 //
5630 int wxGrid::XToEdgeOfCol( int x )
5631 {
5632 int i, d;
5633
5634 for ( i = 0; i < m_numCols; i++ )
5635 {
5636 if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE )
5637 {
5638 d = abs( x - GetColRight(i) );
5639 if ( d < WXGRID_LABEL_EDGE_ZONE )
5640 return i;
5641 }
5642 }
5643
5644 return -1;
5645 }
5646
5647
5648 wxRect wxGrid::CellToRect( int row, int col )
5649 {
5650 wxRect rect( -1, -1, -1, -1 );
5651
5652 if ( row >= 0 && row < m_numRows &&
5653 col >= 0 && col < m_numCols )
5654 {
5655 rect.x = GetColLeft(col);
5656 rect.y = GetRowTop(row);
5657 rect.width = GetColWidth(col);
5658 rect.height = GetRowHeight(row);
5659 }
5660
5661 return rect;
5662 }
5663
5664
5665 bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
5666 {
5667 // get the cell rectangle in logical coords
5668 //
5669 wxRect r( CellToRect( row, col ) );
5670
5671 // convert to device coords
5672 //
5673 int left, top, right, bottom;
5674 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
5675 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
5676
5677 // check against the client area of the grid window
5678 //
5679 int cw, ch;
5680 m_gridWin->GetClientSize( &cw, &ch );
5681
5682 if ( wholeCellVisible )
5683 {
5684 // is the cell wholly visible ?
5685 //
5686 return ( left >= 0 && right <= cw &&
5687 top >= 0 && bottom <= ch );
5688 }
5689 else
5690 {
5691 // is the cell partly visible ?
5692 //
5693 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
5694 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
5695 }
5696 }
5697
5698
5699 // make the specified cell location visible by doing a minimal amount
5700 // of scrolling
5701 //
5702 void wxGrid::MakeCellVisible( int row, int col )
5703 {
5704 int i;
5705 int xpos = -1, ypos = -1;
5706
5707 if ( row >= 0 && row < m_numRows &&
5708 col >= 0 && col < m_numCols )
5709 {
5710 // get the cell rectangle in logical coords
5711 //
5712 wxRect r( CellToRect( row, col ) );
5713
5714 // convert to device coords
5715 //
5716 int left, top, right, bottom;
5717 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
5718 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
5719
5720 int cw, ch;
5721 m_gridWin->GetClientSize( &cw, &ch );
5722
5723 if ( top < 0 )
5724 {
5725 ypos = r.GetTop();
5726 }
5727 else if ( bottom > ch )
5728 {
5729 int h = r.GetHeight();
5730 ypos = r.GetTop();
5731 for ( i = row-1; i >= 0; i-- )
5732 {
5733 int rowHeight = GetRowHeight(i);
5734 if ( h + rowHeight > ch )
5735 break;
5736
5737 h += rowHeight;
5738 ypos -= rowHeight;
5739 }
5740
5741 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
5742 // have rounding errors (this is important, because if we do, we
5743 // might not scroll at all and some cells won't be redrawn)
5744 ypos += GRID_SCROLL_LINE / 2;
5745 }
5746
5747 if ( left < 0 )
5748 {
5749 xpos = r.GetLeft();
5750 }
5751 else if ( right > cw )
5752 {
5753 int w = r.GetWidth();
5754 xpos = r.GetLeft();
5755 for ( i = col-1; i >= 0; i-- )
5756 {
5757 int colWidth = GetColWidth(i);
5758 if ( w + colWidth > cw )
5759 break;
5760
5761 w += colWidth;
5762 xpos -= colWidth;
5763 }
5764
5765 // see comment for ypos above
5766 xpos += GRID_SCROLL_LINE / 2;
5767 }
5768
5769 if ( xpos != -1 || ypos != -1 )
5770 {
5771 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
5772 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
5773 Scroll( xpos, ypos );
5774 AdjustScrollbars();
5775 }
5776 }
5777 }
5778
5779
5780 //
5781 // ------ Grid cursor movement functions
5782 //
5783
5784 bool wxGrid::MoveCursorUp()
5785 {
5786 if ( m_currentCellCoords != wxGridNoCellCoords &&
5787 m_currentCellCoords.GetRow() > 0 )
5788 {
5789 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
5790 m_currentCellCoords.GetCol() );
5791
5792 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
5793 m_currentCellCoords.GetCol() );
5794
5795 return TRUE;
5796 }
5797
5798 return FALSE;
5799 }
5800
5801
5802 bool wxGrid::MoveCursorDown()
5803 {
5804 // TODO: allow for scrolling
5805 //
5806 if ( m_currentCellCoords != wxGridNoCellCoords &&
5807 m_currentCellCoords.GetRow() < m_numRows-1 )
5808 {
5809 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
5810 m_currentCellCoords.GetCol() );
5811
5812 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
5813 m_currentCellCoords.GetCol() );
5814
5815 return TRUE;
5816 }
5817
5818 return FALSE;
5819 }
5820
5821
5822 bool wxGrid::MoveCursorLeft()
5823 {
5824 if ( m_currentCellCoords != wxGridNoCellCoords &&
5825 m_currentCellCoords.GetCol() > 0 )
5826 {
5827 MakeCellVisible( m_currentCellCoords.GetRow(),
5828 m_currentCellCoords.GetCol() - 1 );
5829
5830 SetCurrentCell( m_currentCellCoords.GetRow(),
5831 m_currentCellCoords.GetCol() - 1 );
5832
5833 return TRUE;
5834 }
5835
5836 return FALSE;
5837 }
5838
5839
5840 bool wxGrid::MoveCursorRight()
5841 {
5842 if ( m_currentCellCoords != wxGridNoCellCoords &&
5843 m_currentCellCoords.GetCol() < m_numCols - 1 )
5844 {
5845 MakeCellVisible( m_currentCellCoords.GetRow(),
5846 m_currentCellCoords.GetCol() + 1 );
5847
5848 SetCurrentCell( m_currentCellCoords.GetRow(),
5849 m_currentCellCoords.GetCol() + 1 );
5850
5851 return TRUE;
5852 }
5853
5854 return FALSE;
5855 }
5856
5857
5858 bool wxGrid::MovePageUp()
5859 {
5860 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
5861
5862 int row = m_currentCellCoords.GetRow();
5863 if ( row > 0 )
5864 {
5865 int cw, ch;
5866 m_gridWin->GetClientSize( &cw, &ch );
5867
5868 int y = GetRowTop(row);
5869 int newRow = YToRow( y - ch + 1 );
5870 if ( newRow == -1 )
5871 {
5872 newRow = 0;
5873 }
5874 else if ( newRow == row )
5875 {
5876 newRow = row - 1;
5877 }
5878
5879 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
5880 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
5881
5882 return TRUE;
5883 }
5884
5885 return FALSE;
5886 }
5887
5888 bool wxGrid::MovePageDown()
5889 {
5890 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
5891
5892 int row = m_currentCellCoords.GetRow();
5893 if ( row < m_numRows )
5894 {
5895 int cw, ch;
5896 m_gridWin->GetClientSize( &cw, &ch );
5897
5898 int y = GetRowTop(row);
5899 int newRow = YToRow( y + ch );
5900 if ( newRow == -1 )
5901 {
5902 newRow = m_numRows - 1;
5903 }
5904 else if ( newRow == row )
5905 {
5906 newRow = row + 1;
5907 }
5908
5909 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
5910 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
5911
5912 return TRUE;
5913 }
5914
5915 return FALSE;
5916 }
5917
5918 bool wxGrid::MoveCursorUpBlock()
5919 {
5920 if ( m_table &&
5921 m_currentCellCoords != wxGridNoCellCoords &&
5922 m_currentCellCoords.GetRow() > 0 )
5923 {
5924 int row = m_currentCellCoords.GetRow();
5925 int col = m_currentCellCoords.GetCol();
5926
5927 if ( m_table->IsEmptyCell(row, col) )
5928 {
5929 // starting in an empty cell: find the next block of
5930 // non-empty cells
5931 //
5932 while ( row > 0 )
5933 {
5934 row-- ;
5935 if ( !(m_table->IsEmptyCell(row, col)) ) break;
5936 }
5937 }
5938 else if ( m_table->IsEmptyCell(row-1, col) )
5939 {
5940 // starting at the top of a block: find the next block
5941 //
5942 row--;
5943 while ( row > 0 )
5944 {
5945 row-- ;
5946 if ( !(m_table->IsEmptyCell(row, col)) ) break;
5947 }
5948 }
5949 else
5950 {
5951 // starting within a block: find the top of the block
5952 //
5953 while ( row > 0 )
5954 {
5955 row-- ;
5956 if ( m_table->IsEmptyCell(row, col) )
5957 {
5958 row++ ;
5959 break;
5960 }
5961 }
5962 }
5963
5964 MakeCellVisible( row, col );
5965 SetCurrentCell( row, col );
5966
5967 return TRUE;
5968 }
5969
5970 return FALSE;
5971 }
5972
5973 bool wxGrid::MoveCursorDownBlock()
5974 {
5975 if ( m_table &&
5976 m_currentCellCoords != wxGridNoCellCoords &&
5977 m_currentCellCoords.GetRow() < m_numRows-1 )
5978 {
5979 int row = m_currentCellCoords.GetRow();
5980 int col = m_currentCellCoords.GetCol();
5981
5982 if ( m_table->IsEmptyCell(row, col) )
5983 {
5984 // starting in an empty cell: find the next block of
5985 // non-empty cells
5986 //
5987 while ( row < m_numRows-1 )
5988 {
5989 row++ ;
5990 if ( !(m_table->IsEmptyCell(row, col)) ) break;
5991 }
5992 }
5993 else if ( m_table->IsEmptyCell(row+1, col) )
5994 {
5995 // starting at the bottom of a block: find the next block
5996 //
5997 row++;
5998 while ( row < m_numRows-1 )
5999 {
6000 row++ ;
6001 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6002 }
6003 }
6004 else
6005 {
6006 // starting within a block: find the bottom of the block
6007 //
6008 while ( row < m_numRows-1 )
6009 {
6010 row++ ;
6011 if ( m_table->IsEmptyCell(row, col) )
6012 {
6013 row-- ;
6014 break;
6015 }
6016 }
6017 }
6018
6019 MakeCellVisible( row, col );
6020 SetCurrentCell( row, col );
6021
6022 return TRUE;
6023 }
6024
6025 return FALSE;
6026 }
6027
6028 bool wxGrid::MoveCursorLeftBlock()
6029 {
6030 if ( m_table &&
6031 m_currentCellCoords != wxGridNoCellCoords &&
6032 m_currentCellCoords.GetCol() > 0 )
6033 {
6034 int row = m_currentCellCoords.GetRow();
6035 int col = m_currentCellCoords.GetCol();
6036
6037 if ( m_table->IsEmptyCell(row, col) )
6038 {
6039 // starting in an empty cell: find the next block of
6040 // non-empty cells
6041 //
6042 while ( col > 0 )
6043 {
6044 col-- ;
6045 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6046 }
6047 }
6048 else if ( m_table->IsEmptyCell(row, col-1) )
6049 {
6050 // starting at the left of a block: find the next block
6051 //
6052 col--;
6053 while ( col > 0 )
6054 {
6055 col-- ;
6056 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6057 }
6058 }
6059 else
6060 {
6061 // starting within a block: find the left of the block
6062 //
6063 while ( col > 0 )
6064 {
6065 col-- ;
6066 if ( m_table->IsEmptyCell(row, col) )
6067 {
6068 col++ ;
6069 break;
6070 }
6071 }
6072 }
6073
6074 MakeCellVisible( row, col );
6075 SetCurrentCell( row, col );
6076
6077 return TRUE;
6078 }
6079
6080 return FALSE;
6081 }
6082
6083 bool wxGrid::MoveCursorRightBlock()
6084 {
6085 if ( m_table &&
6086 m_currentCellCoords != wxGridNoCellCoords &&
6087 m_currentCellCoords.GetCol() < m_numCols-1 )
6088 {
6089 int row = m_currentCellCoords.GetRow();
6090 int col = m_currentCellCoords.GetCol();
6091
6092 if ( m_table->IsEmptyCell(row, col) )
6093 {
6094 // starting in an empty cell: find the next block of
6095 // non-empty cells
6096 //
6097 while ( col < m_numCols-1 )
6098 {
6099 col++ ;
6100 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6101 }
6102 }
6103 else if ( m_table->IsEmptyCell(row, col+1) )
6104 {
6105 // starting at the right of a block: find the next block
6106 //
6107 col++;
6108 while ( col < m_numCols-1 )
6109 {
6110 col++ ;
6111 if ( !(m_table->IsEmptyCell(row, col)) ) break;
6112 }
6113 }
6114 else
6115 {
6116 // starting within a block: find the right of the block
6117 //
6118 while ( col < m_numCols-1 )
6119 {
6120 col++ ;
6121 if ( m_table->IsEmptyCell(row, col) )
6122 {
6123 col-- ;
6124 break;
6125 }
6126 }
6127 }
6128
6129 MakeCellVisible( row, col );
6130 SetCurrentCell( row, col );
6131
6132 return TRUE;
6133 }
6134
6135 return FALSE;
6136 }
6137
6138
6139
6140 //
6141 // ------ Label values and formatting
6142 //
6143
6144 void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
6145 {
6146 *horiz = m_rowLabelHorizAlign;
6147 *vert = m_rowLabelVertAlign;
6148 }
6149
6150 void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
6151 {
6152 *horiz = m_colLabelHorizAlign;
6153 *vert = m_colLabelVertAlign;
6154 }
6155
6156 wxString wxGrid::GetRowLabelValue( int row )
6157 {
6158 if ( m_table )
6159 {
6160 return m_table->GetRowLabelValue( row );
6161 }
6162 else
6163 {
6164 wxString s;
6165 s << row;
6166 return s;
6167 }
6168 }
6169
6170 wxString wxGrid::GetColLabelValue( int col )
6171 {
6172 if ( m_table )
6173 {
6174 return m_table->GetColLabelValue( col );
6175 }
6176 else
6177 {
6178 wxString s;
6179 s << col;
6180 return s;
6181 }
6182 }
6183
6184
6185 void wxGrid::SetRowLabelSize( int width )
6186 {
6187 width = wxMax( width, 0 );
6188 if ( width != m_rowLabelWidth )
6189 {
6190 if ( width == 0 )
6191 {
6192 m_rowLabelWin->Show( FALSE );
6193 m_cornerLabelWin->Show( FALSE );
6194 }
6195 else if ( m_rowLabelWidth == 0 )
6196 {
6197 m_rowLabelWin->Show( TRUE );
6198 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
6199 }
6200
6201 m_rowLabelWidth = width;
6202 CalcWindowSizes();
6203 Refresh( TRUE );
6204 }
6205 }
6206
6207
6208 void wxGrid::SetColLabelSize( int height )
6209 {
6210 height = wxMax( height, 0 );
6211 if ( height != m_colLabelHeight )
6212 {
6213 if ( height == 0 )
6214 {
6215 m_colLabelWin->Show( FALSE );
6216 m_cornerLabelWin->Show( FALSE );
6217 }
6218 else if ( m_colLabelHeight == 0 )
6219 {
6220 m_colLabelWin->Show( TRUE );
6221 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
6222 }
6223
6224 m_colLabelHeight = height;
6225 CalcWindowSizes();
6226 Refresh( TRUE );
6227 }
6228 }
6229
6230
6231 void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
6232 {
6233 if ( m_labelBackgroundColour != colour )
6234 {
6235 m_labelBackgroundColour = colour;
6236 m_rowLabelWin->SetBackgroundColour( colour );
6237 m_colLabelWin->SetBackgroundColour( colour );
6238 m_cornerLabelWin->SetBackgroundColour( colour );
6239
6240 if ( !GetBatchCount() )
6241 {
6242 m_rowLabelWin->Refresh();
6243 m_colLabelWin->Refresh();
6244 m_cornerLabelWin->Refresh();
6245 }
6246 }
6247 }
6248
6249 void wxGrid::SetLabelTextColour( const wxColour& colour )
6250 {
6251 if ( m_labelTextColour != colour )
6252 {
6253 m_labelTextColour = colour;
6254 if ( !GetBatchCount() )
6255 {
6256 m_rowLabelWin->Refresh();
6257 m_colLabelWin->Refresh();
6258 }
6259 }
6260 }
6261
6262 void wxGrid::SetLabelFont( const wxFont& font )
6263 {
6264 m_labelFont = font;
6265 if ( !GetBatchCount() )
6266 {
6267 m_rowLabelWin->Refresh();
6268 m_colLabelWin->Refresh();
6269 }
6270 }
6271
6272 void wxGrid::SetRowLabelAlignment( int horiz, int vert )
6273 {
6274 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
6275 {
6276 m_rowLabelHorizAlign = horiz;
6277 }
6278
6279 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
6280 {
6281 m_rowLabelVertAlign = vert;
6282 }
6283
6284 if ( !GetBatchCount() )
6285 {
6286 m_rowLabelWin->Refresh();
6287 }
6288 }
6289
6290 void wxGrid::SetColLabelAlignment( int horiz, int vert )
6291 {
6292 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
6293 {
6294 m_colLabelHorizAlign = horiz;
6295 }
6296
6297 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
6298 {
6299 m_colLabelVertAlign = vert;
6300 }
6301
6302 if ( !GetBatchCount() )
6303 {
6304 m_colLabelWin->Refresh();
6305 }
6306 }
6307
6308 void wxGrid::SetRowLabelValue( int row, const wxString& s )
6309 {
6310 if ( m_table )
6311 {
6312 m_table->SetRowLabelValue( row, s );
6313 if ( !GetBatchCount() )
6314 {
6315 wxRect rect = CellToRect( row, 0);
6316 if ( rect.height > 0 )
6317 {
6318 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
6319 rect.x = m_left;
6320 rect.width = m_rowLabelWidth;
6321 m_rowLabelWin->Refresh( TRUE, &rect );
6322 }
6323 }
6324 }
6325 }
6326
6327 void wxGrid::SetColLabelValue( int col, const wxString& s )
6328 {
6329 if ( m_table )
6330 {
6331 m_table->SetColLabelValue( col, s );
6332 if ( !GetBatchCount() )
6333 {
6334 wxRect rect = CellToRect( 0, col );
6335 if ( rect.width > 0 )
6336 {
6337 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
6338 rect.y = m_top;
6339 rect.height = m_colLabelHeight;
6340 m_colLabelWin->Refresh( TRUE, &rect );
6341 }
6342 }
6343 }
6344 }
6345
6346 void wxGrid::SetGridLineColour( const wxColour& colour )
6347 {
6348 if ( m_gridLineColour != colour )
6349 {
6350 m_gridLineColour = colour;
6351
6352 wxClientDC dc( m_gridWin );
6353 PrepareDC( dc );
6354 DrawAllGridLines( dc, wxRegion() );
6355 }
6356 }
6357
6358 void wxGrid::EnableGridLines( bool enable )
6359 {
6360 if ( enable != m_gridLinesEnabled )
6361 {
6362 m_gridLinesEnabled = enable;
6363
6364 if ( !GetBatchCount() )
6365 {
6366 if ( enable )
6367 {
6368 wxClientDC dc( m_gridWin );
6369 PrepareDC( dc );
6370 DrawAllGridLines( dc, wxRegion() );
6371 }
6372 else
6373 {
6374 m_gridWin->Refresh();
6375 }
6376 }
6377 }
6378 }
6379
6380
6381 int wxGrid::GetDefaultRowSize()
6382 {
6383 return m_defaultRowHeight;
6384 }
6385
6386 int wxGrid::GetRowSize( int row )
6387 {
6388 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
6389
6390 return GetRowHeight(row);
6391 }
6392
6393 int wxGrid::GetDefaultColSize()
6394 {
6395 return m_defaultColWidth;
6396 }
6397
6398 int wxGrid::GetColSize( int col )
6399 {
6400 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
6401
6402 return GetColWidth(col);
6403 }
6404
6405 // ============================================================================
6406 // access to the grid attributes: each of them has a default value in the grid
6407 // itself and may be overidden on a per-cell basis
6408 // ============================================================================
6409
6410 // ----------------------------------------------------------------------------
6411 // setting default attributes
6412 // ----------------------------------------------------------------------------
6413
6414 void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
6415 {
6416 m_defaultCellAttr->SetBackgroundColour(col);
6417 #ifdef __WXGTK__
6418 m_gridWin->SetBackgroundColour(col);
6419 #endif
6420 }
6421
6422 void wxGrid::SetDefaultCellTextColour( const wxColour& col )
6423 {
6424 m_defaultCellAttr->SetTextColour(col);
6425 }
6426
6427 void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
6428 {
6429 m_defaultCellAttr->SetAlignment(horiz, vert);
6430 }
6431
6432 void wxGrid::SetDefaultCellFont( const wxFont& font )
6433 {
6434 m_defaultCellAttr->SetFont(font);
6435 }
6436
6437 void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
6438 {
6439 m_defaultCellAttr->SetRenderer(renderer);
6440 }
6441
6442 void wxGrid::SetDefaultEditor(wxGridCellEditor *editor)
6443 {
6444 m_defaultCellAttr->SetEditor(editor);
6445 }
6446
6447 // ----------------------------------------------------------------------------
6448 // access to the default attrbiutes
6449 // ----------------------------------------------------------------------------
6450
6451 wxColour wxGrid::GetDefaultCellBackgroundColour()
6452 {
6453 return m_defaultCellAttr->GetBackgroundColour();
6454 }
6455
6456 wxColour wxGrid::GetDefaultCellTextColour()
6457 {
6458 return m_defaultCellAttr->GetTextColour();
6459 }
6460
6461 wxFont wxGrid::GetDefaultCellFont()
6462 {
6463 return m_defaultCellAttr->GetFont();
6464 }
6465
6466 void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
6467 {
6468 m_defaultCellAttr->GetAlignment(horiz, vert);
6469 }
6470
6471 wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
6472 {
6473 return m_defaultCellAttr->GetRenderer(NULL,0,0);
6474 }
6475
6476 wxGridCellEditor *wxGrid::GetDefaultEditor() const
6477 {
6478 return m_defaultCellAttr->GetEditor(NULL,0,0);
6479 }
6480
6481 // ----------------------------------------------------------------------------
6482 // access to cell attributes
6483 // ----------------------------------------------------------------------------
6484
6485 wxColour wxGrid::GetCellBackgroundColour(int row, int col)
6486 {
6487 wxGridCellAttr *attr = GetCellAttr(row, col);
6488 wxColour colour = attr->GetBackgroundColour();
6489 attr->SafeDecRef();
6490 return colour;
6491 }
6492
6493 wxColour wxGrid::GetCellTextColour( int row, int col )
6494 {
6495 wxGridCellAttr *attr = GetCellAttr(row, col);
6496 wxColour colour = attr->GetTextColour();
6497 attr->SafeDecRef();
6498 return colour;
6499 }
6500
6501 wxFont wxGrid::GetCellFont( int row, int col )
6502 {
6503 wxGridCellAttr *attr = GetCellAttr(row, col);
6504 wxFont font = attr->GetFont();
6505 attr->SafeDecRef();
6506 return font;
6507 }
6508
6509 void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
6510 {
6511 wxGridCellAttr *attr = GetCellAttr(row, col);
6512 attr->GetAlignment(horiz, vert);
6513 attr->SafeDecRef();
6514 }
6515
6516 wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
6517 {
6518 wxGridCellAttr* attr = GetCellAttr(row, col);
6519 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
6520 attr->DecRef();
6521 return renderer;
6522 }
6523
6524 wxGridCellEditor* wxGrid::GetCellEditor(int row, int col)
6525 {
6526 wxGridCellAttr* attr = GetCellAttr(row, col);
6527 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
6528 attr->DecRef();
6529 return editor;
6530 }
6531
6532 bool wxGrid::IsReadOnly(int row, int col) const
6533 {
6534 wxGridCellAttr* attr = GetCellAttr(row, col);
6535 bool isReadOnly = attr->IsReadOnly();
6536 attr->DecRef();
6537 return isReadOnly;
6538 }
6539
6540 // ----------------------------------------------------------------------------
6541 // attribute support: cache, automatic provider creation, ...
6542 // ----------------------------------------------------------------------------
6543
6544 bool wxGrid::CanHaveAttributes()
6545 {
6546 if ( !m_table )
6547 {
6548 return FALSE;
6549 }
6550
6551 return m_table->CanHaveAttributes();
6552 }
6553
6554 void wxGrid::ClearAttrCache()
6555 {
6556 if ( m_attrCache.row != -1 )
6557 {
6558 m_attrCache.attr->SafeDecRef();
6559 m_attrCache.row = -1;
6560 }
6561 }
6562
6563 void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
6564 {
6565 wxGrid *self = (wxGrid *)this; // const_cast
6566
6567 self->ClearAttrCache();
6568 self->m_attrCache.row = row;
6569 self->m_attrCache.col = col;
6570 self->m_attrCache.attr = attr;
6571 attr->SafeIncRef();
6572 }
6573
6574 bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
6575 {
6576 if ( row == m_attrCache.row && col == m_attrCache.col )
6577 {
6578 *attr = m_attrCache.attr;
6579 (*attr)->SafeIncRef();
6580
6581 #ifdef DEBUG_ATTR_CACHE
6582 gs_nAttrCacheHits++;
6583 #endif
6584
6585 return TRUE;
6586 }
6587 else
6588 {
6589 #ifdef DEBUG_ATTR_CACHE
6590 gs_nAttrCacheMisses++;
6591 #endif
6592 return FALSE;
6593 }
6594 }
6595
6596 wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
6597 {
6598 wxGridCellAttr *attr;
6599 if ( !LookupAttr(row, col, &attr) )
6600 {
6601 attr = m_table ? m_table->GetAttr(row, col) : (wxGridCellAttr *)NULL;
6602 CacheAttr(row, col, attr);
6603 }
6604 if (attr)
6605 {
6606 attr->SetDefAttr(m_defaultCellAttr);
6607 }
6608 else
6609 {
6610 attr = m_defaultCellAttr;
6611 attr->IncRef();
6612 }
6613
6614 return attr;
6615 }
6616
6617 wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
6618 {
6619 wxGridCellAttr *attr;
6620 if ( !LookupAttr(row, col, &attr) || !attr )
6621 {
6622 wxASSERT_MSG( m_table,
6623 _T("we may only be called if CanHaveAttributes() "
6624 "returned TRUE and then m_table should be !NULL") );
6625
6626 attr = m_table->GetAttr(row, col);
6627 if ( !attr )
6628 {
6629 attr = new wxGridCellAttr;
6630
6631 // artificially inc the ref count to match DecRef() in caller
6632 attr->IncRef();
6633
6634 m_table->SetAttr(attr, row, col);
6635 }
6636
6637 CacheAttr(row, col, attr);
6638 }
6639 attr->SetDefAttr(m_defaultCellAttr);
6640 return attr;
6641 }
6642
6643 // ----------------------------------------------------------------------------
6644 // setting cell attributes: this is forwarded to the table
6645 // ----------------------------------------------------------------------------
6646
6647 void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
6648 {
6649 if ( CanHaveAttributes() )
6650 {
6651 m_table->SetRowAttr(attr, row);
6652 }
6653 else
6654 {
6655 attr->SafeDecRef();
6656 }
6657 }
6658
6659 void wxGrid::SetColAttr(int col, wxGridCellAttr *attr)
6660 {
6661 if ( CanHaveAttributes() )
6662 {
6663 m_table->SetColAttr(attr, col);
6664 }
6665 else
6666 {
6667 attr->SafeDecRef();
6668 }
6669 }
6670
6671 void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
6672 {
6673 if ( CanHaveAttributes() )
6674 {
6675 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
6676 attr->SetBackgroundColour(colour);
6677 attr->DecRef();
6678 }
6679 }
6680
6681 void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
6682 {
6683 if ( CanHaveAttributes() )
6684 {
6685 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
6686 attr->SetTextColour(colour);
6687 attr->DecRef();
6688 }
6689 }
6690
6691 void wxGrid::SetCellFont( int row, int col, const wxFont& font )
6692 {
6693 if ( CanHaveAttributes() )
6694 {
6695 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
6696 attr->SetFont(font);
6697 attr->DecRef();
6698 }
6699 }
6700
6701 void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
6702 {
6703 if ( CanHaveAttributes() )
6704 {
6705 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
6706 attr->SetAlignment(horiz, vert);
6707 attr->DecRef();
6708 }
6709 }
6710
6711 void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
6712 {
6713 if ( CanHaveAttributes() )
6714 {
6715 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
6716 attr->SetRenderer(renderer);
6717 attr->DecRef();
6718 }
6719 }
6720
6721 void wxGrid::SetCellEditor(int row, int col, wxGridCellEditor* editor)
6722 {
6723 if ( CanHaveAttributes() )
6724 {
6725 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
6726 attr->SetEditor(editor);
6727 attr->DecRef();
6728 }
6729 }
6730
6731 void wxGrid::SetReadOnly(int row, int col, bool isReadOnly)
6732 {
6733 if ( CanHaveAttributes() )
6734 {
6735 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
6736 attr->SetReadOnly(isReadOnly);
6737 attr->DecRef();
6738 }
6739 }
6740
6741 // ----------------------------------------------------------------------------
6742 // Data type registration
6743 // ----------------------------------------------------------------------------
6744
6745 void wxGrid::RegisterDataType(const wxString& typeName,
6746 wxGridCellRenderer* renderer,
6747 wxGridCellEditor* editor)
6748 {
6749 m_typeRegistry->RegisterDataType(typeName, renderer, editor);
6750 }
6751
6752
6753 wxGridCellEditor* wxGrid::GetDefaultEditorForCell(int row, int col) const
6754 {
6755 wxString typeName = m_table->GetTypeName(row, col);
6756 return GetDefaultEditorForType(typeName);
6757 }
6758
6759 wxGridCellRenderer* wxGrid::GetDefaultRendererForCell(int row, int col) const
6760 {
6761 wxString typeName = m_table->GetTypeName(row, col);
6762 return GetDefaultRendererForType(typeName);
6763 }
6764
6765 wxGridCellEditor*
6766 wxGrid::GetDefaultEditorForType(const wxString& typeName) const
6767 {
6768 int index = m_typeRegistry->FindDataType(typeName);
6769 if (index == -1) {
6770 // Should we force the failure here or let it fallback to string handling???
6771 // wxFAIL_MSG(wxT("Unknown data type name"));
6772 return NULL;
6773 }
6774 return m_typeRegistry->GetEditor(index);
6775 }
6776
6777 wxGridCellRenderer*
6778 wxGrid::GetDefaultRendererForType(const wxString& typeName) const
6779 {
6780 int index = m_typeRegistry->FindDataType(typeName);
6781 if (index == -1) {
6782 // Should we force the failure here or let it fallback to string handling???
6783 // wxFAIL_MSG(wxT("Unknown data type name"));
6784 return NULL;
6785 }
6786 return m_typeRegistry->GetRenderer(index);
6787 }
6788
6789
6790 // ----------------------------------------------------------------------------
6791 // row/col size
6792 // ----------------------------------------------------------------------------
6793
6794 void wxGrid::EnableDragRowSize( bool enable )
6795 {
6796 m_canDragRowSize = enable;
6797 }
6798
6799
6800 void wxGrid::EnableDragColSize( bool enable )
6801 {
6802 m_canDragColSize = enable;
6803 }
6804
6805 void wxGrid::EnableDragGridSize( bool enable )
6806 {
6807 m_canDragGridSize = enable;
6808 }
6809
6810
6811 void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
6812 {
6813 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
6814
6815 if ( resizeExistingRows )
6816 {
6817 InitRowHeights();
6818
6819 CalcDimensions();
6820 }
6821 }
6822
6823 void wxGrid::SetRowSize( int row, int height )
6824 {
6825 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
6826
6827 if ( m_rowHeights.IsEmpty() )
6828 {
6829 // need to really create the array
6830 InitRowHeights();
6831 }
6832
6833 int h = wxMax( 0, height );
6834 int diff = h - m_rowHeights[row];
6835
6836 m_rowHeights[row] = h;
6837 int i;
6838 for ( i = row; i < m_numRows; i++ )
6839 {
6840 m_rowBottoms[i] += diff;
6841 }
6842 CalcDimensions();
6843 }
6844
6845 void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
6846 {
6847 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
6848
6849 if ( resizeExistingCols )
6850 {
6851 InitColWidths();
6852
6853 CalcDimensions();
6854 }
6855 }
6856
6857 void wxGrid::SetColSize( int col, int width )
6858 {
6859 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
6860
6861 // should we check that it's bigger than GetColMinimalWidth(col) here?
6862
6863 if ( m_colWidths.IsEmpty() )
6864 {
6865 // need to really create the array
6866 InitColWidths();
6867 }
6868
6869 int w = wxMax( 0, width );
6870 int diff = w - m_colWidths[col];
6871 m_colWidths[col] = w;
6872
6873 int i;
6874 for ( i = col; i < m_numCols; i++ )
6875 {
6876 m_colRights[i] += diff;
6877 }
6878 CalcDimensions();
6879 }
6880
6881
6882 void wxGrid::SetColMinimalWidth( int col, int width )
6883 {
6884 m_colMinWidths.Put(col, width);
6885 }
6886
6887 void wxGrid::SetRowMinimalHeight( int row, int width )
6888 {
6889 m_rowMinHeights.Put(row, width);
6890 }
6891
6892 int wxGrid::GetColMinimalWidth(int col) const
6893 {
6894 long value = m_colMinWidths.Get(col);
6895 return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_COL_WIDTH;
6896 }
6897
6898 int wxGrid::GetRowMinimalHeight(int row) const
6899 {
6900 long value = m_rowMinHeights.Get(row);
6901 return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_ROW_HEIGHT;
6902 }
6903
6904 // ----------------------------------------------------------------------------
6905 // auto sizing
6906 // ----------------------------------------------------------------------------
6907
6908 void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column )
6909 {
6910 wxClientDC dc(m_gridWin);
6911
6912 int row, col;
6913 if ( column )
6914 col = colOrRow;
6915 else
6916 row = colOrRow;
6917
6918 wxCoord extent, extentMax = 0;
6919 int max = column ? m_numRows : m_numCols;
6920 for ( int rowOrCol = 0; rowOrCol < m_numRows; rowOrCol++ )
6921 {
6922 if ( column )
6923 row = rowOrCol;
6924 else
6925 col = rowOrCol;
6926
6927 wxGridCellAttr* attr = GetCellAttr(row, col);
6928 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
6929 if ( renderer )
6930 {
6931 wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col);
6932 extent = column ? size.x : size.y;
6933 if ( extent > extentMax )
6934 {
6935 extentMax = extent;
6936 }
6937 }
6938
6939 attr->DecRef();
6940 }
6941
6942 // now also compare with the column label extent
6943 wxCoord w, h;
6944 dc.SetFont( GetLabelFont() );
6945 dc.GetTextExtent( column ? GetColLabelValue(col)
6946 : GetRowLabelValue(row), &w, &h );
6947 extent = column ? w : h;
6948 if ( extent > extentMax )
6949 {
6950 extentMax = extent;
6951 }
6952
6953 if ( !extentMax )
6954 {
6955 // empty column - give default extent (notice that if extentMax is less
6956 // than default extent but != 0, it's ok)
6957 extentMax = column ? m_defaultColWidth : m_defaultRowHeight;
6958 }
6959 else
6960 {
6961 // leave some space around text
6962 extentMax += 10;
6963 }
6964
6965 if ( column )
6966 SetColSize(col, extentMax);
6967 else
6968 SetRowSize(col, extentMax);
6969
6970 if ( setAsMin )
6971 {
6972 if ( column )
6973 SetColMinimalWidth(col, extentMax);
6974 else
6975 SetRowMinimalHeight(col, extentMax);
6976 }
6977 }
6978
6979 int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
6980 {
6981 int width = m_rowLabelWidth;
6982
6983 for ( int col = 0; col < m_numCols; col++ )
6984 {
6985 if ( !calcOnly )
6986 {
6987 AutoSizeColumn(col, setAsMin);
6988 }
6989
6990 width += GetColWidth(col);
6991 }
6992
6993 return width;
6994 }
6995
6996 int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
6997 {
6998 int height = m_colLabelHeight;
6999
7000 for ( int row = 0; row < m_numRows; row++ )
7001 {
7002 if ( !calcOnly )
7003 {
7004 AutoSizeRow(row, setAsMin);
7005 }
7006
7007 height += GetRowHeight(row);
7008 }
7009
7010 return height;
7011 }
7012
7013 void wxGrid::AutoSize()
7014 {
7015 // set the size too
7016 SetSize(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE));
7017 }
7018
7019 wxSize wxGrid::DoGetBestSize() const
7020 {
7021 // don't set sizes, only calculate them
7022 wxGrid *self = (wxGrid *)this; // const_cast
7023
7024 return wxSize(self->SetOrCalcColumnSizes(TRUE),
7025 self->SetOrCalcRowSizes(TRUE));
7026 }
7027
7028 void wxGrid::Fit()
7029 {
7030 AutoSize();
7031 }
7032
7033 // ----------------------------------------------------------------------------
7034 // cell value accessor functions
7035 // ----------------------------------------------------------------------------
7036
7037 void wxGrid::SetCellValue( int row, int col, const wxString& s )
7038 {
7039 if ( m_table )
7040 {
7041 m_table->SetValue( row, col, s.c_str() );
7042 if ( !GetBatchCount() )
7043 {
7044 wxClientDC dc( m_gridWin );
7045 PrepareDC( dc );
7046 DrawCell( dc, wxGridCellCoords(row, col) );
7047 }
7048
7049 if ( m_currentCellCoords.GetRow() == row &&
7050 m_currentCellCoords.GetCol() == col &&
7051 IsCellEditControlEnabled())
7052 {
7053 HideCellEditControl();
7054 ShowCellEditControl(); // will reread data from table
7055 }
7056 }
7057 }
7058
7059
7060 //
7061 // ------ Block, row and col selection
7062 //
7063
7064 void wxGrid::SelectRow( int row, bool addToSelected )
7065 {
7066 wxRect r;
7067
7068 if ( IsSelection() && addToSelected )
7069 {
7070 wxRect rect[4];
7071 bool need_refresh[4];
7072 need_refresh[0] =
7073 need_refresh[1] =
7074 need_refresh[2] =
7075 need_refresh[3] = FALSE;
7076
7077 int i;
7078
7079 wxCoord oldLeft = m_selectedTopLeft.GetCol();
7080 wxCoord oldTop = m_selectedTopLeft.GetRow();
7081 wxCoord oldRight = m_selectedBottomRight.GetCol();
7082 wxCoord oldBottom = m_selectedBottomRight.GetRow();
7083
7084 if ( oldTop > row )
7085 {
7086 need_refresh[0] = TRUE;
7087 rect[0] = BlockToDeviceRect( wxGridCellCoords ( row, 0 ),
7088 wxGridCellCoords ( oldTop - 1,
7089 m_numCols - 1 ) );
7090 m_selectedTopLeft.SetRow( row );
7091 }
7092
7093 if ( oldLeft > 0 )
7094 {
7095 need_refresh[1] = TRUE;
7096 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop, 0 ),
7097 wxGridCellCoords ( oldBottom,
7098 oldLeft - 1 ) );
7099
7100 m_selectedTopLeft.SetCol( 0 );
7101 }
7102
7103 if ( oldBottom < row )
7104 {
7105 need_refresh[2] = TRUE;
7106 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1, 0 ),
7107 wxGridCellCoords ( row,
7108 m_numCols - 1 ) );
7109 m_selectedBottomRight.SetRow( row );
7110 }
7111
7112 if ( oldRight < m_numCols - 1 )
7113 {
7114 need_refresh[3] = TRUE;
7115 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop ,
7116 oldRight + 1 ),
7117 wxGridCellCoords ( oldBottom,
7118 m_numCols - 1 ) );
7119 m_selectedBottomRight.SetCol( m_numCols - 1 );
7120 }
7121
7122 for (i = 0; i < 4; i++ )
7123 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
7124 m_gridWin->Refresh( FALSE, &(rect[i]) );
7125 }
7126 else
7127 {
7128 r = SelectionToDeviceRect();
7129 ClearSelection();
7130 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
7131
7132 m_selectedTopLeft.Set( row, 0 );
7133 m_selectedBottomRight.Set( row, m_numCols-1 );
7134 r = SelectionToDeviceRect();
7135 m_gridWin->Refresh( FALSE, &r );
7136 }
7137
7138 wxGridRangeSelectEvent gridEvt( GetId(),
7139 wxEVT_GRID_RANGE_SELECT,
7140 this,
7141 m_selectedTopLeft,
7142 m_selectedBottomRight );
7143
7144 GetEventHandler()->ProcessEvent(gridEvt);
7145 }
7146
7147
7148 void wxGrid::SelectCol( int col, bool addToSelected )
7149 {
7150 if ( IsSelection() && addToSelected )
7151 {
7152 wxRect rect[4];
7153 bool need_refresh[4];
7154 need_refresh[0] =
7155 need_refresh[1] =
7156 need_refresh[2] =
7157 need_refresh[3] = FALSE;
7158 int i;
7159
7160 wxCoord oldLeft = m_selectedTopLeft.GetCol();
7161 wxCoord oldTop = m_selectedTopLeft.GetRow();
7162 wxCoord oldRight = m_selectedBottomRight.GetCol();
7163 wxCoord oldBottom = m_selectedBottomRight.GetRow();
7164
7165 if ( oldLeft > col )
7166 {
7167 need_refresh[0] = TRUE;
7168 rect[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col ),
7169 wxGridCellCoords ( m_numRows - 1,
7170 oldLeft - 1 ) );
7171 m_selectedTopLeft.SetCol( col );
7172 }
7173
7174 if ( oldTop > 0 )
7175 {
7176 need_refresh[1] = TRUE;
7177 rect[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft ),
7178 wxGridCellCoords ( oldTop - 1,
7179 oldRight ) );
7180 m_selectedTopLeft.SetRow( 0 );
7181 }
7182
7183 if ( oldRight < col )
7184 {
7185 need_refresh[2] = TRUE;
7186 rect[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight + 1 ),
7187 wxGridCellCoords ( m_numRows - 1,
7188 col ) );
7189 m_selectedBottomRight.SetCol( col );
7190 }
7191
7192 if ( oldBottom < m_numRows - 1 )
7193 {
7194 need_refresh[3] = TRUE;
7195 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1,
7196 oldLeft ),
7197 wxGridCellCoords ( m_numRows - 1,
7198 oldRight ) );
7199 m_selectedBottomRight.SetRow( m_numRows - 1 );
7200 }
7201
7202 for (i = 0; i < 4; i++ )
7203 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
7204 m_gridWin->Refresh( FALSE, &(rect[i]) );
7205 }
7206 else
7207 {
7208 wxRect r;
7209
7210 r = SelectionToDeviceRect();
7211 ClearSelection();
7212 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
7213
7214 m_selectedTopLeft.Set( 0, col );
7215 m_selectedBottomRight.Set( m_numRows-1, col );
7216 r = SelectionToDeviceRect();
7217 m_gridWin->Refresh( FALSE, &r );
7218 }
7219
7220 wxGridRangeSelectEvent gridEvt( GetId(),
7221 wxEVT_GRID_RANGE_SELECT,
7222 this,
7223 m_selectedTopLeft,
7224 m_selectedBottomRight );
7225
7226 GetEventHandler()->ProcessEvent(gridEvt);
7227 }
7228
7229
7230 void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
7231 {
7232 int temp;
7233 wxGridCellCoords updateTopLeft, updateBottomRight;
7234
7235 if ( topRow > bottomRow )
7236 {
7237 temp = topRow;
7238 topRow = bottomRow;
7239 bottomRow = temp;
7240 }
7241
7242 if ( leftCol > rightCol )
7243 {
7244 temp = leftCol;
7245 leftCol = rightCol;
7246 rightCol = temp;
7247 }
7248
7249 updateTopLeft = wxGridCellCoords( topRow, leftCol );
7250 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
7251
7252 if ( m_selectedTopLeft != updateTopLeft ||
7253 m_selectedBottomRight != updateBottomRight )
7254 {
7255 // Compute two optimal update rectangles:
7256 // Either one rectangle is a real subset of the
7257 // other, or they are (almost) disjoint!
7258 wxRect rect[4];
7259 bool need_refresh[4];
7260 need_refresh[0] =
7261 need_refresh[1] =
7262 need_refresh[2] =
7263 need_refresh[3] = FALSE;
7264 int i;
7265
7266 // Store intermediate values
7267 wxCoord oldLeft = m_selectedTopLeft.GetCol();
7268 wxCoord oldTop = m_selectedTopLeft.GetRow();
7269 wxCoord oldRight = m_selectedBottomRight.GetCol();
7270 wxCoord oldBottom = m_selectedBottomRight.GetRow();
7271
7272 // Determine the outer/inner coordinates.
7273 if (oldLeft > leftCol)
7274 {
7275 temp = oldLeft;
7276 oldLeft = leftCol;
7277 leftCol = temp;
7278 }
7279 if (oldTop > topRow )
7280 {
7281 temp = oldTop;
7282 oldTop = topRow;
7283 topRow = temp;
7284 }
7285 if (oldRight < rightCol )
7286 {
7287 temp = oldRight;
7288 oldRight = rightCol;
7289 rightCol = temp;
7290 }
7291 if (oldBottom < bottomRow)
7292 {
7293 temp = oldBottom;
7294 oldBottom = bottomRow;
7295 bottomRow = temp;
7296 }
7297
7298 // Now, either the stuff marked old is the outer
7299 // rectangle or we don't have a situation where one
7300 // is contained in the other.
7301
7302 if ( oldLeft < leftCol )
7303 {
7304 need_refresh[0] = TRUE;
7305 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
7306 oldLeft ),
7307 wxGridCellCoords ( oldBottom,
7308 leftCol - 1 ) );
7309 }
7310
7311 if ( oldTop < topRow )
7312 {
7313 need_refresh[1] = TRUE;
7314 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
7315 leftCol ),
7316 wxGridCellCoords ( topRow - 1,
7317 rightCol ) );
7318 }
7319
7320 if ( oldRight > rightCol )
7321 {
7322 need_refresh[2] = TRUE;
7323 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
7324 rightCol + 1 ),
7325 wxGridCellCoords ( oldBottom,
7326 oldRight ) );
7327 }
7328
7329 if ( oldBottom > bottomRow )
7330 {
7331 need_refresh[3] = TRUE;
7332 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
7333 leftCol ),
7334 wxGridCellCoords ( oldBottom,
7335 rightCol ) );
7336 }
7337
7338
7339 // Change Selection
7340 m_selectedTopLeft = updateTopLeft;
7341 m_selectedBottomRight = updateBottomRight;
7342
7343 // various Refresh() calls
7344 for (i = 0; i < 4; i++ )
7345 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
7346 m_gridWin->Refresh( FALSE, &(rect[i]) );
7347 }
7348
7349 // only generate an event if the block is not being selected by
7350 // dragging the mouse (in which case the event will be generated in
7351 // the mouse event handler)
7352 if ( !m_isDragging )
7353 {
7354 wxGridRangeSelectEvent gridEvt( GetId(),
7355 wxEVT_GRID_RANGE_SELECT,
7356 this,
7357 m_selectedTopLeft,
7358 m_selectedBottomRight );
7359
7360 GetEventHandler()->ProcessEvent(gridEvt);
7361 }
7362 }
7363
7364 void wxGrid::SelectAll()
7365 {
7366 m_selectedTopLeft.Set( 0, 0 );
7367 m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 );
7368
7369 m_gridWin->Refresh();
7370 }
7371
7372
7373 void wxGrid::ClearSelection()
7374 {
7375 m_selectedTopLeft = wxGridNoCellCoords;
7376 m_selectedBottomRight = wxGridNoCellCoords;
7377 }
7378
7379
7380 // This function returns the rectangle that encloses the given block
7381 // in device coords clipped to the client size of the grid window.
7382 //
7383 wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
7384 const wxGridCellCoords &bottomRight )
7385 {
7386 wxRect rect( wxGridNoCellRect );
7387 wxRect cellRect;
7388
7389 cellRect = CellToRect( topLeft );
7390 if ( cellRect != wxGridNoCellRect )
7391 {
7392 rect = cellRect;
7393 }
7394 else
7395 {
7396 rect = wxRect( 0, 0, 0, 0 );
7397 }
7398
7399 cellRect = CellToRect( bottomRight );
7400 if ( cellRect != wxGridNoCellRect )
7401 {
7402 rect += cellRect;
7403 }
7404 else
7405 {
7406 return wxGridNoCellRect;
7407 }
7408
7409 // convert to scrolled coords
7410 //
7411 int left, top, right, bottom;
7412 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
7413 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
7414
7415 int cw, ch;
7416 m_gridWin->GetClientSize( &cw, &ch );
7417
7418 rect.SetLeft( wxMax(0, left) );
7419 rect.SetTop( wxMax(0, top) );
7420 rect.SetRight( wxMin(cw, right) );
7421 rect.SetBottom( wxMin(ch, bottom) );
7422
7423 return rect;
7424 }
7425
7426
7427
7428 //
7429 // ------ Grid event classes
7430 //
7431
7432 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
7433
7434 wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
7435 int row, int col, int x, int y,
7436 bool control, bool shift, bool alt, bool meta )
7437 : wxNotifyEvent( type, id )
7438 {
7439 m_row = row;
7440 m_col = col;
7441 m_x = x;
7442 m_y = y;
7443 m_control = control;
7444 m_shift = shift;
7445 m_alt = alt;
7446 m_meta = meta;
7447
7448 SetEventObject(obj);
7449 }
7450
7451
7452 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
7453
7454 wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
7455 int rowOrCol, int x, int y,
7456 bool control, bool shift, bool alt, bool meta )
7457 : wxNotifyEvent( type, id )
7458 {
7459 m_rowOrCol = rowOrCol;
7460 m_x = x;
7461 m_y = y;
7462 m_control = control;
7463 m_shift = shift;
7464 m_alt = alt;
7465 m_meta = meta;
7466
7467 SetEventObject(obj);
7468 }
7469
7470
7471 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
7472
7473 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
7474 const wxGridCellCoords& topLeft,
7475 const wxGridCellCoords& bottomRight,
7476 bool control, bool shift, bool alt, bool meta )
7477 : wxNotifyEvent( type, id )
7478 {
7479 m_topLeft = topLeft;
7480 m_bottomRight = bottomRight;
7481 m_control = control;
7482 m_shift = shift;
7483 m_alt = alt;
7484 m_meta = meta;
7485
7486 SetEventObject(obj);
7487 }
7488
7489
7490 #endif // ifndef wxUSE_NEW_GRID
7491