summaryrefslogtreecommitdiffstats
path: root/kexi/core/kexiblobbuffer.h
blob: 73c54549eb19357cb3879f854fddb4f56eb78f43 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/* This file is part of the KDE project
   Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#ifndef KEXIBLOBBUFFER_H
#define KEXIBLOBBUFFER_H

#include <tqobject.h>
#include <tqintdict.h>
#include <tqdict.h>
#include <tqpixmap.h>

#include <kurl.h>

namespace KexiDB
{
	class Connection;
}

//! Application-wide buffer for local BLOB data like pixmaps.
/*! For now only pixmaps are supported 
 @todo support any KPart-compatible objects and more...

 Use this class by acessing to its singleton: KexiBLOBBuffer::self().

 This class is used for buffering BLOB data, 
 to avoid duplicating object's data in memory and a need for loading (decoding) 
 the same object many times. 
 The data is always local, what means database storage is not employed here.
 
 Each BLOB instance is identified by an unsigned integer number (Id_t type), 
 uniquely generated on BLOB loading. Each BLOB can have assigned source url 
 it has been loaded from (the url can be empty though, e.g. for data coming from clipboard). 

 References to KexiBLOBBuffer are counted, so when last reference is lost, data is freed
 and the integer identifier is no longer pointing any valid data.
 KexiBLOBBuffer::Handle is value-based class that describes handle based in an identifier.
 Objects of this class are obtained e.g. from insertPixmap() method.

 There are two kinds of identifiers:
 - integers assigned for BLOBs already saved to a db backend, 
    when KexiBLOBBuffer::Handle::stored() is true
 - temporary integers assigned for new BLOBs not yet saved to a db backend, 
    when KexiBLOBBuffer::Handle::stored() is false
 KexiBLOBBuffer::Handle::setStoredWidthID() can be used to switch from unstored to stored state.
 Among others, the state has effect on saving forms: only unstored BLOBs will be saved back 
 to the database; when a BLOB needs to be removed, only it will be physically removed only if it was stored.

 KexiBLOBBuffer is also useful for two more reasons:
 - Property editor's item for "image" property displays a preview of pixmap contents.
   Without buffering, it would be needed to load pixmap data again: what if the file
   it is loaded from is located remote and connection is slow? Memory would be also unnecessary doubled.
 - Undo/Redo framework requires to store previous property values. Having a reference defined 
   by a single interger, memory can be handled more effectively. 

 Example use cases:
 A large pixmap file "abc.jpg" is loaded as TQByteArray <b>once</b> and buffered:
 integer identifier is returned.
 Then, multiple image widgets are using "abc.jpg" for displaying.
 Duplicating an image widget means only duplicating it's properties 
 like position and BLOB's id: BLOB itself (data of "abc.jpg") is not duplicated.
 Creating a new image widget and assiging the same "abc.jpg" pixmap, means only 
 referencing KexiBLOBBuffer using the same identifier.
*/
class KEXICORE_EXPORT KexiBLOBBuffer : public TQObject
{
	Q_OBJECT
  

	private:
		class Item;
	public:
		//! long integer for unique identifying blobs
//! @todo TQt4: will be changed
		typedef long Id_t;

		//! Access to KexiBLOBBuffer singleton
		static KexiBLOBBuffer* self();

		static void setConnection(KexiDB::Connection *conn);

		//! Object handle used by KexiBLOBBuffer
		class KEXICORE_EXPORT Handle {
			public:
				//! Constructs a null handle. 
				//! Null handles have empty pixap and data members, id == 0 and cast to boolean false.
				Handle();

				//! Constructs a copy of \a handle.
				Handle(const Handle& handle);

				~Handle();

				Id_t id() const { return m_item ? m_item->id : 0; }

				/*! \return true if this BLOB data pointed by this handle is stored at the db backend
				 or false if it is kept in memory. Null handles return false. */
				bool stored() const { return m_item ? m_item->stored : false; }

				//! \return true if this is null handle (i.e. one not pointing to any data)
				operator bool() const { return m_item; }

				Handle& operator=(const Handle& handle);

				TQByteArray data() const { return m_item ? m_item->data() : TQByteArray(); }

				TQPixmap pixmap() const { return m_item ? m_item->pixmap() : TQPixmap(); }

				/*! Sets "stored" flag to true by setting non-temporary identifier.
				 Only call this method for unstored (in memory) BLOBs */
				void setStoredWidthID(Id_t id);

				TQString originalFileName() const { return m_item ? m_item->name: TQString(); }

				TQString mimeType() const { return m_item ? m_item->mimeType : TQString(); }

				Id_t folderId() const { return m_item ? m_item->folderId : 0; }

			protected:
				//! Constructs a handle based on \a item. Null handle is constructed for null \a item.
				Handle(Item* item);
			private:
				Item* m_item;
			friend class KexiBLOBBuffer;
		};

		//! @internal
		KexiBLOBBuffer();

		~KexiBLOBBuffer();

		/*! Inserts a new pixmap loaded from a file at \a url. 
		 If the same file has already been loaded before, it can be found in cache 
		 and returned instantly. It is assumed that the BLOB is unstored, because it is loaded from 
		 external source, so stored() will be equal to false for returned handle.
		 \return handle to the pixmap data or a null handle if such pixmap could not be loaded. */
		Handle insertPixmap(const KURL& url);

		/*! Inserts a new BLOB data. 
		 @param data The data for BLOB object.
		 @param name The name for the object, usually a file name or empty
		 @param caption The more friendly than name, can be based on file name or empty or
		        defined by a user (this case is not yet used)
		 @param mimeType The mimeType for the object for easier and mor accurate decoding.
		 @param identifier Object's identifier. If positive, the "stored" flag for the data 
		 will be set to true with \a identifer, otherwise (the default) the BLOB data will 
		 have "stored" flag set to false, and a new temporary identifier will be assigned. */
		Handle insertObject(const TQByteArray& data, const TQString& name, 
			const TQString& caption, const TQString& mimeType, Id_t identifier = 0);

		/*! Inserts a new pixmap available in memory, e.g. coming from clipboard. */
		Handle insertPixmap(const TQPixmap& pixmap);

		/*! \return an object for a given \a id. If \a stored is true, stored BLOBs buffer 
		 is browsed, otherwise unstored (in memory) BLOBs buffer is browsed.
		 If no object is cached for this id, null handle is returned. */
		Handle objectForId(Id_t id, bool stored);

		/*! \return an object for a given \a id. First, unstored object is checked, then unstored, 
		 if stored was not found. */
		Handle objectForId(Id_t id);

	protected:
		/*! Removes an object for a given \a id. If \a stored is true, stored BLOB is removed,
		 otherwise unstored (in memory) BLOB is removed. */
		void removeItem(Id_t id, bool stored);

		/*! Takes an object for a \a item out of the buffer. */
		void takeItem(Item* item);

		/*! Inserts an object for a given \a id into the buffer. */
		void insertItem(Item* item);

	private:
		class KEXICORE_EXPORT Item {
			public:
				Item(const TQByteArray& data, Id_t ident,
					bool stored,
					const TQString& name = TQString(),
					const TQString& caption = TQString(),
					const TQString& mimeType = TQString(),
					Id_t folderId = 0,
					const TQPixmap& pixmap = TQPixmap());
				~Item();
				TQPixmap pixmap() const;
				TQByteArray data() const;
//				KexiBLOBBuffer* buf;
//				KURL url;
				TQString name;
				TQString caption; //!< @todo for future use within image gallery
				TQString mimeType;
				uint refs;
				Id_t id;
				Id_t folderId;
				bool stored : 1;
				TQString prettyURL; //!< helper
			private:
				TQByteArray *m_data;
				TQPixmap *m_pixmap;
				bool *m_pixmapLoaded; //!< *m_pixmapLoaded will be set in Info::pixmap(), 
				                      //!< to avoid multiple pixmap decoding when it previously failed
			friend class KexiBLOBBuffer;
		};
		class Private;
		Private *d;
		friend class Handle;
};

#endif