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