|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright 2001, 2002, 2003, 2004 Nicolas GOUTTE <goutte@kde.org>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library 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
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include "kword13formatone.h"
|
|
|
|
#include "kword13formatother.h"
|
|
|
|
#include "kword13layout.h"
|
|
|
|
#include "kword13frameset.h"
|
|
|
|
#include "kword13picture.h"
|
|
|
|
#include "kword13document.h"
|
|
|
|
#include "kword13parser.h"
|
|
|
|
|
|
|
|
KWord13StackItem::KWord13StackItem() : elementType( KWord13TypeUnknown ), m_currentFrameset( 0 )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KWord13StackItem::~KWord13StackItem()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KWord13Parser::KWord13Parser( KWord13Document* kwordDocument )
|
|
|
|
: m_kwordDocument(kwordDocument), m_currentParagraph( 0 ),
|
|
|
|
m_currentLayout( 0 ), m_currentFormat( 0 )
|
|
|
|
{
|
|
|
|
parserStack.setAutoDelete( true );
|
|
|
|
KWord13StackItem* bottom = new KWord13StackItem;
|
|
|
|
bottom->elementType = KWord13TypeBottom;
|
|
|
|
parserStack.push( bottom ); //Security item (not to empty the stack)
|
|
|
|
}
|
|
|
|
|
|
|
|
KWord13Parser::~KWord13Parser( void )
|
|
|
|
{
|
|
|
|
parserStack.clear();
|
|
|
|
delete m_currentParagraph;
|
|
|
|
delete m_currentLayout;
|
|
|
|
delete m_currentFormat;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::startElementFormatOneProperty( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem)
|
|
|
|
{
|
|
|
|
// ### TODO: check status
|
|
|
|
if ( stackItem->elementType == KWord13TypeLayoutFormatOne )
|
|
|
|
{
|
|
|
|
if ( ! m_currentLayout )
|
|
|
|
{
|
|
|
|
kdError(30520) << "No current LAYOUT for storing FORMAT property: " << name << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < attributes.count(); ++i )
|
|
|
|
{
|
|
|
|
TQString attrName ( name );
|
|
|
|
attrName += ':';
|
|
|
|
attrName += attributes.qName( i );
|
|
|
|
m_currentLayout->m_format.m_properties[ attrName ] = attributes.value( i );
|
|
|
|
kdDebug(30520) << "Format Property (for LAYOUT): " << attrName << " = " << attributes.value( i ) << endl;
|
|
|
|
}
|
|
|
|
stackItem->elementType = KWord13TypeEmpty;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if ( stackItem->elementType == KWord13TypeFormat )
|
|
|
|
{
|
|
|
|
if ( ! m_currentFormat )
|
|
|
|
{
|
|
|
|
kdError(30520) << "No current FORMAT for storing FORMAT property: " << name << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
KWord13FormatOneData* data = m_currentFormat->getFormatOneData();
|
|
|
|
|
|
|
|
if ( ! data )
|
|
|
|
{
|
|
|
|
kdError(30520) << "Current FORMAT cannot store FORMAT text property: " << name << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < attributes.count(); ++i )
|
|
|
|
{
|
|
|
|
TQString attrName ( name );
|
|
|
|
attrName += ':';
|
|
|
|
attrName += attributes.qName( i );
|
|
|
|
data->m_properties[ attrName ] = attributes.value( i );
|
|
|
|
kdDebug(30520) << "Format Property (for FORMATS): " << attrName << " = " << attributes.value( i ) << endl;
|
|
|
|
}
|
|
|
|
stackItem->elementType = KWord13TypeEmpty;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if ( stackItem->elementType == KWord13TypeIgnore )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdError(30520) << "Wrong tqparents for FORMAT property: " << name << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::startElementLayoutProperty( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem)
|
|
|
|
{
|
|
|
|
// ### TODO: check status
|
|
|
|
if ( stackItem->elementType == KWord13TypeIgnore )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if ( m_currentLayout )
|
|
|
|
{
|
|
|
|
for (int i = 0; i < attributes.count(); ++i )
|
|
|
|
{
|
|
|
|
TQString attrName ( name );
|
|
|
|
attrName += ':';
|
|
|
|
attrName += attributes.qName( i );
|
|
|
|
m_currentLayout->m_layoutProperties[ attrName ] = attributes.value( i );
|
|
|
|
kdDebug(30520) << "Layout Property: " << attrName << " = " << attributes.value( i ) << endl;
|
|
|
|
}
|
|
|
|
stackItem->elementType = KWord13TypeEmpty;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdError(30520) << "No current tqlayout for storing property: " << name << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::startElementName( const TQString&, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
|
|
|
|
{
|
|
|
|
if ( stackItem->elementType != KWord13TypeLayout )
|
|
|
|
{
|
|
|
|
// We have something else than a LAYOU/STYLE, so ignore for now.
|
|
|
|
stackItem->elementType = KWord13TypeIgnore;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
stackItem->elementType = KWord13TypeEmpty;
|
|
|
|
|
|
|
|
if ( m_currentLayout )
|
|
|
|
{
|
|
|
|
m_currentLayout->m_name = attributes.value( "value" );
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::startElementFormat( const TQString&, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
|
|
|
|
{
|
|
|
|
// ### TODO: check tqparent?
|
|
|
|
if ( stackItem->elementType == KWord13TypeIgnore )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if ( stackItem->elementType == KWord13TypeLayout )
|
|
|
|
{
|
|
|
|
stackItem->elementType = KWord13TypeLayoutFormatOne;
|
|
|
|
return true; // Everything is done directly on the tqlayout
|
|
|
|
}
|
|
|
|
else if ( stackItem->elementType != KWord13TypeFormatsPlural )
|
|
|
|
{
|
|
|
|
kdError(30520) << "<FORMAT> is child neither of <FORMATS> nor of <LAYOUT> nor of <STYLE>! Aborting!" << endl;
|
|
|
|
return false; // Assume parsing error!
|
|
|
|
}
|
|
|
|
|
|
|
|
stackItem->elementType = KWord13TypeFormat;
|
|
|
|
|
|
|
|
if ( m_currentFormat )
|
|
|
|
{
|
|
|
|
kdWarning(30520) << "Current format already defined!" << endl;
|
|
|
|
delete m_currentFormat;
|
|
|
|
m_currentFormat = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ok = false;
|
|
|
|
const int id = attributes.value( "id" ).toInt( &ok );
|
|
|
|
|
|
|
|
if ( id == 1 && ok ) // Normal text
|
|
|
|
{
|
|
|
|
KWord13FormatOne* one = new KWord13FormatOne;
|
|
|
|
const int len = attributes.value( "len" ).toInt( &ok );
|
|
|
|
if ( ok )
|
|
|
|
one->m_length = len;
|
|
|
|
m_currentFormat = one;
|
|
|
|
}
|
|
|
|
else if ( id == 4 && ok ) // Variable
|
|
|
|
{
|
|
|
|
stackItem->elementType = KWord13TypeVariable;
|
|
|
|
m_currentFormat = new KWord13FormatFour;
|
|
|
|
}
|
|
|
|
else if ( id == 6 && ok ) // Anchor
|
|
|
|
{
|
|
|
|
stackItem->elementType = KWord13TypeAnchor;
|
|
|
|
m_currentFormat = new KWord13FormatSix;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// ### TODO: provisory
|
|
|
|
stackItem->elementType = KWord13TypeIgnore;
|
|
|
|
m_currentFormat = new KWord13Format;
|
|
|
|
if ( ok )
|
|
|
|
m_currentFormat->m_id = id;
|
|
|
|
}
|
|
|
|
const int pos = attributes.value( "pos" ).toInt( &ok );
|
|
|
|
if ( ok )
|
|
|
|
{
|
|
|
|
m_currentFormat->m_pos = pos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdWarning(30520) << "Cannot set position of <FORMAT>: " << attributes.value( "pos" ) << endl;
|
|
|
|
return false; // Assume parse error!
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug(30520) << "<FORMAT id=\"" << id << "\" pos=\"" << pos << "\" len=\"" << attributes.value( "len" ) << "\">" << endl;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::startElementLayout( const TQString&, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
|
|
|
|
{
|
|
|
|
// ### TODO: check tqparent?
|
|
|
|
if ( stackItem->elementType == KWord13TypeIgnore )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
stackItem->elementType = KWord13TypeLayout;
|
|
|
|
|
|
|
|
if ( m_currentFormat )
|
|
|
|
{
|
|
|
|
kdWarning(30520) << "Current format defined! (Layout)" << endl;
|
|
|
|
delete m_currentFormat;
|
|
|
|
m_currentFormat = 0;
|
|
|
|
}
|
|
|
|
if ( m_currentLayout )
|
|
|
|
{
|
|
|
|
// Delete an eventually already existing paragraph (should not happen)
|
|
|
|
kdWarning(30520) << "Current tqlayout already defined!" << endl;
|
|
|
|
delete m_currentLayout;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_currentLayout = new KWord13Layout;
|
|
|
|
m_currentLayout->m_outline = ( attributes.value( "outline" ) == "true" );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::startElementParagraph( const TQString&, const TQXmlAttributes&, KWord13StackItem *stackItem )
|
|
|
|
{
|
|
|
|
if ( stackItem->elementType == KWord13TypeUnknownFrameset )
|
|
|
|
{
|
|
|
|
stackItem->elementType = KWord13TypeIgnore;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
stackItem->elementType = KWord13TypeParagraph;
|
|
|
|
|
|
|
|
if ( m_currentParagraph )
|
|
|
|
{
|
|
|
|
// Delete an eventually already existing paragraph (should not happen)
|
|
|
|
kdWarning(30520) << "Current paragraph already defined!" << endl;
|
|
|
|
delete m_currentParagraph;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_currentParagraph = new KWord13Paragraph;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::startElementFrame( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
|
|
|
|
{
|
|
|
|
if ( stackItem->elementType == KWord13TypeFrameset || stackItem->elementType == KWord13TypePictureFrameset )
|
|
|
|
{
|
|
|
|
stackItem->elementType = KWord13TypeEmpty;
|
|
|
|
if ( stackItem->m_currentFrameset )
|
|
|
|
{
|
|
|
|
const int num = ++stackItem->m_currentFrameset->m_numFrames;
|
|
|
|
for (int i = 0; i < attributes.count(); ++i )
|
|
|
|
{
|
|
|
|
TQString attrName ( name );
|
|
|
|
attrName += ':';
|
|
|
|
attrName += TQString::number( num );
|
|
|
|
attrName += ':';
|
|
|
|
attrName += attributes.qName( i );
|
|
|
|
stackItem->m_currentFrameset->m_frameData[ attrName ] = attributes.value( i );
|
|
|
|
kdDebug(30520) << "FrameData: " << attrName << " = " << attributes.value( i ) << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdError(30520) << "Data of <FRAMESET> not found" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( stackItem->elementType != KWord13TypeUnknownFrameset )
|
|
|
|
{
|
|
|
|
kdError(30520) << "<FRAME> not child of <FRAMESET>" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::startElementFrameset( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
|
|
|
|
{
|
|
|
|
const TQString frameTypeStr( attributes.value( "frameType" ) );
|
|
|
|
const TQString frameInfoStr( attributes.value( "frameInfo" ) );
|
|
|
|
|
|
|
|
if ( frameTypeStr.isEmpty() || frameInfoStr.isEmpty() )
|
|
|
|
{
|
|
|
|
kdError(30520) << "<FRAMESET> without frameType or frameInfo attribute!" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const int frameType = frameTypeStr.toInt();
|
|
|
|
const int frameInfo = frameInfoStr.toInt();
|
|
|
|
|
|
|
|
if ( frameType == 1 )
|
|
|
|
{
|
|
|
|
stackItem->elementType = KWord13TypeFrameset;
|
|
|
|
KWordTextFrameset* frameset = new KWordTextFrameset( frameType, frameInfo, attributes.value( "name" ) );
|
|
|
|
|
|
|
|
// Normal text frame (in or outside a table)
|
|
|
|
if ( ( !frameInfo ) && attributes.value( "grpMgr" ).isEmpty() )
|
|
|
|
{
|
|
|
|
m_kwordDocument->m_normalTextFramesetList.append( frameset );
|
|
|
|
stackItem->m_currentFrameset = m_kwordDocument->m_normalTextFramesetList.current();
|
|
|
|
}
|
|
|
|
else if ( !frameInfo )
|
|
|
|
{
|
|
|
|
// We just store the frameset in the frameset table list
|
|
|
|
// Grouping the framesets by table will be done after the parsing, not now.
|
|
|
|
m_kwordDocument->m_tableFramesetList.append( frameset );
|
|
|
|
stackItem->m_currentFrameset = m_kwordDocument->m_tableFramesetList.current();
|
|
|
|
}
|
|
|
|
else if ( frameInfo >= 1 && frameInfo <= 6 )
|
|
|
|
{
|
|
|
|
m_kwordDocument->m_headerFooterFramesetList.append( frameset );
|
|
|
|
stackItem->m_currentFrameset = m_kwordDocument->m_headerFooterFramesetList.current();
|
|
|
|
}
|
|
|
|
else if ( frameInfo == 7 )
|
|
|
|
{
|
|
|
|
m_kwordDocument->m_footEndNoteFramesetList.append( frameset );
|
|
|
|
stackItem->m_currentFrameset = m_kwordDocument->m_footEndNoteFramesetList.current();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdError(30520) << "Unknown text frameset!" << endl;
|
|
|
|
m_kwordDocument->m_otherFramesetList.append( frameset );
|
|
|
|
stackItem->m_currentFrameset = m_kwordDocument->m_otherFramesetList.current();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( ( frameType == 2 ) // picture or image
|
|
|
|
|| ( frameType == 5 ) ) // ciipart
|
|
|
|
{
|
|
|
|
if ( !frameInfo )
|
|
|
|
{
|
|
|
|
kdWarning(30520) << "Unknown FrameInfo for pictures: " << frameInfo << endl;
|
|
|
|
}
|
|
|
|
stackItem->elementType = KWord13TypePictureFrameset;
|
|
|
|
KWord13PictureFrameset* frameset = new KWord13PictureFrameset( frameType, frameInfo, attributes.value( "name" ) );
|
|
|
|
m_kwordDocument->m_otherFramesetList.append( frameset );
|
|
|
|
stackItem->m_currentFrameset = m_kwordDocument->m_otherFramesetList.current();
|
|
|
|
}
|
|
|
|
// ### frameType == 6 : horizontal line (however KWord did not save it correctly)
|
|
|
|
// ### frameType == 4 : formula
|
|
|
|
// ### frametype == 3 : embedded (but only in <SETTINGS>)
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Frame of unknown/unsupported type
|
|
|
|
kdWarning(30520) << "Unknown/unsupported <FRAMESET> type! Type: " << frameTypeStr << " Info: " << frameInfoStr << endl;
|
|
|
|
stackItem->elementType = KWord13TypeUnknownFrameset;
|
|
|
|
KWord13Frameset* frameset = new KWord13Frameset( frameType, frameInfo, attributes.value( "name" ) );
|
|
|
|
m_kwordDocument->m_otherFramesetList.append( frameset );
|
|
|
|
stackItem->m_currentFrameset = m_kwordDocument->m_otherFramesetList.current();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KWord13Parser::startElementDocumentAttributes( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem,
|
|
|
|
const KWord13StackItemType& allowedParentType, const KWord13StackItemType& newType )
|
|
|
|
{
|
|
|
|
if ( parserStack.current()->elementType == allowedParentType )
|
|
|
|
{
|
|
|
|
stackItem->elementType = newType;
|
|
|
|
for (int i = 0; i < attributes.count(); ++i )
|
|
|
|
{
|
|
|
|
TQString attrName ( name );
|
|
|
|
attrName += ':';
|
|
|
|
attrName += attributes.qName( i );
|
|
|
|
m_kwordDocument->m_documentProperties[ attrName ] = attributes.value( i );
|
|
|
|
kdDebug(30520) << "DocAttr: " << attrName << " = " << attributes.value( i ) << endl;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdError(30520) << "Wrong tqparent!" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::startElementKey( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
|
|
|
|
{
|
|
|
|
const TQString key( calculatePictureKey( attributes.value( "filename" ),
|
|
|
|
attributes.value( "year" ), attributes.value( "month" ), attributes.value( "day" ),
|
|
|
|
attributes.value( "hour" ), attributes.value( "minute" ), attributes.value( "second" ),
|
|
|
|
attributes.value( "msec" ) ) );
|
|
|
|
kdDebug(30520) << "Picture key: " << key << endl;
|
|
|
|
|
|
|
|
if ( stackItem->elementType == KWord13TypePicturesPlural )
|
|
|
|
{
|
|
|
|
KWord13Picture* pic = new KWord13Picture;
|
|
|
|
pic->m_storeName = attributes.value( "name" );
|
|
|
|
if ( pic->m_storeName.isEmpty() )
|
|
|
|
{
|
|
|
|
kdError(30520) << "Picture defined without store name! Aborting!" << endl;
|
|
|
|
return false; // Assume parse error
|
|
|
|
}
|
|
|
|
// ### TODO: catch duplicate keys (should not happen but who knows?)
|
|
|
|
m_kwordDocument->m_pictureDict.insert( key, pic );
|
|
|
|
}
|
|
|
|
else if ( stackItem->elementType == KWord13TypePicture )
|
|
|
|
{
|
|
|
|
// ### TODO: error messages?
|
|
|
|
if ( stackItem->m_currentFrameset )
|
|
|
|
{
|
|
|
|
stackItem->m_currentFrameset->setKey( key );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Neither child of <PICTURES>, <PIXMAPS>, <CLIPARTS>
|
|
|
|
// nor of <PICTURE>, <IMAGE>, <CLIPART>
|
|
|
|
// ### TODO: parse error?
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::startElementAnchor( const TQString& name, const TQXmlAttributes& attributes, KWord13StackItem *stackItem )
|
|
|
|
{
|
|
|
|
if ( stackItem->elementType == KWord13TypeAnchor )
|
|
|
|
{
|
|
|
|
const TQString anchorType ( attributes.value( "type" ) );
|
|
|
|
if ( anchorType == "grpMgr" )
|
|
|
|
kdWarning(30520) << "Anchor of type grpMgr! Not tested!" << endl; // ### TODO
|
|
|
|
else if ( anchorType != "frameset" )
|
|
|
|
{
|
|
|
|
kdError(30520) << "Unsupported anchor type: " << anchorType << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const TQString frameset ( attributes.value( "instance" ) );
|
|
|
|
if ( frameset.isEmpty() )
|
|
|
|
{
|
|
|
|
kdError(30520) << "Anchor to an empty frameset name! Aborting!" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( m_currentFormat )
|
|
|
|
{
|
|
|
|
KWord13FormatSix* six = (KWord13FormatSix*) m_currentFormat;
|
|
|
|
six->m_anchorName = frameset;
|
|
|
|
}
|
|
|
|
// add frameset name to the list of anchored framesets
|
|
|
|
if ( m_kwordDocument->m_anchoredFramesetNames.tqfind( frameset ) == m_kwordDocument->m_anchoredFramesetNames.end() )
|
|
|
|
{
|
|
|
|
m_kwordDocument->m_anchoredFramesetNames.append( frameset );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdError(30520) << "Anchor not child of <FORMAT id=\"6\"> Aborting!" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KWord13Parser::startElement( const TQString&, const TQString&, const TQString& name, const TQXmlAttributes& attributes )
|
|
|
|
{
|
|
|
|
kdDebug(30520) << indent << "<" << name << ">" << endl; // DEBUG
|
|
|
|
indent += "*"; //DEBUG
|
|
|
|
if (parserStack.isEmpty())
|
|
|
|
{
|
|
|
|
kdError(30520) << "Stack is empty!! Aborting! (in KWordParser::startElement)" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new stack element copying the top of the stack.
|
|
|
|
KWord13StackItem *stackItem=new KWord13StackItem(*parserStack.current());
|
|
|
|
|
|
|
|
if (!stackItem)
|
|
|
|
{
|
|
|
|
kdError(30520) << "Could not create Stack Item! Aborting! (in StructureParser::startElement)" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
stackItem->itemName=name;
|
|
|
|
|
|
|
|
bool success=false;
|
|
|
|
|
|
|
|
// Order of element names: probability in a document
|
|
|
|
if ( name == "COLOR" || name == "FONT" || name =="SIZE"
|
|
|
|
|| name == "WEIGHT" || name == "ITALIC" || name == "UNDERLINE"
|
|
|
|
|| name == "STRIKEOUT" || name == "VERTALIGN" || name == "SHADOW"
|
|
|
|
|| name == "FONTATTRIBUTE" || name == "LANGUAGE"
|
|
|
|
|| name == "TEXTBACKGROUNDCOLOR" || name == "OFFSETFROMBASELINE" )
|
|
|
|
{
|
|
|
|
success = startElementFormatOneProperty( name, attributes, stackItem );
|
|
|
|
}
|
|
|
|
else if ( name == "FLOW" || name == "INDENTS" || name == "OFFSETS"
|
|
|
|
|| name == "LINESPACING" || name == "PAGEBREAKING"
|
|
|
|
|| name == "LEFTBORDER" || name == "RIGHTBORDER" || name == "FOLLOWING"
|
|
|
|
|| name == "TOPBORDER" || name == "BOTTOMBORDER" || name == "COUNTER" )
|
|
|
|
{
|
|
|
|
success = startElementLayoutProperty( name, attributes, stackItem );
|
|
|
|
}
|
|
|
|
else if ( name == "TEXT" )
|
|
|
|
{
|
|
|
|
if ( stackItem->elementType == KWord13TypeParagraph && m_currentParagraph )
|
|
|
|
{
|
|
|
|
stackItem->elementType = KWord13TypeText;
|
|
|
|
m_currentParagraph->setText( TQString() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stackItem->elementType = KWord13TypeIgnore;
|
|
|
|
}
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
else if ( name == "NAME" )
|
|
|
|
{
|
|
|
|
success = startElementName( name, attributes, stackItem );
|
|
|
|
}
|
|
|
|
else if ( name == "FORMATS" )
|
|
|
|
{
|
|
|
|
if ( stackItem->elementType == KWord13TypeParagraph && m_currentParagraph )
|
|
|
|
{
|
|
|
|
stackItem->elementType = KWord13TypeFormatsPlural;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stackItem->elementType = KWord13TypeIgnore;
|
|
|
|
}
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
else if ( name == "PARAGRAPH" )
|
|
|
|
{
|
|
|
|
success = startElementParagraph( name, attributes, stackItem );
|
|
|
|
}
|
|
|
|
else if ( name == "FORMAT" )
|
|
|
|
{
|
|
|
|
success = startElementFormat( name, attributes, stackItem );
|
|
|
|
}
|
|
|
|
else if (name == "LAYOUT" )
|
|
|
|
{
|
|
|
|
success = startElementLayout( name, attributes, stackItem );
|
|
|
|
}
|
|
|
|
else if ( name == "TYPE" )
|
|
|
|
{
|
|
|
|
// ### TEMPORARY
|
|
|
|
if ( m_currentFormat && ( stackItem->elementType == KWord13TypeVariable ) )
|
|
|
|
{
|
|
|
|
( (KWord13FormatFour*) m_currentFormat ) -> m_text = attributes.value( "text" );
|
|
|
|
}
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
else if ( name == "KEY" )
|
|
|
|
{
|
|
|
|
success = startElementKey( name, attributes, stackItem );
|
|
|
|
}
|
|
|
|
else if ( name == "ANCHOR" )
|
|
|
|
{
|
|
|
|
success = startElementAnchor( name, attributes, stackItem );
|
|
|
|
}
|
|
|
|
else if ( name == "PICTURE" || name == "IMAGE" || name == "CLIPART" )
|
|
|
|
{
|
|
|
|
// ### TODO: keepAspectRatio (but how to transform it to OASIS)
|
|
|
|
if ( stackItem->elementType == KWord13TypePictureFrameset )
|
|
|
|
{
|
|
|
|
stackItem->elementType = KWord13TypePicture;
|
|
|
|
}
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
else if ( name == "FRAME" )
|
|
|
|
{
|
|
|
|
success = startElementFrame( name, attributes, stackItem );
|
|
|
|
}
|
|
|
|
else if ( name == "FRAMESET" )
|
|
|
|
{
|
|
|
|
success = startElementFrameset( name, attributes, stackItem );
|
|
|
|
}
|
|
|
|
else if (name == "STYLE" )
|
|
|
|
{
|
|
|
|
success = startElementLayout( name, attributes, stackItem );
|
|
|
|
}
|
|
|
|
else if ( name == "DOC" )
|
|
|
|
{
|
|
|
|
success = startElementDocumentAttributes( name, attributes, stackItem, KWord13TypeBottom, KWord13TypeDocument );
|
|
|
|
}
|
|
|
|
else if ( name == "PAPER")
|
|
|
|
{
|
|
|
|
success = startElementDocumentAttributes( name, attributes, stackItem, KWord13TypeDocument, KWord13TypePaper );
|
|
|
|
}
|
|
|
|
else if ( name == "PAPERBORDERS" )
|
|
|
|
{
|
|
|
|
success = startElementDocumentAttributes( name, attributes, stackItem, KWord13TypePaper, KWord13TypeEmpty );
|
|
|
|
}
|
|
|
|
else if ( ( name == "ATTRIBUTES" ) || ( name == "VARIABLESETTINGS" )
|
|
|
|
|| ( name == "FOOTNOTESETTINGS" ) || ( name == "ENDNOTESETTINGS" ) )
|
|
|
|
{
|
|
|
|
success = startElementDocumentAttributes( name, attributes, stackItem, KWord13TypeDocument, KWord13TypeEmpty );
|
|
|
|
}
|
|
|
|
else if ( name == "FRAMESTYLE" )
|
|
|
|
{
|
|
|
|
// ### TODO, but some of the <STYLE> tqchildren are also tqchildren of <FRAMESTYLE>, so we have to set it to "ignore"
|
|
|
|
stackItem->elementType = KWord13TypeIgnore;
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
else if ( name == "PICTURES" || name == "PIXMAPS" || name == "CLIPARTS" )
|
|
|
|
{
|
|
|
|
// We just need a separate "type" for the <KEY> tqchildren
|
|
|
|
stackItem->elementType = KWord13TypePicturesPlural;
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stackItem->elementType = KWord13TypeUnknown;
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( success )
|
|
|
|
{
|
|
|
|
parserStack.push( stackItem );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // We have a problem so destroy our resources.
|
|
|
|
delete stackItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser :: endElement( const TQString&, const TQString& , const TQString& name)
|
|
|
|
{
|
|
|
|
indent.remove( 0, 1 ); // DEBUG
|
|
|
|
//kdDebug(30520) << indent << "</" << name << ">" << endl; // DEBUG
|
|
|
|
if (parserStack.isEmpty())
|
|
|
|
{
|
|
|
|
kdError(30520) << "Stack is empty!! Aborting! (in StructureParser::endElement)" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool success=false;
|
|
|
|
|
|
|
|
KWord13StackItem *stackItem=parserStack.pop();
|
|
|
|
|
|
|
|
if ( name == "PARAGRAPH" )
|
|
|
|
{
|
|
|
|
if ( stackItem->m_currentFrameset && m_currentParagraph )
|
|
|
|
{
|
|
|
|
if ( stackItem->m_currentFrameset->addParagraph( *m_currentParagraph ) )
|
|
|
|
{
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
// ### HACK: do not delete the data of <FORMATS>
|
|
|
|
m_currentParagraph->m_formats.setAutoDelete( false );
|
|
|
|
}
|
|
|
|
else if ( stackItem->elementType == KWord13TypeIgnore )
|
|
|
|
{
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
delete m_currentParagraph;
|
|
|
|
m_currentParagraph = 0;
|
|
|
|
}
|
|
|
|
else if ( name == "FORMAT" )
|
|
|
|
{
|
|
|
|
if ( stackItem->elementType == KWord13TypeFormat )
|
|
|
|
{
|
|
|
|
if ( m_currentParagraph )
|
|
|
|
{
|
|
|
|
m_currentParagraph->m_formats.append( m_currentFormat );
|
|
|
|
kdDebug(30520) << "Adding to <FORMATS>: " << ((void*) m_currentFormat) << endl;
|
|
|
|
m_currentFormat = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdError(30520) << "No paragraph to store <FORMAT>! Aborting!" << endl;
|
|
|
|
delete m_currentFormat;
|
|
|
|
m_currentFormat = 0;
|
|
|
|
return false; // Assume parsing error!
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else if ( stackItem->elementType == KWord13TypeLayoutFormatOne )
|
|
|
|
{
|
|
|
|
// Nothing to do!
|
|
|
|
}
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
else if ( name == "LAYOUT" )
|
|
|
|
{
|
|
|
|
if ( m_currentLayout && m_currentParagraph )
|
|
|
|
{
|
|
|
|
m_currentParagraph->m_layout = *m_currentLayout;
|
|
|
|
}
|
|
|
|
delete m_currentLayout;
|
|
|
|
m_currentLayout = 0;
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
else if ( name == "STYLE" )
|
|
|
|
{
|
|
|
|
if ( m_kwordDocument && m_currentLayout )
|
|
|
|
{
|
|
|
|
if ( m_currentLayout->m_name.isEmpty() )
|
|
|
|
{
|
|
|
|
// ### TODO: what should be really done with anonymous styles (should not happen but it would have consequences)
|
|
|
|
kdError(30520) << "Anonymous style found! Aborting" << endl;
|
|
|
|
return false; // Assume a parsing error!
|
|
|
|
}
|
|
|
|
m_kwordDocument->m_styles.append( *m_currentLayout );
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
delete m_currentLayout;
|
|
|
|
m_currentLayout = 0;
|
|
|
|
}
|
|
|
|
else if ( name == "DOC" )
|
|
|
|
{
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
success = true; // No problem, so authorisation to continue parsing
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!success)
|
|
|
|
{
|
|
|
|
// If we have no success, then it was surely a tag mismatch. Help debugging!
|
|
|
|
kdError(30506) << "Found closing tag name: " << name << " expected: " << stackItem->itemName << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete stackItem;
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser :: characters ( const TQString & ch )
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
// DEBUG start
|
|
|
|
if (ch=="\n")
|
|
|
|
{
|
|
|
|
kdDebug(30520) << indent << " (LINEFEED)" << endl;
|
|
|
|
}
|
|
|
|
else if (ch.length()> 40)
|
|
|
|
{ // 40 characters are enough (especially for image data)
|
|
|
|
kdDebug(30520) << indent << " :" << ch.left(40) << "..." << endl;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdDebug(30520) << indent << " :" << ch << ":" << endl;
|
|
|
|
}
|
|
|
|
// DEBUG end
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (parserStack.isEmpty())
|
|
|
|
{
|
|
|
|
kdError(30520) << "Stack is empty!! Aborting! (in StructureParser::characters)" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool success=false;
|
|
|
|
|
|
|
|
KWord13StackItem *stackItem = parserStack.current();
|
|
|
|
|
|
|
|
if ( stackItem->elementType == KWord13TypeText )
|
|
|
|
{
|
|
|
|
// <TEXT>
|
|
|
|
if ( m_currentParagraph )
|
|
|
|
{
|
|
|
|
bool found = false; // Some unexpected control character?
|
|
|
|
// ### TODO: this is perhaps a good point to check for non-XML characters
|
|
|
|
const uint length = ch.length();
|
|
|
|
for ( uint i = 0; i < length; ++i )
|
|
|
|
{
|
|
|
|
const ushort uni = ch.tqat(i).tqunicode();
|
|
|
|
if ( uni >= 32 )
|
|
|
|
continue; // Normal character
|
|
|
|
else if ( uni == 9 || uni == 10 || uni == 13)
|
|
|
|
continue; // Tabulator, Line Feed, Carriage Return
|
|
|
|
else if ( uni == 1 )
|
|
|
|
{
|
|
|
|
// Old KWord documents have a TQChar(1) as anchor character
|
|
|
|
// So replace it with the anchor character of recent KWord versions
|
|
|
|
ch[i]='#';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ch[i]='?';
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( found )
|
|
|
|
kdWarning(30520) << "Unexcepted control characters found in text!" << endl;
|
|
|
|
m_currentParagraph->appendText( ch );
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdError(30520) << "No current paragraph defined! Tag mismatch?" << endl;
|
|
|
|
success = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (stackItem->elementType==KWord13TypeEmpty)
|
|
|
|
{
|
|
|
|
success=ch.stripWhiteSpace().isEmpty();
|
|
|
|
if (!success)
|
|
|
|
{
|
|
|
|
// We have a parsing error, so abort!
|
|
|
|
kdError(30520) << "Empty element "<< stackItem->itemName <<" is not empty! Aborting! (in KWordParser::characters)" << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
success=true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::warning(const TQXmlParseException& exception)
|
|
|
|
{
|
|
|
|
kdWarning(30520) << "XML parsing warning: line " << exception.lineNumber()
|
|
|
|
<< " col " << exception.columnNumber() << " message: " << exception.message() << endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::error(const TQXmlParseException& exception)
|
|
|
|
{
|
|
|
|
// A XML error is recoverable, so it is only a KDE warning
|
|
|
|
kdWarning(30520) << "XML parsing error: line " << exception.lineNumber()
|
|
|
|
<< " col " << exception.columnNumber() << " message: " << exception.message() << endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWord13Parser::fatalError (const TQXmlParseException& exception)
|
|
|
|
{
|
|
|
|
kdError(30520) << "XML parsing fatal error: line " << exception.lineNumber()
|
|
|
|
<< " col " << exception.columnNumber() << " message: " << exception.message() << endl;
|
|
|
|
// ### TODO: user message box
|
|
|
|
return false; // Stop parsing now, we do not need further errors.
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KWord13Parser::calculatePictureKey( const TQString& filename,
|
|
|
|
const TQString& year, const TQString& month, const TQString& day,
|
|
|
|
const TQString& hour, const TQString& minute, const TQString& second,
|
|
|
|
const TQString& microsecond ) const
|
|
|
|
{
|
|
|
|
bool ok;
|
|
|
|
bool globalOk = true;
|
|
|
|
|
|
|
|
ok = false;
|
|
|
|
const int iYear = year.toInt( & ok );
|
|
|
|
globalOk = globalOk && ok;
|
|
|
|
|
|
|
|
ok = false;
|
|
|
|
const int iMonth = month.toInt( & ok );
|
|
|
|
globalOk = globalOk && ok;
|
|
|
|
|
|
|
|
ok = false;
|
|
|
|
const int iDay = day.toInt( & ok );
|
|
|
|
globalOk = globalOk && ok;
|
|
|
|
|
|
|
|
ok = false;
|
|
|
|
const int iHour = hour.toInt( & ok );
|
|
|
|
globalOk = globalOk && ok;
|
|
|
|
|
|
|
|
ok = false;
|
|
|
|
const int iMinute = minute.toInt( & ok );
|
|
|
|
globalOk = globalOk && ok;
|
|
|
|
|
|
|
|
ok = false;
|
|
|
|
const int iSecond = second.toInt( & ok );
|
|
|
|
globalOk = globalOk && ok;
|
|
|
|
|
|
|
|
ok = false;
|
|
|
|
const int iMicrosecond = microsecond.toInt( & ok );
|
|
|
|
globalOk = globalOk && ok;
|
|
|
|
|
|
|
|
if ( globalOk )
|
|
|
|
{
|
|
|
|
// No error until then, so check if the date/time is valid at all
|
|
|
|
globalOk = globalOk && TQDate::isValid( iYear, iMonth, iDay );
|
|
|
|
globalOk = globalOk && TQTime::isValid( iHour, iMinute, iSecond, iMicrosecond );
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDateTime dt;
|
|
|
|
if ( globalOk )
|
|
|
|
{
|
|
|
|
// The date/time seems correct
|
|
|
|
dt = TQDateTime( TQDate( iYear, iMonth, iDay ), TQTime( iHour, iMinute, iSecond, iMicrosecond ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// *NIX epoch (We do not really care if it is UTC or local time)
|
|
|
|
dt = TQDateTime( TQDate( 1970, 1, 1 ), TQTime( 0, 0, 0, 0 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// We put the date/time first, as if the date is useful, it will have faster a difference than a path
|
|
|
|
// where the common pth might be very long.
|
|
|
|
|
|
|
|
// Output the date/time as compact as possible
|
|
|
|
TQString result ( dt.toString( "yyyyMMddhhmmsszzz" ) );
|
|
|
|
result += '@'; // A separator
|
|
|
|
result += filename;
|
|
|
|
return result;
|
|
|
|
}
|