diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch) | |
tree | 67208f7c145782a7e90b123b982ca78d88cc2c87 /kaddressbook/views | |
download | tdepim-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')
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 |