[KLF Application][KLF Tools][KLF Backend][KLF Home]
KLatexFormula Project
klfmime.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * file klfmime.cpp
3  * This file is part of the KLatexFormula Project.
4  * Copyright (C) 2011 by Philippe Faist
5  * philippe.faist at bluewin.ch
6  * *
7  * This program is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program; if not, write to the *
19  * Free Software Foundation, Inc., *
20  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21  ***************************************************************************/
22 /* $Id: klfmime.cpp 627 2011-04-12 12:36:22Z phfaist $ */
23 
24 #include <QDebug>
25 #include <QApplication>
26 #include <QMap>
27 #include <QUrl>
28 #include <QBuffer>
29 #include <QDir>
30 #include <QDomDocument>
31 #include <QDomNode>
32 #include <QDomElement>
33 #include <QPainter>
34 #include <QTextCodec>
35 
36 #include <klfbackend.h>
37 
38 #include <klfguiutil.h>
39 #include "klfconfig.h"
40 #include "klflib.h"
41 #include "klfmime.h"
42 #include "klfmime_p.h"
43 
44 #ifdef Q_WS_MAC
45 #include "macosx/klfmacclipboard.h"
46 #endif
47 
48 #define OPENOFFICE_DRAWING_MIMETYPE "application/x-openoffice-drawing;windows_formatname=\"Drawing Format\""
49 
50 #ifndef Q_WS_MAC
51 // provide empty non-functional function so that it can be called in any
52 // context (also on linux, win: don't need #ifdef Q_WS_MAC)
54 #endif
55 
56 // ---------------------------------------------------------------------
57 
58 bool KLFMimeExporter::supportsKey(const QString& key) const
59 {
60  bool result = (keys().indexOf(key) >= 0) ;
61  klfDbg("key = "<<key<<" ; result="<<result) ;
62  return result;
63 }
64 
65 // static
67 {
69  initMimeExporterList();
70 
71  int k;
72  for (k = 0; k < p_mimeExporterList.size(); ++k) {
73  klfDbg("Testing exporter #"<<k<<": "<<p_mimeExporterList[k]);
74  klfDbg("\t: "<<p_mimeExporterList[k]->exporterName()) ;
75  if (p_mimeExporterList[k]->supportsKey(key))
76  return p_mimeExporterList[k];
77  }
78 
79  // no exporter found.
80  return NULL;
81 }
82 // static
84 {
86  initMimeExporterList();
87 
88  int k;
89  for (k = 0; k < p_mimeExporterList.size(); ++k)
90  if (p_mimeExporterList[k]->exporterName() == exporter) // find the given 'exporter'
91  if (key.isEmpty() || p_mimeExporterList[k]->supportsKey(key)) // check for 'key' support
92  return p_mimeExporterList[k];
93 
94  // no exporter found.
95  return NULL;
96 }
97 
98 
99 // static
101 {
103  initMimeExporterList();
104  return p_mimeExporterList;
105 }
106 
107 // static
109 {
111 
112  initMimeExporterList();
113 
114  KLF_ASSERT_NOT_NULL( exporter ,
115  "Cannot register a NULL exporter!",
116  return ) ;
117 
118  QString ename = exporter->exporterName();
119  klfDbg("want to register exporter "<<ename<<", making sure no duplicate names...") ;
120 
121  // make sure there are no duplicate names
122  int k;
123  for (k = 0; k < p_mimeExporterList.size(); ++k) {
124  klfDbg("making sure p_mimeExporterList["<<k<<"]->exporterName() [="<<p_mimeExporterList[k]->exporterName()<<"]"
125  <<" != ename [="<<ename<<"]") ;
126  KLF_ASSERT_CONDITION(p_mimeExporterList[k]->exporterName() != ename,
127  "An exporter with same name "<<ename<<" is already registered!",
128  return ) ;
129  }
130 
131  klfDbg("registering exporter "<<ename<<", overrides="<<overrides) ;
132 
133  if (overrides)
134  p_mimeExporterList.push_front(exporter);
135  else
136  p_mimeExporterList.push_back(exporter);
137 }
138 // static
140 {
142  p_mimeExporterList.removeAll(exporter);
143 }
144 
145 // static
146 void KLFMimeExporter::initMimeExporterList()
147 {
148  KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
149  if (p_mimeExporterList.isEmpty()) {
150  // ensure an instance of KLFMacPasteboardMime object
152  p_mimeExporterList
153  << new KLFMimeExporterImage(qApp)
154  << new KLFMimeExporterUrilist(qApp)
155  << new KLFMimeExporterHTML(qApp)
156  << new KLFMimeExporterLibFmts(qApp)
157  << new KLFMimeExporterGlowImage(qApp)
158  ;
159  }
160 }
161 
162 // static
163 QList<KLFMimeExporter*> KLFMimeExporter::p_mimeExporterList = QList<KLFMimeExporter*>();
164 
165 // ---------------------------------------------------------------------
166 
168  const QList<ExportType>& exporttypes)
169  : p_profileName(pname), p_description(desc), p_exportTypes(exporttypes)
170 {
171 }
172 
174  : p_profileName(o.p_profileName), p_description(o.p_description),
175  p_exportTypes(o.p_exportTypes)
176 {
177 }
178 
180 {
182 
183  KLF_ASSERT_CONDITION(k >= 0 && k < p_exportTypes.size(),
184  "Index "<<k<<" out of bounds (size="<<p_exportTypes.size()<<")",
185  return NULL ) ;
186 
187  KLFMimeExporter * exporter = NULL;
188  if ( ! p_exportTypes[k].exporter.isEmpty() ) {
189  // lookup the exporter by name, and make sure that it supports the 'mimetype' key
190  exporter = KLFMimeExporter::mimeExporterLookupByName(p_exportTypes[k].exporter, p_exportTypes[k].mimetype);
191  } else {
192  // lookup the exporter by mime-type
193  exporter = KLFMimeExporter::mimeExporterLookup(p_exportTypes[k].mimetype);
194  }
195 
196  if (warnNotFound)
197  KLF_ASSERT_NOT_NULL(exporter,
198  "Can't find exporter "<<p_exportTypes[k].exporter<<" for export-type #"<<k
199  <<"for key "<<p_exportTypes[k].mimetype, return NULL ) ;
200  return exporter;
201 }
202 
204 {
206 
207  QStringList mimetypes;
208  int k;
209  for (k = 0; k < p_exportTypes.size(); ++k)
210  mimetypes << p_exportTypes[k].mimetype;
211  return mimetypes;
212 }
213 
215 {
217 
218  int k;
219  for (k = 0; k < p_exportTypes.size(); ++k)
220  if (p_exportTypes[k].mimetype == mimeType)
221  return k;
222  return -1;
223 }
224 
226 {
228 
229  QStringList wintypes;
230  int k;
231  for (k = 0; k < p_exportTypes.size(); ++k)
232  wintypes << respectiveWinType(k);
233  return wintypes;
234 }
236 {
237  KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ; klfDbg("k="<<k) ;
238 
239  KLF_ASSERT_CONDITION(k >= 0 && k < p_exportTypes.size(),
240  "Index "<<k<<" out of bounds (size="<<p_exportTypes.size()<<")",
241  return QString() ) ;
242 
243  if ( ! p_exportTypes[k].wintype.isEmpty() )
244  return p_exportTypes[k].wintype;
245 
246  KLFMimeExporter *exporter = exporterLookupFor(k, true);
247  if (exporter == NULL)
248  return QString();
249 
250  return exporter->windowsFormatName(p_exportTypes[k].mimetype);
251 }
252 
254 {
256 
257  QStringList oktypes;
258  int k;
259  for (k = 0; k < p_exportTypes.size(); ++k) {
260  if (exporterLookupFor(k, false) != NULL)
261  oktypes << p_exportTypes[k].mimetype;
262  }
263  return oktypes;
264 }
265 
266 
267 // static
268 QList<KLFMimeExportProfile> KLFMimeExportProfile::p_exportProfileList = QList<KLFMimeExportProfile>();
269 
270 // static
272 {
274 
275  ensureLoadedExportProfileList();
276  return p_exportProfileList;
277 }
278 // static
280 {
282 
283  ensureLoadedExportProfileList();
284  p_exportProfileList.push_front(exportProfile);
285 }
286 // static
288 {
290 
291  ensureLoadedExportProfileList();
292 
293  int k;
294  for (k = 0; k < p_exportProfileList.size(); ++k)
295  if (p_exportProfileList[k].profileName() == pname)
296  return p_exportProfileList[k];
297 
298  // not found, return first (ie. default) export profile
299  return p_exportProfileList[0];
300 }
301 
302 void KLFMimeExportProfile::ensureLoadedExportProfileList()
303 {
304  KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
305 
306  if ( ! p_exportProfileList.isEmpty())
307  return;
308 
309  // read export profile list from XML
310 
311  // find correct XML file
312  QStringList fcandidates;
313 
314  QStringList dirs;
315  dirs << klfconfig.homeConfigDir + "/conf/export_mime_profiles.d"
316  << klfconfig.globalShareDir + "/conf/export_mime_profiles.d"
317  << ":/conf/export_mime_profiles.d";
318  int j, k;
319  for (j = 0; j < dirs.size(); ++j) {
320  // add all files in ...dirs[j].../*.xml
321  QDir d(dirs[j]);
322  QStringList entrylist;
323  entrylist = d.entryList(QStringList()<<QLatin1String("*.xml"), QDir::Files|QDir::Readable, QDir::Name);
324  for (k = 0; k < entrylist.size(); ++k)
325  fcandidates << d.filePath(entrylist[k]);
326  }
327 
328  for (k = 0; k < fcandidates.size(); ++k) {
329  if (QFile::exists(fcandidates[k]))
330  loadFromXMLFile(fcandidates[k]);
331  }
332 
333  // create a temp exporter on the stack to see which keys it supports, and add all avail formats
334  // to an extra export profile
335  QList<ExportType> exporttypes;
336  KLFMimeExporterImage imgexporter(NULL);
337  QStringList mimetypes = imgexporter.keys();
338  for (k = 0; k < mimetypes.size(); ++k) {
339  if (mimetypes[k].startsWith("image/") || mimetypes[k] == "application/x-qt-image")
340  exporttypes << ExportType(mimetypes[k], imgexporter.windowsFormatName(mimetypes[k]));
341  }
342  KLFMimeExportProfile allimgfmts
343  = KLFMimeExportProfile("all_image_formats",
344  QObject::tr("All Available Image Formats"),
345  exporttypes);
346  p_exportProfileList << allimgfmts;
347 
348 }
349 
350 
351 // static, private
352 void KLFMimeExportProfile::loadFromXMLFile(const QString& fname)
353 {
354  KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
355 
356  klfDbg("Loading from file "<<fname<<"; our locale is "<<klfconfig.UI.locale) ;
357 
358  QFile file(fname);
359  if ( ! file.open(QIODevice::ReadOnly) ) {
360  qWarning()<<KLF_FUNC_NAME<<": Error: Can't open export mime profiles XML file "<<fname<<": "
361  <<file.errorString()<<"!";
362  return;
363  }
364 
365  QDomDocument doc("export-profile-list");
366  QString errMsg; int errLine, errCol;
367  bool r = doc.setContent(&file, false, &errMsg, &errLine, &errCol);
368  if (!r) {
369  qWarning()<<KLF_FUNC_NAME<<": Error parsing file "<<fname<<": "<<errMsg<<" at line "<<errLine<<", col "<<errCol;
370  return;
371  }
372  file.close();
373 
374  QDomElement root = doc.documentElement();
375  if (root.nodeName() != "export-profile-list") {
376  qWarning("%s: Error parsing XML for export mime profiles from file `%s': Bad root node `%s'.\n",
377  KLF_FUNC_NAME, qPrintable(fname), qPrintable(root.nodeName()));
378  return;
379  }
380 
381  QStringList descriptionLangs;
382 
383  // read XML file
384  QDomNode n;
385  for (n = root.firstChild(); ! n.isNull(); n = n.nextSibling()) {
386  QDomElement e = n.toElement(); // try to convert the node to an element.
387  if ( e.isNull() || n.nodeType() != QDomNode::ElementNode )
388  continue;
389  if ( e.nodeName() == "add-macosx-type-rules" ) {
390 #ifdef Q_WS_MAC
391  __klf_add_macosx_type_rules(fname, e);
392 #else
393  klfDbg("Ignoring Mac OS X type rules on non-mac window system") ;
394 #endif
395  continue;
396  }
397  if ( e.nodeName() != "profile" ) {
398  qWarning("%s: WARNING in parsing XML \"%s\" : ignoring unexpected tag `%s', expected <profile>.\n",
399  KLF_FUNC_NAME, qPrintable(fname), qPrintable(e.nodeName()));
400  continue;
401  }
402  // read profile
403  QString pname = e.attribute("name");
404 
405  // note: profile may already exist, we will check for that later.
406 
407  klfDbg("Reading profile "<<pname<<" ...") ;
408 
410  // xml:lang attribute for profile description is obsolete, we use now Qt-linguist translated value...
411  QString curDescriptionLang;
412  QList<ExportType> exporttypes;
413 
414  QDomNode en;
415  for (en = e.firstChild(); ! en.isNull(); en = en.nextSibling() ) {
416  if ( en.isNull() || en.nodeType() != QDomNode::ElementNode )
417  continue;
418  QDomElement ee = en.toElement();
419  if ( en.nodeName() == "description" ) {
420  // xml:lang attribute for profile description is obsolete, we use now Qt-linguist translated value...
421  QString lang = ee.hasAttribute("xml:lang") ? ee.attribute("xml:lang") : QString() ;
422  klfDbg("<description>: lang="<<lang<<"; hasAttribute(xml:lang)="<<ee.hasAttribute("xml:lang")
423  <<"; current description="<<description<<",lang="<<curDescriptionLang) ;
424  if (description.isEmpty()) {
425  // no description yet
426  if (lang.isEmpty() || lang.startsWith(klfconfig.UI.locale) || klfconfig.UI.locale.startsWith(lang)) {
427  // correct locale
428  // klfDbg("remembering description tag with lang="<<lang);
429  description = qApp->translate("xmltr_exportprofiles", ee.text().toUtf8().constData(),
430  "[[tag: <description>]]", QCoreApplication::UnicodeUTF8);
431  // xml:lang attribute for profile description is obsolete, we use now Qt-linguist translated value...
432  curDescriptionLang = lang;
433  }
434  // otherwise skip this tag
435  } else {
436  // see if this locale is correct and more specific
437  if ( (lang.startsWith(klfconfig.UI.locale) || klfconfig.UI.locale.startsWith(lang)) &&
438  (curDescriptionLang.isEmpty() || lang.startsWith(curDescriptionLang) ) ) {
439  // then keep it and replace the other
440  // klfDbg("remembering description tag with lang="<<lang);
441  description = ee.text();
442  curDescriptionLang = lang;
443  }
444  // otherwise skip this tag
445  }
446  continue;
447  }
448  if ( en.nodeName() != "export-type" ) {
449  qWarning("%s: WARNING in parsing XML '%s': ignoring unexpected tag `%s' in profile `%s'!\n",
450  KLF_FUNC_NAME, qPrintable(fname), qPrintable(en.nodeName()), qPrintable(pname));
451  continue;
452  }
453  QDomNodeList mimetypetags = ee.elementsByTagName("mime-type");
454  if (mimetypetags.size() != 1) {
455  qWarning()<<KLF_FUNC_NAME<<": in XML file "<<fname<<", profile "<<pname
456  <<": exactly ONE <mime-type> tag must be present in each <export-type>...</export-type>.";
457  continue;
458  }
459  QDomNodeList wintypetags = ee.elementsByTagName("windows-type");
460  if (wintypetags.size() > 1) {
461  qWarning()<<KLF_FUNC_NAME<<": in XML file "<<fname<<", profile "<<pname
462  <<": expecting at most ONE <windows-type> tag in each <export-type>...</export-type>.";
463  continue;
464  }
465  QDomNodeList exporternametags = ee.elementsByTagName("exporter-name");
466  if (exporternametags.size() > 1) {
467  qWarning()<<KLF_FUNC_NAME<<": in XML file "<<fname<<", profile "<<pname
468  <<": expected at most ONE <exporter-name> tag in each <export-type>...</export-type>.";
469  continue;
470  }
471  QString mimetype = mimetypetags.at(0).toElement().text().trimmed();
472  QString wintype = QString();
473  if (wintypetags.size() == 1) {
474  wintype = wintypetags.at(0).toElement().text().trimmed();
475  }
476  QString exportername = QString();
477  if (exporternametags.size() == 1) {
478  exportername = exporternametags.at(0).toElement().text().trimmed();
479  }
480 
481  exporttypes << ExportType(mimetype, wintype, exportername);
482  }
483 
484  // add this profile
485  KLFMimeExportProfile profile(pname, description, exporttypes);
486 
487  // check if a profile has not already been declared with same name
488  int kp;
489  for (kp = 0; kp < p_exportProfileList.size(); ++kp) {
490  if (p_exportProfileList[kp].profileName() == pname) {
491  break;
492  }
493  }
494  if (kp == p_exportProfileList.size()) {
495  // the profile is new
496  klfDbg("Adding profile "<<pname<<" to mime export profiles") ;
497  if (pname == "default") {
498  // prepend default profile, so it's at beginning
499  p_exportProfileList.prepend(profile);
500  } else {
501  p_exportProfileList << profile;
502  // xml:lang attribute for profile description is obsolete, we use now Qt-linguist translated value...
503  descriptionLangs << curDescriptionLang;
504  }
505  } else {
506  // profile already exists, append data to it
507  KLFMimeExportProfile oldp = p_exportProfileList[kp];
508  // see if this description provides a better translation
509  if (!description.isEmpty() &&
510  (descriptionLangs[kp].isEmpty() || curDescriptionLang.startsWith(descriptionLangs[kp]))) {
511  // keep this description
512  } else {
513  description = oldp.description();
514  }
515  KLFMimeExportProfile finalp(pname, description,
516  oldp.exportTypes()+exporttypes // concatenate lists
517  );
518  p_exportProfileList[kp] = finalp;
519  }
520  }
521 }
522 
523 
524 // ---------------------------------------------------------------------
525 
526 
527 
528 
529 KLFMimeData::KLFMimeData(const QString& exportProfile, const KLFBackend::klfOutput& output)
530  : QMimeData(), pExportProfile(KLFMimeExportProfile::findExportProfile(exportProfile))
531 {
533 
534  // ensure an instance of KLFMacPasteboardMime object
536 
537  pOutput = output;
538 
539  set_possible_qt_image_data();
540 }
542 {
544 }
545 
546 // private
547 void KLFMimeData::set_possible_qt_image_data()
548 {
549  KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
550 
551  // Handle platform-specific default image type with 'application/x-qt-image' and setImage()
552  int index;
553  if ( (index=pExportProfile.indexOfMimeType(QLatin1String("application/x-qt-image"))) >= 0) {
554  // set the image data form the exporter
555  KLFMimeExporter * exporter = pExportProfile.exporterLookupFor(index);
556  if (exporter != NULL) {
557  QByteArray img_data = exporter->data(QLatin1String("application/x-qt-image"), pOutput);
558  QImage img;
559  QList<QByteArray> try_formats = QList<QByteArray>() << "PNG" << "JPEG" << "BMP";
560  int k;
561  for (k = 0; k < try_formats.size() && img.isNull(); ++k)
562  img.loadFromData(img_data, try_formats[k].constData());
563  KLF_ASSERT_CONDITION( ! img.isNull() ,
564  "Can't get image for application/x-qt-image for profile "<<pExportProfile.profileName(),
565  return; ) ;
566  setImageData(img);
567  }
568  }
569 }
570 
572 {
574 
575  QStringList fmts = pExportProfile.availableExporterMimeTypes();
576  if (fmts.contains("application/x-qt-image")) {
577  if (pQtOwnedFormats.size() == 0)
578  pQtOwnedFormats = QMimeData::formats();
579  fmts << pQtOwnedFormats;
580  }
581 
582  klfDbg("format list: "<<fmts) ;
583  return fmts;
584 }
585 
586 QVariant KLFMimeData::retrieveData(const QString& mimetype, QVariant::Type type) const
587 {
589 
590  if (mimetype == QLatin1String("application/x-qt-image") ||
591  pQtOwnedFormats.contains(mimetype))
592  return QMimeData::retrieveData(mimetype, type);
593 
594  int index = pExportProfile.indexOfMimeType(mimetype);
595  if (index < 0) {
596  // do not treat this as an error since on windows we seem to have requests for 'text/uri-list' even
597  // if that mime type is not returned by formats()
598  klfDbg("Can't find mime-type "<<mimetype<<" in export profile "<<pExportProfile.profileName()
599  <<" ?!?");
600  return QVariant();
601  }
602 
603  klfDbg("exporting "<<mimetype<<" ...");
604  KLFMimeExporter *exporter = pExportProfile.exporterLookupFor(index);
605 
606  KLF_ASSERT_NOT_NULL(exporter,
607  "Can't find an exporter for mime-type "<<mimetype<<"." ,
608  return QVariant(); ) ;
609 
610  // get the data
611  QByteArray data = exporter->data(mimetype, pOutput);
612 
613  klfDbg("exporting mimetype "<<mimetype<<": data length is "<<data.size());
614 
615  return QVariant::fromValue<QByteArray>(data);
616 }
617 
618 
619 
620 
621 // ---------------------------------------------------------------------
622 
624 {
626 
627  QMap<QString,QByteArray> imageFormats;
628  // get qt's image formats
630  int k;
631  for (k = 0; k < qtimgfmts.size(); ++k) {
632  if ( imageFormats.key(qtimgfmts[k]).isEmpty() ) {
633  QString mime = QString::fromLatin1("image/")+QString::fromLatin1(qtimgfmts[k]).toLower();
634  imageFormats[mime] = qtimgfmts[k];
635  }
636  }
637  return imageFormats;
638 }
639 
640 QMap<QString,QByteArray> KLFMimeExporterImage::imageFormats = QMap<QString,QByteArray>();
641 
643 {
645 
646  // image formats that are always supported. Qt image formats are added too.
647  static QStringList staticKeys
648  = QStringList() << "image/png" << "image/eps" << "application/eps" << "application/postscript"
649  << OPENOFFICE_DRAWING_MIMETYPE << "application/x-qt-image"
650  // add duplicate for png, see below
651  << "image/x-win-png-office-art";
652 
653  if (imageFormats.isEmpty()) {
654  // populate qt's image formats
657  for (it = ifmts.begin(); it != ifmts.end(); ++it) {
658  QString mime = it.key();
659  QByteArray qtfmt = it.value();
660  // add this image format, if not already provided by staticKeys
661  if (staticKeys.indexOf(mime) == -1)
662  imageFormats[mime] = qtfmt;
663  // add duplicate mime types for some formats, to be able to specify multiple windows format
664  // names for them, eg. "Bitmap" and "Windows Bitmap" :
665  if (mime == "image/bmp") {
666  imageFormats["image/x-win-bmp"] = qtfmt;
667  } else if (mime == "image/jpeg") {
668  imageFormats["image/x-win-jfif"] = qtfmt;
669  imageFormats["image/x-win-jfif-office-art"] = qtfmt;
670  } else if (mime == "image/png") {
671  imageFormats["image/x-win-png-office-art"] = qtfmt;
672  }
673  }
674  }
675 
676  QStringList keys = staticKeys;
677 
679  keys <<"application/pdf"; // add PDF only if we have PDF
680 
681  keys << imageFormats.keys();
682 
683  return keys;
684 }
685 
687 {
689 
690  QString wtype;
691  if (mime == "application/pdf")
692  return "PDF";
693  else if (mime == "application/eps")
694  return "Encapsulated PostScript";
695  else if (mime == "image/png")
696  return "PNG";
697  else if (mime == "image/jpg" || mime == "image/jpeg")
698  // standards should only allow image/jpeg, but just in case we treat also erroneous "image/jpg"
699  return "JPEG";
700  else if (mime == "image/x-win-jfif")
701  return "JFIF";
702  else if (mime == "image/x-win-jfif-office-art")
703  return "JFIF+Office Art"; // for Ms Office
704  else if (mime == "image/x-win-png-office-art")
705  return "PNG+Office Art"; // for Ms Office
706  else if (mime == "image/bmp")
707  return "Bitmap";
708  else if (mime == "image/x-win-bmp")
709  return "Windows Bitmap";
710  else if (mime == OPENOFFICE_DRAWING_MIMETYPE)
711  return "Drawing Format";
712  else if (mime == "application/x-qt-image")
713  return mime; // let Qt translate this one
714 
715  return mime;
716 }
717 
719 
721 {
723 
724  QString key = keymime;
725  klfDbg("key="<<key);
726 
727  if (key == "image/png")
728  return klfoutput.pngdata;
729  if (key == "image/eps" || key == "application/eps" || key == "application/postscript")
730  return klfoutput.epsdata;
731  if (key == "application/pdf") {
732 #ifdef KLF_DEBUG
733  if (klfoutput.pdfdata.isEmpty())
734  klfDbg("---warning: don't have PDF data ---") ;
735 #endif
736  return klfoutput.pdfdata;
737  }
738  if (key == OPENOFFICE_DRAWING_MIMETYPE)
739  return klf_openoffice_drawing(klfoutput);
740  if (key == "application/x-qt-image")
741  return klfoutput.pngdata;
742 
743  // rely on qt's image saving routines for other formats
744  klfDbg("Will use Qt's image format exporting");
745 
746  if ( ! imageFormats.contains(key) )
747  return QByteArray();
748 
749  QByteArray imgdata;
750  QBuffer imgdatawriter(&imgdata);
751  imgdatawriter.open(QIODevice::WriteOnly);
752  klfoutput.result.save(&imgdatawriter, imageFormats[key]);
753  imgdatawriter.close();
754 
755  klfDbg("got data: size="<<imgdata.size());
756  return imgdata;
757 }
758 
759 
760 
761 // ---------------------------------------------------------------------
762 
763 QMap<qint64,QString> KLFMimeExporterUrilist::tempFilesForImageCacheKey = QMap<qint64,QString>();
764 
766 {
768  return QStringList() << "text/x-moz-url" << "text/uri-list";
769 }
770 
771 // static
773 {
774  qint64 imgcachekey = output.result.cacheKey();
775 
776  QString tempfilename;
777 
778  if (tempFilesForImageCacheKey.contains(imgcachekey)) {
779  tempfilename = tempFilesForImageCacheKey[imgcachekey];
780  } else {
782  QString("/klf_%1_XXXXXX.png").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm"));
783  QTemporaryFile *tempfile = new QTemporaryFile(templ, qApp);
784  tempfile->setAutoRemove(true); // will be deleted when klatexformula exists (= qApp destroyed)
785  if (tempfile->open() == false) {
786  qWarning("Can't open temp png file for mimetype text/uri-list: template is %s",
787  qPrintable(templ));
788  return QByteArray();
789  } else {
790  QString errStr;
791  bool res = KLFBackend::saveOutputToFile(output, tempfile->fileName(), "PNG", &errStr);
792  if (!res) {
793  qWarning()<<KLF_FUNC_NAME<<": Can't save to temp file "<<tempfile->fileName()<<": "<<errStr;
794  } else {
795  tempfilename = tempfile->fileName();
796  tempfile->write(output.pngdata);
797  tempfile->close();
798  // cache this temp file for other formats' use or other QMimeData instantiation...
799  tempFilesForImageCacheKey[imgcachekey] = tempfilename;
800  }
801  }
802  }
803 
804  return tempfilename;
805 }
806 
808 {
810 
811  Q_UNUSED(key) ;
812  klfDbg("key="<<key) ;
813 
814  QString tempfilename = tempFileForOutput(output);
815  QByteArray urilist = (QUrl::fromLocalFile(tempfilename).toString()+QLatin1String("\n")).toLatin1();
816  return urilist;
817 }
818 
820 {
822 
823  if (mime == "text/x-moz-url")
824  return "FileName";
825  return mime;
826 }
827 
828 
829 
830 // -----------------------------------
831 
832 static QString toAttrTextS(const QString& sbase)
833 {
834  QString s = sbase; // we need a non-const string to .replace() on
835  klfDbg("s="<<s);
836  QRegExp replaceCharsRX("([^a-zA-Z0-9/ ._-])");
837  int pos = 0;
838  while ((pos = replaceCharsRX.indexIn(s, pos)) != -1) {
839  QString entity = "&#x"+QString::number(replaceCharsRX.cap(1)[0].unicode(), 16).toUpper()+";" ;
840  klfDbg("replacing char at pos="<<pos<<" by entity="<<entity<<": s(pos...pos+5)="<<s.mid(pos,5));
841  s.replace(pos, replaceCharsRX.matchedLength(), entity);
842  pos += entity.length();
843  }
844  klfDbg("final string: "<<s);
845  return s;
846 
847  // QString s2 = sbase;
848  // return s2.replace("&", "&amp;").replace("\"", "&quot;").replace("'", "&apos;").replace("<", "&lt")
849  // .replace(">", "&gt;").replace("\r", "&#xD;").replace("\t", "&#x9;").replace("\n", "&#xA;")
850  // .replace("!", "&#x21;").toUtf8();
851 }
852 
853 static QByteArray toAttrText(const QString& sbase)
854 {
855  return toAttrTextS(sbase).toUtf8();
856 }
857 
859 {
860  return QStringList() << QLatin1String("text/html");
861 }
862 
864 {
865  if (key != QLatin1String("text/html")) {
866  qWarning()<<KLF_FUNC_NAME<<": key="<<key<<" is not \"text/html\"";
867  return QByteArray();
868  }
869 
871 
872  QSize imgsize = klfoutput.result.size();
873  int imgDpi = klfoutput.input.dpi;
874  int dispDpi = 100;
875 
876  QString latex = klfoutput.input.latex;
877  // remove initial comments from latex code...
878  QStringList latexlines = latex.split("\n");
879  while (latexlines.size() && QRegExp("\\s*\\%.*").exactMatch(latexlines[0]))
880  latexlines.removeAt(0);
881  latex = latexlines.join("\n");
882 
883  QString fn = toAttrTextS(fname);
884  QString l = toAttrTextS(latex);
885  fn.replace("\"", "&#34;");
886  l.replace("\"", "&#34;");
887  QString w = QString::number((int)(1.5 * imgsize.width() * dispDpi/imgDpi));
888  QString h = QString::number((int)(1.5 * imgsize.height() * dispDpi/imgDpi));
889  QString win = QString::number(1.5 * imgsize.width() / imgDpi);
890  QString hin = QString::number(1.5 * imgsize.height() / imgDpi);
891 
892  QString html =
893  QString("<img src=\"file://%1\" alt=\"%2\" title=\"%3\" " //"width=\"%4\" height=\"%5\" "
894  " style=\"width: %4in; height: %5in; vertical-align: middle;\">")
895  .arg(fn, l, l, win, hin);
896 
897 #ifdef Q_WS_MAC
898  return html.toUtf8();
899 #else
900  QTextCodec *codec = QTextCodec::codecForName("UTF-16");
901  return codec->fromUnicode(html);
902 #endif
903 }
904 
906 {
907  if (key == QLatin1String("text/html"))
908  return "HTML";
909  return key;
910 }
911 
912 
913 // -----------------------------------
914 
915 
917 {
919 
920  QByteArray pngdata = klfoutput.pngdata;
921 
922  QFile templfile(":/data/ooodrawingtemplate");
923  templfile.open(QIODevice::ReadOnly);
924  QByteArray templ = templfile.readAll();
925 
926  QString fgcols = QColor(klfoutput.input.fg_color).name();
927  QString bgcols;
928  if (qAlpha(klfoutput.input.bg_color) > 0)
929  bgcols = QColor(klfoutput.input.fg_color).name();
930  else
931  bgcols = "-";
932 
933  templ.replace(QByteArray("<!--KLF_PNG_BASE64_DATA-->"), pngdata.toBase64());
934 
935  templ.replace(QByteArray("<!--KLF_INPUT_LATEX-->"), toAttrText(klfoutput.input.latex));
936  templ.replace(QByteArray("<!--KLF_INPUT_MATHMODE-->"), toAttrText(klfoutput.input.mathmode));
937  templ.replace(QByteArray("<!--KLF_INPUT_PREAMBLE-->"), toAttrText(klfoutput.input.preamble));
938  templ.replace(QByteArray("<!--KLF_INPUT_FGCOLOR-->"), toAttrText(fgcols));
939  templ.replace(QByteArray("<!--KLF_INPUT_BGCOLOR-->"), toAttrText(bgcols));
940  templ.replace(QByteArray("<!--KLF_INPUT_DPI-->"), toAttrText(QString::number(klfoutput.input.dpi)));
941  templ.replace(QByteArray("<!--KLF_SETTINGS_TBORDEROFFSET_PSPT-->"),
943  templ.replace(QByteArray("<!--KLF_SETTINGS_RBORDEROFFSET_PSPT-->"),
945  templ.replace(QByteArray("<!--KLF_SETTINGS_BBORDEROFFSET_PSPT-->"),
947  templ.replace(QByteArray("<!--KLF_SETTINGS_LBORDEROFFSET_PSPT-->"),
949 
950  templ.replace(QByteArray("<!--KLF_INPUT_LATEX_BASE64-->"), klfoutput.input.latex.toLocal8Bit().toBase64());
951  templ.replace(QByteArray("<!--KLF_INPUT_MATHMODE_BASE64-->"), klfoutput.input.mathmode.toLocal8Bit().toBase64());
952  templ.replace(QByteArray("<!--KLF_INPUT_PREAMBLE_BASE64-->"), klfoutput.input.preamble.toLocal8Bit().toBase64());
953  templ.replace(QByteArray("<!--KLF_INPUT_FGCOLOR_BASE64-->"), fgcols.toLocal8Bit().toBase64());
954  templ.replace(QByteArray("<!--KLF_INPUT_BGCOLOR_BASE64-->"), bgcols.toLocal8Bit().toBase64());
955 
956  templ.replace(QByteArray("<!--KLF_OOOLATEX_ARGS-->"), toAttrText("12§display§"+klfoutput.input.latex));
957 
958  // make the equations larger, so it is not too cramped up
959  const double DPI_FACTOR = 1.6;
960  // cm/inch = 2.54
961  // include an elargment factor in these tags
962  templ.replace(QByteArray("<!--KLF_IMAGE_WIDTH_CM-->"),
963  QString::number(DPI_FACTOR * 2.54 * klfoutput.result.width()/klfoutput.input.dpi, 'f', 2).toUtf8());
964  templ.replace(QByteArray("<!--KLF_IMAGE_HEIGHT_CM-->"),
965  QString::number(DPI_FACTOR * 2.54 * klfoutput.result.height()/klfoutput.input.dpi, 'f', 2).toUtf8());
966  // same, without the enlargment factor
967  templ.replace(QByteArray("<!--KLF_IMAGE_ORIG_WIDTH_CM-->"),
968  QString::number(2.54 * klfoutput.result.width()/klfoutput.input.dpi, 'f', 2).toUtf8());
969  templ.replace(QByteArray("<!--KLF_IMAGE_ORIG_HEIGHT_CM-->"),
970  QString::number(2.54 * klfoutput.result.height()/klfoutput.input.dpi, 'f', 2).toUtf8());
971 
972  templ.replace(QByteArray("<!--KLF_IMAGE_WIDTH_PX-->"), QString::number(klfoutput.result.width()).toUtf8());
973  templ.replace(QByteArray("<!--KLF_IMAGE_HEIGHT_PX-->"), QString::number(klfoutput.result.height()).toUtf8());
974  templ.replace(QByteArray("<!--KLF_IMAGE_ASPECT_RATIO-->"),
975  QString::number((double)klfoutput.result.width()/klfoutput.result.height(), 'f', 3).toUtf8());
976 
977  klfDbg("final templ: "<<templ);
978 
979  return templ;
980 }
981 
982 
983 
984 
985 
986 // ---------------------------
987 
988 
989 
991 {
993 
996 }
997 
999 {
1001 
1002  klfDbg("key="<<key);
1005  if (encoder == NULL) {
1006  // warning already issued in findEncoderFor(.., TRUE)
1007  return QByteArray();
1008  }
1009 
1011  output.result.scaled(klfconfig.UI.labelOutputFixedSize, Qt::KeepAspectRatio,
1012  Qt::SmoothTransformation),
1013  KLFStyle(output.input));
1014 
1015  QByteArray data = encoder->encodeMime(KLFLibEntryList()<<e, QVariantMap(), key);
1016 
1017  if (!data.size())
1018  qWarning()<<KLF_FUNC_NAME<<": "<<key<<" encoder returned empty data!";
1019 
1020  klfDbg("got data, size="<<data.size());
1021  return data;
1022 }
1023 
1024 
1025 
1026 
1027 // -------------------------------
1028 
1030 {
1032 
1033  return QStringList() << "image/png" << "application/x-qt-image";
1034 }
1035 
1037 {
1039 
1040  klfDbg("key = "<<key) ;
1041 
1042  QImage img(output.result.size() + QSize(1,1)*2*klfconfig.UI.glowEffectRadius, QImage::Format_ARGB32);
1043 
1044  // initialize image to transparent
1045  img.fill(qRgba(0,0,0,0));
1046 
1047  { // now draw the glowed equation
1048  QPainter p(&img);
1051  }
1052 
1053  QByteArray data;
1054  { // save the image as PNG data into our data qbytearray
1055  QBuffer buf(&data);
1056  buf.open(QIODevice::WriteOnly);
1057  img.save(&buf, "PNG");
1058  }
1059 
1060  // and return the PNG data
1061  return data;
1062 }
1063 
1064 
1065 
QString profileName() const
Definition: klfmime.h:118
QStringList availableExporterMimeTypes() const
Definition: klfmime.cpp:253
elementsByTagName(const QString &tagname)
fromUnicode(const QString &str)
virtual QString windowsFormatName(const QString &key) const
Definition: klfmime.cpp:819
static void unregisterMimeExporter(KLFMimeExporter *exporter)
Definition: klfmime.cpp:139
loadFromData(const uchar *data, int len, const char *format=0)
cap(int nth=0)
data(const QString &mimeType)
retrieveData(const QString &mimeType, QVariant::Type type)
QString locale
When setting this, don't forget to call QLocale::setDefault().
Definition: klfconfig.h:177
contains(const Key &key)
An export profile grouping several mime types.
Definition: klfmime.h:103
static KLFMimeExportProfile findExportProfile(const QString &pname)
Definition: klfmime.cpp:287
push_back(const T &value)
QStringList mimeTypes() const
Definition: klfmime.cpp:203
KLFConfig klfconfig
Definition: klfconfig.cpp:88
virtual QString windowsFormatName(const QString &key) const
Definition: klfmime.cpp:905
struct KLFConfig::@1 UI
QList< KLFLibEntry > KLFLibEntryList
Definition: klflib.h:140
save(const QString &fileName, const char *format=0, int quality=-1)
split(const QString &sep, SplitBehavior behavior=KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive)
virtual QByteArray data(const QString &key, const KLFBackend::klfOutput &klfoutput)=0
contains(const QString &str, Qt::CaseSensitivity cs=Qt::CaseSensitive)
virtual QByteArray data(const QString &key, const KLFBackend::klfOutput &klfoutput)
Definition: klfmime.cpp:998
push_front(const T &value)
#define klfDbg(streamableItems)
static QString tempFileForOutput(const KLFBackend::klfOutput &klfoutput)
Definition: klfmime.cpp:772
QColor glowEffectColor
Definition: klfconfig.h:198
#define KLF_DEBUG_BLOCK(msg)
QByteArray klf_openoffice_drawing(const KLFBackend::klfOutput &klfoutput)
Definition: klfmime.cpp:916
replace(int pos, int len, const QByteArray &after)
QStringList respectiveWinTypes() const
Definition: klfmime.cpp:225
join(const QString &separator)
QString tempDir
Definition: klfconfig.h:220
int indexOfMimeType(const QString &mimeType) const
Definition: klfmime.cpp:214
static QMap< QString, QByteArray > get_qt_image_formats()
Definition: klfmime.cpp:623
tr(const char *sourceText, const char *comment=0, int n=-1)
virtual QStringList keys() const
Definition: klfmime.cpp:858
static KLFMimeExporter * mimeExporterLookupByName(const QString &exporter, const QString &key=QString())
Definition: klfmime.cpp:83
static QStringList allEncodingMimeTypes()
Definition: klflib.cpp:305
#define KLF_ASSERT_NOT_NULL(ptr, msg, failaction)
replace(int position, int n, const QString &after)
void __klf_init_the_macpasteboardmime()
Definition: klfmime.cpp:53
matchedLength()
static QList< KLFMimeExportProfile > exportProfileList()
Definition: klfmime.cpp:271
indexIn(const QString &str, int offset=0, CaretMode caretMode=CaretAtZero)
number(long n, int base=10)
KLFMimeExporter * exporterLookupFor(int n, bool warnNotFound=true) const
Definition: klfmime.cpp:179
QString respectiveWinType(int k) const
Definition: klfmime.cpp:235
virtual QString windowsFormatName(const QString &key) const
Definition: klfmime.h:71
virtual bool supportsKey(const QString &key) const
Shortcut function (do not reimplement in subclasses)
Definition: klfmime.cpp:58
QStringList formats() const
Definition: klfmime.cpp:571
fill(uint pixelValue)
hasAttribute(const QString &name)
virtual QByteArray data(const QString &key, const KLFBackend::klfOutput &klfoutput)
Definition: klfmime.cpp:1036
A helper class to export KLF output to other applications.
Definition: klfmime.h:55
setAutoRemove(bool b)
removeAll(const T &value)
unsigned long fg_color
startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive)
virtual QByteArray data(const QString &key, const KLFBackend::klfOutput &klfoutput)
Definition: klfmime.cpp:863
virtual QStringList keys() const
Definition: klfmime.cpp:990
unsigned long bg_color
virtual ~KLFMimeData()
Definition: klfmime.cpp:541
open(OpenMode mode)
setImageData(const QVariant &image)
static QByteArray toAttrText(const QString &sbase)
Definition: klfmime.cpp:853
static void registerMimeExporter(KLFMimeExporter *exporter, bool overrides=true)
Definition: klfmime.cpp:108
QString description() const
Definition: klfmime.h:119
#define KLF_FUNC_NAME
static void addExportProfile(const KLFMimeExportProfile &exportProfile)
Definition: klfmime.cpp:279
struct KLFConfig::@3 BackendSettings
key(const T &value)
QList< ExportType > exportTypes() const
Definition: klfmime.h:122
QString homeConfigDir
Definition: klfconfig.h:151
mid(int position, int n=-1)
static KLFMimeExporter * mimeExporterLookup(const QString &key)
Definition: klfmime.cpp:66
virtual QStringList keys() const
Definition: klfmime.cpp:642
An entry (single formula) in the library.
Definition: klflib.h:55
scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode=Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode=Qt::FastTransformation)
virtual QString windowsFormatName(const QString &key) const
Definition: klfmime.cpp:686
virtual QStringList keys() const
Definition: klfmime.cpp:765
KLFMimeData(const QString &exportProfileName, const KLFBackend::klfOutput &output)
Definition: klfmime.cpp:529
codecForName(const QByteArray &name)
KLFMimeExportProfile(const QString &pname, const QString &desc, const QList< ExportType > &exporttypes)
Definition: klfmime.cpp:167
static KLFAbstractLibEntryMimeEncoder * findEncoderFor(const QString &mimeType, bool warnIfNotFound=true)
Definition: klflib.cpp:380
translate(const QPointF &offset)
static bool saveOutputToFile(const klfOutput &output, const QString &fileName, const QString &format=QString(), QString *errorString=NULL)
QVariant retrieveData(const QString &mimetype, QVariant::Type type) const
Definition: klfmime.cpp:586
KLF_EXPORT void klfDrawGlowedImage(QPainter *p, const QImage &foreground, const QColor &glowcol, int r, bool also_draw_image)
virtual QByteArray data(const QString &key, const KLFBackend::klfOutput &klfoutput)
Definition: klfmime.cpp:807
#define OPENOFFICE_DRAWING_MIMETYPE
Definition: klfmime.cpp:48
fromLatin1(const char *str, int size=-1)
static QString toAttrTextS(const QString &sbase)
Definition: klfmime.cpp:832
Helper class to encode an entry list as mime data (abstract interface)
Definition: klflib.h:1841
virtual QByteArray data(const QString &key, const KLFBackend::klfOutput &klfoutput)
Definition: klfmime.cpp:720
indexOf(const QRegExp &rx, int from=0)
prepend(const T &value)
QString globalShareDir
Definition: klfconfig.h:152
virtual QByteArray encodeMime(const KLFLibEntryList &entryList, const QVariantMap &metaData, const QString &mimeType) const =0
isEmpty()
QSize labelOutputFixedSize
Definition: klfconfig.h:183
#define KLF_ASSERT_CONDITION(expr, msg, failaction)
QString execEpstopdf
Definition: klfconfig.h:224
exactMatch(const QString &str)
virtual QStringList keys() const
Definition: klfmime.cpp:1029
virtual QStringList keys() const =0
fromLocalFile(const QString &localFile)
virtual QString exporterName() const =0
at(int index)
value(const Key &key)
attribute(const QString &name, const QString &defValue=QString()
int glowEffectRadius
Definition: klfconfig.h:199
static QList< KLFMimeExporter * > mimeExporterList()
Definition: klfmime.cpp:100

Generated by doxygen 1.8.8