1 /* AbiWord xml2ps export plugin
2 * Copyright (C) 2004 David Bolack
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program 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
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20 #include <string.h>
21
22 #include "ut_string.h"
23 #include "ut_locale.h"
24 #include "pt_Types.h"
25 #include "fd_Field.h"
26 #include "pd_Document.h"
27 #include "pp_AttrProp.h"
28 #include "px_ChangeRecord.h"
29 #include "px_CR_Object.h"
30 #include "px_CR_Span.h"
31 #include "px_CR_Strux.h"
32 #include "ut_string_class.h"
33
34 #include "ie_exp_Passepartout.h"
35
36 /*****************************************************************/
37 /*****************************************************************/
38
39 class IE_Exp_Passepartout : public IE_Exp
40 {
41 public:
42 IE_Exp_Passepartout(PD_Document * pDocument);
~IE_Exp_Passepartout()43 virtual ~IE_Exp_Passepartout() {}
44
45 protected:
46 virtual PL_Listener * _constructListener(void);
47 virtual UT_Error _writeDocument(void);
48
49 private:
50 PL_Listener * m_pListener;
51 };
52
53 //////////////////////////////////////////////////////////////////
54 // a private listener class to help us translate the document
55 // into a passepartout stream.
56 //////////////////////////////////////////////////////////////////
57
58 class Passepartout_Listener : public PL_Listener
59 {
60 public:
61 Passepartout_Listener(PD_Document * pDocument,
62 IE_Exp_Passepartout * pie);
63 virtual ~Passepartout_Listener();
64
65 virtual bool populate(fl_ContainerLayout* sfh,
66 const PX_ChangeRecord * pcr);
67
68 virtual bool populateStrux(pf_Frag_Strux* sdh,
69 const PX_ChangeRecord * pcr,
70 fl_ContainerLayout* * psfh);
71
72 virtual bool change(fl_ContainerLayout* sfh,
73 const PX_ChangeRecord * pcr);
74
75 virtual bool insertStrux(fl_ContainerLayout* sfh,
76 const PX_ChangeRecord * pcr,
77 pf_Frag_Strux* sdh,
78 PL_ListenerId lid,
79 void (* pfnBindHandles)(pf_Frag_Strux* sdhNew,
80 PL_ListenerId lid,
81 fl_ContainerLayout* sfhNew));
82
83 virtual bool signal(UT_uint32 iSignal);
84
85 protected:
86 virtual void _outputData(const UT_UCSChar * p, UT_uint32 length);
87 void _closeBlock(void);
88 void _openBlock(PT_AttrPropIndex api);
89 void _closeFont(void);
90 void _openFont(PT_AttrPropIndex api);
91
92 private:
93
94 PD_Document * m_pDocument;
95 IE_Exp_Passepartout * m_pie;
96 bool m_bInBlock;
97 bool m_inFont;
98 bool m_inParagraph;
99 bool m_bBreakExtra;
100 bool m_bWasSpace;
101 };
102
103 /*****************************************************************/
104 /*****************************************************************/
105
IE_Exp_Passepartout_Sniffer(const char *)106 IE_Exp_Passepartout_Sniffer::IE_Exp_Passepartout_Sniffer (const char * /*name*/)
107 : IE_ExpSniffer(IE_IMPEXPNAME_TEXT, true)
108 {
109 }
110
supportsMIME(const char * szMIME)111 UT_Confidence_t IE_Exp_Passepartout_Sniffer::supportsMIME (const char * szMIME)
112 {
113 if (strncmp (szMIME, "text/xml2ps", 11) == 0)
114 return UT_CONFIDENCE_PERFECT;
115 return UT_CONFIDENCE_ZILCH;
116 }
117
118 /*!
119 Check filename extension for filetypes we support
120 \param szSuffix Filename extension
121 */
recognizeSuffix(const char * szSuffix)122 bool IE_Exp_Passepartout_Sniffer::recognizeSuffix(const char * szSuffix)
123 {
124 return (!g_ascii_strcasecmp(szSuffix,".xml2ps"));
125 }
126
constructExporter(PD_Document * pDocument,IE_Exp ** ppie)127 UT_Error IE_Exp_Passepartout_Sniffer::constructExporter(PD_Document * pDocument,
128 IE_Exp ** ppie)
129 {
130 *ppie = new IE_Exp_Passepartout(pDocument);
131 return UT_OK;
132 }
133
getDlgLabels(const char ** pszDesc,const char ** pszSuffixList,IEFileType * ft)134 bool IE_Exp_Passepartout_Sniffer::getDlgLabels(const char ** pszDesc,
135 const char ** pszSuffixList,
136 IEFileType * ft)
137 {
138 *pszDesc = "PassepartoutToo (.xml2ps)";
139 *pszSuffixList = "*.xml2ps";
140 *ft = getFileType();
141 return true;
142 }
143
144 /*****************************************************************/
145 /*****************************************************************/
146
IE_Exp_Passepartout(PD_Document * pDocument)147 IE_Exp_Passepartout::IE_Exp_Passepartout(PD_Document * pDocument)
148 : IE_Exp(pDocument),
149 m_pListener(NULL)
150 {
151 m_error = UT_OK;
152 }
153
_constructListener(void)154 PL_Listener * IE_Exp_Passepartout::_constructListener(void)
155 {
156 return new Passepartout_Listener(getDoc(),this);
157 }
158
_writeDocument(void)159 UT_Error IE_Exp_Passepartout::_writeDocument(void)
160 {
161 m_pListener = _constructListener();
162 if (!m_pListener)
163 return UT_IE_NOMEMORY;
164
165 if (getDocRange())
166 getDoc()->tellListenerSubset(static_cast<PL_Listener *>(m_pListener),getDocRange());
167 else
168 getDoc()->tellListener(static_cast<PL_Listener *>(m_pListener));
169 DELETEP(m_pListener);
170
171 return ((m_error) ? UT_IE_COULDNOTWRITE : UT_OK);
172 }
173
174 /*****************************************************************/
175 /*****************************************************************/
176
177 /*!
178 Output text buffer to stream
179 \param data Buffer to output
180 \param length Size of buffer
181 */
_outputData(const UT_UCSChar * data,UT_uint32 length)182 void Passepartout_Listener::_outputData(const UT_UCSChar * data, UT_uint32 length)
183 {
184 if (!m_bInBlock)
185 return;
186
187 UT_UTF8String sBuf;
188 const UT_UCSChar * pData;
189
190 sBuf.reserve(length);
191 for (pData=data; (pData<data+length); /**/)
192 {
193 switch (*pData)
194 {
195 case '<':
196 sBuf += "<";
197 pData++;
198 break;
199
200 case '>':
201 sBuf += ">";
202 pData++;
203 break;
204
205 case '&':
206 sBuf += "&";
207 pData++;
208 break;
209
210 case UCS_LF: // LF -- representing a Forced-Line-Break
211 sBuf += "<br/>";
212 pData++;
213 break;
214
215 case ' ':
216 case '\t':
217 if(m_bWasSpace)
218 {
219 sBuf += " ";
220 pData++;
221 }
222 else
223 {
224 // just tack on a single space to the textrun
225 m_bWasSpace = true;
226 sBuf += " ";
227 pData++;
228 }
229 break;
230
231 default:
232 sBuf.appendUCS4(pData, 1);
233 pData++;
234 }
235 }
236
237 m_pie->write(sBuf.utf8_str(),sBuf.byteLength());
238 }
239
_closeBlock(void)240 void Passepartout_Listener::_closeBlock(void)
241 {
242 if (m_inFont)
243 _closeFont();
244
245 if (!m_bInBlock)
246 return;
247
248 m_pie->write("</para>\n");
249
250 m_bInBlock = false;
251 }
252
_openBlock(PT_AttrPropIndex api)253 void Passepartout_Listener::_openBlock(PT_AttrPropIndex api)
254 {
255 const PP_AttrProp * pAP = NULL;
256
257 const char* pszLeftMargin = NULL;
258 const char* pszRightMargin = NULL;
259 const char* pszTopMargin = NULL;
260 const char* pszBottomMargin = NULL;
261 const char* pszFontFamily = NULL;
262 const char* pszFontSize = NULL;
263 const char* pszParaAlign = NULL;
264 const char* pszParaLineHeight = NULL;
265
266 if(m_bInBlock)
267 _closeBlock();
268
269 m_bInBlock = true;
270
271 UT_UTF8String TempStr;
272
273 double pszLeftMarginDouble, pszRightMarginDouble, pszTopMarginDouble,pszBottomMarginDouble;
274
275 bool bHaveProp = m_pDocument->getAttrProp (api, &pAP);
276
277 // Get a bunch of block level and other default properties.
278 // Note, these don't seem to exist in the piecetable until someone alters them. need a
279 // better way to get the defaults.
280
281 pAP->getProperty("page-margin-left", (const gchar *&)pszLeftMargin);
282 pAP->getProperty("page-margin-right", (const gchar *&)pszRightMargin);
283 pAP->getProperty("page-margin-top", (const gchar *&)pszTopMargin);
284 pAP->getProperty("page-margin-bottom", (const gchar *&)pszBottomMargin);
285 pAP->getProperty("font-family", (const gchar *&) pszFontFamily);
286 pAP->getProperty("font-size", (const gchar *&) pszFontSize );
287 pAP->getProperty("text-align", (const gchar *&) pszParaAlign );
288 pAP->getProperty("line-height", (const gchar *&) pszParaLineHeight );
289
290
291 // Insert defaults if we don't have any values. Note that these come from hardcoded values from pp_Property.cpp and
292 // Probably should be found via a function/method at a later date.
293
294 pszLeftMarginDouble = UT_convertToPoints(pszLeftMargin);
295 pszRightMarginDouble = UT_convertToPoints(pszRightMargin);
296 pszTopMarginDouble = UT_convertToPoints(pszTopMargin);
297 pszBottomMarginDouble = UT_convertToPoints(pszBottomMargin);
298
299 if ( !pszLeftMargin )
300 pszLeftMarginDouble = 1;
301 if ( !pszRightMargin )
302 pszRightMarginDouble = 1;
303 if ( !pszTopMargin )
304 pszTopMarginDouble = 1;
305 if ( !pszBottomMargin )
306 pszBottomMarginDouble = 1;
307
308 UT_LocaleTransactor locale(LC_NUMERIC, "C");
309
310 if (bHaveProp && pAP)
311 {
312 m_pie->write("<para");
313
314 if ( pszFontFamily != NULL )
315 {
316 TempStr = UT_UTF8String_sprintf(" font-family=\"%s\"", pszFontFamily );
317 m_pie->write(TempStr.utf8_str());
318 }
319 else
320 {
321 TempStr = UT_UTF8String_sprintf(" font-family=\"%s\"", "Times New Roman" );
322 m_pie->write(TempStr.utf8_str());
323 }
324
325 if ( pszFontSize != NULL )
326 {
327 TempStr = UT_UTF8String_sprintf(" font-size=\"%s\"", pszFontSize );
328 m_pie->write(TempStr.utf8_str());
329 }
330 else
331 {
332 TempStr = UT_UTF8String_sprintf(" font-size=\"%s\"", "12pt" );
333 m_pie->write(TempStr.utf8_str());
334 }
335
336 if ( pszParaAlign != NULL )
337 {
338 TempStr = UT_UTF8String_sprintf(" align=\"%s\"", pszParaAlign );
339 m_pie->write(TempStr.utf8_str());
340 }
341 else
342 {
343 TempStr = UT_UTF8String_sprintf(" align=\"%s\"", "right" );
344 m_pie->write(TempStr.utf8_str());
345 }
346
347 if ( pszParaLineHeight != NULL )
348 {
349 TempStr = UT_UTF8String_sprintf(" line-height=\"%s\"", pszParaLineHeight );
350 m_pie->write(TempStr.utf8_str());
351 }
352 else
353 {
354 TempStr = UT_UTF8String_sprintf(" line-height=\"%s\"", "1.0" );
355 m_pie->write(TempStr.utf8_str());
356 }
357
358 if( pszTopMargin != NULL )
359 {
360 TempStr = UT_UTF8String_sprintf(" margin-top=\"%gpt\"", pszTopMarginDouble );
361 m_pie->write(TempStr.utf8_str());
362 }
363 if( pszBottomMargin != NULL )
364 {
365 TempStr = UT_UTF8String_sprintf(" margin-bottom=\"%gpt\"", pszBottomMarginDouble );
366 m_pie->write(TempStr.utf8_str());
367 }
368 if( pszLeftMargin != NULL )
369 {
370 TempStr = UT_UTF8String_sprintf(" margin-right=\"%gpt\"", pszRightMarginDouble );
371 m_pie->write(TempStr.utf8_str());
372 }
373 if( pszRightMargin != NULL )
374 {
375 TempStr = UT_UTF8String_sprintf(" margin-left=\"%gpt\"", pszLeftMarginDouble );
376 m_pie->write(TempStr.utf8_str());
377 }
378 m_pie->write(">");
379 }
380 else
381 {
382 m_pie->write("<para>\n");
383 }
384
385 }
386
_closeFont(void)387 void Passepartout_Listener::_closeFont(void)
388 {
389 if (!m_inFont)
390 return;
391
392 m_pie->write("</font>");
393
394 m_inFont = false;
395 }
396
_openFont(PT_AttrPropIndex api)397 void Passepartout_Listener::_openFont(PT_AttrPropIndex api)
398 {
399 const PP_AttrProp * pAP = NULL;
400
401 const char* pszFontFamily = NULL;
402 const char* pszFontSize = NULL;
403
404 if(m_inFont)
405 _closeFont();
406
407 m_inFont = true;
408
409 UT_UTF8String TempStr;
410
411 bool bHaveProp = m_pDocument->getAttrProp (api, &pAP);
412
413 // Get a bunch of block level and other default properties.
414
415 pAP->getProperty("font-family", (const gchar *&) pszFontFamily);
416 pAP->getProperty("font-size", (const gchar *&) pszFontSize );
417
418 if (bHaveProp && pAP)
419 {
420 m_pie->write("<font");
421
422 if ( pszFontFamily != NULL )
423 {
424 TempStr = UT_UTF8String_sprintf(" font-family=\"%s\"", pszFontFamily );
425 m_pie->write(TempStr.utf8_str());
426 }
427 else
428 {
429 TempStr = UT_UTF8String_sprintf(" font-family=\"%s\"", "Times New Roman" );
430 m_pie->write(TempStr.utf8_str());
431 }
432
433 if ( pszFontSize != NULL )
434 {
435 TempStr = UT_UTF8String_sprintf(" font-size=\"%s\"", pszFontSize );
436 m_pie->write(TempStr.utf8_str());
437 }
438 else
439 {
440 TempStr = UT_UTF8String_sprintf(" font-size=\"%s\"", "12pt" );
441 m_pie->write(TempStr.utf8_str());
442 }
443
444 m_pie->write(">");
445 }
446 else
447 {
448 m_pie->write("<font>\n");
449 }
450
451 }
452
453 /***************************************************************/
454 /***************************************************************/
455
Passepartout_Listener(PD_Document * pDocument,IE_Exp_Passepartout * pie)456 Passepartout_Listener::Passepartout_Listener(PD_Document * pDocument,
457 IE_Exp_Passepartout * pie)
458 : m_pDocument(pDocument),
459 m_pie(pie),
460 m_bInBlock(false),
461 m_bBreakExtra(false),
462 m_bWasSpace(false)
463 {
464 PT_AttrPropIndex api = m_pDocument->getAttrPropIndex();
465 const PP_AttrProp * pAP = NULL;
466 const char* pszLeftMargin = NULL;
467 const char* pszRightMargin = NULL;
468 const char* pszTopMargin = NULL;
469 const char* pszBottomMargin = NULL;
470 const char* pszFontFamily = NULL;
471 const char* pszFontSize = NULL;
472
473 UT_UTF8String TempStr;
474
475 double pszLeftMarginDouble, pszRightMarginDouble, pszTopMarginDouble,pszBottomMarginDouble;
476
477 bool bHaveProp = m_pDocument->getAttrProp (api, &pAP);
478
479
480 m_inFont = false;
481 m_inParagraph = false;
482
483
484 // Get a bunch of block level and other default properties.
485
486 pAP->getProperty("margin-left", (const gchar *&)pszLeftMargin);
487 pAP->getProperty("margin-right", (const gchar *&)pszRightMargin);
488 pAP->getProperty("margin-top", (const gchar *&)pszTopMargin);
489 pAP->getProperty("margin-bottom", (const gchar *&)pszBottomMargin);
490 pAP->getProperty("font-family", (const gchar *&) pszFontFamily);
491 pAP->getProperty("font-size", (const gchar *&) pszFontSize );
492
493
494 // Manipulate them a little. Not sure this is needed.
495
496 pszLeftMarginDouble = UT_convertToPoints(pszLeftMargin);
497 pszRightMarginDouble = UT_convertToPoints(pszRightMargin);
498 pszTopMarginDouble = UT_convertToPoints(pszTopMargin);
499 pszBottomMarginDouble = UT_convertToPoints(pszBottomMargin);
500
501 m_pie->write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
502
503 UT_LocaleTransactor locale(LC_NUMERIC, "C");
504
505 if (bHaveProp && pAP)
506 {
507 m_pie->write("<block-container");
508
509 if ( pszFontFamily != NULL )
510 {
511 TempStr = UT_UTF8String_sprintf(" font-family=\"%s\"", pszFontFamily );
512 m_pie->write(TempStr.utf8_str());
513 }
514 if ( pszFontSize != NULL )
515 {
516 TempStr = UT_UTF8String_sprintf(" font-size=\"%s\"", pszFontSize );
517 m_pie->write(TempStr.utf8_str());
518 }
519 if( pszTopMargin != NULL )
520 {
521 TempStr = UT_UTF8String_sprintf(" margin-top=\"%gpt\"", pszTopMarginDouble );
522 m_pie->write(TempStr.utf8_str());
523 }
524 if( pszBottomMargin != NULL )
525 {
526 TempStr = UT_UTF8String_sprintf(" margin-bottom=\"%gpt\"", pszBottomMarginDouble );
527 m_pie->write(TempStr.utf8_str());
528 }
529 if( pszRightMargin != NULL )
530 {
531 TempStr = UT_UTF8String_sprintf(" margin-right=\"%gpt\"", pszRightMarginDouble );
532 m_pie->write(TempStr.utf8_str());
533 }
534 if( pszLeftMargin != NULL )
535 {
536 TempStr = UT_UTF8String_sprintf(" margin-left=\"%gpt\"", pszLeftMarginDouble );
537 m_pie->write(TempStr.utf8_str());
538 }
539
540 m_pie->write(">");
541 }
542 else
543 {
544 m_pie->write("<block-container>\n");
545 }
546 }
547
~Passepartout_Listener()548 Passepartout_Listener::~Passepartout_Listener()
549 {
550 _closeBlock();
551 m_pie->write("</block-container>\n");
552 }
553
554 /***************************************************************/
555 /***************************************************************/
556
populate(fl_ContainerLayout *,const PX_ChangeRecord * pcr)557 bool Passepartout_Listener::populate(fl_ContainerLayout* /*sfh*/,
558 const PX_ChangeRecord * pcr)
559 {
560 switch (pcr->getType())
561 {
562 case PX_ChangeRecord::PXT_InsertSpan:
563 {
564 const PX_ChangeRecord_Span * pcrs = static_cast<const PX_ChangeRecord_Span *>(pcr);
565
566 PT_AttrPropIndex api = pcr->getIndexAP();
567 _closeFont();
568 _openFont(api);
569
570 PT_BufIndex bi = pcrs->getBufIndex();
571 const UT_UCS4Char * pData = m_pDocument->getPointer(bi);
572 _outputData(pData,pcrs->getLength());
573
574 return true;
575 }
576
577 case PX_ChangeRecord::PXT_InsertFmtMark:
578 return true;
579
580 default:
581 UT_ASSERT_HARMLESS(UT_TODO);
582 return true;
583 }
584 }
585
populateStrux(pf_Frag_Strux *,const PX_ChangeRecord * pcr,fl_ContainerLayout ** psfh)586 bool Passepartout_Listener::populateStrux(pf_Frag_Strux* /*sdh*/,
587 const PX_ChangeRecord * pcr,
588 fl_ContainerLayout* * psfh)
589 {
590 UT_ASSERT(pcr->getType() == PX_ChangeRecord::PXT_InsertStrux);
591 const PX_ChangeRecord_Strux * pcrx = static_cast<const PX_ChangeRecord_Strux *>(pcr);
592 *psfh = 0; // we don't need it.
593
594 switch (pcrx->getStruxType())
595 {
596 case PTX_SectionEndnote:
597 case PTX_SectionHdrFtr:
598 case PTX_Section:
599 {
600 _closeBlock();
601 PT_AttrPropIndex api = pcr->getIndexAP();
602 const PP_AttrProp * pAP = NULL;
603 bool bHaveProp = m_pDocument->getAttrProp (api, &pAP);
604
605 if (bHaveProp && pAP)
606 {
607 }
608 return true;
609 }
610
611 case PTX_Block:
612 {
613 PT_AttrPropIndex api = pcr->getIndexAP();
614 _closeBlock();
615 _openBlock(api);
616 m_bInBlock = true;
617 return true;
618 }
619
620 // Be nice about these until we figure out what to do with 'em
621 case PTX_SectionTable:
622 case PTX_SectionCell:
623 case PTX_EndTable:
624 case PTX_EndCell:
625 case PTX_EndFrame:
626 case PTX_EndMarginnote:
627 case PTX_EndFootnote:
628 case PTX_SectionFrame:
629 case PTX_SectionMarginnote:
630 case PTX_SectionFootnote:
631 case PTX_EndEndnote:
632 return true ;
633
634 default:
635 UT_ASSERT_HARMLESS(UT_TODO);
636 return true;
637 }
638 }
639
change(fl_ContainerLayout *,const PX_ChangeRecord *)640 bool Passepartout_Listener::change(fl_ContainerLayout* /*sfh*/,
641 const PX_ChangeRecord * /*pcr*/)
642 {
643 UT_ASSERT_NOT_REACHED(); // this function is not used.
644 return false;
645 }
646
insertStrux(fl_ContainerLayout *,const PX_ChangeRecord *,pf_Frag_Strux *,PL_ListenerId,void (*)(pf_Frag_Strux *,PL_ListenerId,fl_ContainerLayout *))647 bool Passepartout_Listener::insertStrux(fl_ContainerLayout* /*sfh*/,
648 const PX_ChangeRecord * /*pcr*/,
649 pf_Frag_Strux* /*sdh*/,
650 PL_ListenerId /* lid */,
651 void (* /*pfnBindHandles*/)(pf_Frag_Strux* /* sdhNew */,
652 PL_ListenerId /* lid */,
653 fl_ContainerLayout* /* sfhNew */))
654 {
655 UT_ASSERT_NOT_REACHED(); // this function is not used.
656 return false;
657 }
658
signal(UT_uint32)659 bool Passepartout_Listener::signal(UT_uint32 /* iSignal */)
660 {
661 UT_ASSERT_NOT_REACHED();
662 return false;
663 }
664
665