diff options
Diffstat (limited to 'src/kernel/qmime.cpp')
-rw-r--r-- | src/kernel/qmime.cpp | 618 |
1 files changed, 618 insertions, 0 deletions
diff --git a/src/kernel/qmime.cpp b/src/kernel/qmime.cpp new file mode 100644 index 000000000..0944bf7f6 --- /dev/null +++ b/src/kernel/qmime.cpp @@ -0,0 +1,618 @@ +/**************************************************************************** +** +** Implementation of MIME support +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qmime.h" + +#ifndef QT_NO_MIME + +#include "qmap.h" +#include "qstringlist.h" +#include "qfileinfo.h" +#include "qdir.h" +#include "qdragobject.h" +#include "qcleanuphandler.h" +#include "qapplication.h" // ### for now +#include "qclipboard.h" // ### for now + +/*! + \class TQMimeSource qmime.h + \brief The TQMimeSource class is an abstraction of objects which provide formatted data of a certain MIME type. + + \ingroup io + \ingroup draganddrop + \ingroup misc + + \link dnd.html Drag-and-drop\endlink and + \link TQClipboard clipboard\endlink use this abstraction. + + \sa \link http://www.isi.edu/in-notes/iana/assignments/media-types/ + IANA list of MIME media types\endlink +*/ + +static int qt_mime_serial_number = 0; +static TQMimeSourceFactory* defaultfactory = 0; +static TQSingleCleanupHandler<TQMimeSourceFactory> qmime_cleanup_factory; + +/*! + Constructs a mime source and assigns a globally unique serial + number to it. + + \sa serialNumber() +*/ + +TQMimeSource::TQMimeSource() +{ + ser_no = qt_mime_serial_number++; + cacheType = NoCache; +} + +/*! + \fn int TQMimeSource::serialNumber() const + + Returns the mime source's globally unique serial number. +*/ + + +void TQMimeSource::clearCache() +{ + if ( cacheType == Text ) { + delete cache.txt.str; + delete cache.txt.subtype; + cache.txt.str = 0; + cache.txt.subtype = 0; + } else if ( cacheType == Graphics ) { + delete cache.gfx.img; + delete cache.gfx.pix; + cache.gfx.img = 0; + cache.gfx.pix = 0; + } + cacheType = NoCache; +} + +/*! + Provided to ensure that subclasses destroy themselves correctly. +*/ +TQMimeSource::~TQMimeSource() +{ +#ifndef QT_NO_CLIPBOARD + extern void qt_clipboard_cleanup_mime_source(TQMimeSource *); + qt_clipboard_cleanup_mime_source(this); +#endif + clearCache(); +} + +/*! + \fn TQByteArray TQMimeSource::encodedData(const char*) const + + Returns the encoded data of this object in the specified MIME + format. + + Subclasses must reimplement this function. +*/ + + + +/*! + Returns TRUE if the object can provide the data in format \a + mimeType; otherwise returns FALSE. + + If you inherit from TQMimeSource, for consistency reasons it is + better to implement the more abstract canDecode() functions such + as TQTextDrag::canDecode() and TQImageDrag::canDecode(). +*/ +bool TQMimeSource::provides(const char* mimeType) const +{ + const char* fmt; + for (int i=0; (fmt = format(i)); i++) { + if ( !qstricmp(mimeType,fmt) ) + return TRUE; + } + return FALSE; +} + + +/*! + \fn const char * TQMimeSource::format(int i) const + + Returns the \a{i}-th supported MIME format, or 0. +*/ + + + +class TQMimeSourceFactoryData { +public: + TQMimeSourceFactoryData() : + last(0) + { + } + + ~TQMimeSourceFactoryData() + { + TQMap<TQString, TQMimeSource*>::Iterator it = stored.begin(); + while ( it != stored.end() ) { + delete *it; + ++it; + } + delete last; + } + + TQMap<TQString, TQMimeSource*> stored; + TQMap<TQString, TQString> extensions; + TQStringList path; + TQMimeSource* last; + TQPtrList<TQMimeSourceFactory> factories; +}; + + +/*! + \class TQMimeSourceFactory qmime.h + \brief The TQMimeSourceFactory class is an extensible provider of mime-typed data. + + \ingroup io + \ingroup environment + + A TQMimeSourceFactory provides an abstract interface to a + collection of information. Each piece of information is + represented by a TQMimeSource object which can be examined and + converted to concrete data types by functions such as + TQImageDrag::canDecode() and TQImageDrag::decode(). + + The base TQMimeSourceFactory can be used in two ways: as an + abstraction of a collection of files or as specifically stored + data. For it to access files, call setFilePath() before accessing + data. For stored data, call setData() for each item (there are + also convenience functions, e.g. setText(), setImage() and + setPixmap(), that simply call setData() with appropriate + parameters). + + The rich text widgets, TQTextEdit and TQTextBrowser, use + TQMimeSourceFactory to resolve references such as images or links + within rich text documents. They either access the default factory + (see \l{defaultFactory()}) or their own (see + \l{TQTextEdit::setMimeSourceFactory()}). Other classes that are + capable of displaying rich text (such as TQLabel, TQWhatsThis or + TQMessageBox) always use the default factory. + + A factory can also be used as a container to store data associated + with a name. This technique is useful whenever rich text contains + images that are stored in the program itself, not loaded from the + hard disk. Your program may, for example, define some image data + as: + \code + static const char* myimage_data[]={ + "...", + ... + "..."}; + \endcode + + To be able to use this image within some rich text, for example + inside a TQLabel, you must create a TQImage from the raw data and + insert it into the factory with a unique name: + \code + TQMimeSourceFactory::defaultFactory()->setImage( "myimage", TQImage(myimage_data) ); + \endcode + + Now you can create a rich text TQLabel with + + \code + TQLabel* label = new TQLabel( + "Rich text with embedded image:<img source=\"myimage\">" + "Isn't that <em>cute</em>?" ); + \endcode + + When no longer needed, you can clear the data from the factory: + + \code + delete label; + TQMimeSourceFactory::defaultFactory()->setData( "myimage", 0 ); + \endcode +*/ + + +/*! + Constructs a TQMimeSourceFactory that has no file path and no + stored content. +*/ +TQMimeSourceFactory::TQMimeSourceFactory() : + d(new TQMimeSourceFactoryData) +{ + // add some reasonable defaults + setExtensionType("htm", "text/html;charset=iso8859-1"); + setExtensionType("html", "text/html;charset=iso8859-1"); + setExtensionType("txt", "text/plain"); + setExtensionType("xml", "text/xml;charset=UTF-8"); + setExtensionType("jpg", "image/jpeg"); // support misspelled jpeg files +} + +/*! + Destroys the TQMimeSourceFactory, deleting all stored content. +*/ +TQMimeSourceFactory::~TQMimeSourceFactory() +{ + if ( defaultFactory() == this ) + defaultfactory = 0; + delete d; +} + +TQMimeSource* TQMimeSourceFactory::dataInternal(const TQString& abs_name, const TQMap<TQString, TQString> &extensions ) const +{ + TQMimeSource* r = 0; + TQFileInfo fi(abs_name); + if ( fi.isReadable() ) { + + // get the right mimetype + TQString e = fi.extension(FALSE); + TQCString mimetype = "application/octet-stream"; + const char* imgfmt; + if ( extensions.contains(e) ) + mimetype = extensions[e].latin1(); + else if ( ( imgfmt = TQImage::imageFormat( abs_name ) ) ) + mimetype = TQCString("image/")+TQCString(imgfmt).lower(); + + TQFile f(abs_name); + if ( f.open(IO_ReadOnly) && f.size() ) { + TQByteArray ba(f.size()); + f.readBlock(ba.data(), ba.size()); + TQStoredDrag* sr = new TQStoredDrag( mimetype ); + sr->setEncodedData( ba ); + delete d->last; + d->last = r = sr; + } + } + + // we didn't find the mime-source, so ask the default factory for + // the mime-source (this one will iterate over all installed ones) + // + // this looks dangerous, as this dataInternal() function will be + // called again when the default factory loops over all installed + // factories (including this), but the static bool looping in + // data() avoids endless recursions + if ( !r && this != defaultFactory() ) + r = (TQMimeSource*)defaultFactory()->data( abs_name ); + + return r; +} + + +/*! + Returns a reference to the data associated with \a abs_name. The + return value remains valid only until the next data() or setData() + call, so you should immediately decode the result. + + If there is no data associated with \a abs_name in the factory's + store, the factory tries to access the local filesystem. If \a + abs_name isn't an absolute file name, the factory will search for + it in all defined paths (see \l{setFilePath()}). + + The factory understands all the image formats supported by + TQImageIO. Any other mime types are determined by the file name + extension. The default settings are + \code + setExtensionType("html", "text/html;charset=iso8859-1"); + setExtensionType("htm", "text/html;charset=iso8859-1"); + setExtensionType("txt", "text/plain"); + setExtensionType("xml", "text/xml;charset=UTF-8"); + \endcode + The effect of these is that file names ending in "txt" will be + treated as text encoded in the local encoding; those ending in + "xml" will be treated as text encoded in Unicode UTF-8 encoding. + The text/html type is treated specially, since the encoding can be + specified in the html file itself. "html" or "htm" will be treated + as text encoded in the encoding specified by the html meta tag, if + none could be found, the charset of the mime type will be used. + The text subtype ("html", "plain", or "xml") does not affect the + factory, but users of the factory may behave differently. We + recommend creating "xml" files where practical. These files can be + viewed regardless of the runtime encoding and can encode any + Unicode characters without resorting to encoding definitions + inside the file. + + Any file data that is not recognized will be retrieved as a + TQMimeSource providing the "application/octet-stream" mime type, + meaning uninterpreted binary data. + + You can add further extensions or change existing ones with + subsequent calls to setExtensionType(). If the extension mechanism + is not sufficient for your problem domain, you can inherit + TQMimeSourceFactory and reimplement this function to perform some + more specialized mime-type detection. The same applies if you want + to use the mime source factory to access URL referenced data over + a network. +*/ +const TQMimeSource* TQMimeSourceFactory::data(const TQString& abs_name) const +{ + if ( d->stored.contains(abs_name) ) + return d->stored[abs_name]; + + TQMimeSource* r = 0; + TQStringList::Iterator it; + if ( abs_name[0] == '/' +#ifdef Q_WS_WIN + || ( abs_name[0] && abs_name[1] == ':' ) || abs_name.startsWith("\\\\") +#endif + ) + { + // handle absolute file names directly + r = dataInternal( abs_name, d->extensions); + } + else { // check list of paths + for ( it = d->path.begin(); !r && it != d->path.end(); ++it ) { + TQString filename = *it; + if ( filename[(int)filename.length()-1] != '/' ) + filename += '/'; + filename += abs_name; + r = dataInternal( filename, d->extensions ); + } + } + + static bool looping = FALSE; + if ( !r && this == defaultFactory() ) { + // we found no mime-source and we are the default factory, so + // we know all the other installed mime-source factories, so + // ask them + if ( !looping ) { + // to avoid endless recustions, don't enter the loop below + // if data() got called from within the loop below + looping = TRUE; + TQPtrListIterator<TQMimeSourceFactory> it( d->factories ); + TQMimeSourceFactory *f; + while ( ( f = it.current() ) ) { + ++it; + if ( f == this ) + continue; + r = (TQMimeSource*)f->data( abs_name ); + if ( r ) { + looping = FALSE; + return r; + } + } + looping = FALSE; + } + } else if ( !r ) { + // we are not the default mime-source factory, so ask the + // default one for the mime-source, as this one will loop over + // all installed mime-source factories and ask these + r = (TQMimeSource*)defaultFactory()->data( abs_name ); + } + + return r; +} + +/*! + Sets the list of directories that will be searched when named data + is requested to the those given in the string list \a path. + + \sa filePath() +*/ +void TQMimeSourceFactory::setFilePath( const TQStringList& path ) +{ + d->path = path; +} + +/*! + Returns the currently set search paths. +*/ +TQStringList TQMimeSourceFactory::filePath() const +{ + return d->path; +} + +/*! + Adds another search path, \a p to the existing search paths. + + \sa setFilePath() +*/ +void TQMimeSourceFactory::addFilePath( const TQString& p ) +{ + d->path += p; +} + +/*! + Sets the mime-type to be associated with the file name extension, + \a ext to \a mimetype. This determines the mime-type for files + found via the paths set by setFilePath(). +*/ +void TQMimeSourceFactory::setExtensionType( const TQString& ext, const char* mimetype ) +{ + d->extensions.replace(ext, mimetype); +} + +/*! + Converts the absolute or relative data item name \a + abs_or_rel_name to an absolute name, interpreted within the + context (path) of the data item named \a context (this must be an + absolute name). +*/ +TQString TQMimeSourceFactory::makeAbsolute(const TQString& abs_or_rel_name, const TQString& context) const +{ + if ( context.isNull() || + !(context[0] == '/' +#ifdef Q_WS_WIN + || ( context[0] && context[1] == ':') +#endif + )) + return abs_or_rel_name; + if ( abs_or_rel_name.isEmpty() ) + return context; + TQFileInfo c( context ); + if (!c.isDir()) { + TQFileInfo r( c.dir(TRUE), abs_or_rel_name ); + return r.absFilePath(); + } else { + TQDir d(context); + TQFileInfo r(d, abs_or_rel_name); + return r.absFilePath(); + } +} + +/*! + \overload + A convenience function. See data(const TQString& abs_name). The + file name is given in \a abs_or_rel_name and the path is in \a + context. +*/ +const TQMimeSource* TQMimeSourceFactory::data(const TQString& abs_or_rel_name, const TQString& context) const +{ + const TQMimeSource* r = data(makeAbsolute(abs_or_rel_name,context)); + if ( !r && !d->path.isEmpty() ) + r = data(abs_or_rel_name); + return r; +} + + +/*! + Sets \a text to be the data item associated with the absolute name + \a abs_name. + + Equivalent to setData(abs_name, new TQTextDrag(text)). +*/ +void TQMimeSourceFactory::setText( const TQString& abs_name, const TQString& text ) +{ + setData(abs_name, new TQTextDrag(text)); +} + +/*! + Sets \a image to be the data item associated with the absolute + name \a abs_name. + + Equivalent to setData(abs_name, new TQImageDrag(image)). +*/ +void TQMimeSourceFactory::setImage( const TQString& abs_name, const TQImage& image ) +{ + setData(abs_name, new TQImageDrag(image)); +} + +/*! + Sets \a pixmap to be the data item associated with the absolute + name \a abs_name. +*/ +void TQMimeSourceFactory::setPixmap( const TQString& abs_name, const TQPixmap& pixmap ) +{ + setData(abs_name, new TQImageDrag(pixmap.convertToImage())); +} + +/*! + Sets \a data to be the data item associated with + the absolute name \a abs_name. Note that the ownership of \a data is + transferred to the factory: do not delete or access the pointer after + passing it to this function. + + Passing 0 for data removes previously stored data. +*/ +void TQMimeSourceFactory::setData( const TQString& abs_name, TQMimeSource* data ) +{ + if ( d->stored.contains(abs_name) ) + delete d->stored[abs_name]; + d->stored.replace(abs_name,data); +} + + +/*! + Returns the application-wide default mime source factory. This + factory is used by rich text rendering classes such as + TQSimpleRichText, TQWhatsThis and TQMessageBox to resolve named + references within rich text documents. It serves also as the + initial factory for the more complex render widgets, TQTextEdit and + TQTextBrowser. + + \sa setDefaultFactory() +*/ +TQMimeSourceFactory* TQMimeSourceFactory::defaultFactory() +{ + if (!defaultfactory) + { + defaultfactory = new TQMimeSourceFactory(); + qmime_cleanup_factory.set( &defaultfactory ); + } + return defaultfactory; +} + +/*! + Sets the default \a factory, destroying any previously set mime + source provider. The ownership of the factory is transferred to + TQt. + + \sa defaultFactory() +*/ +void TQMimeSourceFactory::setDefaultFactory( TQMimeSourceFactory* factory) +{ + if ( !defaultfactory ) + qmime_cleanup_factory.set( &defaultfactory ); + else if ( defaultfactory != factory ) + delete defaultfactory; + defaultfactory = factory; +} + +/*! + Sets the defaultFactory() to 0 and returns the previous one. +*/ + +TQMimeSourceFactory* TQMimeSourceFactory::takeDefaultFactory() +{ + TQMimeSourceFactory *f = defaultfactory; + defaultfactory = 0; + return f; +} + +/*! + Adds the TQMimeSourceFactory \a f to the list of available + mimesource factories. If the defaultFactory() can't resolve a + data() it iterates over the list of installed mimesource factories + until the data can be resolved. + + \sa removeFactory(); +*/ + +void TQMimeSourceFactory::addFactory( TQMimeSourceFactory *f ) +{ + TQMimeSourceFactory::defaultFactory()->d->factories.append( f ); +} + +/*! + Removes the mimesource factory \a f from the list of available + mimesource factories. + + \sa addFactory(); +*/ + +void TQMimeSourceFactory::removeFactory( TQMimeSourceFactory *f ) +{ + TQMimeSourceFactory::defaultFactory()->d->factories.removeRef( f ); +} + +#endif // QT_NO_MIME |