1 /* AbiWord
2 * Copyright (C) 2000 AbiSource, Inc.
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 <stdio.h>
21 #include <string.h>
22 #include <string>
23 #include <map>
24
25 #include "ap_Convert.h"
26 #include "xap_App.h"
27 #include "ie_exp.h"
28 #include "ie_imp.h"
29 #include "ut_types.h"
30 #include "ut_string.h"
31 #include "ut_string_class.h"
32 #include "ut_misc.h"
33
34 #include "ut_assert.h"
35 #include "ut_debugmsg.h"
36
37 #include "gr_DrawArgs.h"
38 #include "gr_Graphics.h"
39 #include "fv_View.h"
40 #include "fl_BlockLayout.h"
41 #include "ap_EditMethods.h"
42
43 // needed for convertToPNG
44 #include "ie_impGraphic.h"
45 #include "ut_bytebuf.h"
46 #include "ie_mailmerge.h"
47
48 //////////////////////////////////////////////////////////////////
49
AP_Convert(int inVerbose)50 AP_Convert::AP_Convert(int inVerbose)
51 : m_iVerbose(inVerbose)
52 {
53 }
54
~AP_Convert(void)55 AP_Convert::~AP_Convert(void)
56 {
57 }
58
setMergeSource(const char * source)59 void AP_Convert::setMergeSource (const char * source)
60 {
61 m_mergeSource = source;
62 }
63
64 /////////////////////////////////////////////////////////////////
65
66 class ABI_EXPORT Save_MailMerge_Listener : public IE_MailMerge::IE_MailMerge_Listener
67 {
68 public:
69
Save_MailMerge_Listener(PD_Document * pDoc,const UT_UTF8String & szOut,IEFileType out_ieft,const UT_UTF8String & szExpProps)70 explicit Save_MailMerge_Listener (PD_Document * pDoc,
71 const UT_UTF8String & szOut,
72 IEFileType out_ieft,
73 const UT_UTF8String & szExpProps)
74 : IE_MailMerge::IE_MailMerge_Listener (), m_doc (pDoc),
75 m_szFile(szOut), m_count(0), m_ieft(out_ieft), m_expProps(szExpProps)
76 {
77 }
78
~Save_MailMerge_Listener()79 virtual ~Save_MailMerge_Listener ()
80 {
81 }
82
getMergeDocument() const83 virtual PD_Document* getMergeDocument () const
84 {
85 return m_doc;
86 }
87
fireUpdate()88 virtual bool fireUpdate ()
89 {
90 if (!m_doc)
91 return false;
92
93 UT_UTF8String out_file (UT_UTF8String_sprintf("%s-%d",
94 m_szFile.utf8_str(),
95 m_count++));
96
97 if (UT_OK == static_cast<AD_Document*>(m_doc)->saveAs (out_file.utf8_str(), m_ieft, m_expProps.utf8_str()))
98 return true;
99 return false;
100 }
101
102 private:
103 PD_Document *m_doc;
104 UT_UTF8String m_szFile;
105 UT_uint32 m_count;
106 IEFileType m_ieft;
107 UT_UTF8String m_expProps;
108 };
109
110 class ABI_EXPORT Print_MailMerge_Listener : public IE_MailMerge::IE_MailMerge_Listener
111 {
112 public:
113
Print_MailMerge_Listener(PD_Document * pd,GR_Graphics * pGraphics,const UT_UTF8String & szFile)114 explicit Print_MailMerge_Listener (PD_Document * pd,
115 GR_Graphics * pGraphics,
116 const UT_UTF8String & szFile)
117 : IE_MailMerge::IE_MailMerge_Listener (), m_doc (pd),
118 m_szFile(szFile), m_pGraphics(pGraphics), m_bPrintedFirstPage(false), m_iter(1)
119 {
120 }
121
~Print_MailMerge_Listener()122 virtual ~Print_MailMerge_Listener ()
123 {
124 if (m_bPrintedFirstPage)
125 m_pGraphics->endPrint();
126 }
127
getMergeDocument() const128 virtual PD_Document* getMergeDocument () const
129 {
130 return m_doc;
131 }
132
fireUpdate()133 virtual bool fireUpdate ()
134 {
135 FL_DocLayout *pDocLayout = new FL_DocLayout(m_doc,m_pGraphics);
136 FV_View printView(XAP_App::getApp(),0,pDocLayout);
137 //pDocLayout->setView (&printView);
138 pDocLayout->fillLayouts();
139 pDocLayout->formatAll();
140 pDocLayout->recalculateTOCFields();
141
142 if (!m_bPrintedFirstPage)
143 if (m_pGraphics->startPrint())
144 m_bPrintedFirstPage = true;
145
146
147 if (m_bPrintedFirstPage) {
148
149 dg_DrawArgs da;
150 memset(&da, 0, sizeof(da));
151 da.pG = m_pGraphics;
152
153 for (UT_sint32 k = 1; (k <= pDocLayout->countPages()); k++)
154 {
155 UT_uint32 iHeight = pDocLayout->getHeight() / pDocLayout->countPages();
156 m_pGraphics->m_iRasterPosition = (k-1)*iHeight;
157 m_pGraphics->startPage(m_szFile.utf8_str(), m_iter++, printView.getPageSize().isPortrait(), pDocLayout->getWidth(), iHeight);
158 printView.draw(k-1, &da);
159 }
160 }
161
162 DELETEP(pDocLayout);
163
164 // sure, we'll process more data if it exists
165 return true;
166 }
167
168 private:
169 PD_Document *m_doc;
170 UT_UTF8String m_szFile;
171
172 GR_Graphics * m_pGraphics;
173
174 bool m_bPrintedFirstPage;
175 UT_uint32 m_iter;
176 };
177
handleMerge(const char * szMailMergeFile,IE_MailMerge::IE_MailMerge_Listener & listener)178 static UT_Error handleMerge(const char * szMailMergeFile,
179 IE_MailMerge::IE_MailMerge_Listener & listener){
180 IE_MailMerge * pie = NULL;
181 UT_Error errorCode = IE_MailMerge::constructMerger(szMailMergeFile, IEMT_Unknown, &pie);
182 if (!errorCode)
183 {
184 pie->setListener (&listener);
185 errorCode = pie->mergeFile (szMailMergeFile);
186 DELETEP(pie);
187 }
188
189 return errorCode;
190 }
191
192 /////////////////////////////////////////////////////////////////
193
getImportFileType(const char * szSuffixOrMime)194 static IEFileType getImportFileType(const char * szSuffixOrMime)
195 {
196 IEFileType ieft = IEFT_Unknown;
197
198 if(szSuffixOrMime && *szSuffixOrMime) {
199 IE_Imp::fileTypeForMimetype(szSuffixOrMime);
200 if(ieft == IEFT_Unknown) {
201 UT_String suffix;
202
203 if(*szSuffixOrMime != '.')
204 suffix = ".";
205 suffix += szSuffixOrMime;
206 ieft = IE_Imp::fileTypeForSuffix(suffix.c_str());
207 }
208 }
209
210 return ieft;
211 }
212
getExportFileType(const char * szSuffixOrMime)213 static IEFileType getExportFileType(const char * szSuffixOrMime)
214 {
215 IEFileType ieft = IEFT_Unknown;
216
217 if(szSuffixOrMime && *szSuffixOrMime) {
218 IE_Exp::fileTypeForMimetype(szSuffixOrMime);
219 if(ieft == IEFT_Unknown) {
220 UT_String suffix;
221
222 if(*szSuffixOrMime != '.')
223 suffix = ".";
224 suffix += szSuffixOrMime;
225 ieft = IE_Exp::fileTypeForSuffix(suffix.c_str());
226 }
227 }
228
229 return ieft;
230 }
231
convertTo(const char * szSourceFilename,IEFileType sourceFormat,const char * szTargetFilename,IEFileType targetFormat)232 bool AP_Convert::convertTo(const char * szSourceFilename,
233 IEFileType sourceFormat,
234 const char * szTargetFilename,
235 IEFileType targetFormat)
236 {
237 UT_Error error = UT_OK;
238
239 UT_return_val_if_fail(targetFormat != IEFT_Unknown, false);
240 UT_return_val_if_fail(szSourceFilename != NULL, false);
241 UT_return_val_if_fail(szTargetFilename != NULL, false);
242
243 PD_Document * pNewDoc = new PD_Document();
244 UT_return_val_if_fail(pNewDoc, false);
245
246 char * uri = UT_go_shell_arg_to_uri (szSourceFilename);
247 error = pNewDoc->readFromFile(uri, sourceFormat, m_impProps.utf8_str());
248 g_free (uri);
249
250 if (!UT_IS_IE_SUCCESS(error)) {
251 switch (error) {
252 case UT_INVALIDFILENAME:
253 if (m_iVerbose > 0)
254 fprintf(stderr, "AbiWord: [%s] is not a valid file name.\n", szSourceFilename);
255 break;
256 case UT_IE_NOMEMORY:
257 if (m_iVerbose > 0)
258 fprintf(stderr, "AbiWord: Arrrgh... I don't have enough memory!\n");
259 break;
260 case UT_NOPIECETABLE:
261 // TODO
262 default:
263 if (m_iVerbose > 0)
264 fprintf(stderr, "AbiWord: could not open the file [%s]\n", szSourceFilename);
265 }
266
267 UNREFP(pNewDoc);
268 return (error == UT_OK);
269 }
270
271 if (m_mergeSource.size()) {
272 uri = UT_go_shell_arg_to_uri (szTargetFilename);
273 IE_MailMerge::IE_MailMerge_Listener * listener = new Save_MailMerge_Listener (pNewDoc, uri, targetFormat, m_expProps);
274 g_free(uri);
275
276 uri = UT_go_shell_arg_to_uri (m_mergeSource.utf8_str());
277 handleMerge (uri, *listener);
278 g_free (uri);
279 DELETEP(listener);
280 } else {
281 uri = UT_go_shell_arg_to_uri (szTargetFilename);
282 error = static_cast<AD_Document*>(pNewDoc)->saveAs(uri, targetFormat, m_expProps.utf8_str());
283 g_free(uri);
284
285 switch (error) {
286 case UT_OK:
287 if (m_iVerbose > 1)
288 printf("AbiWord: [%s] -> [%s]\tConversion ok!\n", szSourceFilename, szTargetFilename);
289 break;
290 case UT_SAVE_EXPORTERROR:
291 if (m_iVerbose > 0)
292 fprintf(stderr, "AbiWord: Uch! Are you sure that you've specified a valid exporter?\n");
293 break;
294 case UT_SAVE_WRITEERROR:
295 if (m_iVerbose > 0)
296 fprintf(stderr, "AbiWord: Uch! Could not write the file [%s]\n", szTargetFilename);
297 break;
298 default:
299 if (m_iVerbose > 0)
300 fprintf(stderr, "AbiWord: could not write the file [%s]\n", szTargetFilename);
301 break;
302 }
303 }
304
305 UNREFP(pNewDoc);
306
307 return UT_IS_IE_SUCCESS(error);
308 }
309
convertTo(const char * szFilename,const char * szSourceSuffixOrMime,const char * szTargetFilename,const char * szTargetSuffixOrMime)310 bool AP_Convert::convertTo(const char * szFilename,
311 const char * szSourceSuffixOrMime,
312 const char * szTargetFilename,
313 const char * szTargetSuffixOrMime)
314 {
315 return convertTo(szFilename, getImportFileType(szSourceSuffixOrMime), szTargetFilename, getExportFileType(szTargetSuffixOrMime));
316 }
317
convertTo(const char * szFilename,const char * szSourceSuffixOrMime,const char * szTargetSuffixOrMime)318 bool AP_Convert::convertTo(const char * szFilename,
319 const char * szSourceSuffixOrMime,
320 const char * szTargetSuffixOrMime)
321 {
322 UT_return_val_if_fail(szTargetSuffixOrMime, false);
323 UT_return_val_if_fail(strlen(szTargetSuffixOrMime)>0, false);
324
325 UT_String ext;
326 IEFileType ieft = IEFT_Unknown;
327
328 UT_String file;
329
330 // maybe it is a mime type. try that first
331 ieft = IE_Exp::fileTypeForMimetype(szTargetSuffixOrMime);
332 if(ieft != IEFT_Unknown) {
333 ext = IE_Exp::preferredSuffixForFileType(ieft).utf8_str();
334 }
335 else
336 {
337 std::string suffix = UT_pathSuffix(szTargetSuffixOrMime);
338 if (!suffix.empty())
339 {
340 // suffix is ".txt" or ".html"
341 ieft = IE_Exp::fileTypeForSuffix(suffix.c_str());
342
343 // szTargetSuffixOrMime is something like "file://home/dom/foo.html", so use it as our target filename
344 if (suffix.size() != strlen(szTargetSuffixOrMime))
345 file = szTargetSuffixOrMime;
346 }
347 else
348 {
349 // assume that szSourceSuffixOrMime is "txt" or "html"
350 ext = ".";
351 ext += szTargetSuffixOrMime;
352 ieft = IE_Exp::fileTypeForSuffix(ext.c_str());
353 }
354
355 // unknown suffix and mime type
356 if(ieft == IEFT_Unknown)
357 return false;
358 }
359
360 if (file.empty())
361 {
362 char * fileDup = g_strdup ( szFilename );
363
364 char *tmp = strrchr(fileDup, '.');
365 if (tmp != NULL)
366 *tmp = '\0';
367
368 file = fileDup;
369 file += ext;
370
371 FREEP(fileDup);
372 }
373
374 return convertTo(szFilename, getImportFileType(szSourceSuffixOrMime), file.c_str(), ieft);
375 }
376
setVerbose(int level)377 void AP_Convert::setVerbose(int level)
378 {
379 if ((level >= 0) && (level <= 2))
380 m_iVerbose = level;
381 }
382
print(const char * szFile,GR_Graphics * pGraphics,const char * szFileExtensionOrMime)383 bool AP_Convert::print(const char * szFile, GR_Graphics * pGraphics, const char * szFileExtensionOrMime)
384 {
385 // get the current document
386 PD_Document *pDoc = new PD_Document();
387 UT_Error err;
388 char * uri = UT_go_shell_arg_to_uri (szFile);
389
390 IEFileType ieft = getImportFileType(szFileExtensionOrMime);
391
392 err = pDoc->readFromFile(uri, ieft, m_impProps.utf8_str());
393 g_free(uri);
394
395 if( err != UT_OK)
396 {
397 fprintf(stderr, "AbiWord: Error importing file. [%s] Could not print \n", szFile);
398 UNREFP(pDoc);
399 return false;
400 }
401 if (m_mergeSource.size()){
402 IE_MailMerge::IE_MailMerge_Listener * listener = new Print_MailMerge_Listener(pDoc, pGraphics, szFile);
403
404 uri = UT_go_shell_arg_to_uri (m_mergeSource.utf8_str());
405 handleMerge (uri, *listener);
406 g_free (uri);
407
408 DELETEP(listener);
409 } else {
410
411 // create a new layout and view object for the doc
412 FL_DocLayout *pDocLayout = new FL_DocLayout(pDoc,pGraphics);
413 FV_View printView(XAP_App::getApp(),0,pDocLayout);
414 pDocLayout->setView (&printView);
415 pDocLayout->fillLayouts();
416 pDocLayout->formatAll();
417 pDocLayout->recalculateTOCFields();
418
419 bool bCollate = true;
420 UT_sint32 nCopies = 1;
421 std::set<UT_sint32> pages;
422
423 std::map<std::string, std::string> props_map;
424 UT_parse_properties(m_expProps.utf8_str(), props_map);
425
426 if (props_map.find("collate") != props_map.end())
427 {
428 bCollate = UT_parseBool(props_map["collate"].c_str(), true);
429 }
430
431 if (props_map.find("copies") != props_map.end())
432 {
433 nCopies = atoi(props_map["copies"].c_str());
434 if (nCopies <= 0)
435 nCopies = 1;
436 }
437
438 if (props_map.find("pages") != props_map.end())
439 {
440 char **page_descriptions;
441
442 page_descriptions = g_strsplit(props_map["pages"].c_str(), ",", -1);
443
444 int i = 0;
445 while (page_descriptions[i] != NULL)
446 {
447 char *description = page_descriptions[i];
448 i++;
449
450 int start_page, end_page;
451
452 if (2 == sscanf(description, "%d-%d", &start_page, &end_page))
453 {
454 }
455 else if (1 == sscanf(description, "%d", &start_page))
456 {
457 end_page = start_page;
458 }
459 else
460 {
461 // invalid page specification
462 continue;
463 }
464
465 for (int pageno = start_page; pageno <= end_page; pageno++)
466 {
467 if ((pageno > 0) && (pageno <= (int)pDocLayout->countPages()))
468 pages.insert(pageno);
469 }
470 }
471
472 g_strfreev(page_descriptions);
473 }
474
475 if (pages.empty())
476 {
477 for (UT_sint32 i = 1; i <= pDocLayout->countPages(); i++)
478 {
479 pages.insert(i);
480 }
481 }
482
483 if(!s_actuallyPrint (pDoc, pGraphics,
484 &printView, szFile,
485 nCopies, bCollate,
486 pDocLayout->getWidth(), pDocLayout->getHeight() / pDocLayout->countPages(),
487 pages))
488 err = UT_SAVE_WRITEERROR;
489
490 DELETEP(pDocLayout);
491 }
492
493 UNREFP(pDoc);
494
495 return (err == UT_OK);
496 }
497
498
printFirstPage(GR_Graphics * pGraphics,PD_Document * pDoc)499 bool AP_Convert::printFirstPage(GR_Graphics * pGraphics,PD_Document * pDoc)
500 {
501 // create a new layout and view object for the doc
502
503 FL_DocLayout *pDocLayout = new FL_DocLayout(pDoc,pGraphics);
504 FV_View printView(XAP_App::getApp(),0,pDocLayout);
505 pDocLayout->setView (&printView);
506 pDocLayout->fillLayouts();
507 pDocLayout->formatAll();
508
509 bool success = s_actuallyPrint (pDoc, pGraphics,
510 &printView, "pngThumb",
511 1, true,
512 pDocLayout->getWidth(), pDocLayout->getHeight() / pDocLayout->countPages(),
513 1, 1);
514
515 DELETEP(pDocLayout);
516
517 return success;
518 }
519