00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <limits.h>
00025
00026 #include <Qt3Support/Q3PtrList>
00027 #include <QtCore/QDateTime>
00028 #include <QtCore/QEvent>
00029 #include <QtCore/QTimer>
00030 #include <QtGui/QCursor>
00031 #include <QtGui/QFocusEvent>
00032 #include <QtGui/QKeyEvent>
00033 #include <QtGui/QLabel>
00034 #include <QtGui/QMouseEvent>
00035 #include <QtGui/QPainter>
00036 #include <QtGui/QResizeEvent>
00037 #include <QtGui/QStyle>
00038 #include <QtGui/QStyleOption>
00039 #include <QtGui/QToolTip>
00040 #include <QtGui/QWheelEvent>
00041
00042 #include <kdebug.h>
00043 #include <kglobalsettings.h>
00044
00045 #include "cardview.h"
00046
00047 #define MIN_ITEM_WIDTH 80
00048
00049 class CardViewTip : public QLabel
00050 {
00051 public:
00052 CardViewTip( QWidget *parent = 0, const char *name = 0 )
00053 : QLabel( parent )
00054 {
00055 setObjectName( name );
00056 setPalette( QToolTip::palette() );
00057 setFrameStyle( Panel | Plain );
00058 setMidLineWidth( 0 );
00059 setIndent( 1 );
00060 }
00061
00062 ~CardViewTip() {}
00063
00064 protected:
00065 void leaveEvent( QEvent* )
00066 {
00067 hide();
00068 }
00069 };
00070
00071
00072
00073
00074
00075 class CardViewItemList : public Q3PtrList<CardViewItem>
00076 {
00077 protected:
00078 virtual int compareItems( Q3PtrCollection::Item item1,
00079 Q3PtrCollection::Item item2 )
00080 {
00081 CardViewItem *cItem1 = (CardViewItem*)item1;
00082 CardViewItem *cItem2 = (CardViewItem*)item2;
00083
00084 if ( cItem1 == cItem2 )
00085 return 0;
00086
00087 if ( (cItem1 == 0) || (cItem2 == 0) )
00088 return cItem1 ? -1 : 1;
00089
00090 if ( cItem1->caption() < cItem2->caption() )
00091 return -1;
00092 else if ( cItem1->caption() > cItem2->caption() )
00093 return 1;
00094
00095 return 0;
00096 }
00097 };
00098
00099 class CardViewSeparator
00100 {
00101 friend class CardView;
00102
00103 public:
00104 CardViewSeparator( CardView *view )
00105 : mView( view )
00106 {
00107 mRect = QRect( 0, 0, view->separatorWidth(), 0 );
00108 }
00109
00110 ~CardViewSeparator() {}
00111
00112 void paintSeparator( QPainter *p, const QPalette &pal )
00113 {
00114 p->fillRect( 0, 0, mRect.width(), mRect.height(),
00115 pal.brush(QPalette::Button) );
00116 }
00117
00118 void repaintSeparator()
00119 {
00120 mView->repaintContents( mRect );
00121 }
00122
00123 private:
00124 CardView *mView;
00125 QRect mRect;
00126 };
00127
00128 class CardViewPrivate
00129 {
00130 public:
00131 CardViewPrivate()
00132 : mSelectionMode( CardView::Multi ),
00133 mDrawCardBorder( true ),
00134 mDrawFieldLabels( true ),
00135 mDrawSeparators( true),
00136 mSepWidth( 2 ),
00137 mShowEmptyFields( false ),
00138 mLayoutDirty( true ),
00139 mLastClickOnItem( false ),
00140 mItemMargin( 0 ),
00141 mItemSpacing( 10 ),
00142 mItemWidth( 200 ),
00143 mMaxFieldLines( INT_MAX ),
00144 mCurrentItem( 0L ),
00145 mLastClickPos( QPoint(0, 0) ),
00146 mRubberBandAnchor( 0 ),
00147 mCompText( QString() )
00148 {}
00149
00150 CardViewItemList mItemList;
00151 Q3PtrList<CardViewSeparator> mSeparatorList;
00152 QFontMetrics *mFm;
00153 QFontMetrics *mBFm;
00154 QFont mHeaderFont;
00155 CardView::SelectionMode mSelectionMode;
00156 bool mDrawCardBorder;
00157 bool mDrawFieldLabels;
00158 bool mDrawSeparators;
00159 int mSepWidth;
00160 bool mShowEmptyFields;
00161 bool mLayoutDirty;
00162 bool mLastClickOnItem;
00163 uint mItemMargin;
00164 uint mItemSpacing;
00165 int mItemWidth;
00166 uint mMaxFieldLines;
00167 CardViewItem *mCurrentItem;
00168 QPoint mLastClickPos;
00169 QTimer *mTimer;
00170 CardViewTip *mTip;
00171 bool mOnSeparator;
00172
00173 int mResizeAnchor;
00174 int mRubberBandAnchor;
00175
00176
00177
00178 int mColspace;
00179 uint mFirst;
00180 int mFirstX;
00181 int mPressed;
00182 int mSpan;
00183
00184 QString mCompText;
00185 QDateTime mCompUpdated;
00186 };
00187
00188 class CardViewItemPrivate
00189 {
00190 public:
00191 CardViewItemPrivate() {}
00192
00193 QString mCaption;
00194 Q3PtrList< CardViewItem::Field > mFieldList;
00195 bool mSelected;
00196 int x;
00197 int y;
00198 int maxLabelWidth;
00199 int hcache;
00200 };
00201
00202
00203 CardViewItem::CardViewItem( CardView *parent, const QString &caption )
00204 : d( new CardViewItemPrivate() ), mView( parent )
00205 {
00206 d->mCaption = caption;
00207
00208 initialize();
00209 }
00210
00211 CardViewItem::~CardViewItem()
00212 {
00213
00214 if ( mView != 0 )
00215 mView->takeItem( this );
00216
00217 delete d;
00218 d = 0;
00219 }
00220
00221 void CardViewItem::initialize()
00222 {
00223 d->mSelected = false;
00224 d->mFieldList.setAutoDelete( true );
00225 d->maxLabelWidth = 0;
00226 d->hcache = 0;
00227
00228
00229 if ( mView != 0 )
00230 mView->insertItem( this );
00231 }
00232
00233 void CardViewItem::paintCard( QPainter *p, const QPalette &pal )
00234 {
00235 if ( !mView )
00236 return;
00237
00238 QPen pen;
00239 QBrush brush;
00240 QFontMetrics fm = *(mView->d->mFm);
00241 QFontMetrics bFm = *(mView->d->mBFm);
00242 bool drawLabels = mView->d->mDrawFieldLabels;
00243 bool drawBorder = mView->d->mDrawCardBorder;
00244 int mg = mView->itemMargin();
00245 int w = mView->itemWidth() - ( mg * 2 );
00246 int h = height() - ( mg * 2 );
00247 const int colonWidth( fm.width( ":" ) );
00248 int labelXPos = 2 + mg;
00249 int labelWidth = qMin( w / 2 - 4 - mg, d->maxLabelWidth + colonWidth + 4 );
00250 int valueXPos = labelWidth + 4 + mg;
00251 int valueWidth = w - labelWidth - 4 - mg;
00252
00253 p->setFont( mView->font() );
00254 labelWidth -= colonWidth;
00255
00256 if ( !drawLabels ) {
00257 valueXPos = labelXPos;
00258 valueWidth = w - 4;
00259 }
00260
00261
00262 if ( isSelected() )
00263 pen = QPen( pal.color( QPalette::Highlight ), 1 );
00264 else
00265 pen = QPen( pal.color( QPalette::Button), 1 );
00266 p->setPen( pen );
00267
00268
00269 if ( drawBorder )
00270 p->drawRect( mg, mg, w, h );
00271
00272
00273 if ( isSelected() )
00274 brush = pal.brush( QPalette::Highlight );
00275 else
00276 brush = pal.brush( QPalette::Button );
00277
00278 p->fillRect( mg, mg, w, 4 + bFm.height(), brush );
00279
00280
00281 p->save();
00282 QFont bFont = mView->headerFont();
00283 p->setFont( bFont );
00284 if ( isSelected() )
00285 p->setPen( pal.color( QPalette::HighlightedText) );
00286 else
00287 p->setPen( pal.color( QPalette::ButtonText) );
00288
00289 p->drawText( 2 + mg, 2 + mg + bFm.ascent(), trimString( d->mCaption, w - 4, bFm ) );
00290 p->restore();
00291
00292
00293 Q3PtrListIterator<CardViewItem::Field> iter( d->mFieldList );
00294 QString label, value;
00295 int yPos = mg + 4 + bFm.height() + fm.height();
00296 p->setPen( pal.text().color() );
00297
00298 int fh = fm.height();
00299 int cln( 0 );
00300 QString tmp;
00301 int maxLines = mView->maxFieldLines();
00302 for ( iter.toFirst(); iter.current(); ++iter ) {
00303 value = (*iter)->second;
00304 if ( value.isEmpty() && ! mView->d->mShowEmptyFields )
00305 continue;
00306
00307 if ( drawLabels ) {
00308 label = trimString( (*iter)->first, labelWidth, fm );
00309 p->drawText( labelXPos, yPos, label + ':' );
00310 }
00311
00312 for ( cln = 0; cln <= maxLines; cln++ ) {
00313 tmp = value.section( '\n', cln, cln );
00314 if ( !tmp.isEmpty() )
00315 p->drawText( valueXPos, yPos + cln * fh, trimString( tmp, valueWidth, fm ) );
00316 else
00317 break;
00318 }
00319
00320 if ( cln == 0 )
00321 cln = 1;
00322 yPos += cln * fh + 2;
00323 }
00324
00325
00326 if ( mView->currentItem() == this && mView->hasFocus() ) {
00327
00328 QStyleOption opt;
00329
00330
00331
00332
00333
00334 mView->style()->drawPrimitive( QStyle::PE_FrameFocusRect, &opt, p, 0 );
00335 }
00336 }
00337
00338 const QString &CardViewItem::caption() const
00339 {
00340 return d->mCaption;
00341 }
00342
00343
00344 int CardViewItem::height( bool allowCache ) const
00345 {
00346
00347 if ( allowCache && d->hcache )
00348 return d->hcache;
00349
00350
00351
00352
00353
00354
00355
00356 int baseHeight = 8 + ( 2 * mView->itemMargin() );
00357
00358
00359
00360
00361 bool sef = mView->showEmptyFields();
00362 int fh = mView->d->mFm->height();
00363 int fieldHeight = 0;
00364 int lines;
00365 int maxLines( mView->maxFieldLines() );
00366 Q3PtrListIterator<CardViewItem::Field> iter( d->mFieldList );
00367 for ( iter.toFirst(); iter.current(); ++iter ) {
00368 if ( !sef && (*iter)->second.isEmpty() )
00369 continue;
00370 lines = qMin( (*iter)->second.count( '\n' ) + 1, maxLines );
00371 fieldHeight += ( lines * fh ) + 2;
00372 }
00373
00374
00375 fieldHeight += mView->d->mBFm->height();
00376 d->hcache = baseHeight + fieldHeight;
00377 return d->hcache;
00378 }
00379
00380 bool CardViewItem::isSelected() const
00381 {
00382 return d->mSelected;
00383 }
00384
00385 void CardViewItem::setSelected( bool selected )
00386 {
00387 d->mSelected = selected;
00388 }
00389
00390 void CardViewItem::insertField( const QString &label, const QString &value )
00391 {
00392 CardViewItem::Field *f = new CardViewItem::Field( label, value );
00393 d->mFieldList.append( f );
00394 d->hcache = 0;
00395
00396 if ( mView ) {
00397 mView->setLayoutDirty( true );
00398 d->maxLabelWidth = qMax( mView->d->mFm->width( label ), d->maxLabelWidth );
00399 }
00400 }
00401
00402 void CardViewItem::removeField( const QString &label )
00403 {
00404 CardViewItem::Field *f;
00405
00406 Q3PtrListIterator<CardViewItem::Field> iter( d->mFieldList );
00407 for ( iter.toFirst(); iter.current(); ++iter ) {
00408 f = *iter;
00409 if ( f->first == label )
00410 break;
00411 }
00412
00413 if (*iter)
00414 d->mFieldList.remove( *iter );
00415 d->hcache = 0;
00416
00417 if ( mView )
00418 mView->setLayoutDirty( true );
00419 }
00420
00421 void CardViewItem::clearFields()
00422 {
00423 d->mFieldList.clear();
00424 d->hcache = 0;
00425
00426 if ( mView )
00427 mView->setLayoutDirty( true );
00428 }
00429
00430 QString CardViewItem::trimString( const QString &text, int width,
00431 QFontMetrics &fm ) const
00432 {
00433 if ( fm.width( text ) <= width )
00434 return text;
00435
00436 QString dots = "...";
00437 int dotWidth = fm.width( dots );
00438 QString trimmed;
00439 int charNum = 0;
00440
00441 while ( fm.width( trimmed ) + dotWidth < width ) {
00442 trimmed += text[ charNum ];
00443 charNum++;
00444 }
00445
00446
00447 trimmed = trimmed.left( trimmed.length() - 1 );
00448 trimmed += dots;
00449
00450 return trimmed;
00451 }
00452
00453 CardViewItem *CardViewItem::nextItem() const
00454 {
00455 CardViewItem *item = 0;
00456
00457 if ( mView )
00458 item = mView->itemAfter( this );
00459
00460 return item;
00461 }
00462
00463 void CardViewItem::repaintCard()
00464 {
00465 if ( mView )
00466 mView->repaintItem( this );
00467 }
00468
00469 void CardViewItem::setCaption( const QString &caption )
00470 {
00471 d->mCaption = caption;
00472 repaintCard();
00473 }
00474
00475 QString CardViewItem::fieldValue( const QString &label ) const
00476 {
00477 Q3PtrListIterator<CardViewItem::Field> iter( d->mFieldList );
00478 for ( iter.toFirst(); iter.current(); ++iter )
00479 if ( (*iter)->first == label )
00480 return (*iter)->second;
00481
00482 return QString();
00483 }
00484
00485
00486 void CardViewItem::showFullString( const QPoint &itempos, CardViewTip *tip )
00487 {
00488 bool trimmed( false );
00489 QString s;
00490 int mrg = mView->itemMargin();
00491 int y = mView->d->mBFm->height() + 6 + mrg;
00492 int w = mView->itemWidth() - (2 * mrg);
00493 int lw;
00494 bool drawLabels = mView->drawFieldLabels();
00495 bool isLabel = drawLabels && itempos.x() < w / 2 ? true : false;
00496
00497 if ( itempos.y() < y ) {
00498 if ( itempos.y() < 8 + mrg || itempos.y() > y - 4 )
00499 return;
00500
00501 s = caption();
00502 trimmed = mView->d->mBFm->width( s ) > w - 4;
00503 y = 2 + mrg;
00504 lw = 0;
00505 isLabel = true;
00506 } else {
00507
00508 Field *f = fieldAt( itempos );
00509 if ( !f || ( !mView->showEmptyFields() && f->second.isEmpty() ) )
00510 return;
00511
00512
00513
00514
00515 int maxLines = mView->maxFieldLines();
00516 bool se = mView->showEmptyFields();
00517 int fh = mView->d->mFm->height();
00518
00519 Field *_f;
00520 for ( _f = d->mFieldList.first(); _f != f; _f = d->mFieldList.next() )
00521 if ( se || ! _f->second.isEmpty() )
00522 y += ( qMin( _f->second.count( '\n' ) + 1, maxLines ) * fh ) + 2;
00523
00524 if ( isLabel && itempos.y() > y + fh )
00525 return;
00526
00527 s = isLabel ? f->first : f->second;
00528
00529 int colonWidth = mView->d->mFm->width(":");
00530 lw = drawLabels ? qMin( w / 2 - 4 - mrg, d->maxLabelWidth + colonWidth + 4 ) : 0;
00531 int mw = isLabel ? lw - colonWidth : w - lw - ( mrg * 2 );
00532 if ( isLabel ) {
00533 trimmed = mView->d->mFm->width( s ) > mw - colonWidth;
00534 } else {
00535 QRect r( mView->d->mFm->boundingRect( 0, 0, INT_MAX, INT_MAX, Qt::AlignTop|Qt::AlignLeft, s ) );
00536 trimmed = r.width() > mw || r.height() / fh > qMin( s.count( '\n' ) + 1, maxLines );
00537 }
00538 }
00539
00540 if ( trimmed ) {
00541 tip->setFont( (isLabel && !lw) ? mView->headerFont() : mView->font() );
00542 tip->setText( s );
00543 tip->adjustSize();
00544
00545 int lx;
00546 lx = isLabel || !drawLabels ? mrg : lw + mrg + 2;
00547 QPoint pnt( mView->contentsToViewport( QPoint( d->x, d->y ) ) );
00548 pnt += QPoint( lx, y );
00549 if ( pnt.x() < 0 )
00550 pnt.setX( 0 );
00551 if ( pnt.x() + tip->width() > mView->visibleWidth() )
00552 pnt.setX( mView->visibleWidth() - tip->width() );
00553 if ( pnt.y() + tip->height() > mView->visibleHeight() )
00554 pnt.setY( qMax( 0, mView->visibleHeight() - tip->height() ) );
00555
00556 tip->move( pnt );
00557 tip->show();
00558 }
00559 }
00560
00561 CardViewItem::Field *CardViewItem::fieldAt( const QPoint & itempos ) const
00562 {
00563 int ypos = mView->d->mBFm->height() + 7 + mView->d->mItemMargin;
00564 int iy = itempos.y();
00565
00566 if ( iy <= ypos )
00567 return 0;
00568
00569 bool showEmpty = mView->showEmptyFields();
00570 int fh = mView->d->mFm->height();
00571 int maxLines = mView->maxFieldLines();
00572 Field *f;
00573 for ( f = d->mFieldList.first(); f; f = d->mFieldList.next() ) {
00574 if ( showEmpty || !f->second.isEmpty() )
00575 ypos += (qMin( f->second.count( '\n' )+1, maxLines ) * fh) + 2;
00576 if ( iy <= ypos )
00577 break;
00578 }
00579
00580 return f ? f : 0;
00581 }
00582
00583
00584 CardView::CardView( QWidget *parent, const char *name )
00585 : Q3ScrollView( parent, name ),
00586 d( new CardViewPrivate() )
00587 {
00588 d->mItemList.setAutoDelete( true );
00589 d->mSeparatorList.setAutoDelete( true );
00590
00591 QFont f = font();
00592 d->mFm = new QFontMetrics( f );
00593 f.setBold( true );
00594 d->mHeaderFont = f;
00595 d->mBFm = new QFontMetrics( f );
00596 d->mTip = new CardViewTip( viewport() );
00597 d->mTip->hide();
00598 d->mTimer = new QTimer( this );
00599 d->mTimer->setObjectName( "mouseTimer" );
00600
00601 viewport()->setMouseTracking( true );
00602 viewport()->setFocusProxy( this );
00603 viewport()->setFocusPolicy( Qt::WheelFocus );
00604 viewport()->setBackgroundRole( QPalette::Base );
00605
00606 connect( d->mTimer, SIGNAL( timeout() ), this, SLOT( tryShowFullText() ) );
00607
00608 setBackgroundRole( QPalette::Background );
00609
00610
00611 setVScrollBarMode( AlwaysOff );
00612 }
00613
00614 CardView::~CardView()
00615 {
00616 delete d->mFm;
00617 delete d->mBFm;
00618 delete d;
00619 d = 0;
00620 }
00621
00622 void CardView::insertItem( CardViewItem *item )
00623 {
00624 d->mItemList.inSort( item );
00625 setLayoutDirty( true );
00626 }
00627
00628 void CardView::takeItem( CardViewItem *item )
00629 {
00630 if ( d->mCurrentItem == item )
00631 d->mCurrentItem = item->nextItem();
00632 d->mItemList.take( d->mItemList.findRef( item ) );
00633
00634 setLayoutDirty( true );
00635 }
00636
00637 void CardView::clear()
00638 {
00639 d->mItemList.clear();
00640
00641 setLayoutDirty( true );
00642 }
00643
00644 CardViewItem *CardView::currentItem() const
00645 {
00646 if ( !d->mCurrentItem && d->mItemList.count() )
00647 d->mCurrentItem = d->mItemList.first();
00648
00649 return d->mCurrentItem;
00650 }
00651
00652 void CardView::setCurrentItem( CardViewItem *item )
00653 {
00654 if ( !item )
00655 return;
00656 else if ( item->cardView() != this ) {
00657 kDebug(5720)<<"CardView::setCurrentItem: Item ("<<item<<") not owned! Backing out..";
00658 return;
00659 } else if ( item == currentItem() ) {
00660 return;
00661 }
00662
00663 if ( d->mSelectionMode == Single ) {
00664 setSelected( item, true );
00665 } else {
00666 CardViewItem *it = d->mCurrentItem;
00667 d->mCurrentItem = item;
00668 if ( it )
00669 it->repaintCard();
00670
00671 item->repaintCard();
00672 }
00673
00674 if ( ! d->mOnSeparator )
00675 ensureItemVisible( item );
00676
00677 emit currentChanged( item );
00678 }
00679
00680 CardViewItem *CardView::itemAt( const QPoint &viewPos ) const
00681 {
00682 CardViewItem *item = 0;
00683 Q3PtrListIterator<CardViewItem> iter( d->mItemList );
00684 bool found = false;
00685 for ( iter.toFirst(); iter.current() && !found; ++iter ) {
00686 item = *iter;
00687 if ( QRect( item->d->x, item->d->y, d->mItemWidth, item->height() ).contains( viewPos ) )
00688 found = true;
00689 }
00690
00691 if ( found )
00692 return item;
00693
00694 return 0;
00695 }
00696
00697 QRect CardView::itemRect( const CardViewItem *item ) const
00698 {
00699 return QRect( item->d->x, item->d->y, d->mItemWidth, item->height() );
00700 }
00701
00702 void CardView::ensureItemVisible( const CardViewItem *item )
00703 {
00704 ensureVisible( item->d->x, item->d->y, d->mItemSpacing, 0 );
00705 ensureVisible( item->d->x + d->mItemWidth, item->d->y, d->mItemSpacing, 0 );
00706 }
00707
00708 void CardView::repaintItem( const CardViewItem *item )
00709 {
00710 repaintContents( QRect( item->d->x, item->d->y, d->mItemWidth, item->height() ) );
00711 }
00712
00713 void CardView::setSelectionMode( CardView::SelectionMode mode )
00714 {
00715 selectAll( false );
00716
00717 d->mSelectionMode = mode;
00718 }
00719
00720 CardView::SelectionMode CardView::selectionMode() const
00721 {
00722 return d->mSelectionMode;
00723 }
00724
00725 void CardView::selectAll( bool state )
00726 {
00727 Q3PtrListIterator<CardViewItem> iter( d->mItemList );
00728 if ( !state ) {
00729 for ( iter.toFirst(); iter.current(); ++iter ) {
00730 if ( (*iter)->isSelected() ) {
00731 (*iter)->setSelected( false );
00732 (*iter)->repaintCard();
00733 }
00734 }
00735
00736 emit selectionChanged( 0 );
00737 } else if ( d->mSelectionMode != CardView::Single ) {
00738 for ( iter.toFirst(); iter.current(); ++iter ) {
00739 (*iter)->setSelected( true );
00740 }
00741
00742 if ( d->mItemList.count() > 0 ) {
00743
00744 emit selectionChanged();
00745 viewport()->update();
00746 }
00747 }
00748 }
00749
00750 void CardView::setSelected( CardViewItem *item, bool selected )
00751 {
00752 if ( (item == 0) || (item->isSelected() == selected) )
00753 return;
00754
00755 if ( selected && d->mCurrentItem != item ) {
00756 CardViewItem *it = d->mCurrentItem;
00757 d->mCurrentItem = item;
00758 if ( it )
00759 it->repaintCard();
00760 }
00761
00762 if ( d->mSelectionMode == CardView::Single ) {
00763 bool b = signalsBlocked();
00764 blockSignals( true );
00765 selectAll( false );
00766 blockSignals( b );
00767
00768 if ( selected ) {
00769 item->setSelected( selected );
00770 item->repaintCard();
00771 emit selectionChanged();
00772 emit selectionChanged( item );
00773 } else {
00774 emit selectionChanged();
00775 emit selectionChanged( 0 );
00776 }
00777 } else if ( d->mSelectionMode == CardView::Multi ) {
00778 item->setSelected( selected );
00779 item->repaintCard();
00780 emit selectionChanged();
00781 } else if ( d->mSelectionMode == CardView::Extended ) {
00782 bool b = signalsBlocked();
00783 blockSignals( true );
00784 selectAll( false );
00785 blockSignals( b );
00786
00787 item->setSelected( selected );
00788 item->repaintCard();
00789 emit selectionChanged();
00790 }
00791 }
00792
00793 bool CardView::isSelected( CardViewItem *item ) const
00794 {
00795 return (item && item->isSelected());
00796 }
00797
00798 CardViewItem *CardView::selectedItem() const
00799 {
00800
00801 Q3PtrListIterator<CardViewItem> iter( d->mItemList );
00802 for ( iter.toFirst(); iter.current(); ++iter ) {
00803 if ( (*iter)->isSelected() )
00804 return *iter;
00805 }
00806
00807 return 0;
00808 }
00809
00810 CardViewItem *CardView::firstItem() const
00811 {
00812 return d->mItemList.first();
00813 }
00814
00815 int CardView::childCount() const
00816 {
00817 return d->mItemList.count();
00818 }
00819
00820 CardViewItem *CardView::findItem( const QString &text, const QString &label,
00821 Q3ListBox::StringComparisonMode compare ) const
00822 {
00823
00824
00825 if ( text.isEmpty() )
00826 return 0;
00827
00828 Q3PtrListIterator<CardViewItem> iter( d->mItemList );
00829 if ( compare & Q3ListBox::BeginsWith ) {
00830 QString value;
00831 for ( iter.toFirst(); iter.current(); ++iter ) {
00832 value = (*iter)->fieldValue( label ).toUpper();
00833 if ( value.startsWith( text.toUpper() ) )
00834 return *iter;
00835 }
00836 } else {
00837 kDebug(5720) <<"CardView::findItem: search method not implemented";
00838 }
00839
00840 return 0;
00841 }
00842
00843 uint CardView::columnWidth() const
00844 {
00845 return d->mDrawSeparators ?
00846 d->mItemWidth + ( 2 * d->mItemSpacing ) + d->mSepWidth :
00847 d->mItemWidth + d->mItemSpacing;
00848 }
00849
00850 void CardView::drawContents( QPainter *p, int clipx, int clipy,
00851 int clipw, int cliph )
00852 {
00853 Q3ScrollView::drawContents( p, clipx, clipy, clipw, cliph );
00854
00855 if ( d->mLayoutDirty )
00856 calcLayout();
00857
00858
00859 QPalette pal = viewport()->palette();
00860
00861 QRect clipRect( clipx, clipy, clipw, cliph );
00862 QRect cardRect;
00863 QRect sepRect;
00864 CardViewItem *item;
00865 CardViewSeparator *sep;
00866
00867
00868 Q3PtrListIterator<CardViewItem> iter( d->mItemList );
00869 for ( iter.toFirst(); iter.current(); ++iter) {
00870 item = *iter;
00871 cardRect.setRect( item->d->x, item->d->y, d->mItemWidth, item->height() );
00872
00873 if ( clipRect.intersects( cardRect ) || clipRect.contains( cardRect ) ) {
00874
00875 p->save();
00876 p->translate( cardRect.x(), cardRect.y() );
00877 item->paintCard( p, pal );
00878 p->restore();
00879 }
00880 }
00881
00882
00883 Q3PtrListIterator<CardViewSeparator> sepIter( d->mSeparatorList );
00884 for ( sepIter.toFirst(); sepIter.current(); ++sepIter ) {
00885 sep = *sepIter;
00886 sepRect = sep->mRect;
00887
00888 if ( clipRect.intersects( sepRect ) || clipRect.contains( sepRect ) ) {
00889 p->save();
00890 p->translate( sepRect.x(), sepRect.y() );
00891 sep->paintSeparator( p, pal );
00892 p->restore();
00893 }
00894 }
00895 }
00896
00897 void CardView::resizeEvent( QResizeEvent *event )
00898 {
00899 Q3ScrollView::resizeEvent( event );
00900
00901 setLayoutDirty( true );
00902 }
00903
00904 void CardView::calcLayout()
00905 {
00906
00907
00908 int maxWidth = 0;
00909 int maxHeight = 0;
00910 int xPos = 0;
00911 int yPos = 0;
00912 int cardSpacing = d->mItemSpacing;
00913
00914
00915 d->mSeparatorList.clear();
00916
00917 Q3PtrListIterator<CardViewItem> iter( d->mItemList );
00918 CardViewItem *item = 0;
00919 CardViewSeparator *sep = 0;
00920 xPos += cardSpacing;
00921
00922 for ( iter.toFirst(); iter.current(); ++iter ) {
00923 item = *iter;
00924
00925 yPos += cardSpacing;
00926
00927 if ( yPos + item->height() + cardSpacing >= height() - horizontalScrollBar()->height() ) {
00928 maxHeight = qMax( maxHeight, yPos );
00929
00930
00931
00932 yPos = cardSpacing;
00933 xPos += cardSpacing + maxWidth;
00934 if ( d->mDrawSeparators ) {
00935
00936 sep = new CardViewSeparator( this );
00937 sep->mRect.moveTopLeft( QPoint( xPos, yPos + d->mItemMargin ) );
00938 xPos += d->mSepWidth + cardSpacing;
00939 d->mSeparatorList.append( sep );
00940 }
00941
00942 maxWidth = 0;
00943 }
00944
00945 item->d->x = xPos;
00946 item->d->y = yPos;
00947
00948 yPos += item->height();
00949 maxWidth = qMax( maxWidth, d->mItemWidth );
00950 }
00951
00952 xPos += maxWidth;
00953 resizeContents( xPos + cardSpacing, maxHeight );
00954
00955
00956
00957 Q3PtrListIterator<CardViewSeparator> sepIter( d->mSeparatorList );
00958 for ( sepIter.toFirst(); sepIter.current(); ++sepIter )
00959 (*sepIter)->mRect.setHeight( maxHeight - 2 * cardSpacing - 2 * d->mItemMargin );
00960
00961 d->mLayoutDirty = false;
00962 }
00963
00964 CardViewItem *CardView::itemAfter( const CardViewItem *item ) const
00965 {
00966 d->mItemList.findRef( item );
00967 return d->mItemList.next();
00968 }
00969
00970 uint CardView::itemMargin() const
00971 {
00972 return d->mItemMargin;
00973 }
00974
00975 void CardView::setItemMargin( uint margin )
00976 {
00977 if ( margin == d->mItemMargin )
00978 return;
00979
00980 d->mItemMargin = margin;
00981 setLayoutDirty( true );
00982 }
00983
00984 uint CardView::itemSpacing() const
00985 {
00986 return d->mItemSpacing;
00987 }
00988
00989 void CardView::setItemSpacing( uint spacing )
00990 {
00991 if ( spacing == d->mItemSpacing )
00992 return;
00993
00994 d->mItemSpacing = spacing;
00995 setLayoutDirty( true );
00996 }
00997
00998 void CardView::contentsMousePressEvent( QMouseEvent *e )
00999 {
01000 Q3ScrollView::contentsMousePressEvent( e );
01001
01002 QPoint pos = contentsToViewport( e->pos() );
01003 d->mLastClickPos = e->pos();
01004
01005 CardViewItem *item = itemAt( e->pos() );
01006
01007 if ( item == 0 ) {
01008 d->mLastClickOnItem = false;
01009 if ( d->mOnSeparator) {
01010 d->mResizeAnchor = e->x() + contentsX();
01011 d->mColspace = (2 * d->mItemSpacing);
01012 int ccw = d->mItemWidth + d->mColspace + d->mSepWidth;
01013 d->mFirst = (contentsX() + d->mSepWidth) / ccw;
01014 d->mPressed = (d->mResizeAnchor + d->mSepWidth) / ccw;
01015 d->mSpan = d->mPressed - d->mFirst;
01016 d->mFirstX = d->mFirst * ccw;
01017 if ( d->mFirstX )
01018 d->mFirstX -= d->mSepWidth;
01019 } else {
01020 selectAll( false );
01021 }
01022
01023 return;
01024 }
01025
01026 d->mLastClickOnItem = true;
01027
01028 CardViewItem *other = d->mCurrentItem;
01029 setCurrentItem( item );
01030
01031
01032 emit clicked( item );
01033
01034
01035 if (