summaryrefslogtreecommitdiffstats
path: root/filters/kword/msword/tablehandler.cpp
blob: 3f4ebec357be252070f6cce79eab91a025074dce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/* This file is part of the KOffice project
   Copyright (C) 2002 Werner Trobin <trobin@kde.org>
   Copyright (C) 2002 David Faure <faure@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License version 2 as published by the Free Software Foundation.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include "tablehandler.h"

#include <wv2/word97_generated.h>

#include <kdebug.h>
#include <KoRect.h>
#include <qtl.h>

KWordTableHandler::KWordTableHandler()
{
    tableEnd();
}

// Called by Document before invoking the table-row-functors
void KWordTableHandler::tableStart( KWord::Table* table )
{
    Q_ASSERT( table );
    Q_ASSERT( !table->name.isEmpty() );
    m_currentTable = table;
    qHeapSort( table->m_cellEdges );
#if 0
    for (unsigned int i = 0; i < table->m_cellEdges.size(); i++)
        kdDebug(30513) << table->m_cellEdges[i] << endl;
#endif
    m_row = -1;
    m_currentY = 0;
}

void KWordTableHandler::tableEnd()
{
    m_currentTable = 0L; // we don't own it, the table-queue does!
    m_row = -2;
    m_column = -2;
    // Warning: if doing more here, check that it's still ok to call this from the ctor
}

void KWordTableHandler::tableRowStart( wvWare::SharedPtr<const wvWare::Word97::TAP> tap )
{
    if ( m_row == -2 )
    {
        kdWarning(30513) << "tableRowStart: tableStart not called previously!" << endl;
        return;
    }
    Q_ASSERT( m_currentTable );
    Q_ASSERT( !m_currentTable->name.isEmpty() );
    m_row++;
    m_column = -1;
    m_tap = tap;
    kdDebug(30513) << "tableRowStart row=" << m_row << endl;
}

void KWordTableHandler::tableRowEnd()
{
    kdDebug(30513) << "tableRowEnd" << endl;
    m_currentY += rowHeight();
}

void KWordTableHandler::tableCellStart()
{
    Q_ASSERT( m_tap );
    if ( !m_tap )
        return;
    m_column++;
    int nbCells = m_tap->itcMac;
    Q_ASSERT( m_column < nbCells );
    if ( m_column >= nbCells )
        return;

    // Get table cell descriptor
    const wvWare::Word97::TC& tc = m_tap->rgtc[ m_column ];

    int left = m_tap->rgdxaCenter[ m_column ]; // in DXAs
    int right = m_tap->rgdxaCenter[ m_column+1 ]; // in DXAs

    // Check for merged cells
    // ## We can ignore that one. Our cell-edge magic is much more flexible.
#if 0
    int colSize = 1;
    if ( tc.fFirstMerged )
    {
        // This cell is the first one of a series of merged cells ->
        // we want to find out its size.
        int i = m_column + 1;
        while ( i < nbCells && m_tap->rgtc[ i ].fMerged && !m_tap->rgtc[i].fFirstMerged ) {
            ++colSize;
            ++i;
        }
    }
#endif
    int rowSpan = 1;
    if ( tc.fVertRestart )
    {
        //kdDebug(30513) << "fVertRestart is set!" << endl;
        // This cell is the first one of a series of vertically merged cells ->
        // we want to find out its size.
        QValueList<KWord::Row>::Iterator it = m_currentTable->rows.at( m_row + 1 );
        for( ; it != m_currentTable->rows.end(); ++it )  {
            // Find cell right below us in row (*it), if any
            KWord::TAPptr tapBelow = (*it).tap;
            const wvWare::Word97::TC* tcBelow = 0L;
            for ( int c = 0; !tcBelow && c < tapBelow->itcMac ; ++c )
            {
                 if ( QABS( tapBelow->rgdxaCenter[ c ] - left ) <= 3
                      && QABS( tapBelow->rgdxaCenter[ c + 1 ] - right ) <= 3 ) {
                     tcBelow = &tapBelow->rgtc[ c ];
                     //kdDebug(30513) << "found cell below, at (Word) column " << c << " fVertMerge:" << tcBelow->fVertMerge << endl;
                 }
            }
            if ( tcBelow && tcBelow->fVertMerge && !tcBelow->fVertRestart )
                ++rowSpan;
            else
                break;
        }
        //kdDebug(30513) << "rowSpan=" << rowSpan << endl;
    }
    // Skip cells that are part of a vertically merged cell, KWord doesn't want them
    // The MSWord spec says they must be empty anyway (and we'll get a warning if not).
    if ( tc.fVertMerge && !tc.fVertRestart )
        return;

    // Check how many cells that mean, according to our cell edge array
    int leftCellNumber = m_currentTable->columnNumber( left );
    int rightCellNumber = m_currentTable->columnNumber( right );

    // In cases where not all columns are present, ensure that the last
    // column spans the remainder of the table.
    // ### It would actually be more closer to the original if we created
    // an empty cell from m_column+1 to the last column. (table-6.doc)
    if ( m_column == nbCells - 1 )  {
        rightCellNumber = m_currentTable->m_cellEdges.size() - 1;
        right = m_currentTable->m_cellEdges[ rightCellNumber ];
    }

    Q_ASSERT( rightCellNumber >= leftCellNumber ); // you'd better be...
    int colSpan = rightCellNumber - leftCellNumber; // the resulting number of merged cells

    KoRect cellRect( left / 20.0, // left
                     m_currentY, // top
                     ( right - left ) / 20.0, // width
                     rowHeight() ); // height

    kdDebug(30513) << " tableCellStart row=" << m_row << " WordColumn=" << m_column << " colSpan=" << colSpan << " (from " << leftCellNumber << " to " << rightCellNumber << " for KWord) rowSpan=" << rowSpan << " cellRect=" << cellRect << endl;

    // Sort out the borders.
    // It seems we get this on the cells that are adjacent
    // to one has a border, as if it means "whatever the adjacent cell on this border
    // specifies". (cf table-22.doc)
    // We need to set the adjacent cell's border instead, in that case.
    // ### No idea how to do it properly for top/bottom though. The cell above might not have the same size...
    const wvWare::Word97::BRC& brcTop = tc.brcTop;
    const wvWare::Word97::BRC& brcBottom = tc.brcBottom;
    const wvWare::Word97::BRC& brcLeft =
     ( tc.brcLeft.ico == 255 && tc.brcLeft.dptLineWidth == 255 && m_column > 0 ) ?
        m_tap->rgtc[ m_column - 1 ].brcRight
        : tc.brcLeft;
    const wvWare::Word97::BRC& brcRight =
      ( tc.brcRight.ico == 255 && tc.brcRight.dptLineWidth == 255 && m_column < nbCells - 1 ) ?
        m_tap->rgtc[ m_column + 1 ].brcLeft
        : tc.brcRight;

    emit sigTableCellStart( m_row, leftCellNumber, rowSpan, colSpan, cellRect, m_currentTable->name, brcTop, brcBottom, brcLeft, brcRight, m_tap->rgshd[ m_column ] );
}

void KWordTableHandler::tableCellEnd()
{
    kdDebug(30513) << " tableCellEnd" << endl;
    emit sigTableCellEnd();
}


// Add cell edge into the cache of cell edges for a given table.
void KWord::Table::cacheCellEdge(int cellEdge)
{
    uint size = m_cellEdges.size();
    // Do we already know about this edge?
    for (unsigned int i = 0; i < size; i++)
    {
        if (m_cellEdges[i] == cellEdge)  {
            kdDebug(30513) << k_funcinfo << cellEdge << " -> found" << endl;
            return;
        }
    }

    // Add the edge to the array.
    m_cellEdges.resize(size + 1, QGArray::SpeedOptim);
    m_cellEdges[size] = cellEdge;
    kdDebug(30513) << k_funcinfo << cellEdge << " -> added. Size=" << size+1 << endl;
}

// Lookup a cell edge from the cache of cell edges
// And return the column number
int KWord::Table::columnNumber(int cellEdge) const
{
    for (unsigned int i = 0; i < m_cellEdges.size(); i++)
    {
        if (m_cellEdges[i] == cellEdge)
            return i;
    }
    // This can't happen, if cacheCellEdge has been properly called
    kdWarning(30513) << "Column not found for cellEdge x=" << cellEdge << " - BUG." << endl;
    return 0;
}

double KWordTableHandler::rowHeight() const
{
    return QMAX( m_tap->dyaRowHeight / 20.0, 20);
}

#include "tablehandler.moc"