kexi

kexiblobbuffer.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "kexiblobbuffer.h"
00021 
00022 #include <assert.h>
00023 
00024 #include <qfile.h>
00025 #include <qfileinfo.h>
00026 #include <qbuffer.h>
00027 
00028 #include <kdebug.h>
00029 #include <kstaticdeleter.h>
00030 #include <kimageio.h>
00031 
00032 #include <kexidb/connection.h>
00033 
00034 static KStaticDeleter<KexiBLOBBuffer> m_bufferDeleter;
00035 static KexiBLOBBuffer* m_buffer = 0;
00036 
00037 //-----------------
00038 
00039 class KexiBLOBBuffer::Private
00040 {
00041     public:
00042         Private()
00043          : maxId(0)
00044          , inMemoryItems(1009)
00045          , storedItems(1009)
00046          , itemsByURL(1009)
00047         {
00048         }
00049         Id_t maxId; 
00050 
00051         QIntDict<Item> inMemoryItems; 
00052         QIntDict<Item> storedItems; 
00053         QDict<Item> itemsByURL;
00054         QGuardedPtr<KexiDB::Connection> conn;
00055 };
00056 
00057 //-----------------
00058 
00059 KexiBLOBBuffer::Handle::Handle(Item* item)
00060  : m_item(item)
00061 {
00062     if (m_item)
00063         m_item->refs++;
00064 }
00065 
00066 KexiBLOBBuffer::Handle::Handle(const Handle& handle)
00067 {
00068     *this = handle;
00069 }
00070 
00071 KexiBLOBBuffer::Handle::Handle()
00072  : m_item(0)
00073 {
00074 }
00075 
00076 KexiBLOBBuffer::Handle::~Handle()
00077 {
00078     if (m_item) {
00079         m_item->refs--;
00080         if (m_item->refs<=0)
00081             KexiBLOBBuffer::self()->removeItem(m_item->id, m_item->stored);
00082     }
00083 }
00084 
00085 KexiBLOBBuffer::Handle& KexiBLOBBuffer::Handle::operator=(const Handle& handle)
00086 {
00087     m_item = handle.m_item;
00088     if (m_item)
00089         m_item->refs++;
00090     return *this;
00091 }
00092 
00093 void KexiBLOBBuffer::Handle::setStoredWidthID(KexiBLOBBuffer::Id_t id)
00094 {
00095     if (!m_item)
00096         return;
00097     if (m_item->stored) {
00098         kdWarning() << "KexiBLOBBuffer::Handle::setStoredWidthID(): object for id=" << id 
00099             << " is aleady stored" << endl;
00100         return;
00101     }
00102 
00103     KexiBLOBBuffer::self()->takeItem(m_item);
00104     m_item->id = id; //new id
00105     m_item->stored = true;
00108     KexiBLOBBuffer::self()->insertItem(m_item);
00109 }
00110 
00111 //-----------------
00112 
00113 KexiBLOBBuffer::Item::Item(const QByteArray& data, KexiBLOBBuffer::Id_t ident, bool _stored,
00114     const QString& _name, const QString& _caption, const QString& _mimeType, 
00115     Id_t _folderId, const QPixmap& pixmap)
00116  : name(_name), caption(_caption), mimeType(_mimeType), refs(0), 
00117  id(ident), folderId(_folderId), stored(_stored),
00118  m_pixmapLoaded(new bool(false)/*workaround for pixmap() const*/)
00119 {
00120     if (pixmap.isNull())
00121         m_pixmap = new QPixmap();
00122     else
00123         m_pixmap = new QPixmap(pixmap);
00124 
00125     if (data.isEmpty())
00126         m_data = new QByteArray();
00127     else
00128         m_data = new QByteArray(data);
00129 }
00130 
00131 KexiBLOBBuffer::Item::~Item()
00132 {
00133     kexipluginsdbg << "KexiBLOBBuffer::Item::~Item()" << endl;
00134     delete m_pixmap;
00135     m_pixmap = 0;
00136     delete m_data;
00137     m_data = 0;
00138     delete m_pixmapLoaded;
00139 }
00140 
00141 QPixmap KexiBLOBBuffer::Item::pixmap() const
00142 {
00143     if (!*m_pixmapLoaded && m_pixmap->isNull() && !m_data->isEmpty()) {
00144         QString type( KImageIO::typeForMime(mimeType) );
00145         if (!KImageIO::canRead( type ) || !m_pixmap->loadFromData(*m_data, type.latin1())) {
00147         }
00148         *m_pixmapLoaded = true;
00149     }
00150     return *m_pixmap;
00151 }
00152 
00153 QByteArray KexiBLOBBuffer::Item::data() const
00154 {
00155     if (!m_data->isEmpty())
00156         return *m_data;
00157 
00158     if (m_data->isEmpty() && m_pixmap->isNull())
00159         return QByteArray();
00160     
00161     if (m_data->isEmpty() && !m_pixmap->isNull()) {
00162         //convert pixmap to byte array
00163         //(do it only on demand)
00164         QBuffer buffer( *m_data );
00165         buffer.open( IO_WriteOnly );
00166         m_pixmap->save( &buffer, mimeType.isEmpty() ? (const char*)"PNG" : mimeType.latin1() );
00167     }
00168     return *m_data;
00169 }
00170 
00171 //-----------------
00172 
00173 KexiBLOBBuffer::KexiBLOBBuffer()
00174  : QObject()
00175  , d(new Private())
00176 {
00177     Q_ASSERT(!m_buffer);
00178     d->inMemoryItems.setAutoDelete(true);
00179     d->storedItems.setAutoDelete(true);
00180 }
00181 
00182 KexiBLOBBuffer::~KexiBLOBBuffer()
00183 {
00184     delete d;
00185 }
00186 
00187 KexiBLOBBuffer::Handle KexiBLOBBuffer::insertPixmap(const KURL& url)
00188 {
00189     if (url.isEmpty() )
00190         return KexiBLOBBuffer::Handle();
00191     if (!url.isValid()) {
00192         kexipluginswarn << "::insertPixmap: INVALID URL '" << url << "'" << endl;
00193         return KexiBLOBBuffer::Handle();
00194     }
00196     Item * item = d->itemsByURL.find(url.prettyURL());
00197     if (item)
00198         return KexiBLOBBuffer::Handle(item);
00199 
00200     QString fileName = url.isLocalFile() ? url.path() : url.prettyURL();
00202     QFile f(fileName);
00203     if (!f.open(IO_ReadOnly)) {
00205         return KexiBLOBBuffer::Handle();
00206     }
00207     QString mimeType( KImageIO::mimeType( fileName ) );
00208 
00209     QByteArray data( f.readAll() );
00210     if (f.status()!=IO_Ok) {
00212         return KexiBLOBBuffer::Handle();
00213     }
00214     QFileInfo fi(url.fileName());
00215     QString caption(fi.baseName().replace('_', " ").simplifyWhiteSpace());
00216 
00217     item = new Item(data, ++d->maxId, false, url.fileName(), caption, mimeType);
00218     insertItem(item);
00219 
00220     //cache
00221     item->prettyURL = url.prettyURL();
00222     d->itemsByURL.replace(url.prettyURL(), item);
00223     return KexiBLOBBuffer::Handle(item);
00224 }
00225 
00226 KexiBLOBBuffer::Handle KexiBLOBBuffer::insertObject(const QByteArray& data, 
00227     const QString& name, const QString& caption, const QString& mimeType, KexiBLOBBuffer::Id_t identifier)
00228 {
00229     KexiBLOBBuffer::Id_t newIdentifier;
00230     if (identifier>0)
00231         newIdentifier = identifier;
00232     else
00233         newIdentifier = ++d->maxId;
00234 
00235     Item *item = new Item(data, newIdentifier, identifier>0, name, caption, mimeType);
00236     insertItem( item );
00237     return KexiBLOBBuffer::Handle(item);
00238 }
00239 
00240 KexiBLOBBuffer::Handle KexiBLOBBuffer::insertPixmap(const QPixmap& pixmap)
00241 {
00242     if (pixmap.isNull())
00243         return KexiBLOBBuffer::Handle();
00244 
00245     Item * item = new Item(
00246         QByteArray(), //(pixmap will be converted to byte array on demand)
00247         ++d->maxId, 
00248         false, //not stored
00249         QString::null, 
00250         QString::null, 
00251         "image/png", 
00252         0, //folder id
00253         pixmap);
00254 
00255     insertItem(item);
00256     return KexiBLOBBuffer::Handle(item);
00257 }
00258 
00259 KexiBLOBBuffer::Handle KexiBLOBBuffer::objectForId(Id_t id, bool stored)
00260 {
00261     if (id<=0)
00262         return KexiBLOBBuffer::Handle();
00263     if (stored) {
00264         Item *item = d->storedItems.find(id);
00265         if (item || !d->conn)
00266             return KexiBLOBBuffer::Handle(item);
00267         //retrieve stored BLOB:
00268 
00269 //#if 0
00270         assert(d->conn);
00271         KexiDB::TableSchema *blobsTable = d->conn->tableSchema("kexi__blobs"); 
00272         if (!blobsTable) {
00274             return KexiBLOBBuffer::Handle();
00275         }
00276 /*      QStringList where;
00277         where << "o_id";
00278         KexiDB::PreparedStatement::Ptr st = d->conn->prepareStatement(
00279             KexiDB::PreparedStatement::SelectStatement, *blobsTable, where);*/
00281         KexiDB::QuerySchema schema;
00282         schema.addField( blobsTable->field("o_data") );
00283         schema.addField( blobsTable->field("o_name") );
00284         schema.addField( blobsTable->field("o_caption") );
00285         schema.addField( blobsTable->field("o_mime") );
00286         schema.addField( blobsTable->field("o_folder_id") );
00287         schema.addToWhereExpression(blobsTable->field("o_id"), QVariant((Q_LLONG)id));
00288 
00289         KexiDB::RowData rowData;
00290         tristate res = d->conn->querySingleRecord(
00291             schema,
00292 //          QString::fromLatin1("SELECT o_data, o_name, o_caption, o_mime FROM kexi__blobs where o_id=")
00293 //          +QString::number(id), 
00294             rowData); 
00295         if (res!=true || rowData.size()<4) {
00297             kdWarning() << "KexiBLOBBuffer::objectForId("<<id<<","<<stored
00298             <<"): res!=true || rowData.size()<4; res=="<<res<<" rowData.size()=="<<rowData.size()<< endl;
00299             return KexiBLOBBuffer::Handle();
00300         }
00301 
00302         item = new Item(
00303             rowData[0].toByteArray(),
00304             id, 
00305             true, //stored
00306             rowData[1].toString(),
00307             rowData[2].toString(),
00308             rowData[3].toString(),
00309             (Id_t)rowData[4].toInt() 
00310         );
00311 
00312         insertItem(item);
00313         return KexiBLOBBuffer::Handle(item);
00314 //#endif
00315     }
00316     else
00317         return KexiBLOBBuffer::Handle(d->inMemoryItems.find(id));
00318 }
00319 
00320 KexiBLOBBuffer::Handle KexiBLOBBuffer::objectForId(Id_t id)
00321 {
00322     KexiBLOBBuffer::Handle h(objectForId(id, false));
00323     if (h)
00324         return h;
00325     return objectForId(id, true/*stored*/);
00326 }
00327 
00328 void KexiBLOBBuffer::removeItem(Id_t id, bool stored)
00329 {
00330     Item *item;
00331     if (stored)
00332         item = d->storedItems.take(id);
00333     else
00334         item = d->inMemoryItems.take(id);
00335 
00336     if (item && !item->prettyURL.isEmpty()) {
00337         d->itemsByURL.remove(item->prettyURL);
00338     }
00339     delete item;
00340 }
00341 
00342 void KexiBLOBBuffer::takeItem(Item *item)
00343 {
00344     assert(item);
00345     if (item->stored)
00346         d->storedItems.take(item->id);
00347     else
00348         d->inMemoryItems.take(item->id);
00349 }
00350 
00351 void KexiBLOBBuffer::insertItem(Item *item)
00352 {
00353     assert(item);
00354     if (item->stored)
00355         d->storedItems.insert(item->id, item);
00356     else
00357         d->inMemoryItems.insert(item->id, item);
00358 }
00359 
00360 void KexiBLOBBuffer::setConnection(KexiDB::Connection *conn)
00361 {
00362     KexiBLOBBuffer::self()->d->conn = conn;
00363 }
00364 
00365 KexiBLOBBuffer* KexiBLOBBuffer::self()
00366 {
00367     if(!m_buffer) {
00368         m_bufferDeleter.setObject( m_buffer, new KexiBLOBBuffer() );
00369     }
00370     return m_buffer;
00371 }
00372 
00373 #include "kexiblobbuffer.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys