kexi

kexiblobbuffer.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "kexiblobbuffer.h"
21
22#include <assert.h>
23
24#include <tqfile.h>
25#include <tqfileinfo.h>
26#include <tqbuffer.h>
27
28#include <kdebug.h>
29#include <kstaticdeleter.h>
30#include <kimageio.h>
31
32#include <kexidb/connection.h>
33
34static KStaticDeleter<KexiBLOBBuffer> m_bufferDeleter;
35static KexiBLOBBuffer* m_buffer = 0;
36
37//-----------------
38
39class KexiBLOBBuffer::Private
40{
41 public:
42 Private()
43 : maxId(0)
44 , inMemoryItems(1009)
45 , storedItems(1009)
46 , itemsByURL(1009)
47 {
48 }
49 Id_t maxId;
51 TQIntDict<Item> inMemoryItems;
52 TQIntDict<Item> storedItems;
53 TQDict<Item> itemsByURL;
54 TQGuardedPtr<KexiDB::Connection> conn;
55};
56
57//-----------------
58
60 : m_item(item)
61{
62 if (m_item)
63 m_item->refs++;
64}
65
67{
68 *this = handle;
69}
70
72 : m_item(0)
73{
74}
75
76KexiBLOBBuffer::Handle::~Handle()
77{
78 if (m_item) {
79 m_item->refs--;
80 if (m_item->refs<=0)
81 KexiBLOBBuffer::self()->removeItem(m_item->id, m_item->stored);
82 }
83}
84
85KexiBLOBBuffer::Handle& KexiBLOBBuffer::Handle::operator=(const Handle& handle)
86{
87 m_item = handle.m_item;
88 if (m_item)
89 m_item->refs++;
90 return *this;
91}
92
94{
95 if (!m_item)
96 return;
97 if (m_item->stored) {
98 kdWarning() << "KexiBLOBBuffer::Handle::setStoredWidthID(): object for id=" << id
99 << " is aleady stored" << endl;
100 return;
101 }
102
104 m_item->id = id; //new id
105 m_item->stored = true;
109}
110
111//-----------------
112
113KexiBLOBBuffer::Item::Item(const TQByteArray& data, KexiBLOBBuffer::Id_t ident, bool _stored,
114 const TQString& _name, const TQString& _caption, const TQString& _mimeType,
115 Id_t _folderId, const TQPixmap& pixmap)
116 : name(_name), caption(_caption), mimeType(_mimeType), refs(0),
117 id(ident), folderId(_folderId), stored(_stored),
118 m_pixmapLoaded(new bool(false)/*workaround for pixmap() const*/)
119{
120 if (pixmap.isNull())
121 m_pixmap = new TQPixmap();
122 else
123 m_pixmap = new TQPixmap(pixmap);
124
125 if (data.isEmpty())
126 m_data = new TQByteArray();
127 else
128 m_data = new TQByteArray(data);
129}
130
131KexiBLOBBuffer::Item::~Item()
132{
133 kexipluginsdbg << "KexiBLOBBuffer::Item::~Item()" << endl;
134 delete m_pixmap;
135 m_pixmap = 0;
136 delete m_data;
137 m_data = 0;
138 delete m_pixmapLoaded;
139}
140
141TQPixmap KexiBLOBBuffer::Item::pixmap() const
142{
143 if (!*m_pixmapLoaded && m_pixmap->isNull() && !m_data->isEmpty()) {
144 TQString type( KImageIO::typeForMime(mimeType) );
145 if (!KImageIO::canRead( type ) || !m_pixmap->loadFromData(*m_data, type.latin1())) {
147 }
148 *m_pixmapLoaded = true;
149 }
150 return *m_pixmap;
151}
152
153TQByteArray KexiBLOBBuffer::Item::data() const
154{
155 if (!m_data->isEmpty())
156 return *m_data;
157
158 if (m_data->isEmpty() && m_pixmap->isNull())
159 return TQByteArray();
160
161 if (m_data->isEmpty() && !m_pixmap->isNull()) {
162 //convert pixmap to byte array
163 //(do it only on demand)
164 TQBuffer buffer( *m_data );
165 buffer.open( IO_WriteOnly );
166 m_pixmap->save( &buffer, mimeType.isEmpty() ? (const char*)"PNG" : mimeType.latin1() );
167 }
168 return *m_data;
169}
170
171//-----------------
172
173KexiBLOBBuffer::KexiBLOBBuffer()
174 : TQObject()
175 , d(new Private())
176{
177 Q_ASSERT(!m_buffer);
178 d->inMemoryItems.setAutoDelete(true);
179 d->storedItems.setAutoDelete(true);
180}
181
182KexiBLOBBuffer::~KexiBLOBBuffer()
183{
184 delete d;
185}
186
188{
189 if (url.isEmpty() )
190 return KexiBLOBBuffer::Handle();
191 if (!url.isValid()) {
192 kexipluginswarn << "::insertPixmap: INVALID URL '" << url << "'" << endl;
193 return KexiBLOBBuffer::Handle();
194 }
196 Item * item = d->itemsByURL.find(url.prettyURL());
197 if (item)
198 return KexiBLOBBuffer::Handle(item);
199
200 TQString fileName = url.isLocalFile() ? url.path() : url.prettyURL();
202 TQFile f(fileName);
203 if (!f.open(IO_ReadOnly)) {
205 return KexiBLOBBuffer::Handle();
206 }
207 TQString mimeType( KImageIO::mimeType( fileName ) );
208
209 TQByteArray data( f.readAll() );
210 if (f.status()!=IO_Ok) {
212 return KexiBLOBBuffer::Handle();
213 }
214 TQFileInfo fi(url.fileName());
215 TQString caption(fi.baseName().replace('_', " ").simplifyWhiteSpace());
216
217 item = new Item(data, ++d->maxId, false, url.fileName(), caption, mimeType);
218 insertItem(item);
219
220 //cache
221 item->prettyURL = url.prettyURL();
222 d->itemsByURL.replace(url.prettyURL(), item);
223 return KexiBLOBBuffer::Handle(item);
224}
225
227 const TQString& name, const TQString& caption, const TQString& mimeType, KexiBLOBBuffer::Id_t identifier)
228{
229 KexiBLOBBuffer::Id_t newIdentifier;
230 if (identifier>0)
231 newIdentifier = identifier;
232 else
233 newIdentifier = ++d->maxId;
234
235 Item *item = new Item(data, newIdentifier, identifier>0, name, caption, mimeType);
236 insertItem( item );
237 return KexiBLOBBuffer::Handle(item);
238}
239
241{
242 if (pixmap.isNull())
243 return KexiBLOBBuffer::Handle();
244
245 Item * item = new Item(
246 TQByteArray(), //(pixmap will be converted to byte array on demand)
247 ++d->maxId,
248 false, //not stored
249 TQString(),
250 TQString(),
251 "image/png",
252 0, //folder id
253 pixmap);
254
255 insertItem(item);
256 return KexiBLOBBuffer::Handle(item);
257}
258
260{
261 if (id<=0)
262 return KexiBLOBBuffer::Handle();
263 if (stored) {
264 Item *item = d->storedItems.find(id);
265 if (item || !d->conn)
266 return KexiBLOBBuffer::Handle(item);
267 //retrieve stored BLOB:
268
269//#if 0
270 assert(d->conn);
271 KexiDB::TableSchema *blobsTable = d->conn->tableSchema("kexi__blobs");
272 if (!blobsTable) {
274 return KexiBLOBBuffer::Handle();
275 }
276/* TQStringList where;
277 where << "o_id";
278 KexiDB::PreparedStatement::Ptr st = d->conn->prepareStatement(
279 KexiDB::PreparedStatement::SelectStatement, *blobsTable, where);*/
281 KexiDB::QuerySchema schema;
282 schema.addField( blobsTable->field("o_data") );
283 schema.addField( blobsTable->field("o_name") );
284 schema.addField( blobsTable->field("o_caption") );
285 schema.addField( blobsTable->field("o_mime") );
286 schema.addField( blobsTable->field("o_folder_id") );
287 schema.addToWhereExpression(blobsTable->field("o_id"), TQVariant((TQ_LLONG)id));
288
289 KexiDB::RowData rowData;
290 tristate res = d->conn->querySingleRecord(
291 schema,
292// TQString::fromLatin1("SELECT o_data, o_name, o_caption, o_mime FROM kexi__blobs where o_id=")
293// +TQString::number(id),
294 rowData);
295 if (res!=true || rowData.size()<4) {
297 kdWarning() << "KexiBLOBBuffer::objectForId("<<id<<","<<stored
298 <<"): res!=true || rowData.size()<4; res=="<<res.toString()<<" rowData.size()=="<<rowData.size()<< endl;
299 return KexiBLOBBuffer::Handle();
300 }
301
302 item = new Item(
303 rowData[0].toByteArray(),
304 id,
305 true, //stored
306 rowData[1].toString(),
307 rowData[2].toString(),
308 rowData[3].toString(),
309 (Id_t)rowData[4].toInt()
310 );
311
312 insertItem(item);
313 return KexiBLOBBuffer::Handle(item);
314//#endif
315 }
316 else
317 return KexiBLOBBuffer::Handle(d->inMemoryItems.find(id));
318}
319
321{
323 if (h)
324 return h;
325 return objectForId(id, true/*stored*/);
326}
327
328void KexiBLOBBuffer::removeItem(Id_t id, bool stored)
329{
330 Item *item;
331 if (stored)
332 item = d->storedItems.take(id);
333 else
334 item = d->inMemoryItems.take(id);
335
336 if (item && !item->prettyURL.isEmpty()) {
337 d->itemsByURL.remove(item->prettyURL);
338 }
339 delete item;
340}
341
343{
344 assert(item);
345 if (item->stored)
346 d->storedItems.take(item->id);
347 else
348 d->inMemoryItems.take(item->id);
349}
350
352{
353 assert(item);
354 if (item->stored)
355 d->storedItems.insert(item->id, item);
356 else
357 d->inMemoryItems.insert(item->id, item);
358}
359
360void KexiBLOBBuffer::setConnection(KexiDB::Connection *conn)
361{
362 KexiBLOBBuffer::self()->d->conn = conn;
363}
364
365KexiBLOBBuffer* KexiBLOBBuffer::self()
366{
367 if(!m_buffer) {
368 m_bufferDeleter.setObject( m_buffer, new KexiBLOBBuffer() );
369 }
370 return m_buffer;
371}
372
373#include "kexiblobbuffer.moc"
Object handle used by KexiBLOBBuffer.
void setStoredWidthID(Id_t id)
Application-wide buffer for local BLOB data like pixmaps.
long Id_t
long integer for unique identifying blobs
Handle insertObject(const TQByteArray &data, const TQString &name, const TQString &caption, const TQString &mimeType, Id_t identifier=0)
Handle objectForId(Id_t id, bool stored)
void insertItem(Item *item)
Handle insertPixmap(const KURL &url)
static KexiBLOBBuffer * self()
Access to KexiBLOBBuffer singleton.
void removeItem(Id_t id, bool stored)
void takeItem(Item *item)
Provides database connection, allowing queries and data modification.
Definition connection.h:62
Field * field(uint id)
Definition fieldlist.h:76
KexiDB::QuerySchema provides information about database query.
FieldList & addField(Field *field, bool visible=true)
void addToWhereExpression(KexiDB::Field *field, const TQVariant &value, int relation='=')
3-state logical type with three values: true, false and cancelled and convenient operators.
Definition tristate.h:100
TQString toString() const
Definition tristate.h:166
TQValueVector< TQVariant > RowData
structure for storing single record with type information
Definition connection.h:47