/src/libwps/src/lib/WPSTable.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | | /* libwps |
3 | | * Version: MPL 2.0 / LGPLv2.1+ |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * Major Contributor(s): |
10 | | * Copyright (C) 2009, 2011 Alonso Laurent (alonso@loria.fr) |
11 | | * Copyright (C) 2006, 2007 Andrew Ziem |
12 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
13 | | * Copyright (C) 2004 Marc Maurer (uwog@uwog.net) |
14 | | * Copyright (C) 2003-2005 William Lachance (william.lachance@sympatico.ca) |
15 | | * |
16 | | * For minor contributions see the git repository. |
17 | | * |
18 | | * Alternatively, the contents of this file may be used under the terms |
19 | | * of the GNU Lesser General Public License Version 2.1 or later |
20 | | * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are |
21 | | * applicable instead of those above. |
22 | | * |
23 | | * For further information visit http://libwps.sourceforge.net |
24 | | */ |
25 | | |
26 | | /* |
27 | | * Structure to store and construct a table from an unstructured list |
28 | | * of cell |
29 | | * |
30 | | */ |
31 | | |
32 | | #include <iostream> |
33 | | #include <set> |
34 | | |
35 | | #include "WPSContentListener.h" |
36 | | #include "WPSCell.h" |
37 | | |
38 | | #include "WPSTable.h" |
39 | | |
40 | | //////////////////////////////////////////////////////////// |
41 | | // WPSColumnFormat |
42 | | std::ostream &operator<<(std::ostream &o, WPSColumnFormat const &column) |
43 | 0 | { |
44 | 0 | if (column.m_width>=0) |
45 | 0 | { |
46 | 0 | if (column.m_isPercentWidth) |
47 | 0 | o<<"w=" << column.m_width << "%,"; |
48 | 0 | else |
49 | 0 | o<<"w=" << column.m_width << ","; |
50 | 0 | } |
51 | 0 | if (column.m_useOptimalWidth) o << "optimal[h],"; |
52 | 0 | if (column.m_isHeader) o << "table[header],"; |
53 | 0 | if (column.m_numRepeat>1) o << "repeat=" << column.m_numRepeat << ","; |
54 | 0 | return o; |
55 | 0 | } |
56 | | |
57 | | void WPSColumnFormat::addTo(librevenge::RVNGPropertyList &propList) const |
58 | 1.56M | { |
59 | 1.56M | if (m_width>=0) |
60 | 1.55M | propList.insert("style:column-width", double(m_width), m_isPercentWidth ? librevenge::RVNG_PERCENT : librevenge::RVNG_POINT); |
61 | 1.56M | if (m_useOptimalWidth) |
62 | 907k | propList.insert("style:use-optimal-column-width", true); |
63 | 1.56M | if (m_isHeader) |
64 | 0 | propList.insert("librevenge:is-header-column", true); // checkme |
65 | 1.56M | if (m_numRepeat>1) |
66 | 457k | propList.insert("table:number-columns-repeated", m_numRepeat); |
67 | 1.56M | } |
68 | | |
69 | | //////////////////////////////////////////////////////////// |
70 | | // WPSRowFormat |
71 | | std::ostream &operator<<(std::ostream &o, WPSRowFormat const &row) |
72 | 0 | { |
73 | 0 | if (row.m_height>=0) |
74 | 0 | { |
75 | 0 | if (row.m_isMinimalHeight) |
76 | 0 | o<<"h[min]=" << row.m_height << ","; |
77 | 0 | else |
78 | 0 | o<<"h=" << row.m_height << ","; |
79 | 0 | } |
80 | 0 | if (row.m_useOptimalHeight) o << "optimal[h],"; |
81 | 0 | if (row.m_isHeader) o << "table[header],"; |
82 | 0 | return o; |
83 | 0 | } |
84 | | |
85 | | void WPSRowFormat::addTo(librevenge::RVNGPropertyList &propList) const |
86 | 6.15M | { |
87 | 6.15M | if (m_height>=0) |
88 | 6.15M | { |
89 | 6.15M | if (m_isMinimalHeight) |
90 | 1.37M | propList.insert("style:min-row-height", double(m_height), librevenge::RVNG_POINT); |
91 | 4.78M | else |
92 | 4.78M | propList.insert("style:row-height", double(m_height), librevenge::RVNG_POINT); |
93 | 6.15M | } |
94 | 6.15M | if (m_useOptimalHeight) |
95 | 5.00k | propList.insert("style:use-optimal-row-height", true); |
96 | 6.15M | propList.insert("librevenge:is-header-row", m_isHeader); |
97 | 6.15M | } |
98 | | |
99 | | //////////////////////////////////////////////////////////// |
100 | | // destructor, ... |
101 | | WPSTable::~WPSTable() |
102 | 339k | { |
103 | 339k | } |
104 | | |
105 | | void WPSTable::add(WPSCellPtr &cell) |
106 | 214k | { |
107 | 214k | m_cellsList.push_back(cell); |
108 | 214k | } |
109 | | |
110 | | WPSCellPtr WPSTable::getCell(int id) |
111 | 36.3k | { |
112 | 36.3k | if (id < 0 || id >= int(m_cellsList.size())) |
113 | 0 | { |
114 | 0 | WPS_DEBUG_MSG(("WPSTable::get: cell %d does not exists\n",id)); |
115 | 0 | return std::shared_ptr<WPSCell>(); |
116 | 0 | } |
117 | 36.3k | return m_cellsList[size_t(id)]; |
118 | 36.3k | } |
119 | | |
120 | | //////////////////////////////////////////////////////////// |
121 | | // build the table structure |
122 | | bool WPSTable::buildStructures() |
123 | 391 | { |
124 | 391 | if (m_colsSize.size()) |
125 | 66 | return true; |
126 | | |
127 | 325 | size_t nCells = m_cellsList.size(); |
128 | 325 | std::vector<float> listPositions[2]; |
129 | 975 | for (int dim = 0; dim < 2; dim++) |
130 | 650 | { |
131 | 650 | WPSCell::Compare compareFunction(dim); |
132 | 650 | std::set<WPSCell::Compare::Point, |
133 | 650 | WPSCell::Compare> set(compareFunction); |
134 | 2.69k | for (size_t c = 0; c < nCells; c++) |
135 | 2.04k | { |
136 | 2.04k | set.insert(WPSCell::Compare::Point(0, m_cellsList[c].get())); |
137 | 2.04k | set.insert(WPSCell::Compare::Point(1, m_cellsList[c].get())); |
138 | 2.04k | } |
139 | | |
140 | 650 | std::vector<float> positions; |
141 | 650 | float maxPosiblePos=0; |
142 | 650 | int actCell = -1; |
143 | 650 | for (auto const &it : set) |
144 | 4.09k | { |
145 | 4.09k | float pos = it.getPos(dim); |
146 | 4.09k | if (actCell < 0 || pos > maxPosiblePos) |
147 | 2.09k | { |
148 | 2.09k | actCell++; |
149 | 2.09k | positions.push_back(pos); |
150 | 2.09k | maxPosiblePos = pos+2.0f; // 2 pixel ok |
151 | 2.09k | } |
152 | 4.09k | if (it.m_which == 0 && it.getPos(dim)-2.0f < maxPosiblePos) |
153 | 2.01k | maxPosiblePos = pos; |
154 | 4.09k | } |
155 | 650 | listPositions[dim] = positions; |
156 | 650 | } |
157 | 325 | std::vector<int> numYSet(listPositions[1].size(), 0); |
158 | 325 | std::vector<int> numYUnset(listPositions[1].size(), 0); |
159 | 325 | for (auto const &cell : m_cellsList) |
160 | 896 | { |
161 | 896 | int cellPos[2], spanCell[2]; |
162 | 2.45k | for (int dim = 0; dim < 2; dim++) |
163 | 1.68k | { |
164 | 1.68k | float const pt[2] = { cell->box().min()[dim], |
165 | 1.68k | cell->box().max()[dim] |
166 | 1.68k | }; |
167 | 1.68k | std::vector<float> const &pos = listPositions[dim]; |
168 | 1.68k | size_t numPos = pos.size(); |
169 | 1.68k | size_t i = 0; |
170 | 2.57k | while (i+1 < numPos && pos[i+1] < pt[0]) |
171 | 882 | i++; |
172 | 2.15k | while (i+1 < numPos && (pos[i]+pos[i+1])/2 < pt[0]) |
173 | 465 | i++; |
174 | 1.68k | if (i+1 > numPos) |
175 | 0 | { |
176 | 0 | WPS_DEBUG_MSG(("WPSTable::buildStructures: impossible to find cell position !!!\n")); |
177 | 0 | return false; |
178 | 0 | } |
179 | 1.68k | cellPos[dim] = int(i); |
180 | 1.92k | while (i+1 < numPos && pos[i+1] < pt[1]) |
181 | 233 | i++; |
182 | 1.68k | if (i+1 < numPos && (pos[i]+pos[i+1])/2 < pt[1]) |
183 | 1.29k | i++; |
184 | 1.68k | spanCell[dim] = int(i)-cellPos[dim]; |
185 | 1.68k | if (spanCell[dim]==0 && |
186 | 390 | (cell->box().size()[dim]<0||cell->box().size()[dim]>0)) |
187 | 135 | { |
188 | 135 | WPS_DEBUG_MSG(("WPSTable::buildStructures: impossible to find span number !!!\n")); |
189 | 135 | return false; |
190 | 135 | } |
191 | 1.55k | if (spanCell[dim] > 1 && |
192 | 158 | pos[size_t(cellPos[dim])]+2.0f > pos[size_t(cellPos[dim]+1)]) |
193 | 89 | { |
194 | 89 | spanCell[dim]--; |
195 | 89 | cellPos[dim]++; |
196 | 89 | } |
197 | 1.55k | if (spanCell[dim] > 1 && |
198 | 99 | pos[size_t(cellPos[dim])]+2.0f > pos[size_t(cellPos[dim]+1)]) |
199 | 30 | { |
200 | 30 | spanCell[dim]--; |
201 | 30 | cellPos[dim]++; |
202 | 30 | } |
203 | 1.55k | } |
204 | 761 | cell->m_position = Vec2i(cellPos[0], cellPos[1]); |
205 | 761 | cell->m_numberCellSpanned = Vec2i(spanCell[0], spanCell[1]); |
206 | 761 | if (spanCell[1] > 0) |
207 | 650 | { |
208 | 1.34k | for (int x = cellPos[0]; x < cellPos[0]+spanCell[0]; x++) |
209 | 692 | { |
210 | 692 | if (cell->isVerticalSet()) |
211 | 160 | numYSet[size_t(cellPos[1]+spanCell[1]-1)]++; |
212 | 532 | else |
213 | 532 | numYUnset[size_t(cellPos[1]+spanCell[1]-1)]++; |
214 | 692 | } |
215 | 650 | } |
216 | 761 | } |
217 | | // finally update the row/col size |
218 | 570 | for (int dim = 0; dim < 2; dim++) |
219 | 380 | { |
220 | 380 | std::vector<float> const &pos = listPositions[dim]; |
221 | 380 | size_t numPos = pos.size(); |
222 | 380 | if (!numPos) continue; |
223 | 358 | std::vector<float> &res = (dim==0) ? m_colsSize : m_rowsSize; |
224 | 358 | res.resize(numPos-1); |
225 | 1.12k | for (size_t i = 0; i < numPos-1; i++) |
226 | 769 | { |
227 | 769 | if (dim==0 || numYUnset[i]==0) |
228 | 524 | res[i] = pos[i+1]-pos[i]; |
229 | 245 | else if (numYSet[i]) |
230 | 38 | res[i] = -(pos[i+1]-pos[i]); |
231 | 207 | else |
232 | 207 | res[i] = 0; |
233 | 769 | } |
234 | 358 | } |
235 | | |
236 | 190 | return true; |
237 | 325 | } |
238 | | |
239 | | //////////////////////////////////////////////////////////// |
240 | | // try to send the table |
241 | | bool WPSTable::sendTable(WPSContentListenerPtr listener) |
242 | 391 | { |
243 | 391 | if (!buildStructures()) |
244 | 135 | return false; |
245 | 256 | if (!listener) |
246 | 0 | return true; |
247 | | |
248 | 256 | size_t numCols = m_colsSize.size(); |
249 | 256 | size_t numRows = m_rowsSize.size(); |
250 | 256 | if (!numCols || !numRows) |
251 | 28 | return false; |
252 | 228 | std::vector<int> cellsId(numCols*numRows, -1); |
253 | 228 | size_t nCells = m_cellsList.size(); |
254 | 852 | for (size_t c = 0; c < nCells; c++) |
255 | 642 | { |
256 | 642 | if (!m_cellsList[c]) continue; |
257 | 642 | Vec2i const &pos=m_cellsList[c]->m_position; |
258 | 642 | Vec2i const &span=m_cellsList[c]->m_numberCellSpanned; |
259 | | |
260 | 1.25k | for (int x = pos[0]; x < pos[0]+span[0]; x++) |
261 | 631 | { |
262 | 631 | if (x >= int(numCols)) |
263 | 0 | { |
264 | 0 | WPS_DEBUG_MSG(("WPSTable::sendTable: x is too big !!!\n")); |
265 | 0 | return false; |
266 | 0 | } |
267 | 1.26k | for (int y = pos[1]; y < pos[1]+span[1]; y++) |
268 | 655 | { |
269 | 655 | if (y >= int(numRows)) |
270 | 0 | { |
271 | 0 | WPS_DEBUG_MSG(("WPSTable::sendTable: y is too big !!!\n")); |
272 | 0 | return false; |
273 | 0 | } |
274 | 655 | auto tablePos = size_t(y*int(numCols)+x); |
275 | 655 | if (cellsId[tablePos] != -1) |
276 | 18 | { |
277 | 18 | WPS_DEBUG_MSG(("WPSTable::sendTable: cells is used!!!\n")); |
278 | 18 | return false; |
279 | 18 | } |
280 | 637 | if (x == pos[0] && y == pos[1]) |
281 | 558 | cellsId[tablePos] = int(c); |
282 | 79 | else |
283 | 79 | cellsId[tablePos] = -2; |
284 | 637 | } |
285 | 631 | } |
286 | 642 | } |
287 | | |
288 | 210 | listener->openTable(m_colsSize, librevenge::RVNG_POINT); |
289 | 210 | WPSListenerPtr listen=listener; |
290 | 663 | for (size_t r = 0; r < numRows; r++) |
291 | 453 | { |
292 | 453 | listener->openTableRow(m_rowsSize[r], librevenge::RVNG_POINT); |
293 | 1.51k | for (size_t c = 0; c < numCols; c++) |
294 | 1.05k | { |
295 | 1.05k | size_t tablePos = r*numCols+c; |
296 | 1.05k | int id = cellsId[tablePos]; |
297 | 1.05k | if (id == -1) |
298 | 559 | listener->addEmptyTableCell(Vec2i(int(c), int(r))); |
299 | 1.05k | if (id < 0) |
300 | 577 | continue; |
301 | | |
302 | 481 | m_cellsList[size_t(id)]->send(listen); |
303 | 481 | } |
304 | 453 | listener->closeTableRow(); |
305 | 453 | } |
306 | 210 | listener->closeTable(); |
307 | | |
308 | 210 | return true; |
309 | 228 | } |
310 | | |
311 | | |
312 | | //////////////////////////////////////////////////////////// |
313 | | // try to send the table |
314 | | bool WPSTable::sendAsText(WPSContentListenerPtr listener) |
315 | 181 | { |
316 | 181 | if (!listener) return true; |
317 | | |
318 | 181 | WPSListenerPtr listen=listener; |
319 | 181 | for (auto &cell : m_cellsList) |
320 | 585 | { |
321 | 585 | if (!cell) continue; |
322 | 585 | cell->sendContent(listen); |
323 | 585 | listener->insertEOL(); |
324 | 585 | } |
325 | 181 | return true; |
326 | 181 | } |
327 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |