]> git.saurik.com Git - wxWidgets.git/blame - src/html/m_tables.cpp
added test for writing empty value to the config
[wxWidgets.git] / src / html / m_tables.cpp
CommitLineData
5526e819 1/////////////////////////////////////////////////////////////////////////////
c88293a4 2// Name: m_tables.cpp
5526e819
VS
3// Purpose: wxHtml module for tables
4// Author: Vaclav Slavik
69941f05 5// RCS-ID: $Id$
5526e819
VS
6// Copyright: (c) 1999 Vaclav Slavik
7// Licence: wxWindows Licence
8/////////////////////////////////////////////////////////////////////////////
9
3364ab79
RS
10#ifdef __GNUG__
11#pragma implementation
12#endif
13
3096bd2f 14#include "wx/wxprec.h"
3364ab79 15
314260fb 16#include "wx/defs.h"
f6bcfd97 17#if wxUSE_HTML && wxUSE_STREAMS
3364ab79
RS
18#ifdef __BORDLANDC__
19#pragma hdrstop
20#endif
21
22#ifndef WXPRECOMP
3364ab79
RS
23#endif
24
5526e819
VS
25
26/*
27REMARKS:
c88293a4 28 1. This version of m_tables doesn't support auto-layout algorithm.
5526e819
VS
29 This means that all columns are of same width unless explicitly specified.
30*/
31
32
69941f05
VS
33#include "wx/html/forcelnk.h"
34#include "wx/html/m_templ.h"
5526e819 35
69941f05 36#include "wx/html/htmlcell.h"
5526e819 37
c88293a4 38FORCE_LINK_ME(m_tables)
5526e819
VS
39
40
41#define TABLE_BORDER_CLR_1 wxColour(0xC5, 0xC2, 0xC5)
42#define TABLE_BORDER_CLR_2 wxColour(0x62, 0x61, 0x62)
43
44
45//-----------------------------------------------------------------------------
46// wxHtmlTableCell
47//-----------------------------------------------------------------------------
48
49
50typedef struct {
04dbb646 51 int width, units;
8bd72d90 52 // universal
04dbb646 53 int leftpos, pixwidth, maxrealwidth;
8bd72d90 54 // temporary (depends on width of table)
5526e819
VS
55 } colStruct;
56
57typedef enum {
58 cellSpan,
59 cellUsed,
60 cellFree
61 } cellState;
62
63typedef struct {
64 wxHtmlContainerCell *cont;
65 int colspan, rowspan;
66 int minheight, valign;
67 cellState flag;
68 } cellStruct;
69
70
71class wxHtmlTableCell : public wxHtmlContainerCell
72{
73 protected:
74 /* These are real attributes: */
75 bool m_HasBorders;
76 // should we draw borders or not?
77 int m_NumCols, m_NumRows;
78 // number of columns; rows
79 colStruct *m_ColsInfo;
80 // array of column information
81 cellStruct **m_CellInfo;
82 // 2D array of all cells in the table : m_CellInfo[row][column]
83 int m_Spacing;
84 // spaces between cells
85 int m_Padding;
86 // cells internal indentation
87
88 private:
89 /* ...and these are valid only during parsing of table: */
90 int m_ActualCol, m_ActualRow;
91 // number of actual column (ranging from 0..m_NumCols)
92
93 // default values (for table and row):
8bd72d90 94 wxColour m_tBkg, m_rBkg;
5526e819
VS
95 wxString m_tValign, m_rValign;
96
edbd0635
VS
97 double m_PixelScale;
98
5526e819
VS
99
100 public:
edbd0635 101 wxHtmlTableCell(wxHtmlContainerCell *parent, const wxHtmlTag& tag, double pixel_scale = 1.0);
5526e819
VS
102 ~wxHtmlTableCell();
103 virtual void Layout(int w);
104
105 void AddRow(const wxHtmlTag& tag);
106 void AddCell(wxHtmlContainerCell *cell, const wxHtmlTag& tag);
107 private:
108 void ReallocCols(int cols);
109 void ReallocRows(int rows);
110 // reallocates memory to given number of cols/rows
111 // and changes m_NumCols/m_NumRows value to reflect this change
112 // NOTE! You CAN'T change m_NumCols/m_NumRows before calling this!!
113};
114
115
116
edbd0635 117wxHtmlTableCell::wxHtmlTableCell(wxHtmlContainerCell *parent, const wxHtmlTag& tag, double pixel_scale)
5526e819
VS
118 : wxHtmlContainerCell(parent)
119{
edbd0635 120 m_PixelScale = pixel_scale;
b0bdbbfe
VS
121 m_HasBorders =
122 (tag.HasParam(wxT("BORDER")) && tag.GetParam(wxT("BORDER")) != wxT("0"));
5526e819
VS
123 m_ColsInfo = NULL;
124 m_NumCols = m_NumRows = 0;
125 m_CellInfo = NULL;
126 m_ActualCol = m_ActualRow = -1;
127
128 /* scan params: */
04dbb646 129 if (tag.HasParam(wxT("BGCOLOR")))
8bd72d90 130 tag.GetParamAsColour(wxT("BGCOLOR"), &m_tBkg);
04dbb646
VZ
131 if (tag.HasParam(wxT("VALIGN")))
132 m_tValign = tag.GetParam(wxT("VALIGN"));
133 else
8bd72d90
VS
134 m_tValign = wxEmptyString;
135 if (!tag.GetParamAsInt(wxT("CELLSPACING"), &m_Spacing))
136 m_Spacing = 2;
137 if (!tag.GetParamAsInt(wxT("CELLPADDING"), &m_Padding))
138 m_Padding = 3;
edbd0635
VS
139 m_Spacing = (int)(m_PixelScale * (double)m_Spacing);
140 m_Padding = (int)(m_PixelScale * (double)m_Padding);
5526e819
VS
141
142 if (m_HasBorders)
143 SetBorder(TABLE_BORDER_CLR_1, TABLE_BORDER_CLR_2);
144}
145
146
147
148wxHtmlTableCell::~wxHtmlTableCell()
149{
150 if (m_ColsInfo) free(m_ColsInfo);
04dbb646 151 if (m_CellInfo)
4f9297b0 152 {
5526e819
VS
153 for (int i = 0; i < m_NumRows; i++)
154 free(m_CellInfo[i]);
155 free(m_CellInfo);
156 }
157}
158
159
160
161void wxHtmlTableCell::ReallocCols(int cols)
162{
163 int i,j;
164
04dbb646 165 for (i = 0; i < m_NumRows; i++)
4f9297b0 166 {
5526e819
VS
167 m_CellInfo[i] = (cellStruct*) realloc(m_CellInfo[i], sizeof(cellStruct) * cols);
168 for (j = m_NumCols; j < cols; j++)
169 m_CellInfo[i][j].flag = cellFree;
170 }
171
172 m_ColsInfo = (colStruct*) realloc(m_ColsInfo, sizeof(colStruct) * cols);
04dbb646 173 for (j = m_NumCols; j < cols; j++)
4f9297b0 174 {
5526e819 175 m_ColsInfo[j].width = 0;
efba2b89 176 m_ColsInfo[j].units = wxHTML_UNITS_PERCENT;
5526e819
VS
177 }
178
179 m_NumCols = cols;
180}
181
182
183
184void wxHtmlTableCell::ReallocRows(int rows)
185{
186 m_CellInfo = (cellStruct**) realloc(m_CellInfo, sizeof(cellStruct*) * rows);
04dbb646 187 for (int row = m_NumRows; row < rows ; row++)
80eab469 188 {
04dbb646 189 if (m_NumCols == 0)
80eab469 190 m_CellInfo[row] = NULL;
04dbb646 191 else
80eab469
VS
192 {
193 m_CellInfo[row] = (cellStruct*) malloc(sizeof(cellStruct) * m_NumCols);
194 for (int col = 0; col < m_NumCols; col++)
195 m_CellInfo[row][col].flag = cellFree;
196 }
5526e819 197 }
5526e819
VS
198 m_NumRows = rows;
199}
200
201
5526e819
VS
202void wxHtmlTableCell::AddRow(const wxHtmlTag& tag)
203{
5526e819 204 m_ActualCol = -1;
d361bbff
VS
205 // VS: real allocation of row entry is done in AddCell in order
206 // to correctly handle empty rows (i.e. "<tr></tr>")
207 // m_ActualCol == -1 indicates that AddCell has to allocate new row.
5526e819 208
d361bbff 209 // scan params:
5526e819 210 m_rBkg = m_tBkg;
04dbb646 211 if (tag.HasParam(wxT("BGCOLOR")))
8bd72d90 212 tag.GetParamAsColour(wxT("BGCOLOR"), &m_rBkg);
04dbb646
VZ
213 if (tag.HasParam(wxT("VALIGN")))
214 m_rValign = tag.GetParam(wxT("VALIGN"));
215 else
d361bbff 216 m_rValign = m_tValign;
5526e819
VS
217}
218
219
220
221void wxHtmlTableCell::AddCell(wxHtmlContainerCell *cell, const wxHtmlTag& tag)
222{
d361bbff
VS
223 // Is this cell in new row?
224 // VS: we can't do it in AddRow, see my comment there
225 if (m_ActualCol == -1)
226 {
227 if (m_ActualRow + 1 > m_NumRows - 1)
228 ReallocRows(m_ActualRow + 2);
229 m_ActualRow++;
230 }
231
232 // cells & columns:
04dbb646 233 do
4f9297b0 234 {
5526e819 235 m_ActualCol++;
04dbb646 236 } while ((m_ActualCol < m_NumCols) &&
8bd72d90 237 (m_CellInfo[m_ActualRow][m_ActualCol].flag != cellFree));
04dbb646 238
5526e819
VS
239 if (m_ActualCol > m_NumCols - 1)
240 ReallocCols(m_ActualCol + 1);
241
242 int r = m_ActualRow, c = m_ActualCol;
243
244 m_CellInfo[r][c].cont = cell;
245 m_CellInfo[r][c].colspan = 1;
246 m_CellInfo[r][c].rowspan = 1;
247 m_CellInfo[r][c].flag = cellUsed;
248 m_CellInfo[r][c].minheight = 0;
efba2b89 249 m_CellInfo[r][c].valign = wxHTML_ALIGN_TOP;
5526e819
VS
250
251 /* scan for parameters: */
252
253 // width:
254 {
8bd72d90 255 if (tag.HasParam(wxT("WIDTH")))
2fa3b707 256 {
8bd72d90 257 wxString wd = tag.GetParam(wxT("WIDTH"));
5526e819 258
8bd72d90 259 if (wd[wd.Length()-1] == wxT('%'))
2fa3b707 260 {
66a77a74 261 wxSscanf(wd.c_str(), wxT("%i%%"), &m_ColsInfo[c].width);
efba2b89 262 m_ColsInfo[c].units = wxHTML_UNITS_PERCENT;
5526e819 263 }
04dbb646 264 else
2fa3b707 265 {
66a77a74 266 wxSscanf(wd.c_str(), wxT("%i"), &m_ColsInfo[c].width);
edbd0635 267 m_ColsInfo[c].width = (int)(m_PixelScale * (double)m_ColsInfo[c].width);
efba2b89 268 m_ColsInfo[c].units = wxHTML_UNITS_PIXELS;
5526e819
VS
269 }
270 }
271 }
272
273
274 // spanning:
275 {
8bd72d90
VS
276 tag.GetParamAsInt(wxT("COLSPAN"), &m_CellInfo[r][c].colspan);
277 tag.GetParamAsInt(wxT("ROWSPAN"), &m_CellInfo[r][c].rowspan);
04dbb646 278 if ((m_CellInfo[r][c].colspan != 1) || (m_CellInfo[r][c].rowspan != 1))
2fa3b707 279 {
5526e819
VS
280 int i, j;
281
04dbb646 282 if (r + m_CellInfo[r][c].rowspan > m_NumRows)
8bd72d90 283 ReallocRows(r + m_CellInfo[r][c].rowspan);
04dbb646 284 if (c + m_CellInfo[r][c].colspan > m_NumCols)
8bd72d90 285 ReallocCols(c + m_CellInfo[r][c].colspan);
5526e819
VS
286 for (i = r; i < r + m_CellInfo[r][c].rowspan; i++)
287 for (j = c; j < c + m_CellInfo[r][c].colspan; j++)
288 m_CellInfo[i][j].flag = cellSpan;
289 m_CellInfo[r][c].flag = cellUsed;
290 }
291 }
292
293 //background color:
294 {
8bd72d90 295 wxColour bk = m_rBkg;
04dbb646 296 if (tag.HasParam(wxT("BGCOLOR")))
8bd72d90
VS
297 tag.GetParamAsColour(wxT("BGCOLOR"), &bk);
298 if (bk.Ok())
299 cell->SetBackgroundColour(bk);
5526e819
VS
300 }
301 if (m_HasBorders)
4f9297b0 302 cell->SetBorder(TABLE_BORDER_CLR_2, TABLE_BORDER_CLR_1);
5526e819
VS
303
304 // vertical alignment:
305 {
306 wxString valign;
04dbb646
VZ
307 if (tag.HasParam(wxT("VALIGN")))
308 valign = tag.GetParam(wxT("VALIGN"));
309 else
8bd72d90 310 valign = m_tValign;
5526e819 311 valign.MakeUpper();
04dbb646 312 if (valign == wxT("TOP"))
8bd72d90 313 m_CellInfo[r][c].valign = wxHTML_ALIGN_TOP;
04dbb646 314 else if (valign == wxT("BOTTOM"))
8bd72d90 315 m_CellInfo[r][c].valign = wxHTML_ALIGN_BOTTOM;
efba2b89 316 else m_CellInfo[r][c].valign = wxHTML_ALIGN_CENTER;
5526e819
VS
317 }
318
4f9297b0 319 cell->SetIndent(m_Padding, wxHTML_INDENT_ALL, wxHTML_UNITS_PIXELS);
5526e819
VS
320}
321
322
323
324
325
326void wxHtmlTableCell::Layout(int w)
327{
328 /*
329
330 WIDTH ADJUSTING :
331
332 */
333
04dbb646 334 if (m_WidthFloatUnits == wxHTML_UNITS_PERCENT)
4f9297b0 335 {
5526e819
VS
336 if (m_WidthFloat < 0) m_Width = (100 + m_WidthFloat) * w / 100;
337 else m_Width = m_WidthFloat * w / 100;
338 }
04dbb646 339 else
4f9297b0 340 {
5526e819
VS
341 if (m_WidthFloat < 0) m_Width = w + m_WidthFloat;
342 else m_Width = m_WidthFloat;
343 }
344
345
346 /*
347
348 LAYOUTING :
349
350 */
351
352 /* 1. setup columns widths: */
353 {
354 int wpix = m_Width - (m_NumCols + 1) * m_Spacing;
355 int i, j;
356 int wtemp = 0;
357
358 // 1a. setup fixed-width columns:
359 for (i = 0; i < m_NumCols; i++)
efba2b89 360 if (m_ColsInfo[i].units == wxHTML_UNITS_PIXELS)
5526e819
VS
361 wpix -= (m_ColsInfo[i].pixwidth = m_ColsInfo[i].width);
362
363 // 1b. setup floating-width columns:
364 for (i = 0; i < m_NumCols; i++)
efba2b89 365 if ((m_ColsInfo[i].units == wxHTML_UNITS_PERCENT) && (m_ColsInfo[i].width != 0))
5526e819
VS
366 wtemp += (m_ColsInfo[i].pixwidth = m_ColsInfo[i].width * wpix / 100);
367 wpix -= wtemp;
368
369 // 1c. setup defalut columns (no width specification supplied):
370 // NOTE! This algorithm doesn't conform to HTML standard : it assigns equal widths
371 // instead of optimal
372 for (i = j = 0; i < m_NumCols; i++)
373 if (m_ColsInfo[i].width == 0) j++;
374 for (i = 0; i < m_NumCols; i++)
375 if (m_ColsInfo[i].width == 0)
376 m_ColsInfo[i].pixwidth = wpix / j;
377 }
378
379 /* 2. compute positions of columns: */
380 {
381 int wpos = m_Spacing;
04dbb646 382 for (int i = 0; i < m_NumCols; i++)
2fa3b707 383 {
5526e819
VS
384 m_ColsInfo[i].leftpos = wpos;
385 wpos += m_ColsInfo[i].pixwidth + m_Spacing;
386 }
387 }
388
389 /* 3. sub-layout all cells: */
390 {
2776d7c3 391 int *ypos = new int[m_NumRows + 1];
5526e819
VS
392
393 int actcol, actrow;
394 int fullwid;
395 wxHtmlContainerCell *actcell;
396
2fa3b707
VS
397 ypos[0] = m_Spacing;
398 for (actrow = 1; actrow <= m_NumRows; actrow++) ypos[actrow] = -1;
04dbb646 399 for (actrow = 0; actrow < m_NumRows; actrow++)
2fa3b707
VS
400 {
401 if (ypos[actrow] == -1) ypos[actrow] = ypos[actrow-1];
5526e819
VS
402 // 3a. sub-layout and detect max height:
403
404 for (actcol = 0; actcol < m_NumCols; actcol++) {
405 if (m_CellInfo[actrow][actcol].flag != cellUsed) continue;
406 actcell = m_CellInfo[actrow][actcol].cont;
407 fullwid = 0;
408 for (int i = actcol; i < m_CellInfo[actrow][actcol].colspan + actcol; i++)
409 fullwid += m_ColsInfo[i].pixwidth;
a97a264f 410 fullwid += (m_CellInfo[actrow][actcol].colspan - 1) * m_Spacing;
4f9297b0
VS
411 actcell->SetMinHeight(m_CellInfo[actrow][actcol].minheight, m_CellInfo[actrow][actcol].valign);
412 actcell->Layout(fullwid);
5526e819 413
4f9297b0 414 if (ypos[actrow] + actcell->GetHeight() + m_CellInfo[actrow][actcol].rowspan * m_Spacing > ypos[actrow + m_CellInfo[actrow][actcol].rowspan])
5526e819 415 ypos[actrow + m_CellInfo[actrow][actcol].rowspan] =
4f9297b0 416 ypos[actrow] + actcell->GetHeight() + m_CellInfo[actrow][actcol].rowspan * m_Spacing;
5526e819
VS
417 }
418 }
419
04dbb646 420 for (actrow = 0; actrow < m_NumRows; actrow++)
2fa3b707 421 {
5526e819
VS
422 // 3b. place cells in row & let'em all have same height:
423
04dbb646 424 for (actcol = 0; actcol < m_NumCols; actcol++)
2fa3b707 425 {
5526e819
VS
426 if (m_CellInfo[actrow][actcol].flag != cellUsed) continue;
427 actcell = m_CellInfo[actrow][actcol].cont;
4f9297b0 428 actcell->SetMinHeight(
a97a264f 429 ypos[actrow + m_CellInfo[actrow][actcol].rowspan] - ypos[actrow] - m_Spacing,
5526e819
VS
430 m_CellInfo[actrow][actcol].valign);
431 fullwid = 0;
432 for (int i = actcol; i < m_CellInfo[actrow][actcol].colspan + actcol; i++)
433 fullwid += m_ColsInfo[i].pixwidth;
a97a264f 434 fullwid += (m_CellInfo[actrow][actcol].colspan - 1) * m_Spacing;
4f9297b0
VS
435 actcell->Layout(fullwid);
436 actcell->SetPos(m_ColsInfo[actcol].leftpos, ypos[actrow]);
5526e819 437 }
5526e819
VS
438 }
439 m_Height = ypos[m_NumRows];
2776d7c3 440 delete[] ypos;
5526e819
VS
441 }
442}
443
444
445
446
447
448
449//-----------------------------------------------------------------------------
450// The tables handler:
451//-----------------------------------------------------------------------------
452
453
454TAG_HANDLER_BEGIN(TABLE, "TABLE,TR,TD,TH")
455
456 TAG_HANDLER_VARS
457 wxHtmlTableCell* m_Table;
458 wxString m_tAlign, m_rAlign;
459 int m_OldAlign;
460
461 TAG_HANDLER_CONSTR(TABLE)
462 {
463 m_Table = NULL;
01325161
VS
464 m_tAlign = m_rAlign = wxEmptyString;
465 m_OldAlign = wxHTML_ALIGN_LEFT;
5526e819
VS
466 }
467
468
469 TAG_HANDLER_PROC(tag)
470 {
471 wxHtmlContainerCell *c;
472
473 // new table started, backup upper-level table (if any) and create new:
04dbb646 474 if (tag.GetName() == wxT("TABLE"))
2fa3b707 475 {
5526e819
VS
476 wxHtmlTableCell *oldt = m_Table;
477 wxHtmlContainerCell *oldcont;
478 int m_OldAlign;
479
4f9297b0 480 oldcont = c = m_WParser->OpenContainer();
5526e819 481
4f9297b0
VS
482 c->SetWidthFloat(tag, m_WParser->GetPixelScale());
483 m_Table = new wxHtmlTableCell(c, tag, m_WParser->GetPixelScale());
484 m_OldAlign = m_WParser->GetAlign();
5526e819 485 m_tAlign = wxEmptyString;
8bd72d90
VS
486 if (tag.HasParam(wxT("ALIGN")))
487 m_tAlign = tag.GetParam(wxT("ALIGN"));
5526e819
VS
488
489 ParseInner(tag);
490
4f9297b0
VS
491 m_WParser->SetAlign(m_OldAlign);
492 m_WParser->SetContainer(oldcont);
493 m_WParser->CloseContainer();
5526e819
VS
494 m_Table = oldt;
495 return TRUE;
496 }
497
498
211dfedd 499 else if (m_Table)
2fa3b707 500 {
5526e819 501 // new row in table
04dbb646 502 if (tag.GetName() == wxT("TR"))
2fa3b707 503 {
4f9297b0 504 m_Table->AddRow(tag);
5526e819 505 m_rAlign = m_tAlign;
04dbb646 506 if (tag.HasParam(wxT("ALIGN")))
8bd72d90 507 m_rAlign = tag.GetParam(wxT("ALIGN"));
5526e819
VS
508 }
509
510 // new cell
04dbb646 511 else
2fa3b707 512 {
4f9297b0
VS
513 m_WParser->SetAlign(m_OldAlign);
514 c = m_WParser->SetContainer(new wxHtmlContainerCell(m_Table));
515 m_Table->AddCell(c, tag);
5526e819 516
4f9297b0 517 m_WParser->OpenContainer();
5526e819 518
04dbb646 519 if (tag.GetName() == wxT("TH")) /*header style*/
2fa3b707 520 {
4f9297b0 521 m_WParser->SetAlign(wxHTML_ALIGN_CENTER);
5526e819
VS
522 }
523
524 {
525 wxString als;
526
527 als = m_rAlign;
04dbb646 528 if (tag.HasParam(wxT("ALIGN")))
8bd72d90 529 als = tag.GetParam(wxT("ALIGN"));
5526e819 530 als.MakeUpper();
04dbb646 531 if (als == wxT("RIGHT"))
8bd72d90 532 m_WParser->SetAlign(wxHTML_ALIGN_RIGHT);
04dbb646 533 else if (als == wxT("CENTER"))
8bd72d90 534 m_WParser->SetAlign(wxHTML_ALIGN_CENTER);
5526e819 535 }
4f9297b0 536 m_WParser->OpenContainer();
5526e819
VS
537 }
538 }
539 return FALSE;
540 }
541
542TAG_HANDLER_END(TABLE)
543
544
545
546
547
548TAGS_MODULE_BEGIN(Tables)
549
550 TAGS_MODULE_ADD(TABLE)
551
552TAGS_MODULE_END(Tables)
553
554
555#endif