Don't try to mmap past EOF
[qt-netbsd.git] / src / qt3support / other / q3mimefactory.cpp
blobea88c330cc9136d24e6d92c114261b0fd24a8268
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the Qt3Support module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "q3mimefactory.h"
44 #ifndef QT_NO_MIMEFACTORY
46 #include "qmap.h"
47 #include "qmime.h"
48 #include "qstringlist.h"
49 #include "qfileinfo.h"
50 #include "qdir.h"
51 #include "q3dragobject.h"
52 #include "qpixmap.h"
53 #include "qimagereader.h"
54 #include "q3cleanuphandler.h"
55 #include "private/qtextimagehandler_p.h"
57 QT_BEGIN_NAMESPACE
59 static Q3MimeSourceFactory* defaultfactory = 0;
60 static Q3SingleCleanupHandler<Q3MimeSourceFactory> qmime_cleanup_factory;
62 class Q3MimeSourceFactoryData {
63 public:
64 Q3MimeSourceFactoryData() :
65 last(0)
69 ~Q3MimeSourceFactoryData()
71 QMap<QString, QMimeSource*>::Iterator it = stored.begin();
72 while (it != stored.end()) {
73 delete *it;
74 ++it;
76 delete last;
79 QMap<QString, QMimeSource*> stored;
80 QMap<QString, QString> extensions;
81 QStringList path;
82 QMimeSource* last;
83 QList<Q3MimeSourceFactory*> factories;
86 static QImage richTextImageLoader(const QString &name, const QString &context)
88 QImage img;
90 const QMimeSource *src = Q3MimeSourceFactory::defaultFactory()->data(name, context);
91 if (src && Q3ImageDrag::decode(src, img))
92 return img;
94 return QImage();
97 /*!
98 \class Q3MimeSourceFactory
99 \brief The Q3MimeSourceFactory class is an extensible provider of mime-typed data.
101 \compat
103 A Q3MimeSourceFactory provides an abstract interface to a
104 collection of information. Each piece of information is
105 represented by a QMimeSource object which can be examined and
106 converted to concrete data types by functions such as
107 Q3ImageDrag::canDecode() and Q3ImageDrag::decode().
109 The base Q3MimeSourceFactory can be used in two ways: as an
110 abstraction of a collection of files or as specifically stored
111 data. For it to access files, call setFilePath() before accessing
112 data. For stored data, call setData() for each item (there are
113 also convenience functions, e.g. setText(), setImage() and
114 setPixmap(), that simply call setData() with appropriate
115 parameters).
117 The rich text widgets, QTextEdit and QTextBrowser, use
118 Q3MimeSourceFactory to resolve references such as images or links
119 within rich text documents. They either access the default factory
120 (see \l{defaultFactory()}) or their own. Other classes that are
121 capable of displaying rich text (such as QLabel, QWhatsThis or
122 QMessageBox) always use the default factory.
124 A factory can also be used as a container to store data associated
125 with a name. This technique is useful whenever rich text contains
126 images that are stored in the program itself, not loaded from the
127 hard disk. Your program may, for example, define some image data
129 \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 0
131 To be able to use this image within some rich text, for example
132 inside a QLabel, you must create a QImage from the raw data and
133 insert it into the factory with a unique name:
134 \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 1
136 Now you can create a rich text QLabel with
138 \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 2
140 When no longer needed, you can clear the data from the factory:
142 \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 3
147 Constructs a Q3MimeSourceFactory that has no file path and no
148 stored content.
150 Q3MimeSourceFactory::Q3MimeSourceFactory() :
151 d(new Q3MimeSourceFactoryData)
153 addFilePath(QLatin1String(":/qt/q3mimesourcefactory/")); //to get from the resources
154 // add some reasonable defaults
155 setExtensionType(QLatin1String("htm"), "text/html;charset=iso8859-1");
156 setExtensionType(QLatin1String("html"), "text/html;charset=iso8859-1");
157 setExtensionType(QLatin1String("txt"), "text/plain");
158 setExtensionType(QLatin1String("xml"), "text/xml;charset=UTF-8");
159 setExtensionType(QLatin1String("jpg"), "image/jpeg"); // support misspelled jpeg files
163 Destroys the Q3MimeSourceFactory, deleting all stored content.
165 Q3MimeSourceFactory::~Q3MimeSourceFactory()
167 if (defaultFactory() == this)
168 defaultfactory = 0;
169 delete d;
172 QMimeSource* Q3MimeSourceFactory::dataInternal(const QString& abs_name, const QMap<QString, QString> &extensions) const
174 QMimeSource* r = 0;
175 QStringList attempted_names(abs_name);
176 QFileInfo fi(abs_name);
177 if (fi.isReadable()) {
178 // get the right mimetype
179 QString e = fi.extension(false);
180 QByteArray mimetype("application/octet-stream");
181 if (extensions.contains(e))
182 mimetype = extensions[e].latin1();
183 if (!QImageReader::imageFormat(abs_name).isEmpty())
184 mimetype = "application/x-qt-image";
186 QFile f(abs_name);
187 if (f.open(QIODevice::ReadOnly) && f.size()) {
188 QByteArray ba;
189 ba.resize(f.size());
190 f.readBlock(ba.data(), ba.size());
191 Q3StoredDrag* sr = new Q3StoredDrag(mimetype);
192 sr->setEncodedData(ba);
193 delete d->last;
194 d->last = r = sr;
198 // we didn't find the mime-source, so ask the default factory for
199 // the mime-source (this one will iterate over all installed ones)
201 // this looks dangerous, as this dataInternal() function will be
202 // called again when the default factory loops over all installed
203 // factories (including this), but the static bool looping in
204 // data() avoids endless recursions
205 if (!r && this != defaultFactory())
206 r = (QMimeSource*)defaultFactory()->data(abs_name);
208 return r;
213 Returns a reference to the data associated with \a abs_name. The
214 return value remains valid only until the next data() or setData()
215 call, so you should immediately decode the result.
217 If there is no data associated with \a abs_name in the factory's
218 store, the factory tries to access the local filesystem. If \a
219 abs_name isn't an absolute file name, the factory will search for
220 it in all defined paths (see \l{setFilePath()}).
222 The factory understands all the image formats supported by
223 QImageReader. Any other mime types are determined by the file name
224 extension. The default settings are
225 \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 4
226 The effect of these is that file names ending in "txt" will be
227 treated as text encoded in the local encoding; those ending in
228 "xml" will be treated as text encoded in Unicode UTF-8 encoding.
229 The text/html type is treated specially, since the encoding can be
230 specified in the html file itself. "html" or "htm" will be treated
231 as text encoded in the encoding specified by the html meta tag, if
232 none could be found, the charset of the mime type will be used.
233 The text subtype ("html", "plain", or "xml") does not affect the
234 factory, but users of the factory may behave differently. We
235 recommend creating "xml" files where practical. These files can be
236 viewed regardless of the runtime encoding and can encode any
237 Unicode characters without resorting to encoding definitions
238 inside the file.
240 Any file data that is not recognized will be retrieved as a
241 QMimeSource providing the "application/octet-stream" mime type,
242 meaning uninterpreted binary data.
244 You can add further extensions or change existing ones with
245 subsequent calls to setExtensionType(). If the extension mechanism
246 is not sufficient for your problem domain, you can inherit
247 Q3MimeSourceFactory and reimplement this function to perform some
248 more specialized mime-type detection. The same applies if you want
249 to use the mime source factory to access URL referenced data over
250 a network.
252 const QMimeSource *Q3MimeSourceFactory::data(const QString& abs_name) const
254 if (d->stored.contains(abs_name))
255 return d->stored[abs_name];
257 const QMimeSource *r = 0;
258 if (abs_name.isEmpty())
259 return r;
260 QStringList::Iterator it;
261 if (abs_name[0] == QLatin1Char('/')
262 #ifdef Q_WS_WIN
263 || (abs_name[0].isLetter() && abs_name[1] == QLatin1Char(':')) || abs_name.startsWith(QLatin1String("\\\\"))
264 #endif
267 // handle absolute file names directly
268 r = dataInternal(abs_name, d->extensions);
270 else { // check list of paths
271 for (it = d->path.begin(); !r && it != d->path.end(); ++it) {
272 QString filename = *it;
273 if (filename[(int)filename.length()-1] != QLatin1Char('/'))
274 filename += QLatin1Char('/');
275 filename += abs_name;
276 r = dataInternal(filename, d->extensions);
280 static bool looping = false;
281 if (!r && this == defaultFactory()) {
282 // we found no mime-source and we are the default factory, so
283 // we know all the other installed mime-source factories, so
284 // ask them
285 if (!looping) {
286 // to avoid endless recustions, don't enter the loop below
287 // if data() got called from within the loop below
288 looping = true;
289 for (int i = 0; i < d->factories.size(); ++i) {
290 const Q3MimeSourceFactory *f = d->factories.at(i);
291 if (f == this)
292 continue;
293 r = static_cast<const QMimeSource *>(f->data(abs_name));
294 if (r) {
295 looping = false;
296 return r;
299 looping = false;
301 } else if (!r) {
302 // we are not the default mime-source factory, so ask the
303 // default one for the mime-source, as this one will loop over
304 // all installed mime-source factories and ask these
305 r = static_cast<const QMimeSource *>(defaultFactory()->data(abs_name));
307 return r;
311 \fn void Q3MimeSourceFactory::setFilePath(const QStringList &path)
312 \fn void Q3MimeSourceFactory::setFilePath(const QString &path)
314 Sets the list of directories that will be searched when named data
315 is requested to those given in the string list \a path.
317 \sa filePath()
319 void Q3MimeSourceFactory::setFilePath(const QStringList& path)
321 d->path = path;
325 Returns the currently set search paths.
327 QStringList Q3MimeSourceFactory::filePath() const
329 return d->path;
333 Adds another search path, \a p to the existing search paths.
335 \sa setFilePath()
337 void Q3MimeSourceFactory::addFilePath(const QString& p)
339 d->path += p;
343 Sets the mime-type to be associated with the file name extension,
344 \a ext to \a mimetype. This determines the mime-type for files
345 found via the paths set by setFilePath().
347 void Q3MimeSourceFactory::setExtensionType(const QString& ext, const char* mimetype)
349 d->extensions.insert(ext, QLatin1String(mimetype));
353 Converts the absolute or relative data item name \a
354 abs_or_rel_name to an absolute name, interpreted within the
355 context (path) of the data item named \a context (this must be an
356 absolute name).
358 QString Q3MimeSourceFactory::makeAbsolute(const QString& abs_or_rel_name, const QString& context) const
360 if (context.isNull() ||
361 !(context[0] == QLatin1Char('/')
362 #ifdef Q_WS_WIN
363 || (context[0].isLetter() && context[1] == QLatin1Char(':'))
364 #endif
366 return abs_or_rel_name;
367 if (abs_or_rel_name.isEmpty())
368 return context;
369 QFileInfo c(context);
370 if (!c.isDir()) {
371 QFileInfo r(c.dir(true), abs_or_rel_name);
372 return r.absFilePath();
373 } else {
374 QDir d(context);
375 QFileInfo r(d, abs_or_rel_name);
376 return r.absFilePath();
381 \overload
382 A convenience function. See data(const QString& abs_name). The
383 file name is given in \a abs_or_rel_name and the path is in \a
384 context.
386 const QMimeSource* Q3MimeSourceFactory::data(const QString& abs_or_rel_name, const QString& context) const
388 const QMimeSource* r = data(makeAbsolute(abs_or_rel_name,context));
389 if (!r && !d->path.isEmpty())
390 r = data(abs_or_rel_name);
391 return r;
396 Sets \a text to be the data item associated with the absolute name
397 \a abs_name.
399 Equivalent to setData(abs_name, new Q3TextDrag(text)).
401 void Q3MimeSourceFactory::setText(const QString& abs_name, const QString& text)
403 setData(abs_name, new Q3TextDrag(text));
407 Sets \a image to be the data item associated with the absolute
408 name \a abs_name.
410 Equivalent to setData(abs_name, new Q3ImageDrag(image)).
412 void Q3MimeSourceFactory::setImage(const QString& abs_name, const QImage& image)
414 setData(abs_name, new Q3ImageDrag(image));
418 Sets \a pixmap to be the data item associated with the absolute
419 name \a abs_name.
421 void Q3MimeSourceFactory::setPixmap(const QString& abs_name, const QPixmap& pixmap)
423 setData(abs_name, new Q3ImageDrag(pixmap.convertToImage()));
427 Sets \a data to be the data item associated with
428 the absolute name \a abs_name. Note that the ownership of \a data is
429 transferred to the factory: do not delete or access the pointer after
430 passing it to this function.
432 Passing 0 for data removes previously stored data.
434 void Q3MimeSourceFactory::setData(const QString& abs_name, QMimeSource* data)
436 if (d->stored.contains(abs_name))
437 delete d->stored[abs_name];
438 d->stored.insert(abs_name,data);
443 Returns the application-wide default mime source factory. This
444 factory is used by rich text rendering classes such as
445 QSimpleRichText, QWhatsThis and QMessageBox to resolve named
446 references within rich text documents. It serves also as the
447 initial factory for the more complex render widgets, QTextEdit and
448 QTextBrowser.
450 \sa setDefaultFactory()
452 Q3MimeSourceFactory* Q3MimeSourceFactory::defaultFactory()
454 if (!defaultfactory)
456 defaultfactory = new Q3MimeSourceFactory();
457 qmime_cleanup_factory.set(&defaultfactory);
458 QTextImageHandler::externalLoader = richTextImageLoader;
460 return defaultfactory;
464 Sets the default \a factory, destroying any previously set mime
465 source provider. The ownership of the factory is transferred to
468 \sa defaultFactory()
470 void Q3MimeSourceFactory::setDefaultFactory(Q3MimeSourceFactory* factory)
472 if (!defaultfactory)
473 qmime_cleanup_factory.set(&defaultfactory);
474 else if (defaultfactory != factory)
475 delete defaultfactory;
476 defaultfactory = factory;
480 Sets the defaultFactory() to 0 and returns the previous one.
483 Q3MimeSourceFactory* Q3MimeSourceFactory::takeDefaultFactory()
485 Q3MimeSourceFactory *f = defaultfactory;
486 defaultfactory = 0;
487 return f;
491 Adds the Q3MimeSourceFactory \a f to the list of available
492 mimesource factories. If the defaultFactory() can't resolve a
493 data() it iterates over the list of installed mimesource factories
494 until the data can be resolved.
496 \sa removeFactory()
499 void Q3MimeSourceFactory::addFactory(Q3MimeSourceFactory *f)
501 Q3MimeSourceFactory::defaultFactory()->d->factories.append(f);
505 Removes the mimesource factory \a f from the list of available
506 mimesource factories.
508 \sa addFactory()
511 void Q3MimeSourceFactory::removeFactory(Q3MimeSourceFactory *f)
513 Q3MimeSourceFactory::defaultFactory()->d->factories.removeAll(f);
516 QPixmap qPixmapFromMimeSource(const QString &abs_name)
518 const QMimeSource *m = Q3MimeSourceFactory::defaultFactory()->data(abs_name);
519 if (!m) {
520 if (QFile::exists(abs_name))
521 return QPixmap(abs_name);
522 if (!abs_name.isEmpty())
523 qWarning("QPixmap::fromMimeSource: Cannot find pixmap \"%s\" in the mime source factory",
524 abs_name.latin1());
525 return QPixmap();
527 QPixmap pix;
528 Q3ImageDrag::decode(m, pix);
529 return pix;
532 QImage qImageFromMimeSource(const QString &abs_name)
534 const QMimeSource *m = Q3MimeSourceFactory::defaultFactory()->data(abs_name);
535 if (!m) {
536 qWarning("QImage::fromMimeSource: Cannot find image \"%s\" in the mime source factory", abs_name.latin1());
537 return QImage();
539 QImage img;
540 Q3ImageDrag::decode(m, img);
541 return img;
544 QT_END_NAMESPACE
546 #endif // QT_NO_MIMEFACTORY