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  * kioslave 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 <kglobal.h>
38 #include <klocale.h>
39 #include <kabc/ldifconverter.h>
40 #include <kabc/vcardconverter.h>
41 #include <kpixmapsplitter.h>
42 #include <kstandarddirs.h>
43 #include <kglobalsettings.h>
44 
45 #include "ldifvcardcreator.h"
46 
47 extern "C"
48 {
49  ThumbCreator *new_creator()
50  {
51  KGlobal::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  TQString contents = file.readAll();
84 #endif
85  file.close();
86 
87  // convert the file contents to a KABC::Addressee address
88  KABC::AddresseeList addrList;
89  KABC::Addressee addr;
90  KABC::VCardConverter converter;
91 
92 #if defined(KABC_VCARD_ENCODING_FIX)
93  addrList = converter.parseVCardsRaw( contentsRaw );
94 #else
95  addrList = converter.parseVCards( contents );
96 #endif
97  if ( addrList.count() == 0 )
98  if ( !KABC::LDIFConverter::LDIFToAddressee( contents, addrList ) )
99  return false;
100  if ( addrList.count()>1 ) {
101  // create an overview (list of all names)
102  name = i18n("One contact found:", "%n contacts found:", addrList.count());
103  unsigned int no, linenr;
104  for (linenr=no=0; linenr<30 && no<addrList.count(); ++no) {
105  addr = addrList[no];
106  info = addr.formattedName().simplifyWhiteSpace();
107  if (info.isEmpty())
108  info = addr.givenName() + " " + addr.familyName();
109  info = info.simplifyWhiteSpace();
110  if (info.isEmpty())
111  continue;
112  text.append(info);
113  text.append("\n");
114  ++linenr;
115  }
116  return true;
117  }
118 
119  // create card for _one_ contact
120  addr = addrList[ 0 ];
121 
122  // prepare the text
123  name = addr.formattedName().simplifyWhiteSpace();
124  if ( name.isEmpty() )
125  name = addr.givenName() + " " + addr.familyName();
126  name = name.simplifyWhiteSpace();
127 
128 
129  KABC::PhoneNumber::List pnList = addr.phoneNumbers();
130  TQStringList phoneNumbers;
131  for (unsigned int no=0; no<pnList.count(); ++no) {
132  TQString pn = pnList[no].number().simplifyWhiteSpace();
133  if (!pn.isEmpty() && !phoneNumbers.contains(pn))
134  phoneNumbers.append(pn);
135  }
136  if ( !phoneNumbers.isEmpty() )
137  text += phoneNumbers.join("\n") + "\n";
138 
139  info = addr.organization().simplifyWhiteSpace();
140  if ( !info.isEmpty() )
141  text += info + "\n";
142 
143  // get an address
144  KABC::Address address = addr.address(KABC::Address::Work);
145  if (address.isEmpty())
146  address = addr.address(KABC::Address::Home);
147  if (address.isEmpty())
148  address = addr.address(KABC::Address::Pref);
149  info = address.formattedAddress();
150  if ( !info.isEmpty() )
151  text += info + "\n";
152 
153  return true;
154 }
155 
156 
157 bool VCard_LDIFCreator::createImageSmall()
158 {
159  text = name + "\n" + text;
160 
161  if ( !mSplitter ) {
162  mSplitter = new KPixmapSplitter;
163  TQString pixmap = locate( "data", "konqueror/pics/thumbnailfont_7x4.png" );
164  if ( pixmap.isEmpty() ) {
165  delete mSplitter;
166  mSplitter=0;
167  kdWarning() << "VCard_LDIFCreator: Font image \"thumbnailfont_7x4.png\" not found!\n";
168  return false;
169  }
170  mSplitter->setPixmap( TQPixmap( pixmap ) );
171  mSplitter->setItemSize( TQSize( 4, 7 ) );
172  }
173 
174  TQSize chSize = mSplitter->itemSize(); // the size of one char
175  int xOffset = chSize.width();
176  int yOffset = chSize.height();
177 
178  // calculate a better border so that the text is centered
179  int canvasWidth = pixmapSize.width() - 2 * xborder;
180  int canvasHeight = pixmapSize.height() - 2 * yborder;
181  int numCharsPerLine = (int) (canvasWidth / chSize.width());
182  int numLines = (int) (canvasHeight / chSize.height());
183 
184  // render the information
185  TQRect rect;
186  int rest = mPixmap.width() - (numCharsPerLine * chSize.width());
187  xborder = TQMAX( xborder, rest / 2 ); // center horizontally
188  rest = mPixmap.height() - (numLines * chSize.height());
189  yborder = TQMAX( yborder, rest / 2 ); // center vertically
190  // end centering
191 
192  int x = xborder, y = yborder; // where to paint the characters
193  int posNewLine = mPixmap.width() - (chSize.width() + xborder);
194  int posLastLine = mPixmap.height() - (chSize.height() + yborder);
195  bool newLine = false;
196  Q_ASSERT( posNewLine > 0 );
197  const TQPixmap *fontPixmap = &(mSplitter->pixmap());
198 
199  for ( uint i = 0; i < text.length(); i++ ) {
200  if ( x > posNewLine || newLine ) { // start a new line?
201  x = xborder;
202  y += yOffset;
203 
204  if ( y > posLastLine ) // more text than space
205  break;
206 
207  // after starting a new line, we also jump to the next
208  // physical newline in the file if we don't come from one
209  if ( !newLine ) {
210  int pos = text.find( '\n', i );
211  if ( pos > (int) i )
212  i = pos +1;
213  }
214 
215  newLine = false;
216  }
217 
218  // check for newlines in the text (unix,dos)
219  TQChar ch = text.at( i );
220  if ( ch == '\n' ) {
221  newLine = true;
222  continue;
223  } else if ( ch == '\r' && text.at(i+1) == '\n' ) {
224  newLine = true;
225  i++; // skip the next character (\n) as well
226  continue;
227  }
228 
229  rect = mSplitter->coordinates( ch );
230  if ( !rect.isEmpty() )
231  bitBlt( &mPixmap, TQPoint(x,y), fontPixmap, rect, TQt::CopyROP );
232 
233  x += xOffset; // next character
234  }
235 
236  return true;
237 }
238 
239 bool VCard_LDIFCreator::createImageBig()
240 {
241  TQFont normalFont( KGlobalSettings::generalFont() );
242  TQFont titleFont( normalFont );
243  titleFont.setBold(true);
244  // titleFont.setUnderline(true);
245  titleFont.setItalic(true);
246 
247  TQPainter painter(&mPixmap);
248  painter.setFont(titleFont);
249  TQFontMetrics fm(painter.fontMetrics());
250 
251  // draw contact name
252  painter.setClipRect(2, 2, pixmapSize.width()-4, pixmapSize.height()-4);
253  TQPoint p(5, fm.height()+2);
254  painter.drawText(p, name);
255  p.setY( 3*p.y()/2 );
256 
257  // draw contact information
258  painter.setFont(normalFont);
259  fm = painter.fontMetrics();
260 
261  const TQStringList list( TQStringList::split('\n', text) );
262  for ( TQStringList::ConstIterator it = list.begin();
263  p.y()<=pixmapSize.height() && it != list.end(); ++it ) {
264  p.setY( p.y() + fm.height() );
265  painter.drawText(p, *it);
266  }
267 
268  return true;
269 }
270 
271 bool VCard_LDIFCreator::create(const TQString &path, int width, int height, TQImage &img)
272 {
273  if ( !readContents(path) )
274  return false;
275 
276  // resize the image if necessary
277  pixmapSize = TQSize( width, height );
278  if (height * 3 > width * 4)
279  pixmapSize.setHeight( width * 4 / 3 );
280  else
281  pixmapSize.setWidth( height * 3 / 4 );
282 
283  if ( pixmapSize != mPixmap.size() )
284  mPixmap.resize( pixmapSize );
285 
286  mPixmap.fill( TQColor( 245, 245, 245 ) ); // light-grey background
287 
288  // one pixel for the rectangle, the rest. whitespace
289  xborder = 1 + pixmapSize.width()/16; // minimum x-border
290  yborder = 1 + pixmapSize.height()/16; // minimum y-border
291 
292  bool ok;
293  if ( width >= 150 /*pixel*/ )
294  ok = createImageBig();
295  else
296  ok = createImageSmall();
297  if (!ok)
298  return false;
299 
300  img = mPixmap.convertToImage();
301  return true;
302 }
303 
304 ThumbCreator::Flags VCard_LDIFCreator::flags() const
305 {
306  return (Flags)(DrawFrame | BlendIcon);
307 }