summaryrefslogtreecommitdiffstats
path: root/kaddressbook/views
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch)
tree67208f7c145782a7e90b123b982ca78d88cc2c87 /kaddressbook/views
downloadtdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz
tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kaddressbook/views')
-rw-r--r--kaddressbook/views/Makefile.am38
-rw-r--r--kaddressbook/views/cardview.cpp1563
-rw-r--r--kaddressbook/views/cardview.desktop62
-rw-r--r--kaddressbook/views/cardview.h579
-rw-r--r--kaddressbook/views/colorlistbox.cpp193
-rw-r--r--kaddressbook/views/colorlistbox.h71
-rw-r--r--kaddressbook/views/configurecardviewdialog.cpp319
-rw-r--r--kaddressbook/views/configurecardviewdialog.h113
-rw-r--r--kaddressbook/views/configuretableviewdialog.cpp156
-rw-r--r--kaddressbook/views/configuretableviewdialog.h89
-rw-r--r--kaddressbook/views/contactlistview.cpp380
-rw-r--r--kaddressbook/views/contactlistview.h176
-rw-r--r--kaddressbook/views/iconview.desktop76
-rw-r--r--kaddressbook/views/kaddressbookcardview.cpp370
-rw-r--r--kaddressbook/views/kaddressbookcardview.h94
-rw-r--r--kaddressbook/views/kaddressbookiconview.cpp312
-rw-r--r--kaddressbook/views/kaddressbookiconview.h93
-rw-r--r--kaddressbook/views/kaddressbooktableview.cpp384
-rw-r--r--kaddressbook/views/kaddressbooktableview.h115
-rw-r--r--kaddressbook/views/tableview.desktop64
20 files changed, 5247 insertions, 0 deletions
diff --git a/kaddressbook/views/Makefile.am b/kaddressbook/views/Makefile.am
new file mode 100644
index 000000000..39db0f589
--- /dev/null
+++ b/kaddressbook/views/Makefile.am
@@ -0,0 +1,38 @@
+INCLUDES = -I$(top_srcdir) -I$(top_builddir)/kaddressbook/common \
+ -I$(top_srcdir)/kaddressbook/common \
+ -I$(top_srcdir)/kaddressbook/interfaces \
+ -I$(top_srcdir)/kaddressbook $(all_includes)
+
+kde_module_LTLIBRARIES = libkaddrbk_cardview.la libkaddrbk_iconview.la \
+ libkaddrbk_tableview.la
+
+XXLIBS = $(top_builddir)/kaddressbook/libkaddressbook.la
+
+libkaddrbk_cardview_la_SOURCES = cardview.cpp colorlistbox.cpp \
+ configurecardviewdialog.cpp \
+ kaddressbookcardview.cpp
+libkaddrbk_cardview_la_LDFLAGS = -module $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -no-undefined
+libkaddrbk_cardview_la_LIBADD = $(XXLIBS)
+
+libkaddrbk_iconview_la_SOURCES = kaddressbookiconview.cpp
+libkaddrbk_iconview_la_LDFLAGS = -module $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -no-undefined
+libkaddrbk_iconview_la_LIBADD = $(XXLIBS)
+
+libkaddrbk_tableview_la_SOURCES = configuretableviewdialog.cpp \
+ contactlistview.cpp \
+ kaddressbooktableview.cpp
+libkaddrbk_tableview_la_LDFLAGS = -module $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -no-undefined
+libkaddrbk_tableview_la_LIBADD = $(XXLIBS)
+
+noinst_HEADERS = cardview.h colorlistbox.h configurecardviewdialog.h \
+ configuretableviewdialog.h contactlistview.h \
+ kaddressbookcardview.h kaddressbookiconview.h \
+ kaddressbooktableview.h
+
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)/kaddressbook
+service_DATA = cardview.desktop iconview.desktop tableview.desktop
+
+kaddressbookiconview.lo kaddressbooktableview.lo kaddressbookcardview.lo: ../common/kabprefs_base.h
+
diff --git a/kaddressbook/views/cardview.cpp b/kaddressbook/views/cardview.cpp
new file mode 100644
index 000000000..82e987794
--- /dev/null
+++ b/kaddressbook/views/cardview.cpp
@@ -0,0 +1,1563 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+
+#include <limits.h>
+
+#include <qcursor.h>
+#include <qdatetime.h>
+#include <qlabel.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qtimer.h>
+#include <qtooltip.h>
+
+#include <kdebug.h>
+#include <kglobalsettings.h>
+
+#include "cardview.h"
+
+#define MIN_ITEM_WIDTH 80
+
+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();
+ }
+};
+
+//
+// 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;
+ }
+};
+
+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;
+};
+
+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 )
+ {};
+
+ CardViewItemList mItemList;
+ QPtrList<CardViewSeparator> mSeparatorList;
+ QFontMetrics *mFm;
+ QFontMetrics *mBFm;
+ QFont mHeaderFont;
+ 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 mColspace; // amount of space between items pr column
+ uint mFirst; // the first col to anchor at for painting rubber bands
+ int mFirstX; // X position of first in pixel
+ int mPressed; // the colummn that was pressed on at resizing start
+ int mSpan; // pressed - first
+ // key completion
+ QString mCompText; // current completion string
+ QDateTime mCompUpdated; // ...was updated at this time
+};
+
+class CardViewItemPrivate
+{
+ public:
+ CardViewItemPrivate() {}
+
+ 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
+};
+
+
+CardViewItem::CardViewItem( CardView *parent, const 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;
+
+ // 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();
+ p->setFont( bFont );
+ if ( isSelected() )
+ p->setPen( cg.highlightedText() );
+ else
+ p->setPen( cg.buttonText() );
+
+ p->drawText( 2 + mg, 2 + mg + bFm.ascent(), 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() + fm.height();
+ 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 + ":" );
+ }
+
+ 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;
+ }
+
+ 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() ) {
+ 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 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
+
+ bool sef = mView->showEmptyFields();
+ int fh = mView->d->mFm->height();
+ 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;
+ }
+
+ // 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 ) const
+{
+ 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() const
+{
+ 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 ) const
+{
+ 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;
+
+ s = isLabel ? f->first : f->second;
+
+ int colonWidth = mView->d->mFm->width(":");
+ lw = drawLabels ? QMIN( w / 2 - 4 - mrg, d->maxLabelWidth + colonWidth + 4 ) : 0;
+ int mw = isLabel ? lw - colonWidth : w - lw - ( mrg * 2 );
+ 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() );
+ tip->setText( s );
+ tip->adjustSize();
+ // find a proper position
+ int lx;
+ lx = isLabel || !drawLabels ? mrg : lw + mrg + 2;
+ 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;
+}
+
+
+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() ) );
+
+ setBackgroundMode( PaletteBackground, PaletteBase );
+
+ // 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() const
+{
+ 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 ) const
+{
+ CardViewItem *item = 0;
+ QPtrListIterator<CardViewItem> iter( d->mItemList );
+ bool found = false;
+ for ( iter.toFirst(); iter.current() && !found; ++iter ) {
+ item = *iter;
+ 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 ) const
+{
+ 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( 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( 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();
+ 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();
+}
+
+CardViewItem *CardView::findItem( const QString &text, const QString &label,
+ Qt::StringComparisonMode compare ) const
+{
+ // 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() const
+{
+ 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();
+
+ // allow setting costum colors in the viewport pale
+ QColorGroup cg = viewport()->palette().active();
+
+ 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 ) ) {
+ // 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 *event )
+{
+ QScrollView::resizeEvent( event );
+
+ setLayoutDirty( true );
+}
+
+void CardView::calcLayout()
+{
+ // 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( const CardViewItem *item ) const
+{
+ d->mItemList.findRef( item );
+ return d->mItemList.next();
+}
+
+uint CardView::itemMargin() const
+{
+ return d->mItemMargin;
+}
+
+void CardView::setItemMargin( uint margin )
+{
+ if ( margin == d->mItemMargin )
+ return;
+
+ d->mItemMargin = margin;
+ setLayoutDirty( true );
+}
+
+uint CardView::itemSpacing() const
+{
+ 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 = contentsToViewport( e->pos() );
+ d->mLastClickPos = e->pos();
+
+ CardViewItem *item = itemAt( e->pos() );
+
+ if ( item == 0 ) {
+ d->mLastClickOnItem = false;
+ if ( d->mOnSeparator) {
+ d->mResizeAnchor = e->x() + contentsX();
+ d->mColspace = (2 * d->mItemSpacing);
+ int ccw = d->mItemWidth + d->mColspace + d->mSepWidth;
+ d->mFirst = (contentsX() + d->mSepWidth) / ccw;
+ d->mPressed = (d->mResizeAnchor + d->mSepWidth) / ccw;
+ d->mSpan = d->mPressed - d->mFirst;
+ d->mFirstX = d->mFirst * ccw;
+ if ( d->mFirstX )
+ d->mFirstX -= d->mSepWidth;
+ } else {
+ selectAll( false );
+ }
+
+ return;
+ }
+
+ d->mLastClickOnItem = true;
+
+ CardViewItem *other = d->mCurrentItem;
+ setCurrentItem( item );
+
+ // Always emit the selection
+ emit clicked( item );
+
+ // The RMB click
+ if ( e->button() & Qt::RightButton ) {
+ // clear previous selection
+ bool blocked = signalsBlocked();
+ blockSignals( true );
+ selectAll( false );
+ blockSignals( blocked );
+
+ // select current item
+ item->setSelected( true );
+
+ emit contextMenuRequested( item, mapToGlobal( pos ) );
+ return;
+ }
+
+ // 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;
+
+ 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 && d->mSpan ) {
+ unsetCursor();
+ // hide rubber bands
+ int newiw = d->mItemWidth - ((d->mResizeAnchor - d->mRubberBandAnchor) / d->mSpan);
+ drawRubberBands( 0 );
+ // we should move to reflect the new position if we are scrolled.
+ if ( contentsX() ) {
+ int newX = QMAX( 0, ( d->mPressed * ( newiw + d->mColspace + 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( SplitHCursor );
+ 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 = 0;
+ 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;
+ case Key_Menu:
+ emit contextMenuRequested( d->mCurrentItem, viewport()->mapToGlobal(
+ itemRect(d->mCurrentItem).center() ) );
+ break;
+ default:
+ if ( (e->state() & ControlButton) && e->key() == Key_A ) {
+ // select all
+ selectAll( true );
+ break;
+ } else if ( !e->text().isEmpty() && e->text()[ 0 ].isPrint() ) {
+ // if we have a string, do autosearch
+ }
+ 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 );
+ }
+
+ 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
+ QPoint ipos = cpos - itemRect( item ).topLeft();
+ item->showFullString( ipos, d->mTip );
+ }
+}
+
+void CardView::drawRubberBands( int pos )
+{
+ if ( pos && d &&
+ (!d->mSpan || ((pos - d->mFirstX) / d->mSpan) - d->mColspace - d->mSepWidth < MIN_ITEM_WIDTH) )
+ return;
+
+ int tmpcw = (d->mRubberBandAnchor - d->mFirstX) / d->mSpan;
+ int x = d->mFirstX + tmpcw - d->mSepWidth - contentsX();
+ int h = visibleHeight();
+
+ QPainter p( viewport() );
+ p.setRasterOp( XorROP );
+ p.setPen( gray );
+ p.setBrush( gray );
+ uint n = d->mFirst;
+ // 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->mFirstX) / d->mSpan;
+ n = d->mFirst;
+ x = d->mFirstX + 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 );
+ updateContents();
+}
+
+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() const
+{
+ return d->mSepWidth;
+}
+
+void CardView::setSeparatorWidth( int width )
+{
+ d->mSepWidth = width;
+ setLayoutDirty( true );
+}
+
+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!!
+}
+
+#include "cardview.moc"
diff --git a/kaddressbook/views/cardview.desktop b/kaddressbook/views/cardview.desktop
new file mode 100644
index 000000000..cb8d35cb0
--- /dev/null
+++ b/kaddressbook/views/cardview.desktop
@@ -0,0 +1,62 @@
+[Desktop Entry]
+X-KDE-Library=libkaddrbk_cardview
+Name=Card View
+Name[af]=Kaard Aansig
+Name[ar]=عرض البظاقة
+Name[be]=У выглядзе картак
+Name[bg]=Преглед като карти
+Name[br]=Gwell ar c'hartennoù
+Name[bs]=Pogled kartice
+Name[ca]=Vista de targeta
+Name[cs]=Pohled s kartičkami
+Name[cy]=Gweld Cerdyn
+Name[da]=Kort-visning
+Name[de]=Visitenkarten-Betrachter
+Name[el]=Προβολή καρτών
+Name[eo]=Kartrigardo
+Name[es]=Vista de tarjeta
+Name[et]=Kaardivaade
+Name[eu]=Txartel ikuspegia
+Name[fa]=نمای کارت
+Name[fi]=Korttinäkymä
+Name[fr]=Vue en cartes
+Name[fy]=Kaartwerjefte
+Name[gl]=Vista de tarxetas
+Name[he]=תצוגת כרטיס
+Name[hi]=कार्ड दृश्य
+Name[hu]=Kártyanézet
+Name[is]=Spjaldsýn
+Name[it]=Vista scheda
+Name[ja]=カードビュー
+Name[ka]=ბარათების ჩვენება
+Name[kk]=Визитка
+Name[km]=ទិដ្ឋភាព​កាត
+Name[lt]=Kortelės vaizdas
+Name[mk]=Преглед со картички
+Name[ms]=Pelihat Kad
+Name[nb]=Kortvisning
+Name[nds]=Visitenkoort-Kieker
+Name[ne]=कार्ड दृश्य
+Name[nl]=Kaartweergave
+Name[nn]=Kortvising
+Name[pa]=ਕਾਰਡ ਦਰਿਸ਼
+Name[pl]=Widok kartek
+Name[pt]=Vista em Cartões
+Name[pt_BR]=Visualização de Cartão
+Name[ro]=Vizualizare card
+Name[ru]=Карточки
+Name[se]=Goartačájeheapmi
+Name[sk]=Prezeranie karty
+Name[sl]=Kartični prikaz
+Name[sr]=Приказ са картицама
+Name[sr@Latn]=Prikaz sa karticama
+Name[sv]=Kortvy
+Name[ta]=அட்டைக் காட்சி
+Name[tg]=Варақа
+Name[tr]=Kart Görünümü
+Name[uk]=Вигляд картками
+Name[zh_CN]=卡片视图
+Name[zh_TW]=卡片檢視
+Type=Service
+ServiceTypes=KAddressBook/View
+X-KDE-KAddressBook-ViewPluginVersion=1
diff --git a/kaddressbook/views/cardview.h b/kaddressbook/views/cardview.h
new file mode 100644
index 000000000..e38a82d53
--- /dev/null
+++ b/kaddressbook/views/cardview.h
@@ -0,0 +1,579 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#ifndef CARDVIEW_H
+#define CARDVIEW_H
+
+#include <qpair.h>
+#include <qpoint.h>
+#include <qptrlist.h>
+#include <qrect.h>
+#include <qscrollview.h>
+#include <qstring.h>
+
+class QLabel;
+class QMouseEvent;
+class QPainter;
+class QResizeEvent;
+
+class CardView;
+class CardViewItemPrivate;
+class CardViewPrivate;
+class CardViewTip;
+
+/**
+ Represents a single card (item) in the card view. A card has a caption
+ and a list of fields. A Field is a label<->value pair. The labels in a
+ card should be unique, since they will be used to index the values.
+ */
+class CardViewItem
+{
+ friend class CardView;
+
+ public:
+ /**
+ A single field in the card view. The first item is the label
+ and the second item is the value.
+ */
+ typedef QPair<QString, QString> Field;
+
+ /**
+ Constructor.
+
+ @param parent The CardView that this card should be displayed on.
+ @param caption The caption of the card. This is the text that will
+ appear at the top of the card. This is also the string that will
+ be used to sort the cards in the view.
+ */
+ CardViewItem( CardView *parent, const QString &caption = QString() );
+ virtual ~CardViewItem();
+
+ /**
+ @return The caption of the card, or QString::null if none was ever set.
+ */
+ const QString &caption() const;
+
+ /**
+ Sets the caption of the card. This is the text that will
+ appear at the top of the card. This is also the string that will
+ be used to sort the cards in the view.
+ */
+ void setCaption( const QString &caption );
+
+ /**
+ Paints the card using the given painter and color group. The
+ card will handle painting itself selected if it is selected.
+ */
+ virtual void paintCard( QPainter *p, QColorGroup &cg );
+
+ /**
+ Repaints the card. This is done by sending a repaint event to the
+ view with the clip rect defined as this card.
+ */
+ virtual void repaintCard();
+
+ /**
+ Adds a field to the card.
+
+ @param label The label of the field. The field labels must be unique
+ within a card.
+ @param value The value of the field.
+ */
+ void insertField( const QString &label, const QString &value );
+
+ /**
+ Removes the field with label <i>label</i> from the card.
+ */
+ void removeField( const QString &label );
+
+ /**
+ @return The value of the field with label <i>label</i>.
+ */
+ QString fieldValue( const QString &label ) const;
+
+ /**
+ Removes all the fields from this card.
+ */
+ void clearFields();
+
+ /**
+ @return The next card item. The order of the items will be the same
+ as the display order in the view. 0 will be returned if this is the
+ last card.
+ */
+ CardViewItem *nextItem() const;
+
+ /**
+ @return True if this card is currently selected, false otherwise.
+ */
+ bool isSelected() const;
+
+ /**
+ Called by the parent card view when the mouse has been resting for
+ a certain amount of time. If the label or value at pos is obscured
+ (trimmed) make the label display the full text.
+ */
+ void showFullString( const QPoint &pos, CardViewTip *tip );
+
+ /**
+ @return a pointer to the Field at the position itempos
+ in this item. 0 is returned if itempos is in the caption.
+ @param itempos the position in item coordinates
+ */
+ Field *fieldAt( const QPoint &itempos ) const;
+
+ CardView *cardView() const { return mView; };
+
+ /**
+ @return The height of this item as rendered, in pixels.
+
+ if @p allowCache is true, the item may use an internally
+ cached value rather than recalculating from scratch. The
+ argument is mainly to allow the cardView to change global settings (like
+ maxFieldLines) that might influence the items heights
+ */
+ int height( bool allowCache = true ) const;
+
+ protected:
+ /**
+ Sets the card as selected. This is usually only called from the
+ card view.
+ */
+ void setSelected( bool selected );
+
+ private:
+ /**
+ Sets the default values.
+ */
+ void initialize();
+
+ /**
+ Trims a string to the width <i>width</i> using the font metrics
+ to determine the width of each char. If the string is longer than
+ <i>width</i>, then the string will be trimmed and a '...' will
+ be appended.
+ */
+ QString trimString( const QString &text, int width, QFontMetrics &fm ) const;
+
+ CardViewItemPrivate *d;
+ CardView *mView;
+};
+
+/**
+ The CardView is a method of displaying data in cards. This idea is
+ similar to the idea of a rolodex or business cards. Each card has a
+ caption and a list of fields, which are label<->value pairs. The CardView
+ displays multiple cards in a grid. The Cards are sorted based on their
+ caption.
+
+ The CardView class is designed to mirror the API of the QListView or
+ QIconView. The CardView is also completely independant of KAddressBook and
+ can be used elsewhere. With the exception of a few simple config checks,
+ the CardView is also 100% independant of KDE.
+ */
+class CardView : public QScrollView
+{
+ friend class CardViewItem;
+
+ Q_OBJECT
+
+ public:
+ /**
+ Constructor.
+ */
+ CardView( QWidget *parent, const char *name );
+ virtual ~CardView();
+
+ /**
+ Inserts the item into the card view. This method does not have
+ to be called if you created the item with a proper parent. Once
+ inserted, the CardView takes ownership of the item.
+ */
+ void insertItem( CardViewItem *item );
+
+ /**
+ Takes the item from the view. The item will not be deleted and
+ ownership of the item is returned to the caller.
+ */
+ void takeItem( CardViewItem *item );
+
+ /**
+ Clears the view and deletes all card view items
+ */
+ void clear();
+
+ /**
+ @return The current item, the item that has the focus.
+ Whenever the view has focus, this item has a focus rectangle painted
+ at it's border.
+ @sa setCurrentItem()
+ */
+ CardViewItem *currentItem() const;
+
+ /**
+ Sets the CardViewItem @p item to the current item in the view.
+ */
+ void setCurrentItem( CardViewItem *item );
+
+ /**
+ @return The item found at the given point, or 0 if there is no item
+ at that point.
+ */
+ CardViewItem *itemAt( const QPoint &viewPos ) const;
+
+ /**
+ @return The bounding rect of the given item.
+ */
+ QRect itemRect( const CardViewItem *item ) const;
+
+ /**
+ Ensures that the given item is in the viewable area of the widget
+ */
+ void ensureItemVisible( const CardViewItem *item );
+
+ /**
+ Repaints the given item.
+ */
+ void repaintItem( const CardViewItem *item );
+
+ enum SelectionMode { Single, Multi, Extended, NoSelection };
+
+ /**
+ Sets the selection mode.
+
+ @see QListView
+ */
+ void setSelectionMode( SelectionMode mode );
+
+ /**
+ @return The current selection mode.
+ */
+ SelectionMode selectionMode() const;
+
+ /**
+ Selects or deselects the given item. This method honors the current
+ selection mode, so if other items are selected, they may be unselected.
+ */
+ void setSelected( CardViewItem *item, bool selected );
+
+ /**
+ Selects or deselects all items.
+ */
+ void selectAll( bool state );
+
+ /**
+ @return True if the given item is selected, false otherwise.
+ */
+ bool isSelected( CardViewItem *item ) const;
+
+ /**
+ @return The first selected item. In single select mode, this will be
+ the only selected item, in other modes this will be the first selected
+ item, but others may exist. 0 if no item is selected.
+ */
+ CardViewItem *selectedItem() const;
+
+ /**
+ @return The first item in the view. This may be 0 if no items have
+ been inserted. This method combined with CardViewItem::nextItem()
+ can be used to iterator through the list of items.
+ */
+ CardViewItem *firstItem() const;
+
+ /**
+ @return The item after the given item or 0 if the item is the last
+ item.
+ */
+ CardViewItem *itemAfter( const CardViewItem *item ) const;
+
+ /**
+ @return The number of items in the view.
+ */
+ int childCount() const;
+
+ /**
+ Attempts to find the first item matching the params.
+
+ @param text The text to match.
+ @param label The label of the field to match against.
+ @param compare The compare method to use in doing the search.
+
+ @return The first matching item, or 0 if no items match.
+ */
+ CardViewItem *findItem( const QString &text, const QString &label,
+ Qt::StringComparisonMode compare = Qt::BeginsWith ) const;
+
+ /**
+ Returns the amounts of pixels required for one column.
+ This depends on wheather drawSeparators is enabled:
+ If so, it is itemWidth + 2*itemSpacing + separatorWidth
+ If not, it is itemWidth + itemSpacing
+ @see itemWidth(), setItemWidth(), itemSpacing() and setItemSpacing()
+ */
+ uint columnWidth() const;
+
+ /**
+ Sets if the border around a card should be draw. The border is a thing
+ (1 or 2 pixel) line that bounds the card. When drawn, it shows when
+ a card is highlighted and when it isn't.
+ */
+ void setDrawCardBorder( bool enabled );
+
+ /**
+ @return True if borders are drawn, false otherwise.
+ */
+ bool drawCardBorder() const;
+
+ /**
+ Sets if the column separator should be drawn. The column separator
+ is a thin verticle line (1 or 2 pixels) that is used to separate the
+ columns in the list view. The separator is just for esthetics and it
+ does not serve a functional purpose.
+ */
+ void setDrawColSeparators( bool enabled );
+
+ /**
+ @return True if column separators are drawn, false otherwise.
+ */
+ bool drawColSeparators() const;
+
+ /**
+ Sets if the field labels should be drawn. The field labels are the
+ unique strings used to identify the fields. Sometimes drawing these
+ labels makes sense as a source of clarity for the user, othertimes they
+ waste too much space and do not assist the user.
+ */
+ void setDrawFieldLabels( bool enabled );
+
+ /**
+ @return True if the field labels are drawn, false otherwise.
+ */
+ bool drawFieldLabels() const;
+
+ /**
+ Sets if fields with no value should be drawn (of cause the label only,
+ but it allows for embedded editing sometimes...)
+ */
+ void setShowEmptyFields( bool show );
+
+ /**
+ @return Wheather empty fields should be shown
+ */
+ bool showEmptyFields() const;
+
+ /**
+ @return the advisory internal margin in items. Setting a value above 1 means
+ a space between the item contents and the focus recttangle drawn around
+ the current item. The default value is 0.
+ The value should be used by CardViewItem and derived classes.
+ Note that this should not be greater than half of the minimal item width,
+ which is 80. It is currently not checked, so setting a value greater than 40
+ will probably mean a crash in the items painting routine.
+ */
+ // Note: I looked for a value in QStyle::PixelMetric to use, but I could
+ // not see a useful one. One may turn up in a future version of Qt.
+ uint itemMargin() const;
+
+ /**
+ Sets the internal item margin. See itemMargin().
+ */
+ void setItemMargin( uint margin );
+
+ /**
+ @return the item spacing.
+ The item spacing is the space (in pixels) between each item in a
+ column, between the items and column separators if drawn, and between
+ the items and the borders of the widget. The default value is set to 10.
+ */
+ // Note: There is no useful QStyle::PixelMetric to use for this atm.
+ // An option would be using KDialog::spacingHint().
+ uint itemSpacing() const;
+
+ /**
+ Sets the item spacing.
+ @see itemSpacing()
+ */
+ void setItemSpacing( uint spacing );
+
+ /**
+ @return the width made available to the card items.
+ */
+ int itemWidth() const;
+
+ /**
+ Sets the width made available to card items.
+ */
+ void setItemWidth( int width );
+
+ /**
+ Sets the header font
+ */
+ void setHeaderFont( const QFont &fnt );
+
+ /**
+ @return the header font
+ */
+ QFont headerFont() const;
+
+ /**
+ Reimplementation from QWidget
+ */
+ void setFont( const QFont &fnt );
+
+ /**
+ Sets the column separator width
+ */
+ void setSeparatorWidth( int width );
+
+ /**
+ @return the column separator width
+ */
+ int separatorWidth() const;
+
+ /**
+ Sets the maximum number of lines to display pr field.
+ If set to 0 (the default) all lines will be displayed.
+ */
+ void setMaxFieldLines( int howmany );
+
+ /**
+ @return the maximum number of lines pr field
+ */
+ int maxFieldLines() const;
+
+ signals:
+ /**
+ Emitted whenever the selection changes. This means a user highlighted
+ a new item or unhighlighted a currently selected item.
+ */
+ void selectionChanged();
+
+ /**
+ Same as above method, only it carries the item that was selected. This
+ method will only be emitted in single select mode, since it defineds
+ which item was selected.
+ */
+ void selectionChanged( CardViewItem* );
+
+ /**
+ This method is emitted whenever an item is clicked.
+ */
+ void clicked( CardViewItem* );
+
+ /**
+ Emitted whenever the user 'executes' an item. This is dependant on
+ the KDE global config. This could be a single click or a doubleclick.
+ Also emitted when the return key is pressed on an item.
+ */
+ void executed( CardViewItem* );
+
+ /**
+ Emitted whenever the user double clicks on an item.
+ */
+ void doubleClicked( CardViewItem* );
+
+ /**
+ Emitted when the current item changes
+ */
+ void currentChanged( CardViewItem* );
+
+ /**
+ Emitted when the return key is pressed in an item.
+ */
+ void returnPressed( CardViewItem* );
+
+ /**
+ Emitted when the context menu is requested in some way.
+ */
+ void contextMenuRequested( CardViewItem*, const QPoint& );
+
+ protected:
+ /**
+ Determines which cards intersect that region and tells them to paint
+ themselves.
+ */
+ void drawContents( QPainter *p, int clipx, int clipy, int clipw, int cliph );
+
+ /**
+ Sets the layout to dirty and repaints.
+ */
+ void resizeEvent( QResizeEvent* );
+
+ /**
+ Changes the direction the canvas scolls.
+ */
+ void contentsWheelEvent( QWheelEvent* );
+
+ /**
+ Sets the layout to dirty and calls for a repaint.
+ */
+ void setLayoutDirty( bool dirty );
+
+ /**
+ Does the math based on the bounding rect of the cards to properly
+ lay the cards out on the screen. This is only done if the layout is
+ marked as dirty.
+ */
+ void calcLayout();
+
+ virtual void contentsMousePressEvent( QMouseEvent* );
+ virtual void contentsMouseMoveEvent( QMouseEvent* );
+ virtual void contentsMouseReleaseEvent( QMouseEvent* );
+ virtual void contentsMouseDoubleClickEvent( QMouseEvent* );
+
+ virtual void enterEvent( QEvent* );
+ virtual void leaveEvent( QEvent* );
+
+ virtual void focusInEvent( QFocusEvent* );
+ virtual void focusOutEvent( QFocusEvent* );
+
+ virtual void keyPressEvent( QKeyEvent* );
+
+ /**
+ Overload this method to be told when a drag should be started.
+ In most cases you will want to start a drag event with the currently
+ selected item.
+ */
+ virtual void startDrag();
+
+ private slots:
+ /**
+ Called by a timer to display a label with truncated text.
+ Pop up a label, if there is a field with obscured text or
+ label at the cursor position.
+ */
+ void tryShowFullText();
+
+ private:
+ /**
+ draws and erases the rubber bands while columns are resized.
+ @p pos is the horizontal position inside the viewport to use as
+ the anchor.
+ If pos is 0, only erase is done.
+ */
+ void drawRubberBands( int pos );
+
+ CardViewPrivate *d;
+};
+
+#endif
diff --git a/kaddressbook/views/colorlistbox.cpp b/kaddressbook/views/colorlistbox.cpp
new file mode 100644
index 000000000..37a2ac1f4
--- /dev/null
+++ b/kaddressbook/views/colorlistbox.cpp
@@ -0,0 +1,193 @@
+/*
+ * kmail: KDE mail client
+ * This file: Copyright (C) 2000 Espen Sand, espen@kde.org
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <qpainter.h>
+
+#include <kcolordialog.h>
+#include <kcolordrag.h>
+
+#include "colorlistbox.h"
+
+ColorListBox::ColorListBox( QWidget *parent, const char *name, WFlags f )
+ :KListBox( parent, name, f ), mCurrentOnDragEnter(-1)
+{
+ connect( this, SIGNAL(selected(int)), this, SLOT(newColor(int)) );
+ setAcceptDrops( true);
+}
+
+
+void ColorListBox::setEnabled( bool state )
+{
+ if( state == isEnabled() )
+ {
+ return;
+ }
+
+ QListBox::setEnabled( state );
+ for( uint i=0; i<count(); i++ )
+ {
+ updateItem( i );
+ }
+}
+
+
+void ColorListBox::setColor( uint index, const QColor &color )
+{
+ if( index < count() )
+ {
+ ColorListItem *colorItem = (ColorListItem*)item(index);
+ colorItem->setColor(color);
+ updateItem( colorItem );
+ }
+}
+
+
+QColor ColorListBox::color( uint index ) const
+{
+ if( index < count() )
+ {
+ ColorListItem *colorItem = (ColorListItem*)item(index);
+ return( colorItem->color() );
+ }
+ else
+ {
+ return( black );
+ }
+}
+
+
+void ColorListBox::newColor( int index )
+{
+ if( isEnabled() == false )
+ {
+ return;
+ }
+
+ if( (uint)index < count() )
+ {
+ QColor c = color( index );
+ if( KColorDialog::getColor( c, this ) != QDialog::Rejected )
+ {
+ setColor( index, c );
+ }
+ }
+}
+
+
+void ColorListBox::dragEnterEvent( QDragEnterEvent *e )
+{
+ if( KColorDrag::canDecode(e) && isEnabled() )
+ {
+ mCurrentOnDragEnter = currentItem();
+ e->accept( true );
+ }
+ else
+ {
+ mCurrentOnDragEnter = -1;
+ e->accept( false );
+ }
+}
+
+
+void ColorListBox::dragLeaveEvent( QDragLeaveEvent * )
+{
+ if( mCurrentOnDragEnter != -1 )
+ {
+ setCurrentItem( mCurrentOnDragEnter );
+ mCurrentOnDragEnter = -1;
+ }
+}
+
+
+void ColorListBox::dragMoveEvent( QDragMoveEvent *e )
+{
+ if( KColorDrag::canDecode(e) && isEnabled() )
+ {
+ ColorListItem *item = (ColorListItem*)itemAt( e->pos() );
+ if( item != 0 )
+ {
+ setCurrentItem ( item );
+ }
+ }
+}
+
+
+void ColorListBox::dropEvent( QDropEvent *e )
+{
+ QColor color;
+ if( KColorDrag::decode( e, color ) )
+ {
+ int index = currentItem();
+ if( index != -1 )
+ {
+ ColorListItem *colorItem = (ColorListItem*)item(index);
+ colorItem->setColor(color);
+ triggerUpdate( false ); // Redraw item
+ }
+ mCurrentOnDragEnter = -1;
+ }
+}
+
+
+
+ColorListItem::ColorListItem( const QString &text, const QColor &color )
+ : QListBoxItem(), mColor( color ), mBoxWidth( 30 )
+{
+ setText( text );
+}
+
+
+const QColor &ColorListItem::color( void )
+{
+ return( mColor );
+}
+
+
+void ColorListItem::setColor( const QColor &color )
+{
+ mColor = color;
+}
+
+
+void ColorListItem::paint( QPainter *p )
+{
+ QFontMetrics fm = p->fontMetrics();
+ int h = fm.height();
+
+ p->drawText( mBoxWidth+3*2, fm.ascent() + fm.leading()/2, text() );
+
+ p->setPen( Qt::black );
+ p->drawRect( 3, 1, mBoxWidth, h-1 );
+ p->fillRect( 4, 2, mBoxWidth-2, h-3, mColor );
+}
+
+
+int ColorListItem::height(const QListBox *lb ) const
+{
+ return( lb->fontMetrics().lineSpacing()+1 );
+}
+
+
+int ColorListItem::width(const QListBox *lb ) const
+{
+ return( mBoxWidth + lb->fontMetrics().width( text() ) + 6 );
+}
+
+#include "colorlistbox.moc"
diff --git a/kaddressbook/views/colorlistbox.h b/kaddressbook/views/colorlistbox.h
new file mode 100644
index 000000000..06b2c4627
--- /dev/null
+++ b/kaddressbook/views/colorlistbox.h
@@ -0,0 +1,71 @@
+/*
+ * kmail: KDE mail client
+ * This file: Copyright (C) 2000 Espen Sand, espen@kde.org
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _COLOR_LISTBOX_H_
+#define _COLOR_LISTBOX_H_
+
+#include <klistbox.h>
+
+class ColorListBox : public KListBox
+{
+ Q_OBJECT
+
+ public:
+ ColorListBox( QWidget *parent=0, const char * name=0, WFlags f=0 );
+ void setColor( uint index, const QColor &color );
+ QColor color( uint index ) const;
+
+ public slots:
+ virtual void setEnabled( bool state );
+
+ protected:
+ void dragEnterEvent( QDragEnterEvent *e );
+ void dragLeaveEvent( QDragLeaveEvent *e );
+ void dragMoveEvent( QDragMoveEvent *e );
+ void dropEvent( QDropEvent *e );
+
+ private slots:
+ void newColor( int index );
+
+ private:
+ int mCurrentOnDragEnter;
+
+};
+
+
+class ColorListItem : public QListBoxItem
+{
+ public:
+ ColorListItem( const QString &text, const QColor &color=Qt::black );
+ const QColor &color( void );
+ void setColor( const QColor &color );
+
+ protected:
+ virtual void paint( QPainter * );
+ virtual int height( const QListBox * ) const;
+ virtual int width( const QListBox * ) const;
+
+ private:
+ QColor mColor;
+ int mBoxWidth;
+};
+
+#endif
+
diff --git a/kaddressbook/views/configurecardviewdialog.cpp b/kaddressbook/views/configurecardviewdialog.cpp
new file mode 100644
index 000000000..8843d3c68
--- /dev/null
+++ b/kaddressbook/views/configurecardviewdialog.cpp
@@ -0,0 +1,319 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#include <qstring.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qvbox.h>
+#include <qgroupbox.h>
+#include <qspinbox.h>
+#include <qtabwidget.h>
+#include <qwhatsthis.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kconfig.h>
+#include <kfontdialog.h>
+#include <kpushbutton.h>
+
+#include "colorlistbox.h"
+
+#include "configurecardviewdialog.h"
+
+/////////////////////////////////
+// ConfigureCardViewDialog
+
+ConfigureCardViewWidget::ConfigureCardViewWidget( KABC::AddressBook *ab, QWidget *parent,
+ const char *name )
+ : ViewConfigureWidget( ab, parent, name )
+{
+ QWidget *page = addPage( i18n( "Look & Feel" ), QString::null,
+ DesktopIcon( "looknfeel" ) );
+ mAdvancedPage = new CardViewLookNFeelPage( page );
+}
+
+ConfigureCardViewWidget::~ConfigureCardViewWidget()
+{
+}
+
+void ConfigureCardViewWidget::restoreSettings( KConfig *config )
+{
+ ViewConfigureWidget::restoreSettings( config );
+
+ mAdvancedPage->restoreSettings( config );
+}
+
+void ConfigureCardViewWidget::saveSettings( KConfig *config )
+{
+ ViewConfigureWidget::saveSettings( config );
+
+ mAdvancedPage->saveSettings( config );
+}
+
+////////////////////////
+// CardViewLookNFeelPage
+CardViewLookNFeelPage::CardViewLookNFeelPage( QWidget *parent, const char *name )
+ : QVBox( parent, name )
+{
+ initGUI();
+}
+
+CardViewLookNFeelPage::~CardViewLookNFeelPage()
+{
+}
+
+void CardViewLookNFeelPage::restoreSettings( KConfig *config )
+{
+ // colors
+ cbEnableCustomColors->setChecked( config->readBoolEntry( "EnableCustomColors", false ) );
+ QColor c;
+ c = KGlobalSettings::baseColor();
+ lbColors->insertItem( new ColorListItem( i18n("Background Color"),
+ config->readColorEntry( "BackgroundColor", &c ) ) );
+ c = colorGroup().foreground();
+ lbColors->insertItem( new ColorListItem( i18n("Text Color"),
+ config->readColorEntry( "TextColor", &c ) ) );
+ c = colorGroup().button();
+ lbColors->insertItem( new ColorListItem( i18n("Header, Border & Separator Color"),
+ config->readColorEntry( "HeaderColor", &c ) ) );
+ c = colorGroup().buttonText();
+ lbColors->insertItem( new ColorListItem( i18n("Header Text Color"),
+ config->readColorEntry( "HeaderTextColor", &c ) ) );
+ c = colorGroup().highlight();
+ lbColors->insertItem( new ColorListItem( i18n("Highlight Color"),
+ config->readColorEntry( "HighlightColor", &c ) ) );
+ c = colorGroup().highlightedText();
+ lbColors->insertItem( new ColorListItem( i18n("Highlighted Text Color"),
+ config->readColorEntry( "HighlightedTextColor", &c ) ) );
+
+ enableColors();
+
+ // fonts
+ QFont fnt = font();
+ updateFontLabel( config->readFontEntry( "TextFont", &fnt ), (QLabel*)lTextFont );
+ fnt.setBold( true );
+ updateFontLabel( config->readFontEntry( "HeaderFont", &fnt ), (QLabel*)lHeaderFont );
+ cbEnableCustomFonts->setChecked( config->readBoolEntry( "EnableCustomFonts", false ) );
+ enableFonts();
+
+ // layout
+ sbMargin->setValue( config->readNumEntry( "ItemMargin", 0 ) );
+ sbSpacing->setValue( config->readNumEntry( "ItemSpacing", 10 ) );
+ sbSepWidth->setValue( config->readNumEntry( "SeparatorWidth", 2 ) );
+ cbDrawSeps->setChecked( config->readBoolEntry( "DrawSeparators", true ) );
+ cbDrawBorders->setChecked( config->readBoolEntry( "DrawBorder", true ) );
+
+ // behaviour
+ cbShowFieldLabels->setChecked( config->readBoolEntry( "DrawFieldLabels", false ) );
+ cbShowEmptyFields->setChecked( config->readBoolEntry( "ShowEmptyFields", false ) );
+}
+
+void CardViewLookNFeelPage::saveSettings( KConfig *config )
+{
+ // colors
+ config->writeEntry( "EnableCustomColors", cbEnableCustomColors->isChecked() );
+ if ( cbEnableCustomColors->isChecked() ) // ?? - Hmmm.
+ {
+ config->writeEntry( "BackgroundColor", lbColors->color( 0 ) );
+ config->writeEntry( "TextColor", lbColors->color( 1 ) );
+ config->writeEntry( "HeaderColor", lbColors->color( 2 ) );
+ config->writeEntry( "HeaderTextColor", lbColors->color( 3 ) );
+ config->writeEntry( "HighlightColor", lbColors->color( 4 ) );
+ config->writeEntry( "HighlightedTextColor", lbColors->color( 5 ) );
+ }
+ // fonts
+ config->writeEntry( "EnableCustomFonts", cbEnableCustomFonts->isChecked() );
+ if ( cbEnableCustomFonts->isChecked() )
+ {
+ config->writeEntry( "TextFont", lTextFont->font() );
+ config->writeEntry( "HeaderFont", lHeaderFont->font() );
+ }
+ // layout
+ config->writeEntry( "ItemMargin", sbMargin->value() );
+ config->writeEntry( "ItemSpacing", sbSpacing->value() );
+ config->writeEntry( "SeparatorWidth", sbSepWidth->value() );
+ config->writeEntry("DrawBorder", cbDrawBorders->isChecked());
+ config->writeEntry("DrawSeparators", cbDrawSeps->isChecked());
+
+ // behaviour
+ config->writeEntry("DrawFieldLabels", cbShowFieldLabels->isChecked());
+ config->writeEntry("ShowEmptyFields", cbShowEmptyFields->isChecked());
+}
+
+void CardViewLookNFeelPage::setTextFont()
+{
+ QFont f( lTextFont->font() );
+ if ( KFontDialog::getFont( f, false, this ) == QDialog::Accepted )
+ updateFontLabel( f, lTextFont );
+}
+
+void CardViewLookNFeelPage::setHeaderFont()
+{
+ QFont f( lHeaderFont->font() );
+ if ( KFontDialog::getFont( f,false, this ) == QDialog::Accepted )
+ updateFontLabel( f, lHeaderFont );
+}
+
+void CardViewLookNFeelPage::enableFonts()
+{
+ vbFonts->setEnabled( cbEnableCustomFonts->isChecked() );
+}
+
+void CardViewLookNFeelPage::enableColors()
+{
+ lbColors->setEnabled( cbEnableCustomColors->isChecked() );
+}
+
+void CardViewLookNFeelPage::initGUI()
+{
+ int spacing = KDialog::spacingHint();
+ int margin = KDialog::marginHint();
+
+ QTabWidget *tabs = new QTabWidget( this );
+
+ // Layout
+ QVBox *loTab = new QVBox( this, "layouttab" );
+
+ loTab->setSpacing( spacing );
+ loTab->setMargin( margin );
+
+ QGroupBox *gbGeneral = new QGroupBox( 1, Qt::Horizontal, i18n("General"), loTab );
+
+ cbDrawSeps = new QCheckBox( i18n("Draw &separators"), gbGeneral );
+
+ QHBox *hbSW = new QHBox( gbGeneral );
+ QLabel *lSW = new QLabel( i18n("Separator &width:"), hbSW );
+ sbSepWidth = new QSpinBox( 1, 50, 1, hbSW );
+ lSW->setBuddy( sbSepWidth);
+
+ QHBox *hbPadding = new QHBox( gbGeneral );
+ QLabel *lSpacing = new QLabel( i18n("&Padding:"), hbPadding );
+ sbSpacing = new QSpinBox( 0, 100, 1, hbPadding );
+ lSpacing->setBuddy( sbSpacing );
+
+ QGroupBox *gbCards = new QGroupBox( 1, Qt::Horizontal, i18n("Cards"), loTab );
+
+ QHBox *hbMargin = new QHBox( gbCards );
+ QLabel *lMargin = new QLabel( i18n("&Margin:"), hbMargin );
+ sbMargin = new QSpinBox( 0, 100, 1, hbMargin );
+ lMargin->setBuddy( sbMargin );
+
+ cbDrawBorders = new QCheckBox( i18n("Draw &borders"), gbCards );
+
+ loTab->setStretchFactor( new QWidget( loTab ), 1 );
+
+ QWhatsThis::add( sbMargin, i18n(
+ "The item margin is the distance (in pixels) between the item edge and the item data. Most noticeably, "
+ "incrementing the item margin will add space between the focus rectangle and the item data."
+ ) );
+ QWhatsThis::add( lMargin, QWhatsThis::textFor( sbMargin ) );
+ QWhatsThis::add( sbSpacing, i18n(
+ "The item spacing decides the distance (in pixels) between the items and anything else: the view "
+ "borders, other items or column separators."
+ ) );
+ QWhatsThis::add( lSpacing, QWhatsThis::textFor( sbSpacing ) );
+ QWhatsThis::add( sbSepWidth, i18n("Sets the width of column separators") );
+ QWhatsThis::add( lSW, QWhatsThis::textFor( sbSepWidth ) );
+
+ tabs->addTab( loTab, i18n("&Layout") );
+
+ // Colors
+ QVBox *colorTab = new QVBox( this, "colortab" );
+ colorTab->setSpacing( spacing );
+ colorTab->setMargin( spacing );
+ cbEnableCustomColors = new QCheckBox( i18n("&Enable custom colors"), colorTab );
+ connect( cbEnableCustomColors, SIGNAL(clicked()), this, SLOT(enableColors()) );
+ lbColors = new ColorListBox( colorTab );
+ tabs->addTab( colorTab, i18n("&Colors") );
+
+ QWhatsThis::add( cbEnableCustomColors, i18n(
+ "If custom colors is enabled, you may choose the colors for the view below. "
+ "Otherwise colors from your current KDE color scheme are used."
+ ) );
+ QWhatsThis::add( lbColors, i18n(
+ "Double click or press RETURN on a item to select a color for the related strings in the view."
+ ) );
+
+ // Fonts
+ QVBox *fntTab = new QVBox( this, "fonttab" );
+
+ fntTab->setSpacing( spacing );
+ fntTab->setMargin( spacing );
+
+ cbEnableCustomFonts = new QCheckBox( i18n("&Enable custom fonts"), fntTab );
+ connect( cbEnableCustomFonts, SIGNAL(clicked()), this, SLOT(enableFonts()) );
+
+ vbFonts = new QWidget( fntTab );
+ QGridLayout *gFnts = new QGridLayout( vbFonts, 2, 3 );
+ gFnts->setSpacing( spacing );
+ gFnts->setAutoAdd( true );
+ gFnts->setColStretch( 1, 1 );
+ QLabel *lTFnt = new QLabel( i18n("&Text font:"), vbFonts );
+ lTextFont = new QLabel( vbFonts );
+ lTextFont->setFrameStyle( QFrame::Panel|QFrame::Sunken );
+ btnFont = new KPushButton( i18n("Choose..."), vbFonts );
+ lTFnt->setBuddy( btnFont );
+ connect( btnFont, SIGNAL(clicked()), this, SLOT(setTextFont()) );
+
+ QLabel *lHFnt = new QLabel( i18n("&Header font:"), vbFonts );
+ lHeaderFont = new QLabel( vbFonts );
+ lHeaderFont->setFrameStyle( QFrame::Panel|QFrame::Sunken );
+ btnHeaderFont = new KPushButton( i18n("Choose..."), vbFonts );
+ lHFnt->setBuddy( btnHeaderFont );
+ connect( btnHeaderFont, SIGNAL(clicked()), this, SLOT(setHeaderFont()) );
+
+ fntTab->setStretchFactor( new QWidget( fntTab ), 1 );
+
+ QWhatsThis::add( cbEnableCustomFonts, i18n(
+ "If custom fonts are enabled, you may choose which fonts to use for this view below. "
+ "Otherwise the default KDE font will be used, in bold style for the header and "
+ "normal style for the data."
+ ) );
+
+ tabs->addTab( fntTab, i18n("&Fonts") );
+
+ // Behaviour
+ QVBox *behaviourTab = new QVBox( this );
+ behaviourTab->setMargin( margin );
+ behaviourTab->setSpacing( spacing );
+
+ cbShowEmptyFields = new QCheckBox( i18n("Show &empty fields"), behaviourTab );
+ cbShowFieldLabels = new QCheckBox( i18n("Show field &labels"), behaviourTab );
+
+ behaviourTab->setStretchFactor( new QWidget( behaviourTab ), 1 );
+
+ tabs->addTab( behaviourTab, i18n("Be&havior") );
+
+}
+
+void CardViewLookNFeelPage::updateFontLabel( QFont fnt, QLabel *l )
+{
+ l->setFont( fnt );
+ l->setText( QString( fnt.family() + " %1" ).arg( fnt.pointSize() ) );
+}
+
+#include "configurecardviewdialog.moc"
diff --git a/kaddressbook/views/configurecardviewdialog.h b/kaddressbook/views/configurecardviewdialog.h
new file mode 100644
index 000000000..a37db6cb3
--- /dev/null
+++ b/kaddressbook/views/configurecardviewdialog.h
@@ -0,0 +1,113 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#ifndef CONFIGURECARDVIEWDIALOG_H
+#define CONFIGURECARDVIEWDIALOG_H
+
+#include "viewconfigurewidget.h"
+
+#include <qvbox.h>
+#include <qwidget.h>
+#include <qfont.h>
+
+class QString;
+class QWidget;
+class QCheckBox;
+class QLabel;
+class KConfig;
+
+namespace KABC { class AddressBook; }
+
+class CardViewLookAndFeelPage;
+
+/**
+ Configure dialog for the card view. This dialog inherits from the
+ standard view dialog in order to add a custom page for the card
+ view.
+ */
+class ConfigureCardViewWidget : public ViewConfigureWidget
+{
+ public:
+ ConfigureCardViewWidget( KABC::AddressBook *ab, QWidget *parent, const char *name );
+ virtual ~ConfigureCardViewWidget();
+
+ virtual void restoreSettings( KConfig* );
+ virtual void saveSettings( KConfig* );
+
+ private:
+ class CardViewLookNFeelPage *mAdvancedPage;
+};
+
+/**
+ Card View Advanced LookNFeel settings widget:
+ this is a tabbed widget with 3 tabs:
+ Fonts
+ * text font
+ * header font
+
+ Colors
+ * background color
+ * text color
+ * highlight color
+ * title/sep text color
+ * title/sep bg color
+
+ Layout
+ * item margin
+ * item spacing
+*/
+
+class CardViewLookNFeelPage : public QVBox {
+
+ Q_OBJECT
+
+ public:
+ CardViewLookNFeelPage( QWidget *parent=0, const char *name=0 );
+ ~CardViewLookNFeelPage();
+
+ void restoreSettings( KConfig* );
+ void saveSettings( KConfig* );
+
+ private slots:
+ void setTextFont();
+ void setHeaderFont();
+ void enableFonts();
+ void enableColors();
+
+ private:
+ void initGUI();
+ void updateFontLabel( QFont, QLabel * );
+
+ QCheckBox *cbEnableCustomFonts,
+ *cbEnableCustomColors,
+ *cbDrawSeps, *cbDrawBorders,
+ *cbShowFieldLabels, *cbShowEmptyFields;
+ class ColorListBox *lbColors;
+ QLabel *lTextFont, *lHeaderFont;
+ class KPushButton *btnFont, *btnHeaderFont;
+ class QSpinBox *sbMargin, *sbSpacing, *sbSepWidth;
+
+ class QWidget *vbFonts;
+};
+
+#endif
diff --git a/kaddressbook/views/configuretableviewdialog.cpp b/kaddressbook/views/configuretableviewdialog.cpp
new file mode 100644
index 000000000..d01c4d7df
--- /dev/null
+++ b/kaddressbook/views/configuretableviewdialog.cpp
@@ -0,0 +1,156 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#include <qstring.h>
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qvbox.h>
+#include <qbuttongroup.h>
+
+#include <kdeversion.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <klineedit.h>
+#include <kurlrequester.h>
+#include <kiconloader.h>
+#include <kimageio.h>
+#include <kconfig.h>
+
+#include "configuretableviewdialog.h"
+
+ConfigureTableViewWidget::ConfigureTableViewWidget( KABC::AddressBook *ab,
+ QWidget *parent,
+ const char *name )
+ : ViewConfigureWidget( ab, parent, name )
+{
+ QWidget *page = addPage( i18n( "Look & Feel" ), QString::null,
+ KGlobal::iconLoader()->loadIcon( "looknfeel",
+ KIcon::Panel ) );
+
+ mPage = new LookAndFeelPage( page );
+}
+
+ConfigureTableViewWidget::~ConfigureTableViewWidget()
+{
+}
+
+void ConfigureTableViewWidget::restoreSettings( KConfig *config )
+{
+ ViewConfigureWidget::restoreSettings( config );
+
+ mPage->restoreSettings( config );
+}
+
+void ConfigureTableViewWidget::saveSettings( KConfig *config )
+{
+ ViewConfigureWidget::saveSettings( config );
+
+ mPage->saveSettings( config );
+}
+
+
+
+LookAndFeelPage::LookAndFeelPage(QWidget *parent, const char *name)
+ : QWidget(parent, name)
+{
+ initGUI();
+
+ // Set initial state
+ enableBackgroundToggled(mBackgroundBox->isChecked());
+}
+
+void LookAndFeelPage::restoreSettings( KConfig *config )
+{
+ mAlternateButton->setChecked(config->readBoolEntry("ABackground", true));
+ mLineButton->setChecked(config->readBoolEntry("SingleLine", false));
+ mToolTipBox->setChecked(config->readBoolEntry("ToolTips", true));
+
+ if (!mAlternateButton->isChecked() && !mLineButton->isChecked())
+ mNoneButton->setChecked(true);
+
+ mBackgroundBox->setChecked(config->readBoolEntry("Background", false));
+ mBackgroundName->lineEdit()->setText(config->readPathEntry("BackgroundName"));
+#if KDE_IS_VERSION(3,2,90)
+ mIMPresenceBox->setChecked( config->readBoolEntry( "InstantMessagingPresence", false ) );
+#endif
+}
+
+void LookAndFeelPage::saveSettings( KConfig *config )
+{
+ config->writeEntry("ABackground", mAlternateButton->isChecked());
+ config->writeEntry("SingleLine", mLineButton->isChecked());
+ config->writeEntry("ToolTips", mToolTipBox->isChecked());
+ config->writeEntry("Background", mBackgroundBox->isChecked());
+ config->writePathEntry("BackgroundName", mBackgroundName->lineEdit()->text());
+#if KDE_IS_VERSION(3,2,90)
+ config->writeEntry( "InstantMessagingPresence", mIMPresenceBox->isChecked() );
+#endif
+}
+
+void LookAndFeelPage::initGUI()
+{
+ QVBoxLayout *layout = new QVBoxLayout(this, 0, KDialogBase::spacingHint());
+
+ QButtonGroup *group = new QButtonGroup(1, Qt::Horizontal,
+ i18n("Row Separator"), this);
+ layout->addWidget(group);
+
+ mAlternateButton = new QRadioButton(i18n("Alternating backgrounds"),
+ group, "mAlternateButton");
+ mLineButton = new QRadioButton(i18n("Single line"), group, "mLineButton");
+ mNoneButton = new QRadioButton(i18n("None"), group, "mNoneButton");
+
+ // Background Checkbox/Selector
+ QHBoxLayout *backgroundLayout = new QHBoxLayout();
+ layout->addLayout(backgroundLayout);
+
+ mBackgroundBox = new QCheckBox(i18n("Enable background image:"), this,
+ "mBackgroundBox");
+ connect(mBackgroundBox, SIGNAL(toggled(bool)),
+ SLOT(enableBackgroundToggled(bool)));
+ backgroundLayout->addWidget(mBackgroundBox);
+
+ mBackgroundName = new KURLRequester(this, "mBackgroundName");
+ mBackgroundName->setMode(KFile::File | KFile::ExistingOnly |
+ KFile::LocalOnly);
+ mBackgroundName->setFilter(KImageIO::pattern(KImageIO::Reading));
+ backgroundLayout->addWidget(mBackgroundName);
+
+ // ToolTip Checkbox
+ mToolTipBox = new QCheckBox(i18n("Enable contact tooltips"), this,
+ "mToolTipBox");
+ layout->addWidget(mToolTipBox);
+#if KDE_IS_VERSION(3,2,90)
+ mIMPresenceBox = new QCheckBox( i18n( "Show instant messaging presence" ), this, "mIMPresenceBox" );
+ layout->addWidget( mIMPresenceBox );
+#endif
+}
+
+void LookAndFeelPage::enableBackgroundToggled(bool enabled)
+{
+ mBackgroundName->setEnabled(enabled);
+}
+
+#include "configuretableviewdialog.moc"
diff --git a/kaddressbook/views/configuretableviewdialog.h b/kaddressbook/views/configuretableviewdialog.h
new file mode 100644
index 000000000..1260971c2
--- /dev/null
+++ b/kaddressbook/views/configuretableviewdialog.h
@@ -0,0 +1,89 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#ifndef CONFIGURETABLEVIEWDIALOG_H
+#define CONFIGURETABLEVIEWDIALOG_H
+
+#include "viewconfigurewidget.h"
+
+class QString;
+class QWidget;
+class QRadioButton;
+class QCheckBox;
+class KURLRequester;
+class KConfig;
+
+namespace KABC { class AddressBook; }
+
+class LookAndFeelPage;
+
+/**
+ Configure dialog for the table view. This dialog inherits from the
+ standard view dialog in order to add a custom page for the table
+ view.
+ */
+class ConfigureTableViewWidget : public ViewConfigureWidget
+{
+ public:
+ ConfigureTableViewWidget( KABC::AddressBook *ab, QWidget *parent, const char *name );
+ virtual ~ConfigureTableViewWidget();
+
+ virtual void restoreSettings( KConfig* );
+ virtual void saveSettings( KConfig* );
+
+ private:
+ void initGUI();
+
+ LookAndFeelPage *mPage;
+};
+
+/**
+ Internal class. It is only defined here for moc
+*/
+class LookAndFeelPage : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ LookAndFeelPage( QWidget *parent, const char *name = 0 );
+ ~LookAndFeelPage() {}
+
+ void restoreSettings( KConfig* );
+ void saveSettings( KConfig* );
+
+ protected slots:
+ void enableBackgroundToggled( bool );
+
+ private:
+ void initGUI();
+
+ QRadioButton *mAlternateButton;
+ QRadioButton *mLineButton;
+ QRadioButton *mNoneButton;
+ QCheckBox *mToolTipBox;
+ KURLRequester *mBackgroundName;
+ QCheckBox *mBackgroundBox;
+ QCheckBox *mIMPresenceBox;
+};
+
+#endif
diff --git a/kaddressbook/views/contactlistview.cpp b/kaddressbook/views/contactlistview.cpp
new file mode 100644
index 000000000..1deadc190
--- /dev/null
+++ b/kaddressbook/views/contactlistview.cpp
@@ -0,0 +1,380 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#include <qheader.h>
+#include <qiconset.h>
+#include <qimage.h>
+#include <qdragobject.h>
+#include <qcombobox.h>
+#include <qpainter.h>
+#include <qbrush.h>
+#include <qevent.h>
+
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <kdebug.h>
+#include <kconfig.h>
+#include <kapplication.h>
+#include <kurl.h>
+#include <kabc/addressbook.h>
+#include <kabc/addressee.h>
+#include <kimproxy.h>
+
+#include "kaddressbooktableview.h"
+
+#include "contactlistview.h"
+
+/////////////////////////////////
+// DynamicTip Methods
+
+DynamicTip::DynamicTip( ContactListView *parent)
+ : QToolTip( parent )
+{
+}
+
+void DynamicTip::maybeTip( const QPoint &pos )
+{
+ if (!parentWidget()->inherits( "ContactListView" ))
+ return;
+
+ ContactListView *plv = (ContactListView*)parentWidget();
+ if (!plv->tooltips())
+ return;
+
+ QPoint posVp = plv->viewport()->pos();
+
+ QListViewItem *lvi = plv->itemAt( pos - posVp );
+ if (!lvi)
+ return;
+
+ ContactListViewItem *plvi = dynamic_cast< ContactListViewItem* >(lvi);
+ if (!plvi)
+ return;
+
+ QString s;
+ QRect r = plv->itemRect( lvi );
+ r.moveBy( posVp.x(), posVp.y() );
+
+ //kdDebug(5720) << "Tip rec: " << r.x() << "," << r.y() << "," << r.width()
+ // << "," << r.height() << endl;
+
+ KABC::Addressee a = plvi->addressee();
+ if (a.isEmpty())
+ return;
+
+ s += i18n("label: value", "%1: %2").arg(a.formattedNameLabel())
+ .arg(a.formattedName());
+
+ s += '\n';
+ s += i18n("label: value", "%1: %2").arg(a.organizationLabel())
+ .arg(a.organization());
+
+ QString notes = a.note().stripWhiteSpace();
+ if ( !notes.isEmpty() ) {
+ notes += '\n';
+ s += '\n' + i18n("label: value", "%1: \n").arg(a.noteLabel());
+ QFontMetrics fm( font() );
+
+ // Begin word wrap code based on QMultiLineEdit code
+ int i = 0;
+ bool doBreak = false;
+ int linew = 0;
+ int lastSpace = -1;
+ int a = 0;
+ int lastw = 0;
+
+ while ( i < int(notes.length()) ) {
+ doBreak = false;
+ if ( notes[i] != '\n' )
+ linew += fm.width( notes[i] );
+
+ if ( lastSpace >= a && notes[i] != '\n' )
+ if (linew >= parentWidget()->width()) {
+ doBreak = true;
+ if ( lastSpace > a ) {
+ i = lastSpace;
+ linew = lastw;
+ }
+ else
+ i = QMAX( a, i-1 );
+ }
+
+ if ( notes[i] == '\n' || doBreak ) {
+ s += notes.mid( a, i - a + (doBreak?1:0) ) +"\n";
+
+ a = i + 1;
+ lastSpace = a;
+ linew = 0;
+ }
+
+ if ( notes[i].isSpace() ) {
+ lastSpace = i;
+ lastw = linew;
+ }
+
+ if ( lastSpace <= a ) {
+ lastw = linew;
+ }
+
+ ++i;
+ }
+ }
+
+ tip( r, s );
+}
+
+///////////////////////////
+// ContactListViewItem Methods
+
+ContactListViewItem::ContactListViewItem(const KABC::Addressee &a,
+ ContactListView *parent,
+ KABC::AddressBook *doc,
+ const KABC::Field::List &fields,
+ KIMProxy *proxy )
+ : KListViewItem(parent), mAddressee(a), mFields( fields ),
+ parentListView( parent ), mDocument(doc), mIMProxy( proxy )
+{
+ if ( mIMProxy )
+ mHasIM = mIMProxy->isPresent( mAddressee.uid() );
+ else
+ mHasIM = false;
+ refresh();
+}
+
+QString ContactListViewItem::key(int column, bool ascending) const
+{
+ // Preserve behaviour of QListViewItem::key(), otherwise we cause a crash if the column does not exist
+ if ( column >= parentListView->columns() )
+ return QString::null;
+
+#if KDE_VERSION >= 319
+ Q_UNUSED( ascending )
+ if ( parentListView->showIM() ) {
+ // in this case, one column is reserved for IM presence
+ // so we have to process it differently
+ if ( column == parentListView->imColumn() ) {
+ // increment by one before converting to string so that -1 is not greater than 1
+ // create the sort key by taking the numeric status 0 low, 5 high, and subtracting it from 5
+ // so that the default ascending gives online before offline, etc.
+ QString key = QString::number( 5 - ( mIMProxy->presenceNumeric( mAddressee.uid() ) + 1 ) );
+ return key;
+ }
+ else {
+ return mFields[ column ]->sortKey( mAddressee );
+ }
+ }
+ else
+ return mFields[ column ]->sortKey( mAddressee );
+#else
+ return QListViewItem::key( column, ascending ).lower();
+#endif
+}
+
+void ContactListViewItem::paintCell(QPainter * p,
+ const QColorGroup & cg,
+ int column,
+ int width,
+ int align)
+{
+ KListViewItem::paintCell(p, cg, column, width, align);
+
+ if ( !p )
+ return;
+
+ if (parentListView->singleLine()) {
+ p->setPen( parentListView->alternateColor() );
+ p->drawLine( 0, height() - 1, width, height() - 1 );
+ }
+}
+
+
+ContactListView *ContactListViewItem::parent()
+{
+ return parentListView;
+}
+
+
+void ContactListViewItem::refresh()
+{
+ // Update our addressee, since it may have changed else were
+ mAddressee = mDocument->findByUid(mAddressee.uid());
+ if (mAddressee.isEmpty())
+ return;
+
+ int i = 0;
+ // don't show unknown presence, it's not interesting
+ if ( mHasIM ) {
+ if ( mIMProxy->presenceNumeric( mAddressee.uid() ) > 0 )
+ setPixmap( parentListView->imColumn(), mIMProxy->presenceIcon( mAddressee.uid() ) );
+ else
+ setPixmap( parentListView->imColumn(), QPixmap() );
+ }
+
+ KABC::Field::List::ConstIterator it;
+ for ( it = mFields.begin(); it != mFields.end(); ++it ) {
+ if ( (*it)->label() == KABC::Addressee::birthdayLabel() ) {
+ QDate date = mAddressee.birthday().date();
+ if ( date.isValid() )
+ setText( i++, KGlobal::locale()->formatDate( date, true ) );
+ else
+ setText( i++, "" );
+ } else
+ setText( i++, (*it)->value( mAddressee ) );
+ }
+}
+
+void ContactListViewItem::setHasIM( bool hasIM )
+{
+ mHasIM = hasIM;
+}
+
+///////////////////////////////
+// ContactListView
+
+ContactListView::ContactListView(KAddressBookTableView *view,
+ KABC::AddressBook* /* doc */,
+ QWidget *parent,
+ const char *name )
+ : KListView( parent, name ),
+ pabWidget( view ),
+ oldColumn( 0 )
+{
+ mABackground = true;
+ mSingleLine = false;
+ mToolTips = true;
+ mShowIM = true;
+ mAlternateColor = KGlobalSettings::alternateBackgroundColor();
+
+ setAlternateBackgroundEnabled(mABackground);
+ setAcceptDrops( true );
+ viewport()->setAcceptDrops( true );
+ setAllColumnsShowFocus( true );
+ setShowSortIndicator(true);
+ setSelectionModeExt( KListView::Extended );
+ setDropVisualizer(false);
+
+ connect(this, SIGNAL(dropped(QDropEvent*)),
+ this, SLOT(itemDropped(QDropEvent*)));
+
+ new DynamicTip( this );
+}
+
+void ContactListView::paintEmptyArea( QPainter * p, const QRect & rect )
+{
+ QBrush b = palette().brush(QPalette::Active, QColorGroup::Base);
+
+ // Get the brush, which will have the background pixmap if there is one.
+ if (b.pixmap())
+ {
+ p->drawTiledPixmap( rect.left(), rect.top(), rect.width(), rect.height(),
+ *(b.pixmap()),
+ rect.left() + contentsX(),
+ rect.top() + contentsY() );
+ }
+
+ else
+ {
+ // Do a normal paint
+ KListView::paintEmptyArea(p, rect);
+ }
+}
+
+void ContactListView::contentsMousePressEvent(QMouseEvent* e)
+{
+ presspos = e->pos();
+ KListView::contentsMousePressEvent(e);
+}
+
+
+// To initiate a drag operation
+void ContactListView::contentsMouseMoveEvent( QMouseEvent *e )
+{
+ if ((e->state() & LeftButton) && (e->pos() - presspos).manhattanLength() > 4 ) {
+ emit startAddresseeDrag();
+ }
+ else
+ KListView::contentsMouseMoveEvent( e );
+}
+
+bool ContactListView::acceptDrag(QDropEvent *e) const
+{
+ return QTextDrag::canDecode(e);
+}
+
+void ContactListView::itemDropped(QDropEvent *e)
+{
+ contentsDropEvent(e);
+}
+
+void ContactListView::contentsDropEvent( QDropEvent *e )
+{
+ emit addresseeDropped(e);
+}
+
+void ContactListView::setAlternateBackgroundEnabled(bool enabled)
+{
+ mABackground = enabled;
+
+ if (mABackground)
+ {
+ setAlternateBackground(mAlternateColor);
+ }
+ else
+ {
+ setAlternateBackground(QColor());
+ }
+}
+
+void ContactListView::setBackgroundPixmap(const QString &filename)
+{
+ if (filename.isEmpty())
+ {
+ unsetPalette();
+ }
+ else
+ {
+ setPaletteBackgroundPixmap(QPixmap(filename));
+ }
+}
+
+void ContactListView::setShowIM( bool enabled )
+{
+ mShowIM = enabled;
+}
+
+bool ContactListView::showIM()
+{
+ return mShowIM;
+}
+
+void ContactListView::setIMColumn( int column )
+{
+ mInstantMsgColumn = column;
+}
+
+int ContactListView::imColumn()
+{
+ return mInstantMsgColumn;
+}
+
+#include "contactlistview.moc"
diff --git a/kaddressbook/views/contactlistview.h b/kaddressbook/views/contactlistview.h
new file mode 100644
index 000000000..c018e4c2b
--- /dev/null
+++ b/kaddressbook/views/contactlistview.h
@@ -0,0 +1,176 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#ifndef CONTACTLISTVIEW_H
+#define CONTACTLISTVIEW_H
+
+#include <qcolor.h>
+#include <qpixmap.h>
+#include <qtooltip.h>
+#include <qstring.h>
+
+#include <klistview.h>
+
+#include <kabc/field.h>
+
+class QDropEvent;
+class KAddressBookTableView;
+class ContactListView;
+class KIMProxy;
+
+/** The whole tooltip design needs a lot of work. Currently it is
+* hacked together to function.
+*/
+class DynamicTip : public QToolTip
+{
+ public:
+ DynamicTip( ContactListView * parent );
+
+ protected:
+ void maybeTip( const QPoint & );
+
+ private:
+};
+
+class ContactListViewItem : public KListViewItem
+{
+
+public:
+ ContactListViewItem(const KABC::Addressee &a, ContactListView* parent,
+ KABC::AddressBook *doc, const KABC::Field::List &fields, KIMProxy *proxy );
+ const KABC::Addressee &addressee() const { return mAddressee; }
+ virtual void refresh();
+ virtual ContactListView* parent();
+ virtual QString key ( int, bool ) const;
+ void setHasIM( bool hasIM );
+ /** Adds the border around the cell if the user wants it.
+ * This is how the single line config option is implemented.
+ */
+ virtual void paintCell(QPainter * p, const QColorGroup & cg,
+ int column, int width, int align );
+
+private:
+ KABC::Addressee mAddressee;
+ KABC::Field::List mFields;
+ ContactListView *parentListView;
+ KABC::AddressBook *mDocument;
+ KIMProxy *mIMProxy;
+ bool mHasIM;
+};
+
+
+/////////////////////////////////////////////
+// ContactListView
+
+class ContactListView : public KListView
+{
+ Q_OBJECT
+
+public:
+ ContactListView(KAddressBookTableView *view,
+ KABC::AddressBook *doc,
+ QWidget *parent,
+ const char *name = 0L );
+ virtual ~ContactListView() {}
+ //void resort();
+
+ /** Returns true if tooltips should be displayed, false otherwise
+ */
+ bool tooltips() const { return mToolTips; }
+ void setToolTipsEnabled(bool enabled) { mToolTips = enabled; }
+
+ bool alternateBackground() const { return mABackground; }
+ void setAlternateBackgroundEnabled(bool enabled);
+
+ bool singleLine() const { return mSingleLine; }
+ void setSingleLineEnabled(bool enabled) { mSingleLine = enabled; }
+
+ const QColor &alternateColor() const { return mAlternateColor; }
+
+ /** Sets the background pixmap to <i>filename</i>. If the
+ * QString is empty (QString::isEmpty()), then the background
+ * pixmap will be disabled.
+ */
+ void setBackgroundPixmap(const QString &filename);
+
+ /**
+ * Sets whether instant messaging presence should be shown in the first column
+ */
+ void setShowIM( bool enabled );
+
+ /**
+ * Is presence being shown?
+ */
+ bool showIM();
+
+ /**
+ * Set the column index of the column used for instant messaging presence.
+ * This method is necessary because presence, unlike the other fields, is not
+ * a KABC::Field, and cannot be handled using their methods.
+ * TODO: make presence a KABC::Field post 3.3
+ */
+ void setIMColumn( int column );
+
+ /**
+ * get the column used for IM presence
+ */
+ int imColumn();
+
+protected:
+ /** Paints the background pixmap in the empty area. This method is needed
+ * since Qt::FixedPixmap will not scroll with the list view.
+ */
+ virtual void paintEmptyArea( QPainter * p, const QRect & rect );
+ virtual void contentsMousePressEvent(QMouseEvent*);
+ void contentsMouseMoveEvent( QMouseEvent *e );
+ void contentsDropEvent( QDropEvent *e );
+ virtual bool acceptDrag(QDropEvent *e) const;
+
+protected slots:
+ void itemDropped(QDropEvent *e);
+
+public slots:
+
+signals:
+ void startAddresseeDrag();
+ void addresseeDropped(QDropEvent *);
+
+private:
+ KAddressBookTableView *pabWidget;
+ int oldColumn;
+ int column;
+ bool ascending;
+
+ bool mABackground;
+ bool mSingleLine;
+ bool mToolTips;
+ bool mShowIM;
+
+ QColor mAlternateColor;
+
+ QPoint presspos;
+ int mInstantMsgColumn;
+};
+
+
+#endif
diff --git a/kaddressbook/views/iconview.desktop b/kaddressbook/views/iconview.desktop
new file mode 100644
index 000000000..59853a70e
--- /dev/null
+++ b/kaddressbook/views/iconview.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+X-KDE-Library=libkaddrbk_iconview
+Name=Icon View
+Name[af]=Ikoon Aansig
+Name[ar]=عرض الأيقونات
+Name[az]=Timsal Görünüşü
+Name[be]=У выглядзе піктаграмаў
+Name[bg]=Преглед като икони
+Name[br]=Gwel Arlun
+Name[bs]=Ikone
+Name[ca]=Vista d'icona
+Name[cs]=Pohled s ikonami
+Name[cy]=Gweld Eicon
+Name[da]=Ikon-visning
+Name[de]=Symbolansicht
+Name[el]=Προβολή εικονιδίων
+Name[eo]=Piktogramrigardo
+Name[es]=Vista de icono
+Name[et]=Ikoonivaade
+Name[eu]=Ikono ikuspegia
+Name[fa]=نمای شمایل
+Name[fi]=Kuvakenäkymä
+Name[fr]=Icônes
+Name[fy]=Byldkaikewerjefte
+Name[ga]=Amharc Deilbhíní
+Name[gl]=Vista en iconas
+Name[he]=תצוגת סמלים
+Name[hi]=प्रतीक दृश्य
+Name[hr]=Ikonski pogled
+Name[hu]=Ikonos nézet
+Name[id]=Tampilan Ikon
+Name[is]=Táknmyndasýn
+Name[it]=Vista a icone
+Name[ja]=アイコンビュー
+Name[ka]=ხატულების ჩვენება
+Name[kk]=Таңбаша
+Name[km]=ទិដ្ឋភាព​រូបតំណាង
+Name[lt]=Rodyti piktogramas
+Name[lv]=Ikonu Skatījums
+Name[mk]=Преглед со икони
+Name[ms]=Pelihat Ikon
+Name[mt]=Ikoni
+Name[nb]=Ikonvisning
+Name[nds]=Lüttbildansicht
+Name[ne]=प्रतिमा दृश्य
+Name[nl]=Pictogramweergave
+Name[nn]=Ikonvising
+Name[pa]=ਆਈਕਾਨ ਦਰਿਸ਼
+Name[pl]=Widok ikon
+Name[pt]=Vista por Ícones
+Name[pt_BR]=Visualização de Ícone
+Name[ro]=Vizualizare iconică
+Name[ru]=Значки
+Name[rw]=Igaragaza ry'Agashushondanga
+Name[se]=Govaščájeheapmi
+Name[sk]=Prehliadanie ikon
+Name[sl]=Ikoniziran prikaz
+Name[sr]=Приказ са иконама
+Name[sr@Latn]=Prikaz sa ikonama
+Name[sv]=Ikonvy
+Name[ta]=சின்னத்தின் காட்சி
+Name[tg]=Ишоротҳо
+Name[th]=มุมมองแบบไอคอน
+Name[tr]=Simge Görünümü
+Name[uk]=Вигляд піктограмами
+Name[uz]=Nishoncha koʻrinishida
+Name[uz@cyrillic]=Нишонча кўринишида
+Name[ven]=Mbonalelo ya aikhono
+Name[vi]=Xem icon
+Name[xh]=Imboniselo ye Icon
+Name[zh_CN]=图标视图
+Name[zh_TW]=圖示檢視
+Name[zu]=Umboniso we Icon
+Type=Service
+ServiceTypes=KAddressBook/View
+X-KDE-KAddressBook-ViewPluginVersion=1
diff --git a/kaddressbook/views/kaddressbookcardview.cpp b/kaddressbook/views/kaddressbookcardview.cpp
new file mode 100644
index 000000000..d65c4d71f
--- /dev/null
+++ b/kaddressbook/views/kaddressbookcardview.cpp
@@ -0,0 +1,370 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#include <qapplication.h>
+#include <qdragobject.h>
+#include <qevent.h>
+#include <qiconview.h>
+#include <qlayout.h>
+#include <qstringlist.h>
+
+#include <kabc/addressbook.h>
+#include <kabc/addressee.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "core.h"
+#include "configurecardviewdialog.h"
+#include "kabprefs.h"
+
+#include "kaddressbookcardview.h"
+
+class CardViewFactory : public ViewFactory
+{
+ public:
+ KAddressBookView *view( KAB::Core *core, QWidget *parent, const char *name )
+ {
+ return new KAddressBookCardView( core, parent, name );
+ }
+
+ QString type() const { return I18N_NOOP("Card"); }
+
+ QString description() const { return i18n( "Rolodex style cards represent contacts." ); }
+
+ ViewConfigureWidget *configureWidget( KABC::AddressBook *ab, QWidget *parent,
+ const char *name = 0 )
+ {
+ return new ConfigureCardViewWidget( ab, parent, name );
+ }
+};
+
+extern "C" {
+ void *init_libkaddrbk_cardview()
+ {
+ return ( new CardViewFactory );
+ }
+}
+
+class AddresseeCardViewItem : public CardViewItem
+{
+ public:
+ AddresseeCardViewItem( const KABC::Field::List &fields,
+ bool showEmptyFields,
+ KABC::AddressBook *doc, const KABC::Addressee &addr,
+ CardView *parent )
+ : CardViewItem( parent, addr.realName() ),
+ mFields( fields ), mShowEmptyFields( showEmptyFields ),
+ mDocument( doc ), mAddressee( addr )
+ {
+ if ( mFields.isEmpty() )
+ mFields = KABC::Field::defaultFields();
+
+ refresh();
+ }
+
+ const KABC::Addressee &addressee() const { return mAddressee; }
+
+ void refresh()
+ {
+ mAddressee = mDocument->findByUid( mAddressee.uid() );
+
+ if ( !mAddressee.isEmpty() ) {
+ clearFields();
+
+ KABC::Field::List::ConstIterator it( mFields.begin() );
+ const KABC::Field::List::ConstIterator endIt( mFields.end() );
+ for ( ; it != endIt; ++it ) {
+ // insert empty fields or not? not doing so saves a bit of memory and CPU
+ // (during geometry calculations), but prevents having equally
+ // wide label columns in all cards, unless CardViewItem/CardView search
+ // globally for the widest label. (anders)
+
+ // if ( mShowEmptyFields || !(*it)->value( mAddressee ).isEmpty() )
+ insertField( (*it)->label(), (*it)->value( mAddressee ) );
+ }
+
+ setCaption( mAddressee.realName() );
+ }
+ }
+
+ private:
+ KABC::Field::List mFields;
+ bool mShowEmptyFields;
+ KABC::AddressBook *mDocument;
+ KABC::Addressee mAddressee;
+};
+
+
+AddresseeCardView::AddresseeCardView( QWidget *parent, const char *name )
+ : CardView( parent, name )
+{
+ setAcceptDrops( true );
+}
+
+AddresseeCardView::~AddresseeCardView()
+{
+}
+
+void AddresseeCardView::dragEnterEvent( QDragEnterEvent *event )
+{
+ if ( QTextDrag::canDecode( event ) )
+ event->accept();
+}
+
+void AddresseeCardView::dropEvent( QDropEvent *event )
+{
+ emit addresseeDropped( event );
+}
+
+void AddresseeCardView::startDrag()
+{
+ emit startAddresseeDrag();
+}
+
+
+KAddressBookCardView::KAddressBookCardView( KAB::Core *core,
+ QWidget *parent, const char *name )
+ : KAddressBookView( core, parent, name )
+{
+ mShowEmptyFields = false;
+
+ QVBoxLayout *layout = new QVBoxLayout( viewWidget() );
+
+ mCardView = new AddresseeCardView( viewWidget(), "mCardView" );
+ mCardView->setSelectionMode( CardView::Extended );
+ layout->addWidget( mCardView );
+
+ // Connect up the signals
+ connect( mCardView, SIGNAL( executed( CardViewItem* ) ),
+ this, SLOT( addresseeExecuted( CardViewItem* ) ) );
+ connect( mCardView, SIGNAL( selectionChanged() ),
+ this, SLOT( addresseeSelected() ) );
+ connect( mCardView, SIGNAL( addresseeDropped( QDropEvent* ) ),
+ this, SIGNAL( dropped( QDropEvent* ) ) );
+ connect( mCardView, SIGNAL( startAddresseeDrag() ),
+ this, SIGNAL( startDrag() ) );
+ connect( mCardView, SIGNAL( contextMenuRequested( CardViewItem*, const QPoint& ) ),
+ this, SLOT( rmbClicked( CardViewItem*, const QPoint& ) ) );
+}
+
+KAddressBookCardView::~KAddressBookCardView()
+{
+}
+
+KABC::Field *KAddressBookCardView::sortField() const
+{
+ // we have hardcoded sorting, so we have to return a hardcoded field :(
+ return KABC::Field::allFields()[ 0 ];
+}
+
+void KAddressBookCardView::readConfig( KConfig *config )
+{
+ KAddressBookView::readConfig( config );
+
+ // costum colors?
+ if ( config->readBoolEntry( "EnableCustomColors", false ) ) {
+ QPalette p( mCardView->palette() );
+ QColor c = p.color( QPalette::Normal, QColorGroup::Base );
+ p.setColor( QPalette::Normal, QColorGroup::Base, config->readColorEntry( "BackgroundColor", &c ) );
+ c = p.color( QPalette::Normal, QColorGroup::Text );
+ p.setColor( QPalette::Normal, QColorGroup::Text, config->readColorEntry( "TextColor", &c ) );
+ c = p.color( QPalette::Normal, QColorGroup::Button );
+ p.setColor( QPalette::Normal, QColorGroup::Button, config->readColorEntry( "HeaderColor", &c ) );
+ c = p.color( QPalette::Normal, QColorGroup::ButtonText );
+ p.setColor( QPalette::Normal, QColorGroup::ButtonText, config->readColorEntry( "HeaderTextColor", &c ) );
+ c = p.color( QPalette::Normal, QColorGroup::Highlight );
+ p.setColor( QPalette::Normal, QColorGroup::Highlight, config->readColorEntry( "HighlightColor", &c ) );
+ c = p.color( QPalette::Normal, QColorGroup::HighlightedText );
+ p.setColor( QPalette::Normal, QColorGroup::HighlightedText, config->readColorEntry( "HighlightedTextColor", &c ) );
+ mCardView->viewport()->setPalette( p );
+ } else {
+ // needed if turned off during a session.
+ mCardView->viewport()->setPalette( mCardView->palette() );
+ }
+
+ //custom fonts?
+ QFont f( font() );
+ if ( config->readBoolEntry( "EnableCustomFonts", false ) ) {
+ mCardView->setFont( config->readFontEntry( "TextFont", &f ) );
+ f.setBold( true );
+ mCardView->setHeaderFont( config->readFontEntry( "HeaderFont", &f ) );
+ } else {
+ mCardView->setFont( f );
+ f.setBold( true );
+ mCardView->setHeaderFont( f );
+ }
+
+ mCardView->setDrawCardBorder( config->readBoolEntry( "DrawBorder", true ) );
+ mCardView->setDrawColSeparators( config->readBoolEntry( "DrawSeparators", true ) );
+ mCardView->setDrawFieldLabels( config->readBoolEntry( "DrawFieldLabels", false ) );
+ mShowEmptyFields = config->readBoolEntry( "ShowEmptyFields", false );
+
+ mCardView->setShowEmptyFields( mShowEmptyFields );
+
+ mCardView->setItemWidth( config->readNumEntry( "ItemWidth", 200 ) );
+ mCardView->setItemMargin( config->readNumEntry( "ItemMargin", 0 ) );
+ mCardView->setItemSpacing( config->readNumEntry( "ItemSpacing", 10 ) );
+ mCardView->setSeparatorWidth( config->readNumEntry( "SeparatorWidth", 2 ) );
+
+ disconnect( mCardView, SIGNAL( executed( CardViewItem* ) ),
+ this, SLOT( addresseeExecuted( CardViewItem* ) ) );
+
+ if ( KABPrefs::instance()->honorSingleClick() )
+ connect( mCardView, SIGNAL( executed( CardViewItem* ) ),
+ this, SLOT( addresseeExecuted( CardViewItem* ) ) );
+ else
+ connect( mCardView, SIGNAL( doubleClicked( CardViewItem* ) ),
+ this, SLOT( addresseeExecuted( CardViewItem* ) ) );
+}
+
+void KAddressBookCardView::writeConfig( KConfig *config )
+{
+ config->writeEntry( "ItemWidth", mCardView->itemWidth() );
+ KAddressBookView::writeConfig( config );
+}
+
+QStringList KAddressBookCardView::selectedUids()
+{
+ QStringList uidList;
+ CardViewItem *item;
+ AddresseeCardViewItem *aItem;
+
+ for ( item = mCardView->firstItem(); item; item = item->nextItem() ) {
+ if ( item->isSelected() ) {
+ aItem = dynamic_cast<AddresseeCardViewItem*>( item );
+ if ( aItem )
+ uidList << aItem->addressee().uid();
+ }
+ }
+
+ return uidList;
+}
+
+void KAddressBookCardView::refresh( const QString &uid )
+{
+ CardViewItem *item;
+ AddresseeCardViewItem *aItem;
+
+ if ( uid.isEmpty() ) {
+ // Rebuild the view
+ mCardView->viewport()->setUpdatesEnabled( false );
+ mCardView->clear();
+
+ const KABC::Addressee::List addresseeList( addressees() );
+ KABC::Addressee::List::ConstIterator it( addresseeList.begin() );
+ const KABC::Addressee::List::ConstIterator endIt( addresseeList.end() );
+ for ( ; it != endIt; ++it ) {
+ aItem = new AddresseeCardViewItem( fields(), mShowEmptyFields,
+ core()->addressBook(), *it, mCardView );
+ }
+ mCardView->viewport()->setUpdatesEnabled( true );
+ mCardView->viewport()->update();
+
+ // by default nothing is selected
+ emit selected( QString::null );
+ } else {
+ // Try to find the one to refresh
+ bool found = false;
+ for ( item = mCardView->firstItem(); item && !found; item = item->nextItem() ) {
+ aItem = dynamic_cast<AddresseeCardViewItem*>( item );
+ if ( aItem && (aItem->addressee().uid() == uid) ) {
+ aItem->refresh();
+ found = true;
+ }
+ }
+ }
+}
+
+void KAddressBookCardView::setSelected( const QString &uid, bool selected )
+{
+ CardViewItem *item;
+ AddresseeCardViewItem *aItem;
+
+ if ( uid.isEmpty() ) {
+ mCardView->selectAll( selected );
+ } else {
+ bool found = false;
+ for ( item = mCardView->firstItem(); item && !found; item = item->nextItem() ) {
+ aItem = dynamic_cast<AddresseeCardViewItem*>( item );
+
+ if ( aItem && (aItem->addressee().uid() == uid) ) {
+ mCardView->setSelected( aItem, selected );
+ mCardView->ensureItemVisible( item );
+ found = true;
+ }
+ }
+ }
+}
+
+void KAddressBookCardView::setFirstSelected( bool selected )
+{
+ if ( mCardView->firstItem() ) {
+ mCardView->setSelected( mCardView->firstItem(), selected );
+ mCardView->ensureItemVisible( mCardView->firstItem() );
+ }
+}
+
+void KAddressBookCardView::addresseeExecuted( CardViewItem *item )
+{
+ AddresseeCardViewItem *aItem = dynamic_cast<AddresseeCardViewItem*>( item );
+ if ( aItem )
+ emit executed( aItem->addressee().uid() );
+}
+
+void KAddressBookCardView::addresseeSelected()
+{
+ CardViewItem *item;
+ AddresseeCardViewItem *aItem;
+
+ bool found = false;
+ for ( item = mCardView->firstItem(); item && !found; item = item->nextItem() ) {
+ if ( item->isSelected() ) {
+ aItem = dynamic_cast<AddresseeCardViewItem*>( item );
+ if ( aItem ) {
+ emit selected( aItem->addressee().uid() );
+ found = true;
+ }
+ }
+ }
+
+ if ( !found )
+ emit selected( QString::null );
+}
+
+void KAddressBookCardView::rmbClicked( CardViewItem*, const QPoint &point )
+{
+ popup( point );
+}
+
+void KAddressBookCardView::scrollUp()
+{
+ QApplication::postEvent( mCardView, new QKeyEvent( QEvent::KeyPress, Qt::Key_Up, 0, 0 ) );
+}
+
+void KAddressBookCardView::scrollDown()
+{
+ QApplication::postEvent( mCardView, new QKeyEvent( QEvent::KeyPress, Qt::Key_Down, 0, 0 ) );
+}
+
+#include "kaddressbookcardview.moc"
diff --git a/kaddressbook/views/kaddressbookcardview.h b/kaddressbook/views/kaddressbookcardview.h
new file mode 100644
index 000000000..68e2a13f3
--- /dev/null
+++ b/kaddressbook/views/kaddressbookcardview.h
@@ -0,0 +1,94 @@
+#ifndef KADDRESSBOOKCARDVIEW_H
+#define KADDRESSBOOKCARDVIEW_H
+
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#include <qstring.h>
+#include <kiconview.h>
+
+#include "cardview.h"
+#include "kaddressbookview.h"
+
+class QDragEntryEvent;
+class QDropEvent;
+class KConfig;
+class AddresseeCardView;
+
+/**
+ This view uses the CardView class to create a card view. At some
+ point in the future I think this will be the default view of
+ KAddressBook.
+ */
+class KAddressBookCardView : public KAddressBookView
+{
+ Q_OBJECT
+
+ public:
+ KAddressBookCardView( KAB::Core *core, QWidget *parent,
+ const char *name = 0 );
+ virtual ~KAddressBookCardView();
+
+ virtual QStringList selectedUids();
+ virtual QString type() const { return "Card"; }
+ virtual KABC::Field *sortField() const;
+
+ virtual void readConfig( KConfig *config );
+ virtual void writeConfig( KConfig *config );
+
+ void scrollUp();
+ void scrollDown();
+
+ public slots:
+ void refresh( const QString &uid = QString() );
+ void setSelected( const QString &uid = QString(), bool selected = true );
+ virtual void setFirstSelected( bool selected = true );
+
+ protected slots:
+ void addresseeExecuted( CardViewItem* );
+ void addresseeSelected();
+ void rmbClicked( CardViewItem*, const QPoint& );
+
+ private:
+ AddresseeCardView *mCardView;
+ bool mShowEmptyFields;
+};
+
+class AddresseeCardView : public CardView
+{
+ Q_OBJECT
+ public:
+ AddresseeCardView( QWidget *parent, const char *name = 0 );
+ ~AddresseeCardView();
+
+ signals:
+ void startAddresseeDrag();
+ void addresseeDropped( QDropEvent* );
+
+ protected:
+ virtual void dragEnterEvent( QDragEnterEvent* );
+ virtual void dropEvent( QDropEvent* );
+ virtual void startDrag();
+};
+
+#endif
diff --git a/kaddressbook/views/kaddressbookiconview.cpp b/kaddressbook/views/kaddressbookiconview.cpp
new file mode 100644
index 000000000..b5d706cad
--- /dev/null
+++ b/kaddressbook/views/kaddressbookiconview.cpp
@@ -0,0 +1,312 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#include <qapplication.h>
+#include <qiconview.h>
+#include <qlayout.h>
+#include <qstringlist.h>
+
+#include <kabc/addressbook.h>
+#include <kabc/addressee.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include "core.h"
+#include "kabprefs.h"
+
+#include "kaddressbookiconview.h"
+
+class IconViewFactory : public ViewFactory
+{
+ public:
+ KAddressBookView *view( KAB::Core *core, QWidget *parent, const char *name )
+ {
+ return new KAddressBookIconView( core, parent, name );
+ }
+
+ QString type() const { return I18N_NOOP( "Icon" ); }
+
+ QString description() const { return i18n( "Icons represent contacts. Very simple view." ); }
+};
+
+extern "C" {
+ void *init_libkaddrbk_iconview()
+ {
+ return ( new IconViewFactory );
+ }
+}
+
+AddresseeIconView::AddresseeIconView( QWidget *parent, const char *name )
+ : KIconView( parent, name )
+{
+ setSelectionMode( QIconView::Extended );
+ setResizeMode( QIconView::Adjust );
+ setWordWrapIconText( true );
+ setGridX( 100 );
+ setItemsMovable( false );
+ setSorting( true, true );
+ setMode( KIconView::Select );
+
+ connect( this, SIGNAL( dropped( QDropEvent*, const QValueList<QIconDragItem>& ) ),
+ this, SLOT( itemDropped( QDropEvent*, const QValueList<QIconDragItem>& ) ) );
+}
+
+AddresseeIconView::~AddresseeIconView()
+{
+}
+
+void AddresseeIconView::itemDropped( QDropEvent *event, const QValueList<QIconDragItem>& )
+{
+ emit addresseeDropped( event );
+}
+
+QDragObject *AddresseeIconView::dragObject()
+{
+ emit startAddresseeDrag();
+
+ // We never want IconView to start the drag
+ return 0;
+}
+
+
+class AddresseeIconViewItem : public KIconViewItem
+{
+ public:
+ AddresseeIconViewItem( const KABC::Field::List&, KABC::AddressBook *doc,
+ const KABC::Addressee &addr, QIconView *parent )
+ : KIconViewItem( parent ), mDocument( doc ), mAddressee( addr )
+ {
+ refresh();
+ }
+
+ const KABC::Addressee &addressee() const { return mAddressee; }
+
+ void refresh()
+ {
+ mAddressee = mDocument->findByUid( mAddressee.uid() );
+
+ if ( !mAddressee.isEmpty() )
+ setText( mAddressee.givenName() + " " + mAddressee.familyName() );
+
+ QPixmap icon;
+ QPixmap defaultIcon( KGlobal::iconLoader()->loadIcon( "vcard", KIcon::Desktop ) );
+ KABC::Picture pic = mAddressee.photo();
+ if ( pic.data().isNull() )
+ pic = mAddressee.logo();
+
+ if ( pic.isIntern() && !pic.data().isNull() ) {
+ QImage img = pic.data();
+ if ( img.width() > img.height() )
+ icon = img.scaleWidth( 32 );
+ else
+ icon = img.scaleHeight( 32 );
+ } else
+ icon = defaultIcon;
+
+ setPixmap( icon );
+ }
+
+ private:
+ KABC::AddressBook *mDocument;
+ KABC::Addressee mAddressee;
+};
+
+
+KAddressBookIconView::KAddressBookIconView( KAB::Core *core,
+ QWidget *parent, const char *name)
+ : KAddressBookView( core, parent, name )
+{
+ QVBoxLayout *layout = new QVBoxLayout( viewWidget() );
+
+ mIconView = new AddresseeIconView( viewWidget(), "mIconView" );
+ layout->addWidget( mIconView );
+
+ // Connect up the signals
+ connect( mIconView, SIGNAL( executed( QIconViewItem* ) ),
+ this, SLOT( addresseeExecuted( QIconViewItem* ) ) );
+ connect( mIconView, SIGNAL( selectionChanged() ),
+ this, SLOT( addresseeSelected() ) );
+ connect( mIconView, SIGNAL( addresseeDropped( QDropEvent* ) ),
+ this, SIGNAL( dropped( QDropEvent* ) ) );
+ connect( mIconView, SIGNAL( startAddresseeDrag() ),
+ this, SIGNAL( startDrag() ) );
+ connect( mIconView, SIGNAL( contextMenuRequested( QIconViewItem*, const QPoint& ) ),
+ this, SLOT( rmbClicked( QIconViewItem*, const QPoint& ) ) );
+}
+
+KAddressBookIconView::~KAddressBookIconView()
+{
+}
+
+KABC::Field *KAddressBookIconView::sortField() const
+{
+ // we have hardcoded sorting, so we have to return a hardcoded field :(
+ return KABC::Field::allFields()[ 2 ];
+}
+
+void KAddressBookIconView::readConfig( KConfig *config )
+{
+ KAddressBookView::readConfig( config );
+
+ disconnect( mIconView, SIGNAL( executed( QIconViewItem* ) ),
+ this, SLOT( addresseeExecuted( QIconViewItem* ) ) );
+
+ if ( KABPrefs::instance()->honorSingleClick() )
+ connect( mIconView, SIGNAL( executed( QIconViewItem* ) ),
+ this, SLOT( addresseeExecuted( QIconViewItem* ) ) );
+ else
+ connect( mIconView, SIGNAL( doubleClicked( QIconViewItem* ) ),
+ this, SLOT( addresseeExecuted( QIconViewItem* ) ) );
+}
+
+QStringList KAddressBookIconView::selectedUids()
+{
+ QStringList uidList;
+ QIconViewItem *item;
+ AddresseeIconViewItem *aItem;
+
+ for ( item = mIconView->firstItem(); item; item = item->nextItem() ) {
+ if ( item->isSelected() ) {
+ aItem = dynamic_cast<AddresseeIconViewItem*>( item );
+ if ( aItem )
+ uidList << aItem->addressee().uid();
+ }
+ }
+
+ return uidList;
+}
+
+void KAddressBookIconView::refresh( const QString &uid )
+{
+ QIconViewItem *item;
+ AddresseeIconViewItem *aItem;
+
+ if ( uid.isEmpty() ) {
+ // Rebuild the view
+ mIconView->clear();
+ mIconList.clear();
+
+ const KABC::Addressee::List addresseeList( addressees() );
+ KABC::Addressee::List::ConstIterator it( addresseeList.begin() );
+ const KABC::Addressee::List::ConstIterator endIt( addresseeList.end() );
+ for ( ; it != endIt; ++it )
+ aItem = new AddresseeIconViewItem( fields(), core()->addressBook(), *it, mIconView );
+
+ mIconView->arrangeItemsInGrid( true );
+
+ for ( item = mIconView->firstItem(); item; item = item->nextItem() ) {
+ AddresseeIconViewItem* aivi = dynamic_cast<AddresseeIconViewItem*>( item );
+ mIconList.append( aivi );
+ }
+
+ } else {
+ // Try to find the one to refresh
+ for ( item = mIconView->firstItem(); item; item = item->nextItem() ) {
+ aItem = dynamic_cast<AddresseeIconViewItem*>( item );
+ if ( aItem && (aItem->addressee().uid() == uid) ) {
+ aItem->refresh();
+ mIconView->arrangeItemsInGrid( true );
+ return;
+ }
+ }
+
+ refresh( QString::null );
+ }
+}
+
+void KAddressBookIconView::setSelected( const QString &uid, bool selected )
+{
+ QIconViewItem *item;
+ AddresseeIconViewItem *aItem;
+
+ if ( uid.isEmpty() ) {
+ mIconView->selectAll( selected );
+ } else {
+ bool found = false;
+ for ( item = mIconView->firstItem(); item && !found; item = item->nextItem() ) {
+
+ aItem = dynamic_cast<AddresseeIconViewItem*>( item );
+ if ( aItem && (aItem->addressee().uid() == uid) ) {
+ mIconView->setSelected( aItem, selected );
+ mIconView->ensureItemVisible( aItem );
+ found = true;
+ }
+ }
+ }
+}
+
+void KAddressBookIconView::setFirstSelected( bool selected )
+{
+ if ( mIconView->firstItem() ) {
+ mIconView->setSelected( mIconView->firstItem(), selected );
+ mIconView->ensureItemVisible( mIconView->firstItem() );
+ }
+}
+
+void KAddressBookIconView::addresseeExecuted( QIconViewItem *item )
+{
+ AddresseeIconViewItem *aItem = dynamic_cast<AddresseeIconViewItem*>( item );
+
+ if ( aItem )
+ emit executed( aItem->addressee().uid() );
+}
+
+void KAddressBookIconView::addresseeSelected()
+{
+ QIconViewItem *item;
+ AddresseeIconViewItem *aItem;
+
+ bool found = false;
+ for ( item = mIconView->firstItem(); item && !found; item = item->nextItem() ) {
+ if ( item->isSelected() ) {
+ aItem = dynamic_cast<AddresseeIconViewItem*>( item );
+ if ( aItem ) {
+ emit selected( aItem->addressee().uid() );
+ found = true;
+ }
+ }
+ }
+
+ if ( !found )
+ emit selected( QString::null );
+}
+
+void KAddressBookIconView::rmbClicked( QIconViewItem*, const QPoint &point )
+{
+ popup( point );
+}
+
+void KAddressBookIconView::scrollUp()
+{
+ QApplication::postEvent( mIconView, new QKeyEvent( QEvent::KeyPress, Qt::Key_Up, 0, 0 ) );
+}
+
+void KAddressBookIconView::scrollDown()
+{
+ QApplication::postEvent( mIconView, new QKeyEvent( QEvent::KeyPress, Qt::Key_Down, 0, 0 ) );
+}
+
+#include "kaddressbookiconview.moc"
diff --git a/kaddressbook/views/kaddressbookiconview.h b/kaddressbook/views/kaddressbookiconview.h
new file mode 100644
index 000000000..f11e7b8a1
--- /dev/null
+++ b/kaddressbook/views/kaddressbookiconview.h
@@ -0,0 +1,93 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#ifndef KADDRESSBOOKICONVIEW_H
+#define KADDRESSBOOKICONVIEW_H
+
+#include <qstring.h>
+#include <kiconview.h>
+#include "kaddressbookview.h"
+
+class QIconViewItem;
+class KConfig;
+class AddresseeIconView;
+class AddresseeIconViewItem;
+
+namespace KABC { class AddressBook; }
+
+/** This is an example kaddressbook view that is implemented using
+* KIconView. This view is not the most useful view, but it displays
+* how simple implementing a new view can be.
+*/
+class KAddressBookIconView : public KAddressBookView
+{
+ Q_OBJECT
+
+ public:
+ KAddressBookIconView( KAB::Core *core, QWidget *parent,
+ const char *name = 0 );
+ virtual ~KAddressBookIconView();
+
+ virtual QStringList selectedUids();
+ virtual QString type() const { return "Icon"; }
+ virtual KABC::Field *sortField() const;
+ virtual void readConfig( KConfig *config );
+
+ void scrollUp();
+ void scrollDown();
+
+ public slots:
+ void refresh( const QString &uid = QString() );
+ void setSelected( const QString &uid = QString(), bool selected = true );
+ virtual void setFirstSelected( bool selected = true );
+
+ protected slots:
+ void addresseeExecuted( QIconViewItem *item );
+ void addresseeSelected();
+ void rmbClicked( QIconViewItem*, const QPoint& );
+
+ private:
+ AddresseeIconView *mIconView;
+ QPtrList<AddresseeIconViewItem> mIconList;
+};
+
+
+class AddresseeIconView : public KIconView
+{
+ Q_OBJECT
+
+ public:
+ AddresseeIconView( QWidget *parent, const char *name = 0 );
+ ~AddresseeIconView();
+
+ signals:
+ void addresseeDropped( QDropEvent* );
+ void startAddresseeDrag();
+
+ protected:
+ virtual QDragObject *dragObject();
+
+ protected slots:
+ void itemDropped( QDropEvent*, const QValueList<QIconDragItem>& );
+};
+#endif
diff --git a/kaddressbook/views/kaddressbooktableview.cpp b/kaddressbook/views/kaddressbooktableview.cpp
new file mode 100644
index 000000000..e0ac61093
--- /dev/null
+++ b/kaddressbook/views/kaddressbooktableview.cpp
@@ -0,0 +1,384 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#include <qapplication.h>
+#include <qlayout.h>
+#include <qheader.h>
+#include <qvbox.h>
+#include <qlistbox.h>
+#include <qwidget.h>
+#include <qfile.h>
+#include <qimage.h>
+#include <qcombobox.h>
+#include <qapplication.h>
+#include <qdragobject.h>
+#include <qevent.h>
+#include <qurl.h>
+#include <qpixmap.h>
+
+#include <kabc/addressbook.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kcolorbutton.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kurl.h>
+#include <kurlrequester.h>
+#include <kimproxy.h>
+
+#include "configuretableviewdialog.h"
+#include "contactlistview.h"
+#include "core.h"
+#include "kabprefs.h"
+#include "undocmds.h"
+
+#include "kaddressbooktableview.h"
+
+class TableViewFactory : public ViewFactory
+{
+ public:
+ KAddressBookView *view( KAB::Core *core, QWidget *parent, const char *name )
+ {
+ return new KAddressBookTableView( core, parent, name );
+ }
+
+ QString type() const { return I18N_NOOP( "Table" ); }
+
+ QString description() const { return i18n( "A listing of contacts in a table. Each cell of "
+ "the table holds a field of the contact." ); }
+
+ ViewConfigureWidget *configureWidget( KABC::AddressBook *ab, QWidget *parent,
+ const char *name = 0 )
+ {
+ return new ConfigureTableViewWidget( ab, parent, name );
+ }
+};
+
+extern "C" {
+ void *init_libkaddrbk_tableview()
+ {
+ return ( new TableViewFactory );
+ }
+}
+
+KAddressBookTableView::KAddressBookTableView( KAB::Core *core,
+ QWidget *parent, const char *name )
+ : KAddressBookView( core, parent, name )
+{
+ mMainLayout = new QVBoxLayout( viewWidget(), 2 );
+
+ // The list view will be created when the config is read.
+ mListView = 0;
+ mIMProxy = 0;
+}
+
+KAddressBookTableView::~KAddressBookTableView()
+{
+}
+
+void KAddressBookTableView::reconstructListView()
+{
+ if ( mListView ) {
+ disconnect( mListView, SIGNAL( selectionChanged() ),
+ this, SLOT( addresseeSelected() ) );
+ disconnect( mListView, SIGNAL( executed( QListViewItem* ) ),
+ this, SLOT( addresseeExecuted( QListViewItem* ) ) );
+ disconnect( mListView, SIGNAL( doubleClicked( QListViewItem* ) ),
+ this, SLOT( addresseeExecuted( QListViewItem* ) ) );
+ disconnect( mListView, SIGNAL( startAddresseeDrag() ),
+ this, SIGNAL( startDrag() ) );
+ disconnect( mListView, SIGNAL( addresseeDropped( QDropEvent* ) ),
+ this, SIGNAL( dropped( QDropEvent* ) ) );
+ delete mListView;
+ }
+
+ mListView = new ContactListView( this, core()->addressBook(), viewWidget() );
+
+ mListView->setShowIM( mIMProxy != 0 );
+
+ // Add the columns
+ const KABC::Field::List fieldList( fields() );
+ KABC::Field::List::ConstIterator it;
+
+ int c = 0;
+ for ( it = fieldList.begin(); it != fieldList.end(); ++it ) {
+ mListView->addColumn( (*it)->label() );
+ mListView->setColumnWidthMode( c++, QListView::Manual );
+ }
+
+ if ( mListView->showIM() ) {
+ // IM presence is added separately, because it's not a KABC field.
+ // If you want to make this appear as the leftmost column by default, move
+ // this block immediately before the preceding for loop
+ // after the declaration of c.
+ mListView->addColumn( i18n( "Presence" ) );
+ mListView->setIMColumn( c++ );
+ }
+
+ mListView->setFullWidth( true );
+
+ connect( mListView, SIGNAL( selectionChanged() ),
+ this, SLOT( addresseeSelected() ) );
+ connect( mListView, SIGNAL( startAddresseeDrag() ),
+ this, SIGNAL( startDrag() ) );
+ connect( mListView, SIGNAL( addresseeDropped( QDropEvent* ) ),
+ this, SIGNAL( dropped( QDropEvent* ) ) );
+ connect( mListView, SIGNAL( contextMenu( KListView*, QListViewItem*, const QPoint& ) ),
+ this, SLOT( rmbClicked( KListView*, QListViewItem*, const QPoint& ) ) );
+ connect( mListView->header(), SIGNAL( clicked( int ) ),
+ this, SIGNAL( sortFieldChanged() ) );
+
+ if ( KABPrefs::instance()->honorSingleClick() )
+ connect( mListView, SIGNAL( executed( QListViewItem* ) ),
+ this, SLOT( addresseeExecuted( QListViewItem* ) ) );
+ else
+ connect( mListView, SIGNAL( doubleClicked( QListViewItem* ) ),
+ this, SLOT( addresseeExecuted( QListViewItem* ) ) );
+
+ refresh();
+
+ mListView->setSorting( 0, true );
+ mMainLayout->addWidget( mListView );
+ mMainLayout->activate();
+ mListView->show();
+}
+
+KABC::Field *KAddressBookTableView::sortField() const
+{
+ // we have hardcoded sorting, so we have to return a hardcoded field :(
+ return ( mListView->sortColumn() == -1 ? fields()[ 0 ] : fields()[ mListView->sortColumn() ] );
+}
+
+void KAddressBookTableView::writeConfig( KConfig *config )
+{
+ KAddressBookView::writeConfig( config );
+
+ mListView->saveLayout( config, config->group() );
+}
+
+void KAddressBookTableView::readConfig( KConfig *config )
+{
+ KAddressBookView::readConfig( config );
+
+ if ( config->readBoolEntry( "InstantMessagingPresence", false ) ) {
+ if ( !mIMProxy ) {
+ mIMProxy = KIMProxy::instance( kapp->dcopClient() );
+ connect( mIMProxy, SIGNAL( sigContactPresenceChanged( const QString& ) ),
+ this, SLOT( updatePresence( const QString& ) ) );
+ }
+ } else {
+ if ( mIMProxy ) {
+ disconnect( mIMProxy, SIGNAL( sigContactPresenceChanged( const QString& ) ),
+ this, SLOT( updatePresence( const QString& ) ) );
+ mIMProxy = 0;
+ }
+ }
+
+ // The config could have changed the fields, so we need to reconstruct
+ // the listview.
+ reconstructListView();
+
+ // Set the list view options
+ mListView->setAlternateBackgroundEnabled( config->readBoolEntry( "ABackground", true ) );
+ mListView->setSingleLineEnabled( config->readBoolEntry( "SingleLine", false ) );
+ mListView->setToolTipsEnabled( config->readBoolEntry( "ToolTips", true ) );
+
+ if ( config->readBoolEntry( "Background", false ) )
+ mListView->setBackgroundPixmap( config->readPathEntry( "BackgroundName" ) );
+
+ // Restore the layout of the listview
+ mListView->restoreLayout( config, config->group() );
+}
+
+void KAddressBookTableView::refresh( const QString &uid )
+{
+ if ( uid.isEmpty() ) {
+ // Clear the list view
+ QString currentUID, nextUID;
+ ContactListViewItem *currentItem = dynamic_cast<ContactListViewItem*>( mListView->currentItem() );
+ if ( currentItem ) {
+ ContactListViewItem *nextItem = dynamic_cast<ContactListViewItem*>( currentItem->itemBelow() );
+ if ( nextItem )
+ nextUID = nextItem->addressee().uid();
+ currentUID = currentItem->addressee().uid();
+ }
+
+ mListView->clear();
+
+ currentItem = 0;
+ const KABC::Addressee::List addresseeList( addressees() );
+ KABC::Addressee::List::ConstIterator it( addresseeList.begin() );
+ const KABC::Addressee::List::ConstIterator endIt( addresseeList.end() );
+ for ( ; it != endIt; ++it ) {
+ ContactListViewItem *item = new ContactListViewItem( *it, mListView,
+ core()->addressBook(), fields(), mIMProxy );
+ if ( (*it).uid() == currentUID )
+ currentItem = item;
+ else if ( (*it).uid() == nextUID && !currentItem )
+ currentItem = item;
+ }
+
+ // Sometimes the background pixmap gets messed up when we add lots
+ // of items.
+ mListView->repaint();
+
+ if ( currentItem ) {
+ mListView->setCurrentItem( currentItem );
+ mListView->ensureItemVisible( currentItem );
+ }
+ } else {
+ // Only need to update on entry. Iterate through and try to find it
+ ContactListViewItem *ceItem;
+ QPtrList<QListViewItem> selectedItems( mListView->selectedItems() );
+ QListViewItem *it;
+ for ( it = selectedItems.first(); it; it = selectedItems.next() ) {
+ ceItem = dynamic_cast<ContactListViewItem*>( it );
+ if ( ceItem && ceItem->addressee().uid() == uid ) {
+ ceItem->refresh();
+ return;
+ }
+ }
+ refresh( QString::null );
+ }
+}
+
+QStringList KAddressBookTableView::selectedUids()
+{
+ QStringList uidList;
+ ContactListViewItem *item;
+
+ QListViewItemIterator it( mListView, QListViewItemIterator::Selected );
+ while ( it.current() ) {
+ item = dynamic_cast<ContactListViewItem*>( it.current() );
+ if ( item )
+ uidList << item->addressee().uid();
+
+ ++it;
+ }
+
+ return uidList;
+}
+
+void KAddressBookTableView::setSelected( const QString &uid, bool selected )
+{
+ if ( uid.isEmpty() )
+ mListView->selectAll( selected );
+ else {
+ QListViewItemIterator it( mListView );
+ while ( it.current() ) {
+ ContactListViewItem *item = dynamic_cast<ContactListViewItem*>( it.current() );
+ if ( item && (item->addressee().uid() == uid) ) {
+ mListView->setSelected( item, selected );
+
+ if ( selected )
+ mListView->ensureItemVisible( item );
+ }
+
+ ++it;
+ }
+ }
+}
+
+void KAddressBookTableView::setFirstSelected( bool selected )
+{
+ if ( mListView->firstChild() ) {
+ mListView->setSelected( mListView->firstChild(), selected );
+ mListView->ensureItemVisible( mListView->firstChild() );
+ }
+}
+
+void KAddressBookTableView::addresseeSelected()
+{
+ // We need to try to find the first selected item. This might not be the
+ // last selected item, but when QListView is in multiselection mode,
+ // there is no way to figure out which one was
+ // selected last.
+ bool found =false;
+
+ QListViewItemIterator it( mListView, QListViewItemIterator::Selected );
+ while ( it.current() && !found ) {
+ found = true;
+ ContactListViewItem *item = dynamic_cast<ContactListViewItem*>( it.current() );
+ if ( item )
+ emit selected( item->addressee().uid() );
+
+ ++it;
+ }
+
+ if ( !found )
+ emit selected( QString::null );
+}
+
+void KAddressBookTableView::addresseeExecuted( QListViewItem *item )
+{
+ if ( item ) {
+ ContactListViewItem *ceItem = dynamic_cast<ContactListViewItem*>( item );
+
+ if ( ceItem )
+ emit executed( ceItem->addressee().uid() );
+ else
+ emit executed( QString::null );
+ } else {
+ emit executed( QString::null );
+ }
+}
+
+void KAddressBookTableView::rmbClicked( KListView*, QListViewItem*, const QPoint &point )
+{
+ popup( point );
+}
+
+void KAddressBookTableView::updatePresence( const QString &uid )
+{
+ // find the LVI to update and refresh() it
+ QListViewItem *item;
+ ContactListViewItem *ceItem;
+ for ( item = mListView->firstChild(); item; item = item->itemBelow() ) {
+ ceItem = dynamic_cast<ContactListViewItem*>( item );
+ if ( ( ceItem != 0L ) && ( ceItem->addressee().uid() == uid ) ) {
+ ceItem->setHasIM( true );
+ ceItem->refresh();
+ break;
+ }
+ }
+
+ if ( mListView->sortColumn() == mListView->imColumn() )
+ mListView->sort();
+}
+
+void KAddressBookTableView::scrollUp()
+{
+ QApplication::postEvent( mListView, new QKeyEvent( QEvent::KeyPress, Qt::Key_Up, 0, 0 ) );
+}
+
+void KAddressBookTableView::scrollDown()
+{
+ QApplication::postEvent( mListView, new QKeyEvent( QEvent::KeyPress, Qt::Key_Down, 0, 0 ) );
+}
+
+
+#include "kaddressbooktableview.moc"
diff --git a/kaddressbook/views/kaddressbooktableview.h b/kaddressbook/views/kaddressbooktableview.h
new file mode 100644
index 000000000..0d328ce86
--- /dev/null
+++ b/kaddressbook/views/kaddressbooktableview.h
@@ -0,0 +1,115 @@
+/*
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+*/
+
+#ifndef KADDRESSBOOKTABLEVIEW_H
+#define KADDRESSBOOKTABLEVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+#include <qlistview.h>
+#include <qstring.h>
+#include <qdialog.h>
+#include <qtabdialog.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+
+#include "kaddressbookview.h"
+
+class QListViewItem;
+class QListBox;
+class QVBoxLayout;
+class KConfig;
+class KIMProxy;
+
+class ContactListViewItem;
+class ContactListView;
+
+namespace KABC { class AddressBook; }
+
+/**
+ * This class is the table view for kaddressbook. This view is a KListView
+ * with multiple columns for the selected fields.
+ *
+ * @short Table View
+ * @author Don Sanders <dsanders@kde.org>
+ * @version 0.1
+ */
+class KAddressBookTableView : public KAddressBookView
+{
+friend class ContactListView;
+
+ Q_OBJECT
+
+ public:
+ KAddressBookTableView( KAB::Core *core, QWidget *parent,
+ const char *name = 0 );
+ virtual ~KAddressBookTableView();
+
+ virtual void refresh( const QString &uid = QString() );
+ virtual QStringList selectedUids();
+ virtual void setSelected( const QString &uid = QString(), bool selected = false );
+ virtual void setFirstSelected( bool selected = true );
+ virtual KABC::Field *sortField() const;
+
+ virtual void readConfig( KConfig *config );
+ virtual void writeConfig( KConfig *config );
+ virtual QString type() const { return "Table"; }
+
+ void scrollUp();
+ void scrollDown();
+
+ public slots:
+ virtual void reconstructListView();
+
+ protected slots:
+ /**
+ Called whenever the user selects an addressee in the list view.
+ */
+ void addresseeSelected();
+
+ /**
+ Called whenever the user executes an addressee. In terms of the
+ list view, this is probably a double click
+ */
+ void addresseeExecuted( QListViewItem* );
+
+ /**
+ RBM menu called.
+ */
+ void rmbClicked( KListView*, QListViewItem*, const QPoint& );
+
+ /**
+ * Called to update the presence of a single item
+ */
+ void updatePresence( const QString &uid );
+
+ private:
+ QVBoxLayout *mMainLayout;
+ ContactListView *mListView;
+ KIMProxy *mIMProxy;
+};
+
+#endif
diff --git a/kaddressbook/views/tableview.desktop b/kaddressbook/views/tableview.desktop
new file mode 100644
index 000000000..b07b2a19c
--- /dev/null
+++ b/kaddressbook/views/tableview.desktop
@@ -0,0 +1,64 @@
+[Desktop Entry]
+X-KDE-Library=libkaddrbk_tableview
+Name=Table View
+Name[af]=Tabel Aansig
+Name[ar]=عرض الجدول
+Name[be]=У выглядзе табліцы
+Name[bg]=Преглед в таблица
+Name[br]=Gwel taolenn
+Name[bs]=Pogled tabele
+Name[ca]=Vista de taula
+Name[cs]=Tabulkový pohled
+Name[cy]=Golwg Tabl
+Name[da]=Tabel-visning
+Name[de]=Tabellenansicht
+Name[el]=Προβολή πίνακα
+Name[eo]=Tabelrigardo
+Name[es]=Vista de tabla
+Name[et]=Tabelivaade
+Name[eu]=Taula ikupegia
+Name[fa]=نمای جدول
+Name[fi]=Taulukkonäkymä
+Name[fr]=Vue en tableaux
+Name[fy]=Tabelwerjefte
+Name[gl]=Vista de árbore
+Name[he]=תצוגת טבלה
+Name[hi]=टेबल दृश्य
+Name[hu]=Táblázatos nézet
+Name[is]=Töflusýn
+Name[it]=Vista tabella
+Name[ja]=テーブルビュー
+Name[ka]=ცხრილი
+Name[kk]=Кесте
+Name[km]=ទិដ្ឋភាព​តារាង
+Name[lt]=Lentelės vaizdas
+Name[mk]=Преглед со табела
+Name[ms]=Pelihat Jadual
+Name[nb]=Tabellvisning
+Name[nds]=Tabellansicht
+Name[ne]=तालिका दृश्य
+Name[nl]=Tabelweergave
+Name[nn]=Tabellvising
+Name[pa]=ਸਾਰਣੀ ਦਰਿਸ਼
+Name[pl]=Widok tabeli
+Name[pt]=Vista em Tabela
+Name[pt_BR]=Visualização de Tabela
+Name[ro]=Vizualizare tabel
+Name[ru]=Таблица
+Name[se]=Tabeallačájeheapmi
+Name[sk]=Prezeranie tabuľky
+Name[sl]=Tabelarični prikaz
+Name[sr]=Табеларни приказ
+Name[sr@Latn]=Tabelarni prikaz
+Name[sv]=Tabellvy
+Name[ta]=அட்டவணை காட்சி
+Name[tg]=Ҷадвал
+Name[tr]=Tablo Görünümü
+Name[uk]=Вигляд таблицею
+Name[uz]=Jadval koʻrinishida
+Name[uz@cyrillic]=Жадвал кўринишида
+Name[zh_CN]=表格视图
+Name[zh_TW]=表格檢視
+Type=Service
+ServiceTypes=KAddressBook/View
+X-KDE-KAddressBook-ViewPluginVersion=1