ldifvcardcreator.cpp
1/*
2 This file is part of KAddressBook.
3 Copyright (C) 2003 Helge Deller <deller@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 version 2 License as published by the Free Software Foundation.
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/*
21 * - ldifvcardthumbnail -
22 *
23 * tdeioslave which generates tumbnails for vCard and LDIF files.
24 * The thumbnails are used e.g. by Konqueror or in the file selection
25 * dialog.
26 *
27 */
28
29#include <tqdatetime.h>
30#include <tqfile.h>
31#include <tqpixmap.h>
32#include <tqimage.h>
33#include <tqpainter.h>
34#include <tqtextstream.h>
35
36#include <kdebug.h>
37#include <tdeglobal.h>
38#include <tdelocale.h>
39#include <tdeabc/ldifconverter.h>
40#include <tdeabc/vcardconverter.h>
41#include <kpixmapsplitter.h>
42#include <tdestandarddirs.h>
43#include <tdeglobalsettings.h>
44
45#include "ldifvcardcreator.h"
46
47extern "C"
48{
49 ThumbCreator *new_creator()
50 {
51 TDEGlobal::locale()->insertCatalogue( "kaddressbook" );
52 return new VCard_LDIFCreator;
53 }
54}
55
56VCard_LDIFCreator::VCard_LDIFCreator()
57 : mSplitter( 0 )
58{
59}
60
61VCard_LDIFCreator::~VCard_LDIFCreator()
62{
63 delete mSplitter;
64}
65
66
67bool VCard_LDIFCreator::readContents( const TQString &path )
68{
69 // read file contents
70 TQFile file( path );
71 if ( !file.open( IO_ReadOnly ) )
72 return false;
73
74 TQString info;
75 text.truncate(0);
76
77 // read the file
78#if defined(KABC_VCARD_ENCODING_FIX)
79 const TQByteArray data = file.readAll();
80 const TQString contents( data );
81 const TQCString contentsRaw( data.data(), data.size() );
82#else
83 TQTextStream s( &file );
84 s.setEncoding( TQTextStream::UnicodeUTF8 );
85 TQString contents = s.read();
86#endif
87 file.close();
88
89 // convert the file contents to a TDEABC::Addressee address
90 TDEABC::AddresseeList addrList;
91 TDEABC::Addressee addr;
92 TDEABC::VCardConverter converter;
93
94#if defined(KABC_VCARD_ENCODING_FIX)
95 addrList = converter.parseVCardsRaw( contentsRaw );
96#else
97 addrList = converter.parseVCards( contents );
98#endif
99 if ( addrList.count() == 0 )
100 if ( !TDEABC::LDIFConverter::LDIFToAddressee( contents, addrList ) )
101 return false;
102 if ( addrList.count()>1 ) {
103 // create an overview (list of all names)
104 name = i18n("One contact found:", "%n contacts found:", addrList.count());
105 unsigned int no, linenr;
106 for (linenr=no=0; linenr<30 && no<addrList.count(); ++no) {
107 addr = addrList[no];
108 info = addr.formattedName().simplifyWhiteSpace();
109 if (info.isEmpty())
110 info = addr.givenName() + " " + addr.familyName();
111 info = info.simplifyWhiteSpace();
112 if (info.isEmpty())
113 continue;
114 text.append(info);
115 text.append("\n");
116 ++linenr;
117 }
118 return true;
119 }
120
121 // create card for _one_ contact
122 addr = addrList[ 0 ];
123
124 // prepare the text
125 name = addr.formattedName().simplifyWhiteSpace();
126 if ( name.isEmpty() )
127 name = addr.givenName() + " " + addr.familyName();
128 name = name.simplifyWhiteSpace();
129
130
131 TDEABC::PhoneNumber::List pnList = addr.phoneNumbers();
132 TQStringList phoneNumbers;
133 for (unsigned int no=0; no<pnList.count(); ++no) {
134 TQString pn = pnList[no].number().simplifyWhiteSpace();
135 if (!pn.isEmpty() && !phoneNumbers.contains(pn))
136 phoneNumbers.append(pn);
137 }
138 if ( !phoneNumbers.isEmpty() )
139 text += phoneNumbers.join("\n") + "\n";
140
141 info = addr.organization().simplifyWhiteSpace();
142 if ( !info.isEmpty() )
143 text += info + "\n";
144
145 // get an address
146 TDEABC::Address address = addr.address(TDEABC::Address::Work);
147 if (address.isEmpty())
148 address = addr.address(TDEABC::Address::Home);
149 if (address.isEmpty())
150 address = addr.address(TDEABC::Address::Pref);
151 info = address.formattedAddress();
152 if ( !info.isEmpty() )
153 text += info + "\n";
154
155 return true;
156}
157
158
159bool VCard_LDIFCreator::createImageSmall()
160{
161 text = name + "\n" + text;
162
163 if ( !mSplitter ) {
164 mSplitter = new KPixmapSplitter;
165 TQString pixmap = locate( "data", "konqueror/pics/thumbnailfont_7x4.png" );
166 if ( pixmap.isEmpty() ) {
167 delete mSplitter;
168 mSplitter=0;
169 kdWarning() << "VCard_LDIFCreator: Font image \"thumbnailfont_7x4.png\" not found!\n";
170 return false;
171 }
172 mSplitter->setPixmap( TQPixmap( pixmap ) );
173 mSplitter->setItemSize( TQSize( 4, 7 ) );
174 }
175
176 TQSize chSize = mSplitter->itemSize(); // the size of one char
177 int xOffset = chSize.width();
178 int yOffset = chSize.height();
179
180 // calculate a better border so that the text is centered
181 int canvasWidth = pixmapSize.width() - 2 * xborder;
182 int canvasHeight = pixmapSize.height() - 2 * yborder;
183 int numCharsPerLine = (int) (canvasWidth / chSize.width());
184 int numLines = (int) (canvasHeight / chSize.height());
185
186 // render the information
187 TQRect rect;
188 int rest = mPixmap.width() - (numCharsPerLine * chSize.width());
189 xborder = TQMAX( xborder, rest / 2 ); // center horizontally
190 rest = mPixmap.height() - (numLines * chSize.height());
191 yborder = TQMAX( yborder, rest / 2 ); // center vertically
192 // end centering
193
194 int x = xborder, y = yborder; // where to paint the characters
195 int posNewLine = mPixmap.width() - (chSize.width() + xborder);
196 int posLastLine = mPixmap.height() - (chSize.height() + yborder);
197 bool newLine = false;
198 Q_ASSERT( posNewLine > 0 );
199 const TQPixmap *fontPixmap = &(mSplitter->pixmap());
200
201 for ( uint i = 0; i < text.length(); i++ ) {
202 if ( x > posNewLine || newLine ) { // start a new line?
203 x = xborder;
204 y += yOffset;
205
206 if ( y > posLastLine ) // more text than space
207 break;
208
209 // after starting a new line, we also jump to the next
210 // physical newline in the file if we don't come from one
211 if ( !newLine ) {
212 int pos = text.find( '\n', i );
213 if ( pos > (int) i )
214 i = pos +1;
215 }
216
217 newLine = false;
218 }
219
220 // check for newlines in the text (unix,dos)
221 TQChar ch = text.at( i );
222 if ( ch == '\n' ) {
223 newLine = true;
224 continue;
225 } else if ( ch == '\r' && text.at(i+1) == '\n' ) {
226 newLine = true;
227 i++; // skip the next character (\n) as well
228 continue;
229 }
230
231 rect = mSplitter->coordinates( ch );
232 if ( !rect.isEmpty() )
233 bitBlt( &mPixmap, TQPoint(x,y), fontPixmap, rect, TQt::CopyROP );
234
235 x += xOffset; // next character
236 }
237
238 return true;
239}
240
241bool VCard_LDIFCreator::createImageBig()
242{
243 TQFont normalFont( TDEGlobalSettings::generalFont() );
244 TQFont titleFont( normalFont );
245 titleFont.setBold(true);
246 // titleFont.setUnderline(true);
247 titleFont.setItalic(true);
248
249 TQPainter painter(&mPixmap);
250 painter.setFont(titleFont);
251 TQFontMetrics fm(painter.fontMetrics());
252
253 // draw contact name
254 painter.setClipRect(2, 2, pixmapSize.width()-4, pixmapSize.height()-4);
255 TQPoint p(5, fm.height()+2);
256 painter.drawText(p, name);
257 p.setY( 3*p.y()/2 );
258
259 // draw contact information
260 painter.setFont(normalFont);
261 fm = painter.fontMetrics();
262
263 const TQStringList list( TQStringList::split('\n', text) );
264 for ( TQStringList::ConstIterator it = list.begin();
265 p.y()<=pixmapSize.height() && it != list.end(); ++it ) {
266 p.setY( p.y() + fm.height() );
267 painter.drawText(p, *it);
268 }
269
270 return true;
271}
272
273bool VCard_LDIFCreator::create(const TQString &path, int width, int height, TQImage &img)
274{
275 if ( !readContents(path) )
276 return false;
277
278 // resize the image if necessary
279 pixmapSize = TQSize( width, height );
280 if (height * 3 > width * 4)
281 pixmapSize.setHeight( width * 4 / 3 );
282 else
283 pixmapSize.setWidth( height * 3 / 4 );
284
285 if ( pixmapSize != mPixmap.size() )
286 mPixmap.resize( pixmapSize );
287
288 mPixmap.fill( TQColor( 245, 245, 245 ) ); // light-grey background
289
290 // one pixel for the rectangle, the rest. whitespace
291 xborder = 1 + pixmapSize.width()/16; // minimum x-border
292 yborder = 1 + pixmapSize.height()/16; // minimum y-border
293
294 bool ok;
295 if ( width >= 150 /*pixel*/ )
296 ok = createImageBig();
297 else
298 ok = createImageSmall();
299 if (!ok)
300 return false;
301
302 img = mPixmap.convertToImage();
303 return true;
304}
305
306ThumbCreator::Flags VCard_LDIFCreator::flags() const
307{
308 return (Flags)(DrawFrame | BlendIcon);
309}