[Okular-devel] [Bug 154980] Bad ODT rendering
Brad Hards
bradh at frogmouth.net
Sun Jan 4 06:11:02 CET 2009
On Saturday 03 January 2009 06:36:35 pm Brad Hards wrote:
> http://bugs.kde.org/show_bug.cgi?id=154980
> 1. We aren't handling the different alignment of elements within a single
> cell. So the first cell in the second row should render something like:
> BOH
> MAH
> CHI LO SA
> But we render it as
> CHI LO SAMAHBOH (with some wordwrapping)
> That is caused partly by inserting text at the beginning position
> (cell.firstCursorPosition(), which is easily fixed) and partly by not being
> able to set the alignment as a text property, only as a block property. The
> only way I can see of resolving this is to insert invisible frames within
> the cell, one for each <p> block.
See patch below.
> 3. We don't properly size the cells / columns. Need to parse the
> table-column attributes, and find a way to map that into a Qt property.
> Presumably that will require some kind of call to
> tableFormat.setColumnWidthConstraints().
This was actually implemented, but had a bug. I think it is caused by calling
the parent (which doesn't implement the column width) which adds a row size
of zero, followed by the actual column property. The whole approach is a bit
brittle, but I've worked around it. See below.
> 4. We don't support lists. Need to support the parsing and list styles.
Well, we don't support lists within table cells.
5. I also found that if you have anything after the table, all that gets put into
the first table cell. This is really noticeable if you have a couple of tables.
I've attached a test case that shows this.
Those problems are (on my testing) all resolved by this change. Lines that
start with ##### BH: are to help explain the patch.
This is better on my testing than currently, and I think it should go into
4.2 as a bug fix.
Brad
Index: formatproperty.cpp
===================================================================
--- formatproperty.cpp (revision 905238)
+++ formatproperty.cpp (working copy)
@@ -370,12 +370,15 @@
}
##### BH: Changes to formatproperty.cpp are to deal with the problem where we
##### BH: add column widths that are zero, presumably because of being called
##### BH: from a parent that doesn't set it.
TableColumnFormatProperty::TableColumnFormatProperty()
- : mWidth( 0 )
+ : mWidth( 0 ), isValid( false )
{
}
void TableColumnFormatProperty::apply( QTextTableFormat *format ) const
{
+ if ( ! isValid ) {
+ return;
+ }
QVector<QTextLength> lengths = format->columnWidthConstraints();
lengths.append( QTextLength( QTextLength::FixedLength, mWidth ) );
@@ -385,6 +388,7 @@
void TableColumnFormatProperty::setWidth( double width )
{
mWidth = width;
+ isValid = true;
}
TableCellFormatProperty::TableCellFormatProperty()
Index: formatproperty.h
===================================================================
--- formatproperty.h (revision 905238)
+++ formatproperty.h (working copy)
@@ -173,6 +173,7 @@
##### BH: Just add the member variable for the validity check
private:
double mWidth;
+ bool isValid;
};
class TableCellFormatProperty
Index: converter.cpp
===================================================================
--- converter.cpp (revision 903994)
+++ converter.cpp (working copy)
@@ -195,7 +195,7 @@
##### BH: We need to be able to insert the list at a variable cursor position (not
##### BH: just mCursor), in order to put the list into the right cell / frame location.
##### BH: So we pass the cursor position as a parameter.
##### BH:
##### BH: This change just makes the old list handling work the same as before.
if ( !convertHeader( mCursor, child ) )
return false;
} else if ( child.tagName() == QLatin1String( "list" ) ) {
- if ( !convertList( child ) )
+ if ( !convertList( mCursor, child ) )
return false;
} else if ( child.tagName() == QLatin1String( "table" ) ) {
if ( !convertTable( child ) )
@@ -321,21 +321,21 @@
return true;
}
##### BH: Insert list at cursor position passed as argument.
-bool Converter::convertList( const QDomElement &element )
+bool Converter::convertList( QTextCursor *cursor, const QDomElement &element )
{
const QString styleName = element.attribute( "style-name" );
const ListFormatProperty property = mStyleInformation->listProperty( styleName );
QTextListFormat format;
- if ( mCursor->currentList() ) { // we are in a nested list
- format = mCursor->currentList()->format();
+ if ( cursor->currentList() ) { // we are in a nested list
+ format = cursor->currentList()->format();
format.setIndent( format.indent() + 1 );
}
property.apply( &format, 0 );
- QTextList *list = mCursor->insertList( format );
+ QTextList *list = cursor->insertList( format );
QDomElement itemChild = element.firstChildElement();
int loop = 0;
@@ -350,17 +350,17 @@
if ( childElement.tagName() == QLatin1String( "p" ) ) {
if ( loop > 1 )
- mCursor->insertBlock();
+ cursor->insertBlock();
- prevBlock = mCursor->block();
+ prevBlock = cursor->block();
- if ( !convertParagraph( mCursor, childElement, QTextBlockFormat(), true ) )
+ if ( !convertParagraph( cursor, childElement, QTextBlockFormat(), true ) )
return false;
} else if ( childElement.tagName() == QLatin1String( "list" ) ) {
- prevBlock = mCursor->block();
+ prevBlock = cursor->block();
- if ( !convertList( childElement ) )
+ if ( !convertList( cursor, childElement ) )
return false;
}
@@ -391,6 +391,7 @@
*/
int rowCounter = 0;
int columnCounter = 0;
+
QQueue<QDomNode> nodeQueue;
enqueueNodeList( nodeQueue, element.childNodes() );
while ( !nodeQueue.isEmpty() ) {
@@ -420,6 +421,7 @@
* Create table
*/
QTextTable *table = mCursor->insertTable( rowCounter, columnCounter );
##### BH: Adding a table leaves the cursor in the first cell. We want to skip
##### BH: over that, and add additional text at the bottom.
+ mCursor->movePosition( QTextCursor::End );
/**
* Fill table
@@ -450,11 +452,24 @@
##### BH: This change adds an invisible frame around the text provided in each
##### BH: <p> block, so we can vary the block formatting (e.g. left, right, center
##### BH: alignment.
##### BH: I renamed the cursor so I can figure out _which_ cursor is being used...
while ( !paragraphElement.isNull() ) {
if ( paragraphElement.tagName() == QLatin1String( "p" ) ) {
QTextTableCell cell = table->cellAt( rowCounter, columnCounter );
- QTextCursor cursor = cell.firstCursorPosition();
- cursor.setBlockFormat( format );
+ // Insert a frame into the cell and work on that, so we can handle
+ // different parts of the cell having different block formatting
##### BH: Add new text at the end of the cell, not at the start.
+ QTextCursor cellCursor = cell.lastCursorPosition();
+ QTextFrameFormat frameFormat;
+ frameFormat.setMargin( 1 ); // TODO: this shouldn't be hard coded
+ QTextFrame *frame = cellCursor.insertFrame( frameFormat );
+ QTextCursor frameCursor = frame->firstCursorPosition();
+ frameCursor.setBlockFormat( format );
- if ( !convertParagraph( &cursor, paragraphElement, format ) )
+ if ( !convertParagraph( &frameCursor, paragraphElement, format ) )
return false;
##### BH: Previously we only handled text (<p>) within a cell. This adds support
##### BH: for lists with a cell. Re-uses existing list handling, just with a special
##### BH: cursor position. This is the reason for the extra parameter introduced
##### BH: into convertList, above.
+ } else if ( paragraphElement.tagName() == QLatin1String( "list" ) ) {
+ QTextTableCell cell = table->cellAt( rowCounter, columnCounter );
+ // insert a list into the cell
+ QTextCursor cellCursor = cell.lastCursorPosition();
+ if ( !convertList( &cellCursor, paragraphElement ) ) {
+ return false;
+ }
}
paragraphElement = paragraphElement.nextSiblingElement();
@@ -467,7 +482,11 @@
rowCounter++;
} else if ( el.tagName() == QLatin1String( "table-column" ) ) {
##### BH: This change deals with the "number-columns-repeated" approach to column width.
##### BH: Prova.odt uses that.
const StyleFormatProperty property = mStyleInformation->styleProperty( el.attribute( "style-name" ) );
- property.applyTableColumn( &tableFormat );
+ const QString tableColumnNumColumnsRepeated = el.attribute( "number-columns-repeated", "1" );
+ int numColumnsToApplyTo = tableColumnNumColumnsRepeated.toInt();
+ for (int i = 0; i < numColumnsToApplyTo; ++i) {
+ property.applyTableColumn( &tableFormat );
+ }
}
}
Index: converter.h
===================================================================
--- converter.h (revision 903994)
+++ converter.h (working copy)
@@ -40,7 +40,7 @@
##### BH: we changed the signature for convertList - just update here too.
bool convertTextNode( QTextCursor *cursor, const QDomText &element, const QTextCharFormat &format );
bool convertSpan( QTextCursor *cursor, const QDomElement &element, const QTextCharFormat &format );
bool convertLink( QTextCursor *cursor, const QDomElement &element, const QTextCharFormat &format );
- bool convertList( const QDomElement &element );
+ bool convertList( QTextCursor *cursor, const QDomElement &element );
bool convertTable( const QDomElement &element );
bool convertFrame( const QDomElement &element );
bool convertAnnotation( QTextCursor *cursor, const QDomElement &element );
-------------- next part --------------
A non-text attachment was scrubbed...
Name: table-test.odt
Type: application/vnd.oasis.opendocument.text
Size: 8144 bytes
Desc: not available
Url : http://mail.kde.org/pipermail/okular-devel/attachments/20090104/8145bf7d/attachment-0001.odt
More information about the Okular-devel
mailing list