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) (unidiff)
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 @@
1/*
2 This file is part of KAddressBook.
3 Copyright (c) 2002 Mike Pilone <mpilone@slac.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 As a special exception, permission is given to link this program
20 with any edition of Qt, and distribute the resulting executable,
21 without including the source code for Qt in the source distribution.
22*/
23
24//BEGIN Includes
25#include "cardview.h"
26
27#include <limits.h>
28
29#include <qpainter.h>
30#include <qtimer.h>
31#include <qdatetime.h>
32#include <qlabel.h>
33#include <qstyle.h>
34#include <qcursor.h>
35#include <qtooltip.h>
36
37#include <kdebug.h>
38#include <kglobalsettings.h>
39//END includes
40
41#define MIN_ITEM_WIDTH 80
42
43//BEGIN Helpers
44//////////////////////////////////////
45// CardViewTip
46class CardViewTip : public QLabel {
47 public:
48 CardViewTip(QWidget *parent=0, const char *name=0) : QLabel( parent, name )
49 {
50 setPalette( QToolTip::palette() );
51 setFrameStyle( Panel|Plain );
52 setMidLineWidth(0);
53 setIndent(1);
54 }
55
56 ~CardViewTip() {};
57 protected:
58 void leaveEvent( QEvent * )
59 {
60 hide();
61 }
62};
63
64//////////////////////////////////////
65// CardViewItemList
66
67
68//
69// Warning: make sure you use findRef() instead of find() to find an
70// item! Only the pointer value is unique in the list.
71//
72class CardViewItemList : public QPtrList<CardViewItem>
73{
74 protected:
75 virtual int compareItems(QPtrCollection::Item item1,
76 QPtrCollection::Item item2)
77 {
78 CardViewItem *cItem1 = (CardViewItem*)item1;
79 CardViewItem *cItem2 = (CardViewItem*)item2;
80
81 if ( cItem1 == cItem2 )
82 return 0;
83
84 if ((cItem1 == 0) || (cItem2 == 0))
85 return cItem1 ? -1 : 1;
86
87 if (cItem1->caption() < cItem2->caption())
88 return -1;
89
90 else if (cItem1->caption() > cItem2->caption())
91 return 1;
92
93 return 0;
94 }
95
96 private:
97 /*int find( const CardViewItem * )
98 {
99 qDebug("DON'T USE CardViewItemList::find( item )! Use findRef( item )!");
100 }*/
101};
102
103//////////////////////////////////////
104// CardViewSeparator
105class CardViewSeparator
106{
107 friend class CardView;
108
109 public:
110 CardViewSeparator(CardView *view)
111 : mView(view)
112 {
113 mRect = QRect(0, 0, view->separatorWidth(), 0);
114 }
115
116 ~CardViewSeparator() {}
117
118 void paintSeparator(QPainter *p, QColorGroup &cg)
119 {
120 p->fillRect(0, 0, mRect.width(), mRect.height(),
121 cg.brush(QColorGroup::Button));
122 }
123
124 void repaintSeparator()
125 {
126 mView->repaintContents(mRect);
127 }
128
129 private:
130 CardView *mView;
131 QRect mRect;
132};
133
134//END Helpers
135
136//BEGIN Private Data
137
138class CardViewPrivate
139{
140 public:
141 CardViewPrivate()
142 : mSelectionMode( CardView::Multi ),
143 mDrawCardBorder( true ),
144 mDrawFieldLabels( true ),
145 mDrawSeparators( true),
146 mSepWidth( 2 ),
147 mShowEmptyFields( false ),
148 mLayoutDirty( true ),
149 mLastClickOnItem( false ),
150 mItemMargin( 0 ),
151 mItemSpacing( 10 ),
152 mItemWidth( 200 ),
153 mMaxFieldLines( INT_MAX ),
154 mCurrentItem( 0L ),
155 mLastClickPos( QPoint(0, 0) ),
156 mRubberBandAnchor( 0 ),
157 mCompText( QString::null ),
158 mResizeAnchor(0)
159 {};
160
161 CardViewItemList mItemList;
162 QPtrList<CardViewSeparator> mSeparatorList;
163 QFontMetrics *mFm;
164 QFontMetrics *mBFm; // bold font
165 QFont mHeaderFont; // custom header font
166 CardView::SelectionMode mSelectionMode;
167 bool mDrawCardBorder;
168 bool mDrawFieldLabels;
169 bool mDrawSeparators;
170 int mSepWidth;
171 bool mShowEmptyFields;
172 bool mLayoutDirty;
173 bool mLastClickOnItem;
174 uint mItemMargin; // internal margin in items
175 uint mItemSpacing; // spacing between items, column seperators and border
176 int mItemWidth; // width of all items
177 uint mMaxFieldLines; // Max lines to dispaly pr field
178 CardViewItem *mCurrentItem;
179 QPoint mLastClickPos;
180 QTimer *mTimer; // times out if mouse rests for more than 500 msecs
181 CardViewTip *mTip; // passed to the item under a resting cursor to display full text
182 bool mOnSeparator; // set/reset on mouse movement
183 // for resizing by dragging the separators
184 int mResizeAnchor; // uint, ulong? the mouse down separator left
185 int mRubberBandAnchor; // for erasing rubber bands
186 // data used for resizing.
187 // as they are beeded by each mouse move while resizing, we store them here,
188 // saving 8 calculations in each mouse move.
189 int colspace; // amount of space between items pr column
190 uint first; // the first col to anchor at for painting rubber bands
191 int firstX; // X position of first in pixel
192 int pressed; // the colummn that was pressed on at resizing start
193 int span; // pressed - first
194 // key completion
195 QString mCompText; // current completion string
196 QDateTime mCompUpdated; // ...was updated at this time
197};
198
199class CardViewItemPrivate
200{
201 public:
202 CardViewItemPrivate() :
203 x( 0 ),
204 y( 0 ),
205 mSelected( false ){};
206
207
208 QString mCaption;
209 QPtrList< CardViewItem::Field > mFieldList;
210 bool mSelected;
211 int x; // horizontal position, set by the view
212 int y; // vertical position, set by the view
213 int maxLabelWidth; // the width of the widest label, according to the view font.
214 int hcache; // height cache
215};
216//END Private Data
217
218//BEGIN CardViewItem
219
220CardViewItem::CardViewItem(CardView *parent, QString caption)
221 : d(new CardViewItemPrivate()), mView(parent)
222{
223 d->mCaption = caption;
224
225 initialize();
226}
227
228CardViewItem::~CardViewItem()
229{
230 // Remove ourself from the view
231 if (mView != 0)
232 mView->takeItem(this);
233
234 delete d;
235 d = 0;
236}
237
238void CardViewItem::initialize()
239{
240 d->mSelected = false;
241 d->mFieldList.setAutoDelete(true);
242 d->maxLabelWidth = 0;
243 d->hcache=0;
244
245 //calcRect();
246
247 // Add ourself to the view
248 if (mView != 0)
249 mView->insertItem(this);
250}
251
252void CardViewItem::paintCard(QPainter *p, QColorGroup &cg)
253{
254
255 if (!mView)
256 return;
257
258 QPen pen;
259 QBrush brush;
260 QFontMetrics fm = *(mView->d->mFm);
261 QFontMetrics bFm = *(mView->d->mBFm);
262 bool drawLabels = mView->d->mDrawFieldLabels;
263 bool drawBorder = mView->d->mDrawCardBorder;
264 int mg = mView->itemMargin();
265 int w = mView->itemWidth() - (mg*2);
266 int h = height() - (mg*2);
267 const int colonWidth( fm.width(":") );
268 int labelXPos = 2 + mg;
269 int labelWidth = QMIN( w/2 - 4 - mg, d->maxLabelWidth + colonWidth + 4 );
270 int valueXPos = labelWidth + 4 + mg;
271 int valueWidth = w - labelWidth - 4 - mg;
272
273 p->setFont( mView->font() );
274 labelWidth -= colonWidth; // extra space for the colon
275
276 if (!drawLabels)
277 {
278 valueXPos = labelXPos;
279 valueWidth = w - 4;
280 }
281
282 // Draw a simple box
283 if (isSelected())
284 pen = QPen(cg.highlight(), 1);
285 else
286 pen = QPen(cg.button(), 1);
287 p->setPen(pen);
288
289 // Draw the border - this is only draw if the user asks for it.
290 if (drawBorder)
291 p->drawRect( mg, mg, w, h );
292
293 // set the proper pen color for the caption box
294 if (isSelected())
295 brush = cg.brush(QColorGroup::Highlight);
296 else
297 brush = cg.brush(QColorGroup::Button);
298
299 p->fillRect(mg, mg, w, 4 + bFm.height(), brush);
300
301 // Now paint the caption
302 p->save();
303 QFont bFont = mView->headerFont();
304 //bFont.setBold(true);
305 p->setFont(bFont);
306 if (isSelected())
307 p->setPen(cg.highlightedText());
308 else
309 p->setPen(cg.buttonText());
310 p->drawText(2+mg, 2+mg + bFm.ascent()/*bFm.height()*//*-bFm.descent()*//*-bFm.leading()*/, trimString(d->mCaption, w-4, bFm));
311 p->restore();
312
313 // Go through the fields and draw them
314 QPtrListIterator< CardViewItem::Field > iter(d->mFieldList);
315 QString label, value;
316 int yPos = mg + 4 + bFm.height()/* + 1*/ + fm.height(); // why the + 1 ??? (anders)
317 p->setPen(cg.text());
318
319 int fh = fm.height();
320 int cln( 0 );
321 QString tmp;
322 int maxLines = mView->maxFieldLines();
323 for (iter.toFirst(); iter.current(); ++iter)
324 {
325 value = (*iter)->second;
326 if ( value.isEmpty() && ! mView->d->mShowEmptyFields )
327 continue;
328
329 if (drawLabels)
330 {
331 label = trimString((*iter)->first, labelWidth, fm);
332 p->drawText(labelXPos, yPos, label + ":");
333 }
334/* US original
335 for (cln=0; cln <= maxLines; cln++)
336 {
337 tmp = value.section('\n',cln,cln);
338 if ( !tmp.isEmpty() ) p->drawText( valueXPos, yPos + cln*fh, trimString( tmp, valueWidth, fm ) );
339 else break;
340 }
341*/
342
343//US new implementation
344 QStringList strlst = QStringList::split('\n', value, true);
345
346 for (cln=0; cln <= maxLines && cln <= (int)strlst.count(); cln++)
347 {
348 tmp = strlst[cln];
349
350 if ( !tmp.isEmpty() )
351 p->drawText( valueXPos, yPos + cln*fh, trimString( tmp, valueWidth, fm ) );
352 else
353 break;
354
355 }
356
357 if ( cln == 0 ) cln = 1;
358 yPos += cln * fh + 2;
359 }
360
361 // if we are the current item and the view has focus, draw focus rect
362 if ( mView->currentItem() == this && mView->hasFocus() )
363 {
364/*US
365 mView->style().drawPrimitive( QStyle::PE_FocusRect, p,
366 QRect(0, 0, mView->itemWidth(), h+(2*mg)), cg,
367 QStyle::Style_FocusAtBorder,
368 QStyleOption( isSelected() ? cg.highlight() : cg.base() ) );
369*/
370
371 const QColor pHighl = isSelected() ? cg.highlight() : cg.base();
372 const QRect r(0, 0, mView->itemWidth(), h+(2*mg));
373#ifndef DESKTOP_VERSION
374 mView->style().drawFocusRect(p, r, cg, &pHighl, true);
375#endif
376 }
377}
378
379const QString &CardViewItem::caption() const
380{
381 return d->mCaption;
382}
383
384
385int CardViewItem::height( bool allowCache ) const
386{
387 // use cache
388 if ( allowCache && d->hcache )
389 return d->hcache;
390
391 // Base height:
392 // 2 for line width
393 // 2 for top caption pad
394 // 2 for bottom caption pad
395 // 2 pad for the end
396 // + 2 times the advised margin
397 int baseHeight = 8 + ( 2 * mView->itemMargin() );
398
399 // size of font for each field
400 // 2 pad for each field
401
402 // anders: if the view does not show empty fields, check for value
403 bool sef = mView->showEmptyFields();
404 int fh = mView->d->mFm->height();//lineSpacing(); // font height
405 //int sp = QMAX( 0, 2- mView->d->mFm->leading() ); // field spacing NOTE make a property
406 int fieldHeight = 0;
407 int lines;
408 int maxLines( mView->maxFieldLines() );
409 QPtrListIterator< CardViewItem::Field > iter(d->mFieldList);
410 for (iter.toFirst(); iter.current(); ++iter)
411 {
412 if ( !sef && (*iter)->second.isEmpty() )
413 continue;
414 lines = QMIN( (*iter)->second.contains('\n') + 1, maxLines );
415 fieldHeight += ( lines * fh ) + 2;//sp;
416 }
417
418 // height of caption font (bold)
419 fieldHeight += mView->d->mBFm->height();
420 d->hcache = baseHeight + fieldHeight;
421 return d->hcache;
422}
423
424bool CardViewItem::isSelected() const
425{
426 return d->mSelected;
427}
428
429void CardViewItem::setSelected(bool selected)
430{
431 d->mSelected = selected;
432}
433
434void CardViewItem::insertField(const QString &label, const QString &value)
435{
436 CardViewItem::Field *f = new CardViewItem::Field(label, value);
437 d->mFieldList.append(f);
438 d->hcache=0;
439
440 if (mView)
441 {
442 mView->setLayoutDirty(true);
443 d->maxLabelWidth = QMAX( mView->d->mFm->width( label ), d->maxLabelWidth );
444 }
445}
446
447void CardViewItem::removeField(const QString &label)
448{
449 CardViewItem::Field *f;
450
451 QPtrListIterator< CardViewItem::Field > iter(d->mFieldList);
452 for (iter.toFirst(); iter.current(); ++iter)
453 {
454 f = *iter;
455 if (f->first == label)
456 break;
457 }
458
459 if (*iter)
460 d->mFieldList.remove(*iter);
461 d->hcache = 0;
462
463 if (mView)
464 mView->setLayoutDirty(true);
465}
466
467void CardViewItem::clearFields()
468{
469 d->mFieldList.clear();
470 d->hcache = 0;
471
472 if (mView)
473 mView->setLayoutDirty(true);
474}
475
476QString CardViewItem::trimString(const QString &text, int width,
477 QFontMetrics &fm)
478{
479 if (fm.width(text) <= width)
480 return text;
481
482 QString dots = "...";
483 int dotWidth = fm.width(dots);
484 QString trimmed;
485 int charNum = 0;
486
487 while (fm.width(trimmed) + dotWidth < width)
488 {
489 trimmed += text[charNum];
490 charNum++;
491 }
492
493 // Now trim the last char, since it put the width over the top
494 trimmed = trimmed.left(trimmed.length()-1);
495 trimmed += dots;
496
497 return trimmed;
498}
499
500CardViewItem *CardViewItem::nextItem()
501{
502 CardViewItem *item = 0;
503
504 if (mView)
505 item = mView->itemAfter(this);
506
507 return item;
508}
509
510void CardViewItem::repaintCard()
511{
512 if (mView)
513 mView->repaintItem(this);
514}
515
516void CardViewItem::setCaption(const QString &caption)
517{
518 d->mCaption = caption;
519 repaintCard();
520}
521
522QString CardViewItem::fieldValue(const QString &label)
523{
524 QPtrListIterator< CardViewItem::Field > iter(d->mFieldList);
525 for (iter.toFirst(); iter.current(); ++iter)
526 if ((*iter)->first == label)
527 return (*iter)->second;
528
529 return QString();
530}
531
532
533void CardViewItem::showFullString( const QPoint &itempos, CardViewTip *tip )
534{
535 bool trimmed( false );
536 QString s;
537 int mrg = mView->itemMargin();
538 int y = mView->d->mBFm->height() + 6 + mrg;
539 int w = mView->itemWidth() - (2*mrg);
540 int lw;
541 bool drawLabels = mView->drawFieldLabels();
542 bool isLabel = drawLabels && itempos.x() < w/2 ? true : false;
543
544 if ( itempos.y() < y )
545 {
546 if ( itempos.y() < 8 + mrg || itempos.y() > y - 4 )
547 return;
548 // this is the caption
549 s = caption();
550 trimmed = mView->d->mBFm->width( s ) > w - 4;
551 y = 2 + mrg;
552 lw = 0;
553 isLabel=true;
554 } else {
555 // find the field
556 Field *f = fieldAt( itempos );
557 if ( !f || ( !mView->showEmptyFields() && f->second.isEmpty() ) )
558 return;
559
560 // y position:
561 // header font height + 4px hader margin + 2px leading + item margin
562 // + actual field index * (fontheight + 2px leading)
563 int maxLines = mView->maxFieldLines();
564 bool se = mView->showEmptyFields();
565 int fh = mView->d->mFm->height();
566// {
567 Field *_f;
568 for (_f = d->mFieldList.first(); _f != f; _f = d->mFieldList.next())
569 if ( se || ! _f->second.isEmpty() )
570 y += ( QMIN(_f->second.contains('\n')+1, maxLines) * fh ) + 2;
571// }
572 if ( isLabel && itempos.y() > y + fh )
573 return;
574 // label or data?
575 s = isLabel ? f->first : f->second;
576 // trimmed?
577 int colonWidth = mView->d->mFm->width(":");
578 lw = drawLabels ? // label width
579 QMIN( w/2 - 4 - mrg, d->maxLabelWidth + colonWidth + 4 ) :
580 0;
581 int mw = isLabel ? lw - colonWidth : w - lw - (mrg*2); // max width for string
582 if ( isLabel )
583 {
584 trimmed = mView->d->mFm->width( s ) > mw - colonWidth;
585 } else {
586 QRect r( mView->d->mFm->boundingRect( 0, 0, INT_MAX, INT_MAX, Qt::AlignTop|Qt::AlignLeft, s ) );
587 trimmed = r.width() > mw || r.height()/fh > QMIN(s.contains('\n') + 1, maxLines);
588 }
589 }
590 if ( trimmed )
591 {
592 tip->setFont( (isLabel && !lw) ? mView->headerFont() : mView->font() ); // if condition is true, a header
593 tip->setText( s );
594 tip->adjustSize();
595 // find a proper position
596 int lx;
597 lx = isLabel || !drawLabels ? mrg : lw + mrg + 2 /*-1*/;
598 QPoint pnt(mView->contentsToViewport( QPoint(d->x, d->y) ));
599 pnt += QPoint(lx, y);
600 if ( pnt.x() < 0 )
601 pnt.setX( 0 );
602 if ( pnt.x() + tip->width() > mView->visibleWidth() )
603 pnt.setX( mView->visibleWidth() - tip->width() );
604 if ( pnt.y() + tip->height() > mView->visibleHeight() )
605 pnt.setY( QMAX( 0, mView->visibleHeight() - tip->height() ) );
606 // show
607 tip->move( pnt );
608 tip->show();
609 }
610}
611
612CardViewItem::Field *CardViewItem::fieldAt( const QPoint & itempos ) const
613{
614 int ypos = mView->d->mBFm->height() + 7 + mView->d->mItemMargin;
615 int iy = itempos.y();
616 // skip below caption
617 if ( iy <= ypos )
618 return 0;
619 // try find a field
620 bool showEmpty = mView->showEmptyFields();
621 int fh = mView->d->mFm->height();
622 int maxLines = mView->maxFieldLines();
623 Field *f;
624 for ( f = d->mFieldList.first(); f; f = d->mFieldList.next() )
625 {
626 if ( showEmpty || !f->second.isEmpty() )
627 ypos += ( QMIN( f->second.contains('\n')+1, maxLines ) *fh)+2;
628 if ( iy <= ypos )
629 break;
630 }
631 return f ? f : 0;
632}
633//END CardViewItem
634
635//BEGIN CardView
636
637CardView::CardView(QWidget *parent, const char *name)
638 : QScrollView(parent, name),
639 d(new CardViewPrivate())
640{
641 d->mItemList.setAutoDelete(true);
642 d->mSeparatorList.setAutoDelete(true);
643
644 QFont f = font();
645 d->mFm = new QFontMetrics(f);
646 f.setBold(true);
647 d->mHeaderFont = f;
648 d->mBFm = new QFontMetrics(f);
649 d->mTip = ( new CardViewTip( viewport() ) ),
650 d->mTip->hide();
651 d->mTimer = ( new QTimer(this, "mouseTimer") ),
652
653 viewport()->setMouseTracking( true );
654 viewport()->setFocusProxy(this);
655 viewport()->setFocusPolicy(WheelFocus);
656 viewport()->setBackgroundMode(PaletteBase);
657
658 connect( d->mTimer, SIGNAL(timeout()), this, SLOT(tryShowFullText()) );
659
660//US setBackgroundMode(PaletteBackground, PaletteBase);
661 setBackgroundMode(PaletteBackground);
662
663 // no reason for a vertical scrollbar
664 setVScrollBarMode(AlwaysOff);
665}
666
667CardView::~CardView()
668{
669 delete d->mFm;
670 delete d->mBFm;
671 delete d;
672 d = 0;
673}
674
675void CardView::insertItem(CardViewItem *item)
676{
677 d->mItemList.inSort(item);
678 setLayoutDirty(true);
679}
680
681void CardView::takeItem(CardViewItem *item)
682{
683 if ( d->mCurrentItem == item )
684 d->mCurrentItem = item->nextItem();
685 d->mItemList.take(d->mItemList.findRef(item));
686
687 setLayoutDirty(true);
688}
689
690void CardView::clear()
691{
692 d->mItemList.clear();
693
694 setLayoutDirty(true);
695}
696
697CardViewItem *CardView::currentItem()
698{
699 if ( ! d->mCurrentItem && d->mItemList.count() )
700 d->mCurrentItem = d->mItemList.first();
701 return d->mCurrentItem;
702}
703
704void CardView::setCurrentItem( CardViewItem *item )
705{
706 if ( !item )
707 return;
708 else if ( item->cardView() != this )
709 {
710 kdDebug(5720)<<"CardView::setCurrentItem: Item ("<<item<<") not owned! Backing out.."<<endl;
711 return;
712 }
713 else if ( item == currentItem() )
714 {
715 return;
716 }
717
718 if ( d->mSelectionMode == Single )
719 {
720 setSelected( item, true );
721 }
722 else
723 {
724 CardViewItem *it = d->mCurrentItem;
725 d->mCurrentItem = item;
726 if ( it )
727 it->repaintCard();
728 item->repaintCard();
729 }
730 if ( ! d->mOnSeparator )
731 ensureItemVisible( item );
732 emit currentChanged( item );
733}
734
735CardViewItem *CardView::itemAt(const QPoint &viewPos)
736{
737 CardViewItem *item = 0;
738 QPtrListIterator<CardViewItem> iter(d->mItemList);
739 bool found = false;
740 for (iter.toFirst(); iter.current() && !found; ++iter)
741 {
742 item = *iter;
743 //if (item->d->mRect.contains(viewPos))
744 if (QRect(item->d->x, item->d->y, d->mItemWidth, item->height()).contains(viewPos))
745 found = true;
746 }
747
748 if (found)
749 return item;
750
751 return 0;
752}
753
754QRect CardView::itemRect(const CardViewItem *item)
755{
756 //return item->d->mRect;
757 return QRect(item->d->x, item->d->y, d->mItemWidth, item->height());
758}
759
760void CardView::ensureItemVisible(const CardViewItem *item)
761{
762 ensureVisible(item->d->x , item->d->y, d->mItemSpacing, 0);
763 ensureVisible(item->d->x + d->mItemWidth, item->d->y, d->mItemSpacing, 0);
764}
765
766void CardView::repaintItem(const CardViewItem *item)
767{
768 //repaintContents(item->d->mRect);
769 repaintContents( QRect(item->d->x, item->d->y, d->mItemWidth, item->height()) );
770}
771
772void CardView::setSelectionMode(CardView::SelectionMode mode)
773{
774 selectAll(false);
775
776 d->mSelectionMode = mode;
777}
778
779CardView::SelectionMode CardView::selectionMode() const
780{
781 return d->mSelectionMode;
782}
783
784void CardView::selectAll(bool state)
785{
786 QPtrListIterator<CardViewItem> iter(d->mItemList);
787 if (!state)
788 {
789 for (iter.toFirst(); iter.current(); ++iter)
790 {
791 if ((*iter)->isSelected())
792 {
793 (*iter)->setSelected(false);
794 (*iter)->repaintCard();
795 }
796 }
797 //emit selectionChanged(); // WARNING FIXME
798 emit selectionChanged(0);
799 }
800 else if (d->mSelectionMode != CardView::Single)
801 {
802 for (iter.toFirst(); iter.current(); ++iter)
803 {
804 (*iter)->setSelected(true);
805 }
806
807 if (d->mItemList.count() > 0)
808 {
809 // emit, since there must have been at least one selected
810 emit selectionChanged();
811 //repaint();//???
812 viewport()->update();
813 }
814 }
815}
816
817void CardView::setSelected(CardViewItem *item, bool selected)
818{
819 if ((item == 0) || (item->isSelected() == selected))
820 return;
821
822 if ( selected && d->mCurrentItem != item )
823 {
824 CardViewItem *it = d->mCurrentItem;
825 d->mCurrentItem = item;
826 if ( it )
827 it->repaintCard();
828 }
829
830 if (d->mSelectionMode == CardView::Single)
831 {
832 bool b = signalsBlocked();
833 blockSignals(true);
834 selectAll(false);
835 blockSignals(b);
836
837 if (selected)
838 {
839 item->setSelected(selected);
840 item->repaintCard();
841 emit selectionChanged();
842 emit selectionChanged(item);
843 }
844 else
845 {
846 emit selectionChanged();
847 emit selectionChanged(0);
848 }
849 }
850 else if (d->mSelectionMode == CardView::Multi)
851 {
852 item->setSelected(selected);
853 item->repaintCard();
854 emit selectionChanged();
855 }
856 else if (d->mSelectionMode == CardView::Extended)
857 {
858 bool b = signalsBlocked();
859 blockSignals(true);
860 selectAll(false);
861 blockSignals(b);
862
863 item->setSelected(selected);
864 item->repaintCard();
865 emit selectionChanged();
866 }
867}
868
869bool CardView::isSelected(CardViewItem *item) const
870{
871 return (item && item->isSelected());
872}
873
874CardViewItem *CardView::selectedItem() const
875{
876 // find the first selected item
877 QPtrListIterator<CardViewItem> iter(d->mItemList);
878 for (iter.toFirst(); iter.current(); ++iter)
879 {
880 if ((*iter)->isSelected())
881 return *iter;
882 }
883
884 return 0;
885}
886
887CardViewItem *CardView::firstItem() const
888{
889 return d->mItemList.first();
890}
891
892int CardView::childCount() const
893{
894 return d->mItemList.count();
895}
896/*US
897CardViewItem *CardView::findItem(const QString &text, const QString &label,
898 Qt::StringComparisonMode compare)
899{
900 // IF the text is empty, we will return null, since empty text will
901 // match anything!
902 if (text.isEmpty())
903 return 0;
904
905 QPtrListIterator<CardViewItem> iter(d->mItemList);
906 if (compare & Qt::BeginsWith)
907 {
908 QString value;
909 for (iter.toFirst(); iter.current(); ++iter)
910 {
911 value = (*iter)->fieldValue(label).upper();
912 if (value.startsWith(text.upper()))
913 return *iter;
914 }
915 }
916 else
917 {
918 kdDebug(5720) << "CardView::findItem: search method not implemented" << endl;
919 }
920
921 return 0;
922}
923*/
924
925uint CardView::columnWidth()
926{
927 return d->mDrawSeparators ?
928 d->mItemWidth + ( 2 * d->mItemSpacing ) + d->mSepWidth :
929 d->mItemWidth + d->mItemSpacing;
930}
931
932void CardView::drawContents(QPainter *p, int clipx, int clipy,
933 int clipw, int cliph)
934{
935 QScrollView::drawContents(p, clipx, clipy, clipw, cliph);
936
937 if (d->mLayoutDirty)
938 calcLayout();
939
940 //kdDebug() << "CardView::drawContents: " << clipx << ", " << clipy
941 // << ", " << clipw << ", " << cliph << endl;
942
943 QColorGroup cg = viewport()->palette().active(); // allow setting costum colors in the viewport pale
944
945 QRect clipRect(clipx, clipy, clipw, cliph);
946 QRect cardRect;
947 QRect sepRect;
948 CardViewItem *item;
949 CardViewSeparator *sep;
950
951 // make sure the viewport is a pure background
952 viewport()->erase(clipRect);
953
954 // Now tell the cards to draw, if they are in the clip region
955 QPtrListIterator<CardViewItem> iter(d->mItemList);
956 for (iter.toFirst(); iter.current(); ++iter)
957 {
958 item = *iter;
959 cardRect.setRect( item->d->x, item->d->y, d->mItemWidth, item->height() );
960
961 if (clipRect.intersects(cardRect) || clipRect.contains(cardRect))
962 {
963 //kdDebug() << "\trepainting card at: " << cardRect.x() << ", "
964 // << cardRect.y() << endl;
965
966 // Tell the card to paint
967 p->save();
968 p->translate(cardRect.x(), cardRect.y());
969 item->paintCard(p, cg);
970 p->restore();
971 }
972 }
973
974 // Followed by the separators if they are in the clip region
975 QPtrListIterator<CardViewSeparator> sepIter(d->mSeparatorList);
976 for (sepIter.toFirst(); sepIter.current(); ++sepIter)
977 {
978 sep = *sepIter;
979 sepRect = sep->mRect;
980
981 if (clipRect.intersects(sepRect) || clipRect.contains(sepRect))
982 {
983 p->save();
984 p->translate(sepRect.x(), sepRect.y());
985 sep->paintSeparator(p, cg);
986 p->restore();
987 }
988 }
989}
990
991void CardView::resizeEvent(QResizeEvent *e)
992{
993 QScrollView::resizeEvent(e);
994
995 setLayoutDirty(true);
996}
997
998void CardView::calcLayout()
999{
1000 //kdDebug() << "CardView::calcLayout:" << endl;
1001
1002 // Start in the upper left corner and layout all the
1003 // cars using their height and width
1004 int maxWidth = 0;
1005 int maxHeight = 0;
1006 int xPos = 0;
1007 int yPos = 0;
1008 int cardSpacing = d->mItemSpacing;
1009
1010 // delete the old separators
1011 d->mSeparatorList.clear();
1012
1013 QPtrListIterator<CardViewItem> iter(d->mItemList);
1014 CardViewItem *item = 0;
1015 CardViewSeparator *sep = 0;
1016 xPos += cardSpacing;
1017
1018 for (iter.toFirst(); iter.current(); ++iter)
1019 {
1020 item = *iter;
1021
1022 yPos += cardSpacing;
1023
1024 if (yPos + item->height() + cardSpacing >= height() - horizontalScrollBar()->height())
1025 {
1026 maxHeight = QMAX(maxHeight, yPos);
1027
1028 // Drawing in this column would be greater than the height
1029 // of the scroll view, so move to next column
1030 yPos = cardSpacing;
1031 xPos += cardSpacing + maxWidth;
1032 if (d->mDrawSeparators)
1033 {
1034 // Create a separator since the user asked
1035 sep = new CardViewSeparator(this);
1036 sep->mRect.moveTopLeft(QPoint(xPos, yPos+d->mItemMargin));
1037 xPos += d->mSepWidth + cardSpacing;
1038 d->mSeparatorList.append(sep);
1039 }
1040
1041 maxWidth = 0;
1042 }
1043
1044 item->d->x = xPos;
1045 item->d->y = yPos;
1046
1047 yPos += item->height();
1048 maxWidth = QMAX(maxWidth, d->mItemWidth);
1049 }
1050
1051 xPos += maxWidth;
1052 resizeContents( xPos + cardSpacing, maxHeight );
1053
1054 // Update the height of all the separators now that we know the
1055 // max height of a column
1056 QPtrListIterator<CardViewSeparator> sepIter(d->mSeparatorList);
1057 for (sepIter.toFirst(); sepIter.current(); ++sepIter)
1058 {
1059 (*sepIter)->mRect.setHeight(maxHeight - 2*cardSpacing - 2*d->mItemMargin);
1060 }
1061
1062 d->mLayoutDirty = false;
1063}
1064
1065CardViewItem *CardView::itemAfter(CardViewItem *item)
1066{
1067 /*int pos = */d->mItemList.findRef(item);
1068 return d->mItemList.next();//at(pos+1);
1069}
1070
1071uint CardView::itemMargin()
1072{
1073 return d->mItemMargin;
1074}
1075
1076void CardView::setItemMargin( uint margin )
1077{
1078 if ( margin == d->mItemMargin )
1079 return;
1080
1081 d->mItemMargin = margin;
1082 setLayoutDirty( true );
1083}
1084
1085uint CardView::itemSpacing()
1086{
1087 return d->mItemSpacing;
1088}
1089
1090void CardView::setItemSpacing( uint spacing )
1091{
1092 if ( spacing == d->mItemSpacing )
1093 return;
1094
1095 d->mItemSpacing = spacing;
1096 setLayoutDirty( true );
1097}
1098
1099void CardView::contentsMousePressEvent(QMouseEvent *e)
1100{
1101 QScrollView::contentsMousePressEvent(e);
1102
1103 QPoint pos = e->pos();
1104 d->mLastClickPos = pos;
1105
1106 CardViewItem *item = itemAt(pos);
1107
1108 if (item == 0)
1109 {
1110 d->mLastClickOnItem = false;
1111 if ( d->mOnSeparator)
1112 {
1113 d->mResizeAnchor = e->x()+contentsX();
1114 d->colspace = (2*d->mItemSpacing) /*+ (2*d->mItemMargin)*/;
1115 int ccw = d->mItemWidth + d->colspace + d->mSepWidth;
1116 d->first = (contentsX()+d->mSepWidth)/ccw;
1117 d->pressed = (d->mResizeAnchor+d->mSepWidth)/ccw;
1118 d->span = d->pressed - d->first;
1119 d->firstX = d->first * ccw;
1120 if ( d->firstX ) d->firstX -= d->mSepWidth; // (no sep in col 0)
1121 }
1122 else
1123 {
1124 selectAll(false);
1125 }
1126 return;
1127 }
1128
1129 d->mLastClickOnItem = true;
1130
1131 CardViewItem *other = d->mCurrentItem;
1132 setCurrentItem( item );
1133
1134 // Always emit the selection
1135 emit clicked(item);
1136
1137 // Check the selection type and update accordingly
1138 if (d->mSelectionMode == CardView::Single)
1139 {
1140 // make sure it isn't already selected
1141 if (item->isSelected())
1142 return;
1143
1144 bool b = signalsBlocked();
1145 blockSignals(true);
1146 selectAll(false);
1147 blockSignals(b);
1148
1149 item->setSelected(true);
1150 item->repaintCard();
1151 emit selectionChanged(item);
1152 }
1153
1154 else if (d->mSelectionMode == CardView::Multi)
1155 {
1156 // toggle the selection
1157 item->setSelected(!item->isSelected());
1158 item->repaintCard();
1159 emit selectionChanged();
1160 }
1161
1162 else if (d->mSelectionMode == CardView::Extended)
1163 {
1164 if ((e->button() & Qt::LeftButton) &&
1165 (e->state() & Qt::ShiftButton))
1166 {
1167 if ( item == other ) return;
1168
1169 bool s = ! item->isSelected();
1170
1171 if ( s && ! (e->state() & ControlButton) )
1172 {
1173 bool b = signalsBlocked();
1174 blockSignals(true);
1175 selectAll(false);
1176 blockSignals(b);
1177 }
1178
1179 int from, to, a, b;
1180 a = d->mItemList.findRef( item );
1181 b = d->mItemList.findRef( other );
1182 from = a < b ? a : b;
1183 to = a > b ? a : b;
1184 //kdDebug()<<"selecting items "<<from<<" - "<<to<<" ( "<<s<<" )"<<endl;
1185 CardViewItem *aItem;
1186 for ( ; from <= to; from++ )
1187 {
1188 aItem = d->mItemList.at( from );
1189 aItem->setSelected( s );
1190 repaintItem( aItem );
1191 }
1192 emit selectionChanged();
1193 }
1194 else if ((e->button() & Qt::LeftButton) &&
1195 (e->state() & Qt::ControlButton))
1196 {
1197 item->setSelected(!item->isSelected());
1198 item->repaintCard();
1199 emit selectionChanged();
1200 }
1201
1202 else if (e->button() & Qt::LeftButton)
1203 {
1204 bool b = signalsBlocked();
1205 blockSignals(true);
1206 selectAll(false);
1207 blockSignals(b);
1208
1209 item->setSelected(true);
1210 item->repaintCard();
1211 emit selectionChanged();
1212 }
1213 }
1214
1215}
1216
1217void CardView::contentsMouseReleaseEvent(QMouseEvent *e)
1218{
1219 QScrollView::contentsMouseReleaseEvent(e);
1220
1221 if ( d->mResizeAnchor )
1222 {
1223 // finish the resizing:
1224 unsetCursor();
1225 // hide rubber bands
1226 int newiw = d->mItemWidth - ((d->mResizeAnchor - d->mRubberBandAnchor)/d->span);
1227 drawRubberBands( 0 );
1228 // we should move to reflect the new position if we are scrolled.
1229 if ( contentsX() )
1230 {
1231 int newX = QMAX( 0, ( d->pressed * ( newiw + d->colspace + d->mSepWidth ) ) - e->x() );
1232 setContentsPos( newX, contentsY() );
1233 }
1234 // set new item width
1235 setItemWidth( newiw );
1236 // reset anchors
1237 d->mResizeAnchor = 0;
1238 d->mRubberBandAnchor = 0;
1239 return;
1240 }
1241
1242 // If there are accel keys, we will not emit signals
1243 if ((e->state() & Qt::ShiftButton) || (e->state() & Qt::ControlButton))
1244 return;
1245
1246 // Get the item at this position
1247 CardViewItem *item = itemAt(e->pos());
1248
1249 if (item && KGlobalSettings::singleClick())
1250 {
1251 emit executed(item);
1252 }
1253}
1254
1255void CardView::contentsMouseDoubleClickEvent(QMouseEvent *e)
1256{
1257 QScrollView::contentsMouseDoubleClickEvent(e);
1258
1259 CardViewItem *item = itemAt(e->pos());
1260
1261 if (item)
1262 {
1263 d->mCurrentItem = item;
1264 }
1265
1266 if (item && !KGlobalSettings::singleClick())
1267 {
1268 emit executed(item);
1269 }
1270 emit doubleClicked(item);
1271}
1272
1273void CardView::contentsMouseMoveEvent( QMouseEvent *e )
1274{
1275 // resizing
1276 if ( d->mResizeAnchor )
1277 {
1278 int x = e->x();
1279 if ( x != d->mRubberBandAnchor )
1280 drawRubberBands( x );
1281 return;
1282 }
1283
1284 if (d->mLastClickOnItem && (e->state() & Qt::LeftButton) &&
1285 ((e->pos() - d->mLastClickPos).manhattanLength() > 4)) {
1286
1287 startDrag();
1288 return;
1289 }
1290
1291 d->mTimer->start( 500 );
1292
1293 // see if we are over a separator
1294 // only if we actually have them painted?
1295 if ( d->mDrawSeparators )
1296 {
1297 int colcontentw = d->mItemWidth + (2*d->mItemSpacing);
1298 int colw = colcontentw + d->mSepWidth;
1299 int m = e->x()%colw;
1300 if ( m >= colcontentw && m > 0 )
1301 {
1302 setCursor( SplitVCursor ); // Why does this fail sometimes?
1303 d->mOnSeparator = true;
1304 }
1305 else
1306 {
1307 setCursor( ArrowCursor );
1308 d->mOnSeparator = false;
1309 }
1310 }
1311}
1312
1313void CardView::enterEvent( QEvent * )
1314{
1315 d->mTimer->start( 500 );
1316}
1317
1318void CardView::leaveEvent( QEvent * )
1319{
1320 d->mTimer->stop();
1321 if (d->mOnSeparator)
1322 {
1323 d->mOnSeparator = false;
1324 setCursor( ArrowCursor );
1325 }
1326}
1327
1328void CardView::focusInEvent( QFocusEvent * )
1329{
1330 if (!d->mCurrentItem && d->mItemList.count() )
1331 {
1332 setCurrentItem( d->mItemList.first() );
1333 }
1334 else if ( d->mCurrentItem )
1335 {
1336 d->mCurrentItem->repaintCard();
1337 }
1338}
1339
1340void CardView::focusOutEvent( QFocusEvent * )
1341{
1342 if (d->mCurrentItem)
1343 d->mCurrentItem->repaintCard();
1344}
1345
1346void CardView::keyPressEvent( QKeyEvent *e )
1347{
1348 if ( ! ( childCount() && d->mCurrentItem ) )
1349 {
1350 e->ignore();
1351 return;
1352 }
1353
1354 uint pos = d->mItemList.findRef( d->mCurrentItem );
1355 CardViewItem *aItem = 0L; // item that gets the focus
1356 CardViewItem *old = d->mCurrentItem;
1357
1358 switch ( e->key() )
1359 {
1360 case Key_Up:
1361 if ( pos > 0 )
1362 {
1363 aItem = d->mItemList.at( pos - 1 );
1364 setCurrentItem( aItem );
1365 }
1366 break;
1367 case Key_Down:
1368 if ( pos < d->mItemList.count() - 1 )
1369 {
1370 aItem = d->mItemList.at( pos + 1 );
1371 setCurrentItem( aItem );
1372 }
1373 break;
1374 case Key_Left:
1375 {
1376 // look for an item in the previous/next column, starting from
1377 // the vertical middle of the current item.
1378 // FIXME use nice calculatd measures!!!
1379 QPoint aPoint( d->mCurrentItem->d->x, d->mCurrentItem->d->y );
1380 aPoint -= QPoint( 30,-(d->mCurrentItem->height()/2) );
1381 aItem = itemAt( aPoint );
1382 // maybe we hit some space below an item
1383 while ( !aItem && aPoint.y() > 27 )
1384 {
1385 aPoint -= QPoint( 0, 16 );
1386 aItem = itemAt( aPoint );
1387 }
1388 if ( aItem )
1389 setCurrentItem( aItem );
1390 }
1391 break;
1392 case Key_Right:
1393 {
1394 // FIXME use nice calculated measures!!!
1395 QPoint aPoint( d->mCurrentItem->d->x + d->mItemWidth, d->mCurrentItem->d->y );
1396 aPoint += QPoint( 30,(d->mCurrentItem->height()/2) );
1397 aItem = itemAt( aPoint );
1398 while ( !aItem && aPoint.y() > 27 )
1399 {
1400 aPoint -= QPoint( 0, 16 );
1401 aItem = itemAt( aPoint );
1402 }
1403 if ( aItem )
1404 setCurrentItem( aItem );
1405 }
1406 break;
1407 case Key_Home:
1408 aItem = d->mItemList.first();
1409 setCurrentItem( aItem );
1410 break;
1411 case Key_End:
1412 aItem = d->mItemList.last();
1413 setCurrentItem( aItem );
1414 break;
1415 case Key_Prior: // PageUp
1416 {
1417 // QListView: "Make the item above the top visible and current"
1418 // TODO if contentsY(), pick the top item of the leftmost visible column
1419 if ( contentsX() <= 0 )
1420 return;
1421 int cw = columnWidth();
1422 int theCol = ( QMAX( 0, ( contentsX()/cw) * cw ) ) + d->mItemSpacing;
1423 aItem = itemAt( QPoint( theCol + 1, d->mItemSpacing + 1 ) );
1424 if ( aItem )
1425 setCurrentItem( aItem );
1426 }
1427 break;
1428 case Key_Next: // PageDown
1429 {
1430 // QListView: "Make the item below the bottom visible and current"
1431 // find the first not fully visible column.
1432 // TODO: consider if a partly visible (or even hidden) item at the
1433 // bottom of the rightmost column exists
1434 int cw = columnWidth();
1435 int theCol = ( (( contentsX() + visibleWidth() )/cw) * cw ) + d->mItemSpacing + 1;
1436 // if separators are on, we may need to we may be one column further right if only the spacing/sep is hidden
1437 if ( d->mDrawSeparators && cw - (( contentsX() + visibleWidth() )%cw) <= int( d->mItemSpacing + d->mSepWidth ) )
1438 theCol += cw;
1439
1440 // make sure this is not too far right
1441 while ( theCol > contentsWidth() )
1442 theCol -= columnWidth();
1443
1444 aItem = itemAt( QPoint( theCol, d->mItemSpacing + 1 ) );
1445
1446 if ( aItem )
1447 setCurrentItem( aItem );
1448 }
1449 break;
1450 case Key_Space:
1451 setSelected( d->mCurrentItem, !d->mCurrentItem->isSelected() );
1452 emit selectionChanged();
1453 break;
1454 case Key_Return:
1455 case Key_Enter:
1456 emit returnPressed( d->mCurrentItem );
1457 emit executed( d->mCurrentItem );
1458 break;
1459 default:
1460 if ( (e->state() & ControlButton) && e->key() == Key_A )
1461 {
1462 // select all
1463 selectAll( true );
1464 break;
1465 }
1466 // if we have a string, do autosearch
1467 else if ( ! e->text().isEmpty() && e->text()[0].isPrint() )
1468 {
1469
1470 }
1471 break;
1472 }
1473 // handle selection
1474 if ( aItem )
1475 {
1476 if ( d->mSelectionMode == CardView::Extended )
1477 {
1478 if ( (e->state() & ShiftButton) )
1479 {
1480 // shift button: toggle range
1481 // if control button is pressed, leave all items
1482 // and toggle selection current->old current
1483 // otherwise, ??????
1484 bool s = ! aItem->isSelected();
1485 int from, to, a, b;
1486 a = d->mItemList.findRef( aItem );
1487 b = d->mItemList.findRef( old );
1488 from = a < b ? a : b;
1489 to = a > b ? a : b;
1490
1491 if ( to - from > 1 )
1492 {
1493 bool b = signalsBlocked();
1494 blockSignals(true);
1495 selectAll(false);
1496 blockSignals(b);
1497 }
1498
1499 //kdDebug()<<"selecting items "<<from<<" - "<<to<<" ( "<<s<<" )"<<endl;
1500 CardViewItem *item;
1501 for ( ; from <= to; from++ )
1502 {
1503 item = d->mItemList.at( from );
1504 item->setSelected( s );
1505 repaintItem( item );
1506 }
1507 emit selectionChanged();
1508 }
1509 else if ( (e->state() & ControlButton) )
1510 {
1511 // control button: do nothing
1512 }
1513 else
1514 {
1515 // no button: move selection to this item
1516 bool b = signalsBlocked();
1517 blockSignals(true);
1518 selectAll(false);
1519 blockSignals(b);
1520
1521 setSelected( aItem, true );
1522 emit selectionChanged();
1523 }
1524 }
1525 }
1526}
1527
1528void CardView::contentsWheelEvent( QWheelEvent * e )
1529{
1530 scrollBy(2*e->delta()/-3, 0);
1531}
1532
1533void CardView::setLayoutDirty(bool dirty)
1534{
1535 if (d->mLayoutDirty != dirty)
1536 {
1537 d->mLayoutDirty = dirty;
1538 repaint();
1539 }
1540}
1541
1542void CardView::setDrawCardBorder(bool enabled)
1543{
1544 if (enabled != d->mDrawCardBorder)
1545 {
1546 d->mDrawCardBorder = enabled;
1547 repaint();
1548 }
1549}
1550
1551bool CardView::drawCardBorder() const
1552{
1553 return d->mDrawCardBorder;
1554}
1555
1556void CardView::setDrawColSeparators(bool enabled)
1557{
1558 if (enabled != d->mDrawSeparators)
1559 {
1560 d->mDrawSeparators = enabled;
1561 setLayoutDirty(true);
1562 }
1563}
1564
1565bool CardView::drawColSeparators() const
1566{
1567 return d->mDrawSeparators;
1568}
1569
1570void CardView::setDrawFieldLabels(bool enabled)
1571{
1572 if (enabled != d->mDrawFieldLabels)
1573 {
1574 d->mDrawFieldLabels = enabled;
1575 repaint();
1576 }
1577}
1578
1579bool CardView::drawFieldLabels() const
1580{
1581 return d->mDrawFieldLabels;
1582}
1583
1584void CardView::setShowEmptyFields(bool show)
1585{
1586 if (show != d->mShowEmptyFields)
1587 {
1588 d->mShowEmptyFields = show;
1589 setLayoutDirty(true);
1590 }
1591}
1592
1593bool CardView::showEmptyFields() const
1594{
1595 return d->mShowEmptyFields;
1596}
1597
1598void CardView::startDrag()
1599{
1600 // The default implementation is a no-op. It must be
1601 // reimplemented in a subclass to be useful
1602}
1603void CardView::tryShowFullText()
1604{
1605 d->mTimer->stop();
1606 // if we have an item
1607 QPoint cpos = viewportToContents( viewport()->mapFromGlobal( QCursor::pos() ) );
1608 CardViewItem *item = itemAt( cpos );
1609 if ( item )
1610 {
1611 // query it for a value to display
1612 //QString s = item ? item->caption() : "(no item)";
1613 //kdDebug()<<"MOUSE REST: "<<s<<endl;
1614 QPoint ipos = cpos - itemRect( item ).topLeft();
1615 item->showFullString( ipos, d->mTip );
1616 }
1617}
1618
1619void CardView::drawRubberBands( int pos )
1620{
1621 if ( pos && ((pos-d->firstX)/d->span) - d->colspace - d->mSepWidth < MIN_ITEM_WIDTH ) return;
1622
1623 int tmpcw = (d->mRubberBandAnchor-d->firstX)/d->span;
1624 int x = d->firstX + tmpcw - d->mSepWidth - contentsX();
1625 int h = visibleHeight();
1626
1627 QPainter p( viewport() );
1628 p.setRasterOp( XorROP );
1629 p.setPen( gray );
1630 p.setBrush( gray );
1631 uint n = d->first;
1632 // erase
1633 if ( d->mRubberBandAnchor )
1634 do {
1635 p.drawRect( x, 0, 2, h );
1636 x += tmpcw;
1637 n++;
1638 } while ( x < visibleWidth() && n < d->mSeparatorList.count() );
1639 // paint new
1640 if ( ! pos ) return;
1641 tmpcw = (pos - d->firstX)/d->span;
1642 n = d->first;
1643 x = d->firstX + tmpcw - d->mSepWidth - contentsX();
1644 do {
1645 p.drawRect( x, 0, 2, h );
1646 x += tmpcw;
1647 n++;
1648 } while ( x < visibleWidth() && n < d->mSeparatorList.count() );
1649 d->mRubberBandAnchor = pos;
1650}
1651
1652
1653int CardView::itemWidth() const
1654{
1655 return d->mItemWidth;
1656}
1657
1658void CardView::setItemWidth( int w )
1659{
1660 if ( w == d->mItemWidth )
1661 return;
1662 if ( w < MIN_ITEM_WIDTH )
1663 w = MIN_ITEM_WIDTH;
1664 d->mItemWidth = w;
1665 setLayoutDirty( true );
1666#ifndef KAB_EMBEDDED
1667 updateContents();
1668#else //KAB_EMBEDDED
1669//US updateContents( d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight() );
1670qDebug("CardView::setItemWidth has to be verified");
1671 updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
1672#endif //KAB_EMBEDDED
1673}
1674
1675void CardView::setHeaderFont( const QFont &fnt )
1676{
1677 d->mHeaderFont = fnt;
1678 delete d->mBFm;
1679 d->mBFm = new QFontMetrics( fnt );
1680}
1681
1682QFont CardView::headerFont() const
1683{
1684 return d->mHeaderFont;
1685}
1686
1687void CardView::setFont( const QFont &fnt )
1688{
1689 QScrollView::setFont( fnt );
1690 delete d->mFm;
1691 d->mFm = new QFontMetrics( fnt );
1692}
1693
1694int CardView::separatorWidth()
1695{
1696 return d->mSepWidth;
1697}
1698
1699void CardView::setSeparatorWidth( int width )
1700{
1701 d->mSepWidth = width;
1702 setLayoutDirty( true ); // hmm, actually I could just adjust the x'es...
1703}
1704
1705int CardView::maxFieldLines() const
1706{
1707 return d->mMaxFieldLines;
1708}
1709
1710void CardView::setMaxFieldLines( int howmany )
1711{
1712 d->mMaxFieldLines = howmany ? howmany : INT_MAX;
1713 // FIXME update, forcing the items to recalc height!!
1714}
1715//END Cardview
1716
1717#ifndef KAB_EMBEDDED
1718#include "cardview.moc"
1719#endif //KAB_EMBEDDED