00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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;
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))
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
00163
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
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(),
00247 ++d->maxId,
00248 false,
00249 QString::null,
00250 QString::null,
00251 "image/png",
00252 0,
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
00268
00269
00270 assert(d->conn);
00271 KexiDB::TableSchema *blobsTable = d->conn->tableSchema("kexi__blobs");
00272 if (!blobsTable) {
00274 return KexiBLOBBuffer::Handle();
00275 }
00276
00277
00278
00279
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
00293
00294 rowData);
00295 if (res!=true || rowData.size()<4) {
00297 kdWarning() << "KexiBLOBBuffer::objectForId("<<id<<","<<stored
00298 <<"): res!=true || rowData.size()<4; res=="<<res.toString()<<" rowData.size()=="<<rowData.size()<< endl;
00299 return KexiBLOBBuffer::Handle();
00300 }
00301
00302 item = new Item(
00303 rowData[0].toByteArray(),
00304 id,
00305 true,
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
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);
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"