source: trunk/src/qt3support/other/q3mimefactory.cpp@ 104

Last change on this file since 104 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 18.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the Qt3Support module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "q3mimefactory.h"
43
44#ifndef QT_NO_MIMEFACTORY
45
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"
56
57QT_BEGIN_NAMESPACE
58
59static Q3MimeSourceFactory* defaultfactory = 0;
60static Q3SingleCleanupHandler<Q3MimeSourceFactory> qmime_cleanup_factory;
61
62class Q3MimeSourceFactoryData {
63public:
64 Q3MimeSourceFactoryData() :
65 last(0)
66 {
67 }
68
69 ~Q3MimeSourceFactoryData()
70 {
71 QMap<QString, QMimeSource*>::Iterator it = stored.begin();
72 while (it != stored.end()) {
73 delete *it;
74 ++it;
75 }
76 delete last;
77 }
78
79 QMap<QString, QMimeSource*> stored;
80 QMap<QString, QString> extensions;
81 QStringList path;
82 QMimeSource* last;
83 QList<Q3MimeSourceFactory*> factories;
84};
85
86static QImage richTextImageLoader(const QString &name, const QString &context)
87{
88 QImage img;
89
90 const QMimeSource *src = Q3MimeSourceFactory::defaultFactory()->data(name, context);
91 if (src && Q3ImageDrag::decode(src, img))
92 return img;
93
94 return QImage();
95}
96
97/*!
98 \class Q3MimeSourceFactory
99 \brief The Q3MimeSourceFactory class is an extensible provider of mime-typed data.
100
101 \compat
102
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().
108
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).
116
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.
123
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
128 as:
129 \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 0
130
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
135
136 Now you can create a rich text QLabel with
137
138 \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 2
139
140 When no longer needed, you can clear the data from the factory:
141
142 \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 3
143*/
144
145
146/*!
147 Constructs a Q3MimeSourceFactory that has no file path and no
148 stored content.
149*/
150Q3MimeSourceFactory::Q3MimeSourceFactory() :
151 d(new Q3MimeSourceFactoryData)
152{
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
160}
161
162/*!
163 Destroys the Q3MimeSourceFactory, deleting all stored content.
164*/
165Q3MimeSourceFactory::~Q3MimeSourceFactory()
166{
167 if (defaultFactory() == this)
168 defaultfactory = 0;
169 delete d;
170}
171
172QMimeSource* Q3MimeSourceFactory::dataInternal(const QString& abs_name, const QMap<QString, QString> &extensions) const
173{
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";
185
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;
195 }
196 }
197
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)
200 //
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);
207
208 return r;
209}
210
211
212/*!
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.
216
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()}).
221
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.
239
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.
243
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.
251*/
252const QMimeSource *Q3MimeSourceFactory::data(const QString& abs_name) const
253{
254 if (d->stored.contains(abs_name))
255 return d->stored[abs_name];
256
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
265 )
266 {
267 // handle absolute file names directly
268 r = dataInternal(abs_name, d->extensions);
269 }
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);
277 }
278 }
279
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;
297 }
298 }
299 looping = false;
300 }
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));
306 }
307 return r;
308}
309
310/*!
311 \fn void Q3MimeSourceFactory::setFilePath(const QStringList &path)
312 \fn void Q3MimeSourceFactory::setFilePath(const QString &path)
313
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.
316
317 \sa filePath()
318*/
319void Q3MimeSourceFactory::setFilePath(const QStringList& path)
320{
321 d->path = path;
322}
323
324/*!
325 Returns the currently set search paths.
326*/
327QStringList Q3MimeSourceFactory::filePath() const
328{
329 return d->path;
330}
331
332/*!
333 Adds another search path, \a p to the existing search paths.
334
335 \sa setFilePath()
336*/
337void Q3MimeSourceFactory::addFilePath(const QString& p)
338{
339 d->path += p;
340}
341
342/*!
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().
346*/
347void Q3MimeSourceFactory::setExtensionType(const QString& ext, const char* mimetype)
348{
349 d->extensions.insert(ext, QLatin1String(mimetype));
350}
351
352/*!
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).
357*/
358QString Q3MimeSourceFactory::makeAbsolute(const QString& abs_or_rel_name, const QString& context) const
359{
360 if (context.isNull() ||
361 !(context[0] == QLatin1Char('/')
362#ifdef Q_WS_WIN
363 || (context[0].isLetter() && context[1] == QLatin1Char(':'))
364#endif
365 ))
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();
377 }
378}
379
380/*!
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.
385*/
386const QMimeSource* Q3MimeSourceFactory::data(const QString& abs_or_rel_name, const QString& context) const
387{
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;
392}
393
394
395/*!
396 Sets \a text to be the data item associated with the absolute name
397 \a abs_name.
398
399 Equivalent to setData(abs_name, new Q3TextDrag(text)).
400*/
401void Q3MimeSourceFactory::setText(const QString& abs_name, const QString& text)
402{
403 setData(abs_name, new Q3TextDrag(text));
404}
405
406/*!
407 Sets \a image to be the data item associated with the absolute
408 name \a abs_name.
409
410 Equivalent to setData(abs_name, new Q3ImageDrag(image)).
411*/
412void Q3MimeSourceFactory::setImage(const QString& abs_name, const QImage& image)
413{
414 setData(abs_name, new Q3ImageDrag(image));
415}
416
417/*!
418 Sets \a pixmap to be the data item associated with the absolute
419 name \a abs_name.
420*/
421void Q3MimeSourceFactory::setPixmap(const QString& abs_name, const QPixmap& pixmap)
422{
423 setData(abs_name, new Q3ImageDrag(pixmap.convertToImage()));
424}
425
426/*!
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.
431
432 Passing 0 for data removes previously stored data.
433*/
434void Q3MimeSourceFactory::setData(const QString& abs_name, QMimeSource* data)
435{
436 if (d->stored.contains(abs_name))
437 delete d->stored[abs_name];
438 d->stored.insert(abs_name,data);
439}
440
441
442/*!
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.
449
450 \sa setDefaultFactory()
451*/
452Q3MimeSourceFactory* Q3MimeSourceFactory::defaultFactory()
453{
454 if (!defaultfactory)
455 {
456 defaultfactory = new Q3MimeSourceFactory();
457 qmime_cleanup_factory.set(&defaultfactory);
458 QTextImageHandler::externalLoader = richTextImageLoader;
459 }
460 return defaultfactory;
461}
462
463/*!
464 Sets the default \a factory, destroying any previously set mime
465 source provider. The ownership of the factory is transferred to
466 Qt.
467
468 \sa defaultFactory()
469*/
470void Q3MimeSourceFactory::setDefaultFactory(Q3MimeSourceFactory* factory)
471{
472 if (!defaultfactory)
473 qmime_cleanup_factory.set(&defaultfactory);
474 else if (defaultfactory != factory)
475 delete defaultfactory;
476 defaultfactory = factory;
477}
478
479/*!
480 Sets the defaultFactory() to 0 and returns the previous one.
481*/
482
483Q3MimeSourceFactory* Q3MimeSourceFactory::takeDefaultFactory()
484{
485 Q3MimeSourceFactory *f = defaultfactory;
486 defaultfactory = 0;
487 return f;
488}
489
490/*!
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.
495
496 \sa removeFactory()
497*/
498
499void Q3MimeSourceFactory::addFactory(Q3MimeSourceFactory *f)
500{
501 Q3MimeSourceFactory::defaultFactory()->d->factories.append(f);
502}
503
504/*!
505 Removes the mimesource factory \a f from the list of available
506 mimesource factories.
507
508 \sa addFactory()
509*/
510
511void Q3MimeSourceFactory::removeFactory(Q3MimeSourceFactory *f)
512{
513 Q3MimeSourceFactory::defaultFactory()->d->factories.removeAll(f);
514}
515
516QPixmap qPixmapFromMimeSource(const QString &abs_name)
517{
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();
526 }
527 QPixmap pix;
528 Q3ImageDrag::decode(m, pix);
529 return pix;
530}
531
532QImage qImageFromMimeSource(const QString &abs_name)
533{
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();
538 }
539 QImage img;
540 Q3ImageDrag::decode(m, img);
541 return img;
542}
543
544QT_END_NAMESPACE
545
546#endif // QT_NO_MIMEFACTORY
Note: See TracBrowser for help on using the repository browser.