-rw-r--r-- | kaddressbook/views/cardview.cpp | 1719 | ||||
-rw-r--r-- | kaddressbook/views/cardview.desktop | 18 | ||||
-rw-r--r-- | kaddressbook/views/cardview.h | 473 | ||||
-rw-r--r-- | kaddressbook/views/colorlistbox.cpp | 230 | ||||
-rw-r--r-- | kaddressbook/views/colorlistbox.h | 76 | ||||
-rw-r--r-- | kaddressbook/views/configurecardviewdialog.cpp | 364 | ||||
-rw-r--r-- | kaddressbook/views/configurecardviewdialog.h | 117 | ||||
-rw-r--r-- | kaddressbook/views/configuretableviewdialog.cpp | 155 | ||||
-rw-r--r-- | kaddressbook/views/configuretableviewdialog.h | 88 | ||||
-rw-r--r-- | kaddressbook/views/contactlistview.cpp | 340 | ||||
-rw-r--r-- | kaddressbook/views/contactlistview.h | 128 | ||||
-rw-r--r-- | kaddressbook/views/kaddressbookcardview.cpp | 394 | ||||
-rw-r--r-- | kaddressbook/views/kaddressbookcardview.h | 117 | ||||
-rw-r--r-- | kaddressbook/views/kaddressbookiconview.cpp | 378 | ||||
-rw-r--r-- | kaddressbook/views/kaddressbookiconview.h | 130 | ||||
-rw-r--r-- | kaddressbook/views/kaddressbooktableview.cpp | 337 | ||||
-rw-r--r-- | kaddressbook/views/kaddressbooktableview.h | 114 |
17 files changed, 5178 insertions, 0 deletions
diff --git a/kaddressbook/views/cardview.cpp b/kaddressbook/views/cardview.cpp new file mode 100644 index 0000000..65f793c --- a/dev/null +++ b/kaddressbook/views/cardview.cpp @@ -0,0 +1,1719 @@ +/* + This file is part of KAddressBook. + Copyright (c) 2002 Mike Pilone <mpilone@slac.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +//BEGIN Includes +#include "cardview.h" + +#include <limits.h> + +#include <qpainter.h> +#include <qtimer.h> +#include <qdatetime.h> +#include <qlabel.h> +#include <qstyle.h> +#include <qcursor.h> +#include <qtooltip.h> + +#include <kdebug.h> +#include <kglobalsettings.h> +//END includes + +#define MIN_ITEM_WIDTH 80 + +//BEGIN Helpers +////////////////////////////////////// +// CardViewTip +class CardViewTip : public QLabel { + public: + CardViewTip(QWidget *parent=0, const char *name=0) : QLabel( parent, name ) + { + setPalette( QToolTip::palette() ); + setFrameStyle( Panel|Plain ); + setMidLineWidth(0); + setIndent(1); + } + + ~CardViewTip() {}; + protected: + void leaveEvent( QEvent * ) + { + hide(); + } +}; + +////////////////////////////////////// +// CardViewItemList + + +// +// Warning: make sure you use findRef() instead of find() to find an +// item! Only the pointer value is unique in the list. +// +class CardViewItemList : public QPtrList<CardViewItem> +{ + protected: + virtual int compareItems(QPtrCollection::Item item1, + QPtrCollection::Item item2) + { + CardViewItem *cItem1 = (CardViewItem*)item1; + CardViewItem *cItem2 = (CardViewItem*)item2; + + if ( cItem1 == cItem2 ) + return 0; + + if ((cItem1 == 0) || (cItem2 == 0)) + return cItem1 ? -1 : 1; + + if (cItem1->caption() < cItem2->caption()) + return -1; + + else if (cItem1->caption() > cItem2->caption()) + return 1; + + return 0; + } + + private: + /*int find( const CardViewItem * ) + { + qDebug("DON'T USE CardViewItemList::find( item )! Use findRef( item )!"); + }*/ +}; + +////////////////////////////////////// +// CardViewSeparator +class CardViewSeparator +{ + friend class CardView; + + public: + CardViewSeparator(CardView *view) + : mView(view) + { + mRect = QRect(0, 0, view->separatorWidth(), 0); + } + + ~CardViewSeparator() {} + + void paintSeparator(QPainter *p, QColorGroup &cg) + { + p->fillRect(0, 0, mRect.width(), mRect.height(), + cg.brush(QColorGroup::Button)); + } + + void repaintSeparator() + { + mView->repaintContents(mRect); + } + + private: + CardView *mView; + QRect mRect; +}; + +//END Helpers + +//BEGIN Private Data + +class CardViewPrivate +{ + public: + CardViewPrivate() + : mSelectionMode( CardView::Multi ), + mDrawCardBorder( true ), + mDrawFieldLabels( true ), + mDrawSeparators( true), + mSepWidth( 2 ), + mShowEmptyFields( false ), + mLayoutDirty( true ), + mLastClickOnItem( false ), + mItemMargin( 0 ), + mItemSpacing( 10 ), + mItemWidth( 200 ), + mMaxFieldLines( INT_MAX ), + mCurrentItem( 0L ), + mLastClickPos( QPoint(0, 0) ), + mRubberBandAnchor( 0 ), + mCompText( QString::null ), + mResizeAnchor(0) + {}; + + CardViewItemList mItemList; + QPtrList<CardViewSeparator> mSeparatorList; + QFontMetrics *mFm; + QFontMetrics *mBFm; // bold font + QFont mHeaderFont; // custom header font + CardView::SelectionMode mSelectionMode; + bool mDrawCardBorder; + bool mDrawFieldLabels; + bool mDrawSeparators; + int mSepWidth; + bool mShowEmptyFields; + bool mLayoutDirty; + bool mLastClickOnItem; + uint mItemMargin; // internal margin in items + uint mItemSpacing; // spacing between items, column seperators and border + int mItemWidth; // width of all items + uint mMaxFieldLines; // Max lines to dispaly pr field + CardViewItem *mCurrentItem; + QPoint mLastClickPos; + QTimer *mTimer; // times out if mouse rests for more than 500 msecs + CardViewTip *mTip; // passed to the item under a resting cursor to display full text + bool mOnSeparator; // set/reset on mouse movement + // for resizing by dragging the separators + int mResizeAnchor; // uint, ulong? the mouse down separator left + int mRubberBandAnchor; // for erasing rubber bands + // data used for resizing. + // as they are beeded by each mouse move while resizing, we store them here, + // saving 8 calculations in each mouse move. + int colspace; // amount of space between items pr column + uint first; // the first col to anchor at for painting rubber bands + int firstX; // X position of first in pixel + int pressed; // the colummn that was pressed on at resizing start + int span; // pressed - first + // key completion + QString mCompText; // current completion string + QDateTime mCompUpdated; // ...was updated at this time +}; + +class CardViewItemPrivate +{ + public: + CardViewItemPrivate() : + x( 0 ), + y( 0 ), + mSelected( false ){}; + + + QString mCaption; + QPtrList< CardViewItem::Field > mFieldList; + bool mSelected; + int x; // horizontal position, set by the view + int y; // vertical position, set by the view + int maxLabelWidth; // the width of the widest label, according to the view font. + int hcache; // height cache +}; +//END Private Data + +//BEGIN CardViewItem + +CardViewItem::CardViewItem(CardView *parent, QString caption) + : d(new CardViewItemPrivate()), mView(parent) +{ + d->mCaption = caption; + + initialize(); +} + +CardViewItem::~CardViewItem() +{ + // Remove ourself from the view + if (mView != 0) + mView->takeItem(this); + + delete d; + d = 0; +} + +void CardViewItem::initialize() +{ + d->mSelected = false; + d->mFieldList.setAutoDelete(true); + d->maxLabelWidth = 0; + d->hcache=0; + + //calcRect(); + + // Add ourself to the view + if (mView != 0) + mView->insertItem(this); +} + +void CardViewItem::paintCard(QPainter *p, QColorGroup &cg) +{ + + if (!mView) + return; + + QPen pen; + QBrush brush; + QFontMetrics fm = *(mView->d->mFm); + QFontMetrics bFm = *(mView->d->mBFm); + bool drawLabels = mView->d->mDrawFieldLabels; + bool drawBorder = mView->d->mDrawCardBorder; + int mg = mView->itemMargin(); + int w = mView->itemWidth() - (mg*2); + int h = height() - (mg*2); + const int colonWidth( fm.width(":") ); + int labelXPos = 2 + mg; + int labelWidth = QMIN( w/2 - 4 - mg, d->maxLabelWidth + colonWidth + 4 ); + int valueXPos = labelWidth + 4 + mg; + int valueWidth = w - labelWidth - 4 - mg; + + p->setFont( mView->font() ); + labelWidth -= colonWidth; // extra space for the colon + + if (!drawLabels) + { + valueXPos = labelXPos; + valueWidth = w - 4; + } + + // Draw a simple box + if (isSelected()) + pen = QPen(cg.highlight(), 1); + else + pen = QPen(cg.button(), 1); + p->setPen(pen); + + // Draw the border - this is only draw if the user asks for it. + if (drawBorder) + p->drawRect( mg, mg, w, h ); + + // set the proper pen color for the caption box + if (isSelected()) + brush = cg.brush(QColorGroup::Highlight); + else + brush = cg.brush(QColorGroup::Button); + + p->fillRect(mg, mg, w, 4 + bFm.height(), brush); + + // Now paint the caption + p->save(); + QFont bFont = mView->headerFont(); + //bFont.setBold(true); + p->setFont(bFont); + if (isSelected()) + p->setPen(cg.highlightedText()); + else + p->setPen(cg.buttonText()); + p->drawText(2+mg, 2+mg + bFm.ascent()/*bFm.height()*//*-bFm.descent()*//*-bFm.leading()*/, trimString(d->mCaption, w-4, bFm)); + p->restore(); + + // Go through the fields and draw them + QPtrListIterator< CardViewItem::Field > iter(d->mFieldList); + QString label, value; + int yPos = mg + 4 + bFm.height()/* + 1*/ + fm.height(); // why the + 1 ??? (anders) + p->setPen(cg.text()); + + int fh = fm.height(); + int cln( 0 ); + QString tmp; + int maxLines = mView->maxFieldLines(); + for (iter.toFirst(); iter.current(); ++iter) + { + value = (*iter)->second; + if ( value.isEmpty() && ! mView->d->mShowEmptyFields ) + continue; + + if (drawLabels) + { + label = trimString((*iter)->first, labelWidth, fm); + p->drawText(labelXPos, yPos, label + ":"); + } +/* US original + for (cln=0; cln <= maxLines; cln++) + { + tmp = value.section('\n',cln,cln); + if ( !tmp.isEmpty() ) p->drawText( valueXPos, yPos + cln*fh, trimString( tmp, valueWidth, fm ) ); + else break; + } +*/ + +//US new implementation + QStringList strlst = QStringList::split('\n', value, true); + + for (cln=0; cln <= maxLines && cln <= (int)strlst.count(); cln++) + { + tmp = strlst[cln]; + + if ( !tmp.isEmpty() ) + p->drawText( valueXPos, yPos + cln*fh, trimString( tmp, valueWidth, fm ) ); + else + break; + + } + + if ( cln == 0 ) cln = 1; + yPos += cln * fh + 2; + } + + // if we are the current item and the view has focus, draw focus rect + if ( mView->currentItem() == this && mView->hasFocus() ) + { +/*US + mView->style().drawPrimitive( QStyle::PE_FocusRect, p, + QRect(0, 0, mView->itemWidth(), h+(2*mg)), cg, + QStyle::Style_FocusAtBorder, + QStyleOption( isSelected() ? cg.highlight() : cg.base() ) ); +*/ + + const QColor pHighl = isSelected() ? cg.highlight() : cg.base(); + const QRect r(0, 0, mView->itemWidth(), h+(2*mg)); +#ifndef DESKTOP_VERSION + mView->style().drawFocusRect(p, r, cg, &pHighl, true); +#endif + } +} + +const QString &CardViewItem::caption() const +{ + return d->mCaption; +} + + +int CardViewItem::height( bool allowCache ) const +{ + // use cache + if ( allowCache && d->hcache ) + return d->hcache; + + // Base height: + // 2 for line width + // 2 for top caption pad + // 2 for bottom caption pad + // 2 pad for the end + // + 2 times the advised margin + int baseHeight = 8 + ( 2 * mView->itemMargin() ); + + // size of font for each field + // 2 pad for each field + + // anders: if the view does not show empty fields, check for value + bool sef = mView->showEmptyFields(); + int fh = mView->d->mFm->height();//lineSpacing(); // font height + //int sp = QMAX( 0, 2- mView->d->mFm->leading() ); // field spacing NOTE make a property + int fieldHeight = 0; + int lines; + int maxLines( mView->maxFieldLines() ); + QPtrListIterator< CardViewItem::Field > iter(d->mFieldList); + for (iter.toFirst(); iter.current(); ++iter) + { + if ( !sef && (*iter)->second.isEmpty() ) + continue; + lines = QMIN( (*iter)->second.contains('\n') + 1, maxLines ); + fieldHeight += ( lines * fh ) + 2;//sp; + } + + // height of caption font (bold) + fieldHeight += mView->d->mBFm->height(); + d->hcache = baseHeight + fieldHeight; + return d->hcache; +} + +bool CardViewItem::isSelected() const +{ + return d->mSelected; +} + +void CardViewItem::setSelected(bool selected) +{ + d->mSelected = selected; +} + +void CardViewItem::insertField(const QString &label, const QString &value) +{ + CardViewItem::Field *f = new CardViewItem::Field(label, value); + d->mFieldList.append(f); + d->hcache=0; + + if (mView) + { + mView->setLayoutDirty(true); + d->maxLabelWidth = QMAX( mView->d->mFm->width( label ), d->maxLabelWidth ); + } +} + +void CardViewItem::removeField(const QString &label) +{ + CardViewItem::Field *f; + + QPtrListIterator< CardViewItem::Field > iter(d->mFieldList); + for (iter.toFirst(); iter.current(); ++iter) + { + f = *iter; + if (f->first == label) + break; + } + + if (*iter) + d->mFieldList.remove(*iter); + d->hcache = 0; + + if (mView) + mView->setLayoutDirty(true); +} + +void CardViewItem::clearFields() +{ + d->mFieldList.clear(); + d->hcache = 0; + + if (mView) + mView->setLayoutDirty(true); +} + +QString CardViewItem::trimString(const QString &text, int width, + QFontMetrics &fm) +{ + if (fm.width(text) <= width) + return text; + + QString dots = "..."; + int dotWidth = fm.width(dots); + QString trimmed; + int charNum = 0; + + while (fm.width(trimmed) + dotWidth < width) + { + trimmed += text[charNum]; + charNum++; + } + + // Now trim the last char, since it put the width over the top + trimmed = trimmed.left(trimmed.length()-1); + trimmed += dots; + + return trimmed; +} + +CardViewItem *CardViewItem::nextItem() +{ + CardViewItem *item = 0; + + if (mView) + item = mView->itemAfter(this); + + return item; +} + +void CardViewItem::repaintCard() +{ + if (mView) + mView->repaintItem(this); +} + +void CardViewItem::setCaption(const QString &caption) +{ + d->mCaption = caption; + repaintCard(); +} + +QString CardViewItem::fieldValue(const QString &label) +{ + QPtrListIterator< CardViewItem::Field > iter(d->mFieldList); + for (iter.toFirst(); iter.current(); ++iter) + if ((*iter)->first == label) + return (*iter)->second; + + return QString(); +} + + +void CardViewItem::showFullString( const QPoint &itempos, CardViewTip *tip ) +{ + bool trimmed( false ); + QString s; + int mrg = mView->itemMargin(); + int y = mView->d->mBFm->height() + 6 + mrg; + int w = mView->itemWidth() - (2*mrg); + int lw; + bool drawLabels = mView->drawFieldLabels(); + bool isLabel = drawLabels && itempos.x() < w/2 ? true : false; + + if ( itempos.y() < y ) + { + if ( itempos.y() < 8 + mrg || itempos.y() > y - 4 ) + return; + // this is the caption + s = caption(); + trimmed = mView->d->mBFm->width( s ) > w - 4; + y = 2 + mrg; + lw = 0; + isLabel=true; + } else { + // find the field + Field *f = fieldAt( itempos ); + if ( !f || ( !mView->showEmptyFields() && f->second.isEmpty() ) ) + return; + + // y position: + // header font height + 4px hader margin + 2px leading + item margin + // + actual field index * (fontheight + 2px leading) + int maxLines = mView->maxFieldLines(); + bool se = mView->showEmptyFields(); + int fh = mView->d->mFm->height(); +// { + Field *_f; + for (_f = d->mFieldList.first(); _f != f; _f = d->mFieldList.next()) + if ( se || ! _f->second.isEmpty() ) + y += ( QMIN(_f->second.contains('\n')+1, maxLines) * fh ) + 2; +// } + if ( isLabel && itempos.y() > y + fh ) + return; + // label or data? + s = isLabel ? f->first : f->second; + // trimmed? + int colonWidth = mView->d->mFm->width(":"); + lw = drawLabels ? // label width + QMIN( w/2 - 4 - mrg, d->maxLabelWidth + colonWidth + 4 ) : + 0; + int mw = isLabel ? lw - colonWidth : w - lw - (mrg*2); // max width for string + if ( isLabel ) + { + trimmed = mView->d->mFm->width( s ) > mw - colonWidth; + } else { + QRect r( mView->d->mFm->boundingRect( 0, 0, INT_MAX, INT_MAX, Qt::AlignTop|Qt::AlignLeft, s ) ); + trimmed = r.width() > mw || r.height()/fh > QMIN(s.contains('\n') + 1, maxLines); + } + } + if ( trimmed ) + { + tip->setFont( (isLabel && !lw) ? mView->headerFont() : mView->font() ); // if condition is true, a header + tip->setText( s ); + tip->adjustSize(); + // find a proper position + int lx; + lx = isLabel || !drawLabels ? mrg : lw + mrg + 2 /*-1*/; + QPoint pnt(mView->contentsToViewport( QPoint(d->x, d->y) )); + pnt += QPoint(lx, y); + if ( pnt.x() < 0 ) + pnt.setX( 0 ); + if ( pnt.x() + tip->width() > mView->visibleWidth() ) + pnt.setX( mView->visibleWidth() - tip->width() ); + if ( pnt.y() + tip->height() > mView->visibleHeight() ) + pnt.setY( QMAX( 0, mView->visibleHeight() - tip->height() ) ); + // show + tip->move( pnt ); + tip->show(); + } +} + +CardViewItem::Field *CardViewItem::fieldAt( const QPoint & itempos ) const +{ + int ypos = mView->d->mBFm->height() + 7 + mView->d->mItemMargin; + int iy = itempos.y(); + // skip below caption + if ( iy <= ypos ) + return 0; + // try find a field + bool showEmpty = mView->showEmptyFields(); + int fh = mView->d->mFm->height(); + int maxLines = mView->maxFieldLines(); + Field *f; + for ( f = d->mFieldList.first(); f; f = d->mFieldList.next() ) + { + if ( showEmpty || !f->second.isEmpty() ) + ypos += ( QMIN( f->second.contains('\n')+1, maxLines ) *fh)+2; + if ( iy <= ypos ) + break; + } + return f ? f : 0; +} +//END CardViewItem + +//BEGIN CardView + +CardView::CardView(QWidget *parent, const char *name) + : QScrollView(parent, name), + d(new CardViewPrivate()) +{ + d->mItemList.setAutoDelete(true); + d->mSeparatorList.setAutoDelete(true); + + QFont f = font(); + d->mFm = new QFontMetrics(f); + f.setBold(true); + d->mHeaderFont = f; + d->mBFm = new QFontMetrics(f); + d->mTip = ( new CardViewTip( viewport() ) ), + d->mTip->hide(); + d->mTimer = ( new QTimer(this, "mouseTimer") ), + + viewport()->setMouseTracking( true ); + viewport()->setFocusProxy(this); + viewport()->setFocusPolicy(WheelFocus); + viewport()->setBackgroundMode(PaletteBase); + + connect( d->mTimer, SIGNAL(timeout()), this, SLOT(tryShowFullText()) ); + +//US setBackgroundMode(PaletteBackground, PaletteBase); + setBackgroundMode(PaletteBackground); + + // no reason for a vertical scrollbar + setVScrollBarMode(AlwaysOff); +} + +CardView::~CardView() +{ + delete d->mFm; + delete d->mBFm; + delete d; + d = 0; +} + +void CardView::insertItem(CardViewItem *item) +{ + d->mItemList.inSort(item); + setLayoutDirty(true); +} + +void CardView::takeItem(CardViewItem *item) +{ + if ( d->mCurrentItem == item ) + d->mCurrentItem = item->nextItem(); + d->mItemList.take(d->mItemList.findRef(item)); + + setLayoutDirty(true); +} + +void CardView::clear() +{ + d->mItemList.clear(); + + setLayoutDirty(true); +} + +CardViewItem *CardView::currentItem() +{ + if ( ! d->mCurrentItem && d->mItemList.count() ) + d->mCurrentItem = d->mItemList.first(); + return d->mCurrentItem; +} + +void CardView::setCurrentItem( CardViewItem *item ) +{ + if ( !item ) + return; + else if ( item->cardView() != this ) + { + kdDebug(5720)<<"CardView::setCurrentItem: Item ("<<item<<") not owned! Backing out.."<<endl; + return; + } + else if ( item == currentItem() ) + { + return; + } + + if ( d->mSelectionMode == Single ) + { + setSelected( item, true ); + } + else + { + CardViewItem *it = d->mCurrentItem; + d->mCurrentItem = item; + if ( it ) + it->repaintCard(); + item->repaintCard(); + } + if ( ! d->mOnSeparator ) + ensureItemVisible( item ); + emit currentChanged( item ); +} + +CardViewItem *CardView::itemAt(const QPoint &viewPos) +{ + CardViewItem *item = 0; + QPtrListIterator<CardViewItem> iter(d->mItemList); + bool found = false; + for (iter.toFirst(); iter.current() && !found; ++iter) + { + item = *iter; + //if (item->d->mRect.contains(viewPos)) + if (QRect(item->d->x, item->d->y, d->mItemWidth, item->height()).contains(viewPos)) + found = true; + } + + if (found) + return item; + + return 0; +} + +QRect CardView::itemRect(const CardViewItem *item) +{ + //return item->d->mRect; + return QRect(item->d->x, item->d->y, d->mItemWidth, item->height()); +} + +void CardView::ensureItemVisible(const CardViewItem *item) +{ + ensureVisible(item->d->x , item->d->y, d->mItemSpacing, 0); + ensureVisible(item->d->x + d->mItemWidth, item->d->y, d->mItemSpacing, 0); +} + +void CardView::repaintItem(const CardViewItem *item) +{ + //repaintContents(item->d->mRect); + repaintContents( QRect(item->d->x, item->d->y, d->mItemWidth, item->height()) ); +} + +void CardView::setSelectionMode(CardView::SelectionMode mode) +{ + selectAll(false); + + d->mSelectionMode = mode; +} + +CardView::SelectionMode CardView::selectionMode() const +{ + return d->mSelectionMode; +} + +void CardView::selectAll(bool state) +{ + QPtrListIterator<CardViewItem> iter(d->mItemList); + if (!state) + { + for (iter.toFirst(); iter.current(); ++iter) + { + if ((*iter)->isSelected()) + { + (*iter)->setSelected(false); + (*iter)->repaintCard(); + } + } + //emit selectionChanged(); // WARNING FIXME + emit selectionChanged(0); + } + else if (d->mSelectionMode != CardView::Single) + { + for (iter.toFirst(); iter.current(); ++iter) + { + (*iter)->setSelected(true); + } + + if (d->mItemList.count() > 0) + { + // emit, since there must have been at least one selected + emit selectionChanged(); + //repaint();//??? + viewport()->update(); + } + } +} + +void CardView::setSelected(CardViewItem *item, bool selected) +{ + if ((item == 0) || (item->isSelected() == selected)) + return; + + if ( selected && d->mCurrentItem != item ) + { + CardViewItem *it = d->mCurrentItem; + d->mCurrentItem = item; + if ( it ) + it->repaintCard(); + } + + if (d->mSelectionMode == CardView::Single) + { + bool b = signalsBlocked(); + blockSignals(true); + selectAll(false); + blockSignals(b); + + if (selected) + { + item->setSelected(selected); + item->repaintCard(); + emit selectionChanged(); + emit selectionChanged(item); + } + else + { + emit selectionChanged(); + emit selectionChanged(0); + } + } + else if (d->mSelectionMode == CardView::Multi) + { + item->setSelected(selected); + item->repaintCard(); + emit selectionChanged(); + } + else if (d->mSelectionMode == CardView::Extended) + { + bool b = signalsBlocked(); + blockSignals(true); + selectAll(false); + blockSignals(b); + + item->setSelected(selected); + item->repaintCard(); + emit selectionChanged(); + } +} + +bool CardView::isSelected(CardViewItem *item) const +{ + return (item && item->isSelected()); +} + +CardViewItem *CardView::selectedItem() const +{ + // find the first selected item + QPtrListIterator<CardViewItem> iter(d->mItemList); + for (iter.toFirst(); iter.current(); ++iter) + { + if ((*iter)->isSelected()) + return *iter; + } + + return 0; +} + +CardViewItem *CardView::firstItem() const +{ + return d->mItemList.first(); +} + +int CardView::childCount() const +{ + return d->mItemList.count(); +} +/*US +CardViewItem *CardView::findItem(const QString &text, const QString &label, + Qt::StringComparisonMode compare) +{ + // IF the text is empty, we will return null, since empty text will + // match anything! + if (text.isEmpty()) + return 0; + + QPtrListIterator<CardViewItem> iter(d->mItemList); + if (compare & Qt::BeginsWith) + { + QString value; + for (iter.toFirst(); iter.current(); ++iter) + { + value = (*iter)->fieldValue(label).upper(); + if (value.startsWith(text.upper())) + return *iter; + } + } + else + { + kdDebug(5720) << "CardView::findItem: search method not implemented" << endl; + } + + return 0; +} +*/ + +uint CardView::columnWidth() +{ + return d->mDrawSeparators ? + d->mItemWidth + ( 2 * d->mItemSpacing ) + d->mSepWidth : + d->mItemWidth + d->mItemSpacing; +} + +void CardView::drawContents(QPainter *p, int clipx, int clipy, + int clipw, int cliph) +{ + QScrollView::drawContents(p, clipx, clipy, clipw, cliph); + + if (d->mLayoutDirty) + calcLayout(); + + //kdDebug() << "CardView::drawContents: " << clipx << ", " << clipy + // << ", " << clipw << ", " << cliph << endl; + + QColorGroup cg = viewport()->palette().active(); // allow setting costum colors in the viewport pale + + QRect clipRect(clipx, clipy, clipw, cliph); + QRect cardRect; + QRect sepRect; + CardViewItem *item; + CardViewSeparator *sep; + + // make sure the viewport is a pure background + viewport()->erase(clipRect); + + // Now tell the cards to draw, if they are in the clip region + QPtrListIterator<CardViewItem> iter(d->mItemList); + for (iter.toFirst(); iter.current(); ++iter) + { + item = *iter; + cardRect.setRect( item->d->x, item->d->y, d->mItemWidth, item->height() ); + + if (clipRect.intersects(cardRect) || clipRect.contains(cardRect)) + { + //kdDebug() << "\trepainting card at: " << cardRect.x() << ", " + // << cardRect.y() << endl; + + // Tell the card to paint + p->save(); + p->translate(cardRect.x(), cardRect.y()); + item->paintCard(p, cg); + p->restore(); + } + } + + // Followed by the separators if they are in the clip region + QPtrListIterator<CardViewSeparator> sepIter(d->mSeparatorList); + for (sepIter.toFirst(); sepIter.current(); ++sepIter) + { + sep = *sepIter; + sepRect = sep->mRect; + + if (clipRect.intersects(sepRect) || clipRect.contains(sepRect)) + { + p->save(); + p->translate(sepRect.x(), sepRect.y()); + sep->paintSeparator(p, cg); + p->restore(); + } + } +} + +void CardView::resizeEvent(QResizeEvent *e) +{ + QScrollView::resizeEvent(e); + + setLayoutDirty(true); +} + +void CardView::calcLayout() +{ + //kdDebug() << "CardView::calcLayout:" << endl; + + // Start in the upper left corner and layout all the + // cars using their height and width + int maxWidth = 0; + int maxHeight = 0; + int xPos = 0; + int yPos = 0; + int cardSpacing = d->mItemSpacing; + + // delete the old separators + d->mSeparatorList.clear(); + + QPtrListIterator<CardViewItem> iter(d->mItemList); + CardViewItem *item = 0; + CardViewSeparator *sep = 0; + xPos += cardSpacing; + + for (iter.toFirst(); iter.current(); ++iter) + { + item = *iter; + + yPos += cardSpacing; + + if (yPos + item->height() + cardSpacing >= height() - horizontalScrollBar()->height()) + { + maxHeight = QMAX(maxHeight, yPos); + + // Drawing in this column would be greater than the height + // of the scroll view, so move to next column + yPos = cardSpacing; + xPos += cardSpacing + maxWidth; + if (d->mDrawSeparators) + { + // Create a separator since the user asked + sep = new CardViewSeparator(this); + sep->mRect.moveTopLeft(QPoint(xPos, yPos+d->mItemMargin)); + xPos += d->mSepWidth + cardSpacing; + d->mSeparatorList.append(sep); + } + + maxWidth = 0; + } + + item->d->x = xPos; + item->d->y = yPos; + + yPos += item->height(); + maxWidth = QMAX(maxWidth, d->mItemWidth); + } + + xPos += maxWidth; + resizeContents( xPos + cardSpacing, maxHeight ); + + // Update the height of all the separators now that we know the + // max height of a column + QPtrListIterator<CardViewSeparator> sepIter(d->mSeparatorList); + for (sepIter.toFirst(); sepIter.current(); ++sepIter) + { + (*sepIter)->mRect.setHeight(maxHeight - 2*cardSpacing - 2*d->mItemMargin); + } + + d->mLayoutDirty = false; +} + +CardViewItem *CardView::itemAfter(CardViewItem *item) +{ + /*int pos = */d->mItemList.findRef(item); + return d->mItemList.next();//at(pos+1); +} + +uint CardView::itemMargin() +{ + return d->mItemMargin; +} + +void CardView::setItemMargin( uint margin ) +{ + if ( margin == d->mItemMargin ) + return; + + d->mItemMargin = margin; + setLayoutDirty( true ); +} + +uint CardView::itemSpacing() +{ + return d->mItemSpacing; +} + +void CardView::setItemSpacing( uint spacing ) +{ + if ( spacing == d->mItemSpacing ) + return; + + d->mItemSpacing = spacing; + setLayoutDirty( true ); +} + +void CardView::contentsMousePressEvent(QMouseEvent *e) +{ + QScrollView::contentsMousePressEvent(e); + + QPoint pos = e->pos(); + d->mLastClickPos = pos; + + CardViewItem *item = itemAt(pos); + + if (item == 0) + { + d->mLastClickOnItem = false; + if ( d->mOnSeparator) + { + d->mResizeAnchor = e->x()+contentsX(); + d->colspace = (2*d->mItemSpacing) /*+ (2*d->mItemMargin)*/; + int ccw = d->mItemWidth + d->colspace + d->mSepWidth; + d->first = (contentsX()+d->mSepWidth)/ccw; + d->pressed = (d->mResizeAnchor+d->mSepWidth)/ccw; + d->span = d->pressed - d->first; + d->firstX = d->first * ccw; + if ( d->firstX ) d->firstX -= d->mSepWidth; // (no sep in col 0) + } + else + { + selectAll(false); + } + return; + } + + d->mLastClickOnItem = true; + + CardViewItem *other = d->mCurrentItem; + setCurrentItem( item ); + + // Always emit the selection + emit clicked(item); + + // Check the selection type and update accordingly + if (d->mSelectionMode == CardView::Single) + { + // make sure it isn't already selected + if (item->isSelected()) + return; + + bool b = signalsBlocked(); + blockSignals(true); + selectAll(false); + blockSignals(b); + + item->setSelected(true); + item->repaintCard(); + emit selectionChanged(item); + } + + else if (d->mSelectionMode == CardView::Multi) + { + // toggle the selection + item->setSelected(!item->isSelected()); + item->repaintCard(); + emit selectionChanged(); + } + + else if (d->mSelectionMode == CardView::Extended) + { + if ((e->button() & Qt::LeftButton) && + (e->state() & Qt::ShiftButton)) + { + if ( item == other ) return; + + bool s = ! item->isSelected(); + + if ( s && ! (e->state() & ControlButton) ) + { + bool b = signalsBlocked(); + blockSignals(true); + selectAll(false); + blockSignals(b); + } + + int from, to, a, b; + a = d->mItemList.findRef( item ); + b = d->mItemList.findRef( other ); + from = a < b ? a : b; + to = a > b ? a : b; + //kdDebug()<<"selecting items "<<from<<" - "<<to<<" ( "<<s<<" )"<<endl; + CardViewItem *aItem; + for ( ; from <= to; from++ ) + { + aItem = d->mItemList.at( from ); + aItem->setSelected( s ); + repaintItem( aItem ); + } + emit selectionChanged(); + } + else if ((e->button() & Qt::LeftButton) && + (e->state() & Qt::ControlButton)) + { + item->setSelected(!item->isSelected()); + item->repaintCard(); + emit selectionChanged(); + } + + else if (e->button() & Qt::LeftButton) + { + bool b = signalsBlocked(); + blockSignals(true); + selectAll(false); + blockSignals(b); + + item->setSelected(true); + item->repaintCard(); + emit selectionChanged(); + } + } + +} + +void CardView::contentsMouseReleaseEvent(QMouseEvent *e) +{ + QScrollView::contentsMouseReleaseEvent(e); + + if ( d->mResizeAnchor ) + { + // finish the resizing: + unsetCursor(); + // hide rubber bands + int newiw = d->mItemWidth - ((d->mResizeAnchor - d->mRubberBandAnchor)/d->span); + drawRubberBands( 0 ); + // we should move to reflect the new position if we are scrolled. + if ( contentsX() ) + { + int newX = QMAX( 0, ( d->pressed * ( newiw + d->colspace + d->mSepWidth ) ) - e->x() ); + setContentsPos( newX, contentsY() ); + } + // set new item width + setItemWidth( newiw ); + // reset anchors + d->mResizeAnchor = 0; + d->mRubberBandAnchor = 0; + return; + } + + // If there are accel keys, we will not emit signals + if ((e->state() & Qt::ShiftButton) || (e->state() & Qt::ControlButton)) + return; + + // Get the item at this position + CardViewItem *item = itemAt(e->pos()); + + if (item && KGlobalSettings::singleClick()) + { + emit executed(item); + } +} + +void CardView::contentsMouseDoubleClickEvent(QMouseEvent *e) +{ + QScrollView::contentsMouseDoubleClickEvent(e); + + CardViewItem *item = itemAt(e->pos()); + + if (item) + { + d->mCurrentItem = item; + } + + if (item && !KGlobalSettings::singleClick()) + { + emit executed(item); + } + emit doubleClicked(item); +} + +void CardView::contentsMouseMoveEvent( QMouseEvent *e ) +{ + // resizing + if ( d->mResizeAnchor ) + { + int x = e->x(); + if ( x != d->mRubberBandAnchor ) + drawRubberBands( x ); + return; + } + + if (d->mLastClickOnItem && (e->state() & Qt::LeftButton) && + ((e->pos() - d->mLastClickPos).manhattanLength() > 4)) { + + startDrag(); + return; + } + + d->mTimer->start( 500 ); + + // see if we are over a separator + // only if we actually have them painted? + if ( d->mDrawSeparators ) + { + int colcontentw = d->mItemWidth + (2*d->mItemSpacing); + int colw = colcontentw + d->mSepWidth; + int m = e->x()%colw; + if ( m >= colcontentw && m > 0 ) + { + setCursor( SplitVCursor ); // Why does this fail sometimes? + d->mOnSeparator = true; + } + else + { + setCursor( ArrowCursor ); + d->mOnSeparator = false; + } + } +} + +void CardView::enterEvent( QEvent * ) +{ + d->mTimer->start( 500 ); +} + +void CardView::leaveEvent( QEvent * ) +{ + d->mTimer->stop(); + if (d->mOnSeparator) + { + d->mOnSeparator = false; + setCursor( ArrowCursor ); + } +} + +void CardView::focusInEvent( QFocusEvent * ) +{ + if (!d->mCurrentItem && d->mItemList.count() ) + { + setCurrentItem( d->mItemList.first() ); + } + else if ( d->mCurrentItem ) + { + d->mCurrentItem->repaintCard(); + } +} + +void CardView::focusOutEvent( QFocusEvent * ) +{ + if (d->mCurrentItem) + d->mCurrentItem->repaintCard(); +} + +void CardView::keyPressEvent( QKeyEvent *e ) +{ + if ( ! ( childCount() && d->mCurrentItem ) ) + { + e->ignore(); + return; + } + + uint pos = d->mItemList.findRef( d->mCurrentItem ); + CardViewItem *aItem = 0L; // item that gets the focus + CardViewItem *old = d->mCurrentItem; + + switch ( e->key() ) + { + case Key_Up: + if ( pos > 0 ) + { + aItem = d->mItemList.at( pos - 1 ); + setCurrentItem( aItem ); + } + break; + case Key_Down: + if ( pos < d->mItemList.count() - 1 ) + { + aItem = d->mItemList.at( pos + 1 ); + setCurrentItem( aItem ); + } + break; + case Key_Left: + { + // look for an item in the previous/next column, starting from + // the vertical middle of the current item. + // FIXME use nice calculatd measures!!! + QPoint aPoint( d->mCurrentItem->d->x, d->mCurrentItem->d->y ); + aPoint -= QPoint( 30,-(d->mCurrentItem->height()/2) ); + aItem = itemAt( aPoint ); + // maybe we hit some space below an item + while ( !aItem && aPoint.y() > 27 ) + { + aPoint -= QPoint( 0, 16 ); + aItem = itemAt( aPoint ); + } + if ( aItem ) + setCurrentItem( aItem ); + } + break; + case Key_Right: + { + // FIXME use nice calculated measures!!! + QPoint aPoint( d->mCurrentItem->d->x + d->mItemWidth, d->mCurrentItem->d->y ); + aPoint += QPoint( 30,(d->mCurrentItem->height()/2) ); + aItem = itemAt( aPoint ); + while ( !aItem && aPoint.y() > 27 ) + { + aPoint -= QPoint( 0, 16 ); + aItem = itemAt( aPoint ); + } + if ( aItem ) + setCurrentItem( aItem ); + } + break; + case Key_Home: + aItem = d->mItemList.first(); + setCurrentItem( aItem ); + break; + case Key_End: + aItem = d->mItemList.last(); + setCurrentItem( aItem ); + break; + case Key_Prior: // PageUp + { + // QListView: "Make the item above the top visible and current" + // TODO if contentsY(), pick the top item of the leftmost visible column + if ( contentsX() <= 0 ) + return; + int cw = columnWidth(); + int theCol = ( QMAX( 0, ( contentsX()/cw) * cw ) ) + d->mItemSpacing; + aItem = itemAt( QPoint( theCol + 1, d->mItemSpacing + 1 ) ); + if ( aItem ) + setCurrentItem( aItem ); + } + break; + case Key_Next: // PageDown + { + // QListView: "Make the item below the bottom visible and current" + // find the first not fully visible column. + // TODO: consider if a partly visible (or even hidden) item at the + // bottom of the rightmost column exists + int cw = columnWidth(); + int theCol = ( (( contentsX() + visibleWidth() )/cw) * cw ) + d->mItemSpacing + 1; + // if separators are on, we may need to we may be one column further right if only the spacing/sep is hidden + if ( d->mDrawSeparators && cw - (( contentsX() + visibleWidth() )%cw) <= int( d->mItemSpacing + d->mSepWidth ) ) + theCol += cw; + + // make sure this is not too far right + while ( theCol > contentsWidth() ) + theCol -= columnWidth(); + + aItem = itemAt( QPoint( theCol, d->mItemSpacing + 1 ) ); + + if ( aItem ) + setCurrentItem( aItem ); + } + break; + case Key_Space: + setSelected( d->mCurrentItem, !d->mCurrentItem->isSelected() ); + emit selectionChanged(); + break; + case Key_Return: + case Key_Enter: + emit returnPressed( d->mCurrentItem ); + emit executed( d->mCurrentItem ); + break; + default: + if ( (e->state() & ControlButton) && e->key() == Key_A ) + { + // select all + selectAll( true ); + break; + } + // if we have a string, do autosearch + else if ( ! e->text().isEmpty() && e->text()[0].isPrint() ) + { + + } + break; + } + // handle selection + if ( aItem ) + { + if ( d->mSelectionMode == CardView::Extended ) + { + if ( (e->state() & ShiftButton) ) + { + // shift button: toggle range + // if control button is pressed, leave all items + // and toggle selection current->old current + // otherwise, ?????? + bool s = ! aItem->isSelected(); + int from, to, a, b; + a = d->mItemList.findRef( aItem ); + b = d->mItemList.findRef( old ); + from = a < b ? a : b; + to = a > b ? a : b; + + if ( to - from > 1 ) + { + bool b = signalsBlocked(); + blockSignals(true); + selectAll(false); + blockSignals(b); + } + + //kdDebug()<<"selecting items "<<from<<" - "<<to<<" ( "<<s<<" )"<<endl; + CardViewItem *item; + for ( ; from <= to; from++ ) + { + item = d->mItemList.at( from ); + item->setSelected( s ); + repaintItem( item ); + } + emit selectionChanged(); + } + else if ( (e->state() & ControlButton) ) + { + // control button: do nothing + } + else + { + // no button: move selection to this item + bool b = signalsBlocked(); + blockSignals(true); + selectAll(false); + blockSignals(b); + + setSelected( aItem, true ); + emit selectionChanged(); + } + } + } +} + +void CardView::contentsWheelEvent( QWheelEvent * e ) +{ + scrollBy(2*e->delta()/-3, 0); +} + +void CardView::setLayoutDirty(bool dirty) +{ + if (d->mLayoutDirty != dirty) + { + d->mLayoutDirty = dirty; + repaint(); + } +} + +void CardView::setDrawCardBorder(bool enabled) +{ + if (enabled != d->mDrawCardBorder) + { + d->mDrawCardBorder = enabled; + repaint(); + } +} + +bool CardView::drawCardBorder() const +{ + return d->mDrawCardBorder; +} + +void CardView::setDrawColSeparators(bool enabled) +{ + if (enabled != d->mDrawSeparators) + { + d->mDrawSeparators = enabled; + setLayoutDirty(true); + } +} + +bool CardView::drawColSeparators() const +{ + return d->mDrawSeparators; +} + +void CardView::setDrawFieldLabels(bool enabled) +{ + if (enabled != d->mDrawFieldLabels) + { + d->mDrawFieldLabels = enabled; + repaint(); + } +} + +bool CardView::drawFieldLabels() const +{ + return d->mDrawFieldLabels; +} + +void CardView::setShowEmptyFields(bool show) +{ + if (show != d->mShowEmptyFields) + { + d->mShowEmptyFields = show; + setLayoutDirty(true); + } +} + +bool CardView::showEmptyFields() const +{ + return d->mShowEmptyFields; +} + +void CardView::startDrag() +{ + // The default implementation is a no-op. It must be + // reimplemented in a subclass to be useful +} +void CardView::tryShowFullText() +{ + d->mTimer->stop(); + // if we have an item + QPoint cpos = viewportToContents( viewport()->mapFromGlobal( QCursor::pos() ) ); + CardViewItem *item = itemAt( cpos ); + if ( item ) + { + // query it for a value to display + //QString s = item ? item->caption() : "(no item)"; + //kdDebug()<<"MOUSE REST: "<<s<<endl; + QPoint ipos = cpos - itemRect( item ).topLeft(); + item->showFullString( ipos, d->mTip ); + } +} + +void CardView::drawRubberBands( int pos ) +{ + if ( pos && ((pos-d->firstX)/d->span) - d->colspace - d->mSepWidth < MIN_ITEM_WIDTH ) return; + + int tmpcw = (d->mRubberBandAnchor-d->firstX)/d->span; + int x = d->firstX + tmpcw - d->mSepWidth - contentsX(); + int h = visibleHeight(); + + QPainter p( viewport() ); + p.setRasterOp( XorROP ); + p.setPen( gray ); + p.setBrush( gray ); + uint n = d->first; + // erase + if ( d->mRubberBandAnchor ) + do { + p.drawRect( x, 0, 2, h ); + x += tmpcw; + n++; + } while ( x < visibleWidth() && n < d->mSeparatorList.count() ); + // paint new + if ( ! pos ) return; + tmpcw = (pos - d->firstX)/d->span; + n = d->first; + x = d->firstX + tmpcw - d->mSepWidth - contentsX(); + do { + p.drawRect( x, 0, 2, h ); + x += tmpcw; + n++; + } while ( x < visibleWidth() && n < d->mSeparatorList.count() ); + d->mRubberBandAnchor = pos; +} + + +int CardView::itemWidth() const +{ + return d->mItemWidth; +} + +void CardView::setItemWidth( int w ) +{ + if ( w == d->mItemWidth ) + return; + if ( w < MIN_ITEM_WIDTH ) + w = MIN_ITEM_WIDTH; + d->mItemWidth = w; + setLayoutDirty( true ); +#ifndef KAB_EMBEDDED + updateContents(); +#else //KAB_EMBEDDED +//US updateContents( d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight() ); +qDebug("CardView::setItemWidth has to be verified"); + updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() ); +#endif //KAB_EMBEDDED +} + +void CardView::setHeaderFont( const QFont &fnt ) +{ + d->mHeaderFont = fnt; + delete d->mBFm; + d->mBFm = new QFontMetrics( fnt ); +} + +QFont CardView::headerFont() const +{ + return d->mHeaderFont; +} + +void CardView::setFont( const QFont &fnt ) +{ + QScrollView::setFont( fnt ); + delete d->mFm; + d->mFm = new QFontMetrics( fnt ); +} + +int CardView::separatorWidth() +{ + return d->mSepWidth; +} + +void CardView::setSeparatorWidth( int width ) +{ + d->mSepWidth = width; + setLayoutDirty( true ); // hmm, actually I could just adjust the x'es... +} + +int CardView::maxFieldLines() const +{ + return d->mMaxFieldLines; +} + +void CardView::setMaxFieldLines( int howmany ) +{ + d->mMaxFieldLines = howmany ? howmany : INT_MAX; + // FIXME update, forcing the items to recalc height!! +} +//END Cardview + +#ifndef KAB_EMBEDDED +#include "cardview.moc" +#endif //KAB_EMBEDDED diff --git a/kaddressbook/views/cardview.desktop b/kaddressbook/views/cardview.desktop new file mode 100644 index 0000000..8507360 --- a/dev/null +++ b/kaddressbook/views/cardview.desktop @@ -0,0 +1,18 @@ +[Desktop Entry] +Encoding=UTF-8 +X-KDE-Library=libkaddrbk_cardview +Name=Card View +Name[be]=У выглядзе картак +Name[ca]=Vista de targeta +Name[da]=Kort-visning +Name[el]=Προβολή καρτών +Name[es]=Vista de tarjeta +Name[hu]=Kártyanézet +Name[pt_BR]=Visualização de Cartão +Name[ru]=Карточка +Name[sk]=Prezeranie karty +Name[sv]=Kortvy +Name[tr]=Kart Görünümü +Name[zh_CN]=卡片视图 +Type=Service +ServiceTypes=KAddressBook/View diff --git a/kaddressbook/views/cardview.h b/kaddressbook/views/cardview.h new file mode 100644 index 0000000..37dddb6 --- a/dev/null +++ b/kaddressbook/views/cardview.h @@ -0,0 +1,473 @@ +#ifndef CARDVIEW_H +#define CARDVIEW_H + +#include <qscrollview.h> +#include <qptrlist.h> +#include <qstring.h> +#include <qrect.h> +#include <qpair.h> +#include <qpoint.h> + +class QLabel; +class QPainter; +class QResizeEvent; +class QMouseEvent; +class CardView; +class CardViewPrivate; +class CardViewItemPrivate; +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, QString caption = QString::null); + 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 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); + + /** 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(); + + /** @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() { 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); + + 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(); + + /** 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); + + /** @return The bounding rect of the given item. + */ + QRect itemRect(const CardViewItem *item); + + /** 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(CardViewItem *item); + + /** @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. + */ +/*US + CardViewItem *findItem(const QString &text, const QString &label, + Qt::StringComparisonMode compare = Qt::BeginsWith); +*/ + + /** 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(); + + /** 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. + * @private Note: I looked for a value in QStyle::PixelMetric to use, but I could + * not see a usefull one. One may turn up in a future version of Qt. + */ + uint itemMargin(); + + /** 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. + * @private Note: There is no usefull QStyle::PixelMetric to use for this atm. + * An option would be using KDialog::spacingHint(). + */ + uint itemSpacing(); + + /** 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; + + /** @reimp */ + void setFont( const QFont &fnt ); + + /** Sets the column separator width */ + void setSeparatorWidth( int width ); + + /** @return the column separator width */ + int separatorWidth(); + + /** 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 * ); + + 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 *e); + + /** Changes the direction the canvas scolls. + */ + void contentsWheelEvent(QWheelEvent *e); + + /** 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 mousePressEvent(QMouseEvent *e); +// virtual void mouseReleaseEvent(QMouseEvent *e); +// virtual void mouseMoveEvent(QMouseEvent *e); + + virtual void contentsMousePressEvent(QMouseEvent *e); + virtual void contentsMouseMoveEvent(QMouseEvent *e); + virtual void contentsMouseReleaseEvent(QMouseEvent *e); + virtual void contentsMouseDoubleClickEvent(QMouseEvent *e); + + 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 0000000..c243fa0 --- a/dev/null +++ b/kaddressbook/views/colorlistbox.cpp @@ -0,0 +1,230 @@ +/* + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <qpainter.h> + +#include <kcolordialog.h> + +#ifndef KAB_EMBEDDED +#include <kcolordrag.h> +#endif //KAB_EMBEDDED + +#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 ); +#ifndef KAB_EMBEDDED + if( KColorDialog::getColor( c, this ) != QDialog::Rejected ) + { + setColor( index, c ); + } +#else //KAB_EMBEDDED + KColorDialog* k = new KColorDialog( this ); + k->setColor( c ); + int res = k->exec(); + if ( res ) { + setColor( index, k->getColor() ); + } + delete k; +#endif //KAB_EMBEDDED + + } +} + + +void ColorListBox::dragEnterEvent( QDragEnterEvent *e ) +{ +#ifndef KAB_EMBEDDED + if( KColorDrag::canDecode(e) && isEnabled() ) + { + mCurrentOnDragEnter = currentItem(); + e->accept( true ); + } + else + { + mCurrentOnDragEnter = -1; + e->accept( false ); + } +#else //KAB_EMBEDDED +qDebug("ColorListBox::dragEnterEvent drag&drop currently not supported"); +#endif //KAB_EMBEDDED + +} + + +void ColorListBox::dragLeaveEvent( QDragLeaveEvent * ) +{ +#ifndef KAB_EMBEDDED + + if( mCurrentOnDragEnter != -1 ) + { + setCurrentItem( mCurrentOnDragEnter ); + mCurrentOnDragEnter = -1; + } +#else //KAB_EMBEDDED +qDebug("ColorListBox::dragLeaveEvent drag&drop currently not supported"); +#endif //KAB_EMBEDDED +} + + +void ColorListBox::dragMoveEvent( QDragMoveEvent *e ) +{ +#ifndef KAB_EMBEDDED + if( KColorDrag::canDecode(e) && isEnabled() ) + { + ColorListItem *item = (ColorListItem*)itemAt( e->pos() ); + if( item != 0 ) + { + setCurrentItem ( item ); + } + } +#else //KAB_EMBEDDED +qDebug("ColorListBox::dragMoveEvent drag&drop currently not supported"); +#endif //KAB_EMBEDDED + +} + + +void ColorListBox::dropEvent( QDropEvent *e ) +{ +#ifndef KAB_EMBEDDED + 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; + } + +#else //KAB_EMBEDDED +qDebug("ColorListBox::dropEvent drag&drop currently not supported"); +#endif //KAB_EMBEDDED + +} + + + +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 ); +} + +#ifndef KAB_EMBEDDED +#include "colorlistbox.moc" +#endif //KAB_EMBEDDED diff --git a/kaddressbook/views/colorlistbox.h b/kaddressbook/views/colorlistbox.h new file mode 100644 index 0000000..4a0e705 --- a/dev/null +++ b/kaddressbook/views/colorlistbox.h @@ -0,0 +1,76 @@ +/* + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _COLOR_LISTBOX_H_ +#define _COLOR_LISTBOX_H_ + +#include <klistbox.h> + +class QDragEnterEvent; +class QDragLeaveEvent; +class QDragMoveEvent; +class QDropEvent; + +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 0000000..d518cf7 --- a/dev/null +++ b/kaddressbook/views/configurecardviewdialog.cpp @@ -0,0 +1,364 @@ +/* + This file is part of KAddressBook. + Copyright (c) 2002 Mike Pilone <mpilone@slac.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#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> + +#ifndef KAB_EMBEDDED +#include <kpushbutton.h> +#else //KAB_EMBEDDED +#include <qpushbutton.h> +#endif //KAB_EMBEDDED + +#include "colorlistbox.h" + +#include "configurecardviewdialog.h" + +///////////////////////////////// +// ConfigureCardViewDialog + +ConfigureCardViewWidget::ConfigureCardViewWidget( KABC::AddressBook *ab, QWidget *parent, + const char *name ) + : ViewConfigureWidget( ab, parent, name ) +{ +#ifndef KAB_EMBEDDED + QWidget *page = addPage( i18n( "Look & Feel" ), QString::null, + DesktopIcon( "looknfeel" ) ); +#else //KAB_EMBEDDED + QWidget *page = addPage( i18n( "Look & Feel" ), QString::null, + KGlobal::iconLoader()->loadIcon( "looknfeel", + KIcon::Panel ) ); +#endif //KAB_EMBEDDED + + 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; +qDebug("CardViewLookNFeelPage::restoreSettings make base color configurable"); + +#ifndef KAB_EMBEDDED + c = KGlobalSettings::baseColor(); +#else //KAB_EMBEDDED + c = QColor(0,0,0); +#endif //KAB_EMBEDDED + + 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 and 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() ); +#ifndef KAB_EMBEDDED + if ( KFontDialog::getFont( f, false, this ) == QDialog::Accepted ) + updateFontLabel( f, lTextFont ); +#else //KAB_EMBEDDED + bool ok; + QFont fout = KFontDialog::getFont( f, ok); + if ( ok ) + updateFontLabel( fout, lTextFont ); +#endif //KAB_EMBEDDED +} + +void CardViewLookNFeelPage::setHeaderFont() +{ + QFont f( lHeaderFont->font() ); +#ifndef KAB_EMBEDDED + if ( KFontDialog::getFont( f,false, this ) == QDialog::Accepted ) + updateFontLabel( f, lHeaderFont ); +#else //KAB_EMBEDDED + bool ok; + QFont fout = KFontDialog::getFont( f, ok); + if ( ok ) + updateFontLabel( fout, lHeaderFont ); +#endif //KAB_EMBEDDED +} + +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 are 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 ); +#ifndef KAB_EMBEDDED + btnFont = new KPushButton( i18n("Choose..."), vbFonts ); +#else //KAB_EMBEDDED + btnFont = new QPushButton( i18n("Choose..."), vbFonts ); +#endif //KAB_EMBEDDED + + 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 ); +#ifndef KAB_EMBEDDED + btnHeaderFont = new KPushButton( i18n("Choose..."), vbFonts ); +#else //KAB_EMBEDDED + btnHeaderFont = new QPushButton( i18n("Choose..."), vbFonts ); +#endif //KAB_EMBEDDED + 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() ) ); +} + +#ifndef KAB_EMBEDDED +#include "configurecardviewdialog.moc" +#endif //KAB_EMBEDDED diff --git a/kaddressbook/views/configurecardviewdialog.h b/kaddressbook/views/configurecardviewdialog.h new file mode 100644 index 0000000..7a62226 --- a/dev/null +++ b/kaddressbook/views/configurecardviewdialog.h @@ -0,0 +1,117 @@ +/* + This file is part of KAddressBook. + Copyright (c) 2002 Mike Pilone <mpilone@slac.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#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; +#ifndef KAB_EMBEDDED + class KPushButton *btnFont, *btnHeaderFont; +#else //KAB_EMBEDDED + class QPushButton *btnFont, *btnHeaderFont; +#endif //KAB_EMBEDDED + 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 0000000..e1cc63e --- a/dev/null +++ b/kaddressbook/views/configuretableviewdialog.cpp @@ -0,0 +1,155 @@ +/* + This file is part of KAddressBook. + Copyright (c) 2002 Mike Pilone <mpilone@slac.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qstring.h> +#include <qwidget.h> +#include <qlayout.h> +#include <qradiobutton.h> +#include <qcheckbox.h> +#include <qvbox.h> +#include <qbuttongroup.h> + +#include <kglobal.h> +#include <klocale.h> +#include <klineedit.h> +#include <kurlrequester.h> +#include <kiconloader.h> + +#ifndef KAB_EMBEDDED +#include <kimageio.h> +#else //KAB_EMBEDDED +#endif //KAB_EMBEDDED + +#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->readEntry("BackgroundName")); +} + +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->writeEntry("BackgroundName", mBackgroundName->lineEdit()->text()); +} + +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"); +#ifndef KAB_EMBEDDED + mBackgroundName->setMode(KFile::File | KFile::ExistingOnly | + KFile::LocalOnly); + mBackgroundName->setFilter(KImageIO::pattern(KImageIO::Reading)); +#endif //KAB_EMBEDDED + + backgroundLayout->addWidget(mBackgroundName); + + // ToolTip Checkbox + mToolTipBox = new QCheckBox(i18n("Enable contact tooltips"), this, + "mToolTipBox"); + layout->addWidget(mToolTipBox); +} + +void LookAndFeelPage::enableBackgroundToggled(bool enabled) +{ + mBackgroundName->setEnabled(enabled); +} + +#ifndef KAB_EMBEDDED +#include "configuretableviewdialog.moc" +#endif //KAB_EMBEDDED diff --git a/kaddressbook/views/configuretableviewdialog.h b/kaddressbook/views/configuretableviewdialog.h new file mode 100644 index 0000000..8392710 --- a/dev/null +++ b/kaddressbook/views/configuretableviewdialog.h @@ -0,0 +1,88 @@ +/* + This file is part of KAddressBook. + Copyright (c) 2002 Mike Pilone <mpilone@slac.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#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; +}; + +#endif diff --git a/kaddressbook/views/contactlistview.cpp b/kaddressbook/views/contactlistview.cpp new file mode 100644 index 0000000..98b2fb2 --- a/dev/null +++ b/kaddressbook/views/contactlistview.cpp @@ -0,0 +1,340 @@ +/* + This file is part of KAddressBook. + Copyright (c) 2002 Mike Pilone <mpilone@slac.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#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 <kiconloader.h> +#include <kdebug.h> +#include <kconfig.h> +#include <kapplication.h> +#include <kurl.h> + +#include "kaddressbooktableview.h" + +#include "contactlistview.h" + +///////////////////////////////// +// DynamicTip Methods + +DynamicTip::DynamicTip( ContactListView *parent) + : QToolTip( parent ) +{ +} + +void DynamicTip::maybeTip( const QPoint &pos ) +{ + static bool ishidden = true; + 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; + +#ifndef KAB_EMBEDDED + ContactListViewItem *plvi = dynamic_cast< ContactListViewItem* >(lvi); +#else //KAB_EMBEDDED + ContactListViewItem *plvi = (ContactListViewItem*)(lvi); +#endif //KAB_EMBEDDED + + if (!plvi) + return; + + if (ishidden) { + QString s; + QRect r = plv->itemRect( lvi ); + r.moveBy( posVp.x(), posVp.y() ); + + //kdDebug() << "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 ); + } + else + hide(); + ishidden = !ishidden; + +} + +/////////////////////////// +// ContactListViewItem Methods + +ContactListViewItem::ContactListViewItem(const KABC::Addressee &a, + ContactListView *parent, + KABC::AddressBook *doc, + const KABC::Field::List &fields ) + : KListViewItem(parent), mAddressee(a), mFields( fields ), + parentListView( parent ), mDocument(doc) +{ + refresh(); +} + +QString ContactListViewItem::key(int column, bool ascending) const +{ + return QListViewItem::key(column, ascending).lower(); +} + +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; + KABC::Field::List::ConstIterator it; + for( it = mFields.begin(); it != mFields.end(); ++it ) { + setText( i++, (*it)->value( mAddressee ) ); + } +} + +/////////////////////////////// +// 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; +#ifndef KAB_EMBEDDED + mAlternateColor = KGlobalSettings::alternateBackgroundColor(); +#else //KAB_EMBEDDED + mAlternateColor = QColor(240, 240, 240); +#endif //KAB_EMBEDDED + + setAlternateBackgroundEnabled(mABackground); + setAcceptDrops( true ); + viewport()->setAcceptDrops( true ); + setAllColumnsShowFocus( true ); + setShowSortIndicator(true); + + setSelectionModeExt( KListView::Extended ); + setDropVisualizer(false); + // setFrameStyle(QFrame::NoFrame); + setLineWidth ( 0 ); + setMidLineWidth ( 0 ); + setMargin ( 0 ); +#ifndef KAB_EMBEDDED + connect(this, SIGNAL(dropped(QDropEvent*)), + this, SLOT(itemDropped(QDropEvent*))); +#endif //KAB_EMBEDDED + + + 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 +{ +#ifndef KAB_EMBEDDED + return QTextDrag::canDecode(e); +#else //KAB_EMBEDDED +qDebug("ContactListView::acceptDrag has to be fixed"); + return false; +#endif //KAB_EMBEDDED +} + +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 + { + qDebug("ContactListView::setBackgroundPixmap has to be verified"); +//US setPaletteBackgroundPixmap(QPixmap(filename)); + KListView::setBackgroundPixmap((const QPixmap&)QPixmap(filename)); + } + +} +#ifndef KAB_EMBEDDED +#include "contactlistview.moc" +#endif //KAB_EMBEDDED diff --git a/kaddressbook/views/contactlistview.h b/kaddressbook/views/contactlistview.h new file mode 100644 index 0000000..ae9c994 --- a/dev/null +++ b/kaddressbook/views/contactlistview.h @@ -0,0 +1,128 @@ +#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> +#include <kabc/addressee.h> +#include <kabc/addressbook.h> + + +class QDropEvent; +class KAddressBookTableView; +class ContactListView; + +/** 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 ); + const KABC::Addressee &addressee() const { return mAddressee; } + virtual void refresh(); + virtual ContactListView* parent(); + virtual QString key ( int, bool ) const; + + /** 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; +}; + + +///////////////////////////////////////////// +// 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); + +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; + + QColor mAlternateColor; + + QPoint presspos; +}; + + +#endif diff --git a/kaddressbook/views/kaddressbookcardview.cpp b/kaddressbook/views/kaddressbookcardview.cpp new file mode 100644 index 0000000..239429f --- a/dev/null +++ b/kaddressbook/views/kaddressbookcardview.cpp @@ -0,0 +1,394 @@ +/* + This file is part of KAddressBook. + Copyright (c) 2002 Mike Pilone <mpilone@slac.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#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 "kabprefs.h" +#include "viewmanager.h" + +#include "kaddressbookcardview.h" + +#ifndef KAB_EMBEDDED +extern "C" { + void *init_libkaddrbk_cardview() + { + return ( new CardViewFactory ); + } +} +#endif //KAB_EMBEDDED + +//////////////////////////////// +// AddresseeCardViewItem (internal class) +class AddresseeCardViewItem : public CardViewItem +{ + public: + AddresseeCardViewItem(const KABC::Field::List &fields, + bool showEmptyFields, + KABC::AddressBook *doc, const KABC::Addressee &a, + CardView *parent) + : CardViewItem(parent, a.formattedName()), + mFields( fields ), mShowEmptyFields(showEmptyFields), + mDocument(doc), mAddressee(a) + { + if ( mFields.isEmpty() ) { + mFields = KABC::Field::defaultFields(); + } + refresh(); + } + + const KABC::Addressee &addressee() const { return mAddressee; } + + void refresh() + { + // Update our addressee, since it may have changed elsewhere + mAddressee = mDocument->findByUid(mAddressee.uid()); + + if (!mAddressee.isEmpty()) + { + clearFields(); + + // Try all the selected fields until we find one with text. + // This will limit the number of unlabeled icons in the view + KABC::Field::List::Iterator iter; + for (iter = mFields.begin(); iter != mFields.end(); ++iter) + { + // 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 || !(*iter)->value( mAddressee ).isEmpty()) + insertField((*iter)->label(), (*iter)->value( mAddressee )); + } + + // We might want to make this the first field. hmm... -mpilone + setCaption( mAddressee.realName() ); + } + } + + private: + KABC::Field::List mFields; + bool mShowEmptyFields; + KABC::AddressBook *mDocument; + KABC::Addressee mAddressee; +}; + +/////////////////////////////// +// AddresseeCardView + +AddresseeCardView::AddresseeCardView(QWidget *parent, const char *name) + : CardView(parent, name) +{ + setAcceptDrops(true); +} + +AddresseeCardView::~AddresseeCardView() +{ +} + +void AddresseeCardView::dragEnterEvent(QDragEnterEvent *e) +{ +#ifndef KAB_EMBEDDED + if (QTextDrag::canDecode(e)) + e->accept(); +#else //KAB_EMBEDDED +qDebug("AddresseeCardView::dragEnterEvent drag&drop is not implemented"); +#endif //KAB_EMBEDDED +} + +void AddresseeCardView::dropEvent(QDropEvent *e) +{ + emit addresseeDropped(e); +} + +void AddresseeCardView::startDrag() +{ + emit startAddresseeDrag(); +} + + +/////////////////////////////// +// KAddressBookCardView + +KAddressBookCardView::KAddressBookCardView( KABC::AddressBook *ab, + QWidget *parent, const char *name ) + : KAddressBookView( ab, parent, name ) +{ + mShowEmptyFields = false; + + // Init the GUI + 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())); +} + +KAddressBookCardView::~KAddressBookCardView() +{ +} + +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()->mHonorSingleClick) + 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()) + { +#ifndef KAB_EMBEDDED + aItem = dynamic_cast<AddresseeCardViewItem*>(item); +#else //KAB_EMBEDDED + aItem = (AddresseeCardViewItem*)(item); +#endif //KAB_EMBEDDED + if (aItem) + uidList << aItem->addressee().uid(); + } + } + + return uidList; +} + +void KAddressBookCardView::refresh(QString uid) +{ + CardViewItem *item; + AddresseeCardViewItem *aItem; + + if (uid.isNull()) + { + // Rebuild the view + mCardView->viewport()->setUpdatesEnabled( false ); + mCardView->clear(); + + KABC::Addressee::List addresseeList = addressees(); + KABC::Addressee::List::Iterator iter; + for (iter = addresseeList.begin(); iter != addresseeList.end(); ++iter) + { + aItem = new AddresseeCardViewItem(fields(), mShowEmptyFields, + addressBook(), *iter, 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()) + { +#ifndef KAB_EMBEDDED + aItem = dynamic_cast<AddresseeCardViewItem*>(item); +#else //KAB_EMBEDDED + aItem = (AddresseeCardViewItem*)(item); +#endif //KAB_EMBEDDED + + if ((aItem) && (aItem->addressee().uid() == uid)) + { + aItem->refresh(); + found = true; + } + } + } +} + +void KAddressBookCardView::setSelected(QString uid, bool selected) +{ + CardViewItem *item; + AddresseeCardViewItem *aItem; + + if (uid.isNull()) + { + mCardView->selectAll(selected); + } + else + { + bool found = false; + for (item = mCardView->firstItem(); item && !found; + item = item->nextItem()) + { +#ifndef KAB_EMBEDDED + aItem = dynamic_cast<AddresseeCardViewItem*>(item); +#else //KAB_EMBEDDED + aItem = (AddresseeCardViewItem*)(item); +#endif //KAB_EMBEDDED + + if ((aItem) && (aItem->addressee().uid() == uid)) + { + mCardView->setSelected(aItem, selected); + mCardView->ensureItemVisible(item); + found = true; + } + } + } +} + +//US added an additional method without parameter +void KAddressBookCardView::setSelected() +{ + setSelected(QString::null, true); +} + +void KAddressBookCardView::addresseeExecuted(CardViewItem *item) +{ +#ifndef KAB_EMBEDDED + AddresseeCardViewItem *aItem = dynamic_cast<AddresseeCardViewItem*>(item); +#else //KAB_EMBEDDED + AddresseeCardViewItem *aItem = (AddresseeCardViewItem*)(item); +#endif //KAB_EMBEDDED + if (aItem) + { + //kdDebug()<<"... even has a valid item:)"<<endl; + 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()) + { +#ifndef KAB_EMBEDDED + aItem = dynamic_cast<AddresseeCardViewItem*>(item); +#else //KAB_EMBEDDED + aItem = (AddresseeCardViewItem*)(item); +#endif //KAB_EMBEDDED + if ( aItem ) + { + emit selected(aItem->addressee().uid()); + found = true; + } + } + } + + if (!found) + emit selected(QString::null); + +} +#ifndef KAB_EMBEDDED +#include "kaddressbookcardview.moc" +#endif //KAB_EMBEDDED diff --git a/kaddressbook/views/kaddressbookcardview.h b/kaddressbook/views/kaddressbookcardview.h new file mode 100644 index 0000000..cd70371 --- a/dev/null +++ b/kaddressbook/views/kaddressbookcardview.h @@ -0,0 +1,117 @@ +#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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qstring.h> +#ifndef KAB_EMBEDDED +#include <kiconview.h> +#else //KAB_EMBEDDED +#include <klocale.h> +#endif //KAB_EMBEDDED + +#include "cardview.h" +#include "kaddressbookview.h" +#include "configurecardviewdialog.h" + +class QDragEnterEvent; +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( KABC::AddressBook *ab, QWidget *parent, + const char *name = 0 ); + virtual ~KAddressBookCardView(); + + virtual QStringList selectedUids(); + virtual QString type() const { return "Card"; } + + virtual void readConfig(KConfig *config); + virtual void writeConfig(KConfig *); + + public slots: + void refresh(QString uid = QString::null); + void setSelected(QString uid/*US = QString::null*/, bool selected/*US = true*/); +//US added an additional method without parameter + void setSelected(); + + protected slots: + void addresseeExecuted(CardViewItem *item); + void addresseeSelected(); + + 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(); +}; + + +class CardViewFactory : public ViewFactory +{ + public: + KAddressBookView *view( KABC::AddressBook *ab, QWidget *parent, const char *name ) + { + return new KAddressBookCardView( ab, parent, name ); + } + + QString type() const { return "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 ); + } +}; + + +#endif diff --git a/kaddressbook/views/kaddressbookiconview.cpp b/kaddressbook/views/kaddressbookiconview.cpp new file mode 100644 index 0000000..50ff285 --- a/dev/null +++ b/kaddressbook/views/kaddressbookiconview.cpp @@ -0,0 +1,378 @@ +/* + This file is part of KAddressBook. + Copyright (c) 2002 Mike Pilone <mpilone@slac.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef KAB_EMBEDDED +#include <qiconview.h> +#include <qstringlist.h> + +#include <kabc/addressee.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <klocale.h> + +#else //KAB_EMBEDDED +#endif //KAB_EMBEDDED + +#include <kabc/addressbook.h> +#include "kabprefs.h" +#include "viewmanager.h" +#include "kaddressbookiconview.h" +#include <qlayout.h> +#include <kglobal.h> +/*US transfered to the headerfile +class IconViewFactory : public ViewFactory +{ + public: + KAddressBookView *view( KABC::AddressBook *ab, QWidget *parent, const char *name ) + { + return new KAddressBookIconView( ab, parent, name ); + } + + QString type() const { return "Icon"; } + + QString description() const { return i18n( "Icons represent contacts. Very simple view." ); } +}; + +*/ + +extern "C" { + void *init_libkaddrbk_iconview() + { + return ( new IconViewFactory ); + } +} + +//////////////////////////////// +// AddresseeIconView (internal class) +#ifndef KAB_EMBEDDED +AddresseeIconView::AddresseeIconView(QWidget *parent, const char *name) + : KIconView(parent, name) +#else //KAB_EMBEDDED +AddresseeIconView::AddresseeIconView(QWidget *parent, const char *name) + : QIconView(parent, name) +#endif //KAB_EMBEDDED + +{ + setSelectionMode( QIconView::Extended ); + setResizeMode( QIconView::Adjust ); + setWordWrapIconText( true ); + setGridX( 100 ); + setItemsMovable(false); + setSorting(true, true); + + +//US ??? setMode( KIconView::Select ); + +#ifndef KAB_EMBEDDED + + connect(this, SIGNAL(dropped(QDropEvent*, const QValueList<QIconDragItem>&)), + this, SLOT(itemDropped(QDropEvent*, const QValueList<QIconDragItem>&))); +#endif //KAB_EMBEDDED +} + +AddresseeIconView::~AddresseeIconView() +{ +} + +void AddresseeIconView::itemDropped(QDropEvent *e, + const QValueList<QIconDragItem> &) +{ + emit addresseeDropped(e); +} + +QDragObject *AddresseeIconView::dragObject() +{ + emit startAddresseeDrag(); + + // We never want IconView to start the drag + return 0; +} +//////////////////////////////// +// AddresseeIconViewItem (internal class) +#ifndef KAB_EMBEDDED +class AddresseeIconViewItem : public KIconViewItem +#else //KAB_EMBEDDED +class AddresseeIconViewItem : public QIconViewItem +#endif //KAB_EMBEDDED +{ + public: +#ifndef KAB_EMBEDDED + AddresseeIconViewItem(const KABC::Field::List &fields, + KABC::AddressBook *doc, const KABC::Addressee &a, + QIconView *parent) + : KIconViewItem(parent), mFields( fields ), mDocument(doc), mAddressee(a) +#else //KAB_EMBEDDED + AddresseeIconViewItem(const KABC::Field::List &fields, + KABC::AddressBook *doc, const KABC::Addressee &a, + QIconView *parent) + : QIconViewItem(parent), mFields( fields ), mDocument(doc), mAddressee(a) +#endif //KAB_EMBEDDED + { + if ( mFields.isEmpty() ) { + mFields = KABC::Field::defaultFields(); + } + refresh(); + } + + const KABC::Addressee &addressee() const { return mAddressee; } + + void refresh() + { + // Update our addressee, since it may have changed elsewhere + mAddressee = mDocument->findByUid(mAddressee.uid()); + + if (!mAddressee.isEmpty()) + setText( mAddressee.givenName() + " " + mAddressee.familyName() ); + + QPixmap icon; + QPixmap defaultIcon( KGlobal::iconLoader()->loadIcon( "vcard", KIcon::Desktop, 128 ) ); + KABC::Picture pic = mAddressee.photo(); + if ( pic.data().isNull() ) + pic = mAddressee.logo(); + + if ( pic.isIntern() && !pic.data().isNull() ) { + QImage img = pic.data(); +#ifndef KAB_EMBEDDED + if ( img.width() > img.height() ) + icon = img.scaleWidth( 32 ); + else + icon = img.scaleHeight( 32 ); +#else //KAB_EMBEDDED + qDebug("AddresseeIconViewItem::refresh - scale here dependend of the displaysize and the right factor"); + icon.convertFromImage(img.smoothScale(32, 32)); +#endif //KAB_EMBEDDED + + } else + icon = defaultIcon; + + setPixmap( icon ); + } + + private: + KABC::Field::List mFields; + KABC::AddressBook *mDocument; + KABC::Addressee mAddressee; +}; + +/////////////////////////////// +// KAddressBookView + +KAddressBookIconView::KAddressBookIconView( KABC::AddressBook *ab, + QWidget *parent, const char *name) + : KAddressBookView( ab, parent, name ) +{ + // Init the GUI + QVBoxLayout *layout = new QVBoxLayout(viewWidget()); + + mIconView = new AddresseeIconView(viewWidget(), "mIconView"); + layout->addWidget(mIconView); + + // Connect up the signals + +//US method executed is part of KIconView +//US connect(mIconView, SIGNAL(executed(QIconViewItem *)), +//US this, SLOT(addresseeExecuted(QIconViewItem *))); + connect(mIconView, SIGNAL(selectionChanged(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())); +} + +KAddressBookIconView::~KAddressBookIconView() +{ +} + +void KAddressBookIconView::readConfig(KConfig *config) +{ + KAddressBookView::readConfig(config); + +//US method executed is part of KIconView +//US disconnect(mIconView, SIGNAL(executed(QIconViewItem *)), +//US this, SLOT(addresseeExecuted(QIconViewItem *))); + disconnect(mIconView, SIGNAL(selectionChanged(QIconViewItem *)), + this, SLOT(addresseeExecuted(QIconViewItem *))); + +//US method executed is part of KIconView. Use selectionChanged instead +/*US + if (KABPrefs::instance()->mHonorSingleClick) + connect(mIconView, SIGNAL(executed(QIconViewItem *)), + this, SLOT(addresseeExecuted(QIconViewItem *))); + else + connect(mIconView, SIGNAL(doubleClicked(QIconViewItem *)), + this, SLOT(addresseeExecuted(QIconViewItem *))); +*/ + connect(mIconView, SIGNAL(selectionChanged(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()) + { +#ifndef KAB_EMBEDDED + aItem = dynamic_cast<AddresseeIconViewItem*>(item); +#else //KAB_EMBEDDED + aItem = (AddresseeIconViewItem*)(item); +#endif //KAB_EMBEDDED + if (aItem) + uidList << aItem->addressee().uid(); + } + } + + return uidList; +} + +void KAddressBookIconView::refresh(QString uid) +{ + QIconViewItem *item; + AddresseeIconViewItem *aItem; + + if ( uid.isNull() ) { + // Rebuild the view + mIconView->clear(); + mIconList.clear(); + + KABC::Addressee::List addresseeList = addressees(); + KABC::Addressee::List::Iterator iter; + for ( iter = addresseeList.begin(); iter != addresseeList.end(); ++iter ) + aItem = new AddresseeIconViewItem( fields(), addressBook(), *iter, mIconView ); + + mIconView->arrangeItemsInGrid( true ); + + for ( item = mIconView->firstItem(); item; item = item->nextItem() ) + { +#ifndef KAB_EMBEDDED + AddresseeIconViewItem* aivi = dynamic_cast<AddresseeIconViewItem*>( item ); +#else //KAB_EMBEDDED + AddresseeIconViewItem* aivi = (AddresseeIconViewItem*)( item ); +#endif //KAB_EMBEDDED + mIconList.append( aivi ); + } + + } else { + // Try to find the one to refresh + for ( item = mIconView->firstItem(); item; item = item->nextItem() ) { +#ifndef KAB_EMBEDDED + aItem = dynamic_cast<AddresseeIconViewItem*>(item); +#else //KAB_EMBEDDED + aItem = (AddresseeIconViewItem*)(item); +#endif //KAB_EMBEDDED + if ((aItem) && (aItem->addressee().uid() == uid)) { + aItem->refresh(); + mIconView->arrangeItemsInGrid( true ); + return; + } + } + refresh( QString::null ); + } +} + +void KAddressBookIconView::setSelected(QString uid, bool selected) +{ + QIconViewItem *item; + AddresseeIconViewItem *aItem; + + if (uid.isNull()) + { + mIconView->selectAll(selected); + } + else + { + bool found = false; + for (item = mIconView->firstItem(); item && !found; + item = item->nextItem()) + { +#ifndef KAB_EMBEDDED + aItem = dynamic_cast<AddresseeIconViewItem*>(item); +#else //KAB_EMBEDDED + aItem = (AddresseeIconViewItem*)(item); +#endif //KAB_EMBEDDED + + if ((aItem) && (aItem->addressee().uid() == uid)) + { + mIconView->setSelected(aItem, selected); + mIconView->ensureItemVisible( aItem ); + found = true; + } + } + } +} + +void KAddressBookIconView::addresseeExecuted(QIconViewItem *item) +{ +#ifndef KAB_EMBEDDED + AddresseeIconViewItem *aItem = dynamic_cast<AddresseeIconViewItem*>(item); +#else //KAB_EMBEDDED + AddresseeIconViewItem *aItem = (AddresseeIconViewItem*)(item); +#endif //KAB_EMBEDDED + + 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()) + { +#ifndef KAB_EMBEDDED + aItem = dynamic_cast<AddresseeIconViewItem*>(item); +#else //KAB_EMBEDDED + aItem = (AddresseeIconViewItem*)(item); +#endif //KAB_EMBEDDED + if (aItem) + { + emit selected(aItem->addressee().uid()); + found = true; + } + } + } + + if (!found) + emit selected(QString::null); +} + +#ifndef KAB_EMBEDDED +#include "kaddressbookiconview.moc" +#endif //KAB_EMBEDDED diff --git a/kaddressbook/views/kaddressbookiconview.h b/kaddressbook/views/kaddressbookiconview.h new file mode 100644 index 0000000..3afada3 --- a/dev/null +++ b/kaddressbook/views/kaddressbookiconview.h @@ -0,0 +1,130 @@ +/* + This file is part of KAddressBook. + Copyright (c) 2002 Mike Pilone <mpilone@slac.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef KADDRESSBOOKICONVIEW_H +#define KADDRESSBOOKICONVIEW_H + +#include <qstring.h> +#ifndef KAB_EMBEDDED +#include <kiconview.h> +#else //KAB_EMBEDDED +#include <qiconview.h> +#include <qptrlist.h> +#include <klocale.h> +#endif //KAB_EMBEDDED +#include "kaddressbookview.h" + +class QIconViewItem; +class KConfig; +class AddresseeIconView; +class AddresseeIconViewItem; +class QIconDragItem; +class KAddressBookIconView; + +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( KABC::AddressBook *ab, QWidget *parent, + const char *name = 0 ); + virtual ~KAddressBookIconView(); + + virtual QStringList selectedUids(); + virtual QString type() const { return "Icon"; } + + virtual void readConfig(KConfig *config); + + public slots: + void refresh(QString uid = QString::null); +#ifndef KAB_EMBEDDED +//MOC_SKIP_BEGIN + void setSelected(QString uid = QString::null, bool selected = true); +//MOC_SKIP_END +#else //KAB_EMBEDDED +//US my MOC do not like default parameters ??? + void setSelected(QString uid, bool selected); +#endif //KAB_EMBEDDED + + protected slots: + void addresseeExecuted(QIconViewItem *item); + void addresseeSelected(); + + private: + AddresseeIconView *mIconView; + QPtrList<AddresseeIconViewItem> mIconList; +}; + + +#ifndef KAB_EMBEDDED +//MOC_SKIP_BEGIN +class AddresseeIconView : public KIconView +//MOC_SKIP_END +#else //KAB_EMBEDDED +class AddresseeIconView : public QIconView +#endif //KAB_EMBEDDED +{ + Q_OBJECT + + public: + AddresseeIconView(QWidget *parent, const char *name); + ~AddresseeIconView(); + + signals: + void addresseeDropped(QDropEvent *); + void startAddresseeDrag(); + + protected: + virtual QDragObject *dragObject(); + + protected slots: + void itemDropped(QDropEvent *, const QValueList<QIconDragItem> &); +}; + +class IconViewFactory : public ViewFactory +{ + public: + KAddressBookView *view( KABC::AddressBook *ab, QWidget *parent, const char *name ) + { + return new KAddressBookIconView( ab, parent, name ); + } + + QString type() const { return "Icon"; } + + QString description() const { return i18n( "Icons represent contacts. Very simple view." ); } +}; +/* +extern "C" { + void *init_libkaddrbk_iconview() + { + return ( new IconViewFactory ); + } +} +*/ +#endif diff --git a/kaddressbook/views/kaddressbooktableview.cpp b/kaddressbook/views/kaddressbooktableview.cpp new file mode 100644 index 0000000..ee2fcf8 --- a/dev/null +++ b/kaddressbook/views/kaddressbooktableview.cpp @@ -0,0 +1,337 @@ +// $Id$ + +#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> + +//US#include "configuretableviewdialog.h" +#include "contactlistview.h" +#include "kabprefs.h" +#include "undocmds.h" +#include "viewmanager.h" + +#include <qlayout.h> + + +#include "kaddressbooktableview.h" + + +KAddressBookTableView::KAddressBookTableView( KABC::AddressBook *ab, + QWidget *parent, const char *name ) + : KAddressBookView( ab, parent, name ) +{ + mainLayout = new QVBoxLayout( viewWidget(), 2 ); + + // The list view will be created when the config is read. + mListView = 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(returnPressed(QListViewItem*)), + this, SLOT(addresseeExecuted(QListViewItem*))); + + disconnect(mListView, SIGNAL(addresseeDropped(QDropEvent*)), this, + SIGNAL(dropped(QDropEvent*))); + delete mListView; + } + + mListView = new ContactListView( this, addressBook(), viewWidget() ); + + // Add the columns + 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); +//US + // qDebug("KAddressBookTableView::reconstructListView: field %s", (*it)->label().latin1()); + } + + connect(mListView, SIGNAL(selectionChanged()), + this, SLOT(addresseeSelected())); + connect(mListView, SIGNAL(startAddresseeDrag()), this, + SIGNAL(startDrag())); + connect(mListView, SIGNAL(addresseeDropped(QDropEvent*)), this, + SIGNAL(dropped(QDropEvent*))); + + if (KABPrefs::instance()->mHonorSingleClick) + connect(mListView, SIGNAL(executed(QListViewItem*)), + this, SLOT(addresseeExecuted(QListViewItem*))); + else + connect(mListView, SIGNAL(doubleClicked(QListViewItem*)), + this, SLOT(addresseeExecuted(QListViewItem*))); + connect(mListView, SIGNAL(returnPressed(QListViewItem*)), + this, SLOT(addresseeExecuted(QListViewItem*))); + connect(mListView, SIGNAL(signalDelete()), + this, SLOT(addresseeDeleted())); + + refresh(); + + mListView->setSorting( 0, true ); + mainLayout->addWidget( mListView ); + mainLayout->activate(); + mListView->show(); +} + +void KAddressBookTableView::writeConfig(KConfig *config) +{ + KAddressBookView::writeConfig(config); + + mListView->saveLayout(config, config->group()); +} + +void KAddressBookTableView::readConfig(KConfig *config) +{ + KAddressBookView::readConfig( config ); + + // 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->readEntry("BackgroundName")); + + // Restore the layout of the listview + mListView->restoreLayout(config, config->group()); +} + +void KAddressBookTableView::refresh(QString uid) +{ + // For now just repopulate. In reality this method should + // check the value of uid, and if valid iterate through + // the listview to find the entry, then tell it to refresh. + + if (uid.isNull()) { + // Clear the list view + QString currentUID, nextUID; +#ifndef KAB_EMBEDDED + ContactListViewItem *currentItem = dynamic_cast<ContactListViewItem*>( mListView->currentItem() ); +#else //KAB_EMBEDDED + ContactListViewItem *currentItem = (ContactListViewItem*)( mListView->currentItem() ); +#endif //KAB_EMBEDDED + + if ( currentItem ) { +#ifndef KAB_EMBEDDED + ContactListViewItem *nextItem = dynamic_cast<ContactListViewItem*>( currentItem->itemBelow() ); +#else //KAB_EMBEDDED + ContactListViewItem *nextItem = (ContactListViewItem*)( currentItem->itemBelow() ); +#endif //KAB_EMBEDDED + if ( nextItem ) + nextUID = nextItem->addressee().uid(); + currentUID = currentItem->addressee().uid(); + } + + mListView->clear(); + + currentItem = 0; + KABC::Addressee::List addresseeList = addressees(); + KABC::Addressee::List::Iterator it; + for (it = addresseeList.begin(); it != addresseeList.end(); ++it ) { + ContactListViewItem *item = new ContactListViewItem(*it, mListView, addressBook(), fields()); + 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; + QListViewItemIterator it( mListView ); + while ( it.current() ) { +#ifndef KAB_EMBEDDED + ceItem = dynamic_cast<ContactListViewItem*>( it.current() ); +#else //KAB_EMBEDDED + ceItem = (ContactListViewItem*)( it.current() ); +#endif //KAB_EMBEDDED + + if ( ceItem && ceItem->addressee().uid() == uid ) { + ceItem->refresh(); + return; + } + ++it; + } + + refresh( QString::null ); + } +} + +QStringList KAddressBookTableView::selectedUids() +{ + QStringList uidList; + QListViewItem *item; + ContactListViewItem *ceItem; + + for(item = mListView->firstChild(); item; item = item->itemBelow()) + { + if (mListView->isSelected( item )) + { +#ifndef KAB_EMBEDDED + ceItem = dynamic_cast<ContactListViewItem*>(item); +#else //KAB_EMBEDDED + ceItem = (ContactListViewItem*)(item); +#endif //KAB_EMBEDDED + + if (ceItem != 0L) + uidList << ceItem->addressee().uid(); + } + } + if ( uidList.count() == 0 ) + if ( mListView->currentItem() ) { + ceItem = (ContactListViewItem*)(mListView->currentItem()) ; + uidList << ceItem->addressee().uid(); + } + + return uidList; +} + +void KAddressBookTableView::setSelected(QString uid, bool selected) +{ + QListViewItem *item; + ContactListViewItem *ceItem; + + if (uid.isNull()) + { + mListView->selectAll(selected); + } + else + { + for(item = mListView->firstChild(); item; item = item->itemBelow()) + { +#ifndef KAB_EMBEDDED + ceItem = dynamic_cast<ContactListViewItem*>(item); +#else //KAB_EMBEDDED + ceItem = (ContactListViewItem*)(item); +#endif //KAB_EMBEDDED + + + if ((ceItem != 0L) && (ceItem->addressee().uid() == uid)) + { + mListView->setSelected(item, selected); + + if (selected) + mListView->ensureItemVisible(item); + } + } + } +} + +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. + QListViewItem *item; + bool found =false; + for (item = mListView->firstChild(); item && !found; + item = item->nextSibling()) + { + if (item->isSelected()) + { + found = true; +#ifndef KAB_EMBEDDED + ContactListViewItem *ceItem + = dynamic_cast<ContactListViewItem*>(item); +#else //KAB_EMBEDDED + ContactListViewItem *ceItem + = (ContactListViewItem*)(item); +#endif //KAB_EMBEDDED + + if ( ceItem ) emit selected(ceItem->addressee().uid()); + } + } + + if (!found) + emit selected(QString::null); +} + +void KAddressBookTableView::addresseeExecuted(QListViewItem *item) +{ + if (item) + { +#ifndef KAB_EMBEDDED + ContactListViewItem *ceItem + = dynamic_cast<ContactListViewItem*>(item); +#else //KAB_EMBEDDED + ContactListViewItem *ceItem + = (ContactListViewItem*)(item); +#endif //KAB_EMBEDDED + + if (ceItem) + { + emit executed(ceItem->addressee().uid()); + } + } + else + { + emit executed(QString::null); + } +} + +void KAddressBookTableView::addresseeDeleted() +{ + + emit deleteRequest(); + +} + + + + + +#ifndef KAB_EMBEDDED +#include "kaddressbooktableview.moc" +#endif //KAB_EMBEDDED diff --git a/kaddressbook/views/kaddressbooktableview.h b/kaddressbook/views/kaddressbooktableview.h new file mode 100644 index 0000000..bb991bc --- a/dev/null +++ b/kaddressbook/views/kaddressbooktableview.h @@ -0,0 +1,114 @@ +#ifndef KADDRESSBOOKTABLEVIEW_H +#define KADDRESSBOOKTABLEVIEW_H + + +#ifndef KAB_EMBEDDED + + +#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 "undo.h" + +#else //KAB_EMBEDDED +#include "views/configuretableviewdialog.h" +#endif //KAB_EMBEDDED + +#include "klocale.h" +#include "kaddressbookview.h" + +class QListViewItem; +class QListBox; +class QVBoxLayout; +class KConfig; + +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( KABC::AddressBook *ab, QWidget *parent, + const char *name = 0 ); + virtual ~KAddressBookTableView(); + + virtual void refresh(QString uid = QString::null); + virtual QStringList selectedUids(); + virtual void setSelected(QString uid = QString::null, bool selected = false); + virtual void readConfig(KConfig *config); + virtual void writeConfig(KConfig *config); + virtual QString type() const { return "Table"; } + + public slots: + virtual void reconstructListView(); + + protected slots: + /** Called whenever the user selects an addressee in the list view. + */ + void addresseeSelected(); + void addresseeDeleted(); + + /** Called whenever the user executes an addressee. In terms of the + * list view, this is probably a double click + */ + void addresseeExecuted(QListViewItem*); + + private: + QVBoxLayout *mainLayout; + ContactListView *mListView; +}; + + +class TableViewFactory : public ViewFactory +{ + public: + KAddressBookView *view( KABC::AddressBook *ab, QWidget *parent, const char *name ) + { + return new KAddressBookTableView( ab, parent, name ); + } + + QString type() const { return "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 ); + } +}; +/*US +extern "C" { + void *init_libkaddrbk_tableview() + { + return ( new TableViewFactory ); + } +} +*/ + +#endif |