1 /*
2 Copyright (C) 2011 Elvis Stansvik <elvstone@gmail.com>
3
4 For general Scribus (>=1.3.2) copyright and licensing information please refer
5 to the COPYING file provided with the program. Following this notice may exist
6 a copyright and/or license notice that predates the release of Scribus 1.3.2
7 for which a new license (GPL+exception) is in place.
8 */
9
10 #include <QPointF>
11
12 #include "tableborder.h"
13
14 #include "tableutils.h"
15 #include "pageitem_table.h"
16
17 namespace TableUtils
18 {
19
resolveBordersHorizontal(const TableCell & topLeftCell,const TableCell & topCell,const TableCell & topRightCell,const TableCell & bottomLeftCell,const TableCell & bottomCell,const TableCell & bottomRightCell,TableBorder * topLeft,TableBorder * left,TableBorder * bottomLeft,TableBorder * center,TableBorder * topRight,TableBorder * right,TableBorder * bottomRight,PageItem_Table * table)20 void resolveBordersHorizontal(const TableCell& topLeftCell, const TableCell& topCell,
21 const TableCell& topRightCell, const TableCell& bottomLeftCell, const TableCell& bottomCell,
22 const TableCell& bottomRightCell, TableBorder* topLeft, TableBorder* left, TableBorder* bottomLeft,
23 TableBorder* center, TableBorder* topRight, TableBorder* right, TableBorder* bottomRight, PageItem_Table* table)
24 {
25 // Resolve top left.
26 if (!topCell.isValid() && !bottomCell.isValid())
27 return;
28 if (topLeftCell.column() == topCell.column())
29 *topLeft = TableBorder();
30 else if (topLeftCell.isValid() && topCell.isValid())
31 *topLeft = collapseBorders(topCell.leftBorder(), topLeftCell.rightBorder());
32 else if (topLeftCell.isValid())
33 *topLeft = collapseBorders(table->rightBorder(), topLeftCell.rightBorder());
34 else if (topCell.isValid())
35 *topLeft = collapseBorders(topCell.leftBorder(), table->leftBorder());
36 else
37 *topLeft = TableBorder();
38 // Resolve left.
39 if (topLeftCell.row() == bottomLeftCell.row())
40 *left = TableBorder();
41 else if (topLeftCell.isValid() && bottomLeftCell.isValid())
42 *left = collapseBorders(bottomLeftCell.topBorder(), topLeftCell.bottomBorder());
43 else if (topLeftCell.isValid())
44 *left = collapseBorders(table->bottomBorder(), topLeftCell.bottomBorder());
45 else if (bottomLeftCell.isValid())
46 *left = collapseBorders(bottomLeftCell.topBorder(), table->topBorder());
47 else
48 *left = TableBorder();
49 // Resolve bottom left.
50 if (bottomLeftCell.column() == bottomCell.column())
51 *bottomLeft = TableBorder();
52 else if (bottomLeftCell.isValid() && bottomCell.isValid())
53 *bottomLeft = collapseBorders(bottomCell.leftBorder(), bottomLeftCell.rightBorder());
54 else if (bottomLeftCell.isValid())
55 *bottomLeft = collapseBorders(table->rightBorder(), bottomLeftCell.rightBorder());
56 else if (bottomCell.isValid())
57 *bottomLeft = collapseBorders(bottomCell.leftBorder(), table->leftBorder());
58 else
59 *bottomLeft = TableBorder();
60 // Resolve center.
61 if (topCell.row() == bottomCell.row())
62 *center = TableBorder();
63 else if (topCell.isValid() && bottomCell.isValid())
64 *center = collapseBorders(topCell.bottomBorder(), bottomCell.topBorder());
65 else if (topCell.isValid())
66 *center = collapseBorders(table->bottomBorder(), topCell.bottomBorder());
67 else if (bottomCell.isValid())
68 *center = collapseBorders(bottomCell.topBorder(), table->topBorder());
69 else
70 *center = TableBorder();
71 // Resolve top right.
72 if (topRightCell.column() == topCell.column())
73 *topRight = TableBorder();
74 else if (topRightCell.isValid() && topCell.isValid())
75 *topRight = collapseBorders(topRightCell.leftBorder(), topCell.rightBorder());
76 else if (topRightCell.isValid())
77 *topRight = collapseBorders(topRightCell.leftBorder(), table->leftBorder());
78 else if (topCell.isValid())
79 *topRight = collapseBorders(table->rightBorder(), topCell.rightBorder());
80 else
81 *topRight = TableBorder();
82 // Resolve right.
83 if (topRightCell.row() == bottomRightCell.row())
84 *right = TableBorder();
85 else if (topRightCell.isValid() && bottomRightCell.isValid())
86 *right = collapseBorders(bottomRightCell.topBorder(), topRightCell.bottomBorder());
87 else if (topRightCell.isValid())
88 *right = collapseBorders(table->bottomBorder(), topRightCell.bottomBorder());
89 else if (bottomRightCell.isValid())
90 *right = collapseBorders(bottomRightCell.topBorder(), table->topBorder());
91 else
92 *right = TableBorder();
93 // Resolve bottom right.
94 if (bottomRightCell.column() == bottomCell.column())
95 *bottomRight = TableBorder();
96 else if (bottomRightCell.isValid() && bottomCell.isValid())
97 *bottomRight = collapseBorders(bottomRightCell.leftBorder(), bottomCell.rightBorder());
98 else if (bottomRightCell.isValid())
99 *bottomRight = collapseBorders(bottomRightCell.leftBorder(), table->leftBorder());
100 else if (bottomCell.isValid())
101 *bottomRight = collapseBorders(table->rightBorder(), bottomCell.rightBorder());
102 else
103 *bottomRight = TableBorder();
104 }
105
resolveBordersVertical(const TableCell & topLeftCell,const TableCell & topRightCell,const TableCell & leftCell,const TableCell & rightCell,const TableCell & bottomLeftCell,const TableCell & bottomRightCell,TableBorder * topLeft,TableBorder * top,TableBorder * topRight,TableBorder * center,TableBorder * bottomLeft,TableBorder * bottom,TableBorder * bottomRight,PageItem_Table * table)106 void resolveBordersVertical(const TableCell& topLeftCell, const TableCell& topRightCell, const TableCell& leftCell, const TableCell& rightCell, const TableCell& bottomLeftCell,
107 const TableCell& bottomRightCell, TableBorder* topLeft, TableBorder* top, TableBorder* topRight, TableBorder* center, TableBorder* bottomLeft, TableBorder* bottom, TableBorder* bottomRight, PageItem_Table* table)
108 {
109 if (!leftCell.isValid() && !rightCell.isValid())
110 return;
111 // Resolve top left.
112 if (topLeftCell.row() == leftCell.row())
113 *topLeft = TableBorder();
114 else if (topLeftCell.isValid() && leftCell.isValid())
115 *topLeft = collapseBorders(leftCell.topBorder(), topLeftCell.bottomBorder());
116 else if (topLeftCell.isValid())
117 *topLeft = collapseBorders(table->bottomBorder(), topLeftCell.bottomBorder());
118 else if (leftCell.isValid())
119 *topLeft = collapseBorders(leftCell.topBorder(), table->topBorder());
120 else
121 *topLeft = TableBorder();
122 // Resolve top.
123 if (topLeftCell.column() == topRightCell.column())
124 *top = TableBorder();
125 else if (topLeftCell.isValid() && topRightCell.isValid())
126 *top = collapseBorders(topRightCell.leftBorder(), topLeftCell.rightBorder());
127 else if (topLeftCell.isValid())
128 *top = collapseBorders(table->rightBorder(), topLeftCell.rightBorder());
129 else if (topRightCell.isValid())
130 *top = collapseBorders(topRightCell.leftBorder(), table->leftBorder());
131 else
132 *top = TableBorder();
133 // Resolve top right.
134 if (topRightCell.row() == rightCell.row())
135 *topRight = TableBorder();
136 else if (topRightCell.isValid() && rightCell.isValid())
137 *topRight = collapseBorders(rightCell.topBorder(), topRightCell.bottomBorder());
138 else if (topRightCell.isValid())
139 *topRight = collapseBorders(table->bottomBorder(), topRightCell.bottomBorder());
140 else if (rightCell.isValid())
141 *topRight = collapseBorders(rightCell.topBorder(), table->topBorder());
142 else
143 *topRight = TableBorder();
144 // Resolve center.
145 if (leftCell.column() == rightCell.column())
146 *center = TableBorder();
147 else if (leftCell.isValid() && rightCell.isValid())
148 *center = collapseBorders(rightCell.leftBorder(), leftCell.rightBorder());
149 else if (leftCell.isValid())
150 *center = collapseBorders(table->rightBorder(), leftCell.rightBorder());
151 else if (rightCell.isValid())
152 *center = collapseBorders(rightCell.leftBorder(), table->leftBorder());
153 else
154 *center = TableBorder();
155 // Resolve bottom left.
156 if (bottomLeftCell.row() == leftCell.row())
157 *bottomLeft = TableBorder();
158 else if (bottomLeftCell.isValid() && leftCell.isValid())
159 *bottomLeft = collapseBorders(bottomLeftCell.topBorder(), leftCell.bottomBorder());
160 else if (bottomLeftCell.isValid())
161 *bottomLeft = collapseBorders(bottomLeftCell.topBorder(), table->topBorder());
162 else if (leftCell.isValid())
163 *bottomLeft = collapseBorders(table->bottomBorder(), leftCell.bottomBorder());
164 else
165 *bottomLeft = TableBorder();
166 // Resolve bottom.
167 if (bottomLeftCell.column() == bottomRightCell.column())
168 *bottom = TableBorder();
169 else if (bottomLeftCell.isValid() && bottomRightCell.isValid())
170 *bottom = collapseBorders(bottomRightCell.leftBorder(), bottomLeftCell.rightBorder());
171 else if (bottomLeftCell.isValid())
172 *bottom = collapseBorders(table->rightBorder(), bottomLeftCell.rightBorder());
173 else if (bottomRightCell.isValid())
174 *bottom = collapseBorders(bottomRightCell.leftBorder(), table->leftBorder());
175 else
176 *bottom = TableBorder();
177 // Resolve bottom right.
178 if (bottomRightCell.row() == rightCell.row())
179 *bottomRight = TableBorder();
180 else if (bottomRightCell.isValid() && rightCell.isValid())
181 *bottomRight = collapseBorders(bottomRightCell.topBorder(), rightCell.bottomBorder());
182 else if (bottomRightCell.isValid())
183 *bottomRight = collapseBorders(bottomRightCell.topBorder(), table->topBorder());
184 else if (rightCell.isValid())
185 *bottomRight = collapseBorders(table->bottomBorder(), rightCell.bottomBorder());
186 else
187 *bottomRight = TableBorder();
188 }
189
collapseBorders(const TableBorder & firstBorder,const TableBorder & secondBorder)190 TableBorder collapseBorders(const TableBorder& firstBorder, const TableBorder& secondBorder)
191 {
192 TableBorder collapsedBorder;
193
194 if (firstBorder.isNull() && secondBorder.isNull())
195 {
196 // Both borders are null, so return a null border.
197 return collapsedBorder;
198 }
199 if (firstBorder.isNull())
200 {
201 // First border is null, so return second border.
202 collapsedBorder = secondBorder;
203 }
204 else if (secondBorder.isNull())
205 {
206 // Second border is null, so return first border.
207 collapsedBorder = firstBorder;
208 }
209 else
210 {
211 if (firstBorder.width() > secondBorder.width())
212 {
213 // First border is wider than second border, so return first border.
214 collapsedBorder = firstBorder; // (4)
215 }
216 else if (firstBorder.width() < secondBorder.width())
217 {
218 // Second border is wider than first border, so return second border.
219 collapsedBorder = secondBorder; // (5)
220 }
221 else
222 {
223 if (firstBorder.borderLines().size() > secondBorder.borderLines().size())
224 {
225 // First border has more border lines than second border, so return first border.
226 collapsedBorder = firstBorder;
227 }
228 else
229 {
230 // Second border has more or equal border lines than first border, so return second border.
231 collapsedBorder = secondBorder;
232 }
233 }
234 }
235
236 return collapsedBorder;
237 }
238
joinVertical(const TableBorder & border,const TableBorder & topLeft,const TableBorder & top,const TableBorder & topRight,const TableBorder & bottomLeft,const TableBorder & bottom,const TableBorder & bottomRight,QPointF * start,QPointF * end,QPointF * startOffsetFactors,QPointF * endOffsetFactors)239 void joinVertical(const TableBorder& border, const TableBorder& topLeft, const TableBorder& top,
240 const TableBorder& topRight, const TableBorder& bottomLeft, const TableBorder& bottom,
241 const TableBorder& bottomRight, QPointF* start, QPointF* end, QPointF* startOffsetFactors,
242 QPointF* endOffsetFactors)
243 {
244 Q_ASSERT(start);
245 Q_ASSERT(end);
246 Q_ASSERT(startOffsetFactors);
247 Q_ASSERT(endOffsetFactors);
248
249 // Reset offset coefficients.
250 startOffsetFactors->setX(0.0);
251 startOffsetFactors->setY(0.0);
252 endOffsetFactors->setX(0.0);
253 endOffsetFactors->setY(0.0);
254
255 /*
256 * The numbered cases in the code below refers to the 45 possible join cases illustrated
257 * in the picture at http://wiki.scribus.net/canvas/File:Table_border_join_cases.png
258 */
259
260 /*
261 * Adjust start point(s). Possible cases are 1-20, 26-39.
262 */
263 if (border.joinsWith(topLeft))
264 {
265 if (border.joinsWith(topRight))
266 {
267 if (!border.joinsWith(top))
268 {
269 // Cases: 8, 19.
270 startOffsetFactors->setY(-0.5);
271 }
272 }
273 else if (!border.joinsWith(top))
274 {
275 if (top.joinsWith(topRight))
276 {
277 if (border.width() < top.width())
278 {
279 // Cases: 15A.
280 start->setY(start->y() + 0.5 * top.width());
281 }
282 else
283 {
284 // Cases: 15B.
285 startOffsetFactors->setY(-0.5);
286 }
287 }
288 else
289 {
290 // Cases: 5, 17, 27, 38.
291 startOffsetFactors->setY(-0.5);
292 }
293 }
294 }
295 else if (border.joinsWith(topRight))
296 {
297 if (!border.joinsWith(top))
298 {
299 if (top.joinsWith(topLeft))
300 {
301 if (border.width() < top.width())
302 {
303 // Cases: 14A.
304 start->setY(start->y() + 0.5 * top.width());
305 }
306 else
307 {
308 // Cases: 14B.
309 startOffsetFactors->setY(-0.5);
310 }
311 }
312 else
313 {
314 // Cases: 4, 18, 32, 36.
315 startOffsetFactors->setY(-0.5);
316 }
317 }
318 }
319 else if (border.joinsWith(top))
320 {
321 if (topLeft.joinsWith(topRight))
322 {
323 // Cases: 11.
324 start->setY(start->y() + 0.5 * topLeft.width());
325 }
326 }
327 else
328 {
329 // Cases: 1, 2, 3, 6, 12, 16, 20, 26, 28, 31, 33, 37, 39.
330 start->setY(start->y() + 0.5 * qMax(topLeft.width(), topRight.width()));
331 }
332 // Cases: 7, 9, 10, 13, 29, 30, 34, 35 - No adjustment to start point(s) needed.
333
334 /*
335 * Adjust end point(s). Possible cases are 1-15, 21-35, 40-43.
336 */
337 if (border.joinsWith(bottomLeft))
338 {
339 if (border.joinsWith(bottomRight))
340 {
341 if (!border.joinsWith(bottom))
342 {
343 // Cases: 6, 24.
344 endOffsetFactors->setY(0.5);
345 }
346 }
347 else if (!border.joinsWith(bottom))
348 {
349 if (bottom.joinsWith(bottomRight))
350 {
351 if (bottom.width() < border.width())
352 {
353 // Cases: 14A.
354 endOffsetFactors->setY(0.5);
355 }
356 else
357 {
358 // Cases: 14B.
359 end->setY(end->y() - 0.5 * bottom.width());
360 }
361 }
362 else
363 {
364 // Cases: 2, 22, 28, 42.
365 endOffsetFactors->setY(0.5);
366 }
367 }
368 }
369 else if (border.joinsWith(bottomRight))
370 {
371 if (!border.joinsWith(bottom))
372 {
373 if (bottom.joinsWith(bottomLeft))
374 {
375 if (bottom.width() < border.width())
376 {
377 // Cases: 15A.
378 endOffsetFactors->setY(0.5);
379 }
380 else
381 {
382 // Cases: 15B.
383 end->setY(end->y() - 0.5 * bottom.width());
384 }
385 }
386 else
387 {
388 // Cases: 3, 23, 33, 40.
389 endOffsetFactors->setY(0.5);
390 }
391 }
392 }
393 else if (border.joinsWith(bottom))
394 {
395 if (bottomLeft.joinsWith(bottomRight))
396 {
397 // Cases: 11.
398 end->setY(end->y() - 0.5 * bottomLeft.width());
399 }
400 }
401 else
402 {
403 // Cases: 1, 4, 5, 8, 12, 21, 25, 26, 27, 31, 32, 41, 43.
404 end->setY(end->y() - 0.5 * qMax(bottomLeft.width(), bottomRight.width()));
405 }
406 // Cases: 7, 9, 10, 13, 29, 30, 34, 35 - No adjustment to end point(s) needed.
407 }
408
joinHorizontal(const TableBorder & border,const TableBorder & topLeft,const TableBorder & left,const TableBorder & bottomLeft,const TableBorder & topRight,const TableBorder & right,const TableBorder & bottomRight,QPointF * start,QPointF * end,QPointF * startOffsetFactors,QPointF * endOffsetFactors)409 void joinHorizontal(const TableBorder& border, const TableBorder& topLeft, const TableBorder& left,
410 const TableBorder& bottomLeft, const TableBorder& topRight, const TableBorder& right,
411 const TableBorder& bottomRight, QPointF* start, QPointF* end, QPointF* startOffsetFactors,
412 QPointF* endOffsetFactors)
413 {
414 Q_ASSERT(start);
415 Q_ASSERT(end);
416 Q_ASSERT(startOffsetFactors);
417 Q_ASSERT(endOffsetFactors);
418
419 // Reset offset coefficients.
420 startOffsetFactors->setX(0.0);
421 startOffsetFactors->setY(0.0);
422 endOffsetFactors->setX(0.0);
423 endOffsetFactors->setY(0.0);
424
425 /*
426 * The numbered cases in the code below refers to the 45 possible join cases illustrated
427 * in the picture at http://wiki.scribus.net/canvas/File:Table_border_join_cases.png
428 */
429
430 /*
431 * Adjust start point(s). Possible cases are 1-25, 31-37, 40-41.
432 */
433 if (border.joinsWith(bottomLeft))
434 {
435 if (border.joinsWith(topLeft))
436 {
437 if (border.joinsWith(left))
438 {
439 // Cases: 10.
440 startOffsetFactors->setX(0.5);
441 }
442 else
443 {
444 // Cases: 7, 34.
445 startOffsetFactors->setX(0.5);
446 }
447 }
448 else
449 {
450 if (border.joinsWith(left))
451 {
452 // Cases: 8, 19.
453 startOffsetFactors->setX(0.5);
454 }
455 else if (left.joinsWith(topLeft))
456 {
457 if (border.width() < left.width())
458 {
459 // Cases: 14A.
460 start->setX(start->x() + 0.5 * left.width());
461 }
462 else
463 {
464 // Cases: 14B.
465 startOffsetFactors->setX(0.5);
466 }
467 }
468 else
469 {
470 // Cases: 4, 18, 32, 36.
471 startOffsetFactors->setX(0.5);
472 }
473 }
474 }
475 else if (border.joinsWith(topLeft))
476 {
477 if (border.joinsWith(left))
478 {
479 // Cases: 6, 24.
480 startOffsetFactors->setX(0.5);
481 }
482 else
483 {
484 if (left.joinsWith(bottomLeft))
485 {
486 if (left.width() < border.width())
487 {
488 // Cases: 15A.
489 startOffsetFactors->setX(0.5);
490 }
491 else
492 {
493 // Cases: 15B.
494 start->setX(start->x() + 0.5 * left.width());
495 }
496 }
497 else
498 {
499 // Cases: 3, 23, 33, 40.
500 startOffsetFactors->setX(0.5);
501 }
502 }
503 }
504 else if (!border.joinsWith(left) &&
505 (topLeft.joinsWith(bottomLeft) || topLeft.joinsWith(left) || bottomLeft.joinsWith(left)))
506 {
507 // Cases: 2, 5, 9, 13, 17, 22, 35.
508 start->setX(start->x() + 0.5 * qMax(topLeft.width(), bottomLeft.width()));
509 }
510 else if (left.isNull())
511 {
512 // Cases: 31, 37, 41.
513 start->setX(start->x() - 0.5 * qMax(topLeft.width(), bottomLeft.width()));
514 }
515 // Cases: 1, 11, 12, 16, 20, 21, 25 - No adjustment to start point(s) needed.
516
517 /*
518 * Adjust end point(s). Possible cases are 1-30, 38-39, 42-43.
519 */
520 if (border.joinsWith(bottomRight))
521 {
522 if (border.joinsWith(topRight))
523 {
524 if (border.joinsWith(right))
525 {
526 // Cases: 10.
527 endOffsetFactors->setX(-0.5);
528 }
529 else
530 {
531 // Cases: 9, 29.
532 endOffsetFactors->setX(-0.5);
533 }
534 }
535 else if (border.joinsWith(right))
536 {
537 // Cases: 6, 24.
538 endOffsetFactors->setX(-0.5);
539 }
540 else
541 {
542 if (right.joinsWith(topRight))
543 {
544 if (border.width() < right.width())
545 {
546 // Cases: 15A.
547 end->setX(end->x() - 0.5 * right.width());
548 }
549 else
550 {
551 // Cases: 15B.
552 endOffsetFactors->setX(-0.5);
553 }
554 }
555 else
556 {
557 // Cases: 5, 17, 27, 38.
558 endOffsetFactors->setX(-0.5);
559 }
560 }
561 }
562 else if (border.joinsWith(topRight))
563 {
564 if (border.joinsWith(right))
565 {
566 // Cases: 6, 24.
567 endOffsetFactors->setX(-0.5);
568 }
569 else
570 {
571 if (right.joinsWith(bottomRight))
572 {
573 if (right.width() < border.width())
574 {
575 // Cases: 14A.
576 endOffsetFactors->setX(-0.5);
577 }
578 else
579 {
580 // Cases: 14B.
581 end->setX(end->x() - 0.5 * right.width());
582 }
583 }
584 else
585 {
586 // Cases: 2, 22, 28, 42.
587 endOffsetFactors->setX(-0.5);
588 }
589 }
590 }
591 else if (!border.joinsWith(right) &&
592 (topRight.joinsWith(bottomRight) || topRight.joinsWith(right) || bottomRight.joinsWith(right)))
593 {
594 // Cases: 3, 4, 7, 13, 18, 23, 30.
595 end->setX(end->x() - 0.5 * qMax(topRight.width(), bottomRight.width()));
596 }
597 else if (right.isNull())
598 {
599 // Cases: 26, 39, 43.
600 end->setX(end->x() + 0.5 * qMax(topRight.width(), bottomRight.width()));
601 }
602 // Cases: 1, 11, 12, 16, 20, 21, 25 - No adjustment to end point(s) needed.
603 }
604
605 } // namespace TableUtils
606