amiproimport.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002 Ariya Hidayat <ariyahidayat@yahoo.de>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include <config.h>
21
22#ifdef HAVE_UNISTD_H
23#include <unistd.h>
24#endif
25
26#include <tqregexp.h>
27#include <tqfileinfo.h>
28#include <tqvaluelist.h>
29#include <tqfont.h>
30
31#include <kdebug.h>
32#include <KoFilterChain.h>
33#include <kgenericfactory.h>
34#include <KoGlobal.h>
35
36#include <amiproimport.h>
37#include <amiproparser.h>
38
39typedef KGenericFactory<AmiProImport, KoFilter> AmiProImportFactory;
40K_EXPORT_COMPONENT_FACTORY( libamiproimport, AmiProImportFactory( "kofficefilters" ) )
41
42AmiProImport::AmiProImport( KoFilter *, const char *, const TQStringList& ):
43 KoFilter()
44{
45}
46
47class AmiProConverter: public AmiProListener
48{
49 public:
50 AmiProConverter();
51 TQString root, documentInfo;
52 virtual bool doOpenDocument();
53 virtual bool doCloseDocument();
54 virtual bool doDefineStyle( const AmiProStyle& style );
55 virtual bool doParagraph( const TQString& text, AmiProFormatList formatList,
56 AmiProLayout& l );
57 private:
58 AmiProStyleList styleList;
59};
60
61// helper function to escape string for XML-ness
62static TQString XMLEscape( const TQString& str )
63{
64 TQString result;
65
66 for( unsigned i=0; i<str.length(); i++ )
67 if( str[i] == '&' ) result += "&amp;";
68 else if( str[i] == '<' ) result += "&lt;";
69 else if( str[i] == '>' ) result += "&gt;";
70 else if( str[i] == '"' ) result += "&quot;";
71 else if( str[i] == TQChar(39) ) result += "&apos;";
72 else result += str[i];
73
74 return result;
75}
76
77// helper function to convert AmiPro format to KWord's FORMAT
78static TQString AmiProFormatAsXML( AmiProFormat format )
79{
80 TQString result;
81
82 TQString fontname = format.fontFamily;
83 if( fontname.isEmpty() ) fontname = KoGlobal::defaultFont().family();
84 TQString fontsize = TQString::number( format.fontSize );
85 TQString boldness = format.bold ? "75" : "50";
86 TQString italic = format.italic ? "1" : "0";
87 TQString strikeout = format.strikethrough ? "1" : "0";
88 TQString vertalign = format.superscript ? "2" : format.subscript ? "1" : "0";
89 TQString underline = format.double_underline ? "double" :
90 format.underline|format.word_underline ? "1" : "0";
91
92 result = "<FORMAT id=\"1\" pos=\"" + TQString::number(format.pos) +
93 "\" len=\"" + TQString::number(format.len) + "\">\n";
94 result.append( " <FONT name=\"" + fontname + "\" />\n" );
95 result.append( " <SIZE value=\"" + fontsize + "\" />\n" );
96 result.append( " <WEIGHT value=\"" + boldness + "\" />\n" );
97 result.append( " <ITALIC value=\"" + italic + "\" />\n" );
98 result.append( " <STRIKEOUT value=\"" + strikeout + "\" />\n" );
99 result.append( " <VERTALIGN value=\"" + vertalign + "\" />\n" );
100 result.append( " <UNDERLINE value=\"" + underline + "\" />\n" );
101 result.append( "</FORMAT>\n" );
102
103 return result;
104}
105
106// helper function to convert AmiPro list of formats to KWord FORMATS
107static TQString AmiProFormatListAsXML( AmiProFormatList& formatList )
108{
109 TQString result;
110
111 AmiProFormatList::iterator it;
112 for( it=formatList.begin(); it!=formatList.end(); ++it )
113 {
114 AmiProFormat& format = *it;
115 result.append( AmiProFormatAsXML(format) );
116 }
117
118 if( !result.isEmpty() )
119 {
120 result.prepend( "<FORMATS>\n" );
121 result.append( "</FORMATS>\n" );
122 }
123
124 return result;
125}
126
127// helper function to convert AmiPro paragraph layout to KWord's LAYOUT
128static TQString AmiProLayoutAsXML( const AmiProLayout& layout )
129{
130 TQString result;
131
132 TQString referredStyle = layout.name;
133 if( referredStyle.isEmpty() ) referredStyle = "Standard";
134
135 TQString fontname = layout.fontFamily;
136 if( fontname.isEmpty() ) fontname = KoGlobal::defaultFont().family();
137 TQString fontsize = TQString::number( layout.fontSize );
138 TQString fontcolor = "red=\"" + TQString::number( layout.fontColor.red() ) +
139 "\" green=\"" + TQString::number( layout.fontColor.green() ) +
140 "\" blue=\"" + TQString::number( layout.fontColor.blue() ) + "\"";
141 TQString boldness = layout.bold ? "75" : "50";
142 TQString italic = layout.italic ? "1" : "0";
143 TQString strikeout = layout.strikethrough ? "1" : "0";
144 TQString vertalign = layout.superscript ? "2" : layout.subscript ? "1" : "0";
145 TQString underline = layout.double_underline ? "double" :
146 layout.underline|layout.word_underline ? "1" : "0";
147
148 TQString align;
149 align = layout.align==TQt::AlignLeft ? "left" :
150 layout.align==TQt::AlignRight ? "right" :
151 layout.align==TQt::AlignCenter ? "center" :
152 layout.align==TQt::AlignJustify ? "justify" :
153 "left";
154
155 TQString offsets;
156 offsets = "before=\"" + TQString::number(layout.spaceBefore) +
157 "\" after=\"" + TQString::number(layout.spaceAfter) + "\"";
158
159 TQString linespacing;
160 linespacing = layout.linespace==AmiPro::LS_Single ? TQString::fromLatin1( "0" ) :
161 layout.linespace==AmiPro::LS_OneAndHalf ? TQString::fromLatin1( "oneandhalf" ) :
162 layout.linespace==AmiPro::LS_Double ? TQString::fromLatin1( "double" ) :
163 TQString::number( layout.linespace );
164
165 result.append( "<LAYOUT>\n" );
166 result.append( " <NAME value=\"" + XMLEscape( referredStyle ) + "\" />\n" );
167 result.append( " <FLOW align=\"" + align + "\" />\n" );
168 result.append( " <LINESPACING value=\"" + linespacing + "\" />\n" );
169 result.append( " <OFFSETS " + offsets + " />\n" );
170 result.append( " <LEFTBORDER width=\"0\" style=\"0\" />\n" );
171 result.append( " <RIGHTBORDER width=\"0\" style=\"0\" />\n" );
172 result.append( " <TOPBORDER width=\"0\" style=\"0\" />\n" );
173 result.append( " <BOTTOMBORDER width=\"0\" style=\"0\" />\n" );
174 result.append( " <INDENTS />\n" );
175 result.append( " <OFFSETS />\n" );
176 result.append( " <PAGEBREAKING />\n" );
177 result.append( " <COUNTER />\n" );
178 result.append( " <FORMAT id=\"1\">\n" );
179 result.append( " <FONT name=\"" + fontname + "\" />\n" );
180 result.append( " <SIZE value=\"" + fontsize + "\" />\n" );
181 result.append( " <COLOR " + fontcolor + " />\n" );
182 result.append( " <WEIGHT value=\"" + boldness + "\" />\n" );
183 result.append( " <ITALIC value=\"" + italic + "\" />\n" );
184 result.append( " <STRIKEOUT value=\"" + strikeout + "\" />\n" );
185 result.append( " <VERTALIGN value=\"" + vertalign + "\" />\n" );
186 result.append( " <UNDERLINE value=\"" + underline + "\" />\n" );
187 result.append( " </FORMAT>\n" );
188 result.append( "</LAYOUT>\n" );
189
190 return result;
191}
192
193// helper function to convert AmiPro style to KWord STYLE
194static TQString AmiProStyleAsXML( const AmiProStyle& style )
195{
196 TQString result;
197
198 TQString fontname = style.fontFamily;
199 if( fontname.isEmpty() ) fontname = KoGlobal::defaultFont().family();
200 TQString fontsize = TQString::number( style.fontSize );
201 TQString boldness = style.bold ? "75" : "50";
202 TQString italic = style.italic ? "1" : "0";
203 TQString strikeout = style.strikethrough ? "1" : "0";
204 TQString vertalign = style.superscript ? "2" : style.subscript ? "1" : "0";
205 TQString underline = style.double_underline ? "double" :
206 style.underline|style.word_underline ? "1" : "0";
207
208 TQString align;
209 align = style.align==TQt::AlignLeft ? "left" :
210 style.align==TQt::AlignRight ? "right" :
211 style.align==TQt::AlignCenter ? "center" :
212 style.align==TQt::AlignJustify ? "justify" :
213 "left";
214
215 TQString linespacing;
216 linespacing = style.linespace==AmiPro::LS_Single ? TQString::fromLatin1( "0" ) :
217 style.linespace==AmiPro::LS_OneAndHalf ? TQString::fromLatin1( "oneandhalf" ) :
218 style.linespace==AmiPro::LS_Double ? TQString::fromLatin1( "double" ) :
219 TQString::number( style.linespace );
220
221 TQString offsets;
222 offsets = "before=\"" + TQString::number(style.spaceBefore) +
223 "\" after=\"" + TQString::number(style.spaceAfter) + "\"";
224
225 result.append( "<STYLE>\n" );
226 result.append( " <NAME value=\"" + XMLEscape( style.name ) + "\" />\n" );
227 result.append( " <FOLLOWING name=\"Body Text\" />\n" );
228 result.append( " <FLOW align=\"" + align + "\" />\n" );
229 result.append( " <LINESPACING value=\"" + linespacing + "\" />\n" );
230 result.append( " <OFFSETS " + offsets + " />\n" );
231 result.append( " <LEFTBORDER width=\"0\" style=\"0\" />\n" );
232 result.append( " <RIGHTBORDER width=\"0\" style=\"0\" />\n" );
233 result.append( " <TOPBORDER width=\"0\" style=\"0\" />\n" );
234 result.append( " <BOTTOMBORDER width=\"0\" style=\"0\" />\n" );
235 result.append( " <FORMAT id=\"1\">\n" );
236 result.append( " <FONT name=\"" + fontname + "\" />\n" );
237 result.append( " <SIZE value=\"" + fontsize + "\" />\n" );
238 result.append( " <WEIGHT value=\"" + boldness + "\" />\n" );
239 result.append( " <ITALIC value=\"" + italic + "\" />\n" );
240 result.append( " <STRIKEOUT value=\"" + strikeout + "\" />\n" );
241 result.append( " <VERTALIGN value=\"" + vertalign + "\" />\n" );
242 result.append( " <UNDERLINE value=\"" + underline + "\" />\n" );
243 result.append( " </FORMAT>\n" );
244 result.append( "</STYLE>\n" );
245
246 return result;
247}
248
249// helper function to convert AmiPro styles to KWord STYLES
250static TQString AmiProStyleListAsXML( AmiProStyleList& styleList )
251{
252 TQString result;
253
254 AmiProStyleList::iterator it;
255 for( it=styleList.begin(); it!=styleList.end(); ++it )
256 {
257 AmiProStyle& style = *it;
258 result.append( AmiProStyleAsXML( style ) );
259 }
260
261 if( !result.isEmpty() )
262 {
263 result.prepend ( "<STYLES>\n" );
264 result.append( "</STYLES>\n" );
265 }
266
267 return result;
268}
269
270AmiProConverter::AmiProConverter()
271{
272 root = "";
273}
274
275bool AmiProConverter::doOpenDocument()
276{
277 TQString prolog = "<!DOCTYPE DOC>\n";
278
279 prolog.append( "<DOC mime=\"application/x-kword\" syntaxVersion=\"2\" editor=\"KWord\">\n");
280 prolog.append( "<PAPER width=\"595\" height=\"841\" format=\"1\" fType=\"0\" orientation=\"0\" hType=\"0\" columns=\"1\">\n" );
281 prolog.append( " <PAPERBORDERS left=\"36\" right=\"36\" top=\"36\" bottom=\"36\" />\n" );
282 prolog.append( "</PAPER>\n" );
283 prolog.append( "<ATTRIBUTES standardpage=\"1\" hasFooter=\"0\" hasHeader=\"0\" processing=\"0\" />\n" );
284 prolog.append( "<FRAMESETS>\n" );
285 prolog.append( "<FRAMESET removable=\"0\" frameType=\"1\" frameInfo=\"0\" autoCreateNewFrame=\"1\">\n" );
286 prolog.append( "<FRAME right=\"567\" left=\"28\" top=\"42\" bottom=\"799\" />\n" );
287 root = prolog;
288
289 return true;
290}
291
292bool AmiProConverter::doCloseDocument()
293{
294 TQString epilog = "</FRAMESET>\n";
295 epilog.append( "</FRAMESETS>\n" );
296 epilog.append( AmiProStyleListAsXML( styleList ) );
297 epilog.append( "</DOC>\n" );
298
299 root.append( epilog );
300
301 return true;
302}
303
304bool AmiProConverter::doDefineStyle( const AmiProStyle& style )
305{
306 styleList.append( style );
307 return true;
308}
309
310bool AmiProConverter::doParagraph( const TQString& text, AmiProFormatList formatList,
311 AmiProLayout& layout )
312{
313 root.append( "<PARAGRAPH>\n" );
314 root.append( "<TEXT>" + XMLEscape( text ) + "</TEXT>\n" );
315 root.append( AmiProFormatListAsXML( formatList ) );
316 root.append( AmiProLayoutAsXML( layout ) );
317 root.append( "</PARAGRAPH>\n" );
318
319 return true;
320}
321
322KoFilter::ConversionStatus AmiProImport::convert( const TQCString& from, const TQCString& to )
323{
324 // check for proper conversion
325 if( to!= "application/x-kword" || from != "application/x-amipro" )
326 return KoFilter::NotImplemented;
327
328 // parse/convert input file
329 AmiProParser *parser = new AmiProParser;
330 AmiProConverter *converter = new AmiProConverter;
331 parser->setListener( converter );
332
333 parser->process( m_chain->inputFile() );
334
335 if( converter->root.isEmpty() )
336 return KoFilter::StupidError;
337
338 TQString root = converter->root;
339 TQString documentInfo = converter->documentInfo;
340
341 delete converter;
342 delete parser;
343
344 // prepare storage
345 KoStoreDevice* out=m_chain->storageFile( "root", KoStore::Write );
346
347 // store output document
348 if( out )
349 {
350 TQCString cstring = root.utf8();
351 cstring.prepend( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
352 out->writeBlock( (const char*) cstring, cstring.length() );
353 }
354
355 // store document info
356 out = m_chain->storageFile( "documentinfo.xml", KoStore::Write );
357 if ( out )
358 {
359 TQCString cstring = documentInfo.utf8();
360 cstring.prepend( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
361
362 out->writeBlock( (const char*) cstring, cstring.length() );
363 }
364
365 return KoFilter::OK;
366}
367
368#include "amiproimport.moc"