kaddressbook Library API Documentation

ringbinderstyle.cpp

00001 /* 00002 This file is part of KAddressBook. 00003 Copyright (c) 2002 Jost Schenck <jost@schenck.de> 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; either version 2 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program; if not, write to the Free Software 00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00018 00019 As a special exception, permission is given to link this program 00020 with any edition of Qt, and distribute the resulting executable, 00021 without including the source code for Qt in the source distribution. 00022 */ 00023 00024 #include "ringbinderstyle.h" 00025 00026 #include <qcheckbox.h> 00027 #include <qlayout.h> 00028 #include <qpaintdevicemetrics.h> 00029 #include <qpainter.h> 00030 #include <qspinbox.h> 00031 #include <qstringlist.h> 00032 00033 #include <kapplication.h> 00034 #include <kcombobox.h> 00035 #include <kconfig.h> 00036 #include <kdebug.h> 00037 #include <klistbox.h> 00038 #include <klocale.h> 00039 #include <kprinter.h> 00040 #include <kstandarddirs.h> 00041 #include <kabc/addresseelist.h> 00042 00043 #include "printingwizard.h" 00044 #include "printprogress.h" 00045 #include "printstyle.h" 00046 00047 #include "rbs_appearance.h" 00048 00049 namespace KABPrinting 00050 { 00051 00052 const char* RingBinderConfigSectionName = "RingBinderPrintStyle"; 00053 const char* ShowPhoneNumbers = "ShowPhoneNumbers"; 00054 const char* ShowEmailAddresses = "ShowEmailAddresses"; 00055 const char* ShowStreetAddresses = "ShowStreetAddresses"; 00056 const char* ShowOrganization = "ShowOrganization"; 00057 const char* ShowBirthday = "ShowBirthday"; 00058 const char* FillWithEmptyFields = "FillWithEmptyFields"; 00059 const char* MinNumberOfEmptyFields = "MinNumberOfEmptyFields"; 00060 const char* LetterGroups = "LetterGroups"; 00061 00062 RingBinderPrintStyle::RingBinderPrintStyle( PrintingWizard* parent, 00063 const char* name ) 00064 : PrintStyle( parent, name ), 00065 mPageAppearance( new RingBinderStyleAppearanceForm( parent, 00066 "AppearancePage" ) ), 00067 mPrintProgress( 0 ) 00068 { 00069 KConfig * config; 00070 setPreview( "ringbinder-style.png" ); 00071 // how is this done? : setPreferredSortOptions( ); 00072 00073 addPage( mPageAppearance, i18n( "Ring Binder Printing Style - Appearance" ) ); 00074 00075 // applying previous settings 00076 config = kapp->config(); 00077 config->setGroup( RingBinderConfigSectionName ); 00078 mPageAppearance->cbPhoneNumbers->setChecked( config->readBoolEntry( ShowPhoneNumbers, true ) ); 00079 mPageAppearance->cbEmails->setChecked( config->readBoolEntry( ShowEmailAddresses, true ) ); 00080 mPageAppearance->cbStreetAddresses->setChecked( config->readBoolEntry( ShowStreetAddresses, true ) ); 00081 mPageAppearance->cbOrganization->setChecked( config->readBoolEntry( ShowOrganization, true ) ); 00082 mPageAppearance->cbBirthday->setChecked( config->readBoolEntry( ShowBirthday, false ) ); 00083 mPageAppearance->cbFillEmpty->setChecked( config->readBoolEntry( FillWithEmptyFields, true ) ); 00084 mPageAppearance->sbMinNumFill->setValue( config->readUnsignedNumEntry( MinNumberOfEmptyFields, 0 ) ); 00085 QStringList tabNames = config->readListEntry( LetterGroups, ',' ); 00086 if ( tabNames.isEmpty() ) { 00087 tabNames = QStringList::split( ',', QString( "AB,CD,EF,GH,IJK,LM,NO,PQR,S,TU,VW,XYZ" ) ); 00088 } 00089 mPageAppearance->letterListBox->insertStringList( tabNames ); 00090 } 00091 00092 RingBinderPrintStyle::~RingBinderPrintStyle() 00093 {} 00094 00095 void RingBinderPrintStyle::print( KABC::Addressee::List &contacts, PrintProgress *progress ) 00096 { 00097 mPrintProgress = progress; 00098 progress->addMessage( i18n( "Setting up fonts and colors" ) ); 00099 progress->setProgress( 0 ); 00100 00101 // first write current config settings 00102 KConfig *config = kapp->config(); 00103 config->setGroup( RingBinderConfigSectionName ); 00104 config->writeEntry( ShowPhoneNumbers, mPageAppearance->cbPhoneNumbers->isChecked() ); 00105 config->writeEntry( ShowEmailAddresses, mPageAppearance->cbEmails->isChecked() ); 00106 config->writeEntry( ShowStreetAddresses, mPageAppearance->cbStreetAddresses->isChecked() ); 00107 config->writeEntry( ShowOrganization, mPageAppearance->cbOrganization->isChecked() ); 00108 config->writeEntry( ShowBirthday, mPageAppearance->cbBirthday->isChecked() ); 00109 config->writeEntry( FillWithEmptyFields, mPageAppearance->cbFillEmpty->isChecked() ); 00110 config->writeEntry( MinNumberOfEmptyFields, mPageAppearance->sbMinNumFill->value() ); 00111 QStringList tmpstrl; 00112 for ( uint i = 0; i < mPageAppearance->letterListBox->count(); i++ ) { 00113 if ( !mPageAppearance->letterListBox->text( i ).isEmpty() ) { 00114 tmpstrl.append( mPageAppearance->letterListBox->text( i ) ); 00115 } 00116 } 00117 config->writeEntry( LetterGroups, tmpstrl ); 00118 00119 KPrinter *printer = wizard() ->printer(); 00120 QPainter painter; 00121 00122 // margins like in detailledprintstyle. FIXME: See how we can make this configurable. 00123 progress->addMessage( i18n( "Setting up margins and spacing" ) ); 00124 int marginTop = 0, 00125 marginLeft = 64, // to allow stapling, need refinement with two-side prints 00126 marginRight = 0, 00127 marginBottom = 0; 00128 register int left, top, width, height; 00129 00130 // ----- we expect the printer to be set up (it is, before the wizard is started): 00131 painter.begin( printer ); 00132 painter.setPen( Qt::black ); 00133 printer->setFullPage( true ); // use whole page 00134 QPaintDeviceMetrics metrics( printer ); 00135 kdDebug(5720) << "RingBinderPrintStyle::print: printing on a " 00136 << metrics.width() << "x" << metrics.height() 00137 << " size area," << endl << " " 00138 << "margins are " 00139 << printer->margins().width() << " (left/right) and " 00140 << printer->margins().height() << " (top/bottom)." << endl; 00141 left = QMAX( printer->margins().width(), marginLeft ); // left margin 00142 top = QMAX( printer->margins().height(), marginTop ); // top margin 00143 width = metrics.width() - left 00144 - QMAX( printer->margins().width(), marginRight ); // page width 00145 height = metrics.height() - top 00146 - QMAX( printer->margins().height(), marginBottom ); // page height 00147 00148 // ----- now do the printing: 00149 // this prepares for, like, two-up etc: 00150 painter.setViewport( left, top, width, height ); 00151 progress->addMessage( i18n( "Printing" ) ); 00152 printEntries( contacts, printer, &painter, 00153 QRect( 0, 0, metrics.width(), metrics.height() ) ); 00154 progress->addMessage( i18n( "Done" ) ); 00155 painter.end(); 00156 config->sync(); 00157 } 00158 00159 bool RingBinderPrintStyle::printEntries( KABC::Addressee::List &contacts, 00160 KPrinter *printer, 00161 QPainter *painter, 00162 const QRect& window ) 00163 { 00164 // FIXME: handle following situations 00165 // - handle situation in which we sort descending. In this case the 00166 // letter groups should first also be sorted descending. 00167 00168 // FIXME: downcast should not be necessary, change printstyle interface 00169 KABC::AddresseeList * tmpl = ( KABC::AddresseeList* ) & contacts; 00170 #if KDE_VERSION >= 319 00171 KABC::Field* sfield = tmpl->sortingField(); 00172 #else 00173 KABC::Field* sfield = *(KABC::Field::defaultFields().begin()); 00174 #endif 00175 00176 // we now collect the letter groups. For reverse sorted address books we 00177 // reverse the sorting of the groups: 00178 QStringList ltgroups; 00179 if ( !tmpl->reverseSorting() ) { 00180 for ( unsigned int i = 0; i < mPageAppearance->letterListBox->count(); i++ ) { 00181 ltgroups.append( mPageAppearance->letterListBox->text( i ) ); 00182 } 00183 } else { 00184 for ( unsigned int i = mPageAppearance->letterListBox->count() - 1; i > 0; i-- ) { 00185 ltgroups.append( mPageAppearance->letterListBox->text( i ) ); 00186 } 00187 } 00188 00189 // the yposition of the current entry 00190 int ypos = 0; 00191 // counter variable for the progress widget 00192 int count = 0; 00193 00194 // counter for the letter group in which we currently are: 00195 uint grpnum = 0; 00196 00197 // iterate through the contacts 00198 printPageHeader( ltgroups[ grpnum ], window, painter ); 00199 ypos = pageHeaderMetrics( window, painter ).height(); 00200 for ( KABC::AddresseeList::iterator it = contacts.begin(); 00201 it != contacts.end(); ++it ) { 00202 KABC::Addressee addressee = ( *it ); 00203 if ( !addressee.isEmpty() ) { 00204 // let's see if we have to open the next group: 00205 while ( ltgroups.count() > grpnum + 1 ) { 00206 QChar nextchar; 00207 QChar nowchar; 00208 if ( !tmpl->reverseSorting() ) { 00209 nextchar = ltgroups[ grpnum + 1 ].at( 0 ).upper(); 00210 } else { 00211 QString tmpstr = ltgroups[ grpnum + 1 ]; 00212 nextchar = tmpstr.at( tmpstr.length() - 1 ).upper(); 00213 kdDebug(5720) << "################### " << tmpstr << " last is: " << 00214 QString(nextchar) << endl; 00215 } 00216 00217 // determine nowchar depending on sorting criterion 00218 { 00219 QString tmpstr = sfield->value( addressee ); 00220 if ( !tmpstr.isEmpty() ) { 00221 nowchar = tmpstr.at( 0 ).upper(); 00222 kdDebug(5720) << "------------------ " << tmpstr << " has nowchar: " 00223 << QString(nowchar) << endl; 00224 } 00225 } 00226 if ( ( !tmpl->reverseSorting() && nowchar >= nextchar ) 00227 || ( tmpl->reverseSorting() && nowchar <= nextchar ) ) { 00228 // we have reached the next letter group: 00229 // 00230 // first check if we should fill the rest of the page or even more 00231 // with empty fields: 00232 fillEmpty( window, printer, painter, ypos, grpnum ); 00233 00234 // now do change letter group 00235 grpnum++; 00236 printer->newPage(); 00237 printPageHeader( ltgroups[ grpnum ], window, painter ); 00238 ypos = pageHeaderMetrics( window, painter ).height(); 00239 // -> next loop as there might be empty letter groups 00240 } else { 00241 break; 00242 } 00243 } 00244 // print it: 00245 kdDebug(5720) << "RingBinderPrintStyle::printEntries: printing addressee " 00246 << addressee.realName() << endl; 00247 00248 // get the bounding rect: 00249 int entryheight = entryMetrics( addressee, window, painter, ypos ).height(); 00250 00251 // FIXME: the following conditional means that if we encounter an entry 00252 // that does not fit on one page we just paint over the borders 00253 if ( entryheight > ( window.height() - ypos ) 00254 && !( entryheight > window.height() ) ) { 00255 // it does not fit on the page beginning at ypos: 00256 printer->newPage(); 00257 printPageHeader( mPageAppearance->letterListBox->text( grpnum ) 00258 , window, painter ); 00259 ypos = pageHeaderMetrics( window, painter ).height(); 00260 } 00261 printEntry( addressee, window, painter, ypos ); 00262 ypos += entryheight; 00263 } else { 00264 kdDebug(5720) << "RingBinderPrintStyle::printEntries: strange, addressee " 00265 << "with UID " << addressee.uid() << " not available." << endl; 00266 } 00267 mPrintProgress->setProgress( ( count++*100 ) / contacts.count() ); 00268 } 00269 00270 // check again if we should fill the last page with empty fields 00271 // (as the above call won't be reached for the last letter group) 00272 fillEmpty( window, printer, painter, ypos, grpnum ); 00273 // ----- set progress: 00274 mPrintProgress->setProgress( 100 ); 00275 kdDebug(5720) << "PLANNER STYLE: PRINT FINISHED" << endl; 00276 return true; 00277 } 00278 00279 void RingBinderPrintStyle::fillEmpty( const QRect& window 00280 , KPrinter *printer 00281 , QPainter* painter 00282 , int top 00283 , int grpnum 00284 ) 00285 { 00286 if ( mPageAppearance->cbFillEmpty->isChecked() ) { 00287 // print as many empty fields as fit on the page 00288 int ypos = top; 00289 int fieldscounter = 0; 00290 int entryheight = emptyEntryMetrics( window, painter, ypos ).height(); 00291 do { 00292 while ( ( window.height() - ypos ) > entryheight ) { 00293 printEmptyEntry( window, painter, ypos ); 00294 ypos += entryheight; 00295 fieldscounter++; 00296 } 00297 qDebug( "fieldscounter %i", fieldscounter ); 00298 qDebug( "minNumFill %i", mPageAppearance->sbMinNumFill->value() ); 00299 if ( fieldscounter < mPageAppearance->sbMinNumFill->value() ) { 00300 printer->newPage(); 00301 printPageHeader( mPageAppearance->letterListBox->text( grpnum ) 00302 , window, painter ); 00303 ypos = pageHeaderMetrics( window, painter ).height(); 00304 } 00305 } while ( fieldscounter < mPageAppearance->sbMinNumFill->value() ); 00306 } 00307 } 00308 00309 bool RingBinderPrintStyle::printEntry( const KABC::Addressee& contact 00310 , const QRect& window 00311 , QPainter* painter 00312 , int top 00313 , bool fake 00314 , QRect* brect 00315 ) 00316 { 00317 QFont normfont( "Helvetica", 10, QFont::Normal ); 00318 QFontMetrics fmnorm( normfont ); 00319 QPen thickpen( Qt::black, 0 ); 00320 QPen thinpen ( Qt::black, 0 ); 00321 // store at which line we are and how many lines we have for this entry: 00322 int linenum = 0; 00323 int maxlines = 0; 00324 painter->setFont( normfont ); 00325 linenum++; 00326 // FIXME: maybe we should not rely on formattedName only but make this 00327 // configurable -- if somebody sorts by familyName, but most entries have 00328 // a formatted name of "GivenName FamilyName" it might look strange. 00329 if ( !fake ) { 00330 QString namestr = contact.formattedName(); 00331 if ( namestr.isEmpty() ) { 00332 namestr = contact.familyName() + ", " + contact.givenName(); 00333 } 00334 if ( mPageAppearance->cbOrganization->isChecked() 00335 && !contact.organization().isEmpty() ) { 00336 namestr += QString( " (" ) + contact.organization() + QString( ")" ); 00337 } 00338 if ( mPageAppearance->cbBirthday->isChecked() && !contact.birthday().isNull() ) { 00339 namestr += QString( " *" ) + KGlobal::locale()->formatDate( 00340 contact.birthday().date(), true ); 00341 } 00342 painter->drawText( 5, top + ( linenum * fmnorm.lineSpacing() ) 00343 - fmnorm.leading(), namestr ); 00344 } 00345 painter->setFont( normfont ); 00346 00347 // print street addresses: 00348 if ( mPageAppearance->cbStreetAddresses->isChecked() ) { 00349 KABC::Address::List addrl = contact.addresses(); 00350 KABC::Address::List::iterator it; 00351 for ( it = addrl.begin(); it != addrl.end(); ++it ) { 00352 if ( !( *it ).isEmpty() ) { 00353 //FIXME:draw type label somehow 00354 // linenum++; 00355 // if(!fake) 00356 // painter->drawText(5, top + (linenum*fmnorm.lineSpacing()) 00357 // - fmnorm.leading(), (*it).typeLabel()); 00358 painter->setFont( normfont ); 00359 QString formattedAddress; 00360 #if KDE_VERSION >= 319 00361 formattedAddress = (*it).formattedAddress(); 00362 #else 00363 formattedAddress = (*it).label(); 00364 #endif 00365 QStringList laddr = QStringList::split( QChar( '\n' ), 00366 formattedAddress ); 00367 for ( QStringList::iterator it = laddr.begin(); it != laddr.end(); ++it ) { 00368 linenum++; 00369 if ( !fake ) { 00370 painter->drawText( 20, top + ( linenum * fmnorm.lineSpacing() ) 00371 - fmnorm.leading(), *it ); 00372 } 00373 } 00374 } 00375 } 00376 } 00377 maxlines = linenum; 00378 linenum = 0; 00379 00380 // print phone numbers 00381 if ( mPageAppearance->cbPhoneNumbers->isChecked() ) { 00382 KABC::PhoneNumber::List phonel = contact.phoneNumbers(); 00383 KABC::PhoneNumber::List::iterator nit; 00384 for ( nit = phonel.begin(); nit != phonel.end(); ++nit ) { 00385 00386 // don't print empty lines just reading "Home:" 00387 if ( ( *nit ).number().isEmpty() ) { 00388 continue; 00389 } 00390 linenum++; 00391 00392 // construct phone string and draw it 00393 QString numstr = ( *nit ).typeLabel(); 00394 if ( !numstr.isEmpty() ) { 00395 numstr.append( ": " ); 00396 } 00397 numstr.append( ( *nit ).number() ); 00398 painter->drawText( ( int ) ( window.width() * 0.5 ) + 5, 00399 top + ( linenum * fmnorm.lineSpacing() ) 00400 - fmnorm.leading(), numstr ); 00401 } 00402 } 00403 00404 // print email addresses 00405 if ( mPageAppearance->cbEmails->isChecked() ) { 00406 QStringList emails = contact.emails(); 00407 for ( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) { 00408 // don't print empty lines 00409 if ( ( *it ).isEmpty() ) { 00410 continue; 00411 } 00412 linenum++; 00413 painter->drawText( ( int ) ( window.width() * 0.5 ) + 5, 00414 top + ( linenum * fmnorm.lineSpacing() ) 00415 - fmnorm.leading(), *it ); 00416 } 00417 } 00418 00419 // total number of lines: 00420 if ( linenum > maxlines ) { 00421 maxlines = linenum; 00422 } 00423 if ( brect ) { 00424 brect->setRect( 0, top, window.width(), 00425 ( maxlines * fmnorm.lineSpacing() ) + fmnorm.leading() ); 00426 } 00427 if ( fake ) { // nothing to do anymore as we already have dimensions 00428 return true; 00429 } 00430 painter->setPen( thickpen ); 00431 if ( !fake ) 00432 painter->drawRect( 0, top, window.width(), 00433 ( maxlines * fmnorm.lineSpacing() ) + fmnorm.leading() ); 00434 if ( !fake ) 00435 painter->drawLine( ( int ) ( window.width() * 0.5 ), top, 00436 (int)( window.width() * 0.5 ), 00437 top + ( maxlines * fmnorm.lineSpacing() ) + fmnorm.leading() ); 00438 painter->setPen( thinpen ); 00439 return true; 00440 } 00441 00442 QRect RingBinderPrintStyle::entryMetrics( const KABC::Addressee& contact 00443 , const QRect& window 00444 , QPainter* painter 00445 , int top 00446 ) 00447 { 00448 QRect ret; 00449 printEntry( contact, window, painter, top, true, &ret ); 00450 return ret; 00451 } 00452 00453 bool RingBinderPrintStyle::printEmptyEntry( 00454 const QRect& window 00455 , QPainter* painter 00456 , int top 00457 ) 00458 { 00459 QFont normfont( "Helvetica", 10, QFont::Normal ); 00460 QFontMetrics fmnorm( normfont ); 00461 // QPen thickpen(Qt::black, 1); 00462 QPen thickpen( Qt::black, 0 ); 00463 QPen thinpen ( Qt::black, 0 ); 00464 painter->setFont( normfont ); 00465 painter->setPen( thickpen ); 00466 painter->drawRect( 0, top, window.width(), ( 3 * fmnorm.lineSpacing() ) ); 00467 painter->setPen( thinpen ); 00468 for ( int i = 1; i < 3; i++ ) { 00469 painter->drawLine( 0, top + i * fmnorm.lineSpacing(), window.width(), 00470 top + i * fmnorm.lineSpacing() ); 00471 } 00472 painter->drawLine( (int)( window.width() * 0.5 ), top, 00473 (int)( window.width() * 0.5 ), top + ( 3 * fmnorm.lineSpacing() ) ); 00474 // this line not as deep as we need room for the email field 00475 painter->drawLine( (int)( window.width() * 0.75 ), top, 00476 (int)( window.width() * 0.75 ), top + ( 2 * fmnorm.lineSpacing() ) ); 00477 // painter->drawText((window.width()*0.5) + 5, 00478 // top+3*fmnorm.lineSpacing() -4, "email"); 00479 return true; 00480 } 00481 00482 QRect RingBinderPrintStyle::emptyEntryMetrics( 00483 const QRect& window 00484 , QPainter* /*painter*/ 00485 , int top 00486 ) 00487 { 00488 QFont normfont( "Helvetica", 10, QFont::Normal ); 00489 QFontMetrics fmnorm( normfont ); 00490 return QRect( 0, top, window.width(), ( 3 * fmnorm.lineSpacing() ) ); 00491 } 00492 00493 00494 bool RingBinderPrintStyle::printPageHeader( 00495 const QString section 00496 , const QRect& window 00497 , QPainter* painter 00498 ) 00499 { 00500 QFont sectfont( "Helvetica", 16, QFont::Normal ); 00501 QFontMetrics fmsect( sectfont ); 00502 painter->setFont( sectfont ); 00503 painter->drawText( QRect( 0, 0, window.width(), fmsect.height() ), 00504 Qt::AlignRight, section ); 00505 return true; 00506 } 00507 00508 QRect RingBinderPrintStyle::pageHeaderMetrics( 00509 const QRect& window 00510 , QPainter* /*painter*/ 00511 ) 00512 { 00513 QFont sectfont( "Helvetica", 16, QFont::Normal ); 00514 QFont normfont( "Helvetica", 12, QFont::Normal ); 00515 QFontMetrics fmsect( sectfont ); 00516 QFontMetrics fmnorm( normfont ); 00517 return QRect( 0, 0, window.width(), fmsect.height() + 10 ); 00518 } 00519 00520 00521 RingBinderPrintStyleFactory::RingBinderPrintStyleFactory( 00522 PrintingWizard* parent, 00523 const char* name ) 00524 : PrintStyleFactory( parent, name ) 00525 {} 00526 00527 00528 PrintStyle *RingBinderPrintStyleFactory::create() 00529 { 00530 return new RingBinderPrintStyle( mParent, mName ); 00531 } 00532 00533 QString RingBinderPrintStyleFactory::description() 00534 { 00535 return i18n( "Printout for Ring Binders" ); 00536 } 00537 00538 } 00539 00540 #include "ringbinderstyle.moc" 00541 // vim:tw=78 cin et sw=2 comments=sr\:/*,mb\:\ ,ex\:*/,\://
KDE Logo
This file is part of the documentation for kaddressbook Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Oct 21 19:46:37 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003