1 ///////////////////////////////////////////////////////////////////////////
2 // Name:        generic/gridctrl.cpp
3 // Purpose:     wxGrid controls
4 // Author:      Paul Gammans, Roger Gammans
5 // Modified by:
6 // Created:     11/04/2001
7 // RCS-ID:      $Id: gridctrl.cpp 59121 2009-02-25 00:09:23Z VZ $
8 // Copyright:   (c) The Computer Surgery (paul@compsurg.co.uk)
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 #include "wx/wxprec.h"
13 
14 #ifdef __BORLANDC__
15     #pragma hdrstop
16 #endif
17 
18 #if wxUSE_GRID
19 
20 #include "wx/generic/gridctrl.h"
21 
22 #ifndef WX_PRECOMP
23     #include "wx/textctrl.h"
24     #include "wx/dc.h"
25     #include "wx/combobox.h"
26 #endif // WX_PRECOMP
27 
28 #include "wx/tokenzr.h"
29 
30 // ----------------------------------------------------------------------------
31 // wxGridCellDateTimeRenderer
32 // ----------------------------------------------------------------------------
33 
34 #if wxUSE_DATETIME
35 
36 // Enables a grid cell to display a formatted date and or time
37 
wxGridCellDateTimeRenderer(const wxString & outformat,const wxString & informat)38 wxGridCellDateTimeRenderer::wxGridCellDateTimeRenderer(const wxString& outformat, const wxString& informat)
39 {
40     m_iformat = informat;
41     m_oformat = outformat;
42     m_tz = wxDateTime::Local;
43     m_dateDef = wxDefaultDateTime;
44 }
45 
Clone() const46 wxGridCellRenderer *wxGridCellDateTimeRenderer::Clone() const
47 {
48     wxGridCellDateTimeRenderer *renderer = new wxGridCellDateTimeRenderer;
49     renderer->m_iformat = m_iformat;
50     renderer->m_oformat = m_oformat;
51     renderer->m_dateDef = m_dateDef;
52     renderer->m_tz = m_tz;
53 
54     return renderer;
55 }
56 
GetString(const wxGrid & grid,int row,int col)57 wxString wxGridCellDateTimeRenderer::GetString(const wxGrid& grid, int row, int col)
58 {
59     wxGridTableBase *table = grid.GetTable();
60 
61     bool hasDatetime = false;
62     wxDateTime val;
63     wxString text;
64     if ( table->CanGetValueAs(row, col, wxGRID_VALUE_DATETIME) )
65     {
66         void * tempval = table->GetValueAsCustom(row, col,wxGRID_VALUE_DATETIME);
67 
68         if (tempval){
69             val = *((wxDateTime *)tempval);
70             hasDatetime = true;
71             delete (wxDateTime *)tempval;
72         }
73 
74     }
75 
76     if (!hasDatetime )
77     {
78         text = table->GetValue(row, col);
79         hasDatetime = (val.ParseFormat( text, m_iformat, m_dateDef ) != (wxChar *)NULL) ;
80     }
81 
82     if ( hasDatetime )
83         text = val.Format(m_oformat, m_tz );
84 
85     //If we faild to parse string just show what we where given?
86     return text;
87 }
88 
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rectCell,int row,int col,bool isSelected)89 void wxGridCellDateTimeRenderer::Draw(wxGrid& grid,
90                                    wxGridCellAttr& attr,
91                                    wxDC& dc,
92                                    const wxRect& rectCell,
93                                    int row, int col,
94                                    bool isSelected)
95 {
96     wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
97 
98     SetTextColoursAndFont(grid, attr, dc, isSelected);
99 
100     // draw the text right aligned by default
101     int hAlign, vAlign;
102     attr.GetAlignment(&hAlign, &vAlign);
103     hAlign = wxRIGHT;
104 
105     wxRect rect = rectCell;
106     rect.Inflate(-1);
107 
108     grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
109 }
110 
GetBestSize(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,int row,int col)111 wxSize wxGridCellDateTimeRenderer::GetBestSize(wxGrid& grid,
112                                             wxGridCellAttr& attr,
113                                             wxDC& dc,
114                                             int row, int col)
115 {
116     return DoGetBestSize(attr, dc, GetString(grid, row, col));
117 }
118 
SetParameters(const wxString & params)119 void wxGridCellDateTimeRenderer::SetParameters(const wxString& params)
120 {
121     if (!params.empty())
122         m_oformat=params;
123 }
124 
125 #endif // wxUSE_DATETIME
126 
127 // ----------------------------------------------------------------------------
128 // wxGridCellChoiceNumberRenderer
129 // ----------------------------------------------------------------------------
130 // Renders a number as a textual equivalent.
131 // eg data in cell is 0,1,2 ... n the cell could be rendered as "John","Fred"..."Bob"
132 
133 
wxGridCellEnumRenderer(const wxString & choices)134 wxGridCellEnumRenderer::wxGridCellEnumRenderer(const wxString& choices)
135 {
136     if (!choices.empty())
137         SetParameters(choices);
138 }
139 
Clone() const140 wxGridCellRenderer *wxGridCellEnumRenderer::Clone() const
141 {
142     wxGridCellEnumRenderer *renderer = new wxGridCellEnumRenderer;
143     renderer->m_choices = m_choices;
144     return renderer;
145 }
146 
GetString(const wxGrid & grid,int row,int col)147 wxString wxGridCellEnumRenderer::GetString(const wxGrid& grid, int row, int col)
148 {
149     wxGridTableBase *table = grid.GetTable();
150     wxString text;
151     if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
152     {
153         int choiceno = table->GetValueAsLong(row, col);
154         text.Printf(_T("%s"), m_choices[ choiceno ].c_str() );
155     }
156     else
157     {
158         text = table->GetValue(row, col);
159     }
160 
161 
162     //If we faild to parse string just show what we where given?
163     return text;
164 }
165 
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rectCell,int row,int col,bool isSelected)166 void wxGridCellEnumRenderer::Draw(wxGrid& grid,
167                                    wxGridCellAttr& attr,
168                                    wxDC& dc,
169                                    const wxRect& rectCell,
170                                    int row, int col,
171                                    bool isSelected)
172 {
173     wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
174 
175     SetTextColoursAndFont(grid, attr, dc, isSelected);
176 
177     // draw the text right aligned by default
178     int hAlign, vAlign;
179     attr.GetAlignment(&hAlign, &vAlign);
180     hAlign = wxRIGHT;
181 
182     wxRect rect = rectCell;
183     rect.Inflate(-1);
184 
185     grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
186 }
187 
GetBestSize(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,int row,int col)188 wxSize wxGridCellEnumRenderer::GetBestSize(wxGrid& grid,
189                                             wxGridCellAttr& attr,
190                                             wxDC& dc,
191                                             int row, int col)
192 {
193     return DoGetBestSize(attr, dc, GetString(grid, row, col));
194 }
195 
SetParameters(const wxString & params)196 void wxGridCellEnumRenderer::SetParameters(const wxString& params)
197 {
198     if ( !params )
199     {
200         // what can we do?
201         return;
202     }
203 
204     m_choices.Empty();
205 
206     wxStringTokenizer tk(params, _T(','));
207     while ( tk.HasMoreTokens() )
208     {
209         m_choices.Add(tk.GetNextToken());
210     }
211 }
212 
213 #if wxUSE_COMBOBOX
214 
215 // ----------------------------------------------------------------------------
216 // wxGridCellEnumEditor
217 // ----------------------------------------------------------------------------
218 
219 // A cell editor which displays an enum number as a textual equivalent. eg
220 // data in cell is 0,1,2 ... n the cell could be displayed as
221 // "John","Fred"..."Bob" in the combo choice box
222 
wxGridCellEnumEditor(const wxString & choices)223 wxGridCellEnumEditor::wxGridCellEnumEditor(const wxString& choices)
224                      :wxGridCellChoiceEditor()
225 {
226     m_startint = -1;
227 
228     if (!choices.empty())
229         SetParameters(choices);
230 }
231 
Clone() const232 wxGridCellEditor *wxGridCellEnumEditor::Clone() const
233 {
234     wxGridCellEnumEditor *editor = new wxGridCellEnumEditor();
235     editor->m_startint = m_startint;
236     return editor;
237 }
238 
BeginEdit(int row,int col,wxGrid * grid)239 void wxGridCellEnumEditor::BeginEdit(int row, int col, wxGrid* grid)
240 {
241     wxASSERT_MSG(m_control,
242                  wxT("The wxGridCellEnumEditor must be Created first!"));
243 
244     wxGridTableBase *table = grid->GetTable();
245 
246     if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
247     {
248         m_startint = table->GetValueAsLong(row, col);
249     }
250     else
251     {
252         wxString startValue = table->GetValue(row, col);
253         if (startValue.IsNumber() && !startValue.empty())
254         {
255             startValue.ToLong(&m_startint);
256         }
257         else
258         {
259             m_startint=-1;
260         }
261     }
262 
263     Combo()->SetSelection(m_startint);
264     Combo()->SetInsertionPointEnd();
265     Combo()->SetFocus();
266 
267 }
268 
EndEdit(int row,int col,wxGrid * grid)269 bool wxGridCellEnumEditor::EndEdit(int row, int col, wxGrid* grid)
270 {
271     int pos = Combo()->GetSelection();
272     bool changed = (pos != m_startint);
273     if (changed)
274     {
275         if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
276             grid->GetTable()->SetValueAsLong(row, col, pos);
277         else
278             grid->GetTable()->SetValue(row, col,wxString::Format(wxT("%i"),pos));
279     }
280 
281     return changed;
282 }
283 
284 #endif // wxUSE_COMBOBOX
285 
286 // ----------------------------------------------------------------------------
287 // wxGridCellAutoWrapStringEditor
288 // ----------------------------------------------------------------------------
289 
290 void
Create(wxWindow * parent,wxWindowID id,wxEvtHandler * evtHandler)291 wxGridCellAutoWrapStringEditor::Create(wxWindow* parent,
292                                        wxWindowID id,
293                                        wxEvtHandler* evtHandler)
294 {
295   m_control = new wxTextCtrl(parent, id, wxEmptyString,
296                              wxDefaultPosition, wxDefaultSize,
297                              wxTE_MULTILINE | wxTE_RICH);
298 
299 
300   wxGridCellEditor::Create(parent, id, evtHandler);
301 }
302 
303 void
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rectCell,int row,int col,bool isSelected)304 wxGridCellAutoWrapStringRenderer::Draw(wxGrid& grid,
305                       wxGridCellAttr& attr,
306                       wxDC& dc,
307                       const wxRect& rectCell,
308                       int row, int col,
309                       bool isSelected) {
310 
311 
312     wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
313 
314     // now we only have to draw the text
315     SetTextColoursAndFont(grid, attr, dc, isSelected);
316 
317     int horizAlign, vertAlign;
318     attr.GetAlignment(&horizAlign, &vertAlign);
319 
320     wxRect rect = rectCell;
321     rect.Inflate(-1);
322 
323     grid.DrawTextRectangle(dc, GetTextLines(grid,dc,attr,rect,row,col),
324                            rect, horizAlign, vertAlign);
325 }
326 
327 
328 wxArrayString
GetTextLines(wxGrid & grid,wxDC & dc,const wxGridCellAttr & attr,const wxRect & rect,int row,int col)329 wxGridCellAutoWrapStringRenderer::GetTextLines(wxGrid& grid,
330                                                wxDC& dc,
331                                                const wxGridCellAttr& attr,
332                                                const wxRect& rect,
333                                                int row, int col)
334 {
335     wxString  data = grid.GetCellValue(row, col);
336 
337     wxArrayString lines;
338     dc.SetFont(attr.GetFont());
339 
340     //Taken from wxGrid again!
341     wxCoord x = 0, y = 0, curr_x = 0;
342     wxCoord max_x = rect.GetWidth();
343 
344     dc.SetFont(attr.GetFont());
345     wxStringTokenizer tk(data , _T(" \n\t\r"));
346     wxString thisline = wxEmptyString;
347 
348     while ( tk.HasMoreTokens() )
349     {
350         wxString tok = tk.GetNextToken();
351         //FIXME: this causes us to print an extra unnecesary
352         //       space at the end of the line. But it
353         //       is invisible , simplifies the size calculation
354         //       and ensures tokens are separated in the display
355         tok += _T(" ");
356 
357         dc.GetTextExtent(tok, &x, &y);
358         if ( curr_x + x > max_x)
359         {
360             if ( curr_x == 0 )
361             {
362                 // this means that a single token is wider than the maximal
363                 // width -- still use it as is as we need to show at least the
364                 // part of it which fits
365                 lines.Add(tok);
366             }
367             else
368             {
369                 lines.Add(thisline);
370                 thisline = tok;
371                 curr_x = x;
372             }
373         }
374         else
375         {
376             thisline+= tok;
377             curr_x += x;
378         }
379     }
380     //Add last line
381     lines.Add( wxString(thisline) );
382 
383     return lines;
384 }
385 
386 
387 wxSize
GetBestSize(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,int row,int col)388 wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid& grid,
389                                               wxGridCellAttr& attr,
390                                               wxDC& dc,
391                                               int row, int col)
392 {
393     wxCoord x,y, height , width = grid.GetColSize(col) -20;
394     // for width, subtract 20 because ColSize includes a magin of 10 pixels
395     // that we do not want here and because we always start with an increment
396     // by 10 in the loop below.
397     int count = 250; //Limit iterations..
398 
399     wxRect rect(0,0,width,10);
400 
401     // M is a nice large character 'y' gives descender!.
402     dc.GetTextExtent(wxT("My"), &x, &y);
403 
404     do
405     {
406         width+=10;
407         rect.SetWidth(width);
408         height = y * (wx_truncate_cast(wxCoord, GetTextLines(grid,dc,attr,rect,row,col).GetCount()));
409         count--;
410     // Search for a shape no taller than the golden ratio.
411     } while (count && (width  < (height*1.68)) );
412 
413 
414     return wxSize(width,height);
415 }
416 
417 #endif // wxUSE_GRID
418 
419