kaddressbook Library API Documentation

cardview.cpp

00001 /* 00002 This file is part of KAddressBook. 00003 Copyright (c) 2002 Mike Pilone <mpilone@slac.com> 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 //BEGIN Includes 00025 #include "cardview.h" 00026 00027 #include <limits.h> 00028 00029 #include <qpainter.h> 00030 #include <qtimer.h> 00031 #include <qdatetime.h> 00032 #include <qlabel.h> 00033 #include <qstyle.h> 00034 #include <qcursor.h> 00035 #include <qtooltip.h> 00036 00037 #include <kdebug.h> 00038 #include <kglobalsettings.h> 00039 //END includes 00040 00041 #define MIN_ITEM_WIDTH 80 00042 00043 //BEGIN Helpers 00045 // CardViewTip 00046 class CardViewTip : public QLabel { 00047 public: 00048 CardViewTip(QWidget *parent=0, const char *name=0) : QLabel( parent, name ) 00049 { 00050 setPalette( QToolTip::palette() ); 00051 setFrameStyle( Panel|Plain ); 00052 setMidLineWidth(0); 00053 setIndent(1); 00054 } 00055 00056 ~CardViewTip() {}; 00057 protected: 00058 void leaveEvent( QEvent * ) 00059 { 00060 hide(); 00061 } 00062 }; 00063 00065 // CardViewItemList 00066 00067 00068 // 00069 // Warning: make sure you use findRef() instead of find() to find an 00070 // item! Only the pointer value is unique in the list. 00071 // 00072 class CardViewItemList : public QPtrList<CardViewItem> 00073 { 00074 protected: 00075 virtual int compareItems(QPtrCollection::Item item1, 00076 QPtrCollection::Item item2) 00077 { 00078 CardViewItem *cItem1 = (CardViewItem*)item1; 00079 CardViewItem *cItem2 = (CardViewItem*)item2; 00080 00081 if ( cItem1 == cItem2 ) 00082 return 0; 00083 00084 if ((cItem1 == 0) || (cItem2 == 0)) 00085 return cItem1 ? -1 : 1; 00086 00087 if (cItem1->caption() < cItem2->caption()) 00088 return -1; 00089 00090 else if (cItem1->caption() > cItem2->caption()) 00091 return 1; 00092 00093 return 0; 00094 } 00095 00096 private: 00097 /*int find( const CardViewItem * ) 00098 { 00099 qDebug("DON'T USE CardViewItemList::find( item )! Use findRef( item )!"); 00100 }*/ 00101 }; 00102 00104 // CardViewSeparator 00105 class CardViewSeparator 00106 { 00107 friend class CardView; 00108 00109 public: 00110 CardViewSeparator(CardView *view) 00111 : mView(view) 00112 { 00113 mRect = QRect(0, 0, view->separatorWidth(), 0); 00114 } 00115 00116 ~CardViewSeparator() {} 00117 00118 void paintSeparator(QPainter *p, QColorGroup &cg) 00119 { 00120 p->fillRect(0, 0, mRect.width(), mRect.height(), 00121 cg.brush(QColorGroup::Button)); 00122 } 00123 00124 void repaintSeparator() 00125 { 00126 mView->repaintContents(mRect); 00127 } 00128 00129 private: 00130 CardView *mView; 00131 QRect mRect; 00132 }; 00133 00134 //END Helpers 00135 00136 //BEGIN Private Data 00137 00138 class CardViewPrivate 00139 { 00140 public: 00141 CardViewPrivate() 00142 : mSelectionMode( CardView::Multi ), 00143 mDrawCardBorder( true ), 00144 mDrawFieldLabels( true ), 00145 mDrawSeparators( true), 00146 mSepWidth( 2 ), 00147 mShowEmptyFields( false ), 00148 mLayoutDirty( true ), 00149 mLastClickOnItem( false ), 00150 mItemMargin( 0 ), 00151 mItemSpacing( 10 ), 00152 mItemWidth( 200 ), 00153 mMaxFieldLines( INT_MAX ), 00154 mCurrentItem( 0L ), 00155 mLastClickPos( QPoint(0, 0) ), 00156 mRubberBandAnchor( 0 ), 00157 mCompText( QString::null ) 00158 {}; 00159 00160 CardViewItemList mItemList; 00161 QPtrList<CardViewSeparator> mSeparatorList; 00162 QFontMetrics *mFm; 00163 QFontMetrics *mBFm; // bold font 00164 QFont mHeaderFont; // custom header font 00165 CardView::SelectionMode mSelectionMode; 00166 bool mDrawCardBorder; 00167 bool mDrawFieldLabels; 00168 bool mDrawSeparators; 00169 int mSepWidth; 00170 bool mShowEmptyFields; 00171 bool mLayoutDirty; 00172 bool mLastClickOnItem; 00173 uint mItemMargin; // internal margin in items 00174 uint mItemSpacing; // spacing between items, column seperators and border 00175 int mItemWidth; // width of all items 00176 uint mMaxFieldLines; // Max lines to dispaly pr field 00177 CardViewItem *mCurrentItem; 00178 QPoint mLastClickPos; 00179 QTimer *mTimer; // times out if mouse rests for more than 500 msecs 00180 CardViewTip *mTip; // passed to the item under a resting cursor to display full text 00181 bool mOnSeparator; // set/reset on mouse movement 00182 // for resizing by dragging the separators 00183 int mResizeAnchor; // uint, ulong? the mouse down separator left 00184 int mRubberBandAnchor; // for erasing rubber bands 00185 // data used for resizing. 00186 // as they are beeded by each mouse move while resizing, we store them here, 00187 // saving 8 calculations in each mouse move. 00188 int colspace; // amount of space between items pr column 00189 uint first; // the first col to anchor at for painting rubber bands 00190 int firstX; // X position of first in pixel 00191 int pressed; // the colummn that was pressed on at resizing start 00192 int span; // pressed - first 00193 // key completion 00194 QString mCompText; // current completion string 00195 QDateTime mCompUpdated; // ...was updated at this time 00196 }; 00197 00198 class CardViewItemPrivate 00199 { 00200 public: 00201 CardViewItemPrivate() {} 00202 00203 QString mCaption; 00204 QPtrList< CardViewItem::Field > mFieldList; 00205 bool mSelected; 00206 int x; // horizontal position, set by the view 00207 int y; // vertical position, set by the view 00208 int maxLabelWidth; // the width of the widest label, according to the view font. 00209 int hcache; // height cache 00210 }; 00211 //END Private Data 00212 00213 //BEGIN CardViewItem 00214 00215 CardViewItem::CardViewItem(CardView *parent, QString caption) 00216 : d(new CardViewItemPrivate()), mView(parent) 00217 { 00218 d->mCaption = caption; 00219 00220 initialize(); 00221 } 00222 00223 CardViewItem::~CardViewItem() 00224 { 00225 // Remove ourself from the view 00226 if (mView != 0) 00227 mView->takeItem(this); 00228 00229 delete d; 00230 d = 0; 00231 } 00232 00233 void CardViewItem::initialize() 00234 { 00235 d->mSelected = false; 00236 d->mFieldList.setAutoDelete(true); 00237 d->maxLabelWidth = 0; 00238 d->hcache=0; 00239 00240 //calcRect(); 00241 00242 // Add ourself to the view 00243 if (mView != 0) 00244 mView->insertItem(this); 00245 } 00246 00247 void CardViewItem::paintCard(QPainter *p, QColorGroup &cg) 00248 { 00249 00250 if (!mView) 00251 return; 00252 00253 QPen pen; 00254 QBrush brush; 00255 QFontMetrics fm = *(mView->d->mFm); 00256 QFontMetrics bFm = *(mView->d->mBFm); 00257 bool drawLabels = mView->d->mDrawFieldLabels; 00258 bool drawBorder = mView->d->mDrawCardBorder; 00259 int mg = mView->itemMargin(); 00260 int w = mView->itemWidth() - (mg*2); 00261 int h = height() - (mg*2); 00262 const int colonWidth( fm.width(":") ); 00263 int labelXPos = 2 + mg; 00264 int labelWidth = QMIN( w/2 - 4 - mg, d->maxLabelWidth + colonWidth + 4 ); 00265 int valueXPos = labelWidth + 4 + mg; 00266 int valueWidth = w - labelWidth - 4 - mg; 00267 00268 p->setFont( mView->font() ); 00269 labelWidth -= colonWidth; // extra space for the colon 00270 00271 if (!drawLabels) 00272 { 00273 valueXPos = labelXPos; 00274 valueWidth = w - 4; 00275 } 00276 00277 // Draw a simple box 00278 if (isSelected()) 00279 pen = QPen(cg.highlight(), 1); 00280 else 00281 pen = QPen(cg.button(), 1); 00282 p->setPen(pen); 00283 00284 // Draw the border - this is only draw if the user asks for it. 00285 if (drawBorder) 00286 p->drawRect( mg, mg, w, h ); 00287 00288 // set the proper pen color for the caption box 00289 if (isSelected()) 00290 brush = cg.brush(QColorGroup::Highlight); 00291 else 00292 brush = cg.brush(QColorGroup::Button); 00293 00294 p->fillRect(mg, mg, w, 4 + bFm.height(), brush); 00295 00296 // Now paint the caption 00297 p->save(); 00298 QFont bFont = mView->headerFont(); 00299 //bFont.setBold(true); 00300 p->setFont(bFont); 00301 if (isSelected()) 00302 p->setPen(cg.highlightedText()); 00303 else 00304 p->setPen(cg.buttonText()); 00305 p->drawText(2+mg, 2+mg + bFm.ascent()/*bFm.height()*//*-bFm.descent()*//*-bFm.leading()*/, trimString(d->mCaption, w-4, bFm)); 00306 p->restore(); 00307 00308 // Go through the fields and draw them 00309 QPtrListIterator< CardViewItem::Field > iter(d->mFieldList); 00310 QString label, value; 00311 int yPos = mg + 4 + bFm.height()/* + 1*/ + fm.height(); // why the + 1 ??? (anders) 00312 p->setPen(cg.text()); 00313 00314 int fh = fm.height(); 00315 int cln( 0 ); 00316 QString tmp; 00317 int maxLines = mView->maxFieldLines(); 00318 for (iter.toFirst(); iter.current(); ++iter) 00319 { 00320 value = (*iter)->second; 00321 if ( value.isEmpty() && ! mView->d->mShowEmptyFields ) 00322 continue; 00323 00324 if (drawLabels) 00325 { 00326 label = trimString((*iter)->first, labelWidth, fm); 00327 p->drawText(labelXPos, yPos, label + ":"); 00328 } 00329 00330 for (cln=0; cln <= maxLines; cln++) 00331 { 00332 tmp = value.section('\n',cln,cln); 00333 if ( !tmp.isEmpty() ) p->drawText( valueXPos, yPos + cln*fh, trimString( tmp, valueWidth, fm ) ); 00334 else break; 00335 } 00336 00337 if ( cln == 0 ) cln = 1; 00338 yPos += cln * fh + 2; 00339 } 00340 00341 // if we are the current item and the view has focus, draw focus rect 00342 if ( mView->currentItem() == this && mView->hasFocus() ) 00343 { 00344 mView->style().drawPrimitive( QStyle::PE_FocusRect, p, 00345 QRect(0, 0, mView->itemWidth(), h+(2*mg)), cg, 00346 QStyle::Style_FocusAtBorder, 00347 QStyleOption( isSelected() ? cg.highlight() : cg.base() ) ); 00348 } 00349 } 00350 00351 const QString &CardViewItem::caption() const 00352 { 00353 return d->mCaption; 00354 } 00355 00356 00357 int CardViewItem::height( bool allowCache ) const 00358 { 00359 // use cache 00360 if ( allowCache && d->hcache ) 00361 return d->hcache; 00362 00363 // Base height: 00364 // 2 for line width 00365 // 2 for top caption pad 00366 // 2 for bottom caption pad 00367 // 2 pad for the end 00368 // + 2 times the advised margin 00369 int baseHeight = 8 + ( 2 * mView->itemMargin() ); 00370 00371 // size of font for each field 00372 // 2 pad for each field 00373 00374 // anders: if the view does not show empty fields, check for value 00375 bool sef = mView->showEmptyFields(); 00376 int fh = mView->d->mFm->height();//lineSpacing(); // font height 00377 //int sp = QMAX( 0, 2- mView->d->mFm->leading() ); // field spacing NOTE make a property 00378 int fieldHeight = 0; 00379 int lines; 00380 int maxLines( mView->maxFieldLines() ); 00381 QPtrListIterator< CardViewItem::Field > iter(d->mFieldList); 00382 for (iter.toFirst(); iter.current(); ++iter) 00383 { 00384 if ( !sef && (*iter)->second.isEmpty() ) 00385 continue; 00386 lines = QMIN( (*iter)->second.contains('\n') + 1, maxLines ); 00387 fieldHeight += ( lines * fh ) + 2;//sp; 00388 } 00389 00390 // height of caption font (bold) 00391 fieldHeight += mView->d->mBFm->height(); 00392 d->hcache = baseHeight + fieldHeight; 00393 return d->hcache; 00394 } 00395 00396 bool CardViewItem::isSelected() const 00397 { 00398 return d->mSelected; 00399 } 00400 00401 void CardViewItem::setSelected(bool selected) 00402 { 00403 d->mSelected = selected; 00404 } 00405 00406 void CardViewItem::insertField(const QString &label, const QString &value) 00407 { 00408 CardViewItem::Field *f = new CardViewItem::Field(label, value); 00409 d->mFieldList.append(f); 00410 d->hcache=0; 00411 00412 if (mView) 00413 { 00414 mView->setLayoutDirty(true); 00415 d->maxLabelWidth = QMAX( mView->d->mFm->width( label ), d->maxLabelWidth ); 00416 } 00417 } 00418 00419 void CardViewItem::removeField(const QString &label) 00420 { 00421 CardViewItem::Field *f; 00422 00423 QPtrListIterator< CardViewItem::Field > iter(d->mFieldList); 00424 for (iter.toFirst(); iter.current(); ++iter) 00425 { 00426 f = *iter; 00427 if (f->first == label) 00428 break; 00429 } 00430 00431 if (*iter) 00432 d->mFieldList.remove(*iter); 00433 d->hcache = 0; 00434 00435 if (mView) 00436 mView->setLayoutDirty(true); 00437 } 00438 00439 void CardViewItem::clearFields() 00440 { 00441 d->mFieldList.clear(); 00442 d->hcache = 0; 00443 00444 if (mView) 00445 mView->setLayoutDirty(true); 00446 } 00447 00448 QString CardViewItem::trimString(const QString &text, int width, 00449 QFontMetrics &fm) 00450 { 00451 if (fm.width(text) <= width) 00452 return text; 00453 00454 QString dots = "..."; 00455 int dotWidth = fm.width(dots); 00456 QString trimmed; 00457 int charNum = 0; 00458 00459 while (fm.width(trimmed) + dotWidth < width) 00460 { 00461 trimmed += text[charNum]; 00462 charNum++; 00463 } 00464 00465 // Now trim the last char, since it put the width over the top 00466 trimmed = trimmed.left(trimmed.length()-1); 00467 trimmed += dots; 00468 00469 return trimmed; 00470 } 00471 00472 CardViewItem *CardViewItem::nextItem() 00473 { 00474 CardViewItem *item = 0; 00475 00476 if (mView) 00477 item = mView->itemAfter(this); 00478 00479 return item; 00480 } 00481 00482 void CardViewItem::repaintCard() 00483 { 00484 if (mView) 00485 mView->repaintItem(this); 00486 } 00487 00488 void CardViewItem::setCaption(const QString &caption) 00489 { 00490 d->mCaption = caption; 00491 repaintCard(); 00492 } 00493 00494 QString CardViewItem::fieldValue(const QString &label) 00495 { 00496 QPtrListIterator< CardViewItem::Field > iter(d->mFieldList); 00497 for (iter.toFirst(); iter.current(); ++iter) 00498 if ((*iter)->first == label) 00499 return (*iter)->second; 00500 00501 return QString(); 00502 } 00503 00504 00505 void CardViewItem::showFullString( const QPoint &itempos, CardViewTip *tip ) 00506 { 00507 bool trimmed( false ); 00508 QString s; 00509 int mrg = mView->itemMargin(); 00510 int y = mView->d->mBFm->height() + 6 + mrg; 00511 int w = mView->itemWidth() - (2*mrg); 00512 int lw; 00513 bool drawLabels = mView->drawFieldLabels(); 00514 bool isLabel = drawLabels && itempos.x() < w/2 ? true : false; 00515 00516 if ( itempos.y() < y ) 00517 { 00518 if ( itempos.y() < 8 + mrg || itempos.y() > y - 4 ) 00519 return; 00520 // this is the caption 00521 s = caption(); 00522 trimmed = mView->d->mBFm->width( s ) > w - 4; 00523 y = 2 + mrg; 00524 lw = 0; 00525 isLabel=true; 00526 } else { 00527 // find the field 00528 Field *f = fieldAt( itempos ); 00529 if ( !f || ( !mView->showEmptyFields() && f->second.isEmpty() ) ) 00530 return; 00531 00532 // y position: 00533 // header font height + 4px hader margin + 2px leading + item margin 00534 // + actual field index * (fontheight + 2px leading) 00535 int maxLines = mView->maxFieldLines(); 00536 bool se = mView->showEmptyFields(); 00537 int fh = mView->d->mFm->height(); 00538 // { 00539 Field *_f; 00540 for (_f = d->mFieldList.first(); _f != f; _f = d->mFieldList.next()) 00541 if ( se || ! _f->second.isEmpty() ) 00542 y += ( QMIN(_f->second.contains('\n')+1, maxLines) * fh ) + 2; 00543 // } 00544 if ( isLabel && itempos.y() > y + fh ) 00545 return; 00546 // label or data? 00547 s = isLabel ? f->first : f->second; 00548 // trimmed? 00549 int colonWidth = mView->d->mFm->width(":"); 00550 lw = drawLabels ? // label width 00551 QMIN( w/2 - 4 - mrg, d->maxLabelWidth + colonWidth + 4 ) : 00552 0; 00553 int mw = isLabel ? lw - colonWidth : w - lw - (mrg*2); // max width for string 00554 if ( isLabel ) 00555 { 00556 trimmed = mView->d->mFm->width( s ) > mw - colonWidth; 00557 } else { 00558 QRect r( mView->d->mFm->boundingRect( 0, 0, INT_MAX, INT_MAX, Qt::AlignTop|Qt::AlignLeft, s ) ); 00559 trimmed = r.width() > mw || r.height()/fh > QMIN(s.contains('\n') + 1, maxLines); 00560 } 00561 } 00562 if ( trimmed ) 00563 { 00564 tip->setFont( (isLabel && !lw) ? mView->headerFont() : mView->font() ); // if condition is true, a header 00565 tip->setText( s ); 00566 tip->adjustSize(); 00567 // find a proper position 00568 int lx; 00569 lx = isLabel || !drawLabels ? mrg : lw + mrg + 2 /*-1*/; 00570 QPoint pnt(mView->contentsToViewport( QPoint(d->x, d->y) )); 00571 pnt += QPoint(lx, y); 00572 if ( pnt.x() < 0 ) 00573 pnt.setX( 0 ); 00574 if ( pnt.x() + tip->width() > mView->visibleWidth() ) 00575 pnt.setX( mView->visibleWidth() - tip->width() ); 00576 if ( pnt.y() + tip->height() > mView->visibleHeight() ) 00577 pnt.setY( QMAX( 0, mView->visibleHeight() - tip->height() ) ); 00578 // show 00579 tip->move( pnt ); 00580 tip->show(); 00581 } 00582 } 00583 00584 CardViewItem::Field *CardViewItem::fieldAt( const QPoint & itempos ) const 00585 { 00586 int ypos = mView->d->mBFm->height() + 7 + mView->d->mItemMargin; 00587 int iy = itempos.y(); 00588 // skip below caption 00589 if ( iy <= ypos ) 00590 return 0; 00591 // try find a field 00592 bool showEmpty = mView->showEmptyFields(); 00593 int fh = mView->d->mFm->height(); 00594 int maxLines = mView->maxFieldLines(); 00595 Field *f; 00596 for ( f = d->mFieldList.first(); f; f = d->mFieldList.next() ) 00597 { 00598 if ( showEmpty || !f->second.isEmpty() ) 00599 ypos += ( QMIN( f->second.contains('\n')+1, maxLines ) *fh)+2; 00600 if ( iy <= ypos ) 00601 break; 00602 } 00603 return f ? f : 0; 00604 } 00605 //END CardViewItem 00606 00607 //BEGIN CardView 00608 00609 CardView::CardView(QWidget *parent, const char *name) 00610 : QScrollView(parent, name), 00611 d(new CardViewPrivate()) 00612 { 00613 d->mItemList.setAutoDelete(true); 00614 d->mSeparatorList.setAutoDelete(true); 00615 00616 QFont f = font(); 00617 d->mFm = new QFontMetrics(f); 00618 f.setBold(true); 00619 d->mHeaderFont = f; 00620 d->mBFm = new QFontMetrics(f); 00621 d->mTip = ( new CardViewTip( viewport() ) ), 00622 d->mTip->hide(); 00623 d->mTimer = ( new QTimer(this, "mouseTimer") ), 00624 00625 viewport()->setMouseTracking( true ); 00626 viewport()->setFocusProxy(this); 00627 viewport()->setFocusPolicy(WheelFocus); 00628 viewport()->setBackgroundMode(PaletteBase); 00629 00630 connect( d->mTimer, SIGNAL(timeout()), this, SLOT(tryShowFullText()) ); 00631 00632 setBackgroundMode(PaletteBackground, PaletteBase); 00633 00634 // no reason for a vertical scrollbar 00635 setVScrollBarMode(AlwaysOff); 00636 } 00637 00638 CardView::~CardView() 00639 { 00640 delete d->mFm; 00641 delete d->mBFm; 00642 delete d; 00643 d = 0; 00644 } 00645 00646 void CardView::insertItem(CardViewItem *item) 00647 { 00648 d->mItemList.inSort(item); 00649 setLayoutDirty(true); 00650 } 00651 00652 void CardView::takeItem(CardViewItem *item) 00653 { 00654 if ( d->mCurrentItem == item ) 00655 d->mCurrentItem = item->nextItem(); 00656 d->mItemList.take(d->mItemList.findRef(item)); 00657 00658 setLayoutDirty(true); 00659 } 00660 00661 void CardView::clear() 00662 { 00663 d->mItemList.clear(); 00664 00665 setLayoutDirty(true); 00666 } 00667 00668 CardViewItem *CardView::currentItem() 00669 { 00670 if ( ! d->mCurrentItem && d->mItemList.count() ) 00671 d->mCurrentItem = d->mItemList.first(); 00672 return d->mCurrentItem; 00673 } 00674 00675 void CardView::setCurrentItem( CardViewItem *item ) 00676 { 00677 if ( !item ) 00678 return; 00679 else if ( item->cardView() != this ) 00680 { 00681 kdDebug(5720)<<"CardView::setCurrentItem: Item ("<<item<<") not owned! Backing out.."<<endl; 00682 return; 00683 } 00684 else if ( item == currentItem() ) 00685 { 00686 return; 00687 } 00688 00689 if ( d->mSelectionMode == Single ) 00690 { 00691 setSelected( item, true ); 00692 } 00693 else 00694 { 00695 CardViewItem *it = d->mCurrentItem; 00696 d->mCurrentItem = item; 00697 if ( it ) 00698 it->repaintCard(); 00699 item->repaintCard(); 00700 } 00701 if ( ! d->mOnSeparator ) 00702 ensureItemVisible( item ); 00703 emit currentChanged( item ); 00704 } 00705 00706 CardViewItem *CardView::itemAt(const QPoint &viewPos) 00707 { 00708 CardViewItem *item = 0; 00709 QPtrListIterator<CardViewItem> iter(d->mItemList); 00710 bool found = false; 00711 for (iter.toFirst(); iter.current() && !found; ++iter) 00712 { 00713 item = *iter; 00714 //if (item->d->mRect.contains(viewPos)) 00715 if (QRect(item->d->x, item->d->y, d->mItemWidth, item->height()).contains(viewPos)) 00716 found = true; 00717 } 00718 00719 if (found) 00720 return item; 00721 00722 return 0; 00723 } 00724 00725 QRect CardView::itemRect(const CardViewItem *item) 00726 { 00727 //return item->d->mRect; 00728 return QRect(item->d->x, item->d->y, d->mItemWidth, item->height()); 00729 } 00730 00731 void CardView::ensureItemVisible(const CardViewItem *item) 00732 { 00733 ensureVisible(item->d->x , item->d->y, d->mItemSpacing, 0); 00734 ensureVisible(item->d->x + d->mItemWidth, item->d->y, d->mItemSpacing, 0); 00735 } 00736 00737 void CardView::repaintItem(const CardViewItem *item) 00738 { 00739 //repaintContents(item->d->mRect); 00740 repaintContents( QRect(item->d->x, item->d->y, d->mItemWidth, item->height()) ); 00741 } 00742 00743 void CardView::setSelectionMode(CardView::SelectionMode mode) 00744 { 00745 selectAll(false); 00746 00747 d->mSelectionMode = mode; 00748 } 00749 00750 CardView::SelectionMode CardView::selectionMode() const 00751 { 00752 return d->mSelectionMode; 00753 } 00754 00755 void CardView::selectAll(bool state) 00756 { 00757 QPtrListIterator<CardViewItem> iter(d->mItemList); 00758 if (!state) 00759 { 00760 for (iter.toFirst(); iter.current(); ++iter) 00761 { 00762 if ((*iter)->isSelected()) 00763 { 00764 (*iter)->setSelected(false); 00765 (*iter)->repaintCard(); 00766 } 00767 } 00768 //emit selectionChanged(); // WARNING FIXME 00769 emit selectionChanged(0); 00770 } 00771 else if (d->mSelectionMode != CardView::Single) 00772 { 00773 for (iter.toFirst(); iter.current(); ++iter) 00774 { 00775 (*iter)->setSelected(true); 00776 } 00777 00778 if (d->mItemList.count() > 0) 00779 { 00780 // emit, since there must have been at least one selected 00781 emit selectionChanged(); 00782 //repaint();//??? 00783 viewport()->update(); 00784 } 00785 } 00786 } 00787 00788 void CardView::setSelected(CardViewItem *item, bool selected) 00789 { 00790 if ((item == 0) || (item->isSelected() == selected)) 00791 return; 00792 00793 if ( selected && d->mCurrentItem != item ) 00794 { 00795 CardViewItem *it = d->mCurrentItem; 00796 d->mCurrentItem = item; 00797 if ( it ) 00798 it->repaintCard(); 00799 } 00800 00801 if (d->mSelectionMode == CardView::Single) 00802 { 00803 bool b = signalsBlocked(); 00804 blockSignals(true); 00805 selectAll(false); 00806 blockSignals(b); 00807 00808 if (selected) 00809 { 00810 item->setSelected(selected); 00811 item->repaintCard(); 00812 emit selectionChanged(); 00813 emit selectionChanged(item); 00814 } 00815 else 00816 { 00817 emit selectionChanged(); 00818 emit selectionChanged(0); 00819 } 00820 } 00821 else if (d->mSelectionMode == CardView::Multi) 00822 { 00823 item->setSelected(selected); 00824 item->repaintCard(); 00825 emit selectionChanged(); 00826 } 00827 else if (d->mSelectionMode == CardView::Extended) 00828 { 00829 bool b = signalsBlocked(); 00830 blockSignals(true); 00831 selectAll(false); 00832 blockSignals(b); 00833 00834 item->setSelected(selected); 00835 item->repaintCard(); 00836 emit selectionChanged(); 00837 } 00838 } 00839 00840 bool CardView::isSelected(CardViewItem *item) const 00841 { 00842 return (item && item->isSelected()); 00843 } 00844 00845 CardViewItem *CardView::selectedItem() const 00846 { 00847 // find the first selected item 00848 QPtrListIterator<CardViewItem> iter(d->mItemList); 00849 for (iter.toFirst(); iter.current(); ++iter) 00850 { 00851 if ((*iter)->isSelected()) 00852 return *iter; 00853 } 00854 00855 return 0; 00856 } 00857 00858 CardViewItem *CardView::firstItem() const 00859 { 00860 return d->mItemList.first(); 00861 } 00862 00863 int CardView::childCount() const 00864 { 00865 return d->mItemList.count(); 00866 } 00867 00868 CardViewItem *CardView::findItem(const QString &text, const QString &label, 00869 Qt::StringComparisonMode compare) 00870 { 00871 // IF the text is empty, we will return null, since empty text will 00872 // match anything! 00873 if (text.isEmpty()) 00874 return 0; 00875 00876 QPtrListIterator<CardViewItem> iter(d->mItemList); 00877 if (compare & Qt::BeginsWith) 00878 { 00879 QString value; 00880 for (iter.toFirst(); iter.current(); ++iter) 00881 { 00882 value = (*iter)->fieldValue(label).upper(); 00883 if (value.startsWith(text.upper())) 00884 return *iter; 00885 } 00886 } 00887 else 00888 { 00889 kdDebug(5720) << "CardView::findItem: search method not implemented" << endl; 00890 } 00891 00892 return 0; 00893 } 00894 00895 uint CardView::columnWidth() 00896 { 00897 return d->mDrawSeparators ? 00898 d->mItemWidth + ( 2 * d->mItemSpacing ) + d->mSepWidth : 00899 d->mItemWidth + d->mItemSpacing; 00900 } 00901 00902 void CardView::drawContents(QPainter *p, int clipx, int clipy, 00903 int clipw, int cliph) 00904 { 00905 QScrollView::drawContents(p, clipx, clipy, clipw, cliph); 00906 00907 if (d->mLayoutDirty) 00908 calcLayout(); 00909 00910 //kdDebug(5720) << "CardView::drawContents: " << clipx << ", " << clipy 00911 // << ", " << clipw << ", " << cliph << endl; 00912 00913 QColorGroup cg = viewport()->palette().active(); // allow setting costum colors in the viewport pale 00914 00915 QRect clipRect(clipx, clipy, clipw, cliph); 00916 QRect cardRect; 00917 QRect sepRect; 00918 CardViewItem *item; 00919 CardViewSeparator *sep; 00920 00921 // make sure the viewport is a pure background 00922 viewport()->erase(clipRect); 00923 00924 // Now tell the cards to draw, if they are in the clip region 00925 QPtrListIterator<CardViewItem> iter(d->mItemList); 00926 for (iter.toFirst(); iter.current(); ++iter) 00927 { 00928 item = *iter; 00929 cardRect.setRect( item->d->x, item->d->y, d->mItemWidth, item->height() ); 00930 00931 if (clipRect.intersects(cardRect) || clipRect.contains(cardRect)) 00932 { 00933 //kdDebug(5720) << "\trepainting card at: " << cardRect.x() << ", " 00934 // << cardRect.y() << endl; 00935 00936 // Tell the card to paint 00937 p->save(); 00938 p->translate(cardRect.x(), cardRect.y()); 00939 item->paintCard(p, cg); 00940 p->restore(); 00941 } 00942 } 00943 00944 // Followed by the separators if they are in the clip region 00945 QPtrListIterator<CardViewSeparator> sepIter(d->mSeparatorList); 00946 for (sepIter.toFirst(); sepIter.current(); ++sepIter) 00947 { 00948 sep = *sepIter; 00949 sepRect = sep->mRect; 00950 00951 if (clipRect.intersects(sepRect) || clipRect.contains(sepRect)) 00952 { 00953 p->save(); 00954 p->translate(sepRect.x(), sepRect.y()); 00955 sep->paintSeparator(p, cg); 00956 p->restore(); 00957 } 00958 } 00959 } 00960 00961 void CardView::resizeEvent(QResizeEvent *e) 00962 { 00963 QScrollView::resizeEvent(e); 00964 00965 setLayoutDirty(true); 00966 } 00967 00968 void CardView::calcLayout() 00969 { 00970 //kdDebug(5720) << "CardView::calcLayout:" << endl; 00971 00972 // Start in the upper left corner and layout all the 00973 // cars using their height and width 00974 int maxWidth = 0; 00975 int maxHeight = 0; 00976 int xPos = 0; 00977 int yPos = 0; 00978 int cardSpacing = d->mItemSpacing; 00979 00980 // delete the old separators 00981 d->mSeparatorList.clear(); 00982 00983 QPtrListIterator<CardViewItem> iter(d->mItemList); 00984 CardViewItem *item = 0; 00985 CardViewSeparator *sep = 0; 00986 xPos += cardSpacing; 00987 00988 for (iter.toFirst(); iter.current(); ++iter) 00989 { 00990 item = *iter; 00991 00992 yPos += cardSpacing; 00993 00994 if (yPos + item->height() + cardSpacing >= height() - horizontalScrollBar()->height()) 00995 { 00996 maxHeight = QMAX(maxHeight, yPos); 00997 00998 // Drawing in this column would be greater than the height 00999 // of the scroll view, so move to next column 01000 yPos = cardSpacing; 01001 xPos += cardSpacing + maxWidth; 01002 if (d->mDrawSeparators) 01003 { 01004 // Create a separator since the user asked 01005 sep = new CardViewSeparator(this); 01006 sep->mRect.moveTopLeft(QPoint(xPos, yPos+d->mItemMargin)); 01007 xPos += d->mSepWidth + cardSpacing; 01008 d->mSeparatorList.append(sep); 01009 } 01010 01011 maxWidth = 0; 01012 } 01013 01014 item->d->x = xPos; 01015 item->d->y = yPos; 01016 01017 yPos += item->height(); 01018 maxWidth = QMAX(maxWidth, d->mItemWidth); 01019 } 01020 01021 xPos += maxWidth; 01022 resizeContents( xPos + cardSpacing, maxHeight ); 01023 01024 // Update the height of all the separators now that we know the 01025 // max height of a column 01026 QPtrListIterator<CardViewSeparator> sepIter(d->mSeparatorList); 01027 for (sepIter.toFirst(); sepIter.current(); ++sepIter) 01028 { 01029 (*sepIter)->mRect.setHeight(maxHeight - 2*cardSpacing - 2*d->mItemMargin); 01030 } 01031 01032 d->mLayoutDirty = false; 01033 } 01034 01035 CardViewItem *CardView::itemAfter(CardViewItem *item) 01036 { 01037 /*int pos = */d->mItemList.findRef(item); 01038 return d->mItemList.next();//at(pos+1); 01039 } 01040 01041 uint CardView::itemMargin() 01042 { 01043 return d->mItemMargin; 01044 } 01045 01046 void CardView::setItemMargin( uint margin ) 01047 { 01048 if ( margin == d->mItemMargin ) 01049 return; 01050 01051 d->mItemMargin = margin; 01052 setLayoutDirty( true ); 01053 } 01054 01055 uint CardView::itemSpacing() 01056 { 01057 return d->mItemSpacing; 01058 } 01059 01060 void CardView::setItemSpacing( uint spacing ) 01061 { 01062 if ( spacing == d->mItemSpacing ) 01063 return; 01064 01065 d->mItemSpacing = spacing; 01066 setLayoutDirty( true ); 01067 } 01068 01069 void CardView::contentsMousePressEvent(QMouseEvent *e) 01070 { 01071 QScrollView::contentsMousePressEvent(e); 01072 01073 QPoint pos = e->pos(); 01074 d->mLastClickPos = pos; 01075 01076 CardViewItem *item = itemAt(pos); 01077 01078 if (item == 0) 01079 { 01080 d->mLastClickOnItem = false; 01081 if ( d->mOnSeparator) 01082 { 01083 d->mResizeAnchor = e->x()+contentsX(); 01084 d->colspace = (2*d->mItemSpacing) /*+ (2*d->mItemMargin)*/; 01085 int ccw = d->mItemWidth + d->colspace + d->mSepWidth; 01086 d->first = (contentsX()+d->mSepWidth)/ccw; 01087 d->pressed = (d->mResizeAnchor+d->mSepWidth)/ccw; 01088 d->span = d->pressed - d->first; 01089 d->firstX = d->first * ccw; 01090 if ( d->firstX ) d->firstX -= d->mSepWidth; // (no sep in col 0) 01091 } 01092 else 01093 { 01094 selectAll(false); 01095 } 01096 return; 01097 } 01098 01099 d->mLastClickOnItem = true; 01100 01101 CardViewItem *other = d->mCurrentItem; 01102 setCurrentItem( item ); 01103 01104 // Always emit the selection 01105 emit clicked(item); 01106 01107 // The RMB click 01108 if ( e->button() & Qt::RightButton ) { 01109 // clear previous selection 01110 bool blocked = signalsBlocked(); 01111 blockSignals( true ); 01112 selectAll( false ); 01113 blockSignals( blocked ); 01114 01115 // select current item 01116 item->setSelected( true ); 01117 01118 emit contextMenuRequested( item, mapToGlobal( e->pos() ) ); 01119 return; 01120 } 01121 01122 // Check the selection type and update accordingly 01123 if (d->mSelectionMode == CardView::Single) 01124 { 01125 // make sure it isn't already selected 01126 if (item->isSelected()) 01127 return; 01128 01129 bool b = signalsBlocked(); 01130 blockSignals(true); 01131 selectAll(false); 01132 blockSignals(b); 01133 01134 item->setSelected(true); 01135 item->repaintCard(); 01136 emit selectionChanged(item); 01137 } 01138 01139 else if (d->mSelectionMode == CardView::Multi) 01140 { 01141 // toggle the selection 01142 item->setSelected(!item->isSelected()); 01143 item->repaintCard(); 01144 emit selectionChanged(); 01145 } 01146 01147 else if (d->mSelectionMode == CardView::Extended) 01148 { 01149 if ((e->button() & Qt::LeftButton) && 01150 (e->state() & Qt::ShiftButton)) 01151 { 01152 if ( item == other ) return; 01153 01154 bool s = ! item->isSelected(); 01155 01156 if ( s && ! (e->state() & ControlButton) ) 01157 { 01158 bool b = signalsBlocked(); 01159 blockSignals(true); 01160 selectAll(false); 01161 blockSignals(b); 01162 } 01163 01164 int from, to, a, b; 01165 a = d->mItemList.findRef( item ); 01166 b = d->mItemList.findRef( other ); 01167 from = a < b ? a : b; 01168 to = a > b ? a : b; 01169 //kdDebug(5720)<<"selecting items "<<from<<" - "<<to<<" ( "<<s<<" )"<<endl; 01170 CardViewItem *aItem; 01171 for ( ; from <= to; from++ ) 01172 { 01173 aItem = d->mItemList.at( from ); 01174 aItem->setSelected( s ); 01175 repaintItem( aItem ); 01176 } 01177 emit selectionChanged(); 01178 } 01179 else if ((e->button() & Qt::LeftButton) && 01180 (e->state() & Qt::ControlButton)) 01181 { 01182 item->setSelected(!item->isSelected()); 01183 item->repaintCard(); 01184 emit selectionChanged(); 01185 } 01186 01187 else if (e->button() & Qt::LeftButton) 01188 { 01189 bool b = signalsBlocked(); 01190 blockSignals(true); 01191 selectAll(false); 01192 blockSignals(b); 01193 01194 item->setSelected(true); 01195 item->repaintCard(); 01196 emit selectionChanged(); 01197 } 01198 } 01199 } 01200 01201 void CardView::contentsMouseReleaseEvent(QMouseEvent *e) 01202 { 01203 QScrollView::contentsMouseReleaseEvent(e); 01204 01205 if ( d->mResizeAnchor && d->span ) 01206 { 01207 // finish the resizing: 01208 unsetCursor(); 01209 // hide rubber bands 01210 int newiw = d->mItemWidth - ((d->mResizeAnchor - d->mRubberBandAnchor)/d->span); 01211 drawRubberBands( 0 ); 01212 // we should move to reflect the new position if we are scrolled. 01213 if ( contentsX() ) 01214 { 01215 int newX = QMAX( 0, ( d->pressed * ( newiw + d->colspace + d->mSepWidth ) ) - e->x() ); 01216 setContentsPos( newX, contentsY() ); 01217 } 01218 // set new item width 01219 setItemWidth( newiw ); 01220 // reset anchors 01221 d->mResizeAnchor = 0; 01222 d->mRubberBandAnchor = 0; 01223 return; 01224 } 01225 01226 // If there are accel keys, we will not emit signals 01227 if ((e->state() & Qt::ShiftButton) || (e->state() & Qt::ControlButton)) 01228 return; 01229 01230 // Get the item at this position 01231 CardViewItem *item = itemAt(e->pos()); 01232 01233 if (item && KGlobalSettings::singleClick()) 01234 { 01235 emit executed(item); 01236 } 01237 } 01238 01239 void CardView::contentsMouseDoubleClickEvent(QMouseEvent *e) 01240 { 01241 QScrollView::contentsMouseDoubleClickEvent(e); 01242 01243 CardViewItem *item = itemAt(e->pos()); 01244 01245 if (item) 01246 { 01247 d->mCurrentItem = item; 01248 } 01249 01250 if (item && !KGlobalSettings::singleClick()) 01251 { 01252 emit executed(item); 01253 } 01254 emit doubleClicked(item); 01255 } 01256 01257 void CardView::contentsMouseMoveEvent( QMouseEvent *e ) 01258 { 01259 // resizing 01260 if ( d->mResizeAnchor ) 01261 { 01262 int x = e->x(); 01263 if ( x != d->mRubberBandAnchor ) 01264 drawRubberBands( x ); 01265 return; 01266 } 01267 01268 if (d->mLastClickOnItem && (e->state() & Qt::LeftButton) && 01269 ((e->pos() - d->mLastClickPos).manhattanLength() > 4)) { 01270 01271 startDrag(); 01272 return; 01273 } 01274 01275 d->mTimer->start( 500 ); 01276 01277 // see if we are over a separator 01278 // only if we actually have them painted? 01279 if ( d->mDrawSeparators ) 01280 { 01281 int colcontentw = d->mItemWidth + (2*d->mItemSpacing); 01282 int colw = colcontentw + d->mSepWidth; 01283 int m = e->x()%colw; 01284 if ( m >= colcontentw && m > 0 ) 01285 { 01286 setCursor( SplitHCursor ); 01287 d->mOnSeparator = true; 01288 } 01289 else 01290 { 01291 setCursor( ArrowCursor ); 01292 d->mOnSeparator = false; 01293 } 01294 } 01295 } 01296 01297 void CardView::enterEvent( QEvent * ) 01298 { 01299 d->mTimer->start( 500 ); 01300 } 01301 01302 void CardView::leaveEvent( QEvent * ) 01303 { 01304 d->mTimer->stop(); 01305 if (d->mOnSeparator) 01306 { 01307 d->mOnSeparator = false; 01308 setCursor( ArrowCursor ); 01309 } 01310 } 01311 01312 void CardView::focusInEvent( QFocusEvent * ) 01313 { 01314 if (!d->mCurrentItem && d->mItemList.count() ) 01315 { 01316 setCurrentItem( d->mItemList.first() ); 01317 } 01318 else if ( d->mCurrentItem ) 01319 { 01320 d->mCurrentItem->repaintCard(); 01321 } 01322 } 01323 01324 void CardView::focusOutEvent( QFocusEvent * ) 01325 { 01326 if (d->mCurrentItem) 01327 d->mCurrentItem->repaintCard(); 01328 } 01329 01330 void CardView::keyPressEvent( QKeyEvent *e ) 01331 { 01332 if ( ! ( childCount() && d->mCurrentItem ) ) 01333 { 01334 e->ignore(); 01335 return; 01336 } 01337 01338 uint pos = d->mItemList.findRef( d->mCurrentItem ); 01339 CardViewItem *aItem = 0L; // item that gets the focus 01340 CardViewItem *old = d->mCurrentItem; 01341 01342 switch ( e->key() ) 01343 { 01344 case Key_Up: 01345 if ( pos > 0 ) 01346 { 01347 aItem = d->mItemList.at( pos - 1 ); 01348 setCurrentItem( aItem ); 01349 } 01350 break; 01351 case Key_Down: 01352 if ( pos < d->mItemList.count() - 1 ) 01353 { 01354 aItem = d->mItemList.at( pos + 1 ); 01355 setCurrentItem( aItem ); 01356 } 01357 break; 01358 case Key_Left: 01359 { 01360 // look for an item in the previous/next column, starting from 01361 // the vertical middle of the current item. 01362 // FIXME use nice calculatd measures!!! 01363 QPoint aPoint( d->mCurrentItem->d->x, d->mCurrentItem->d->y ); 01364 aPoint -= QPoint( 30,-(d->mCurrentItem->height()/2) ); 01365 aItem = itemAt( aPoint ); 01366 // maybe we hit some space below an item 01367 while ( !aItem && aPoint.y() > 27 ) 01368 { 01369 aPoint -= QPoint( 0, 16 ); 01370 aItem = itemAt( aPoint ); 01371 } 01372 if ( aItem ) 01373 setCurrentItem( aItem ); 01374 } 01375 break; 01376 case Key_Right: 01377 { 01378 // FIXME use nice calculated measures!!! 01379 QPoint aPoint( d->mCurrentItem->d->x + d->mItemWidth, d->mCurrentItem->d->y ); 01380 aPoint += QPoint( 30,(d->mCurrentItem->height()/2) ); 01381 aItem = itemAt( aPoint ); 01382 while ( !aItem && aPoint.y() > 27 ) 01383 { 01384 aPoint -= QPoint( 0, 16 ); 01385 aItem = itemAt( aPoint ); 01386 } 01387 if ( aItem ) 01388 setCurrentItem( aItem ); 01389 } 01390 break; 01391 case Key_Home: 01392 aItem = d->mItemList.first(); 01393 setCurrentItem( aItem ); 01394 break; 01395 case Key_End: 01396 aItem = d->mItemList.last(); 01397 setCurrentItem( aItem ); 01398 break; 01399 case Key_Prior: // PageUp 01400 { 01401 // QListView: "Make the item above the top visible and current" 01402 // TODO if contentsY(), pick the top item of the leftmost visible column 01403 if ( contentsX() <= 0 ) 01404 return; 01405 int cw = columnWidth(); 01406 int theCol = ( QMAX( 0, ( contentsX()/cw) * cw ) ) + d->mItemSpacing; 01407 aItem = itemAt( QPoint( theCol + 1, d->mItemSpacing + 1 ) ); 01408 if ( aItem ) 01409 setCurrentItem( aItem ); 01410 } 01411 break; 01412 case Key_Next: // PageDown 01413 { 01414 // QListView: "Make the item below the bottom visible and current" 01415 // find the first not fully visible column. 01416 // TODO: consider if a partly visible (or even hidden) item at the 01417 // bottom of the rightmost column exists 01418 int cw = columnWidth(); 01419 int theCol = ( (( contentsX() + visibleWidth() )/cw) * cw ) + d->mItemSpacing + 1; 01420 // if separators are on, we may need to we may be one column further right if only the spacing/sep is hidden 01421 if ( d->mDrawSeparators && cw - (( contentsX() + visibleWidth() )%cw) <= int( d->mItemSpacing + d->mSepWidth ) ) 01422 theCol += cw; 01423 01424 // make sure this is not too far right 01425 while ( theCol > contentsWidth() ) 01426 theCol -= columnWidth(); 01427 01428 aItem = itemAt( QPoint( theCol, d->mItemSpacing + 1 ) ); 01429 01430 if ( aItem ) 01431 setCurrentItem( aItem ); 01432 } 01433 break; 01434 case Key_Space: 01435 setSelected( d->mCurrentItem, !d->mCurrentItem->isSelected() ); 01436 emit selectionChanged(); 01437 break; 01438 case Key_Return: 01439 case Key_Enter: 01440 emit returnPressed( d->mCurrentItem ); 01441 emit executed( d->mCurrentItem ); 01442 break; 01443 case Key_Menu: 01444 emit contextMenuRequested( d->mCurrentItem, viewport()->mapToGlobal( 01445 itemRect(d->mCurrentItem).center() ) ); 01446 break; 01447 default: 01448 if ( (e->state() & ControlButton) && e->key() == Key_A ) 01449 { 01450 // select all 01451 selectAll( true ); 01452 break; 01453 } 01454 // if we have a string, do autosearch 01455 else if ( ! e->text().isEmpty() && e->text()[0].isPrint() ) 01456 { 01457 01458 } 01459 break; 01460 } 01461 // handle selection 01462 if ( aItem ) 01463 { 01464 if ( d->mSelectionMode == CardView::Extended ) 01465 { 01466 if ( (e->state() & ShiftButton) ) 01467 { 01468 // shift button: toggle range 01469 // if control button is pressed, leave all items 01470 // and toggle selection current->old current 01471 // otherwise, ?????? 01472 bool s = ! aItem->isSelected(); 01473 int from, to, a, b; 01474 a = d->mItemList.findRef( aItem ); 01475 b = d->mItemList.findRef( old ); 01476 from = a < b ? a : b; 01477 to = a > b ? a : b; 01478 01479 if ( to - from > 1 ) 01480 { 01481 bool b = signalsBlocked(); 01482 blockSignals(true); 01483 selectAll(false); 01484 blockSignals(b); 01485 } 01486 01487 //kdDebug(5720)<<"selecting items "<<from<<" - "<<to<<" ( "<<s<<" )"<<endl; 01488 CardViewItem *item; 01489 for ( ; from <= to; from++ ) 01490 { 01491 item = d->mItemList.at( from ); 01492 item->setSelected( s ); 01493 repaintItem( item ); 01494 } 01495 emit selectionChanged(); 01496 } 01497 else if ( (e->state() & ControlButton) ) 01498 { 01499 // control button: do nothing 01500 } 01501 else 01502 { 01503 // no button: move selection to this item 01504 bool b = signalsBlocked(); 01505 blockSignals(true); 01506 selectAll(false); 01507 blockSignals(b); 01508 01509 setSelected( aItem, true ); 01510 emit selectionChanged(); 01511 } 01512 } 01513 } 01514 } 01515 01516 void CardView::contentsWheelEvent( QWheelEvent * e ) 01517 { 01518 scrollBy(2*e->delta()/-3, 0); 01519 } 01520 01521 void CardView::setLayoutDirty(bool dirty) 01522 { 01523 if (d->mLayoutDirty != dirty) 01524 { 01525 d->mLayoutDirty = dirty; 01526 repaint(); 01527 } 01528 } 01529 01530 void CardView::setDrawCardBorder(bool enabled) 01531 { 01532 if (enabled != d->mDrawCardBorder) 01533 { 01534 d->mDrawCardBorder = enabled; 01535 repaint(); 01536 } 01537 } 01538 01539 bool CardView::drawCardBorder() const 01540 { 01541 return d->mDrawCardBorder; 01542 } 01543 01544 void CardView::setDrawColSeparators(bool enabled) 01545 { 01546 if (enabled != d->mDrawSeparators) 01547 { 01548 d->mDrawSeparators = enabled; 01549 setLayoutDirty(true); 01550 } 01551 } 01552 01553 bool CardView::drawColSeparators() const 01554 { 01555 return d->mDrawSeparators; 01556 } 01557 01558 void CardView::setDrawFieldLabels(bool enabled) 01559 { 01560 if (enabled != d->mDrawFieldLabels) 01561 { 01562 d->mDrawFieldLabels = enabled; 01563 repaint(); 01564 } 01565 } 01566 01567 bool CardView::drawFieldLabels() const 01568 { 01569 return d->mDrawFieldLabels; 01570 } 01571 01572 void CardView::setShowEmptyFields(bool show) 01573 { 01574 if (show != d->mShowEmptyFields) 01575 { 01576 d->mShowEmptyFields = show; 01577 setLayoutDirty(true); 01578 } 01579 } 01580 01581 bool CardView::showEmptyFields() const 01582 { 01583 return d->mShowEmptyFields; 01584 } 01585 01586 void CardView::startDrag() 01587 { 01588 // The default implementation is a no-op. It must be 01589 // reimplemented in a subclass to be useful 01590 } 01591 void CardView::tryShowFullText() 01592 { 01593 d->mTimer->stop(); 01594 // if we have an item 01595 QPoint cpos = viewportToContents( viewport()->mapFromGlobal( QCursor::pos() ) ); 01596 CardViewItem *item = itemAt( cpos ); 01597 if ( item ) 01598 { 01599 // query it for a value to display 01600 //QString s = item ? item->caption() : "(no item)"; 01601 //kdDebug(5720)<<"MOUSE REST: "<<s<<endl; 01602 QPoint ipos = cpos - itemRect( item ).topLeft(); 01603 item->showFullString( ipos, d->mTip ); 01604 } 01605 } 01606 01607 void CardView::drawRubberBands( int pos ) 01608 { 01609 if ( pos && d && 01610 (!d->span || ((pos-d->firstX)/d->span) - d->colspace - d->mSepWidth < MIN_ITEM_WIDTH) ) 01611 return; 01612 01613 int tmpcw = (d->mRubberBandAnchor-d->firstX)/d->span; 01614 int x = d->firstX + tmpcw - d->mSepWidth - contentsX(); 01615 int h = visibleHeight(); 01616 01617 QPainter p( viewport() ); 01618 p.setRasterOp( XorROP ); 01619 p.setPen( gray ); 01620 p.setBrush( gray ); 01621 uint n = d->first; 01622 // erase 01623 if ( d->mRubberBandAnchor ) 01624 do { 01625 p.drawRect( x, 0, 2, h ); 01626 x += tmpcw; 01627 n++; 01628 } while ( x < visibleWidth() && n < d->mSeparatorList.count() ); 01629 // paint new 01630 if ( ! pos ) return; 01631 tmpcw = (pos - d->firstX)/d->span; 01632 n = d->first; 01633 x = d->firstX + tmpcw - d->mSepWidth - contentsX(); 01634 do { 01635 p.drawRect( x, 0, 2, h ); 01636 x += tmpcw; 01637 n++; 01638 } while ( x < visibleWidth() && n < d->mSeparatorList.count() ); 01639 d->mRubberBandAnchor = pos; 01640 } 01641 01642 01643 int CardView::itemWidth() const 01644 { 01645 return d->mItemWidth; 01646 } 01647 01648 void CardView::setItemWidth( int w ) 01649 { 01650 if ( w == d->mItemWidth ) 01651 return; 01652 if ( w < MIN_ITEM_WIDTH ) 01653 w = MIN_ITEM_WIDTH; 01654 d->mItemWidth = w; 01655 setLayoutDirty( true ); 01656 updateContents(); 01657 } 01658 01659 void CardView::setHeaderFont( const QFont &fnt ) 01660 { 01661 d->mHeaderFont = fnt; 01662 delete d->mBFm; 01663 d->mBFm = new QFontMetrics( fnt ); 01664 } 01665 01666 QFont CardView::headerFont() const 01667 { 01668 return d->mHeaderFont; 01669 } 01670 01671 void CardView::setFont( const QFont &fnt ) 01672 { 01673 QScrollView::setFont( fnt ); 01674 delete d->mFm; 01675 d->mFm = new QFontMetrics( fnt ); 01676 } 01677 01678 int CardView::separatorWidth() 01679 { 01680 return d->mSepWidth; 01681 } 01682 01683 void CardView::setSeparatorWidth( int width ) 01684 { 01685 d->mSepWidth = width; 01686 setLayoutDirty( true ); // hmm, actually I could just adjust the x'es... 01687 } 01688 01689 int CardView::maxFieldLines() const 01690 { 01691 return d->mMaxFieldLines; 01692 } 01693 01694 void CardView::setMaxFieldLines( int howmany ) 01695 { 01696 d->mMaxFieldLines = howmany ? howmany : INT_MAX; 01697 // FIXME update, forcing the items to recalc height!! 01698 } 01699 //END Cardview 01700 01701 #include "cardview.moc"
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:36 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003