summaryrefslogtreecommitdiffabout
path: root/kaddressbook/views/cardview.cpp
authorzautrix <zautrix>2004-06-26 19:01:18 (UTC)
committer zautrix <zautrix>2004-06-26 19:01:18 (UTC)
commitb9aad1f15dc600e4dbe4c62d3fcced6363188ba3 (patch) (side-by-side diff)
tree2c3d4004fb21c72cba65793859f9bcd8ffd3a49c /kaddressbook/views/cardview.cpp
downloadkdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.zip
kdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.tar.gz
kdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.tar.bz2
Initial revision
Diffstat (limited to 'kaddressbook/views/cardview.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--kaddressbook/views/cardview.cpp1719
1 files changed, 1719 insertions, 0 deletions
diff --git a/kaddressbook/views/cardview.cpp b/kaddressbook/views/cardview.cpp
new file mode 100644
index 0000000..65f793c
--- a/dev/null
+++ b/kaddressbook/views/cardview.cpp
@@ -0,0 +1,1719 @@
+/*
+ This file is part of KAddressBook.
+ Copyright (c) 2002 Mike Pilone <mpilone@slac.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+//BEGIN Includes
+#include "cardview.h"
+
+#include <limits.h>
+
+#include <qpainter.h>
+#include <qtimer.h>
+#include <qdatetime.h>
+#include <qlabel.h>
+#include <qstyle.h>
+#include <qcursor.h>
+#include <qtooltip.h>
+
+#include <kdebug.h>
+#include <kglobalsettings.h>
+//END includes
+
+#define MIN_ITEM_WIDTH 80
+
+//BEGIN Helpers
+//////////////////////////////////////
+// CardViewTip
+class CardViewTip : public QLabel {
+ public:
+ CardViewTip(QWidget *parent=0, const char *name=0) : QLabel( parent, name )
+ {
+ setPalette( QToolTip::palette() );
+ setFrameStyle( Panel|Plain );
+ setMidLineWidth(0);
+ setIndent(1);
+ }
+
+ ~CardViewTip() {};
+ protected:
+ void leaveEvent( QEvent * )
+ {
+ hide();
+ }
+};
+
+//////////////////////////////////////
+// CardViewItemList
+
+
+//
+// Warning: make sure you use findRef() instead of find() to find an
+// item! Only the pointer value is unique in the list.
+//
+class CardViewItemList : public QPtrList<CardViewItem>
+{
+ protected:
+ virtual int compareItems(QPtrCollection::Item item1,
+ QPtrCollection::Item item2)
+ {
+ CardViewItem *cItem1 = (CardViewItem*)item1;
+ CardViewItem *cItem2 = (CardViewItem*)item2;
+
+ if ( cItem1 == cItem2 )
+ return 0;
+
+ if ((cItem1 == 0) || (cItem2 == 0))
+ return cItem1 ? -1 : 1;
+
+ if (cItem1->caption() < cItem2->caption())
+ return -1;
+
+ else if (cItem1->caption() > cItem2->caption())
+ return 1;
+
+ return 0;
+ }
+
+ private:
+ /*int find( const CardViewItem * )
+ {
+ qDebug("DON'T USE CardViewItemList::find( item )! Use findRef( item )!");
+ }*/
+};
+
+//////////////////////////////////////
+// CardViewSeparator
+class CardViewSeparator
+{
+ friend class CardView;
+
+ public:
+ CardViewSeparator(CardView *view)
+ : mView(view)
+ {
+ mRect = QRect(0, 0, view->separatorWidth(), 0);
+ }
+
+ ~CardViewSeparator() {}
+
+ void paintSeparator(QPainter *p, QColorGroup &cg)
+ {
+ p->fillRect(0, 0, mRect.width(), mRect.height(),
+ cg.brush(QColorGroup::Button));
+ }
+
+ void repaintSeparator()
+ {
+ mView->repaintContents(mRect);
+ }
+
+ private:
+ CardView *mView;
+ QRect mRect;
+};
+
+//END Helpers
+
+//BEGIN Private Data
+
+class CardViewPrivate
+{
+ public:
+ CardViewPrivate()
+ : mSelectionMode( CardView::Multi ),
+ mDrawCardBorder( true ),
+ mDrawFieldLabels( true ),
+ mDrawSeparators( true),
+ mSepWidth( 2 ),
+ mShowEmptyFields( false ),
+ mLayoutDirty( true ),
+ mLastClickOnItem( false ),
+ mItemMargin( 0 ),
+ mItemSpacing( 10 ),
+ mItemWidth( 200 ),
+ mMaxFieldLines( INT_MAX ),
+ mCurrentItem( 0L ),
+ mLastClickPos( QPoint(0, 0) ),
+ mRubberBandAnchor( 0 ),
+ mCompText( QString::null ),
+ mResizeAnchor(0)
+ {};
+
+ CardViewItemList mItemList;
+ QPtrList<CardViewSeparator> mSeparatorList;
+ QFontMetrics *mFm;
+ QFontMetrics *mBFm; // bold font
+ QFont mHeaderFont; // custom header font
+ CardView::SelectionMode mSelectionMode;
+ bool mDrawCardBorder;
+ bool mDrawFieldLabels;
+ bool mDrawSeparators;
+ int mSepWidth;
+ bool mShowEmptyFields;
+ bool mLayoutDirty;
+ bool mLastClickOnItem;
+ uint mItemMargin; // internal margin in items
+ uint mItemSpacing; // spacing between items, column seperators and border
+ int mItemWidth; // width of all items
+ uint mMaxFieldLines; // Max lines to dispaly pr field
+ CardViewItem *mCurrentItem;
+ QPoint mLastClickPos;
+ QTimer *mTimer; // times out if mouse rests for more than 500 msecs
+ CardViewTip *mTip; // passed to the item under a resting cursor to display full text
+ bool mOnSeparator; // set/reset on mouse movement
+ // for resizing by dragging the separators
+ int mResizeAnchor; // uint, ulong? the mouse down separator left
+ int mRubberBandAnchor; // for erasing rubber bands
+ // data used for resizing.
+ // as they are beeded by each mouse move while resizing, we store them here,
+ // saving 8 calculations in each mouse move.
+ int colspace; // amount of space between items pr column
+ uint first; // the first col to anchor at for painting rubber bands
+ int firstX; // X position of first in pixel
+ int pressed; // the colummn that was pressed on at resizing start
+ int span; // pressed - first
+ // key completion
+ QString mCompText; // current completion string
+ QDateTime mCompUpdated; // ...was updated at this time
+};
+
+class CardViewItemPrivate
+{
+ public:
+ CardViewItemPrivate() :
+ x( 0 ),
+ y( 0 ),
+ mSelected( false ){};
+
+
+ QString mCaption;
+ QPtrList< CardViewItem::Field > mFieldList;
+ bool mSelected;
+ int x; // horizontal position, set by the view
+ int y; // vertical position, set by the view
+ int maxLabelWidth; // the width of the widest label, according to the view font.
+ int hcache; // height cache
+};
+//END Private Data
+
+//BEGIN CardViewItem
+
+CardViewItem::CardViewItem(CardView *parent, QString caption)
+ : d(new CardViewItemPrivate()), mView(parent)
+{
+ d->mCaption = caption;
+
+ initialize();
+}
+
+CardViewItem::~CardViewItem()
+{
+ // Remove ourself from the view
+ if (mView != 0)
+ mView->takeItem(this);
+
+ delete d;
+ d = 0;
+}
+
+void CardViewItem::initialize()
+{
+ d->mSelected = false;
+ d->mFieldList.setAutoDelete(true);
+ d->maxLabelWidth = 0;
+ d->hcache=0;
+
+ //calcRect();
+
+ // Add ourself to the view
+ if (mView != 0)
+ mView->insertItem(this);
+}
+
+void CardViewItem::paintCard(QPainter *p, QColorGroup &cg)
+{
+
+ if (!mView)
+ return;
+
+ QPen pen;
+ QBrush brush;
+ QFontMetrics fm = *(mView->d->mFm);
+ QFontMetrics bFm = *(mView->d->mBFm);
+ bool drawLabels = mView->d->mDrawFieldLabels;
+ bool drawBorder = mView->d->mDrawCardBorder;
+ int mg = mView->itemMargin();
+ int w = mView->itemWidth() - (mg*2);
+ int h = height() - (mg*2);
+ const int colonWidth( fm.width(":") );
+ int labelXPos = 2 + mg;
+ int labelWidth = QMIN( w/2 - 4 - mg, d->maxLabelWidth + colonWidth + 4 );
+ int valueXPos = labelWidth + 4 + mg;
+ int valueWidth = w - labelWidth - 4 - mg;
+
+ p->setFont( mView->font() );
+ labelWidth -= colonWidth; // extra space for the colon
+
+ if (!drawLabels)
+ {
+ valueXPos = labelXPos;
+ valueWidth = w - 4;
+ }
+
+ // Draw a simple box
+ if (isSelected())
+ pen = QPen(cg.highlight(), 1);
+ else
+ pen = QPen(cg.button(), 1);
+ p->setPen(pen);
+
+ // Draw the border - this is only draw if the user asks for it.
+ if (drawBorder)
+ p->drawRect( mg, mg, w, h );
+
+ // set the proper pen color for the caption box
+ if (isSelected())
+ brush = cg.brush(QColorGroup::Highlight);
+ else
+ brush = cg.brush(QColorGroup::Button);
+
+ p->fillRect(mg, mg, w, 4 + bFm.height(), brush);
+
+ // Now paint the caption
+ p->save();
+ QFont bFont = mView->headerFont();
+ //bFont.setBold(true);
+ p->setFont(bFont);
+ if (isSelected())
+ p->setPen(cg.highlightedText());
+ else
+ p->setPen(cg.buttonText());
+ p->drawText(2+mg, 2+mg + bFm.ascent()/*bFm.height()*//*-bFm.descent()*//*-bFm.leading()*/, trimString(d->mCaption, w-4, bFm));
+ p->restore();
+
+ // Go through the fields and draw them
+ QPtrListIterator< CardViewItem::Field > iter(d->mFieldList);
+ QString label, value;
+ int yPos = mg + 4 + bFm.height()/* + 1*/ + fm.height(); // why the + 1 ??? (anders)
+ p->setPen(cg.text());
+
+ int fh = fm.height();
+ int cln( 0 );
+ QString tmp;
+ int maxLines = mView->maxFieldLines();
+ for (iter.toFirst(); iter.current(); ++iter)
+ {
+ value = (*iter)->second;
+ if ( value.isEmpty() && ! mView->d->mShowEmptyFields )
+ continue;
+
+ if (drawLabels)
+ {
+ label = trimString((*iter)->first, labelWidth, fm);
+ p->drawText(labelXPos, yPos, label + ":");
+ }
+/* US original
+ for (cln=0; cln <= maxLines; cln++)
+ {
+ tmp = value.section('\n',cln,cln);
+ if ( !tmp.isEmpty() ) p->drawText( valueXPos, yPos + cln*fh, trimString( tmp, valueWidth, fm ) );
+ else break;
+ }
+*/
+
+//US new implementation
+ QStringList strlst = QStringList::split('\n', value, true);
+
+ for (cln=0; cln <= maxLines && cln <= (int)strlst.count(); cln++)
+ {
+ tmp = strlst[cln];
+
+ if ( !tmp.isEmpty() )
+ p->drawText( valueXPos, yPos + cln*fh, trimString( tmp, valueWidth, fm ) );
+ else
+ break;
+
+ }
+
+ if ( cln == 0 ) cln = 1;
+ yPos += cln * fh + 2;
+ }
+
+ // if we are the current item and the view has focus, draw focus rect
+ if ( mView->currentItem() == this && mView->hasFocus() )
+ {
+/*US
+ mView->style().drawPrimitive( QStyle::PE_FocusRect, p,
+ QRect(0, 0, mView->itemWidth(), h+(2*mg)), cg,
+ QStyle::Style_FocusAtBorder,
+ QStyleOption( isSelected() ? cg.highlight() : cg.base() ) );
+*/
+
+ const QColor pHighl = isSelected() ? cg.highlight() : cg.base();
+ const QRect r(0, 0, mView->itemWidth(), h+(2*mg));
+#ifndef DESKTOP_VERSION
+ mView->style().drawFocusRect(p, r, cg, &pHighl, true);
+#endif
+ }
+}
+
+const QString &CardViewItem::caption() const
+{
+ return d->mCaption;
+}
+
+
+int CardViewItem::height( bool allowCache ) const
+{
+ // use cache
+ if ( allowCache && d->hcache )
+ return d->hcache;
+
+ // Base height:
+ // 2 for line width
+ // 2 for top caption pad
+ // 2 for bottom caption pad
+ // 2 pad for the end
+ // + 2 times the advised margin
+ int baseHeight = 8 + ( 2 * mView->itemMargin() );
+
+ // size of font for each field
+ // 2 pad for each field
+
+ // anders: if the view does not show empty fields, check for value
+ bool sef = mView->showEmptyFields();
+ int fh = mView->d->mFm->height();//lineSpacing(); // font height
+ //int sp = QMAX( 0, 2- mView->d->mFm->leading() ); // field spacing NOTE make a property
+ int fieldHeight = 0;
+ int lines;
+ int maxLines( mView->maxFieldLines() );
+ QPtrListIterator< CardViewItem::Field > iter(d->mFieldList);
+ for (iter.toFirst(); iter.current(); ++iter)
+ {
+ if ( !sef && (*iter)->second.isEmpty() )
+ continue;
+ lines = QMIN( (*iter)->second.contains('\n') + 1, maxLines );
+ fieldHeight += ( lines * fh ) + 2;//sp;
+ }
+
+ // height of caption font (bold)
+ fieldHeight += mView->d->mBFm->height();
+ d->hcache = baseHeight + fieldHeight;
+ return d->hcache;
+}
+
+bool CardViewItem::isSelected() const
+{
+ return d->mSelected;
+}
+
+void CardViewItem::setSelected(bool selected)
+{
+ d->mSelected = selected;
+}
+
+void CardViewItem::insertField(const QString &label, const QString &value)
+{
+ CardViewItem::Field *f = new CardViewItem::Field(label, value);
+ d->mFieldList.append(f);
+ d->hcache=0;
+
+ if (mView)
+ {
+ mView->setLayoutDirty(true);
+ d->maxLabelWidth = QMAX( mView->d->mFm->width( label ), d->maxLabelWidth );
+ }
+}
+
+void CardViewItem::removeField(const QString &label)
+{
+ CardViewItem::Field *f;
+
+ QPtrListIterator< CardViewItem::Field > iter(d->mFieldList);
+ for (iter.toFirst(); iter.current(); ++iter)
+ {
+ f = *iter;
+ if (f->first == label)
+ break;
+ }
+
+ if (*iter)
+ d->mFieldList.remove(*iter);
+ d->hcache = 0;
+
+ if (mView)
+ mView->setLayoutDirty(true);
+}
+
+void CardViewItem::clearFields()
+{
+ d->mFieldList.clear();
+ d->hcache = 0;
+
+ if (mView)
+ mView->setLayoutDirty(true);
+}
+
+QString CardViewItem::trimString(const QString &text, int width,
+ QFontMetrics &fm)
+{
+ if (fm.width(text) <= width)
+ return text;
+
+ QString dots = "...";
+ int dotWidth = fm.width(dots);
+ QString trimmed;
+ int charNum = 0;
+
+ while (fm.width(trimmed) + dotWidth < width)
+ {
+ trimmed += text[charNum];
+ charNum++;
+ }
+
+ // Now trim the last char, since it put the width over the top
+ trimmed = trimmed.left(trimmed.length()-1);
+ trimmed += dots;
+
+ return trimmed;
+}
+
+CardViewItem *CardViewItem::nextItem()
+{
+ CardViewItem *item = 0;
+
+ if (mView)
+ item = mView->itemAfter(this);
+
+ return item;
+}
+
+void CardViewItem::repaintCard()
+{
+ if (mView)
+ mView->repaintItem(this);
+}
+
+void CardViewItem::setCaption(const QString &caption)
+{
+ d->mCaption = caption;
+ repaintCard();
+}
+
+QString CardViewItem::fieldValue(const QString &label)
+{
+ QPtrListIterator< CardViewItem::Field > iter(d->mFieldList);
+ for (iter.toFirst(); iter.current(); ++iter)
+ if ((*iter)->first == label)
+ return (*iter)->second;
+
+ return QString();
+}
+
+
+void CardViewItem::showFullString( const QPoint &itempos, CardViewTip *tip )
+{
+ bool trimmed( false );
+ QString s;
+ int mrg = mView->itemMargin();
+ int y = mView->d->mBFm->height() + 6 + mrg;
+ int w = mView->itemWidth() - (2*mrg);
+ int lw;
+ bool drawLabels = mView->drawFieldLabels();
+ bool isLabel = drawLabels && itempos.x() < w/2 ? true : false;
+
+ if ( itempos.y() < y )
+ {
+ if ( itempos.y() < 8 + mrg || itempos.y() > y - 4 )
+ return;
+ // this is the caption
+ s = caption();
+ trimmed = mView->d->mBFm->width( s ) > w - 4;
+ y = 2 + mrg;
+ lw = 0;
+ isLabel=true;
+ } else {
+ // find the field
+ Field *f = fieldAt( itempos );
+ if ( !f || ( !mView->showEmptyFields() && f->second.isEmpty() ) )
+ return;
+
+ // y position:
+ // header font height + 4px hader margin + 2px leading + item margin
+ // + actual field index * (fontheight + 2px leading)
+ int maxLines = mView->maxFieldLines();
+ bool se = mView->showEmptyFields();
+ int fh = mView->d->mFm->height();
+// {
+ Field *_f;
+ for (_f = d->mFieldList.first(); _f != f; _f = d->mFieldList.next())
+ if ( se || ! _f->second.isEmpty() )
+ y += ( QMIN(_f->second.contains('\n')+1, maxLines) * fh ) + 2;
+// }
+ if ( isLabel && itempos.y() > y + fh )
+ return;
+ // label or data?
+ s = isLabel ? f->first : f->second;
+ // trimmed?
+ int colonWidth = mView->d->mFm->width(":");
+ lw = drawLabels ? // label width
+ QMIN( w/2 - 4 - mrg, d->maxLabelWidth + colonWidth + 4 ) :
+ 0;
+ int mw = isLabel ? lw - colonWidth : w - lw - (mrg*2); // max width for string
+ if ( isLabel )
+ {
+ trimmed = mView->d->mFm->width( s ) > mw - colonWidth;
+ } else {
+ QRect r( mView->d->mFm->boundingRect( 0, 0, INT_MAX, INT_MAX, Qt::AlignTop|Qt::AlignLeft, s ) );
+ trimmed = r.width() > mw || r.height()/fh > QMIN(s.contains('\n') + 1, maxLines);
+ }
+ }
+ if ( trimmed )
+ {
+ tip->setFont( (isLabel && !lw) ? mView->headerFont() : mView->font() ); // if condition is true, a header
+ tip->setText( s );
+ tip->adjustSize();
+ // find a proper position
+ int lx;
+ lx = isLabel || !drawLabels ? mrg : lw + mrg + 2 /*-1*/;
+ QPoint pnt(mView->contentsToViewport( QPoint(d->x, d->y) ));
+ pnt += QPoint(lx, y);
+ if ( pnt.x() < 0 )
+ pnt.setX( 0 );
+ if ( pnt.x() + tip->width() > mView->visibleWidth() )
+ pnt.setX( mView->visibleWidth() - tip->width() );
+ if ( pnt.y() + tip->height() > mView->visibleHeight() )
+ pnt.setY( QMAX( 0, mView->visibleHeight() - tip->height() ) );
+ // show
+ tip->move( pnt );
+ tip->show();
+ }
+}
+
+CardViewItem::Field *CardViewItem::fieldAt( const QPoint & itempos ) const
+{
+ int ypos = mView->d->mBFm->height() + 7 + mView->d->mItemMargin;
+ int iy = itempos.y();
+ // skip below caption
+ if ( iy <= ypos )
+ return 0;
+ // try find a field
+ bool showEmpty = mView->showEmptyFields();
+ int fh = mView->d->mFm->height();
+ int maxLines = mView->maxFieldLines();
+ Field *f;
+ for ( f = d->mFieldList.first(); f; f = d->mFieldList.next() )
+ {
+ if ( showEmpty || !f->second.isEmpty() )
+ ypos += ( QMIN( f->second.contains('\n')+1, maxLines ) *fh)+2;
+ if ( iy <= ypos )
+ break;
+ }
+ return f ? f : 0;
+}
+//END CardViewItem
+
+//BEGIN CardView
+
+CardView::CardView(QWidget *parent, const char *name)
+ : QScrollView(parent, name),
+ d(new CardViewPrivate())
+{
+ d->mItemList.setAutoDelete(true);
+ d->mSeparatorList.setAutoDelete(true);
+
+ QFont f = font();
+ d->mFm = new QFontMetrics(f);
+ f.setBold(true);
+ d->mHeaderFont = f;
+ d->mBFm = new QFontMetrics(f);
+ d->mTip = ( new CardViewTip( viewport() ) ),
+ d->mTip->hide();
+ d->mTimer = ( new QTimer(this, "mouseTimer") ),
+
+ viewport()->setMouseTracking( true );
+ viewport()->setFocusProxy(this);
+ viewport()->setFocusPolicy(WheelFocus);
+ viewport()->setBackgroundMode(PaletteBase);
+
+ connect( d->mTimer, SIGNAL(timeout()), this, SLOT(tryShowFullText()) );
+
+//US setBackgroundMode(PaletteBackground, PaletteBase);
+ setBackgroundMode(PaletteBackground);
+
+ // no reason for a vertical scrollbar
+ setVScrollBarMode(AlwaysOff);
+}
+
+CardView::~CardView()
+{
+ delete d->mFm;
+ delete d->mBFm;
+ delete d;
+ d = 0;
+}
+
+void CardView::insertItem(CardViewItem *item)
+{
+ d->mItemList.inSort(item);
+ setLayoutDirty(true);
+}
+
+void CardView::takeItem(CardViewItem *item)
+{
+ if ( d->mCurrentItem == item )
+ d->mCurrentItem = item->nextItem();
+ d->mItemList.take(d->mItemList.findRef(item));
+
+ setLayoutDirty(true);
+}
+
+void CardView::clear()
+{
+ d->mItemList.clear();
+
+ setLayoutDirty(true);
+}
+
+CardViewItem *CardView::currentItem()
+{
+ if ( ! d->mCurrentItem && d->mItemList.count() )
+ d->mCurrentItem = d->mItemList.first();
+ return d->mCurrentItem;
+}
+
+void CardView::setCurrentItem( CardViewItem *item )
+{
+ if ( !item )
+ return;
+ else if ( item->cardView() != this )
+ {
+ kdDebug(5720)<<"CardView::setCurrentItem: Item ("<<item<<") not owned! Backing out.."<<endl;
+ return;
+ }
+ else if ( item == currentItem() )
+ {
+ return;
+ }
+
+ if ( d->mSelectionMode == Single )
+ {
+ setSelected( item, true );
+ }
+ else
+ {
+ CardViewItem *it = d->mCurrentItem;
+ d->mCurrentItem = item;
+ if ( it )
+ it->repaintCard();
+ item->repaintCard();
+ }
+ if ( ! d->mOnSeparator )
+ ensureItemVisible( item );
+ emit currentChanged( item );
+}
+
+CardViewItem *CardView::itemAt(const QPoint &viewPos)
+{
+ CardViewItem *item = 0;
+ QPtrListIterator<CardViewItem> iter(d->mItemList);
+ bool found = false;
+ for (iter.toFirst(); iter.current() && !found; ++iter)
+ {
+ item = *iter;
+ //if (item->d->mRect.contains(viewPos))
+ if (QRect(item->d->x, item->d->y, d->mItemWidth, item->height()).contains(viewPos))
+ found = true;
+ }
+
+ if (found)
+ return item;
+
+ return 0;
+}
+
+QRect CardView::itemRect(const CardViewItem *item)
+{
+ //return item->d->mRect;
+ return QRect(item->d->x, item->d->y, d->mItemWidth, item->height());
+}
+
+void CardView::ensureItemVisible(const CardViewItem *item)
+{
+ ensureVisible(item->d->x , item->d->y, d->mItemSpacing, 0);
+ ensureVisible(item->d->x + d->mItemWidth, item->d->y, d->mItemSpacing, 0);
+}
+
+void CardView::repaintItem(const CardViewItem *item)
+{
+ //repaintContents(item->d->mRect);
+ repaintContents( QRect(item->d->x, item->d->y, d->mItemWidth, item->height()) );
+}
+
+void CardView::setSelectionMode(CardView::SelectionMode mode)
+{
+ selectAll(false);
+
+ d->mSelectionMode = mode;
+}
+
+CardView::SelectionMode CardView::selectionMode() const
+{
+ return d->mSelectionMode;
+}
+
+void CardView::selectAll(bool state)
+{
+ QPtrListIterator<CardViewItem> iter(d->mItemList);
+ if (!state)
+ {
+ for (iter.toFirst(); iter.current(); ++iter)
+ {
+ if ((*iter)->isSelected())
+ {
+ (*iter)->setSelected(false);
+ (*iter)->repaintCard();
+ }
+ }
+ //emit selectionChanged(); // WARNING FIXME
+ emit selectionChanged(0);
+ }
+ else if (d->mSelectionMode != CardView::Single)
+ {
+ for (iter.toFirst(); iter.current(); ++iter)
+ {
+ (*iter)->setSelected(true);
+ }
+
+ if (d->mItemList.count() > 0)
+ {
+ // emit, since there must have been at least one selected
+ emit selectionChanged();
+ //repaint();//???
+ viewport()->update();
+ }
+ }
+}
+
+void CardView::setSelected(CardViewItem *item, bool selected)
+{
+ if ((item == 0) || (item->isSelected() == selected))
+ return;
+
+ if ( selected && d->mCurrentItem != item )
+ {
+ CardViewItem *it = d->mCurrentItem;
+ d->mCurrentItem = item;
+ if ( it )
+ it->repaintCard();
+ }
+
+ if (d->mSelectionMode == CardView::Single)
+ {
+ bool b = signalsBlocked();
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(b);
+
+ if (selected)
+ {
+ item->setSelected(selected);
+ item->repaintCard();
+ emit selectionChanged();
+ emit selectionChanged(item);
+ }
+ else
+ {
+ emit selectionChanged();
+ emit selectionChanged(0);
+ }
+ }
+ else if (d->mSelectionMode == CardView::Multi)
+ {
+ item->setSelected(selected);
+ item->repaintCard();
+ emit selectionChanged();
+ }
+ else if (d->mSelectionMode == CardView::Extended)
+ {
+ bool b = signalsBlocked();
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(b);
+
+ item->setSelected(selected);
+ item->repaintCard();
+ emit selectionChanged();
+ }
+}
+
+bool CardView::isSelected(CardViewItem *item) const
+{
+ return (item && item->isSelected());
+}
+
+CardViewItem *CardView::selectedItem() const
+{
+ // find the first selected item
+ QPtrListIterator<CardViewItem> iter(d->mItemList);
+ for (iter.toFirst(); iter.current(); ++iter)
+ {
+ if ((*iter)->isSelected())
+ return *iter;
+ }
+
+ return 0;
+}
+
+CardViewItem *CardView::firstItem() const
+{
+ return d->mItemList.first();
+}
+
+int CardView::childCount() const
+{
+ return d->mItemList.count();
+}
+/*US
+CardViewItem *CardView::findItem(const QString &text, const QString &label,
+ Qt::StringComparisonMode compare)
+{
+ // IF the text is empty, we will return null, since empty text will
+ // match anything!
+ if (text.isEmpty())
+ return 0;
+
+ QPtrListIterator<CardViewItem> iter(d->mItemList);
+ if (compare & Qt::BeginsWith)
+ {
+ QString value;
+ for (iter.toFirst(); iter.current(); ++iter)
+ {
+ value = (*iter)->fieldValue(label).upper();
+ if (value.startsWith(text.upper()))
+ return *iter;
+ }
+ }
+ else
+ {
+ kdDebug(5720) << "CardView::findItem: search method not implemented" << endl;
+ }
+
+ return 0;
+}
+*/
+
+uint CardView::columnWidth()
+{
+ return d->mDrawSeparators ?
+ d->mItemWidth + ( 2 * d->mItemSpacing ) + d->mSepWidth :
+ d->mItemWidth + d->mItemSpacing;
+}
+
+void CardView::drawContents(QPainter *p, int clipx, int clipy,
+ int clipw, int cliph)
+{
+ QScrollView::drawContents(p, clipx, clipy, clipw, cliph);
+
+ if (d->mLayoutDirty)
+ calcLayout();
+
+ //kdDebug() << "CardView::drawContents: " << clipx << ", " << clipy
+ // << ", " << clipw << ", " << cliph << endl;
+
+ QColorGroup cg = viewport()->palette().active(); // allow setting costum colors in the viewport pale
+
+ QRect clipRect(clipx, clipy, clipw, cliph);
+ QRect cardRect;
+ QRect sepRect;
+ CardViewItem *item;
+ CardViewSeparator *sep;
+
+ // make sure the viewport is a pure background
+ viewport()->erase(clipRect);
+
+ // Now tell the cards to draw, if they are in the clip region
+ QPtrListIterator<CardViewItem> iter(d->mItemList);
+ for (iter.toFirst(); iter.current(); ++iter)
+ {
+ item = *iter;
+ cardRect.setRect( item->d->x, item->d->y, d->mItemWidth, item->height() );
+
+ if (clipRect.intersects(cardRect) || clipRect.contains(cardRect))
+ {
+ //kdDebug() << "\trepainting card at: " << cardRect.x() << ", "
+ // << cardRect.y() << endl;
+
+ // Tell the card to paint
+ p->save();
+ p->translate(cardRect.x(), cardRect.y());
+ item->paintCard(p, cg);
+ p->restore();
+ }
+ }
+
+ // Followed by the separators if they are in the clip region
+ QPtrListIterator<CardViewSeparator> sepIter(d->mSeparatorList);
+ for (sepIter.toFirst(); sepIter.current(); ++sepIter)
+ {
+ sep = *sepIter;
+ sepRect = sep->mRect;
+
+ if (clipRect.intersects(sepRect) || clipRect.contains(sepRect))
+ {
+ p->save();
+ p->translate(sepRect.x(), sepRect.y());
+ sep->paintSeparator(p, cg);
+ p->restore();
+ }
+ }
+}
+
+void CardView::resizeEvent(QResizeEvent *e)
+{
+ QScrollView::resizeEvent(e);
+
+ setLayoutDirty(true);
+}
+
+void CardView::calcLayout()
+{
+ //kdDebug() << "CardView::calcLayout:" << endl;
+
+ // Start in the upper left corner and layout all the
+ // cars using their height and width
+ int maxWidth = 0;
+ int maxHeight = 0;
+ int xPos = 0;
+ int yPos = 0;
+ int cardSpacing = d->mItemSpacing;
+
+ // delete the old separators
+ d->mSeparatorList.clear();
+
+ QPtrListIterator<CardViewItem> iter(d->mItemList);
+ CardViewItem *item = 0;
+ CardViewSeparator *sep = 0;
+ xPos += cardSpacing;
+
+ for (iter.toFirst(); iter.current(); ++iter)
+ {
+ item = *iter;
+
+ yPos += cardSpacing;
+
+ if (yPos + item->height() + cardSpacing >= height() - horizontalScrollBar()->height())
+ {
+ maxHeight = QMAX(maxHeight, yPos);
+
+ // Drawing in this column would be greater than the height
+ // of the scroll view, so move to next column
+ yPos = cardSpacing;
+ xPos += cardSpacing + maxWidth;
+ if (d->mDrawSeparators)
+ {
+ // Create a separator since the user asked
+ sep = new CardViewSeparator(this);
+ sep->mRect.moveTopLeft(QPoint(xPos, yPos+d->mItemMargin));
+ xPos += d->mSepWidth + cardSpacing;
+ d->mSeparatorList.append(sep);
+ }
+
+ maxWidth = 0;
+ }
+
+ item->d->x = xPos;
+ item->d->y = yPos;
+
+ yPos += item->height();
+ maxWidth = QMAX(maxWidth, d->mItemWidth);
+ }
+
+ xPos += maxWidth;
+ resizeContents( xPos + cardSpacing, maxHeight );
+
+ // Update the height of all the separators now that we know the
+ // max height of a column
+ QPtrListIterator<CardViewSeparator> sepIter(d->mSeparatorList);
+ for (sepIter.toFirst(); sepIter.current(); ++sepIter)
+ {
+ (*sepIter)->mRect.setHeight(maxHeight - 2*cardSpacing - 2*d->mItemMargin);
+ }
+
+ d->mLayoutDirty = false;
+}
+
+CardViewItem *CardView::itemAfter(CardViewItem *item)
+{
+ /*int pos = */d->mItemList.findRef(item);
+ return d->mItemList.next();//at(pos+1);
+}
+
+uint CardView::itemMargin()
+{
+ return d->mItemMargin;
+}
+
+void CardView::setItemMargin( uint margin )
+{
+ if ( margin == d->mItemMargin )
+ return;
+
+ d->mItemMargin = margin;
+ setLayoutDirty( true );
+}
+
+uint CardView::itemSpacing()
+{
+ return d->mItemSpacing;
+}
+
+void CardView::setItemSpacing( uint spacing )
+{
+ if ( spacing == d->mItemSpacing )
+ return;
+
+ d->mItemSpacing = spacing;
+ setLayoutDirty( true );
+}
+
+void CardView::contentsMousePressEvent(QMouseEvent *e)
+{
+ QScrollView::contentsMousePressEvent(e);
+
+ QPoint pos = e->pos();
+ d->mLastClickPos = pos;
+
+ CardViewItem *item = itemAt(pos);
+
+ if (item == 0)
+ {
+ d->mLastClickOnItem = false;
+ if ( d->mOnSeparator)
+ {
+ d->mResizeAnchor = e->x()+contentsX();
+ d->colspace = (2*d->mItemSpacing) /*+ (2*d->mItemMargin)*/;
+ int ccw = d->mItemWidth + d->colspace + d->mSepWidth;
+ d->first = (contentsX()+d->mSepWidth)/ccw;
+ d->pressed = (d->mResizeAnchor+d->mSepWidth)/ccw;
+ d->span = d->pressed - d->first;
+ d->firstX = d->first * ccw;
+ if ( d->firstX ) d->firstX -= d->mSepWidth; // (no sep in col 0)
+ }
+ else
+ {
+ selectAll(false);
+ }
+ return;
+ }
+
+ d->mLastClickOnItem = true;
+
+ CardViewItem *other = d->mCurrentItem;
+ setCurrentItem( item );
+
+ // Always emit the selection
+ emit clicked(item);
+
+ // Check the selection type and update accordingly
+ if (d->mSelectionMode == CardView::Single)
+ {
+ // make sure it isn't already selected
+ if (item->isSelected())
+ return;
+
+ bool b = signalsBlocked();
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(b);
+
+ item->setSelected(true);
+ item->repaintCard();
+ emit selectionChanged(item);
+ }
+
+ else if (d->mSelectionMode == CardView::Multi)
+ {
+ // toggle the selection
+ item->setSelected(!item->isSelected());
+ item->repaintCard();
+ emit selectionChanged();
+ }
+
+ else if (d->mSelectionMode == CardView::Extended)
+ {
+ if ((e->button() & Qt::LeftButton) &&
+ (e->state() & Qt::ShiftButton))
+ {
+ if ( item == other ) return;
+
+ bool s = ! item->isSelected();
+
+ if ( s && ! (e->state() & ControlButton) )
+ {
+ bool b = signalsBlocked();
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(b);
+ }
+
+ int from, to, a, b;
+ a = d->mItemList.findRef( item );
+ b = d->mItemList.findRef( other );
+ from = a < b ? a : b;
+ to = a > b ? a : b;
+ //kdDebug()<<"selecting items "<<from<<" - "<<to<<" ( "<<s<<" )"<<endl;
+ CardViewItem *aItem;
+ for ( ; from <= to; from++ )
+ {
+ aItem = d->mItemList.at( from );
+ aItem->setSelected( s );
+ repaintItem( aItem );
+ }
+ emit selectionChanged();
+ }
+ else if ((e->button() & Qt::LeftButton) &&
+ (e->state() & Qt::ControlButton))
+ {
+ item->setSelected(!item->isSelected());
+ item->repaintCard();
+ emit selectionChanged();
+ }
+
+ else if (e->button() & Qt::LeftButton)
+ {
+ bool b = signalsBlocked();
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(b);
+
+ item->setSelected(true);
+ item->repaintCard();
+ emit selectionChanged();
+ }
+ }
+
+}
+
+void CardView::contentsMouseReleaseEvent(QMouseEvent *e)
+{
+ QScrollView::contentsMouseReleaseEvent(e);
+
+ if ( d->mResizeAnchor )
+ {
+ // finish the resizing:
+ unsetCursor();
+ // hide rubber bands
+ int newiw = d->mItemWidth - ((d->mResizeAnchor - d->mRubberBandAnchor)/d->span);
+ drawRubberBands( 0 );
+ // we should move to reflect the new position if we are scrolled.
+ if ( contentsX() )
+ {
+ int newX = QMAX( 0, ( d->pressed * ( newiw + d->colspace + d->mSepWidth ) ) - e->x() );
+ setContentsPos( newX, contentsY() );
+ }
+ // set new item width
+ setItemWidth( newiw );
+ // reset anchors
+ d->mResizeAnchor = 0;
+ d->mRubberBandAnchor = 0;
+ return;
+ }
+
+ // If there are accel keys, we will not emit signals
+ if ((e->state() & Qt::ShiftButton) || (e->state() & Qt::ControlButton))
+ return;
+
+ // Get the item at this position
+ CardViewItem *item = itemAt(e->pos());
+
+ if (item && KGlobalSettings::singleClick())
+ {
+ emit executed(item);
+ }
+}
+
+void CardView::contentsMouseDoubleClickEvent(QMouseEvent *e)
+{
+ QScrollView::contentsMouseDoubleClickEvent(e);
+
+ CardViewItem *item = itemAt(e->pos());
+
+ if (item)
+ {
+ d->mCurrentItem = item;
+ }
+
+ if (item && !KGlobalSettings::singleClick())
+ {
+ emit executed(item);
+ }
+ emit doubleClicked(item);
+}
+
+void CardView::contentsMouseMoveEvent( QMouseEvent *e )
+{
+ // resizing
+ if ( d->mResizeAnchor )
+ {
+ int x = e->x();
+ if ( x != d->mRubberBandAnchor )
+ drawRubberBands( x );
+ return;
+ }
+
+ if (d->mLastClickOnItem && (e->state() & Qt::LeftButton) &&
+ ((e->pos() - d->mLastClickPos).manhattanLength() > 4)) {
+
+ startDrag();
+ return;
+ }
+
+ d->mTimer->start( 500 );
+
+ // see if we are over a separator
+ // only if we actually have them painted?
+ if ( d->mDrawSeparators )
+ {
+ int colcontentw = d->mItemWidth + (2*d->mItemSpacing);
+ int colw = colcontentw + d->mSepWidth;
+ int m = e->x()%colw;
+ if ( m >= colcontentw && m > 0 )
+ {
+ setCursor( SplitVCursor ); // Why does this fail sometimes?
+ d->mOnSeparator = true;
+ }
+ else
+ {
+ setCursor( ArrowCursor );
+ d->mOnSeparator = false;
+ }
+ }
+}
+
+void CardView::enterEvent( QEvent * )
+{
+ d->mTimer->start( 500 );
+}
+
+void CardView::leaveEvent( QEvent * )
+{
+ d->mTimer->stop();
+ if (d->mOnSeparator)
+ {
+ d->mOnSeparator = false;
+ setCursor( ArrowCursor );
+ }
+}
+
+void CardView::focusInEvent( QFocusEvent * )
+{
+ if (!d->mCurrentItem && d->mItemList.count() )
+ {
+ setCurrentItem( d->mItemList.first() );
+ }
+ else if ( d->mCurrentItem )
+ {
+ d->mCurrentItem->repaintCard();
+ }
+}
+
+void CardView::focusOutEvent( QFocusEvent * )
+{
+ if (d->mCurrentItem)
+ d->mCurrentItem->repaintCard();
+}
+
+void CardView::keyPressEvent( QKeyEvent *e )
+{
+ if ( ! ( childCount() && d->mCurrentItem ) )
+ {
+ e->ignore();
+ return;
+ }
+
+ uint pos = d->mItemList.findRef( d->mCurrentItem );
+ CardViewItem *aItem = 0L; // item that gets the focus
+ CardViewItem *old = d->mCurrentItem;
+
+ switch ( e->key() )
+ {
+ case Key_Up:
+ if ( pos > 0 )
+ {
+ aItem = d->mItemList.at( pos - 1 );
+ setCurrentItem( aItem );
+ }
+ break;
+ case Key_Down:
+ if ( pos < d->mItemList.count() - 1 )
+ {
+ aItem = d->mItemList.at( pos + 1 );
+ setCurrentItem( aItem );
+ }
+ break;
+ case Key_Left:
+ {
+ // look for an item in the previous/next column, starting from
+ // the vertical middle of the current item.
+ // FIXME use nice calculatd measures!!!
+ QPoint aPoint( d->mCurrentItem->d->x, d->mCurrentItem->d->y );
+ aPoint -= QPoint( 30,-(d->mCurrentItem->height()/2) );
+ aItem = itemAt( aPoint );
+ // maybe we hit some space below an item
+ while ( !aItem && aPoint.y() > 27 )
+ {
+ aPoint -= QPoint( 0, 16 );
+ aItem = itemAt( aPoint );
+ }
+ if ( aItem )
+ setCurrentItem( aItem );
+ }
+ break;
+ case Key_Right:
+ {
+ // FIXME use nice calculated measures!!!
+ QPoint aPoint( d->mCurrentItem->d->x + d->mItemWidth, d->mCurrentItem->d->y );
+ aPoint += QPoint( 30,(d->mCurrentItem->height()/2) );
+ aItem = itemAt( aPoint );
+ while ( !aItem && aPoint.y() > 27 )
+ {
+ aPoint -= QPoint( 0, 16 );
+ aItem = itemAt( aPoint );
+ }
+ if ( aItem )
+ setCurrentItem( aItem );
+ }
+ break;
+ case Key_Home:
+ aItem = d->mItemList.first();
+ setCurrentItem( aItem );
+ break;
+ case Key_End:
+ aItem = d->mItemList.last();
+ setCurrentItem( aItem );
+ break;
+ case Key_Prior: // PageUp
+ {
+ // QListView: "Make the item above the top visible and current"
+ // TODO if contentsY(), pick the top item of the leftmost visible column
+ if ( contentsX() <= 0 )
+ return;
+ int cw = columnWidth();
+ int theCol = ( QMAX( 0, ( contentsX()/cw) * cw ) ) + d->mItemSpacing;
+ aItem = itemAt( QPoint( theCol + 1, d->mItemSpacing + 1 ) );
+ if ( aItem )
+ setCurrentItem( aItem );
+ }
+ break;
+ case Key_Next: // PageDown
+ {
+ // QListView: "Make the item below the bottom visible and current"
+ // find the first not fully visible column.
+ // TODO: consider if a partly visible (or even hidden) item at the
+ // bottom of the rightmost column exists
+ int cw = columnWidth();
+ int theCol = ( (( contentsX() + visibleWidth() )/cw) * cw ) + d->mItemSpacing + 1;
+ // if separators are on, we may need to we may be one column further right if only the spacing/sep is hidden
+ if ( d->mDrawSeparators && cw - (( contentsX() + visibleWidth() )%cw) <= int( d->mItemSpacing + d->mSepWidth ) )
+ theCol += cw;
+
+ // make sure this is not too far right
+ while ( theCol > contentsWidth() )
+ theCol -= columnWidth();
+
+ aItem = itemAt( QPoint( theCol, d->mItemSpacing + 1 ) );
+
+ if ( aItem )
+ setCurrentItem( aItem );
+ }
+ break;
+ case Key_Space:
+ setSelected( d->mCurrentItem, !d->mCurrentItem->isSelected() );
+ emit selectionChanged();
+ break;
+ case Key_Return:
+ case Key_Enter:
+ emit returnPressed( d->mCurrentItem );
+ emit executed( d->mCurrentItem );
+ break;
+ default:
+ if ( (e->state() & ControlButton) && e->key() == Key_A )
+ {
+ // select all
+ selectAll( true );
+ break;
+ }
+ // if we have a string, do autosearch
+ else if ( ! e->text().isEmpty() && e->text()[0].isPrint() )
+ {
+
+ }
+ break;
+ }
+ // handle selection
+ if ( aItem )
+ {
+ if ( d->mSelectionMode == CardView::Extended )
+ {
+ if ( (e->state() & ShiftButton) )
+ {
+ // shift button: toggle range
+ // if control button is pressed, leave all items
+ // and toggle selection current->old current
+ // otherwise, ??????
+ bool s = ! aItem->isSelected();
+ int from, to, a, b;
+ a = d->mItemList.findRef( aItem );
+ b = d->mItemList.findRef( old );
+ from = a < b ? a : b;
+ to = a > b ? a : b;
+
+ if ( to - from > 1 )
+ {
+ bool b = signalsBlocked();
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(b);
+ }
+
+ //kdDebug()<<"selecting items "<<from<<" - "<<to<<" ( "<<s<<" )"<<endl;
+ CardViewItem *item;
+ for ( ; from <= to; from++ )
+ {
+ item = d->mItemList.at( from );
+ item->setSelected( s );
+ repaintItem( item );
+ }
+ emit selectionChanged();
+ }
+ else if ( (e->state() & ControlButton) )
+ {
+ // control button: do nothing
+ }
+ else
+ {
+ // no button: move selection to this item
+ bool b = signalsBlocked();
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(b);
+
+ setSelected( aItem, true );
+ emit selectionChanged();
+ }
+ }
+ }
+}
+
+void CardView::contentsWheelEvent( QWheelEvent * e )
+{
+ scrollBy(2*e->delta()/-3, 0);
+}
+
+void CardView::setLayoutDirty(bool dirty)
+{
+ if (d->mLayoutDirty != dirty)
+ {
+ d->mLayoutDirty = dirty;
+ repaint();
+ }
+}
+
+void CardView::setDrawCardBorder(bool enabled)
+{
+ if (enabled != d->mDrawCardBorder)
+ {
+ d->mDrawCardBorder = enabled;
+ repaint();
+ }
+}
+
+bool CardView::drawCardBorder() const
+{
+ return d->mDrawCardBorder;
+}
+
+void CardView::setDrawColSeparators(bool enabled)
+{
+ if (enabled != d->mDrawSeparators)
+ {
+ d->mDrawSeparators = enabled;
+ setLayoutDirty(true);
+ }
+}
+
+bool CardView::drawColSeparators() const
+{
+ return d->mDrawSeparators;
+}
+
+void CardView::setDrawFieldLabels(bool enabled)
+{
+ if (enabled != d->mDrawFieldLabels)
+ {
+ d->mDrawFieldLabels = enabled;
+ repaint();
+ }
+}
+
+bool CardView::drawFieldLabels() const
+{
+ return d->mDrawFieldLabels;
+}
+
+void CardView::setShowEmptyFields(bool show)
+{
+ if (show != d->mShowEmptyFields)
+ {
+ d->mShowEmptyFields = show;
+ setLayoutDirty(true);
+ }
+}
+
+bool CardView::showEmptyFields() const
+{
+ return d->mShowEmptyFields;
+}
+
+void CardView::startDrag()
+{
+ // The default implementation is a no-op. It must be
+ // reimplemented in a subclass to be useful
+}
+void CardView::tryShowFullText()
+{
+ d->mTimer->stop();
+ // if we have an item
+ QPoint cpos = viewportToContents( viewport()->mapFromGlobal( QCursor::pos() ) );
+ CardViewItem *item = itemAt( cpos );
+ if ( item )
+ {
+ // query it for a value to display
+ //QString s = item ? item->caption() : "(no item)";
+ //kdDebug()<<"MOUSE REST: "<<s<<endl;
+ QPoint ipos = cpos - itemRect( item ).topLeft();
+ item->showFullString( ipos, d->mTip );
+ }
+}
+
+void CardView::drawRubberBands( int pos )
+{
+ if ( pos && ((pos-d->firstX)/d->span) - d->colspace - d->mSepWidth < MIN_ITEM_WIDTH ) return;
+
+ int tmpcw = (d->mRubberBandAnchor-d->firstX)/d->span;
+ int x = d->firstX + tmpcw - d->mSepWidth - contentsX();
+ int h = visibleHeight();
+
+ QPainter p( viewport() );
+ p.setRasterOp( XorROP );
+ p.setPen( gray );
+ p.setBrush( gray );
+ uint n = d->first;
+ // erase
+ if ( d->mRubberBandAnchor )
+ do {
+ p.drawRect( x, 0, 2, h );
+ x += tmpcw;
+ n++;
+ } while ( x < visibleWidth() && n < d->mSeparatorList.count() );
+ // paint new
+ if ( ! pos ) return;
+ tmpcw = (pos - d->firstX)/d->span;
+ n = d->first;
+ x = d->firstX + tmpcw - d->mSepWidth - contentsX();
+ do {
+ p.drawRect( x, 0, 2, h );
+ x += tmpcw;
+ n++;
+ } while ( x < visibleWidth() && n < d->mSeparatorList.count() );
+ d->mRubberBandAnchor = pos;
+}
+
+
+int CardView::itemWidth() const
+{
+ return d->mItemWidth;
+}
+
+void CardView::setItemWidth( int w )
+{
+ if ( w == d->mItemWidth )
+ return;
+ if ( w < MIN_ITEM_WIDTH )
+ w = MIN_ITEM_WIDTH;
+ d->mItemWidth = w;
+ setLayoutDirty( true );
+#ifndef KAB_EMBEDDED
+ updateContents();
+#else //KAB_EMBEDDED
+//US updateContents( d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight() );
+qDebug("CardView::setItemWidth has to be verified");
+ updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
+#endif //KAB_EMBEDDED
+}
+
+void CardView::setHeaderFont( const QFont &fnt )
+{
+ d->mHeaderFont = fnt;
+ delete d->mBFm;
+ d->mBFm = new QFontMetrics( fnt );
+}
+
+QFont CardView::headerFont() const
+{
+ return d->mHeaderFont;
+}
+
+void CardView::setFont( const QFont &fnt )
+{
+ QScrollView::setFont( fnt );
+ delete d->mFm;
+ d->mFm = new QFontMetrics( fnt );
+}
+
+int CardView::separatorWidth()
+{
+ return d->mSepWidth;
+}
+
+void CardView::setSeparatorWidth( int width )
+{
+ d->mSepWidth = width;
+ setLayoutDirty( true ); // hmm, actually I could just adjust the x'es...
+}
+
+int CardView::maxFieldLines() const
+{
+ return d->mMaxFieldLines;
+}
+
+void CardView::setMaxFieldLines( int howmany )
+{
+ d->mMaxFieldLines = howmany ? howmany : INT_MAX;
+ // FIXME update, forcing the items to recalc height!!
+}
+//END Cardview
+
+#ifndef KAB_EMBEDDED
+#include "cardview.moc"
+#endif //KAB_EMBEDDED