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 <kstandarddirs.h>
43 #include <tdeglobalsettings.h>
44 
45 #include "ldifvcardcreator.h"
46 
47 extern "C"
48 {
49  ThumbCreator *new_creator()
50  {
51  TDEGlobal::locale()->insertCatalogue( "kaddressbook" );
52  return new VCard_LDIFCreator;
53  }
54 }
55 
56 VCard_LDIFCreator::VCard_LDIFCreator()
57  : mSplitter( 0 )
58 {
59 }
60 
61 VCard_LDIFCreator::~VCard_LDIFCreator()
62 {
63  delete mSplitter;
64 }
65 
66 
67 bool 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 
159 bool 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 
241 bool 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 
273 bool 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 
306 ThumbCreator::Flags VCard_LDIFCreator::flags() const
307 {
308  return (Flags)(DrawFrame | BlendIcon);
309 }