]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/grid.cpp
check default library directories in WX_PATH_FIND_LIBRARIES; do *not* add default...
[wxWidgets.git] / src / generic / grid.cpp
... / ...
Content-type: text/html ]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/grid.cpp


500 - Internal Server Error

Malformed UTF-8 character (fatal) at /usr/lib/x86_64-linux-gnu/perl5/5.40/HTML/Entities.pm line 485, <$fd> line 3911.
CommitLineData
1///////////////////////////////////////////////////////////////////////////
2// Name: generic/grid.cpp
3// Purpose: wxGrid and related classes
4// Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
5// Modified by: Robin Dunn, Vadim Zeitlin
6// Created: 1/08/1999
7// RCS-ID: $Id$
8// Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "grid.h"
22#endif
23
24// For compilers that support precompilatixon, includes "wx/wx.h".
25#include "wx/wxprec.h"
26
27#include "wx/defs.h"
28
29#ifdef __BORLANDC__
30 #pragma hdrstop
31#endif
32
33#if wxUSE_GRID
34
35#ifndef WX_PRECOMP
36 #include "wx/utils.h"
37 #include "wx/dcclient.h"
38 #include "wx/settings.h"
39 #include "wx/log.h"
40 #include "wx/textctrl.h"
41 #include "wx/checkbox.h"
42 #include "wx/combobox.h"
43 #include "wx/valtext.h"
44 #include "wx/intl.h"
45#endif
46
47#include "wx/textfile.h"
48#include "wx/spinctrl.h"
49#include "wx/tokenzr.h"
50#include "wx/renderer.h"
51
52#include "wx/grid.h"
53#include "wx/generic/gridsel.h"
54
55#if defined(__WXMOTIF__)
56 #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier)
57#else
58 #define WXUNUSED_MOTIF(identifier) identifier
59#endif
60
61#if defined(__WXGTK__)
62 #define WXUNUSED_GTK(identifier) WXUNUSED(identifier)
63#else
64 #define WXUNUSED_GTK(identifier) identifier
65#endif
66
67// Required for wxIs... functions
68#include <ctype.h>
69
70// ----------------------------------------------------------------------------
71// array classes
72// ----------------------------------------------------------------------------
73
74WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridCellAttr *, wxArrayAttrs,
75 class WXDLLIMPEXP_ADV);
76
77struct wxGridCellWithAttr
78{
79 wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_)
80 : coords(row, col), attr(attr_)
81 {
82 }
83
84 ~wxGridCellWithAttr()
85 {
86 attr->DecRef();
87 }
88
89 wxGridCellCoords coords;
90 wxGridCellAttr *attr;
91
92// Cannot do this:
93// DECLARE_NO_COPY_CLASS(wxGridCellWithAttr)
94// without rewriting the macros, which require a public copy constructor.
95};
96
97WX_DECLARE_OBJARRAY_WITH_DECL(wxGridCellWithAttr, wxGridCellWithAttrArray,
98 class WXDLLIMPEXP_ADV);
99
100#include "wx/arrimpl.cpp"
101
102WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
103WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
104
105// ----------------------------------------------------------------------------
106// events
107// ----------------------------------------------------------------------------
108
109DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_CLICK)
110DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_CLICK)
111DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_DCLICK)
112DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_DCLICK)
113DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_BEGIN_DRAG)
114DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_CLICK)
115DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_CLICK)
116DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK)
117DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK)
118DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE)
119DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE)
120DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT)
121DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE)
122DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL)
123DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN)
124DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN)
125DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED)
126
127// ----------------------------------------------------------------------------
128// private classes
129// ----------------------------------------------------------------------------
130
131class WXDLLIMPEXP_ADV wxGridRowLabelWindow : public wxWindow
132{
133public:
134 wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; }
135 wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
136 const wxPoint &pos, const wxSize &size );
137
138private:
139 wxGrid *m_owner;
140
141 void OnPaint( wxPaintEvent& event );
142 void OnMouseEvent( wxMouseEvent& event );
143 void OnMouseWheel( wxMouseEvent& event );
144 void OnKeyDown( wxKeyEvent& event );
145 void OnKeyUp( wxKeyEvent& );
146 void OnChar( wxKeyEvent& );
147
148 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
149 DECLARE_EVENT_TABLE()
150 DECLARE_NO_COPY_CLASS(wxGridRowLabelWindow)
151};
152
153
154class WXDLLIMPEXP_ADV wxGridColLabelWindow : public wxWindow
155{
156public:
157 wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; }
158 wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
159 const wxPoint &pos, const wxSize &size );
160
161private:
162 wxGrid *m_owner;
163
164 void OnPaint( wxPaintEvent &event );
165 void OnMouseEvent( wxMouseEvent& event );
166 void OnMouseWheel( wxMouseEvent& event );
167 void OnKeyDown( wxKeyEvent& event );
168 void OnKeyUp( wxKeyEvent& );
169 void OnChar( wxKeyEvent& );
170
171 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
172 DECLARE_EVENT_TABLE()
173 DECLARE_NO_COPY_CLASS(wxGridColLabelWindow)
174};
175
176
177class WXDLLIMPEXP_ADV wxGridCornerLabelWindow : public wxWindow
178{
179public:
180 wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; }
181 wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
182 const wxPoint &pos, const wxSize &size );
183
184private:
185 wxGrid *m_owner;
186
187 void OnMouseEvent( wxMouseEvent& event );
188 void OnMouseWheel( wxMouseEvent& event );
189 void OnKeyDown( wxKeyEvent& event );
190 void OnKeyUp( wxKeyEvent& );
191 void OnChar( wxKeyEvent& );
192 void OnPaint( wxPaintEvent& event );
193
194 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
195 DECLARE_EVENT_TABLE()
196 DECLARE_NO_COPY_CLASS(wxGridCornerLabelWindow)
197};
198
199class WXDLLIMPEXP_ADV wxGridWindow : public wxWindow
200{
201public:
202 wxGridWindow()
203 {
204 m_owner = (wxGrid *)NULL;
205 m_rowLabelWin = (wxGridRowLabelWindow *)NULL;
206 m_colLabelWin = (wxGridColLabelWindow *)NULL;
207 }
208
209 wxGridWindow( wxGrid *parent,
210 wxGridRowLabelWindow *rowLblWin,
211 wxGridColLabelWindow *colLblWin,
212 wxWindowID id, const wxPoint &pos, const wxSize &size );
213 ~wxGridWindow(){}
214
215 void ScrollWindow( int dx, int dy, const wxRect *rect );
216
217 wxGrid* GetOwner() { return m_owner; }
218
219private:
220 wxGrid *m_owner;
221 wxGridRowLabelWindow *m_rowLabelWin;
222 wxGridColLabelWindow *m_colLabelWin;
223
224 void OnPaint( wxPaintEvent &event );
225 void OnMouseWheel( wxMouseEvent& event );
226 void OnMouseEvent( wxMouseEvent& event );
227 void OnKeyDown( wxKeyEvent& );
228 void OnKeyUp( wxKeyEvent& );
229 void OnChar( wxKeyEvent& );
230 void OnEraseBackground( wxEraseEvent& );
231 void OnFocus( wxFocusEvent& );
232
233 DECLARE_DYNAMIC_CLASS(wxGridWindow)
234 DECLARE_EVENT_TABLE()
235 DECLARE_NO_COPY_CLASS(wxGridWindow)
236};
237
238
239
240class wxGridCellEditorEvtHandler : public wxEvtHandler
241{
242public:
243 wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor)
244 : m_grid(grid),
245 m_editor(editor),
246 m_inSetFocus(false)
247 {
248 }
249
250 void OnKillFocus(wxFocusEvent& event);
251 void OnKeyDown(wxKeyEvent& event);
252 void OnChar(wxKeyEvent& event);
253
254 void SetInSetFocus(bool inSetFocus) { m_inSetFocus = inSetFocus; }
255
256private:
257 wxGrid* m_grid;
258 wxGridCellEditor* m_editor;
259
260 // Work around the fact that a focus kill event can be sent to
261 // a combobox within a set focus event.
262 bool m_inSetFocus;
263
264 DECLARE_EVENT_TABLE()
265 DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler)
266 DECLARE_NO_COPY_CLASS(wxGridCellEditorEvtHandler)
267};
268
269
270IMPLEMENT_ABSTRACT_CLASS(wxGridCellEditorEvtHandler, wxEvtHandler)
271
272BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler )
273 EVT_KILL_FOCUS( wxGridCellEditorEvtHandler::OnKillFocus )
274 EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown )
275 EVT_CHAR( wxGridCellEditorEvtHandler::OnChar )
276END_EVENT_TABLE()
277
278
279
280// ----------------------------------------------------------------------------
281// the internal data representation used by wxGridCellAttrProvider
282// ----------------------------------------------------------------------------
283
284// this class stores attributes set for cells
285class WXDLLIMPEXP_ADV wxGridCellAttrData
286{
287public:
288 void SetAttr(wxGridCellAttr *attr, int row, int col);
289 wxGridCellAttr *GetAttr(int row, int col) const;
290 void UpdateAttrRows( size_t pos, int numRows );
291 void UpdateAttrCols( size_t pos, int numCols );
292
293private:
294 // searches for the attr for given cell, returns wxNOT_FOUND if not found
295 int FindIndex(int row, int col) const;
296
297 wxGridCellWithAttrArray m_attrs;
298};
299
300// this class stores attributes set for rows or columns
301class WXDLLIMPEXP_ADV wxGridRowOrColAttrData
302{
303public:
304 // empty ctor to suppress warnings
305 wxGridRowOrColAttrData() { }
306 ~wxGridRowOrColAttrData();
307
308 void SetAttr(wxGridCellAttr *attr, int rowOrCol);
309 wxGridCellAttr *GetAttr(int rowOrCol) const;
310 void UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols );
311
312private:
313 wxArrayInt m_rowsOrCols;
314 wxArrayAttrs m_attrs;
315};
316
317// NB: this is just a wrapper around 3 objects: one which stores cell
318// attributes, and 2 others for row/col ones
319class WXDLLIMPEXP_ADV wxGridCellAttrProviderData
320{
321public:
322 wxGridCellAttrData m_cellAttrs;
323 wxGridRowOrColAttrData m_rowAttrs,
324 m_colAttrs;
325};
326
327
328// ----------------------------------------------------------------------------
329// data structures used for the data type registry
330// ----------------------------------------------------------------------------
331
332struct wxGridDataTypeInfo
333{
334 wxGridDataTypeInfo(const wxString& typeName,
335 wxGridCellRenderer* renderer,
336 wxGridCellEditor* editor)
337 : m_typeName(typeName), m_renderer(renderer), m_editor(editor)
338 { }
339
340 ~wxGridDataTypeInfo()
341 {
342 wxSafeDecRef(m_renderer);
343 wxSafeDecRef(m_editor);
344 }
345
346 wxString m_typeName;
347 wxGridCellRenderer* m_renderer;
348 wxGridCellEditor* m_editor;
349
350 DECLARE_NO_COPY_CLASS(wxGridDataTypeInfo)
351};
352
353
354WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridDataTypeInfo*, wxGridDataTypeInfoArray,
355 class WXDLLIMPEXP_ADV);
356
357
358class WXDLLIMPEXP_ADV wxGridTypeRegistry
359{
360public:
361 wxGridTypeRegistry() {}
362 ~wxGridTypeRegistry();
363
364 void RegisterDataType(const wxString& typeName,
365 wxGridCellRenderer* renderer,
366 wxGridCellEditor* editor);
367
368 // find one of already registered data types
369 int FindRegisteredDataType(const wxString& typeName);
370
371 // try to FindRegisteredDataType(), if this fails and typeName is one of
372 // standard typenames, register it and return its index
373 int FindDataType(const wxString& typeName);
374
375 // try to FindDataType(), if it fails see if it is not one of already
376 // registered data types with some params in which case clone the
377 // registered data type and set params for it
378 int FindOrCloneDataType(const wxString& typeName);
379
380 wxGridCellRenderer* GetRenderer(int index);
381 wxGridCellEditor* GetEditor(int index);
382
383private:
384 wxGridDataTypeInfoArray m_typeinfo;
385};
386
387// ----------------------------------------------------------------------------
388// conditional compilation
389// ----------------------------------------------------------------------------
390
391#ifndef WXGRID_DRAW_LINES
392#define WXGRID_DRAW_LINES 1
393#endif
394
395// ----------------------------------------------------------------------------
396// globals
397// ----------------------------------------------------------------------------
398
399//#define DEBUG_ATTR_CACHE
400#ifdef DEBUG_ATTR_CACHE
401 static size_t gs_nAttrCacheHits = 0;
402 static size_t gs_nAttrCacheMisses = 0;
403#endif // DEBUG_ATTR_CACHE
404
405// ----------------------------------------------------------------------------
406// constants
407// ----------------------------------------------------------------------------
408
409wxGridCellCoords wxGridNoCellCoords( -1, -1 );
410wxRect wxGridNoCellRect( -1, -1, -1, -1 );
411
412// scroll line size
413// TODO: this doesn't work at all, grid cells have different sizes and approx
414// calculations don't work as because of the size mismatch scrollbars
415// sometimes fail to be shown when they should be or vice versa
416//
417// The scroll bars may be a little flakey once in a while, but that is
418// surely much less horrible than having scroll lines of only 1!!!
419// -- Robin
420//
421// Well, it's still seriously broken so it might be better but needs
422// fixing anyhow
423// -- Vadim
424static const size_t GRID_SCROLL_LINE_X = 15; // 1;
425static const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X;
426
427// the size of hash tables used a bit everywhere (the max number of elements
428// in these hash tables is the number of rows/columns)
429static const int GRID_HASH_SIZE = 100;
430
431#if 0
432// ----------------------------------------------------------------------------
433// private functions
434// ----------------------------------------------------------------------------
435
436static inline int GetScrollX(int x)
437{
438 return (x + GRID_SCROLL_LINE_X - 1) / GRID_SCROLL_LINE_X;
439}
440
441static inline int GetScrollY(int y)
442{
443 return (y + GRID_SCROLL_LINE_Y - 1) / GRID_SCROLL_LINE_Y;
444}
445#endif
446
447// ============================================================================
448// implementation
449// ============================================================================
450
451// ----------------------------------------------------------------------------
452// wxGridCellEditor
453// ----------------------------------------------------------------------------
454
455wxGridCellEditor::wxGridCellEditor()
456{
457 m_control = NULL;
458 m_attr = NULL;
459}
460
461
462wxGridCellEditor::~wxGridCellEditor()
463{
464 Destroy();
465}
466
467void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
468 wxWindowID WXUNUSED(id),
469 wxEvtHandler* evtHandler)
470{
471 if ( evtHandler )
472 m_control->PushEventHandler(evtHandler);
473}
474
475void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
476 wxGridCellAttr *attr)
477{
478 // erase the background because we might not fill the cell
479 wxClientDC dc(m_control->GetParent());
480 wxGridWindow* gridWindow = wxDynamicCast(m_control->GetParent(), wxGridWindow);
481 if (gridWindow)
482 gridWindow->GetOwner()->PrepareDC(dc);
483
484 dc.SetPen(*wxTRANSPARENT_PEN);
485 dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
486 dc.DrawRectangle(rectCell);
487
488 // redraw the control we just painted over
489 m_control->Refresh();
490}
491
492void wxGridCellEditor::Destroy()
493{
494 if (m_control)
495 {
496 m_control->PopEventHandler(true /* delete it*/);
497
498 m_control->Destroy();
499 m_control = NULL;
500 }
501}
502
503void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
504{
505 wxASSERT_MSG(m_control,
506 wxT("The wxGridCellEditor must be Created first!"));
507 m_control->Show(show);
508
509 if ( show )
510 {
511 // set the colours/fonts if we have any
512 if ( attr )
513 {
514 m_colFgOld = m_control->GetForegroundColour();
515 m_control->SetForegroundColour(attr->GetTextColour());
516
517 m_colBgOld = m_control->GetBackgroundColour();
518 m_control->SetBackgroundColour(attr->GetBackgroundColour());
519
520// Workaround for GTK+1 font setting problem on some platforms
521#if !defined(__WXGTK__) || defined(__WXGTK20__)
522 m_fontOld = m_control->GetFont();
523 m_control->SetFont(attr->GetFont());
524#endif
525 // can't do anything more in the base class version, the other
526 // attributes may only be used by the derived classes
527 }
528 }
529 else
530 {
531 // restore the standard colours fonts
532 if ( m_colFgOld.Ok() )
533 {
534 m_control->SetForegroundColour(m_colFgOld);
535 m_colFgOld = wxNullColour;
536 }
537
538 if ( m_colBgOld.Ok() )
539 {
540 m_control->SetBackgroundColour(m_colBgOld);
541 m_colBgOld = wxNullColour;
542 }
543// Workaround for GTK+1 font setting problem on some platforms
544#if !defined(__WXGTK__) || defined(__WXGTK20__)
545 if ( m_fontOld.Ok() )
546 {
547 m_control->SetFont(m_fontOld);
548 m_fontOld = wxNullFont;
549 }
550#endif
551 }
552}
553
554void wxGridCellEditor::SetSize(const wxRect& rect)
555{
556 wxASSERT_MSG(m_control,
557 wxT("The wxGridCellEditor must be Created first!"));
558 m_control->SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
559}
560
561void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
562{
563 event.Skip();
564}
565
566bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event)
567{
568 bool ctrl = event.ControlDown();
569 bool alt = event.AltDown();
570#ifdef __WXMAC__
571 // On the Mac the Alt key is more like shift and is used for entry of
572 // valid characters, so check for Ctrl and Meta instead.
573 alt = event.MetaDown();
574#endif
575
576 // Assume it's not a valid char if ctrl or alt is down, but if both are
577 // down then it may be because of an AltGr key combination, so let them
578 // through in that case.
579 if ((ctrl || alt) && !(ctrl && alt))
580 return false;
581
582#if wxUSE_UNICODE
583 int key = event.GetUnicodeKey();
584 bool keyOk = true;
585
586 // if the unicode key code is not really a unicode character (it may
587 // be a function key or etc., the platforms appear to always give us a
588 // small value in this case) then fallback to the ascii key code but
589 // don't do anything for function keys or etc.
590 if (key <= 127)
591 {
592 key = event.GetKeyCode();
593 keyOk = (key <= 127);
594 }
595 return keyOk;
596#else // !wxUSE_UNICODE
597 int key = event.GetKeyCode();
598 if (key <= 255)
599 return true;
600 return false;
601#endif // wxUSE_UNICODE/!wxUSE_UNICODE
602}
603
604void wxGridCellEditor::StartingKey(wxKeyEvent& event)
605{
606 event.Skip();
607}
608
609void wxGridCellEditor::StartingClick()
610{
611}
612
613#if wxUSE_TEXTCTRL
614
615// ----------------------------------------------------------------------------
616// wxGridCellTextEditor
617// ----------------------------------------------------------------------------
618
619wxGridCellTextEditor::wxGridCellTextEditor()
620{
621 m_maxChars = 0;
622}
623
624void wxGridCellTextEditor::Create(wxWindow* parent,
625 wxWindowID id,
626 wxEvtHandler* evtHandler)
627{
628 m_control = new wxTextCtrl(parent, id, wxEmptyString,
629 wxDefaultPosition, wxDefaultSize
630#if defined(__WXMSW__)
631 , wxTE_PROCESS_TAB | wxTE_AUTO_SCROLL
632#endif
633 );
634
635 // set max length allowed in the textctrl, if the parameter was set
636 if (m_maxChars != 0)
637 {
638 ((wxTextCtrl*)m_control)->SetMaxLength(m_maxChars);
639 }
640
641 wxGridCellEditor::Create(parent, id, evtHandler);
642}
643
644void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell),
645 wxGridCellAttr * WXUNUSED(attr))
646{
647 // as we fill the entire client area, don't do anything here to minimize
648 // flicker
649}
650
651void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
652{
653 wxRect rect(rectOrig);
654
655 // Make the edit control large enough to allow for internal
656 // margins
657 //
658 // TODO: remove this if the text ctrl sizing is improved esp. for
659 // unix
660 //
661#if defined(__WXGTK__)
662 if (rect.x != 0)
663 {
664 rect.x += 1;
665 rect.y += 1;
666 rect.width -= 1;
667 rect.height -= 1;
668 }
669#else // !GTK
670 int extra_x = ( rect.x > 2 )? 2 : 1;
671
672// MB: treat MSW separately here otherwise the caret doesn't show
673// when the editor is in the first row.
674#if defined(__WXMSW__)
675 int extra_y = 2;
676#else
677 int extra_y = ( rect.y > 2 )? 2 : 1;
678#endif // MSW
679
680#if defined(__WXMOTIF__)
681 extra_x *= 2;
682 extra_y *= 2;
683#endif
684 rect.SetLeft( wxMax(0, rect.x - extra_x) );
685 rect.SetTop( wxMax(0, rect.y - extra_y) );
686 rect.SetRight( rect.GetRight() + 2*extra_x );
687 rect.SetBottom( rect.GetBottom() + 2*extra_y );
688#endif // GTK/!GTK
689
690 wxGridCellEditor::SetSize(rect);
691}
692
693void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid)
694{
695 wxASSERT_MSG(m_control,
696 wxT("The wxGridCellEditor must be Created first!"));
697
698 m_startValue = grid->GetTable()->GetValue(row, col);
699
700 DoBeginEdit(m_startValue);
701}
702
703void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
704{
705 Text()->SetValue(startValue);
706 Text()->SetInsertionPointEnd();
707 Text()->SetSelection(-1,-1);
708 Text()->SetFocus();
709}
710
711bool wxGridCellTextEditor::EndEdit(int row, int col,
712 wxGrid* grid)
713{
714 wxASSERT_MSG(m_control,
715 wxT("The wxGridCellEditor must be Created first!"));
716
717 bool changed = false;
718 wxString value = Text()->GetValue();
719 if (value != m_startValue)
720 changed = true;
721
722 if (changed)
723 grid->GetTable()->SetValue(row, col, value);
724
725 m_startValue = wxEmptyString;
726 // No point in setting the text of the hidden control
727 //Text()->SetValue(m_startValue);
728
729 return changed;
730}
731
732
733void wxGridCellTextEditor::Reset()
734{
735 wxASSERT_MSG(m_control,
736 wxT("The wxGridCellEditor must be Created first!"));
737
738 DoReset(m_startValue);
739}
740
741void wxGridCellTextEditor::DoReset(const wxString& startValue)
742{
743 Text()->SetValue(startValue);
744 Text()->SetInsertionPointEnd();
745}
746
747bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event)
748{
749 return wxGridCellEditor::IsAcceptedKey(event);
750}
751
752void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
753{
754 // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no
755 // longer an appropriate way to get the character into the text control.
756 // Do it ourselves instead. We know that if we get this far that we have
757 // a valid character, so not a whole lot of testing needs to be done.
758
759 wxTextCtrl* tc = Text();
760 wxChar ch;
761 long pos;
762
763#if wxUSE_UNICODE
764 ch = event.GetUnicodeKey();
765 if (ch <= 127)
766 ch = (wxChar)event.GetKeyCode();
767#else
768 ch = (wxChar)event.GetKeyCode();
769#endif
770 switch (ch)
771 {
772 case WXK_DELETE:
773 // delete the character at the cursor
774 pos = tc->GetInsertionPoint();
775 if (pos < tc->GetLastPosition())
776 tc->Remove(pos, pos+1);
777 break;
778
779 case WXK_BACK:
780 // delete the character before the cursor
781 pos = tc->GetInsertionPoint();
782 if (pos > 0)
783 tc->Remove(pos-1, pos);
784 break;
785
786 default:
787 tc->WriteText(ch);
788 break;
789 }
790}
791
792void wxGridCellTextEditor::HandleReturn( wxKeyEvent&
793 WXUNUSED_GTK(WXUNUSED_MOTIF(event)) )
794{
795#if defined(__WXMOTIF__) || defined(__WXGTK__)
796 // wxMotif needs a little extra help...
797 size_t pos = (size_t)( Text()->GetInsertionPoint() );
798 wxString s( Text()->GetValue() );
799 s = s.Left(pos) + wxT("\n") + s.Mid(pos);
800 Text()->SetValue(s);
801 Text()->SetInsertionPoint( pos );
802#else
803 // the other ports can handle a Return key press
804 //
805 event.Skip();
806#endif
807}
808
809void wxGridCellTextEditor::SetParameters(const wxString& params)
810{
811 if ( !params )
812 {
813 // reset to default
814 m_maxChars = 0;
815 }
816 else
817 {
818 long tmp;
819 if ( !params.ToLong(&tmp) )
820 {
821 wxLogDebug(_T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str());
822 }
823 else
824 {
825 m_maxChars = (size_t)tmp;
826 }
827 }
828}
829
830// return the value in the text control
831wxString wxGridCellTextEditor::GetValue() const
832{
833 return Text()->GetValue();
834}
835
836// ----------------------------------------------------------------------------
837// wxGridCellNumberEditor
838// ----------------------------------------------------------------------------
839
840wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max)
841{
842 m_min = min;
843 m_max = max;
844}
845
846void wxGridCellNumberEditor::Create(wxWindow* parent,
847 wxWindowID id,
848 wxEvtHandler* evtHandler)
849{
850#if wxUSE_SPINCTRL
851 if ( HasRange() )
852 {
853 // create a spin ctrl
854 m_control = new wxSpinCtrl(parent, wxID_ANY, wxEmptyString,
855 wxDefaultPosition, wxDefaultSize,
856 wxSP_ARROW_KEYS,
857 m_min, m_max);
858
859 wxGridCellEditor::Create(parent, id, evtHandler);
860 }
861 else
862#endif
863 {
864 // just a text control
865 wxGridCellTextEditor::Create(parent, id, evtHandler);
866
867#if wxUSE_VALIDATORS
868 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
869#endif // wxUSE_VALIDATORS
870 }
871}
872
873void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
874{
875 // first get the value
876 wxGridTableBase *table = grid->GetTable();
877 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
878 {
879 m_valueOld = table->GetValueAsLong(row, col);
880 }
881 else
882 {
883 m_valueOld = 0;
884 wxString sValue = table->GetValue(row, col);
885 if (! sValue.ToLong(&m_valueOld) && ! sValue.empty())
886 {
887 wxFAIL_MSG( _T("this cell doesn't have numeric value") );
888 return;
889 }
890 }
891
892#if wxUSE_SPINCTRL
893 if ( HasRange() )
894 {
895 Spin()->SetValue((int)m_valueOld);
896 Spin()->SetFocus();
897 }
898 else
899#endif
900 {
901 DoBeginEdit(GetString());
902 }
903}
904
905bool wxGridCellNumberEditor::EndEdit(int row, int col,
906 wxGrid* grid)
907{
908 bool changed;
909 long value = 0;
910 wxString text;
911
912#if wxUSE_SPINCTRL
913 if ( HasRange() )
914 {
915 value = Spin()->GetValue();
916 changed = value != m_valueOld;
917 if (changed)
918 text = wxString::Format(wxT("%ld"), value);
919 }
920 else
921#endif
922 {
923 text = Text()->GetValue();
924 changed = (text.empty() || text.ToLong(&value)) && (value != m_valueOld);
925 }
926
927 if ( changed )
928 {
929 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
930 grid->GetTable()->SetValueAsLong(row, col, value);
931 else
932 grid->GetTable()->SetValue(row, col, text);
933 }
934
935 return changed;
936}
937
938void wxGridCellNumberEditor::Reset()
939{
940#if wxUSE_SPINCTRL
941 if ( HasRange() )
942 {
943 Spin()->SetValue((int)m_valueOld);
944 }
945 else
946#endif
947 {
948 DoReset(GetString());
949 }
950}
951
952bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent& event)
953{
954 if ( wxGridCellEditor::IsAcceptedKey(event) )
955 {
956 int keycode = event.GetKeyCode();
957 if ( (keycode < 128) &&
958 (wxIsdigit(keycode) || keycode == '+' || keycode == '-'))
959 {
960 return true;
961 }
962 }
963
964 return false;
965}
966
967void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event)
968{
969 int keycode = event.GetKeyCode();
970 if ( !HasRange() )
971 {
972 if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-')
973 {
974 wxGridCellTextEditor::StartingKey(event);
975
976 // skip Skip() below
977 return;
978 }
979 }
980#if wxUSE_SPINCTRL
981 else
982 {
983 if ( wxIsdigit(keycode) )
984 {
985 wxSpinCtrl* spin = (wxSpinCtrl*)m_control;
986 spin->SetValue(keycode - '0');
987 spin->SetSelection(1,1);
988 return;
989 }
990 }
991#endif
992 event.Skip();
993}
994
995void wxGridCellNumberEditor::SetParameters(const wxString& params)
996{
997 if ( !params )
998 {
999 // reset to default
1000 m_min =
1001 m_max = -1;
1002 }
1003 else
1004 {
1005 long tmp;
1006 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
1007 {
1008 m_min = (int)tmp;
1009
1010 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
1011 {
1012 m_max = (int)tmp;
1013
1014 // skip the error message below
1015 return;
1016 }
1017 }
1018
1019 wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str());
1020 }
1021}
1022
1023// return the value in the spin control if it is there (the text control otherwise)
1024wxString wxGridCellNumberEditor::GetValue() const
1025{
1026 wxString s;
1027
1028#if wxUSE_SPINCTRL
1029 if( HasRange() )
1030 {
1031 long value = Spin()->GetValue();
1032 s.Printf(wxT("%ld"), value);
1033 }
1034 else
1035#endif
1036 {
1037 s = Text()->GetValue();
1038 }
1039
1040 return s;
1041}
1042
1043// ----------------------------------------------------------------------------
1044// wxGridCellFloatEditor
1045// ----------------------------------------------------------------------------
1046
1047wxGridCellFloatEditor::wxGridCellFloatEditor(int width, int precision)
1048{
1049 m_width = width;
1050 m_precision = precision;
1051}
1052
1053void wxGridCellFloatEditor::Create(wxWindow* parent,
1054 wxWindowID id,
1055 wxEvtHandler* evtHandler)
1056{
1057 wxGridCellTextEditor::Create(parent, id, evtHandler);
1058
1059#if wxUSE_VALIDATORS
1060 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
1061#endif // wxUSE_VALIDATORS
1062}
1063
1064void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid)
1065{
1066 // first get the value
1067 wxGridTableBase *table = grid->GetTable();
1068 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
1069 {
1070 m_valueOld = table->GetValueAsDouble(row, col);
1071 }
1072 else
1073 {
1074 m_valueOld = 0.0;
1075 wxString sValue = table->GetValue(row, col);
1076 if (! sValue.ToDouble(&m_valueOld) && ! sValue.empty())
1077 {
1078 wxFAIL_MSG( _T("this cell doesn't have float value") );
1079 return;
1080 }
1081 }
1082
1083 DoBeginEdit(GetString());
1084}
1085
1086bool wxGridCellFloatEditor::EndEdit(int row, int col,
1087 wxGrid* grid)
1088{
1089 double value = 0.0;
1090 wxString text(Text()->GetValue());
1091
1092 if ( (text.empty() || text.ToDouble(&value)) && (value != m_valueOld) )
1093 {
1094 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT))
1095 grid->GetTable()->SetValueAsDouble(row, col, value);
1096 else
1097 grid->GetTable()->SetValue(row, col, text);
1098
1099 return true;
1100 }
1101 return false;
1102}
1103
1104void wxGridCellFloatEditor::Reset()
1105{
1106 DoReset(GetString());
1107}
1108
1109void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
1110{
1111 int keycode = event.GetKeyCode();
1112 char tmpbuf[2];
1113 tmpbuf[0] = (char) keycode;
1114 tmpbuf[1] = '\0';
1115 wxString strbuf(tmpbuf, *wxConvCurrent);
1116#if wxUSE_INTL
1117 bool is_decimal_point = ( strbuf ==
1118 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER) );
1119#else
1120 bool is_decimal_point = ( strbuf == _T(".") );
1121#endif
1122 if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-'
1123 || is_decimal_point )
1124 {
1125 wxGridCellTextEditor::StartingKey(event);
1126
1127 // skip Skip() below
1128 return;
1129 }
1130
1131 event.Skip();
1132}
1133
1134void wxGridCellFloatEditor::SetParameters(const wxString& params)
1135{
1136 if ( !params )
1137 {
1138 // reset to default
1139 m_width =
1140 m_precision = -1;
1141 }
1142 else
1143 {
1144 long tmp;
1145 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
1146 {
1147 m_width = (int)tmp;
1148
1149 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
1150 {
1151 m_precision = (int)tmp;
1152
1153 // skip the error message below
1154 return;
1155 }
1156 }
1157
1158 wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params.c_str());
1159 }
1160}
1161
1162wxString wxGridCellFloatEditor::GetString() const
1163{
1164 wxString fmt;
1165 if ( m_width == -1 )
1166 {
1167 // default width/precision
1168 fmt = _T("%f");
1169 }
1170 else if ( m_precision == -1 )
1171 {
1172 // default precision
1173 fmt.Printf(_T("%%%d.f"), m_width);
1174 }
1175 else
1176 {
1177 fmt.Printf(_T("%%%d.%df"), m_width, m_precision);
1178 }
1179
1180 return wxString::Format(fmt, m_valueOld);
1181}
1182
1183bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event)
1184{
1185 if ( wxGridCellEditor::IsAcceptedKey(event) )
1186 {
1187 int keycode = event.GetKeyCode();
1188 printf("%d\n", keycode);
1189 // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
1190 char tmpbuf[2];
1191 tmpbuf[0] = (char) keycode;
1192 tmpbuf[1] = '\0';
1193 wxString strbuf(tmpbuf, *wxConvCurrent);
1194#if wxUSE_INTL
1195 bool is_decimal_point =
1196 ( strbuf == wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT,
1197 wxLOCALE_CAT_NUMBER) );
1198#else
1199 bool is_decimal_point = ( strbuf == _T(".") );
1200#endif
1201 if ( (keycode < 128) &&
1202 (wxIsdigit(keycode) || tolower(keycode) == 'e' ||
1203 is_decimal_point || keycode == '+' || keycode == '-') )
1204 return true;
1205 }
1206
1207 return false;
1208}
1209
1210#endif // wxUSE_TEXTCTRL
1211
1212#if wxUSE_CHECKBOX
1213
1214// ----------------------------------------------------------------------------
1215// wxGridCellBoolEditor
1216// ----------------------------------------------------------------------------
1217
1218void wxGridCellBoolEditor::Create(wxWindow* parent,
1219 wxWindowID id,
1220 wxEvtHandler* evtHandler)
1221{
1222 m_control = new wxCheckBox(parent, id, wxEmptyString,
1223 wxDefaultPosition, wxDefaultSize,
1224 wxNO_BORDER);
1225
1226 wxGridCellEditor::Create(parent, id, evtHandler);
1227}
1228
1229void wxGridCellBoolEditor::SetSize(const wxRect& r)
1230{
1231 bool resize = false;
1232 wxSize size = m_control->GetSize();
1233 wxCoord minSize = wxMin(r.width, r.height);
1234
1235 // check if the checkbox is not too big/small for this cell
1236 wxSize sizeBest = m_control->GetBestSize();
1237 if ( !(size == sizeBest) )
1238 {
1239 // reset to default size if it had been made smaller
1240 size = sizeBest;
1241
1242 resize = true;
1243 }
1244
1245 if ( size.x >= minSize || size.y >= minSize )
1246 {
1247 // leave 1 pixel margin
1248 size.x = size.y = minSize - 2;
1249
1250 resize = true;
1251 }
1252
1253 if ( resize )
1254 {
1255 m_control->SetSize(size);
1256 }
1257
1258 // position it in the centre of the rectangle (TODO: support alignment?)
1259
1260#if defined(__WXGTK__) || defined (__WXMOTIF__)
1261 // the checkbox without label still has some space to the right in wxGTK,
1262 // so shift it to the right
1263 size.x -= 8;
1264#elif defined(__WXMSW__)
1265 // here too, but in other way
1266 size.x += 1;
1267 size.y -= 2;
1268#endif
1269
1270 int hAlign = wxALIGN_CENTRE;
1271 int vAlign = wxALIGN_CENTRE;
1272 if (GetCellAttr())
1273 GetCellAttr()->GetAlignment(& hAlign, & vAlign);
1274
1275 int x = 0, y = 0;
1276 if (hAlign == wxALIGN_LEFT)
1277 {
1278 x = r.x + 2;
1279#ifdef __WXMSW__
1280 x += 2;
1281#endif
1282 y = r.y + r.height/2 - size.y/2;
1283 }
1284 else if (hAlign == wxALIGN_RIGHT)
1285 {
1286 x = r.x + r.width - size.x - 2;
1287 y = r.y + r.height/2 - size.y/2;
1288 }
1289 else if (hAlign == wxALIGN_CENTRE)
1290 {
1291 x = r.x + r.width/2 - size.x/2;
1292 y = r.y + r.height/2 - size.y/2;
1293 }
1294
1295 m_control->Move(x, y);
1296}
1297
1298void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
1299{
1300 m_control->Show(show);
1301
1302 if ( show )
1303 {
1304 wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
1305 CBox()->SetBackgroundColour(colBg);
1306 }
1307}
1308
1309void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid)
1310{
1311 wxASSERT_MSG(m_control,
1312 wxT("The wxGridCellEditor must be Created first!"));
1313
1314 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
1315 m_startValue = grid->GetTable()->GetValueAsBool(row, col);
1316 else
1317 {
1318 wxString cellval( grid->GetTable()->GetValue(row, col) );
1319 m_startValue = !( !cellval || (cellval == wxT("0")) );
1320 }
1321 CBox()->SetValue(m_startValue);
1322 CBox()->SetFocus();
1323}
1324
1325bool wxGridCellBoolEditor::EndEdit(int row, int col,
1326 wxGrid* grid)
1327{
1328 wxASSERT_MSG(m_control,
1329 wxT("The wxGridCellEditor must be Created first!"));
1330
1331 bool changed = false;
1332 bool value = CBox()->GetValue();
1333 if ( value != m_startValue )
1334 changed = true;
1335
1336 if ( changed )
1337 {
1338 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
1339 grid->GetTable()->SetValueAsBool(row, col, value);
1340 else
1341 grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString);
1342 }
1343
1344 return changed;
1345}
1346
1347void wxGridCellBoolEditor::Reset()
1348{
1349 wxASSERT_MSG(m_control,
1350 wxT("The wxGridCellEditor must be Created first!"));
1351
1352 CBox()->SetValue(m_startValue);
1353}
1354
1355void wxGridCellBoolEditor::StartingClick()
1356{
1357 CBox()->SetValue(!CBox()->GetValue());
1358}
1359
1360bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent& event)
1361{
1362 if ( wxGridCellEditor::IsAcceptedKey(event) )
1363 {
1364 int keycode = event.GetKeyCode();
1365 switch ( keycode )
1366 {
1367 case WXK_SPACE:
1368 case '+':
1369 case '-':
1370 return true;
1371 }
1372 }
1373
1374 return false;
1375}
1376
1377void wxGridCellBoolEditor::StartingKey(wxKeyEvent& event)
1378{
1379 int keycode = event.GetKeyCode();
1380 switch ( keycode )
1381 {
1382 case WXK_SPACE:
1383 CBox()->SetValue(!CBox()->GetValue());
1384 break;
1385
1386 case '+':
1387 CBox()->SetValue(true);
1388 break;
1389
1390 case '-':
1391 CBox()->SetValue(false);
1392 break;
1393 }
1394}
1395
1396
1397// return the value as "1" for true and the empty string for false
1398wxString wxGridCellBoolEditor::GetValue() const
1399{
1400 bool bSet = CBox()->GetValue();
1401 return bSet ? _T("1") : wxEmptyString;
1402}
1403
1404#endif // wxUSE_CHECKBOX
1405
1406#if wxUSE_COMBOBOX
1407
1408// ----------------------------------------------------------------------------
1409// wxGridCellChoiceEditor
1410// ----------------------------------------------------------------------------
1411
1412wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString& choices,
1413 bool allowOthers)
1414 : m_choices(choices),
1415 m_allowOthers(allowOthers) { }
1416
1417wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count,
1418 const wxString choices[],
1419 bool allowOthers)
1420 : m_allowOthers(allowOthers)
1421{
1422 if ( count )
1423 {
1424 m_choices.Alloc(count);
1425 for ( size_t n = 0; n < count; n++ )
1426 {
1427 m_choices.Add(choices[n]);
1428 }
1429 }
1430}
1431
1432wxGridCellEditor *wxGridCellChoiceEditor::Clone() const
1433{
1434 wxGridCellChoiceEditor *editor = new wxGridCellChoiceEditor;
1435 editor->m_allowOthers = m_allowOthers;
1436 editor->m_choices = m_choices;
1437
1438 return editor;
1439}
1440
1441void wxGridCellChoiceEditor::Create(wxWindow* parent,
1442 wxWindowID id,
1443 wxEvtHandler* evtHandler)
1444{
1445 m_control = new wxComboBox(parent, id, wxEmptyString,
1446 wxDefaultPosition, wxDefaultSize,
1447 m_choices,
1448 m_allowOthers ? 0 : wxCB_READONLY);
1449
1450 wxGridCellEditor::Create(parent, id, evtHandler);
1451}
1452
1453void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
1454 wxGridCellAttr * attr)
1455{
1456 // as we fill the entire client area, don't do anything here to minimize
1457 // flicker
1458
1459 // TODO: It doesn't actually fill the client area since the height of a
1460 // combo always defaults to the standard... Until someone has time to
1461 // figure out the right rectangle to paint, just do it the normal way...
1462 wxGridCellEditor::PaintBackground(rectCell, attr);
1463}
1464
1465void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
1466{
1467 wxASSERT_MSG(m_control,
1468 wxT("The wxGridCellEditor must be Created first!"));
1469
1470 wxGridCellEditorEvtHandler* evtHandler = NULL;
1471 if (m_control)
1472 evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler);
1473
1474 // Don't immediately end if we get a kill focus event within BeginEdit
1475 if (evtHandler)
1476 evtHandler->SetInSetFocus(true);
1477
1478 m_startValue = grid->GetTable()->GetValue(row, col);
1479
1480 if (m_allowOthers)
1481 Combo()->SetValue(m_startValue);
1482 else
1483 {
1484 // find the right position, or default to the first if not found
1485 int pos = Combo()->FindString(m_startValue);
1486 if (pos == wxNOT_FOUND)
1487 pos = 0;
1488 Combo()->SetSelection(pos);
1489 }
1490 Combo()->SetInsertionPointEnd();
1491 Combo()->SetFocus();
1492
1493 if (evtHandler)
1494 evtHandler->SetInSetFocus(false);
1495}
1496
1497bool wxGridCellChoiceEditor::EndEdit(int row, int col,
1498 wxGrid* grid)
1499{
1500 wxString value = Combo()->GetValue();
1501 if ( value == m_startValue )
1502 return false;
1503
1504 grid->GetTable()->SetValue(row, col, value);
1505
1506 return true;
1507}
1508
1509void wxGridCellChoiceEditor::Reset()
1510{
1511 Combo()->SetValue(m_startValue);
1512 Combo()->SetInsertionPointEnd();
1513}
1514
1515void wxGridCellChoiceEditor::SetParameters(const wxString& params)
1516{
1517 if ( !params )
1518 {
1519 // what can we do?
1520 return;
1521 }
1522
1523 m_choices.Empty();
1524
1525 wxStringTokenizer tk(params, _T(','));
1526 while ( tk.HasMoreTokens() )
1527 {
1528 m_choices.Add(tk.GetNextToken());
1529 }
1530}
1531
1532// return the value in the text control
1533wxString wxGridCellChoiceEditor::GetValue() const
1534{
1535 return Combo()->GetValue();
1536}
1537
1538#endif // wxUSE_COMBOBOX
1539
1540// ----------------------------------------------------------------------------
1541// wxGridCellEditorEvtHandler
1542// ----------------------------------------------------------------------------
1543
1544void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent& event)
1545{
1546 // Don't disable the cell if we're just starting to edit it
1547 if (m_inSetFocus)
1548 return;
1549
1550 // accept changes
1551 m_grid->DisableCellEditControl();
1552
1553 event.Skip();
1554}
1555
1556void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
1557{
1558 switch ( event.GetKeyCode() )
1559 {
1560 case WXK_ESCAPE:
1561 m_editor->Reset();
1562 m_grid->DisableCellEditControl();
1563 break;
1564
1565 case WXK_TAB:
1566 m_grid->GetEventHandler()->ProcessEvent( event );
1567 break;
1568
1569 case WXK_RETURN:
1570 case WXK_NUMPAD_ENTER:
1571 if (!m_grid->GetEventHandler()->ProcessEvent(event))
1572 m_editor->HandleReturn(event);
1573 break;
1574
1575 default:
1576 event.Skip();
1577 }
1578}
1579
1580void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event)
1581{
1582 switch ( event.GetKeyCode() )
1583 {
1584 case WXK_ESCAPE:
1585 case WXK_TAB:
1586 case WXK_RETURN:
1587 case WXK_NUMPAD_ENTER:
1588 break;
1589
1590 default:
1591 event.Skip();
1592 }
1593}
1594
1595// ----------------------------------------------------------------------------
1596// wxGridCellWorker is an (almost) empty common base class for
1597// wxGridCellRenderer and wxGridCellEditor managing ref counting
1598// ----------------------------------------------------------------------------
1599
1600void wxGridCellWorker::SetParameters(const wxString& WXUNUSED(params))
1601{
1602 // nothing to do
1603}
1604
1605wxGridCellWorker::~wxGridCellWorker()
1606{
1607}
1608
1609// ============================================================================
1610// renderer classes
1611// ============================================================================
1612
1613// ----------------------------------------------------------------------------
1614// wxGridCellRenderer
1615// ----------------------------------------------------------------------------
1616
1617void wxGridCellRenderer::Draw(wxGrid& grid,
1618 wxGridCellAttr& attr,
1619 wxDC& dc,
1620 const wxRect& rect,
1621 int WXUNUSED(row), int WXUNUSED(col),
1622 bool isSelected)
1623{
1624 dc.SetBackgroundMode( wxSOLID );
1625
1626 // grey out fields if the grid is disabled
1627 if( grid.IsEnabled() )
1628 {
1629 if ( isSelected )
1630 {
1631 dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) );
1632 }
1633 else
1634 {
1635 dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) );
1636 }
1637 }
1638 else
1639 {
1640 dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxSOLID));
1641 }
1642
1643 dc.SetPen( *wxTRANSPARENT_PEN );
1644 dc.DrawRectangle(rect);
1645}
1646
1647// ----------------------------------------------------------------------------
1648// wxGridCellStringRenderer
1649// ----------------------------------------------------------------------------
1650
1651void wxGridCellStringRenderer::SetTextColoursAndFont(wxGrid& grid,
1652 wxGridCellAttr& attr,
1653 wxDC& dc,
1654 bool isSelected)
1655{
1656 dc.SetBackgroundMode( wxTRANSPARENT );
1657
1658 // TODO some special colours for attr.IsReadOnly() case?
1659
1660 // different coloured text when the grid is disabled
1661 if( grid.IsEnabled() )
1662 {
1663 if ( isSelected )
1664 {
1665 dc.SetTextBackground( grid.GetSelectionBackground() );
1666 dc.SetTextForeground( grid.GetSelectionForeground() );
1667 }
1668 else
1669 {
1670 dc.SetTextBackground( attr.GetBackgroundColour() );
1671 dc.SetTextForeground( attr.GetTextColour() );
1672 }
1673 }
1674 else
1675 {
1676 dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
1677 dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
1678 }
1679
1680 dc.SetFont( attr.GetFont() );
1681}
1682
1683wxSize wxGridCellStringRenderer::DoGetBestSize(wxGridCellAttr& attr,
1684 wxDC& dc,
1685 const wxString& text)
1686{
1687 wxCoord x = 0, y = 0, max_x = 0;
1688 dc.SetFont(attr.GetFont());
1689 wxStringTokenizer tk(text, _T('\n'));
1690 while ( tk.HasMoreTokens() )
1691 {
1692 dc.GetTextExtent(tk.GetNextToken(), &x, &y);
1693 max_x = wxMax(max_x, x);
1694 }
1695
1696 y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines.
1697
1698 return wxSize(max_x, y);
1699}
1700
1701wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
1702 wxGridCellAttr& attr,
1703 wxDC& dc,
1704 int row, int col)
1705{
1706 return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
1707}
1708
1709void wxGridCellStringRenderer::Draw(wxGrid& grid,
1710 wxGridCellAttr& attr,
1711 wxDC& dc,
1712 const wxRect& rectCell,
1713 int row, int col,
1714 bool isSelected)
1715{
1716 wxRect rect = rectCell;
1717 rect.Inflate(-1);
1718
1719 // erase only this cells background, overflow cells should have been erased
1720 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1721
1722 int hAlign, vAlign;
1723 attr.GetAlignment(&hAlign, &vAlign);
1724
1725 int overflowCols = 0;
1726
1727 if (attr.GetOverflow())
1728 {
1729 int cols = grid.GetNumberCols();
1730 int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth();
1731 int cell_rows, cell_cols;
1732 attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <=0
1733 if ((best_width > rectCell.width) && (col < cols) && grid.GetTable())
1734 {
1735 int i, c_cols, c_rows;
1736 for (i = col+cell_cols; i < cols; i++)
1737 {
1738 bool is_empty = true;
1739 for (int j=row; j<row+cell_rows; j++)
1740 {
1741 // check w/ anchor cell for multicell block
1742 grid.GetCellSize(j, i, &c_rows, &c_cols);
1743 if (c_rows > 0) c_rows = 0;
1744 if (!grid.GetTable()->IsEmptyCell(j+c_rows, i))
1745 {
1746 is_empty = false;
1747 break;
1748 }
1749 }
1750 if (is_empty)
1751 rect.width += grid.GetColSize(i);
1752 else
1753 {
1754 i--;
1755 break;
1756 }
1757 if (rect.width >= best_width) break;
1758 }
1759 overflowCols = i - col - cell_cols + 1;
1760 if (overflowCols >= cols) overflowCols = cols - 1;
1761 }
1762
1763 if (overflowCols > 0) // redraw overflow cells w/ proper hilight
1764 {
1765 hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned
1766 wxRect clip = rect;
1767 clip.x += rectCell.width;
1768 // draw each overflow cell individually
1769 int col_end = col+cell_cols+overflowCols;
1770 if (col_end >= grid.GetNumberCols())
1771 col_end = grid.GetNumberCols() - 1;
1772 for (int i = col+cell_cols; i <= col_end; i++)
1773 {
1774 clip.width = grid.GetColSize(i) - 1;
1775 dc.DestroyClippingRegion();
1776 dc.SetClippingRegion(clip);
1777
1778 SetTextColoursAndFont(grid, attr, dc,
1779 grid.IsInSelection(row,i));
1780
1781 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
1782 rect, hAlign, vAlign);
1783 clip.x += grid.GetColSize(i) - 1;
1784 }
1785
1786 rect = rectCell;
1787 rect.Inflate(-1);
1788 rect.width++;
1789 dc.DestroyClippingRegion();
1790 }
1791 }
1792
1793 // now we only have to draw the text
1794 SetTextColoursAndFont(grid, attr, dc, isSelected);
1795
1796 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
1797 rect, hAlign, vAlign);
1798}
1799
1800// ----------------------------------------------------------------------------
1801// wxGridCellNumberRenderer
1802// ----------------------------------------------------------------------------
1803
1804wxString wxGridCellNumberRenderer::GetString(wxGrid& grid, int row, int col)
1805{
1806 wxGridTableBase *table = grid.GetTable();
1807 wxString text;
1808 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
1809 {
1810 text.Printf(_T("%ld"), table->GetValueAsLong(row, col));
1811 }
1812 else
1813 {
1814 text = table->GetValue(row, col);
1815 }
1816
1817 return text;
1818}
1819
1820void wxGridCellNumberRenderer::Draw(wxGrid& grid,
1821 wxGridCellAttr& attr,
1822 wxDC& dc,
1823 const wxRect& rectCell,
1824 int row, int col,
1825 bool isSelected)
1826{
1827 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1828
1829 SetTextColoursAndFont(grid, attr, dc, isSelected);
1830
1831 // draw the text right aligned by default
1832 int hAlign, vAlign;
1833 attr.GetAlignment(&hAlign, &vAlign);
1834 hAlign = wxALIGN_RIGHT;
1835
1836 wxRect rect = rectCell;
1837 rect.Inflate(-1);
1838
1839 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
1840}
1841
1842wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
1843 wxGridCellAttr& attr,
1844 wxDC& dc,
1845 int row, int col)
1846{
1847 return DoGetBestSize(attr, dc, GetString(grid, row, col));
1848}
1849
1850// ----------------------------------------------------------------------------
1851// wxGridCellFloatRenderer
1852// ----------------------------------------------------------------------------
1853
1854wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision)
1855{
1856 SetWidth(width);
1857 SetPrecision(precision);
1858}
1859
1860wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
1861{
1862 wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
1863 renderer->m_width = m_width;
1864 renderer->m_precision = m_precision;
1865 renderer->m_format = m_format;
1866
1867 return renderer;
1868}
1869
1870wxString wxGridCellFloatRenderer::GetString(wxGrid& grid, int row, int col)
1871{
1872 wxGridTableBase *table = grid.GetTable();
1873
1874 bool hasDouble;
1875 double val;
1876 wxString text;
1877 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
1878 {
1879 val = table->GetValueAsDouble(row, col);
1880 hasDouble = true;
1881 }
1882 else
1883 {
1884 text = table->GetValue(row, col);
1885 hasDouble = text.ToDouble(&val);
1886 }
1887
1888 if ( hasDouble )
1889 {
1890 if ( !m_format )
1891 {
1892 if ( m_width == -1 )
1893 {
1894 if ( m_precision == -1 )
1895 {
1896 // default width/precision
1897 m_format = _T("%f");
1898 }
1899 else
1900 {
1901 m_format.Printf(_T("%%.%df"), m_precision);
1902 }
1903 }
1904 else if ( m_precision == -1 )
1905 {
1906 // default precision
1907 m_format.Printf(_T("%%%d.f"), m_width);
1908 }
1909 else
1910 {
1911 m_format.Printf(_T("%%%d.%df"), m_width, m_precision);
1912 }
1913 }
1914
1915 text.Printf(m_format, val);
1916
1917 }
1918 //else: text already contains the string
1919
1920 return text;
1921}
1922
1923void wxGridCellFloatRenderer::Draw(wxGrid& grid,
1924 wxGridCellAttr& attr,
1925 wxDC& dc,
1926 const wxRect& rectCell,
1927 int row, int col,
1928 bool isSelected)
1929{
1930 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1931
1932 SetTextColoursAndFont(grid, attr, dc, isSelected);
1933
1934 // draw the text right aligned by default
1935 int hAlign, vAlign;
1936 attr.GetAlignment(&hAlign, &vAlign);
1937 hAlign = wxALIGN_RIGHT;
1938
1939 wxRect rect = rectCell;
1940 rect.Inflate(-1);
1941
1942 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
1943}
1944
1945wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
1946 wxGridCellAttr& attr,
1947 wxDC& dc,
1948 int row, int col)
1949{
1950 return DoGetBestSize(attr, dc, GetString(grid, row, col));
1951}
1952
1953void wxGridCellFloatRenderer::SetParameters(const wxString& params)
1954{
1955 if ( !params )
1956 {
1957 // reset to defaults
1958 SetWidth(-1);
1959 SetPrecision(-1);
1960 }
1961 else
1962 {
1963 wxString tmp = params.BeforeFirst(_T(','));
1964 if ( !tmp.empty() )
1965 {
1966 long width;
1967 if ( tmp.ToLong(&width) )
1968 {
1969 SetWidth((int)width);
1970 }
1971 else
1972 {
1973 wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
1974 }
1975 }
1976 tmp = params.AfterFirst(_T(','));
1977 if ( !tmp.empty() )
1978 {
1979 long precision;
1980 if ( tmp.ToLong(&precision) )
1981 {
1982 SetPrecision((int)precision);
1983 }
1984 else
1985 {
1986 wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
1987 }
1988 }
1989 }
1990}
1991
1992
1993// ----------------------------------------------------------------------------
1994// wxGridCellBoolRenderer
1995// ----------------------------------------------------------------------------
1996
1997wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
1998
1999// FIXME these checkbox size calculations are really ugly...
2000
2001// between checkmark and box
2002static const wxCoord wxGRID_CHECKMARK_MARGIN = 2;
2003
2004wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
2005 wxGridCellAttr& WXUNUSED(attr),
2006 wxDC& WXUNUSED(dc),
2007 int WXUNUSED(row),
2008 int WXUNUSED(col))
2009{
2010 // compute it only once (no locks for MT safeness in GUI thread...)
2011 if ( !ms_sizeCheckMark.x )
2012 {
2013 // get checkbox size
2014 wxCheckBox *checkbox = new wxCheckBox(&grid, wxID_ANY, wxEmptyString);
2015 wxSize size = checkbox->GetBestSize();
2016 wxCoord checkSize = size.y + 2*wxGRID_CHECKMARK_MARGIN;
2017
2018 // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
2019#if defined(__WXGTK__) || defined(__WXMOTIF__)
2020 checkSize -= size.y / 2;
2021#endif
2022
2023 delete checkbox;
2024
2025 ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize;
2026 }
2027
2028 return ms_sizeCheckMark;
2029}
2030
2031void wxGridCellBoolRenderer::Draw(wxGrid& grid,
2032 wxGridCellAttr& attr,
2033 wxDC& dc,
2034 const wxRect& rect,
2035 int row, int col,
2036 bool isSelected)
2037{
2038 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
2039
2040 // draw a check mark in the centre (ignoring alignment - TODO)
2041 wxSize size = GetBestSize(grid, attr, dc, row, col);
2042
2043 // don't draw outside the cell
2044 wxCoord minSize = wxMin(rect.width, rect.height);
2045 if ( size.x >= minSize || size.y >= minSize )
2046 {
2047 // and even leave (at least) 1 pixel margin
2048 size.x = size.y = minSize - 2;
2049 }
2050
2051 // draw a border around checkmark
2052 int vAlign, hAlign;
2053 attr.GetAlignment(& hAlign, &vAlign);
2054
2055 wxRect rectBorder;
2056 if (hAlign == wxALIGN_CENTRE)
2057 {
2058 rectBorder.x = rect.x + rect.width/2 - size.x/2;
2059 rectBorder.y = rect.y + rect.height/2 - size.y/2;
2060 rectBorder.width = size.x;
2061 rectBorder.height = size.y;
2062 }
2063 else if (hAlign == wxALIGN_LEFT)
2064 {
2065 rectBorder.x = rect.x + 2;
2066 rectBorder.y = rect.y + rect.height/2 - size.y/2;
2067 rectBorder.width = size.x;
2068 rectBorder.height = size.y;
2069 }
2070 else if (hAlign == wxALIGN_RIGHT)
2071 {
2072 rectBorder.x = rect.x + rect.width - size.x - 2;
2073 rectBorder.y = rect.y + rect.height/2 - size.y/2;
2074 rectBorder.width = size.x;
2075 rectBorder.height = size.y;
2076 }
2077
2078 bool value;
2079 if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
2080 value = grid.GetTable()->GetValueAsBool(row, col);
2081 else
2082 {
2083 wxString cellval( grid.GetTable()->GetValue(row, col) );
2084 value = !( !cellval || (cellval == wxT("0")) );
2085 }
2086
2087 if ( value )
2088 {
2089 wxRect rectMark = rectBorder;
2090#ifdef __WXMSW__
2091 // MSW DrawCheckMark() is weird (and should probably be changed...)
2092 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN/2);
2093 rectMark.x++;
2094 rectMark.y++;
2095#else // !MSW
2096 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN);
2097#endif // MSW/!MSW
2098
2099 dc.SetTextForeground(attr.GetTextColour());
2100 dc.DrawCheckMark(rectMark);
2101 }
2102
2103 dc.SetBrush(*wxTRANSPARENT_BRUSH);
2104 dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID));
2105 dc.DrawRectangle(rectBorder);
2106}
2107
2108// ----------------------------------------------------------------------------
2109// wxGridCellAttr
2110// ----------------------------------------------------------------------------
2111
2112void wxGridCellAttr::Init(wxGridCellAttr *attrDefault)
2113{
2114 m_nRef = 1;
2115
2116 m_isReadOnly = Unset;
2117
2118 m_renderer = NULL;
2119 m_editor = NULL;
2120
2121 m_attrkind = wxGridCellAttr::Cell;
2122
2123 m_sizeRows = m_sizeCols = 1;
2124 m_overflow = UnsetOverflow;
2125
2126 SetDefAttr(attrDefault);
2127}
2128
2129wxGridCellAttr *wxGridCellAttr::Clone() const
2130{
2131 wxGridCellAttr *attr = new wxGridCellAttr(m_defGridAttr);
2132
2133 if ( HasTextColour() )
2134 attr->SetTextColour(GetTextColour());
2135 if ( HasBackgroundColour() )
2136 attr->SetBackgroundColour(GetBackgroundColour());
2137 if ( HasFont() )
2138 attr->SetFont(GetFont());
2139 if ( HasAlignment() )
2140 attr->SetAlignment(m_hAlign, m_vAlign);
2141
2142 attr->SetSize( m_sizeRows, m_sizeCols );
2143
2144 if ( m_renderer )
2145 {
2146 attr->SetRenderer(m_renderer);
2147 m_renderer->IncRef();
2148 }
2149 if ( m_editor )
2150 {
2151 attr->SetEditor(m_editor);
2152 m_editor->IncRef();
2153 }
2154
2155 if ( IsReadOnly() )
2156 attr->SetReadOnly();
2157
2158 attr->SetKind( m_attrkind );
2159
2160 return attr;
2161}
2162
2163void wxGridCellAttr::MergeWith(wxGridCellAttr *mergefrom)
2164{
2165 if ( !HasTextColour() && mergefrom->HasTextColour() )
2166 SetTextColour(mergefrom->GetTextColour());
2167 if ( !HasBackgroundColour() && mergefrom->HasBackgroundColour() )
2168 SetBackgroundColour(mergefrom->GetBackgroundColour());
2169 if ( !HasFont() && mergefrom->HasFont() )
2170 SetFont(mergefrom->GetFont());
2171 if ( !HasAlignment() && mergefrom->HasAlignment() ){
2172 int hAlign, vAlign;
2173 mergefrom->GetAlignment( &hAlign, &vAlign);
2174 SetAlignment(hAlign, vAlign);
2175 }
2176 if ( !HasSize() && mergefrom->HasSize() )
2177 mergefrom->GetSize( &m_sizeRows, &m_sizeCols );
2178
2179 // Directly access member functions as GetRender/Editor don't just return
2180 // m_renderer/m_editor
2181 //
2182 // Maybe add support for merge of Render and Editor?
2183 if (!HasRenderer() && mergefrom->HasRenderer() )
2184 {
2185 m_renderer = mergefrom->m_renderer;
2186 m_renderer->IncRef();
2187 }
2188 if ( !HasEditor() && mergefrom->HasEditor() )
2189 {
2190 m_editor = mergefrom->m_editor;
2191 m_editor->IncRef();
2192 }
2193 if ( !HasReadWriteMode() && mergefrom->HasReadWriteMode() )
2194 SetReadOnly(mergefrom->IsReadOnly());
2195
2196 if (!HasOverflowMode() && mergefrom->HasOverflowMode() )
2197 SetOverflow(mergefrom->GetOverflow());
2198
2199 SetDefAttr(mergefrom->m_defGridAttr);
2200}
2201
2202void wxGridCellAttr::SetSize(int num_rows, int num_cols)
2203{
2204 // The size of a cell is normally 1,1
2205
2206 // If this cell is larger (2,2) then this is the top left cell
2207 // the other cells that will be covered (lower right cells) must be
2208 // set to negative or zero values such that
2209 // row + num_rows of the covered cell points to the larger cell (this cell)
2210 // same goes for the col + num_cols.
2211
2212 // Size of 0,0 is NOT valid, neither is <=0 and any positive value
2213
2214 wxASSERT_MSG( (!((num_rows>0)&&(num_cols<=0)) ||
2215 !((num_rows<=0)&&(num_cols>0)) ||
2216 !((num_rows==0)&&(num_cols==0))),
2217 wxT("wxGridCellAttr::SetSize only takes two postive values or negative/zero values"));
2218
2219 m_sizeRows = num_rows;
2220 m_sizeCols = num_cols;
2221}
2222
2223const wxColour& wxGridCellAttr::GetTextColour() const
2224{
2225 if (HasTextColour())
2226 {
2227 return m_colText;
2228 }
2229 else if (m_defGridAttr && m_defGridAttr != this)
2230 {
2231 return m_defGridAttr->GetTextColour();
2232 }
2233 else
2234 {
2235 wxFAIL_MSG(wxT("Missing default cell attribute"));
2236 return wxNullColour;
2237 }
2238}
2239
2240
2241const wxColour& wxGridCellAttr::GetBackgroundColour() const
2242{
2243 if (HasBackgroundColour())
2244 return m_colBack;
2245 else if (m_defGridAttr && m_defGridAttr != this)
2246 return m_defGridAttr->GetBackgroundColour();
2247 else
2248 {
2249 wxFAIL_MSG(wxT("Missing default cell attribute"));
2250 return wxNullColour;
2251 }
2252}
2253
2254
2255const wxFont& wxGridCellAttr::GetFont() const
2256{
2257 if (HasFont())
2258 return m_font;
2259 else if (m_defGridAttr && m_defGridAttr != this)
2260 return m_defGridAttr->GetFont();
2261 else
2262 {
2263 wxFAIL_MSG(wxT("Missing default cell attribute"));
2264 return wxNullFont;
2265 }
2266}
2267
2268
2269void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
2270{
2271 if (HasAlignment())
2272 {
2273 if ( hAlign ) *hAlign = m_hAlign;
2274 if ( vAlign ) *vAlign = m_vAlign;
2275 }
2276 else if (m_defGridAttr && m_defGridAttr != this)
2277 m_defGridAttr->GetAlignment(hAlign, vAlign);
2278 else
2279 {
2280 wxFAIL_MSG(wxT("Missing default cell attribute"));
2281 }
2282}
2283
2284void wxGridCellAttr::GetSize( int *num_rows, int *num_cols ) const
2285{
2286 if ( num_rows ) *num_rows = m_sizeRows;
2287 if ( num_cols ) *num_cols = m_sizeCols;
2288}
2289
2290// GetRenderer and GetEditor use a slightly different decision path about
2291// which attribute to use. If a non-default attr object has one then it is
2292// used, otherwise the default editor or renderer is fetched from the grid and
2293// used. It should be the default for the data type of the cell. If it is
2294// NULL (because the table has a type that the grid does not have in its
2295// registry,) then the grid's default editor or renderer is used.
2296
2297wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const
2298{
2299 wxGridCellRenderer *renderer;
2300
2301 if ( m_renderer && this != m_defGridAttr )
2302 {
2303 // use the cells renderer if it has one
2304 renderer = m_renderer;
2305 renderer->IncRef();
2306 }
2307 else // no non default cell renderer
2308 {
2309 // get default renderer for the data type
2310 if ( grid )
2311 {
2312 // GetDefaultRendererForCell() will do IncRef() for us
2313 renderer = grid->GetDefaultRendererForCell(row, col);
2314 }
2315 else
2316 {
2317 renderer = NULL;
2318 }
2319
2320 if ( !renderer )
2321 {
2322 if (m_defGridAttr && this != m_defGridAttr )
2323 {
2324 // if we still don't have one then use the grid default
2325 // (no need for IncRef() here neither)
2326 renderer = m_defGridAttr->GetRenderer(NULL, 0, 0);
2327 }
2328 else // default grid attr
2329 {
2330 // use m_renderer which we had decided not to use initially
2331 renderer = m_renderer;
2332 if ( renderer )
2333 renderer->IncRef();
2334 }
2335 }
2336 }
2337
2338 // we're supposed to always find something
2339 wxASSERT_MSG(renderer, wxT("Missing default cell renderer"));
2340
2341 return renderer;
2342}
2343
2344// same as above, except for s/renderer/editor/g
2345wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const
2346{
2347 wxGridCellEditor *editor;
2348
2349 if ( m_editor && this != m_defGridAttr )
2350 {
2351 // use the cells editor if it has one
2352 editor = m_editor;
2353 editor->IncRef();
2354 }
2355 else // no non default cell editor
2356 {
2357 // get default editor for the data type
2358 if ( grid )
2359 {
2360 // GetDefaultEditorForCell() will do IncRef() for us
2361 editor = grid->GetDefaultEditorForCell(row, col);
2362 }
2363 else
2364 {
2365 editor = NULL;
2366 }
2367
2368 if ( !editor )
2369 {
2370 if ( m_defGridAttr && this != m_defGridAttr )
2371 {
2372 // if we still don't have one then use the grid default
2373 // (no need for IncRef() here neither)
2374 editor = m_defGridAttr->GetEditor(NULL, 0, 0);
2375 }
2376 else // default grid attr
2377 {
2378 // use m_editor which we had decided not to use initially
2379 editor = m_editor;
2380 if ( editor )
2381 editor->IncRef();
2382 }
2383 }
2384 }
2385
2386 // we're supposed to always find something
2387 wxASSERT_MSG(editor, wxT("Missing default cell editor"));
2388
2389 return editor;
2390}
2391
2392// ----------------------------------------------------------------------------
2393// wxGridCellAttrData
2394// ----------------------------------------------------------------------------
2395
2396void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
2397{
2398 int n = FindIndex(row, col);
2399 if ( n == wxNOT_FOUND )
2400 {
2401 // add the attribute
2402 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
2403 }
2404 else
2405 {
2406 // free the old attribute
2407 m_attrs[(size_t)n].attr->DecRef();
2408
2409 if ( attr )
2410 {
2411 // change the attribute
2412 m_attrs[(size_t)n].attr = attr;
2413 }
2414 else
2415 {
2416 // remove this attribute
2417 m_attrs.RemoveAt((size_t)n);
2418 }
2419 }
2420}
2421
2422wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
2423{
2424 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2425
2426 int n = FindIndex(row, col);
2427 if ( n != wxNOT_FOUND )
2428 {
2429 attr = m_attrs[(size_t)n].attr;
2430 attr->IncRef();
2431 }
2432
2433 return attr;
2434}
2435
2436void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows )
2437{
2438 size_t count = m_attrs.GetCount();
2439 for ( size_t n = 0; n < count; n++ )
2440 {
2441 wxGridCellCoords& coords = m_attrs[n].coords;
2442 wxCoord row = coords.GetRow();
2443 if ((size_t)row >= pos)
2444 {
2445 if (numRows > 0)
2446 {
2447 // If rows inserted, include row counter where necessary
2448 coords.SetRow(row + numRows);
2449 }
2450 else if (numRows < 0)
2451 {
2452 // If rows deleted ...
2453 if ((size_t)row >= pos - numRows)
2454 {
2455 // ...either decrement row counter (if row still exists)...
2456 coords.SetRow(row + numRows);
2457 }
2458 else
2459 {
2460 // ...or remove the attribute
2461 // No need to DecRef the attribute itself since this is
2462 // done be wxGridCellWithAttr's destructor!
2463 m_attrs.RemoveAt(n);
2464 n--; count--;
2465 }
2466 }
2467 }
2468 }
2469}
2470
2471void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols )
2472{
2473 size_t count = m_attrs.GetCount();
2474 for ( size_t n = 0; n < count; n++ )
2475 {
2476 wxGridCellCoords& coords = m_attrs[n].coords;
2477 wxCoord col = coords.GetCol();
2478 if ( (size_t)col >= pos )
2479 {
2480 if ( numCols > 0 )
2481 {
2482 // If rows inserted, include row counter where necessary
2483 coords.SetCol(col + numCols);
2484 }
2485 else if (numCols < 0)
2486 {
2487 // If rows deleted ...
2488 if ((size_t)col >= pos - numCols)
2489 {
2490 // ...either decrement row counter (if row still exists)...
2491 coords.SetCol(col + numCols);
2492 }
2493 else
2494 {
2495 // ...or remove the attribute
2496 // No need to DecRef the attribute itself since this is
2497 // done be wxGridCellWithAttr's destructor!
2498 m_attrs.RemoveAt(n);
2499 n--; count--;
2500 }
2501 }
2502 }
2503 }
2504}
2505
2506int wxGridCellAttrData::FindIndex(int row, int col) const
2507{
2508 size_t count = m_attrs.GetCount();
2509 for ( size_t n = 0; n < count; n++ )
2510 {
2511 const wxGridCellCoords& coords = m_attrs[n].coords;
2512 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
2513 {
2514 return n;
2515 }
2516 }
2517
2518 return wxNOT_FOUND;
2519}
2520
2521// ----------------------------------------------------------------------------
2522// wxGridRowOrColAttrData
2523// ----------------------------------------------------------------------------
2524
2525wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
2526{
2527 size_t count = m_attrs.Count();
2528 for ( size_t n = 0; n < count; n++ )
2529 {
2530 m_attrs[n]->DecRef();
2531 }
2532}
2533
2534wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
2535{
2536 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2537
2538 int n = m_rowsOrCols.Index(rowOrCol);
2539 if ( n != wxNOT_FOUND )
2540 {
2541 attr = m_attrs[(size_t)n];
2542 attr->IncRef();
2543 }
2544
2545 return attr;
2546}
2547
2548void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
2549{
2550 int i = m_rowsOrCols.Index(rowOrCol);
2551 if ( i == wxNOT_FOUND )
2552 {
2553 // add the attribute
2554 m_rowsOrCols.Add(rowOrCol);
2555 m_attrs.Add(attr);
2556 }
2557 else
2558 {
2559 size_t n = (size_t)i;
2560 if ( attr )
2561 {
2562 // change the attribute
2563 m_attrs[n]->DecRef();
2564 m_attrs[n] = attr;
2565 }
2566 else
2567 {
2568 // remove this attribute
2569 m_attrs[n]->DecRef();
2570 m_rowsOrCols.RemoveAt(n);
2571 m_attrs.RemoveAt(n);
2572 }
2573 }
2574}
2575
2576void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols )
2577{
2578 size_t count = m_attrs.GetCount();
2579 for ( size_t n = 0; n < count; n++ )
2580 {
2581 int & rowOrCol = m_rowsOrCols[n];
2582 if ( (size_t)rowOrCol >= pos )
2583 {
2584 if ( numRowsOrCols > 0 )
2585 {
2586 // If rows inserted, include row counter where necessary
2587 rowOrCol += numRowsOrCols;
2588 }
2589 else if ( numRowsOrCols < 0)
2590 {
2591 // If rows deleted, either decrement row counter (if row still exists)
2592 if ((size_t)rowOrCol >= pos - numRowsOrCols)
2593 rowOrCol += numRowsOrCols;
2594 else
2595 {
2596 m_rowsOrCols.RemoveAt(n);
2597 m_attrs[n]->DecRef();
2598 m_attrs.RemoveAt(n);
2599 n--; count--;
2600 }
2601 }
2602 }
2603 }
2604}
2605
2606// ----------------------------------------------------------------------------
2607// wxGridCellAttrProvider
2608// ----------------------------------------------------------------------------
2609
2610wxGridCellAttrProvider::wxGridCellAttrProvider()
2611{
2612 m_data = (wxGridCellAttrProviderData *)NULL;
2613}
2614
2615wxGridCellAttrProvider::~wxGridCellAttrProvider()
2616{
2617 delete m_data;
2618}
2619
2620void wxGridCellAttrProvider::InitData()
2621{
2622 m_data = new wxGridCellAttrProviderData;
2623}
2624
2625wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col,
2626 wxGridCellAttr::wxAttrKind kind ) const
2627{
2628 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2629 if ( m_data )
2630 {
2631 switch(kind)
2632 {
2633 case (wxGridCellAttr::Any):
2634 //Get cached merge attributes.
2635 // Currenlty not used as no cache implemented as not mutiable
2636 // attr = m_data->m_mergeAttr.GetAttr(row, col);
2637 if(!attr)
2638 {
2639 //Basicaly implement old version.
2640 //Also check merge cache, so we don't have to re-merge every time..
2641 wxGridCellAttr *attrcell = m_data->m_cellAttrs.GetAttr(row, col);
2642 wxGridCellAttr *attrrow = m_data->m_rowAttrs.GetAttr(row);
2643 wxGridCellAttr *attrcol = m_data->m_colAttrs.GetAttr(col);
2644
2645 if((attrcell != attrrow) && (attrrow != attrcol) && (attrcell != attrcol)){
2646 // Two or more are non NULL
2647 attr = new wxGridCellAttr;
2648 attr->SetKind(wxGridCellAttr::Merged);
2649
2650 //Order important..
2651 if(attrcell){
2652 attr->MergeWith(attrcell);
2653 attrcell->DecRef();
2654 }
2655 if(attrcol){
2656 attr->MergeWith(attrcol);
2657 attrcol->DecRef();
2658 }
2659 if(attrrow){
2660 attr->MergeWith(attrrow);
2661 attrrow->DecRef();
2662 }
2663 //store merge attr if cache implemented
2664 //attr->IncRef();
2665 //m_data->m_mergeAttr.SetAttr(attr, row, col);
2666 }
2667 else
2668 {
2669 // one or none is non null return it or null.
2670 if(attrrow) attr = attrrow;
2671 if(attrcol)
2672 {
2673 if(attr)
2674 attr->DecRef();
2675 attr = attrcol;
2676 }
2677 if(attrcell)
2678 {
2679 if(attr)
2680 attr->DecRef();
2681 attr = attrcell;
2682 }
2683 }
2684 }
2685 break;
2686 case (wxGridCellAttr::Cell):
2687 attr = m_data->m_cellAttrs.GetAttr(row, col);
2688 break;
2689 case (wxGridCellAttr::Col):
2690 attr = m_data->m_colAttrs.GetAttr(col);
2691 break;
2692 case (wxGridCellAttr::Row):
2693 attr = m_data->m_rowAttrs.GetAttr(row);
2694 break;
2695 default:
2696 // unused as yet...
2697 // (wxGridCellAttr::Default):
2698 // (wxGridCellAttr::Merged):
2699 break;
2700 }
2701 }
2702 return attr;
2703}
2704
2705void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
2706 int row, int col)
2707{
2708 if ( !m_data )
2709 InitData();
2710
2711 m_data->m_cellAttrs.SetAttr(attr, row, col);
2712}
2713
2714void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
2715{
2716 if ( !m_data )
2717 InitData();
2718
2719 m_data->m_rowAttrs.SetAttr(attr, row);
2720}
2721
2722void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
2723{
2724 if ( !m_data )
2725 InitData();
2726
2727 m_data->m_colAttrs.SetAttr(attr, col);
2728}
2729
2730void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows )
2731{
2732 if ( m_data )
2733 {
2734 m_data->m_cellAttrs.UpdateAttrRows( pos, numRows );
2735
2736 m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows );
2737 }
2738}
2739
2740void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols )
2741{
2742 if ( m_data )
2743 {
2744 m_data->m_cellAttrs.UpdateAttrCols( pos, numCols );
2745
2746 m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols );
2747 }
2748}
2749
2750// ----------------------------------------------------------------------------
2751// wxGridTypeRegistry
2752// ----------------------------------------------------------------------------
2753
2754wxGridTypeRegistry::~wxGridTypeRegistry()
2755{
2756 size_t count = m_typeinfo.Count();
2757 for ( size_t i = 0; i < count; i++ )
2758 delete m_typeinfo[i];
2759}
2760
2761
2762void wxGridTypeRegistry::RegisterDataType(const wxString& typeName,
2763 wxGridCellRenderer* renderer,
2764 wxGridCellEditor* editor)
2765{
2766 wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor);
2767
2768 // is it already registered?
2769 int loc = FindRegisteredDataType(typeName);
2770 if ( loc != wxNOT_FOUND )
2771 {
2772 delete m_typeinfo[loc];
2773 m_typeinfo[loc] = info;
2774 }
2775 else
2776 {
2777 m_typeinfo.Add(info);
2778 }
2779}
2780
2781int wxGridTypeRegistry::FindRegisteredDataType(const wxString& typeName)
2782{
2783 size_t count = m_typeinfo.GetCount();
2784 for ( size_t i = 0; i < count; i++ )
2785 {
2786 if ( typeName == m_typeinfo[i]->m_typeName )
2787 {
2788 return i;
2789 }
2790 }
2791
2792 return wxNOT_FOUND;
2793}
2794
2795int wxGridTypeRegistry::FindDataType(const wxString& typeName)
2796{
2797 int index = FindRegisteredDataType(typeName);
2798 if ( index == wxNOT_FOUND )
2799 {
2800 // check whether this is one of the standard ones, in which case
2801 // register it "on the fly"
2802#if wxUSE_TEXTCTRL
2803 if ( typeName == wxGRID_VALUE_STRING )
2804 {
2805 RegisterDataType(wxGRID_VALUE_STRING,
2806 new wxGridCellStringRenderer,
2807 new wxGridCellTextEditor);
2808 } else
2809#endif // wxUSE_TEXTCTRL
2810#if wxUSE_CHECKBOX
2811 if ( typeName == wxGRID_VALUE_BOOL )
2812 {
2813 RegisterDataType(wxGRID_VALUE_BOOL,
2814 new wxGridCellBoolRenderer,
2815 new wxGridCellBoolEditor);
2816 } else
2817#endif // wxUSE_CHECKBOX
2818#if wxUSE_TEXTCTRL
2819 if ( typeName == wxGRID_VALUE_NUMBER )
2820 {
2821 RegisterDataType(wxGRID_VALUE_NUMBER,
2822 new wxGridCellNumberRenderer,
2823 new wxGridCellNumberEditor);
2824 }
2825 else if ( typeName == wxGRID_VALUE_FLOAT )
2826 {
2827 RegisterDataType(wxGRID_VALUE_FLOAT,
2828 new wxGridCellFloatRenderer,
2829 new wxGridCellFloatEditor);
2830 } else
2831#endif // wxUSE_TEXTCTRL
2832#if wxUSE_COMBOBOX
2833 if ( typeName == wxGRID_VALUE_CHOICE )
2834 {
2835 RegisterDataType(wxGRID_VALUE_CHOICE,
2836 new wxGridCellStringRenderer,
2837 new wxGridCellChoiceEditor);
2838 } else
2839#endif // wxUSE_COMBOBOX
2840 {
2841 return wxNOT_FOUND;
2842 }
2843
2844 // we get here only if just added the entry for this type, so return
2845 // the last index
2846 index = m_typeinfo.GetCount() - 1;
2847 }
2848
2849 return index;
2850}
2851
2852int wxGridTypeRegistry::FindOrCloneDataType(const wxString& typeName)
2853{
2854 int index = FindDataType(typeName);
2855 if ( index == wxNOT_FOUND )
2856 {
2857 // the first part of the typename is the "real" type, anything after ':'
2858 // are the parameters for the renderer
2859 index = FindDataType(typeName.BeforeFirst(_T(':')));
2860 if ( index == wxNOT_FOUND )
2861 {
2862 return wxNOT_FOUND;
2863 }
2864
2865 wxGridCellRenderer *renderer = GetRenderer(index);
2866 wxGridCellRenderer *rendererOld = renderer;
2867 renderer = renderer->Clone();
2868 rendererOld->DecRef();
2869
2870 wxGridCellEditor *editor = GetEditor(index);
2871 wxGridCellEditor *editorOld = editor;
2872 editor = editor->Clone();
2873 editorOld->DecRef();
2874
2875 // do it even if there are no parameters to reset them to defaults
2876 wxString params = typeName.AfterFirst(_T(':'));
2877 renderer->SetParameters(params);
2878 editor->SetParameters(params);
2879
2880 // register the new typename
2881 RegisterDataType(typeName, renderer, editor);
2882
2883 // we just registered it, it's the last one
2884 index = m_typeinfo.GetCount() - 1;
2885 }
2886
2887 return index;
2888}
2889
2890wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index)
2891{
2892 wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer;
2893 if (renderer)
2894 renderer->IncRef();
2895 return renderer;
2896}
2897
2898wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
2899{
2900 wxGridCellEditor* editor = m_typeinfo[index]->m_editor;
2901 if (editor)
2902 editor->IncRef();
2903 return editor;
2904}
2905
2906// ----------------------------------------------------------------------------
2907// wxGridTableBase
2908// ----------------------------------------------------------------------------
2909
2910IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
2911
2912
2913wxGridTableBase::wxGridTableBase()
2914{
2915 m_view = (wxGrid *) NULL;
2916 m_attrProvider = (wxGridCellAttrProvider *) NULL;
2917}
2918
2919wxGridTableBase::~wxGridTableBase()
2920{
2921 delete m_attrProvider;
2922}
2923
2924void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
2925{
2926 delete m_attrProvider;
2927 m_attrProvider = attrProvider;
2928}
2929
2930bool wxGridTableBase::CanHaveAttributes()
2931{
2932 if ( ! GetAttrProvider() )
2933 {
2934 // use the default attr provider by default
2935 SetAttrProvider(new wxGridCellAttrProvider);
2936 }
2937 return true;
2938}
2939
2940wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind)
2941{
2942 if ( m_attrProvider )
2943 return m_attrProvider->GetAttr(row, col, kind);
2944 else
2945 return (wxGridCellAttr *)NULL;
2946}
2947
2948
2949void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
2950{
2951 if ( m_attrProvider )
2952 {
2953 attr->SetKind(wxGridCellAttr::Cell);
2954 m_attrProvider->SetAttr(attr, row, col);
2955 }
2956 else
2957 {
2958 // as we take ownership of the pointer and don't store it, we must
2959 // free it now
2960 wxSafeDecRef(attr);
2961 }
2962}
2963
2964void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
2965{
2966 if ( m_attrProvider )
2967 {
2968 attr->SetKind(wxGridCellAttr::Row);
2969 m_attrProvider->SetRowAttr(attr, row);
2970 }
2971 else
2972 {
2973 // as we take ownership of the pointer and don't store it, we must
2974 // free it now
2975 wxSafeDecRef(attr);
2976 }
2977}
2978
2979void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
2980{
2981 if ( m_attrProvider )
2982 {
2983 attr->SetKind(wxGridCellAttr::Col);
2984 m_attrProvider->SetColAttr(attr, col);
2985 }
2986 else
2987 {
2988 // as we take ownership of the pointer and don't store it, we must
2989 // free it now
2990 wxSafeDecRef(attr);
2991 }
2992}
2993
2994bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos),
2995 size_t WXUNUSED(numRows) )
2996{
2997 wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") );
2998
2999 return false;
3000}
3001
3002bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows) )
3003{
3004 wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function"));
3005
3006 return false;
3007}
3008
3009bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos),
3010 size_t WXUNUSED(numRows) )
3011{
3012 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function"));
3013
3014 return false;
3015}
3016
3017bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos),
3018 size_t WXUNUSED(numCols) )
3019{
3020 wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function"));
3021
3022 return false;
3023}
3024
3025bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols) )
3026{
3027 wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function"));
3028
3029 return false;
3030}
3031
3032bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos),
3033 size_t WXUNUSED(numCols) )
3034{
3035 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function"));
3036
3037 return false;
3038}
3039
3040
3041wxString wxGridTableBase::GetRowLabelValue( int row )
3042{
3043 wxString s;
3044 s << row + 1; // RD: Starting the rows at zero confuses users, no matter
3045 // how much it makes sense to us geeks.
3046 return s;
3047}
3048
3049wxString wxGridTableBase::GetColLabelValue( int col )
3050{
3051 // default col labels are:
3052 // cols 0 to 25 : A-Z
3053 // cols 26 to 675 : AA-ZZ
3054 // etc.
3055
3056 wxString s;
3057 unsigned int i, n;
3058 for ( n = 1; ; n++ )
3059 {
3060 s += (wxChar) (_T('A') + (wxChar)( col%26 ));
3061 col = col/26 - 1;
3062 if ( col < 0 ) break;
3063 }
3064
3065 // reverse the string...
3066 wxString s2;
3067 for ( i = 0; i < n; i++ )
3068 {
3069 s2 += s[n-i-1];
3070 }
3071
3072 return s2;
3073}
3074
3075
3076wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) )
3077{
3078 return wxGRID_VALUE_STRING;
3079}
3080
3081bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col),
3082 const wxString& typeName )
3083{
3084 return typeName == wxGRID_VALUE_STRING;
3085}
3086
3087bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName )
3088{
3089 return CanGetValueAs(row, col, typeName);
3090}
3091
3092long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) )
3093{
3094 return 0;
3095}
3096
3097double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) )
3098{
3099 return 0.0;
3100}
3101
3102bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) )
3103{
3104 return false;
3105}
3106
3107void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col),
3108 long WXUNUSED(value) )
3109{
3110}
3111
3112void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col),
3113 double WXUNUSED(value) )
3114{
3115}
3116
3117void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col),
3118 bool WXUNUSED(value) )
3119{
3120}
3121
3122
3123void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
3124 const wxString& WXUNUSED(typeName) )
3125{
3126 return NULL;
3127}
3128
3129void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
3130 const wxString& WXUNUSED(typeName),
3131 void* WXUNUSED(value) )
3132{
3133}
3134
3135//////////////////////////////////////////////////////////////////////
3136//
3137// Message class for the grid table to send requests and notifications
3138// to the grid view
3139//
3140
3141wxGridTableMessage::wxGridTableMessage()
3142{
3143 m_table = (wxGridTableBase *) NULL;
3144 m_id = -1;
3145 m_comInt1 = -1;
3146 m_comInt2 = -1;
3147}
3148
3149wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
3150 int commandInt1, int commandInt2 )
3151{
3152 m_table = table;
3153 m_id = id;
3154 m_comInt1 = commandInt1;
3155 m_comInt2 = commandInt2;
3156}
3157
3158
3159
3160//////////////////////////////////////////////////////////////////////
3161//
3162// A basic grid table for string data. An object of this class will
3163// created by wxGrid if you don't specify an alternative table class.
3164//
3165
3166WX_DEFINE_OBJARRAY(wxGridStringArray)
3167
3168IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
3169
3170wxGridStringTable::wxGridStringTable()
3171 : wxGridTableBase()
3172{
3173}
3174
3175wxGridStringTable::wxGridStringTable( int numRows, int numCols )
3176 : wxGridTableBase()
3177{
3178 m_data.Alloc( numRows );
3179
3180 wxArrayString sa;
3181 sa.Alloc( numCols );
3182 sa.Add( wxEmptyString, numCols );
3183
3184 m_data.Add( sa, numRows );
3185}
3186
3187wxGridStringTable::~wxGridStringTable()
3188{
3189}
3190
3191int wxGridStringTable::GetNumberRows()
3192{
3193 return m_data.GetCount();
3194}
3195
3196int wxGridStringTable::GetNumberCols()
3197{
3198 if ( m_data.GetCount() > 0 )
3199 return m_data[0].GetCount();
3200 else
3201 return 0;
3202}
3203
3204wxString wxGridStringTable::GetValue( int row, int col )
3205{
3206 wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
3207 wxEmptyString,
3208 _T("invalid row or column index in wxGridStringTable") );
3209
3210 return m_data[row][col];
3211}
3212
3213void wxGridStringTable::SetValue( int row, int col, const wxString& value )
3214{
3215 wxCHECK_RET( (row < GetNumberRows()) && (col < GetNumberCols()),
3216 _T("invalid row or column index in wxGridStringTable") );
3217
3218 m_data[row][col] = value;
3219}
3220
3221bool wxGridStringTable::IsEmptyCell( int row, int col )
3222{
3223 wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
3224 true,
3225 _T("invalid row or column index in wxGridStringTable") );
3226
3227 return (m_data[row][col] == wxEmptyString);
3228}
3229
3230void wxGridStringTable::Clear()
3231{
3232 int row, col;
3233 int numRows, numCols;
3234
3235 numRows = m_data.GetCount();
3236 if ( numRows > 0 )
3237 {
3238 numCols = m_data[0].GetCount();
3239
3240 for ( row = 0; row < numRows; row++ )
3241 {
3242 for ( col = 0; col < numCols; col++ )
3243 {
3244 m_data[row][col] = wxEmptyString;
3245 }
3246 }
3247 }
3248}
3249
3250
3251bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
3252{
3253 size_t curNumRows = m_data.GetCount();
3254 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3255 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
3256
3257 if ( pos >= curNumRows )
3258 {
3259 return AppendRows( numRows );
3260 }
3261
3262 wxArrayString sa;
3263 sa.Alloc( curNumCols );
3264 sa.Add( wxEmptyString, curNumCols );
3265 m_data.Insert( sa, pos, numRows );
3266 if ( GetView() )
3267 {
3268 wxGridTableMessage msg( this,
3269 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
3270 pos,
3271 numRows );
3272
3273 GetView()->ProcessTableMessage( msg );
3274 }
3275
3276 return true;
3277}
3278
3279bool wxGridStringTable::AppendRows( size_t numRows )
3280{
3281 size_t curNumRows = m_data.GetCount();
3282 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3283 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
3284
3285 wxArrayString sa;
3286 if ( curNumCols > 0 )
3287 {
3288 sa.Alloc( curNumCols );
3289 sa.Add( wxEmptyString, curNumCols );
3290 }
3291
3292 m_data.Add( sa, numRows );
3293
3294 if ( GetView() )
3295 {
3296 wxGridTableMessage msg( this,
3297 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
3298 numRows );
3299
3300 GetView()->ProcessTableMessage( msg );
3301 }
3302
3303 return true;
3304}
3305
3306bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
3307{
3308 size_t curNumRows = m_data.GetCount();
3309
3310 if ( pos >= curNumRows )
3311 {
3312 wxFAIL_MSG( wxString::Format
3313 (
3314 wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"),
3315 (unsigned long)pos,
3316 (unsigned long)numRows,
3317 (unsigned long)curNumRows
3318 ) );
3319
3320 return false;
3321 }
3322
3323 if ( numRows > curNumRows - pos )
3324 {
3325 numRows = curNumRows - pos;
3326 }
3327
3328 if ( numRows >= curNumRows )
3329 {
3330 m_data.Clear();
3331 }
3332 else
3333 {
3334 m_data.RemoveAt( pos, numRows );
3335 }
3336 if ( GetView() )
3337 {
3338 wxGridTableMessage msg( this,
3339 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
3340 pos,
3341 numRows );
3342
3343 GetView()->ProcessTableMessage( msg );
3344 }
3345
3346 return true;
3347}
3348
3349bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
3350{
3351 size_t row, col;
3352
3353 size_t curNumRows = m_data.GetCount();
3354 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3355 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
3356
3357 if ( pos >= curNumCols )
3358 {
3359 return AppendCols( numCols );
3360 }
3361
3362 for ( row = 0; row < curNumRows; row++ )
3363 {
3364 for ( col = pos; col < pos + numCols; col++ )
3365 {
3366 m_data[row].Insert( wxEmptyString, col );
3367 }
3368 }
3369 if ( GetView() )
3370 {
3371 wxGridTableMessage msg( this,
3372 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
3373 pos,
3374 numCols );
3375
3376 GetView()->ProcessTableMessage( msg );
3377 }
3378
3379 return true;
3380}
3381
3382bool wxGridStringTable::AppendCols( size_t numCols )
3383{
3384 size_t row;
3385
3386 size_t curNumRows = m_data.GetCount();
3387#if 0
3388 if ( !curNumRows )
3389 {
3390 // TODO: something better than this ?
3391 //
3392 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\nCall AppendRows() first") );
3393 return false;
3394 }
3395#endif
3396
3397 for ( row = 0; row < curNumRows; row++ )
3398 {
3399 m_data[row].Add( wxEmptyString, numCols );
3400 }
3401
3402 if ( GetView() )
3403 {
3404 wxGridTableMessage msg( this,
3405 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
3406 numCols );
3407
3408 GetView()->ProcessTableMessage( msg );
3409 }
3410
3411 return true;
3412}
3413
3414bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
3415{
3416 size_t row;
3417
3418 size_t curNumRows = m_data.GetCount();
3419 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3420 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
3421
3422 if ( pos >= curNumCols )
3423 {
3424 wxFAIL_MSG( wxString::Format
3425 (
3426 wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"),
3427 (unsigned long)pos,
3428 (unsigned long)numCols,
3429 (unsigned long)curNumCols
3430 ) );
3431 return false;
3432 }
3433
3434 if ( numCols > curNumCols - pos )
3435 {
3436 numCols = curNumCols - pos;
3437 }
3438
3439 for ( row = 0; row < curNumRows; row++ )
3440 {
3441 if ( numCols >= curNumCols )
3442 {
3443 m_data[row].Clear();
3444 }
3445 else
3446 {
3447 m_data[row].RemoveAt( pos, numCols );
3448 }
3449 }
3450 if ( GetView() )
3451 {
3452 wxGridTableMessage msg( this,
3453 wxGRIDTABLE_NOTIFY_COLS_DELETED,
3454 pos,
3455 numCols );
3456
3457 GetView()->ProcessTableMessage( msg );
3458 }
3459
3460 return true;
3461}
3462
3463wxString wxGridStringTable::GetRowLabelValue( int row )
3464{
3465 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
3466 {
3467 // using default label
3468 //
3469 return wxGridTableBase::GetRowLabelValue( row );
3470 }
3471 else
3472 {
3473 return m_rowLabels[ row ];
3474 }
3475}
3476
3477wxString wxGridStringTable::GetColLabelValue( int col )
3478{
3479 if ( col > (int)(m_colLabels.GetCount()) - 1 )
3480 {
3481 // using default label
3482 //
3483 return wxGridTableBase::GetColLabelValue( col );
3484 }
3485 else
3486 {
3487 return m_colLabels[ col ];
3488 }
3489}
3490
3491void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
3492{
3493 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
3494 {
3495 int n = m_rowLabels.GetCount();
3496 int i;
3497 for ( i = n; i <= row; i++ )
3498 {
3499 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
3500 }
3501 }
3502
3503 m_rowLabels[row] = value;
3504}
3505
3506void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
3507{
3508 if ( col > (int)(m_colLabels.GetCount()) - 1 )
3509 {
3510 int n = m_colLabels.GetCount();
3511 int i;
3512 for ( i = n; i <= col; i++ )
3513 {
3514 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
3515 }
3516 }
3517
3518 m_colLabels[col] = value;
3519}
3520
3521
3522
3523//////////////////////////////////////////////////////////////////////
3524//////////////////////////////////////////////////////////////////////
3525
3526IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
3527
3528BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
3529 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
3530 EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel)
3531 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
3532 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
3533 EVT_KEY_UP( wxGridRowLabelWindow::OnKeyUp )
3534 EVT_CHAR ( wxGridRowLabelWindow::OnChar )
3535END_EVENT_TABLE()
3536
3537wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
3538 wxWindowID id,
3539 const wxPoint &pos, const wxSize &size )
3540 : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE )
3541{
3542 m_owner = parent;
3543}
3544
3545void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
3546{
3547 wxPaintDC dc(this);
3548
3549 // NO - don't do this because it will set both the x and y origin
3550 // coords to match the parent scrolled window and we just want to
3551 // set the y coord - MB
3552 //
3553 // m_owner->PrepareDC( dc );
3554
3555 int x, y;
3556 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
3557 dc.SetDeviceOrigin( 0, -y );
3558
3559 wxArrayInt rows = m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
3560 m_owner->DrawRowLabels( dc , rows );
3561}
3562
3563
3564void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
3565{
3566 m_owner->ProcessRowLabelMouseEvent( event );
3567}
3568
3569
3570void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent& event )
3571{
3572 m_owner->GetEventHandler()->ProcessEvent(event);
3573}
3574
3575
3576// This seems to be required for wxMotif otherwise the mouse
3577// cursor must be in the cell edit control to get key events
3578//
3579void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
3580{
3581 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3582}
3583
3584void wxGridRowLabelWindow::OnKeyUp( wxKeyEvent& event )
3585{
3586 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3587}
3588
3589void wxGridRowLabelWindow::OnChar( wxKeyEvent& event )
3590{
3591 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3592}
3593
3594
3595
3596//////////////////////////////////////////////////////////////////////
3597
3598IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
3599
3600BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
3601 EVT_PAINT( wxGridColLabelWindow::OnPaint )
3602 EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel)
3603 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
3604 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
3605 EVT_KEY_UP( wxGridColLabelWindow::OnKeyUp )
3606 EVT_CHAR ( wxGridColLabelWindow::OnChar )
3607END_EVENT_TABLE()
3608
3609wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
3610 wxWindowID id,
3611 const wxPoint &pos, const wxSize &size )
3612 : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE )
3613{
3614 m_owner = parent;
3615}
3616
3617void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
3618{
3619 wxPaintDC dc(this);
3620
3621 // NO - don't do this because it will set both the x and y origin
3622 // coords to match the parent scrolled window and we just want to
3623 // set the x coord - MB
3624 //
3625 // m_owner->PrepareDC( dc );
3626
3627 int x, y;
3628 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
3629 dc.SetDeviceOrigin( -x, 0 );
3630
3631 wxArrayInt cols = m_owner->CalcColLabelsExposed( GetUpdateRegion() );
3632 m_owner->DrawColLabels( dc , cols );
3633}
3634
3635
3636void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
3637{
3638 m_owner->ProcessColLabelMouseEvent( event );
3639}
3640
3641void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent& event )
3642{
3643 m_owner->GetEventHandler()->ProcessEvent(event);
3644}
3645
3646
3647// This seems to be required for wxMotif otherwise the mouse
3648// cursor must be in the cell edit control to get key events
3649//
3650void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
3651{
3652 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3653}
3654
3655void wxGridColLabelWindow::OnKeyUp( wxKeyEvent& event )
3656{
3657 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3658}
3659
3660void wxGridColLabelWindow::OnChar( wxKeyEvent& event )
3661{
3662 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3663}
3664
3665
3666//////////////////////////////////////////////////////////////////////
3667
3668IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
3669
3670BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
3671 EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel)
3672 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
3673 EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
3674 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
3675 EVT_KEY_UP( wxGridCornerLabelWindow::OnKeyUp )
3676 EVT_CHAR ( wxGridCornerLabelWindow::OnChar )
3677END_EVENT_TABLE()
3678
3679wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
3680 wxWindowID id,
3681 const wxPoint &pos, const wxSize &size )
3682 : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE )
3683{
3684 m_owner = parent;
3685}
3686
3687void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
3688{
3689 wxPaintDC dc(this);
3690
3691 int client_height = 0;
3692 int client_width = 0;
3693 GetClientSize( &client_width, &client_height );
3694
3695 // VZ: any reason for this ifdef? (FIXME)
3696#ifdef __WXGTK__
3697 wxRect rect;
3698 rect.SetX( 1 );
3699 rect.SetY( 1 );
3700 rect.SetWidth( client_width - 2 );
3701 rect.SetHeight( client_height - 2 );
3702
3703 wxRendererNative::Get().DrawHeaderButton( this, dc, rect, 0 );
3704#else // !__WXGTK__
3705 dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW),1, wxSOLID) );
3706 dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
3707 dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
3708 dc.DrawLine( 0, 0, client_width, 0 );
3709 dc.DrawLine( 0, 0, 0, client_height );
3710
3711 dc.SetPen( *wxWHITE_PEN );
3712 dc.DrawLine( 1, 1, client_width-1, 1 );
3713 dc.DrawLine( 1, 1, 1, client_height-1 );
3714#endif // __WXGTK__/!__WXGTK__
3715}
3716
3717
3718void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
3719{
3720 m_owner->ProcessCornerLabelMouseEvent( event );
3721}
3722
3723
3724void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent& event )
3725{
3726 m_owner->GetEventHandler()->ProcessEvent(event);
3727}
3728
3729// This seems to be required for wxMotif otherwise the mouse
3730// cursor must be in the cell edit control to get key events
3731//
3732void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
3733{
3734 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3735}
3736
3737void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event )
3738{
3739 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3740}
3741
3742void wxGridCornerLabelWindow::OnChar( wxKeyEvent& event )
3743{
3744 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3745}
3746
3747
3748//////////////////////////////////////////////////////////////////////
3749
3750IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow )
3751
3752BEGIN_EVENT_TABLE( wxGridWindow, wxWindow )
3753 EVT_PAINT( wxGridWindow::OnPaint )
3754 EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel)
3755 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
3756 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
3757 EVT_KEY_UP( wxGridWindow::OnKeyUp )
3758 EVT_CHAR ( wxGridWindow::OnChar )
3759 EVT_SET_FOCUS( wxGridWindow::OnFocus )
3760 EVT_KILL_FOCUS( wxGridWindow::OnFocus )
3761 EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground )
3762END_EVENT_TABLE()
3763
3764wxGridWindow::wxGridWindow( wxGrid *parent,
3765 wxGridRowLabelWindow *rowLblWin,
3766 wxGridColLabelWindow *colLblWin,
3767 wxWindowID id,
3768 const wxPoint &pos,
3769 const wxSize &size )
3770 : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxCLIP_CHILDREN|wxFULL_REPAINT_ON_RESIZE,
3771 wxT("grid window") )
3772
3773{
3774 m_owner = parent;
3775 m_rowLabelWin = rowLblWin;
3776 m_colLabelWin = colLblWin;
3777}
3778
3779
3780void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
3781{
3782 wxPaintDC dc( this );
3783 m_owner->PrepareDC( dc );
3784 wxRegion reg = GetUpdateRegion();
3785 wxGridCellCoordsArray DirtyCells = m_owner->CalcCellsExposed( reg );
3786 m_owner->DrawGridCellArea( dc , DirtyCells);
3787#if WXGRID_DRAW_LINES
3788 m_owner->DrawAllGridLines( dc, reg );
3789#endif
3790 m_owner->DrawGridSpace( dc );
3791 m_owner->DrawHighlight( dc , DirtyCells );
3792}
3793
3794
3795void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
3796{
3797 wxWindow::ScrollWindow( dx, dy, rect );
3798 m_rowLabelWin->ScrollWindow( 0, dy, rect );
3799 m_colLabelWin->ScrollWindow( dx, 0, rect );
3800}
3801
3802
3803void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
3804{
3805 if (event.ButtonDown(wxMOUSE_BTN_LEFT) && FindFocus() != this)
3806 SetFocus();
3807
3808 m_owner->ProcessGridCellMouseEvent( event );
3809}
3810
3811void wxGridWindow::OnMouseWheel( wxMouseEvent& event )
3812{
3813 m_owner->GetEventHandler()->ProcessEvent(event);
3814}
3815
3816// This seems to be required for wxMotif/wxGTK otherwise the mouse
3817// cursor must be in the cell edit control to get key events
3818//
3819void wxGridWindow::OnKeyDown( wxKeyEvent& event )
3820{
3821 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3822}
3823
3824void wxGridWindow::OnKeyUp( wxKeyEvent& event )
3825{
3826 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3827}
3828
3829void wxGridWindow::OnChar( wxKeyEvent& event )
3830{
3831 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
3832}
3833
3834void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) )
3835{
3836}
3837
3838void wxGridWindow::OnFocus(wxFocusEvent& event)
3839{
3840 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3841 event.Skip();
3842}
3843
3844//////////////////////////////////////////////////////////////////////
3845
3846// Internal Helper function for computing row or column from some
3847// (unscrolled) coordinate value, using either
3848// m_defaultRowHeight/m_defaultColWidth or binary search on array
3849// of m_rowBottoms/m_ColRights to speed up the search!
3850
3851// Internal helper macros for simpler use of that function
3852
3853static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
3854 const wxArrayInt& BorderArray, int nMax,
3855 bool clipToMinMax);
3856
3857#define internalXToCol(x) CoordToRowOrCol(x, m_defaultColWidth, \
3858 m_minAcceptableColWidth, \
3859 m_colRights, m_numCols, true)
3860#define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \
3861 m_minAcceptableRowHeight, \
3862 m_rowBottoms, m_numRows, true)
3863/////////////////////////////////////////////////////////////////////
3864
3865#if wxUSE_EXTENDED_RTTI
3866WX_DEFINE_FLAGS( wxGridStyle )
3867
3868wxBEGIN_FLAGS( wxGridStyle )
3869 // new style border flags, we put them first to
3870 // use them for streaming out
3871 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
3872 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
3873 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
3874 wxFLAGS_MEMBER(wxBORDER_RAISED)
3875 wxFLAGS_MEMBER(wxBORDER_STATIC)
3876 wxFLAGS_MEMBER(wxBORDER_NONE)
3877
3878 // old style border flags
3879 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
3880 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
3881 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
3882 wxFLAGS_MEMBER(wxRAISED_BORDER)
3883 wxFLAGS_MEMBER(wxSTATIC_BORDER)
3884 wxFLAGS_MEMBER(wxBORDER)
3885
3886 // standard window styles
3887 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
3888 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
3889 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
3890 wxFLAGS_MEMBER(wxWANTS_CHARS)
3891 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
3892 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
3893 wxFLAGS_MEMBER(wxVSCROLL)
3894 wxFLAGS_MEMBER(wxHSCROLL)
3895
3896wxEND_FLAGS( wxGridStyle )
3897
3898IMPLEMENT_DYNAMIC_CLASS_XTI(wxGrid, wxScrolledWindow,"wx/grid.h")
3899
3900wxBEGIN_PROPERTIES_TABLE(wxGrid)
3901 wxHIDE_PROPERTY( Children )
3902 wxPROPERTY_FLAGS( WindowStyle , wxGridStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
3903wxEND_PROPERTIES_TABLE()
3904
3905wxBEGIN_HANDLERS_TABLE(wxGrid)
3906wxEND_HANDLERS_TABLE()
3907
3908wxCONSTRUCTOR_5( wxGrid , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle )
3909
3910/*
3911