[scribus-dev] Tables GSoC Mid-term Report

Elvis Stansvik elvstone at gmail.com
Fri Jul 15 09:10:20 UTC 2011


Hi all,

Below is a brief summary report of my work with the project so far
[1]. The report is roughly divided into two parts: one activity part,
where I summarize the things I've done in chronological order and one
design part, where I've tried to document how what I have now is
designed/implemented. I've done this in the hope that it could be
reused for design documentation on the wiki.

Cheers,
Elvis

[1] http://wiki.scribus.net/canvas/GSoC_2011_Tables_Mid-term_Report

= Tables GSoC - Mid-term Report =

== Activity ==
=== Pre-Project Start / Week 1  ===
Before the project started, I did some experimenting with adding a new
table style, to see what work was involved to do that and to
familiarize myself a bit with the Scribus code base. This involved the
new class TableStyle, and SMTableStyle for StyleManager support.

In the first week of the project I added the new table page item,
PageItem_Table, and made sure the new item could be inserted in the
same way the old one could.

I then went on and added API for the basic operations of inserting,
removing and resizing rows and columns as well as merging of table
cells (row/column span). In the process, a helper class CellArea was
written for representing areas of merged cells. I also added some very
basic painting of the table, to be able to see it while experimenting.

Lastly, I added an initial set of scripter functions that exercised the new API.

The first week was quite a jump start and I overshot my quite modest
goals of just doing basic data structures for the tables.

=== Week 2 ===
In the second week, coming to like the way of working with the
scripter API to test my work, I added a poor mans unit testing
"framework" in the form of a Python script that automatically run a
set of test methods and reports any regressions.

I also added a new explicitly shared class TableCell for representing
cells in the table, along with a cell style similar to the table
style, and fixed some bugs.

As I had my last exam this week, the progress wasn't as fast as in the
first week, but I was still ahead of schedule by quite a lot.

=== Week 3 ===
During the third week I worked with integrating the new TableCell
class into PageItem_Table, making sure the table correctly invalidates
cells that have been removed and adjusts their rows/columns/spans when
rows and columns are inserted and removed.

Other things I worked on include extending the set of test methods in
my test script, adding new scripter methods, adding table/cell style
related API to ScribusDoc as well as initial support for border width,
border color and background color.

It was during this third week that my schedule finally caught up with
me, and though my intentions for this week was to start working on
proper painting of cell borders, the work was mostly extending and
improving what I already had.

=== Week 4 ===
In the fourth week of the project, in addition to doing some cleanup
of the code, I finally started working on border painting.

I drafted a design for painting of borders involving "border
collectors" inheriting from a common base class. These collectors
would be responsible for collecting the borders around the table cells
according to the currently used border model (collapsing or
separated). I also added an primitive border "joining" algorithm that
only supported the two modes "horizontal on top" and "vertical on
top". I thought the design was sound. But in the end it turned out I
was wrong, and a big chunk of the work during this week was dropped.

During this week my project also suffered a bit from bad time
management on my part, since me and Hanna had visitors from Singapore
coming in, followed by a trip up to a cabin in the northwest to
celebrate Midsummer, with little or no Internet connectivity.

=== Week 5 ===
Week five saw me taking another approach to the painting problem. The
painting code was moved out of PageItem_Table and TableCell and into a
new CollapsedTablePainter inheriting from an abstract base class
TablePainter. The CollapseTablePainter takes a PageItem_Table and an
ScPainter and is entirely responsible for painting the table. If in
the future we want to support the separated border model, it should be
possible by simply subclassing TablePainter and implementing its pure
virtual paintTable(...) function.

The heavy work turned out to be the correct joining and collapsing of
multi-line borders, and after using up numerous sketch pads trying to
find a good solution I almost gave up. But I then sat down and
categorized all the different cases of joins that can be encountered
in a table and systematically wrote the algorithm that is in use right
now. It's not perfect, but it does cover all cases and it's easy to
make aesthetic adjustments for the corner cases that might occur. The
new code includes TableBorder, TableBorderLine as well as the
algorithms themselves which are kept as helper methods in a separate
namespace TableUtils to facilitate unit testing.

=== Week 6 ===
During week six I polished the joining algorithm further, fixed some
bugs and started working on UI.

I added a new custom widget TableSideSelector for selecting sides of a
table/cell when changing border properties and added support for
configuring the borders, including multi-line borders, to the Table
palette in the Properties Palette. This UI still needs improvement,
but it's part of what I'm working on right now.

== Current Design ==
The current design of the tables is quite simple. We have
PageItem_Table, which is the item representing a table. Internally
this class keeps a few lists with row heights, columns widths as well
as positions of the rows and columns in the table. It also has a
QList<QList<TableCell>> for the cells of the table.

The table also keeps a list of CellAreas. These are simply rectangular
areas of merged cells. This is so the table can easily answer if a
cell is covered by another cell or not, without the code getting too
complicated. These areas are updated when rows or columns are inserted
or removed from the table.

Table cells may be requested from the table using cellAt(int row, int
column). Cells retrieved from the table may be marked as invalid by
the table if the row or column the cell is in is removed. This is made
possibly by TableCell being an explicitly shared class. A cell may be
queried for its validity using isValid().

If a covered cell is requested using the cellAt(...) API, the table
will return the covering cell. This is similar to how the analog API
works in e.g. QTextTable. This behavior is relied upon heavily
throughout the code, especially in the painting.

TableCell itself is simply an interface for setting and getting cell
properties. TableCells also know which row and column they are in, and
their row/column span.

As previously mentioned, the table paints itself completely using the
current TablePainter. There is currently only one TablePainter: the
CollapsedTablePainter.

A recent addition to painting is that the painter will paint the table
offset in the Y direction by half the width of the widest border found
along its top edge, and in the X direction by half the width of the
widest border along its left edge. This is so that the Table will stay
inside the frame at the top and left side at all times. The internal
table grid, represented by the lists of row and column positions, is
still unaffected though; the offsets are only used during painting and
when calculating the table width/height (tableWidth() /
tableHeight()).

Both PageItem_Table and TableCell use a locally stored style for their
properties, and setting a style using setStyle(...) on a table or cell
results in the parent style of this internal style being set. This
allows certain properties to be set locally, while unset ones are
taken from the style. Each property has a get function, a set function
and an unset function.

I think this pretty much covers the gist of it. Things are of course
subject to change.



More information about the scribus-dev mailing list