/* This file is part of the KDE project Copyright (C) 2001 Ariya Hidayat 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 "kwordfilter.h" #include "parser.h" #include #include #include #include using namespace WP; // NOTE: 1 wpu = 1/1200 inch and 1 inch = 72 point static double WPUToPoint( unsigned wpu ) { return wpu * 72 / 1200; } // helper class class KWordFormat { public: bool bold, italic, underline, doubleunderline; bool striked, superscript, subscript, redline; bool color, highlight; int red, green, blue; int bgred, bggreen, bgblue; double fontsize; TQString fontface; KWordFormat(); TQString asXML(); }; KWordFormat::KWordFormat() { bold = italic = underline = doubleunderline = FALSE; striked = superscript = subscript = redline = FALSE; color = highlight = FALSE; red = green = blue = 0; bgred = bggreen = bgblue = 255; fontsize = 0.0; fontface = ""; } TQString KWordFormat::asXML() { TQString result; if( bold ) result.append( " \n" ); if( italic ) result.append( " \n" ); if( underline ) result.append( " \n" ); if( doubleunderline ) result.append( " \n" ); if( striked ) result.append( " \n" ); if( subscript ) result.append( "\n" ); if( superscript ) result.append( "\n" ); if( !fontface.isEmpty() ) result.append( "\n" ); if( fontsize > 0.0 ) result.append( " \n" ); if( color ) result.append( " \n" ); if( highlight ) result.append( " \n" ); return result; } static TQString mapAlign( Token::Align align ) { switch( align ) { case Token::Left: return "left"; case Token::Right: return "right"; case Token::Center: return "center"; case Token::Full: return "justify"; case Token::All: return "justify"; } return "left"; } // NOTE: KWord value for linespace: 72=one, 144=double, .. // Special case: "0" is normal, "oneandhalf" is 108, "double" is 144. static TQString mapLinespace( double linespace ) { return TQString::number( linespace ); } KWordFilter::KWordFilter ():Parser () { } bool KWordFilter::parse (const TQString & filename) { int frameLeftMargin = 36, frameRightMargin = 36; // quick hack if (!Parser::parse (filename)) return FALSE; // this will force very last text and formatting to be flushed as well tokens.append( new Token( Token::HardReturn ) ); TQString text; TQString tqlayout; TQString formats; int LeftMargin = 0; int TopMargin = 36; int RightMargin = 0; int BottomMargin = 36; int LeftMarginAdjust = 0; int RightMarginAdjust = 0; int lm = 0, rm = 0; Token::Align align = Token::Left; double linespace = 1.0; root = ""; KWordFormat flag; int format_pos; TQString fmt; // FIXME replace with doc initial code or default style format_pos = 0; fmt = flag.asXML(); for (TQPtrListIterator < Token > it (tokens); it; ++it) { unsigned int ucode; int attr; int len; Token *t = it.current (); Token::Type type = t->type (); switch (type) { case Token::Text: text.append( t->text() ); break; case Token::SoftSpace: case Token::HardSpace: text.append( " " ); break; case Token::SoftReturn: // ignore break; case Token::AttrOff: case Token::AttrOn: case Token::FontColor: case Token::FontSize: case Token::FontFace: case Token::HighlightOn: case Token::HighlightOff: if( type == Token::FontColor ) { flag.color = true; flag.red = t->red(); flag.green = t->green(); flag.blue= t->blue(); } else if( type == Token::HighlightOn ) { flag.highlight = true; flag.bgred = t->red(); flag.bggreen = t->green(); flag.bgblue = t->blue(); } else if( type == Token::HighlightOff ) { // RGB in the data is last used highlight color // to go back to normal color, simply XOR would do the trick flag.highlight = false; flag.bgred ^= t->red(); flag.bggreen ^= t->green(); flag.bgblue ^= t->blue(); } else if( type == Token::FontSize ) { // WP font size is 1/3600th inch // NOTE 72 pt is 1 inch if( t->value() > 50 ) flag.fontsize = t->value()*72.0/3600; } else if( type == Token::FontFace ) { flag.fontface = t->fontface(); } else { attr = t->attr(); if( attr == Token::Bold ) flag.bold = ( type == Token::AttrOn ); if( attr == Token::Italic ) flag.italic = ( type == Token::AttrOn ); if( attr == Token::Underline) flag.underline = ( type == Token::AttrOn ); if( attr == Token::DoubleUnderline ) flag.doubleunderline = ( type == Token::AttrOn ); if( attr == Token::StrikedOut ) flag.striked = ( type == Token::AttrOn ); if( attr == Token::Subscript ) flag.subscript = ( type == Token::AttrOn ); if( attr == Token::Superscript ) flag.superscript = ( type == Token::AttrOn ); if( attr == Token::Redline ) flag.redline = ( type == Token::AttrOn ); } // process previous fmt first len = text.length() - format_pos; formats.append ( "\n" ); formats.append( fmt ); formats.append ( "\n" ); // now current format fmt = flag.asXML(); format_pos= text.length(); break; case Token::HardReturn: case Token::DormantHardReturn: // last formatting not flushed // SEE ABOVE len = text.length() - format_pos; formats.append ( " \n" ); formats.append( " " + fmt ); formats.append ( " \n" ); tqlayout = ""; tqlayout.append( "\n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); lm = LeftMargin + LeftMarginAdjust - frameLeftMargin; rm = RightMargin + RightMarginAdjust - frameRightMargin; tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( " \n" ); tqlayout.append( "\n" ); // encode text for XML-ness // FIXME could be faster without TQRegExp text.replace( TQRegExp("&"), "&" ); text.replace( TQRegExp("<"), "<" ); text.replace( TQRegExp(">"), ">" ); text.replace( TQRegExp("\""), """ ); text.replace( TQRegExp("'"), "'" ); // construct the root.append( "\n" ); root.append( "" + text + "\n" ); root.append( "\n"); root.append( formats ); root.append( "\n"); root.append( tqlayout ); root.append( "\n" ); // for the next paragraph text = ""; formats = ""; format_pos = 0; fmt = flag.asXML(); break; case Token::HardHyphen: text.append( "-" ); break; case Token::LeftMargin: LeftMargin = (int) WPUToPoint( t->value() ); break; case Token::RightMargin: RightMargin = (int) WPUToPoint( t->value() ); break; case Token::TopMargin: TopMargin = (int) WPUToPoint( t->value() ); break; case Token::BottomMargin: BottomMargin = (int) WPUToPoint( t->value() ); break; case Token::LeftMarginAdjust: LeftMarginAdjust = (int)WPUToPoint( t->value() ); break; case Token::RightMarginAdjust: RightMarginAdjust = (int)WPUToPoint( t->value() ); break; case Token::Justification: align = t->align(); break; case Token::Linespace: // NOTE assume 1.0 = 12 pt, 2.0 = 24 pt, 1.5=18 // from parser.cpp, linespace is stored as 1/65536th inch linespace = t->value() * 12.0 / 65536; break; case Token::ExtChar: ucode = Parser::ExtCharToUnicode (t->charset (), t->charcode ()); if (ucode == 0) ucode = 32; text.append( TQChar (ucode) ); break; case Token::TabHardFlushRight: // FIXME text.append( " " ); break; case Token::None: default: break; }; } TQString content = root; root = "\n"; root.append( "\n"); // quick hack, think of something better in the future LeftMargin = RightMargin = 36; // paper definition root.append( "\n" ); root.append( " \n" ); root.append( "\n" ); root.append( "\n" ); root.append( "\n" ); root.append( "\n" ); root.append( "\n" ); root.append( content ); root.append( "\n" ); root.append( "\n" ); root.append( "\n" ); // in case no document summary is available, then make default // set so that basename of the filename becomes the document title // e.g /home/ariya/test/resume.wpd will have 'resume' as the title if( docTitle.isEmpty() ) { TQFileInfo info( filename ); docTitle = info.baseName(); } // create document information documentInfo = "\n"; documentInfo += "\n"; documentInfo += "\n"; documentInfo += "\n"; documentInfo += "" + docAuthor + "\n"; documentInfo += "\n"; documentInfo += "\n"; documentInfo += "\n"; documentInfo += "\n"; documentInfo += "\n"; documentInfo += "\n"; documentInfo += "\n"; documentInfo += "" + docTitle + "\n"; documentInfo += "\n"; documentInfo += ""; return TRUE; }