summaryrefslogtreecommitdiffstats
path: root/kopete/kopete/contactlist
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitbcb704366cb5e333a626c18c308c7e0448a8e69f (patch)
treef0d6ab7d78ecdd9207cf46536376b44b91a1ca71 /kopete/kopete/contactlist
downloadtdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.tar.gz
tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdenetwork@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kopete/kopete/contactlist')
-rw-r--r--kopete/kopete/contactlist/Makefile.am28
-rw-r--r--kopete/kopete/contactlist/configure.in.in15
-rw-r--r--kopete/kopete/contactlist/customnotificationprops.cpp168
-rw-r--r--kopete/kopete/contactlist/customnotificationprops.h51
-rw-r--r--kopete/kopete/contactlist/customnotifications.ui238
-rw-r--r--kopete/kopete/contactlist/kabcexport.cpp249
-rw-r--r--kopete/kopete/contactlist/kabcexport.h56
-rw-r--r--kopete/kopete/contactlist/kabcexport_base.ui183
-rw-r--r--kopete/kopete/contactlist/kopeteaddrbookexport.cpp298
-rw-r--r--kopete/kopete/contactlist/kopeteaddrbookexport.h102
-rw-r--r--kopete/kopete/contactlist/kopeteaddrbookexportui.ui149
-rw-r--r--kopete/kopete/contactlist/kopetecontactlistview.cpp2134
-rw-r--r--kopete/kopete/contactlist/kopetecontactlistview.h252
-rw-r--r--kopete/kopete/contactlist/kopetegrouplistaction.cpp66
-rw-r--r--kopete/kopete/contactlist/kopetegrouplistaction.h44
-rw-r--r--kopete/kopete/contactlist/kopetegroupviewitem.cpp286
-rw-r--r--kopete/kopete/contactlist/kopetegroupviewitem.h82
-rw-r--r--kopete/kopete/contactlist/kopetegvipropswidget.ui156
-rw-r--r--kopete/kopete/contactlist/kopetelviprops.cpp570
-rw-r--r--kopete/kopete/contactlist/kopetelviprops.h102
-rw-r--r--kopete/kopete/contactlist/kopetemetacontactlvi.cpp1102
-rw-r--r--kopete/kopete/contactlist/kopetemetacontactlvi.h191
-rw-r--r--kopete/kopete/contactlist/kopetemetalvipropswidget.ui587
-rw-r--r--kopete/kopete/contactlist/kopetestatusgroupviewitem.cpp51
-rw-r--r--kopete/kopete/contactlist/kopetestatusgroupviewitem.h43
25 files changed, 7203 insertions, 0 deletions
diff --git a/kopete/kopete/contactlist/Makefile.am b/kopete/kopete/contactlist/Makefile.am
new file mode 100644
index 00000000..d9544d5d
--- /dev/null
+++ b/kopete/kopete/contactlist/Makefile.am
@@ -0,0 +1,28 @@
+METASOURCES = AUTO
+
+AM_CPPFLAGS = $(KOPETE_INCLUDES) \
+ -I$(top_srcdir)/kopete/libkopete/private \
+ -I$(top_srcdir)/kopete/libkopete/ui \
+ -I$(top_srcdir)/kopete/kopete \
+ -I$(top_srcdir)/kopete/kopete/chatwindow \
+ -I$(top_srcdir)/kopete/kopete/addcontactwizard \
+ -I$(top_builddir)/kopete/kopete/addcontactwizard \
+ $(all_includes)
+
+noinst_LTLIBRARIES = libkopetecontactlist.la
+
+libkopetecontactlist_la_SOURCES = kopetemetacontactlvi.cpp \
+ kopetestatusgroupviewitem.cpp kopetegroupviewitem.cpp kopetecontactlistview.cpp \
+ kopetegvipropswidget.ui kopetemetalvipropswidget.ui kopetelviprops.cpp \
+ kopeteaddrbookexport.cpp kopeteaddrbookexportui.ui customnotifications.ui \
+ customnotificationprops.cpp kopetegrouplistaction.cpp kabcexport.cpp \
+ kabcexport_base.ui
+
+libkopetecontactlist_la_LDFLAGS = $(all_libraries)
+libkopetecontactlist_la_LIBADD = -lkabc ../../libkopete/libkopete.la ../addcontactwizard/libkopeteaddcontactwizard.la $(LIB_KDEUI) $(LIB_XRENDER)
+
+noinst_HEADERS = kopeteaddrbookexport.h customnotificationprops.h kabcexport.h
+
+KDE_OPTIONS = nofinal
+
+# vim: set noet:
diff --git a/kopete/kopete/contactlist/configure.in.in b/kopete/kopete/contactlist/configure.in.in
new file mode 100644
index 00000000..900224ea
--- /dev/null
+++ b/kopete/kopete/contactlist/configure.in.in
@@ -0,0 +1,15 @@
+
+dnl -----------------------------------------------------
+dnl XRender check - stolen from kdelibs/kdefx
+dnl -----------------------------------------------------
+LIB_XRENDER=
+if test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no"; then
+ KDE_CHECK_HEADER(X11/extensions/Xrender.h, [xrender_h=yes], [xrender_h=no])
+ if test "$xrender_h" = yes; then
+ KDE_CHECK_LIB(Xrender, XRenderComposite, [
+ LIB_XRENDER=-lXrender
+ AC_DEFINE_UNQUOTED(HAVE_XRENDER, 1, [Defined if your system has XRender support])
+ ], [], -lXext -lX11 $X_EXTRA_LIBS)
+ fi
+fi
+AC_SUBST(LIB_XRENDER)
diff --git a/kopete/kopete/contactlist/customnotificationprops.cpp b/kopete/kopete/contactlist/customnotificationprops.cpp
new file mode 100644
index 00000000..87833fa7
--- /dev/null
+++ b/kopete/kopete/contactlist/customnotificationprops.cpp
@@ -0,0 +1,168 @@
+/*
+ customnotificationprops.cpp
+
+ Kopete Contactlist Custom Notifications GUI for Groups and MetaContacts
+
+ Contains UI controller logic for managing custom notifications
+
+ Copyright (c) 2004 Will Stephenson <lists@stevello.free-online.co.uk>
+ Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+
+#include <kdebug.h>
+#include <kconfig.h>
+#include <kurlrequester.h>
+
+#include "customnotifications.h"
+#include "kopeteeventpresentation.h"
+#include "kopetenotifyevent.h"
+#include "kopetenotifydataobject.h"
+
+#include "customnotificationprops.h"
+
+CustomNotificationProps::CustomNotificationProps( QWidget *parent, Kopete::NotifyDataObject* item, const char * name )
+: QObject( parent, name )
+{
+ m_notifyWidget = new CustomNotificationWidget( parent, "notificationWidget" );
+
+ m_item = item;
+ QString path = "kopete/eventsrc";
+ KConfig eventsfile( path, true, false, "data" );
+ m_eventList = eventsfile.groupList();
+ QStringList contactSpecificEvents; // we are only interested in events that relate to contacts
+ QStringList::Iterator it = m_eventList.begin();
+ QStringList::Iterator end = m_eventList.end();
+ for ( ; it != end; ++it )
+ {
+ if ( !(*it).startsWith( QString::fromLatin1( "kopete_contact_" ) ) )
+ continue;
+ contactSpecificEvents.append( *it );
+ QMap<QString, QString> entries = eventsfile.entryMap( *it );
+ eventsfile.setGroup( *it );
+ QString comment = eventsfile.readEntry( "Comment", QString::fromLatin1( "Found nothing!" ) );
+ m_notifyWidget->cmbEvents->insertItem( comment );
+ }
+ m_eventList = contactSpecificEvents;
+ slotEventsComboChanged( m_notifyWidget->cmbEvents->currentItem() );
+ // we have to do this after adding items
+ connect( m_notifyWidget->cmbEvents, SIGNAL( activated( int ) ), this, SLOT( slotEventsComboChanged( int ) ) );
+}
+
+void CustomNotificationProps::slotEventsComboChanged( int itemNo )
+{
+ // if the combo has changed, store the previous state of the widgets
+ // record the selected item so we can save it when the widget changes next
+ storeCurrentCustoms();
+ m_event = m_eventList[ itemNo ];
+ // update the widgets for the selected item
+ // get the corresponding Kopete::NotifyEvent
+ Kopete::NotifyEvent *evt = m_item->notifyEvent( m_event );
+ // set the widgets accordingly
+ resetEventWidgets();
+ if ( evt )
+ {
+ // sound presentation
+ Kopete::EventPresentation *pres = evt->presentation( Kopete::EventPresentation::Sound );
+ if ( pres )
+ {
+ m_notifyWidget->chkCustomSound->setChecked( pres->enabled() );
+ m_notifyWidget->customSound->setURL( pres->content() );
+ m_notifyWidget->chkSoundSS->setChecked( pres->singleShot() );
+ }
+ // message presentation
+ pres = evt->presentation( Kopete::EventPresentation::Message );
+ if ( pres )
+ {
+ m_notifyWidget->chkCustomMsg->setChecked( pres->enabled() );
+ m_notifyWidget->customMsg->setText( pres->content() );
+ m_notifyWidget->chkMsgSS->setChecked( pres->singleShot() );
+ }
+ // chat presentation
+ pres = evt->presentation( Kopete::EventPresentation::Chat );
+ if ( pres )
+ {
+ m_notifyWidget->chkCustomChat->setChecked( pres->enabled() );
+ m_notifyWidget->chkChatSS->setChecked( pres->singleShot() );
+ }
+ m_notifyWidget->chkSuppressCommon->setChecked( evt->suppressCommon() );
+ }
+ //dumpData();
+}
+
+
+void CustomNotificationProps::dumpData()
+{
+ Kopete::NotifyEvent *evt = m_item->notifyEvent( m_event );
+ if ( evt )
+ kdDebug( 14000 ) << k_funcinfo << evt->toString() << endl;
+ else
+ kdDebug( 14000 ) << k_funcinfo << " no event exists." << endl;
+}
+
+void CustomNotificationProps::resetEventWidgets()
+{
+ m_notifyWidget->chkCustomSound->setChecked( false );
+ m_notifyWidget->customSound->clear();
+ m_notifyWidget->chkSoundSS->setChecked( true );
+ m_notifyWidget->chkCustomMsg->setChecked( false );
+ m_notifyWidget->customMsg->clear();
+ m_notifyWidget->chkMsgSS->setChecked( true );
+ m_notifyWidget->chkCustomChat->setChecked( false );
+ m_notifyWidget->chkChatSS->setChecked( true );
+ m_notifyWidget->chkSuppressCommon->setChecked( false );
+}
+
+void CustomNotificationProps::storeCurrentCustoms()
+{
+ if ( !m_event.isNull() )
+ {
+ Kopete::NotifyEvent *evt = m_item->notifyEvent( m_event );
+ if ( !evt )
+ {
+ evt = new Kopete::NotifyEvent( );
+ // store the changed event
+ m_item->setNotifyEvent( m_event, evt );
+ }
+ evt->setSuppressCommon( m_notifyWidget->chkSuppressCommon->isChecked() );
+ // set different presentations
+ Kopete::EventPresentation *eventNotify = 0;
+ eventNotify = new Kopete::EventPresentation( Kopete::EventPresentation::Sound,
+ m_notifyWidget->customSound->url(),
+ m_notifyWidget->chkSoundSS->isChecked(),
+ m_notifyWidget->chkCustomSound->isChecked() );
+ evt->setPresentation( Kopete::EventPresentation::Sound, eventNotify );
+ // set message attributes
+ eventNotify = new Kopete::EventPresentation( Kopete::EventPresentation::Message,
+ m_notifyWidget->customMsg->text(),
+ m_notifyWidget->chkMsgSS->isChecked(),
+ m_notifyWidget->chkCustomMsg->isChecked() );
+ evt->setPresentation( Kopete::EventPresentation::Message, eventNotify );
+ // set chat attributes
+ eventNotify = new Kopete::EventPresentation( Kopete::EventPresentation::Chat,
+ QString::null,
+ m_notifyWidget->chkChatSS->isChecked(),
+ m_notifyWidget->chkCustomChat->isChecked() );
+ evt->setPresentation( Kopete::EventPresentation::Chat, eventNotify );
+ evt->setSuppressCommon( m_notifyWidget->chkSuppressCommon->isChecked() );
+ }
+}
+
+CustomNotificationWidget* CustomNotificationProps::widget()
+{
+ return m_notifyWidget;
+}
+
+#include "customnotificationprops.moc"
diff --git a/kopete/kopete/contactlist/customnotificationprops.h b/kopete/kopete/contactlist/customnotificationprops.h
new file mode 100644
index 00000000..5d6c1dea
--- /dev/null
+++ b/kopete/kopete/contactlist/customnotificationprops.h
@@ -0,0 +1,51 @@
+/*
+ customnotificationprops.h
+
+ Kopete Contactlist Custom Notifications GUI for Groups and MetaContacts
+
+ Copyright (c) 2004 Will Stephenson <lists@stevello.free-online.co.uk>
+ Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KOPETE_CUSTOM_NOTIFICATION_PROPS_H
+#define KOPETE_CUSTOM_NOTIFICATION_PROPS_H
+
+class CustomNotificationWidget;
+class QBoxLayout;
+
+namespace Kopete
+{
+class NotifyDataObject;
+}
+
+class CustomNotificationProps : public QObject
+{
+ Q_OBJECT
+public:
+ CustomNotificationProps( QWidget *parent, Kopete::NotifyDataObject* item, const char * name = 0 );
+ ~CustomNotificationProps() {}
+ void dumpData();
+ void resetEventWidgets();
+ void storeCurrentCustoms();
+ CustomNotificationWidget* widget();
+
+protected slots:
+ void slotEventsComboChanged( int itemNo );
+
+private:
+ CustomNotificationWidget* m_notifyWidget;
+ Kopete::NotifyDataObject * m_item;
+ QStringList m_eventList;
+ QString m_event;
+};
+
+#endif
diff --git a/kopete/kopete/contactlist/customnotifications.ui b/kopete/kopete/contactlist/customnotifications.ui
new file mode 100644
index 00000000..86224af2
--- /dev/null
+++ b/kopete/kopete/contactlist/customnotifications.ui
@@ -0,0 +1,238 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>CustomNotificationWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CustomNotificationWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>389</width>
+ <height>220</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>On &amp;event:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>cmbEvents</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>cmbEvents</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Choose the event that should have a custom notification</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KURLRequester" row="0" column="1">
+ <property name="name">
+ <cstring>customSound</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Select the sound to play</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>chkCustomSound</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Play a sound:</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Play a sound when this event occurs for this contact</string>
+ </property>
+ </widget>
+ <spacer row="2" column="1">
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>140</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>chkCustomChat</cstring>
+ </property>
+ <property name="text">
+ <string>Start a cha&amp;t</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Open a chat window with this contact when this event occurs for this contact</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>chkCustomMsg</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Display a message:</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Display a message on your screen when this event occurs for this contact</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>customMsg</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Enter the message to display</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="2">
+ <property name="name">
+ <cstring>chkMsgSS</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>D&amp;isplay once</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Only display a message the next time the event occurs</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="2">
+ <property name="name">
+ <cstring>chkSoundSS</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>P&amp;lay once</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Only play a sound the next time the event occurs</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="2">
+ <property name="name">
+ <cstring>chkChatSS</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>T&amp;rigger once</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Only start a chat the next time the event occurs</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>chkSuppressCommon</cstring>
+ </property>
+ <property name="text">
+ <string>S&amp;uppress standard notifications</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Check to prevent notifications common to all contacts from happening for this contact</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>chkCustomSound</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>customSound</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>chkCustomSound</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>chkSoundSS</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>chkCustomMsg</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>customMsg</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>chkCustomMsg</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>chkMsgSS</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>chkCustomChat</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>chkChatSS</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>cmbEvents</tabstop>
+ <tabstop>chkCustomSound</tabstop>
+ <tabstop>customSound</tabstop>
+ <tabstop>chkSoundSS</tabstop>
+ <tabstop>chkCustomMsg</tabstop>
+ <tabstop>customMsg</tabstop>
+ <tabstop>chkMsgSS</tabstop>
+ <tabstop>chkCustomChat</tabstop>
+ <tabstop>chkChatSS</tabstop>
+ <tabstop>chkSuppressCommon</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kopete/kopete/contactlist/kabcexport.cpp b/kopete/kopete/contactlist/kabcexport.cpp
new file mode 100644
index 00000000..73f67344
--- /dev/null
+++ b/kopete/kopete/contactlist/kabcexport.cpp
@@ -0,0 +1,249 @@
+/*
+ kabcexport.cpp - Export Contacts to Address Book Wizard for Kopete
+
+ Copyright (c) 2005 by Will Stephenson <will@stevello.free-online.co.uk>
+ Resource selector taken from KRES::SelectDialog
+ Copyright (c) 2002 Tobias Koenig <tokoe@kde.org>
+ Copyright (c) 2002 Jan-Pascal van Best <janpascal@vanbest.org>
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#include <qpushbutton.h>
+#include <qlistbox.h>
+#include <qlistview.h>
+#include <qptrlist.h>
+#include <qmap.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kabc/addressee.h>
+#include <kabc/addressbook.h>
+#include <kabc/phonenumber.h>
+#include <kabc/picture.h>
+#include <kabc/resource.h>
+#include <kabc/stdaddressbook.h>
+
+#include <kabcpersistence.h>
+#include <kopetecontact.h>
+#include <kopetecontactlist.h>
+#include <kopetecontactproperty.h>
+#include <kopeteglobal.h>
+#include <kopetemetacontact.h>
+
+#include "kabcpersistence.h"
+
+#include "kabcexport.h"
+
+class ContactLVI : public QCheckListItem
+{
+ public:
+ ContactLVI ( Kopete::MetaContact * mc, QListView * parent, const QString & text, Type tt = RadioButtonController ) : QCheckListItem( parent, text, tt ), mc( mc )
+ { }
+ Kopete::MetaContact * mc;
+ QString uid;
+};
+
+// ctor populates the resource list and contact list, and enables the next button on the first page
+KabcExportWizard::KabcExportWizard( QWidget *parent, const char *name )
+ : KabcExportWizard_Base( parent, name )
+{
+ connect( m_addrBooks, SIGNAL( selectionChanged( QListBoxItem * ) ), SLOT( slotResourceSelectionChanged( QListBoxItem * ) ) );
+
+ connect( m_btnSelectAll, SIGNAL( clicked() ), SLOT( slotSelectAll() ) );
+ connect( m_btnDeselectAll, SIGNAL( clicked() ), SLOT( slotDeselectAll() ) );
+
+ // fill resource selector
+ m_addressBook = Kopete::KABCPersistence::self()->addressBook();
+
+ QPtrList<KABC::Resource> kabcResources = m_addressBook->resources();
+
+ QPtrListIterator<KABC::Resource> resIt( kabcResources );
+ KABC::Resource *resource;
+
+ uint counter = 0;
+ while ( ( resource = resIt.current() ) != 0 )
+ {
+ ++resIt;
+ if ( !resource->readOnly() )
+ {
+ m_resourceMap.insert( counter, resource );
+ m_addrBooks->insertItem( resource->resourceName() );
+ counter++;
+ }
+ }
+ setNextEnabled( QWizard::page( 0 ), false );
+ setFinishEnabled( QWizard::page( 1 ), true );
+ // if there were no writable address books, tell the user
+ if ( counter == 0 )
+ {
+ m_addrBooks->insertItem( i18n( "No writeable addressbook resource found." ) );
+ m_addrBooks->insertItem( i18n( "Add or enable one using the KDE Control Center." ) );
+ m_addrBooks->setEnabled( false );
+ }
+
+ if ( m_addrBooks->count() == 1 )
+ m_addrBooks->setSelected( 0, true );
+
+ // fill contact list
+ QPtrList<Kopete::MetaContact> contacts = Kopete::ContactList::self()->metaContacts();
+ QPtrListIterator<Kopete::MetaContact> it( contacts );
+ counter = 0;
+ QString alreadyIn = i18n( " (already in address book)" );
+ for (; it.current(); ++it)
+ {
+ m_contactMap.insert( counter, it.current() );
+ QCheckListItem * lvi = new ContactLVI( it.current(), m_contactList,
+ it.current()->displayName(), QCheckListItem::CheckBox );
+ lvi->setOn( false );
+ if ( it.current()->metaContactId().contains(':') )
+ {
+ lvi->setOn( true );
+ lvi->setEnabled( true );
+ }
+ else
+ lvi->setText( 0, lvi->text( 0 ) + alreadyIn );
+ }
+}
+
+KabcExportWizard::~KabcExportWizard()
+{
+
+}
+
+void KabcExportWizard::slotDeselectAll()
+{
+ QListViewItemIterator it( m_contactList );
+ while ( it.current() )
+ {
+ ContactLVI *item = static_cast<ContactLVI *>( it.current() );
+ item->setOn( false );
+ ++it;
+ }
+}
+
+void KabcExportWizard::slotSelectAll()
+{
+ QListViewItemIterator it( m_contactList );
+ while ( it.current() )
+ {
+ ContactLVI *item = static_cast<ContactLVI *>( it.current() );
+ ++it;
+ if ( !item->isEnabled() )
+ continue;
+ item->setOn( true );
+ }
+}
+
+void KabcExportWizard::slotResourceSelectionChanged( QListBoxItem * lbi )
+{
+ setNextEnabled( QWizard::page( 0 ), lbi->isSelected() );
+}
+
+// accept runs the export algorithm
+void KabcExportWizard::accept()
+{
+ // first add an addressee to the selected resource
+ // then set the metacontactId of each MC to that of the new addressee
+ KABC::Resource * selectedResource =
+ m_resourceMap[ ( m_addrBooks->index( m_addrBooks->selectedItem() ) ) ];
+ // for each item checked
+ {
+ QListViewItemIterator it( m_contactList );
+ while ( it.current() )
+ {
+ ContactLVI *item = static_cast<ContactLVI *>( it.current() );
+ // if it is checked and enabled
+ if ( item->isEnabled() && item->isOn() )
+ {
+ KABC::Addressee addr;
+ addr = m_addressBook->findByUid( item->mc->metaContactId() );
+ if ( addr.isEmpty() ) // unassociated contact
+ {
+ kdDebug( 14000 ) << "creating addressee " << item->mc->displayName() << " in address book " << selectedResource->resourceName() << endl;
+ // create a new addressee in the selected resource
+ addr.setResource( selectedResource );
+
+ // set name
+ QPtrList<Kopete::Contact> contacts = item->mc->contacts();
+ if ( contacts.count() == 1 )
+ {
+ Kopete::ContactProperty prop;
+ prop = contacts.first()->property(
+ Kopete::Global::Properties::self()->fullName() );
+ if ( prop.isNull() )
+ addr.setNameFromString( item->mc->displayName() );
+ else
+ addr.setNameFromString( prop.value().toString() );
+ }
+ else
+ addr.setNameFromString( item->mc->displayName() );
+
+ // set details
+ exportDetails( item->mc, addr );
+ m_addressBook->insertAddressee( addr );
+ // set the metacontact's id to that of the new addressee
+ // - this causes the addressbook to be written by libkopete
+ item->mc->setMetaContactId( addr.uid() );
+ }
+ else
+ {
+ exportDetails( item->mc, addr );
+ m_addressBook->insertAddressee( addr );
+ }
+ }
+ ++it;
+ }
+ }
+ // request a write in case we only changed details on existing linked addressee
+ Kopete::KABCPersistence::self()->writeAddressBook( selectedResource );
+ QDialog::accept();
+}
+
+void KabcExportWizard::exportDetails( Kopete::MetaContact * mc, KABC::Addressee & addr )
+{
+ // for each contact
+ QPtrList<Kopete::Contact> contacts = mc->contacts();
+ QPtrListIterator<Kopete::Contact> cit( contacts );
+ for( ; cit.current(); ++cit )
+ {
+ Kopete::ContactProperty prop;
+ prop = (*cit)->property( Kopete::Global::Properties::self()->emailAddress() );
+ if ( !prop.isNull() )
+ {
+ addr.insertEmail( prop.value().toString() );
+ }
+ prop = (*cit)->property( Kopete::Global::Properties::self()->privatePhone() );
+ if ( !prop.isNull() )
+ {
+ addr.insertPhoneNumber( KABC::PhoneNumber( prop.value().toString(), KABC::PhoneNumber::Home ) );
+ }
+ prop = (*cit)->property( Kopete::Global::Properties::self()->workPhone() );
+ if ( !prop.isNull() )
+ {
+ addr.insertPhoneNumber( KABC::PhoneNumber( prop.value().toString(), KABC::PhoneNumber::Work ) );
+ }
+ prop = (*cit)->property( Kopete::Global::Properties::self()->privateMobilePhone() );
+ if ( !prop.isNull() )
+ {
+ addr.insertPhoneNumber( KABC::PhoneNumber( prop.value().toString(), KABC::PhoneNumber::Cell ) );
+ }
+
+ }
+ // metacontact photo
+ QImage photo = mc->photo();
+ if ( !photo.isNull() )
+ addr.setPhoto( KABC::Picture( photo ) );
+}
+
+#include "kabcexport.moc"
diff --git a/kopete/kopete/contactlist/kabcexport.h b/kopete/kopete/contactlist/kabcexport.h
new file mode 100644
index 00000000..bad1d8e6
--- /dev/null
+++ b/kopete/kopete/contactlist/kabcexport.h
@@ -0,0 +1,56 @@
+/*
+ kabcexport.h - Export Contacts to Address Book Wizard for Kopete
+
+ Copyright (c) 2005 by Will Stephenson <will@stevello.free-online.co.uk>
+
+ Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KABCEXPORTWIZARD_H
+#define KABCEXPORTWIZARD_H
+
+#include "kabcexport_base.h"
+
+namespace KABC {
+ class AddressBook;
+ class Addressee;
+}
+
+namespace Kopete {
+ class MetaContact;
+}
+
+namespace KRES {
+ class Resource;
+}
+
+class KabcExportWizard : public KabcExportWizard_Base
+{
+Q_OBJECT
+ public:
+ KabcExportWizard( QWidget *parent = 0, const char *name = 0 );
+ ~KabcExportWizard();
+ public slots:
+ void accept();
+ protected slots:
+ void slotDeselectAll();
+ void slotSelectAll();
+ void slotResourceSelectionChanged( QListBoxItem * lbi );
+ protected:
+ void exportDetails( Kopete::MetaContact * mc, KABC::Addressee & addr );
+ private:
+ KABC::AddressBook* m_addressBook;
+ QMap<int, KABC::Resource*> m_resourceMap;
+ QMap<int, Kopete::MetaContact*> m_contactMap;
+};
+
+#endif
diff --git a/kopete/kopete/contactlist/kabcexport_base.ui b/kopete/kopete/contactlist/kabcexport_base.ui
new file mode 100644
index 00000000..80ace5c6
--- /dev/null
+++ b/kopete/kopete/contactlist/kabcexport_base.ui
@@ -0,0 +1,183 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KabcExportWizard_Base</class>
+<widget class="QWizard">
+ <property name="name">
+ <cstring>KabcExportWizard_Base</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>423</width>
+ <height>398</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Export Contacts</string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>page</cstring>
+ </property>
+ <attribute name="title">
+ <string>Export Contacts to Address Book</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>This wizard helps you export instant messaging contacts to the KDE address book.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>&amp;Select Address Book</string>
+ </property>
+ <widget class="QListBox">
+ <property name="name">
+ <cstring>m_addrBooks</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>11</x>
+ <y>31</y>
+ <width>230</width>
+ <height>140</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>WizardPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Select Contacts to Export</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Selected contacts will be added to the KDE address book.</string>
+ </property>
+ </widget>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Contact</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_contactList</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="resizeMode">
+ <enum>AllColumns</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_btnSelectAll</cstring>
+ </property>
+ <property name="text">
+ <string>Select &amp;All</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_btnDeselectAll</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Deselect All</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kopete/kopete/contactlist/kopeteaddrbookexport.cpp b/kopete/kopete/contactlist/kopeteaddrbookexport.cpp
new file mode 100644
index 00000000..d752f71e
--- /dev/null
+++ b/kopete/kopete/contactlist/kopeteaddrbookexport.cpp
@@ -0,0 +1,298 @@
+/*
+ kopeteaddrbookexport.cpp - Kopete Online Status
+
+ Logic for exporting data acquired from messaging systems to the
+ KDE address book
+
+ Copyright (c) 2004 by Will Stephenson <lists@stevello.free-online.co.uk>
+
+ Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#include <kabc/phonenumber.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+
+#include <kdialogbase.h>
+#include <kiconloader.h>
+#include <klistbox.h>
+#include <klocale.h>
+
+#include "kopeteaccount.h"
+#include "kopeteglobal.h"
+#include "kopetemetacontact.h"
+#include "kopetecontact.h"
+
+#include "kopeteaddrbookexport.h"
+#include "kopeteaddrbookexportui.h"
+
+KopeteAddressBookExport::KopeteAddressBookExport( QWidget *parent, Kopete::MetaContact *mc ) : QObject( parent )
+{
+ // instantiate dialog and populate widgets
+ mParent = parent;
+ mAddressBook = KABC::StdAddressBook::self();
+ mMetaContact = mc;
+}
+
+KopeteAddressBookExport::~KopeteAddressBookExport()
+{
+
+}
+
+void KopeteAddressBookExport::initLabels()
+{
+ if ( !mAddressee.isEmpty() )
+ {
+ mUI->mLblFirstName->setText( mAddressee.givenNameLabel() );
+ mUI->mLblLastName->setText( mAddressee.familyNameLabel() );
+ mUI->mLblEmail->setText( mAddressee.emailLabel() );
+ mUI->mLblUrl->setText( mAddressee.urlLabel() );
+ mUI->mLblHomePhone->setText( mAddressee.homePhoneLabel() );
+ mUI->mLblWorkPhone->setText( mAddressee.businessPhoneLabel() );
+ mUI->mLblMobilePhone->setText( mAddressee.mobilePhoneLabel() );
+ }
+}
+
+void KopeteAddressBookExport::fetchKABCData()
+{
+ if ( !mAddressee.isEmpty() )
+ {
+ mAddrBookIcon = SmallIcon( "kaddressbook" );
+
+ // given name
+ QString given = mAddressee.givenName();
+ if ( !given.isEmpty() )
+ mUI->mFirstName->insertItem( mAddrBookIcon, given );
+ else
+ mUI->mFirstName->insertItem( mAddrBookIcon, i18n("<Not Set>") );
+
+ // family name
+ QString family = mAddressee.familyName();
+ if ( !family.isEmpty() )
+ mUI->mLastName->insertItem( mAddrBookIcon, family );
+ else
+ mUI->mLastName->insertItem( mAddrBookIcon, i18n("<Not Set>") );
+
+ // url
+ QString url = mAddressee.url().url();
+ if ( !url.isEmpty() )
+ mUI->mUrl->insertItem( mAddrBookIcon, url );
+ else
+ mUI->mUrl->insertItem( mAddrBookIcon, i18n("<Not Set>") );
+
+ // emails
+ QStringList emails = mAddressee.emails();
+ numEmails = emails.count();
+ for ( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it )
+ mUI->mEmails->insertItem( mAddrBookIcon, *it );
+ if ( numEmails == 0 )
+ {
+ mUI->mEmails->insertItem( mAddrBookIcon, i18n("<Not Set>") );
+ numEmails = 1;
+ }
+
+ // phone numbers
+ fetchPhoneNumbers( mUI->mHomePhones, KABC::PhoneNumber::Home, numHomePhones );
+ fetchPhoneNumbers( mUI->mWorkPhones, KABC::PhoneNumber::Work, numWorkPhones );
+ fetchPhoneNumbers( mUI->mMobilePhones, KABC::PhoneNumber::Cell, numMobilePhones );
+ }
+}
+
+void KopeteAddressBookExport::fetchPhoneNumbers( KListBox * listBox, int type, uint& counter )
+{
+ KABC::PhoneNumber::List phones = mAddressee.phoneNumbers( type );
+ counter = phones.count();
+ KABC::PhoneNumber::List::Iterator it;
+ for ( it = phones.begin(); it != phones.end(); ++it )
+ listBox->insertItem( mAddrBookIcon, (*it).number() );
+ if ( counter == 0 )
+ {
+ listBox->insertItem( mAddrBookIcon, i18n("<Not Set>") );
+ counter = 1;
+ }
+}
+
+void KopeteAddressBookExport::fetchIMData()
+{
+ QPtrList<Kopete::Contact> contacts = mMetaContact->contacts();
+ QPtrListIterator<Kopete::Contact> cit( contacts );
+ for( ; cit.current(); ++cit )
+ {
+ // for each contact, get the property content
+ Kopete::Contact* c = cit.current();
+ QPixmap contactIcon = c->account()->accountIcon( 16 );
+ // given name
+ populateIM( c, contactIcon, mUI->mFirstName, Kopete::Global::Properties::self()->firstName() );
+ // family name
+ populateIM( c, contactIcon, mUI->mLastName, Kopete::Global::Properties::self()->lastName() );
+ // url
+ // TODO: make URL/homepage a global template, currently only in IRC channel contact
+ // emails
+ populateIM( c, contactIcon, mUI->mEmails, Kopete::Global::Properties::self()->emailAddress() );
+ // home phone
+ populateIM( c, contactIcon, mUI->mHomePhones, Kopete::Global::Properties::self()->privatePhone() );
+ // work phone
+ populateIM( c, contactIcon, mUI->mWorkPhones, Kopete::Global::Properties::self()->workPhone() );
+ // mobile phone
+ populateIM( c, contactIcon, mUI->mMobilePhones, Kopete::Global::Properties::self()->privateMobilePhone() );
+ }
+}
+
+void KopeteAddressBookExport::populateIM( const Kopete::Contact *contact, const QPixmap &icon, QComboBox *combo, const Kopete::ContactPropertyTmpl &property )
+{
+ Kopete::ContactProperty prop = contact->property( property );
+ if ( !prop.isNull() )
+ {
+ combo->insertItem( icon, prop.value().toString() );
+ }
+}
+
+void KopeteAddressBookExport::populateIM( const Kopete::Contact *contact, const QPixmap &icon, KListBox *listBox, const Kopete::ContactPropertyTmpl &property )
+{
+ Kopete::ContactProperty prop = contact->property( property );
+ if ( !prop.isNull() )
+ {
+ listBox->insertItem( icon, prop.value().toString() );
+ }
+}
+
+int KopeteAddressBookExport::showDialog()
+{
+ mAddressee = mAddressBook->findByUid( mMetaContact->metaContactId() );
+ if ( !mAddressee.isEmpty() )
+ {
+ numEmails = 0;
+ numHomePhones = 0;
+ numWorkPhones = 0;
+ numMobilePhones = 0;
+ mDialog = new KDialogBase( mParent, "addressbookexportdialog", true, i18n("Export to Address Book"), KDialogBase::Ok|KDialogBase::Cancel );
+ mUI = new AddressBookExportUI( mDialog );
+ mDialog->setMainWidget( mUI );
+ mDialog->setButtonOK( KGuiItem( i18n( "Export" ),
+ QString::null, i18n( "Set address book fields using the selected data from Kopete" ) ) );
+
+ initLabels();
+ // fetch existing data from kabc
+ fetchKABCData();
+ // fetch data from contacts
+ fetchIMData();
+
+ return mDialog->exec();
+ }
+ else
+ return QDialog::Rejected;
+}
+
+void KopeteAddressBookExport::exportData()
+{
+ // write the data from the widget to KABC
+ // update the Addressee
+ // first name
+ bool dirty = false;
+ if ( newValue( mUI->mFirstName ) )
+ {
+ dirty = true;
+ mAddressee.setGivenName( mUI->mFirstName->currentText() );
+ }
+ // last name
+ if ( newValue( mUI->mLastName ) )
+ {
+ dirty = true;
+ mAddressee.setFamilyName( mUI->mLastName->currentText() );
+ }
+ // url
+ if ( newValue( mUI->mUrl ) )
+ {
+ dirty = true;
+ mAddressee.setUrl( KURL( mUI->mUrl->currentText() ) );
+ }
+
+ QStringList newVals;
+ // email
+ newVals = newValues( mUI->mEmails, numEmails );
+ for ( QStringList::Iterator it = newVals.begin(); it != newVals.end(); ++it )
+ {
+ dirty = true;
+ mAddressee.insertEmail( *it );
+ }
+ // home phone
+ newVals = newValues( mUI->mHomePhones, numHomePhones );
+ for ( QStringList::Iterator it = newVals.begin(); it != newVals.end(); ++it )
+ {
+ dirty = true;
+ mAddressee.insertPhoneNumber( KABC::PhoneNumber( *it, KABC::PhoneNumber::Home ) );
+ }
+ // work phone
+ newVals = newValues( mUI->mWorkPhones, numWorkPhones );
+ for ( QStringList::Iterator it = newVals.begin(); it != newVals.end(); ++it )
+ {
+ dirty = true;
+ mAddressee.insertPhoneNumber( KABC::PhoneNumber( *it, KABC::PhoneNumber::Work ) );
+ }
+ // mobile
+ newVals = newValues( mUI->mMobilePhones, numMobilePhones );
+ for ( QStringList::Iterator it = newVals.begin(); it != newVals.end(); ++it )
+ {
+ dirty = true;
+ mAddressee.insertPhoneNumber( KABC::PhoneNumber( *it, KABC::PhoneNumber::Cell ) );
+ }
+
+ if ( dirty )
+ {
+ // write the changed addressbook
+ mAddressBook->insertAddressee( mAddressee );
+
+ KABC::Ticket *ticket = mAddressBook->requestSaveTicket();
+ if ( !ticket )
+ kdWarning( 14000 ) << k_funcinfo << "WARNING: Resource is locked by other application!" << endl;
+ else
+ {
+ if ( !mAddressBook->save( ticket ) )
+ {
+ kdWarning( 14000 ) << k_funcinfo << "ERROR: Saving failed!" << endl;
+ mAddressBook->releaseSaveTicket( ticket );
+ }
+ }
+ kdDebug( 14000 ) << k_funcinfo << "Finished writing KABC" << endl;
+ }
+}
+
+bool KopeteAddressBookExport::newValue( QComboBox *combo )
+{
+ // all data in position 0 is from KABC, so if position 0 is selected,
+ // or if the selection is the same as the data at 0, return false
+ return !( combo->currentItem() == 0 ||
+ ( combo->text( combo->currentItem() ) == combo->text( 0 ) ) );
+}
+
+QStringList KopeteAddressBookExport::newValues( KListBox *listBox, uint counter )
+{
+ QStringList newValues;
+ // need to iterate all items except those from KABC and check if selected and not same as the first
+ // counter is the number of KABC items, and hence the index of the first non KABC item
+ for ( uint i = counter; i < listBox->count(); ++i )
+ {
+ if ( listBox->isSelected( i ) )
+ {
+ // check whether it matches any KABC item
+ bool duplicate = false;
+ for ( uint j = 0; j < counter; ++j )
+ {
+ if ( listBox->text( i ) == listBox->text( j ) )
+ duplicate = true;
+ }
+ if ( !duplicate )
+ newValues.append( listBox->text( i ) );
+ }
+ }
+ return newValues;
+}
diff --git a/kopete/kopete/contactlist/kopeteaddrbookexport.h b/kopete/kopete/contactlist/kopeteaddrbookexport.h
new file mode 100644
index 00000000..b4437c4e
--- /dev/null
+++ b/kopete/kopete/contactlist/kopeteaddrbookexport.h
@@ -0,0 +1,102 @@
+/*
+ kopeteaddrbookexport.h - Kopete Online Status
+
+ Logic for exporting data acquired from messaging systems to the
+ KDE address book
+
+ Copyright (c) 2004 by Will Stephenson <lists@stevello.free-online.co.uk>
+
+ Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KOPETEADDRBOOKEXPORT_H
+#define KOPETEADDRBOOKEXPORT_H
+
+#include <kabc/stdaddressbook.h>
+#include <kabc/addressee.h>
+
+#include "kopetecontactproperty.h"
+
+class AddressBookExportUI;
+class KDialogBase;
+class KListBox;
+class KComboBox;
+
+namespace Kopete
+{
+class Contact;
+class MetaContact;
+}
+
+class KopeteAddressBookExport : public QObject
+{
+public:
+ KopeteAddressBookExport( QWidget *parent, Kopete::MetaContact *mc );
+ ~KopeteAddressBookExport();
+
+ /**
+ * Display the dialog
+ * @return a QDialog return code
+ */
+ int showDialog();
+ /**
+ * Export the data to KABC if changed, omitting any duplicates
+ */
+ void exportData();
+
+protected:
+ /**
+ * Initialise the GUI labels with labels from KABC
+ */
+ void initLabels();
+ /**
+ * Populate the GUI with data from KABC
+ */
+ void fetchKABCData();
+ /**
+ * Populate a listbox with a given type of phone number
+ */
+ void fetchPhoneNumbers( KListBox * listBox, int type, uint& counter );
+ /**
+ * Populate the GUI with data from IM systems
+ */
+ void fetchIMData();
+ /**
+ * Populate a combobox with a contact's IM data
+ */
+ void populateIM( const Kopete::Contact *contact, const QPixmap &icon,
+ QComboBox *combo, const Kopete::ContactPropertyTmpl &property );
+ /**
+ * Populate a listbox with a contact's IM data
+ */
+ void populateIM( const Kopete::Contact *contact, const QPixmap &icon,
+ KListBox *combo, const Kopete::ContactPropertyTmpl &property );
+
+ /** Check the selected item is not the first (existing KABC) item, or the same as it */
+ bool newValue( QComboBox *combo );
+ QStringList newValues( KListBox *listBox, uint counter );
+
+ // the GUI
+ QWidget *mParent;
+ KDialogBase * mDialog;
+ QPixmap mAddrBookIcon;
+ AddressBookExportUI *mUI;
+ Kopete::MetaContact *mMetaContact;
+ KABC::AddressBook *mAddressBook;
+ KABC::Addressee mAddressee;
+
+ // counters tracking the number of KABC values where multiple values are possible in a single key
+ uint numEmails, numHomePhones, numWorkPhones, numMobilePhones;
+
+};
+
+#endif
diff --git a/kopete/kopete/contactlist/kopeteaddrbookexportui.ui b/kopete/kopete/contactlist/kopeteaddrbookexportui.ui
new file mode 100644
index 00000000..9613d44f
--- /dev/null
+++ b/kopete/kopete/contactlist/kopeteaddrbookexportui.ui
@@ -0,0 +1,149 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>AddressBookExportUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>AddressBookExportUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>598</width>
+ <height>651</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Merge with Address Book</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>mLblFirstName</cstring>
+ </property>
+ <property name="text">
+ <string>First name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>comboBox1</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>mLblHomePhone</cstring>
+ </property>
+ <property name="text">
+ <string>Home phone:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mPhones</cstring>
+ </property>
+ </widget>
+ <widget class="KListBox" row="5" column="1">
+ <property name="name">
+ <cstring>mWorkPhones</cstring>
+ </property>
+ <property name="selectionMode">
+ <enum>Extended</enum>
+ </property>
+ </widget>
+ <widget class="KListBox" row="6" column="1">
+ <property name="name">
+ <cstring>mMobilePhones</cstring>
+ </property>
+ <property name="selectionMode">
+ <enum>Extended</enum>
+ </property>
+ </widget>
+ <widget class="KListBox" row="4" column="1">
+ <property name="name">
+ <cstring>mHomePhones</cstring>
+ </property>
+ <property name="selectionMode">
+ <enum>Extended</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>mLblWorkPhone</cstring>
+ </property>
+ <property name="text">
+ <string>Work phone:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mPhones_2</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>mLblMobilePhone</cstring>
+ </property>
+ <property name="text">
+ <string>Mobile phone:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mPhones_3</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>mLblUrl</cstring>
+ </property>
+ <property name="text">
+ <string>URL:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>comboBox4</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="3" column="1">
+ <property name="name">
+ <cstring>mUrl</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>mFirstName</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>mLastName</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>mLblLastName</cstring>
+ </property>
+ <property name="text">
+ <string>Last name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>comboBox2</cstring>
+ </property>
+ </widget>
+ <widget class="KListBox" row="2" column="1">
+ <property name="name">
+ <cstring>mEmails</cstring>
+ </property>
+ <property name="selectionMode">
+ <enum>Extended</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>mLblEmail</cstring>
+ </property>
+ <property name="text">
+ <string>Email:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mEmails</cstring>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kopete/kopete/contactlist/kopetecontactlistview.cpp b/kopete/kopete/contactlist/kopetecontactlistview.cpp
new file mode 100644
index 00000000..b6b01a2f
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetecontactlistview.cpp
@@ -0,0 +1,2134 @@
+/*
+ kopetecontactlistview.cpp
+
+ Kopete Contactlist GUI
+
+ Copyright (c) 2001-2002 by Duncan Mac-Vicar Prett <duncan@kde.org>
+ Copyright (c) 2002 by Nick Betcher <nbetcher@usinternet.com>
+ Copyright (c) 2002 by Stefan Gehn <metz AT gehn.net>
+ Copyright (c) 2002-2005 by Olivier Goffart <ogoffart @kde.org>
+ Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
+ Copyright (c) 2004 by Richard Smith <kde@metafoo.co.uk>
+
+ Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#include "kopetecontactlistview.h"
+#include "kopeteuiglobal.h"
+
+#include <qcursor.h>
+#include <qdragobject.h>
+#include <qheader.h>
+#include <qstylesheet.h>
+#include <qtimer.h>
+#include <qtooltip.h>
+#include <qguardedptr.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmainwindow.h>
+#include <kmessagebox.h>
+#include <kpopupmenu.h>
+#include <kurldrag.h>
+#include <kmultipledrag.h>
+#include <kabc/stdaddressbook.h>
+#include <kabc/vcardconverter.h>
+
+#include <kdeversion.h>
+#include <kinputdialog.h>
+
+#include "addcontactwizard.h"
+#include "addcontactpage.h"
+#include "chatmessagepart.h"
+#include "kopeteaccount.h"
+#include "kopeteaccountmanager.h"
+#include "kopetecontactlist.h"
+#include "kopetemessageevent.h"
+#include "kopetegroup.h"
+#include "kopetegroupviewitem.h"
+#include "kopetemetacontact.h"
+#include "kopetemetacontactlvi.h"
+#include "kopeteprefs.h"
+#include "kopeteprotocol.h"
+#include "kopetestatusgroupviewitem.h"
+#include "kopetestdaction.h"
+#include "kopetechatsessionmanager.h"
+#include "kopetecontact.h"
+#include "kopetechatsession.h" //needed to send the URL
+#include "kopetemessage.h" //needed to send the URL
+#include "kopeteglobal.h"
+#include "kopetelviprops.h"
+#include "kopetegrouplistaction.h"
+
+#include <memory>
+
+class ContactListViewStrategy;
+
+class KopeteContactListViewPrivate
+{
+public:
+ std::auto_ptr<ContactListViewStrategy> viewStrategy;
+
+ void updateViewStrategy( KListView *view );
+};
+
+class ContactListViewStrategy
+{
+public:
+ ContactListViewStrategy( KListView *view )
+ : _listView( view )
+ {
+ view->clear();
+ }
+ virtual ~ContactListViewStrategy() {}
+ KListView *listView() { return _listView; }
+ void addCurrentItems()
+ {
+ // Add the already existing groups now
+ QPtrList<Kopete::Group> grps = Kopete::ContactList::self()->groups();
+ for ( QPtrListIterator<Kopete::Group> groupIt( grps ); groupIt.current(); ++groupIt )
+ addGroup( groupIt.current() );
+
+ // Add the already existing meta contacts now
+ QPtrList<Kopete::MetaContact> metaContacts = Kopete::ContactList::self()->metaContacts();
+ for ( QPtrListIterator<Kopete::MetaContact> it( metaContacts ); it.current(); ++it )
+ addMetaContact( it.current() );
+ }
+
+ virtual void addMetaContact( Kopete::MetaContact *mc ) = 0;
+ virtual void removeMetaContact( Kopete::MetaContact *mc ) = 0;
+
+ virtual void addGroup( Kopete::Group * ) {}
+
+ virtual void addMetaContactToGroup( Kopete::MetaContact *mc, Kopete::Group *gp ) = 0;
+ virtual void removeMetaContactFromGroup( Kopete::MetaContact *mc, Kopete::Group *gp ) = 0;
+ virtual void moveMetaContactBetweenGroups( Kopete::MetaContact *mc, Kopete::Group *from, Kopete::Group *to ) = 0;
+
+ virtual void metaContactStatusChanged( Kopete::MetaContact *mc ) = 0;
+
+protected:
+ // work around QListView design stupidity.
+ // GroupViewItem will be QListView-derived, or QListViewItem-derived.
+ template<typename GroupViewItem>
+ void addMetaContactToGroupInner( Kopete::MetaContact *mc, GroupViewItem *gpi )
+ {
+ // check if the contact isn't already in the group
+ for( QListViewItem *item = gpi->firstChild(); item; item = item->nextSibling() )
+ if ( KopeteMetaContactLVI *mci = dynamic_cast<KopeteMetaContactLVI*>(item) )
+ if ( mci->metaContact() == mc )
+ return;
+ (void) new KopeteMetaContactLVI( mc, gpi );
+ }
+
+ template<typename GroupViewItem>
+ void removeMetaContactFromGroupInner( Kopete::MetaContact *mc, GroupViewItem *gpi )
+ {
+ KopeteMetaContactLVI* mci;
+ QListViewItem* item = gpi->firstChild();
+ while(item) {
+ mci = dynamic_cast<KopeteMetaContactLVI*>(item);
+ item = item->nextSibling();
+
+ if ( mci && mci->metaContact() == mc )
+ delete mci;
+ }
+ }
+
+private:
+ KListView *_listView;
+};
+
+class ArrangeByGroupsViewStrategy : public ContactListViewStrategy
+{
+public:
+ ArrangeByGroupsViewStrategy( KListView *view )
+ : ContactListViewStrategy( view )
+ {
+ addCurrentItems();
+ }
+
+ void addMetaContact( Kopete::MetaContact *mc )
+ {
+ // create group items
+ Kopete::GroupList list = mc->groups();
+ for ( Kopete::Group *gp = list.first(); gp; gp = list.next() )
+ // will check to see if the contact is already in the group.
+ // this is inefficient but makes this function idempotent.
+ addMetaContactToGroup( mc, gp );
+ }
+ void removeMetaContact( Kopete::MetaContact *mc )
+ {
+ // usually, the list item will be deleted when the KMC is. however, we still
+ // need to make sure that the item count of the groups is correct.
+ // as a bonus, this allows us to remove a MC from the contact list without deleting it.
+ Kopete::GroupList list = mc->groups();
+ for ( Kopete::Group *gp = list.first(); gp; gp = list.next() )
+ removeMetaContactFromGroup( mc, gp );
+ }
+
+ void addGroup( Kopete::Group *group )
+ {
+ (void) findOrCreateGroupItem( group );
+ }
+
+ void addMetaContactToGroup( Kopete::MetaContact *mc, Kopete::Group *gp )
+ {
+ if ( KopeteGroupViewItem *gpi = findOrCreateGroupItem( gp ) )
+ addMetaContactToGroupInner( mc, gpi );
+ else
+ addMetaContactToGroupInner( mc, listView() );
+ }
+ void removeMetaContactFromGroup( Kopete::MetaContact *mc, Kopete::Group *gp )
+ {
+ if ( gp->type() == Kopete::Group::TopLevel )
+ removeMetaContactFromGroupInner( mc, listView() );
+ else if ( KopeteGroupViewItem *gpi = findGroupItem( gp ) )
+ {
+ removeMetaContactFromGroupInner( mc, gpi );
+
+ // update the group's display of its number of children.
+ // TODO: make the KopeteGroupViewItem not need this, by overriding insertItem and takeItem
+ gpi->refreshDisplayName();
+
+ // remove the temporary group if it's empty
+ if ( gpi->childCount() == 0 )
+ if ( gp->type() == Kopete::Group::Temporary )
+ delete gpi;
+ }
+ }
+ void moveMetaContactBetweenGroups( Kopete::MetaContact *mc, Kopete::Group *from, Kopete::Group *to )
+ {
+ // TODO: use takeItem and insertItem, and mci->movedGroup
+ addMetaContactToGroup( mc, to );
+ removeMetaContactFromGroup( mc, from );
+ }
+ void metaContactStatusChanged( Kopete::MetaContact * ) {}
+
+private:
+ KopeteGroupViewItem *findGroupItem( Kopete::Group *gp )
+ {
+ if ( gp->type() == Kopete::Group::TopLevel ) return 0;
+ for( QListViewItem *item = listView()->firstChild(); item; item = item->nextSibling() )
+ if ( KopeteGroupViewItem *gvi = dynamic_cast<KopeteGroupViewItem*>(item) )
+ if ( gvi->group() == gp )
+ return gvi;
+ return 0;
+ }
+ KopeteGroupViewItem *findOrCreateGroupItem( Kopete::Group *gp )
+ {
+ if ( gp->type() == Kopete::Group::TopLevel ) return 0;
+ if ( KopeteGroupViewItem *item = findGroupItem(gp) )
+ return item;
+ KopeteGroupViewItem *gpi = new KopeteGroupViewItem( gp, listView() );
+ // TODO: store as plugin data the expandedness of a group
+ // currently this requires a 'plugin' for the main UI.
+ gpi->setOpen( gp->isExpanded() );
+ return gpi;
+ }
+};
+
+class ArrangeByPresenceViewStrategy : public ContactListViewStrategy
+{
+public:
+ ArrangeByPresenceViewStrategy( KListView *view )
+ : ContactListViewStrategy( view )
+ , m_onlineItem( new KopeteStatusGroupViewItem( Kopete::OnlineStatus::Online, listView() ) )
+ , m_offlineItem( new KopeteStatusGroupViewItem( Kopete::OnlineStatus::Offline, listView() ) )
+ {
+ m_onlineItem->setOpen( true );
+ m_offlineItem->setOpen( true );
+ addCurrentItems();
+ }
+
+ void removeMetaContact( Kopete::MetaContact *mc )
+ {
+ // there's only three places we put metacontacts: online, offline and temporary.
+ removeMetaContactFromGroupInner( mc, m_onlineItem );
+ removeMetaContactFromGroupInner( mc, m_offlineItem );
+ if ( m_temporaryItem )
+ removeMetaContactFromGroupInner( mc, (KopeteGroupViewItem*)m_temporaryItem );
+ }
+
+ void addMetaContact( Kopete::MetaContact *mc )
+ {
+ updateMetaContact( mc );
+ }
+ void addMetaContactToGroup( Kopete::MetaContact *mc, Kopete::Group * )
+ {
+ updateMetaContact( mc );
+ }
+ void removeMetaContactFromGroup( Kopete::MetaContact *mc, Kopete::Group * )
+ {
+ updateMetaContact( mc );
+ }
+ void moveMetaContactBetweenGroups( Kopete::MetaContact *mc, Kopete::Group *, Kopete::Group * )
+ {
+ updateMetaContact( mc );
+ }
+ void metaContactStatusChanged( Kopete::MetaContact *mc )
+ {
+ updateMetaContact( mc );
+ }
+private:
+ void updateMetaContact( Kopete::MetaContact *mc )
+ {
+ // split into a ...Inner function and this one to make the short-circuiting logic easier
+ updateMetaContactInner( mc );
+
+ // FIXME: these items should do this for themselves...
+ m_onlineItem->setText(0,i18n("Online contacts (%1)").arg(m_onlineItem->childCount()));
+ m_offlineItem->setText(0,i18n("Offline contacts (%1)").arg(m_offlineItem->childCount()));
+ }
+ void updateMetaContactInner( Kopete::MetaContact *mc )
+ {
+ // this function basically *is* the arrange-by-presence strategy.
+ // given a metacontact, it removes it from any existing incorrect place and adds
+ // it to the correct place. usually it does this with takeItem and insertItem.
+
+ // if the metacontact is temporary, it should be only in the temporary group
+ if ( mc->isTemporary() )
+ {
+ removeMetaContactFromGroupInner( mc, m_onlineItem );
+ removeMetaContactFromGroupInner( mc, m_offlineItem );
+
+ // create temporary item on demand
+ if ( !m_temporaryItem )
+ {
+ m_temporaryItem = new KopeteGroupViewItem( Kopete::Group::temporary(), listView() );
+ m_temporaryItem->setOpen( true );
+ }
+
+ addMetaContactToGroupInner( mc, (KopeteGroupViewItem*)m_temporaryItem );
+ return;
+ }
+
+ // if it's not temporary, it should not be in the temporary group
+ if ( m_temporaryItem )
+ {
+ removeMetaContactFromGroupInner( mc, (KopeteGroupViewItem*)m_temporaryItem );
+
+ // remove temporary item if empty
+ if ( m_temporaryItem && m_temporaryItem->childCount() == 0 )
+ {
+ delete (KopeteGroupViewItem*)m_temporaryItem;
+ }
+ }
+
+ // check if the contact is already in the correct "group"
+ QListViewItem *currentGroup = mc->isOnline() ? m_onlineItem : m_offlineItem;
+ for( QListViewItem *lvi = currentGroup->firstChild(); lvi; lvi = lvi->nextSibling() )
+ if ( KopeteMetaContactLVI *kc = dynamic_cast<KopeteMetaContactLVI*>( lvi ) )
+ if ( kc->metaContact() == mc )
+ return;
+
+ // item not found in the right group; look for it in the other group
+ QListViewItem *oppositeGroup = mc->isOnline() ? m_offlineItem : m_onlineItem;
+ for( QListViewItem *lvi = oppositeGroup->firstChild(); lvi; lvi = lvi->nextSibling() )
+ {
+ if ( KopeteMetaContactLVI *kc = dynamic_cast<KopeteMetaContactLVI*>( lvi ) )
+ {
+ if ( kc->metaContact() == mc )
+ {
+ // found: move it over to the right group
+ oppositeGroup->takeItem(kc);
+ currentGroup->insertItem(kc);
+ return;
+ }
+ }
+ }
+
+ // item not found in either online neither offline groups: add it
+ (void) new KopeteMetaContactLVI( mc, currentGroup );
+ }
+
+ KopeteStatusGroupViewItem *m_onlineItem, *m_offlineItem;
+ QGuardedPtr<KopeteGroupViewItem> m_temporaryItem;
+};
+
+void KopeteContactListViewPrivate::updateViewStrategy( KListView *view )
+{
+ // this is a bit nasty, but this function needs changing if we add
+ // more view strategies anyway, so it should be fine.
+ bool bSortByGroup = (bool)dynamic_cast<ArrangeByGroupsViewStrategy*>(viewStrategy.get());
+ if ( !viewStrategy.get() || KopetePrefs::prefs()->sortByGroup() != bSortByGroup )
+ {
+ // delete old strategy first...
+ viewStrategy.reset( 0 );
+ // then create and store a new one
+ if ( KopetePrefs::prefs()->sortByGroup() )
+ viewStrategy.reset( new ArrangeByGroupsViewStrategy(view) );
+ else
+ viewStrategy.reset( new ArrangeByPresenceViewStrategy(view) );
+ }
+}
+
+// returns the next item in a depth-first descent of the list view.
+// much like QLVI::itemBelow but does not depend on visibility of items, etc.
+static QListViewItem *nextItem( QListViewItem *item )
+{
+ if ( QListViewItem *it = item->firstChild() )
+ return it;
+ while ( item && !item->nextSibling() )
+ item = item->parent();
+ if ( !item )
+ return 0;
+ return item->nextSibling();
+}
+
+
+
+KopeteContactListView::KopeteContactListView( QWidget *parent, const char *name )
+ : Kopete::UI::ListView::ListView( parent, name )
+{
+ d = new KopeteContactListViewPrivate;
+ m_undo=0L;
+ m_redo=0L;
+
+ mShowAsTree = KopetePrefs::prefs()->treeView();
+ if ( mShowAsTree )
+ {
+ setRootIsDecorated( true );
+ }
+ else
+ {
+ setRootIsDecorated( false );
+ setTreeStepSize( 0 );
+ }
+
+ d->updateViewStrategy( this );
+
+ setFullWidth( true );
+
+ connect( this, SIGNAL( contextMenu( KListView *, QListViewItem *, const QPoint & ) ),
+ SLOT( slotContextMenu( KListView *, QListViewItem *, const QPoint & ) ) );
+ connect( this, SIGNAL( expanded( QListViewItem * ) ),
+ SLOT( slotExpanded( QListViewItem * ) ) );
+ connect( this, SIGNAL( collapsed( QListViewItem * ) ),
+ SLOT( slotCollapsed( QListViewItem * ) ) );
+ connect( this, SIGNAL( executed( QListViewItem *, const QPoint &, int ) ),
+ SLOT( slotExecuted( QListViewItem *, const QPoint &, int ) ) );
+ connect( this, SIGNAL( selectionChanged() ), SLOT( slotViewSelectionChanged() ) );
+ connect( this, SIGNAL( itemRenamed( QListViewItem * ) ),
+ SLOT( slotItemRenamed( QListViewItem * ) ) );
+
+ connect( KopetePrefs::prefs(), SIGNAL( saved() ), SLOT( slotSettingsChanged() ) );
+
+ connect( Kopete::ContactList::self(), SIGNAL( selectionChanged() ),
+ SLOT( slotListSelectionChanged() ) );
+ connect( Kopete::ContactList::self(),
+ SIGNAL( metaContactAdded( Kopete::MetaContact * ) ),
+ SLOT( slotMetaContactAdded( Kopete::MetaContact * ) ) );
+ connect( Kopete::ContactList::self(),
+ SIGNAL( metaContactRemoved( Kopete::MetaContact * ) ),
+ SLOT( slotMetaContactDeleted( Kopete::MetaContact * ) ) );
+ connect( Kopete::ContactList::self(), SIGNAL( groupAdded( Kopete::Group * ) ),
+ SLOT( slotGroupAdded( Kopete::Group * ) ) );
+
+ connect( Kopete::ChatSessionManager::self(), SIGNAL( newEvent( Kopete::MessageEvent * ) ),
+ this, SLOT( slotNewMessageEvent( Kopete::MessageEvent * ) ) );
+
+ connect( this, SIGNAL( dropped( QDropEvent *, QListViewItem *, QListViewItem * ) ),
+ this, SLOT( slotDropped( QDropEvent *, QListViewItem *, QListViewItem * ) ) );
+
+ connect( &undoTimer, SIGNAL(timeout()) , this, SLOT (slotTimeout() ) );
+
+ addColumn( i18n( "Contacts" ), 0 ); //add an unique colums to add every contact
+ header()->hide(); // and hide the ugly header which show the single word "Contacts"
+
+ setAutoOpen( true );
+ setDragEnabled( true );
+ setAcceptDrops( true );
+ setItemsMovable( false );
+ setDropVisualizer( false );
+ setDropHighlighter( true );
+ setSelectionMode( QListView::Extended );
+
+ // Load in the user's initial settings
+ slotSettingsChanged();
+}
+
+void KopeteContactListView::initActions( KActionCollection *ac )
+{
+ actionUndo = KStdAction::undo( this , SLOT( slotUndo() ) , ac );
+ actionRedo = KStdAction::redo( this , SLOT( slotRedo() ) , ac );
+ actionUndo->setEnabled(false);
+ actionRedo->setEnabled(false);
+
+
+ new KAction( i18n( "Create New Group..." ), 0, 0, this, SLOT( addGroup() ),
+ ac, "AddGroup" );
+
+ actionSendMessage = KopeteStdAction::sendMessage(
+ this, SLOT( slotSendMessage() ), ac, "contactSendMessage" );
+ actionStartChat = KopeteStdAction::chat( this, SLOT( slotStartChat() ),
+ ac, "contactStartChat" );
+
+ actionMove = new KopeteGroupListAction( i18n( "&Move To" ), QString::fromLatin1( "editcut" ),
+ 0, this, SLOT( slotMoveToGroup() ), ac, "contactMove" );
+ actionCopy = new KopeteGroupListAction( i18n( "&Copy To" ), QString::fromLatin1( "editcopy" ), 0,
+ this, SLOT( slotCopyToGroup() ), ac, "contactCopy" );
+
+ actionRemove = KopeteStdAction::deleteContact( this, SLOT( slotRemove() ),
+ ac, "contactRemove" );
+ actionSendEmail = new KAction( i18n( "Send Email..." ), QString::fromLatin1( "mail_generic" ),
+ 0, this, SLOT( slotSendEmail() ), ac, "contactSendEmail" );
+ /* this actionRename is buggy, and useless with properties, removed in kopeteui.rc*/
+ actionRename = new KAction( i18n( "Rename" ), "filesaveas", 0,
+ this, SLOT( slotRename() ), ac, "contactRename" );
+ actionSendFile = KopeteStdAction::sendFile( this, SLOT( slotSendFile() ),
+ ac, "contactSendFile" );
+
+ actionAddContact = new KActionMenu( i18n( "&Add Contact" ),
+ QString::fromLatin1( "add_user" ), ac , "contactAddContact" );
+ actionAddContact->popupMenu()->insertTitle( i18n("Select Account") );
+
+ actionAddTemporaryContact = new KAction( i18n( "Add to Your Contact List" ), "add_user", 0,
+ this, SLOT( slotAddTemporaryContact() ), ac, "contactAddTemporaryContact" );
+
+ connect( Kopete::ContactList::self(), SIGNAL( metaContactSelected( bool ) ), this, SLOT( slotMetaContactSelected( bool ) ) );
+
+ connect( Kopete::AccountManager::self(), SIGNAL(accountRegistered( Kopete::Account* )), SLOT(slotAddSubContactActionNewAccount(Kopete::Account*)));
+ connect( Kopete::AccountManager::self(), SIGNAL(accountUnregistered( const Kopete::Account* )), SLOT(slotAddSubContactActionAccountDeleted(const Kopete::Account *)));
+
+ actionProperties = new KAction( i18n( "&Properties" ), "edit_user", Qt::Key_Alt + Qt::Key_Return,
+ this, SLOT( slotProperties() ), ac, "contactProperties" );
+
+ // Update enabled/disabled actions
+ slotViewSelectionChanged();
+}
+
+KopeteContactListView::~KopeteContactListView()
+{
+ delete d;
+}
+
+void KopeteContactListView::slotAddSubContactActionNewAccount(Kopete::Account* account)
+{
+ KAction *action = new KAction( account->accountLabel(), account->accountIcon(), 0 , this, SLOT(slotAddContact()), account);
+ m_accountAddContactMap.insert( account, action);
+ actionAddContact->insert( action );
+}
+
+void KopeteContactListView::slotAddSubContactActionAccountDeleted(const Kopete::Account *account)
+{
+ kdDebug(14000) << k_funcinfo << endl;
+ if ( m_accountAddContactMap.contains( account ) )
+ {
+ KAction *action = m_accountAddContactMap[account];
+ m_accountAddContactMap.remove( account );
+ actionAddContact->remove( action );
+ }
+}
+
+void KopeteContactListView::slotMetaContactAdded( Kopete::MetaContact *mc )
+{
+ d->viewStrategy->addMetaContact( mc );
+
+ connect( mc, SIGNAL( addedToGroup( Kopete::MetaContact *, Kopete::Group * ) ),
+ SLOT( slotAddedToGroup( Kopete::MetaContact *, Kopete::Group * ) ) );
+ connect( mc, SIGNAL( removedFromGroup( Kopete::MetaContact *, Kopete::Group * ) ),
+ SLOT( slotRemovedFromGroup( Kopete::MetaContact *, Kopete::Group * ) ) );
+ connect( mc, SIGNAL( movedToGroup( Kopete::MetaContact *, Kopete::Group *, Kopete::Group * ) ),
+ SLOT( slotMovedToGroup( Kopete::MetaContact *, Kopete::Group *, Kopete::Group * ) ) );
+ connect( mc, SIGNAL( onlineStatusChanged( Kopete::MetaContact *, Kopete::OnlineStatus::StatusType ) ),
+ SLOT( slotContactStatusChanged( Kopete::MetaContact * ) ) );
+}
+
+void KopeteContactListView::slotMetaContactDeleted( Kopete::MetaContact *mc )
+{
+ d->viewStrategy->removeMetaContact( mc );
+}
+
+void KopeteContactListView::slotMetaContactSelected( bool sel )
+{
+ bool set = sel;
+
+ if( sel )
+ {
+ Kopete::MetaContact *kmc = Kopete::ContactList::self()->selectedMetaContacts().first();
+ set = sel && kmc->isReachable();
+ actionAddTemporaryContact->setEnabled( sel && kmc->isTemporary() );
+ }
+ else
+ {
+ actionAddTemporaryContact->setEnabled(false);
+ }
+
+ actionSendMessage->setEnabled( set );
+ actionStartChat->setEnabled( set );
+ actionMove->setEnabled( sel ); // TODO: make available for several contacts
+ actionCopy->setEnabled( sel ); // TODO: make available for several contacts
+}
+
+void KopeteContactListView::slotAddedToGroup( Kopete::MetaContact *mc, Kopete::Group *to )
+{
+ d->viewStrategy->addMetaContactToGroup( mc, to );
+}
+
+void KopeteContactListView::slotRemovedFromGroup( Kopete::MetaContact *mc, Kopete::Group *from )
+{
+ d->viewStrategy->removeMetaContactFromGroup( mc, from );
+}
+
+void KopeteContactListView::slotMovedToGroup( Kopete::MetaContact *mc,
+ Kopete::Group *from, Kopete::Group *to )
+{
+ d->viewStrategy->moveMetaContactBetweenGroups( mc, from, to );
+}
+
+void KopeteContactListView::removeContact( Kopete::MetaContact *c )
+{
+ d->viewStrategy->removeMetaContact( c );
+}
+
+void KopeteContactListView::addGroup()
+{
+ QString groupName =
+ KInputDialog::getText( i18n( "New Group" ),
+ i18n( "Please enter the name for the new group:" ) );
+
+ if ( !groupName.isEmpty() )
+ addGroup( groupName );
+}
+
+void KopeteContactListView::addGroup( const QString &groupName )
+{
+ d->viewStrategy->addGroup( Kopete::ContactList::self()->findGroup(groupName) );
+}
+
+void KopeteContactListView::slotGroupAdded( Kopete::Group *group )
+{
+ d->viewStrategy->addGroup( group );
+}
+
+void KopeteContactListView::slotExpanded( QListViewItem *item )
+{
+ KopeteGroupViewItem *groupLVI = dynamic_cast<KopeteGroupViewItem *>( item );
+ if ( groupLVI )
+ {
+ groupLVI->group()->setExpanded( true );
+ groupLVI->updateIcon();
+ }
+
+ //workaround a bug in qt which make the items of a closed item not sorted. (qt 3.3.4 here)
+ delayedSort();
+}
+
+void KopeteContactListView::slotCollapsed( QListViewItem *item )
+{
+ KopeteGroupViewItem *groupLVI = dynamic_cast<KopeteGroupViewItem*>( item );
+ if ( groupLVI )
+ {
+ groupLVI->group()->setExpanded( false );
+ groupLVI->updateIcon();
+ }
+}
+
+void KopeteContactListView::slotContextMenu( KListView * /*listview*/,
+ QListViewItem *item, const QPoint &point )
+{
+ // FIXME: this code should be moved to the various list view item classes.
+ KopeteMetaContactLVI *metaLVI = dynamic_cast<KopeteMetaContactLVI *>( item );
+ KopeteGroupViewItem *groupvi = dynamic_cast<KopeteGroupViewItem *>( item );
+
+ if ( item && !item->isSelected() )
+ {
+ clearSelection();
+ item->setSelected( true );
+ }
+
+ if ( !item )
+ {
+ clearSelection();
+ //Clear selection doesn't update lists of selected contact if the item is onlt heilighted (see bug 106090)
+ Kopete::ContactList::self()->setSelectedItems( QPtrList<Kopete::MetaContact>() , QPtrList<Kopete::Group>() );
+ }
+
+ int nb = Kopete::ContactList::self()->selectedMetaContacts().count() +
+ Kopete::ContactList::self()->selectedGroups().count();
+
+ KMainWindow *window = dynamic_cast<KMainWindow *>(topLevelWidget());
+ if ( !window )
+ {
+ kdError( 14000 ) << k_funcinfo << "Main window not found, unable to display context-menu; "
+ << "Kopete::UI::Global::mainWidget() = " << Kopete::UI::Global::mainWidget() << endl;
+ return;
+ }
+
+ if ( metaLVI && nb == 1 )
+ {
+ int px = mapFromGlobal( point ).x() - ( header()->sectionPos( header()->mapToIndex( 0 ) ) +
+ treeStepSize() * ( item->depth() + ( rootIsDecorated() ? 1 : 0 ) ) + itemMargin() );
+ int py = mapFromGlobal( point ).y() - itemRect( item ).y() - (header()->isVisible() ? header()->height() : 0) ;
+
+ //kdDebug( 14000 ) << k_funcinfo << "x: " << px << ", y: " << py << endl;
+ Kopete::Contact *c = metaLVI->contactForPoint( QPoint( px, py ) ) ;
+ if ( c )
+ {
+ KPopupMenu *p = c->popupMenu();
+ connect( p, SIGNAL( aboutToHide() ), p, SLOT( deleteLater() ) );
+ p->popup( point );
+ }
+ else
+ {
+ KPopupMenu *popup = dynamic_cast<KPopupMenu *>(
+ window->factory()->container( "contact_popup", window ) );
+ if ( popup )
+ {
+ QString title = i18n( "Translators: format: '<nickname> (<online status>)'", "%1 (%2)" ).
+ arg( metaLVI->metaContact()->displayName(), metaLVI->metaContact()->statusString() );
+
+ if ( title.length() > 43 )
+ title = title.left( 40 ) + QString::fromLatin1( "..." );
+
+ if ( popup->title( 0 ).isNull() )
+ popup->insertTitle ( title, 0, 0 );
+ else
+ popup->changeTitle ( 0, title );
+
+ // Submenus for separate contact actions
+ bool sep = false; //FIXME: find if there is already a separator in the end - Olivier
+ QPtrList<Kopete::Contact> it = metaLVI->metaContact()->contacts();
+ for( Kopete::Contact *c = it.first(); c; c = it.next() )
+ {
+ if( sep )
+ {
+ popup->insertSeparator();
+ sep = false;
+ }
+
+ KPopupMenu *contactMenu = it.current()->popupMenu();
+ connect( popup, SIGNAL( aboutToHide() ), contactMenu, SLOT( deleteLater() ) );
+ QString nick=c->property(Kopete::Global::Properties::self()->nickName()).value().toString();
+ QString text= nick.isEmpty() ? c->contactId() : i18n( "Translators: format: '<displayName> (<id>)'", "%2 <%1>" ). arg( c->contactId(), nick );
+ text=text.replace("&","&&"); // cf BUG 115449
+
+ if ( text.length() > 41 )
+ text = text.left( 38 ) + QString::fromLatin1( "..." );
+
+ popup->insertItem( c->onlineStatus().iconFor( c, 16 ), text , contactMenu );
+ }
+
+ popup->popup( point );
+ }
+ }
+ }
+ else if ( groupvi && nb == 1 )
+ {
+ KPopupMenu *popup = dynamic_cast<KPopupMenu *>(
+ window->factory()->container( "group_popup", window ) );
+ if ( popup )
+ {
+ QString title = groupvi->group()->displayName();
+ if ( title.length() > 32 )
+ title = title.left( 30 ) + QString::fromLatin1( "..." );
+
+ if( popup->title( 0 ).isNull() )
+ popup->insertTitle( title, 0, 0 );
+ else
+ popup->changeTitle( 0, title );
+
+ popup->popup( point );
+ }
+ }
+ else if ( nb >= 1 )
+ {
+ KPopupMenu *popup = dynamic_cast<KPopupMenu *>(
+ window->factory()->container( "contactlistitems_popup", window ) );
+ if ( popup )
+ popup->popup( point );
+ }
+ else
+ {
+ KPopupMenu *popup = dynamic_cast<KPopupMenu *>(
+ window->factory()->container( "contactlist_popup", window ) );
+ if ( popup )
+ {
+ if ( popup->title( 0 ).isNull() )
+ popup->insertTitle( i18n( "Kopete" ), 0, 0 );
+
+ popup->popup( point );
+ }
+ }
+}
+
+void KopeteContactListView::slotShowAddContactDialog()
+{
+ ( new AddContactWizard( Kopete::UI::Global::mainWidget() ) )->show();
+}
+
+void KopeteContactListView::slotSettingsChanged( void )
+{
+ mShowAsTree = KopetePrefs::prefs()->treeView();
+ if ( mShowAsTree )
+ {
+ setRootIsDecorated( true );
+ setTreeStepSize( 20 );
+ }
+ else
+ {
+ setRootIsDecorated( false );
+ setTreeStepSize( 0 );
+ }
+
+ // maybe setEffects should read these from KopetePrefs itself?
+ Kopete::UI::ListView::Item::setEffects( KopetePrefs::prefs()->contactListAnimation(),
+ KopetePrefs::prefs()->contactListFading(),
+ KopetePrefs::prefs()->contactListFolding() );
+
+ d->updateViewStrategy( this );
+
+ slotUpdateAllGroupIcons();
+ update();
+}
+
+void KopeteContactListView::slotUpdateAllGroupIcons()
+{
+ // FIXME: groups can (should?) do this for themselves
+ // HACK: assume all groups are top-level. works for now, until the fixme above is dealt with
+ for ( QListViewItem *it = firstChild(); it; it = it->nextSibling() )
+ if ( KopeteGroupViewItem *gpi = dynamic_cast<KopeteGroupViewItem*>( it ) )
+ gpi->updateIcon();
+}
+
+void KopeteContactListView::slotExecuted( QListViewItem *item, const QPoint &p, int /* col */ )
+{
+ item->setSelected( false );
+ KopeteMetaContactLVI *metaContactLVI = dynamic_cast<KopeteMetaContactLVI *>( item );
+
+ QPoint pos = viewport()->mapFromGlobal( p );
+ Kopete::Contact *c = 0L;
+ if ( metaContactLVI )
+ {
+ // Try if we are clicking a protocol icon. If so, open a direct
+ // connection for that protocol
+ QRect r = itemRect( item );
+ QPoint relativePos( pos.x() - r.left() - ( treeStepSize() *
+ ( item->depth() + ( rootIsDecorated() ? 1 : 0 ) ) +
+ itemMargin() ), pos.y() - r.top() );
+ c = metaContactLVI->contactForPoint( relativePos );
+ if( c )
+ c->execute();
+ else
+ metaContactLVI->execute();
+ }
+}
+
+void KopeteContactListView::slotContactStatusChanged( Kopete::MetaContact *mc )
+{
+ d->viewStrategy->metaContactStatusChanged( mc );
+}
+
+void KopeteContactListView::slotDropped(QDropEvent *e, QListViewItem *, QListViewItem *after)
+{
+ if(!acceptDrag(e))
+ return;
+
+ KopeteMetaContactLVI *dest_metaLVI=dynamic_cast<KopeteMetaContactLVI*>(after);
+ KopeteGroupViewItem *dest_groupLVI=dynamic_cast<KopeteGroupViewItem*>(after);
+
+ if( const_cast<const QWidget *>( e->source() ) == this )
+ {
+ QPtrListIterator<KopeteMetaContactLVI> it( m_selectedContacts );
+
+ while ( it.current() )
+ {
+ Kopete::Contact *source_contact=0L;
+ KopeteMetaContactLVI *source_metaLVI = it.current();
+ ++it;
+
+ if(source_metaLVI)
+ source_contact = source_metaLVI->contactForPoint( m_startDragPos );
+
+ if(source_metaLVI && dest_groupLVI)
+ {
+ if(source_metaLVI->group() == dest_groupLVI->group())
+ return;
+
+ if(source_metaLVI->metaContact()->isTemporary())
+ {
+ addDraggedContactToGroup(source_metaLVI->metaContact(),dest_groupLVI->group());
+ }
+ else
+ {
+ moveDraggedContactToGroup( source_metaLVI->metaContact(),
+ source_metaLVI->group(), dest_groupLVI->group() );
+ }
+ }
+ else if(source_metaLVI && !dest_metaLVI && !dest_groupLVI)
+ {
+ if ( source_metaLVI->group()->type() == Kopete::Group::TopLevel )
+ return;
+
+ if(source_metaLVI->metaContact()->isTemporary())
+ {
+ addDraggedContactToGroup(source_metaLVI->metaContact() , Kopete::Group::topLevel() );
+ }
+ else
+ {
+ moveDraggedContactToGroup( source_metaLVI->metaContact(),
+ source_metaLVI->group(), Kopete::Group::topLevel() );
+ }
+ }
+ else if(source_contact && dest_metaLVI) //we are moving a contact to another metacontact
+ {
+ if(source_metaLVI->metaContact()->isTemporary())
+ {
+ addDraggedContactToMetaContact( source_contact,dest_metaLVI->metaContact() );
+ }
+ else
+ {
+ UndoItem *u=new UndoItem;
+ u->type=UndoItem::MetaContactChange;
+ u->metacontact=source_metaLVI->metaContact();
+ u->group=source_metaLVI->group();
+ u->args << source_contact->protocol()->pluginId() << source_contact->account()->accountId() << source_contact->contactId();
+ u->args << source_metaLVI->metaContact()->displayName();
+ insertUndoItem(u);
+
+ source_contact->setMetaContact(dest_metaLVI->metaContact());
+ }
+ }
+ }
+ }
+ else if( e->provides("kopete/x-contact") )
+ {
+ QString contactInfo = QString::fromUtf8( e->encodedData("kopete/x-contact") );
+ QString protocolId = contactInfo.section( QChar( 0xE000 ), 0, 0 );
+ QString accountId = contactInfo.section( QChar( 0xE000 ), 1, 1 );
+ QString contactId = contactInfo.section( QChar( 0xE000 ), 2 );
+
+ addDraggedContactByInfo( protocolId, accountId, contactId, after );
+
+ }
+ else if( e->provides("text/uri-list") )
+ {
+ if ( !QUriDrag::canDecode( e ) )
+ {
+ e->ignore();
+ return;
+ }
+
+ KURL::List urlList;
+ KURLDrag::decode( e, urlList );
+
+ for ( KURL::List::Iterator it = urlList.begin(); it != urlList.end(); ++it )
+ {
+ KURL url = (*it);
+ if( url.protocol() == QString::fromLatin1("kopetemessage") )
+ {
+ //Add a contact
+ addDraggedContactByInfo( url.queryItem("protocolId"),
+ url.queryItem("accountId"), url.host(), after );
+ }
+ else if( dest_metaLVI )
+ {
+ QPoint p = contentsToViewport(e->pos());
+ int px = p.x() - ( header()->sectionPos( header()->mapToIndex( 0 ) ) +
+ treeStepSize() * ( dest_metaLVI->depth() + ( rootIsDecorated() ? 1 : 0 ) ) + itemMargin() );
+ int py = p.y() - itemRect( dest_metaLVI ).y();
+
+ Kopete::Contact *c = dest_metaLVI->contactForPoint( QPoint( px, py ) );
+
+ if( url.isLocalFile() )
+ {
+ //send a file
+ if(c)
+ c->sendFile( url );
+ else
+ dest_metaLVI->metaContact()->sendFile( url );
+ }
+ else
+ {
+ //this is a URL, send the URL in a message
+ if(!c)
+ {
+ // We need to know which contact was chosen as the preferred
+ // in order to message it
+ c = dest_metaLVI->metaContact()->execute();
+ }
+
+ if (!c)
+ return;
+
+ Kopete::Message msg(c->account()->myself(), c, url.url(),
+ Kopete::Message::Outbound);
+ c->manager(Kopete::Contact::CanCreate)->sendMessage(msg);
+ }
+ }
+ }
+ e->acceptAction();
+ }
+}
+
+void KopeteContactListView::moveDraggedContactToGroup( Kopete::MetaContact *contact, Kopete::Group *from, Kopete::Group *to )
+{
+ contact->moveToGroup( from, to );
+
+ insertUndoItem( new UndoItem( UndoItem::MetaContactCopy , contact, to ) );
+ UndoItem *u=new UndoItem( UndoItem::MetaContactRemove, contact, to );
+ u->isStep=false;
+ insertUndoItem(u);
+}
+
+void KopeteContactListView::addDraggedContactToGroup( Kopete::MetaContact *contact, Kopete::Group *group )
+{
+ int r=KMessageBox::questionYesNo( Kopete::UI::Global::mainWidget(),
+ i18n( "<qt>Would you like to add <b>%1</b> to your contact list as a member of <b>%2</b>?</qt>" )
+ .arg( contact->displayName(), group->displayName() ),
+ i18n( "Kopete" ), i18n("Add"), i18n("Do Not Add"),
+ "addTemporaryWhenMoving" );
+
+ if( r == KMessageBox::Yes )
+ {
+ contact->setTemporary( false, group );
+ Kopete::ContactList::self()->addMetaContact( contact );
+ insertUndoItem( new UndoItem( UndoItem::MetaContactAdd, contact, group ) );
+ }
+}
+
+void KopeteContactListView::addDraggedContactToMetaContact( Kopete::Contact *contact, Kopete::MetaContact *parent )
+{
+ int r = KMessageBox::questionYesNo( Kopete::UI::Global::mainWidget(),
+ i18n( "<qt>Would you like to add <b>%1</b> to your contact list as a child contact of <b>%2</b>?</qt>" )
+ .arg( contact->contactId(), parent->displayName() ),
+ i18n( "Kopete" ), i18n("Add"), i18n("Do Not Add"),
+ "addTemporaryWhenMoving" );
+
+ if( r == KMessageBox::Yes )
+ {
+ contact->setMetaContact(parent);
+
+ UndoItem *u=new UndoItem;
+ u->type=UndoItem::ContactAdd;
+ u->args << contact->protocol()->pluginId() << contact->account()->accountId() << contact->contactId();
+ insertUndoItem(u);
+ }
+}
+
+void KopeteContactListView::addDraggedContactByInfo( const QString &protocolId, const QString &accountId,
+ const QString &contactId, QListViewItem *after )
+{
+ kdDebug(14000) << k_funcinfo << "protocolId=" << protocolId <<
+ ", accountId=" << accountId << ", contactId=" << contactId << endl;
+
+ Kopete::Account *account = Kopete::AccountManager::self()->findAccount( protocolId,accountId );
+ if( account )
+ {
+ QDict<Kopete::Contact> contacts = account->contacts();
+ Kopete::Contact *source_contact = contacts[ contactId ];
+
+ if( source_contact )
+ {
+ if( source_contact->metaContact()->isTemporary() )
+ {
+ KopeteMetaContactLVI *dest_metaLVI=dynamic_cast<KopeteMetaContactLVI*>(after);
+ KopeteGroupViewItem *dest_groupLVI=dynamic_cast<KopeteGroupViewItem*>(after);
+
+ if( dest_metaLVI )
+ {
+ addDraggedContactToMetaContact( source_contact, dest_metaLVI->metaContact() );
+ }
+ else if( dest_groupLVI )
+ {
+ addDraggedContactToGroup( source_contact->metaContact(),dest_groupLVI->group() );
+ }
+ else
+ {
+ addDraggedContactToGroup( source_contact->metaContact(), Kopete::Group::topLevel() );
+ }
+ }
+ else
+ {
+ KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
+ i18n("<qt>This contact is already on your contact list. It is a child contact of <b>%1</b></qt>")
+ .arg( source_contact->metaContact()->displayName() )
+ );
+ }
+ }
+ }
+}
+
+bool KopeteContactListView::acceptDrag(QDropEvent *e) const
+{
+ QListViewItem *source=currentItem();
+ QListViewItem *parent;
+ QListViewItem *afterme;
+ // Due to a little design problem in KListView::findDrop() we can't
+ // call it directly from a const method until KDE 4.0, but as the
+ // method is in fact const we can of course get away with a
+ // const_cast...
+ const_cast<KopeteContactListView *>( this )->findDrop( e->pos(), parent, afterme );
+
+ KopeteMetaContactLVI *dest_metaLVI=dynamic_cast<KopeteMetaContactLVI*>(afterme);
+
+ if( const_cast<const QWidget *>( e->source() ) == this )
+ {
+ KopeteMetaContactLVI *source_metaLVI=dynamic_cast<KopeteMetaContactLVI*>(source);
+ KopeteGroupViewItem *dest_groupLVI=dynamic_cast<KopeteGroupViewItem*>(afterme);
+ Kopete::Contact *source_contact=0L;
+
+ if(source_metaLVI)
+ source_contact = source_metaLVI->contactForPoint( m_startDragPos );
+
+ if( source_metaLVI && dest_groupLVI && !source_contact)
+ { //we are moving a metacontact to another group
+ if(source_metaLVI->group() == dest_groupLVI->group())
+ return false;
+ if ( dest_groupLVI->group()->type() == Kopete::Group::Temporary )
+ return false;
+ // if(source_metaLVI->metaContact()->isTemporary())
+ // return false;
+ return true;
+ }
+ else if(source_metaLVI && !dest_metaLVI && !dest_groupLVI && !source_contact)
+ { //we are moving a metacontact to toplevel
+ if ( source_metaLVI->group()->type() == Kopete::Group::TopLevel )
+ return false;
+ // if(source_metaLVI->metaContact()->isTemporary())
+ // return false;
+
+ return true;
+ }
+ else if(source_contact && dest_metaLVI) //we are moving a contact to another metacontact
+ {
+ if(source_contact->metaContact() == dest_metaLVI->metaContact() )
+ return false;
+ if(dest_metaLVI->metaContact()->isTemporary())
+ return false;
+ return true;
+ }
+/* else if(source_groupLVI && dest_groupLVI) //we are moving a group to another group
+ {
+ if(dest_groupLVI->group() == Kopete::Group::temporary)
+ return false;
+ if(source_groupLVI->group() == Kopete::Group::temporary)
+ return false;
+ if(source_groupLVI->group()->parentGroup() == dest_groupLVI->group() )
+ return false;
+ Kopete::Group *g=dest_groupLVI->group()->parentGroup();
+ while(g && g != Kopete::Group::toplevel)
+ {
+ if(g==source_groupLVI->group())
+ return false;
+ g=g->parentGroup();
+ }
+ return true;
+ }
+ else if(source_groupLVI && !dest_groupLVI && dest_metaLVI) //we are moving a group to toplevel
+ {
+ if(source_groupLVI->group() == Kopete::Group::temporary)
+ return false;
+ if(source_groupLVI->group()->parentGroup() == Kopete::Group::toplevel)
+ return false;
+ return true;
+ }*/
+ }
+ else
+ {
+ if( e->provides( "text/uri-list" ) )
+ {
+ //we are sending a file (or dragging from the chat view)
+ if( dest_metaLVI )
+ {
+ QPoint p=contentsToViewport(e->pos());
+ int px = p.x() - ( header()->sectionPos( header()->mapToIndex( 0 ) ) +
+ treeStepSize() * ( dest_metaLVI->depth() + ( rootIsDecorated() ? 1 : 0 ) ) + itemMargin() );
+ int py = p.y() - itemRect( dest_metaLVI ).y();
+ Kopete::Contact *c = dest_metaLVI->contactForPoint( QPoint( px, py ) ) ;
+
+ if( c ? !c->isReachable() : !dest_metaLVI->metaContact()->isReachable() )
+ return false; //If the pointed contact is not reachable, abort
+
+ if( c ? c->canAcceptFiles() : dest_metaLVI->metaContact()->canAcceptFiles() )
+ {
+ // If the pointed contact, or the metacontact if no contact are
+ // pointed can accept file, return true in everycase
+ return true;
+ }
+ }
+
+ if ( !QUriDrag::canDecode(e) )
+ return false;
+
+ KURL::List urlList;
+ KURLDrag::decode( e, urlList );
+
+ for ( KURL::List::Iterator it = urlList.begin(); it != urlList.end(); ++it )
+ {
+ if( (*it).protocol() != QString::fromLatin1("kopetemessage") && (*it).isLocalFile() )
+ return false; //we can't send links if a locale file is in link
+ }
+
+ return true; //we will send a link
+ }
+ else if( e->provides( "application/x-qlistviewitem" ) )
+ {
+ //Coming from chat members
+ return true;
+ }
+ else
+ {
+ QString text;
+ QTextDrag::decode(e, text);
+ kdDebug(14000) << k_funcinfo << "drop with mimetype:" << e->format() << " data as text:" << text << endl;
+ }
+
+ }
+
+ return false;
+}
+
+void KopeteContactListView::findDrop(const QPoint &pos, QListViewItem *&parent,
+ QListViewItem *&after)
+{
+ //Since KDE 3.1.1 , the original find Drop return 0L for afterme if the group is open.
+ //This woraround allow us to keep the highlight of the item, and give always a correct position
+ parent=0L;
+ QPoint p (contentsToViewport(pos));
+ after=itemAt(p);
+}
+
+
+void KopeteContactListView::contentsMousePressEvent( QMouseEvent *e )
+{
+ KListView::contentsMousePressEvent( e );
+ if (e->button() == LeftButton )
+ {
+ QPoint p=contentsToViewport(e->pos());
+ QListViewItem *i=itemAt( p );
+ if( i )
+ {
+ //Maybe we are starting a drag?
+ //memorize the position to know later if the user move a small contacticon
+
+ int px = p.x() - ( header()->sectionPos( header()->mapToIndex( 0 ) ) +
+ treeStepSize() * ( i->depth() + ( rootIsDecorated() ? 1 : 0 ) ) + itemMargin() );
+ int py = p.y() - itemRect( i ).y();
+
+ m_startDragPos = QPoint( px , py );
+ }
+ }
+}
+
+void KopeteContactListView::slotNewMessageEvent(Kopete::MessageEvent *event)
+{
+ Kopete::Message msg=event->message();
+ //only for single chat
+ if(msg.from() && msg.to().count()==1)
+ {
+ Kopete::MetaContact *m=msg.from()->metaContact();
+ if(!m)
+ return;
+
+ for ( QListViewItem *item = firstChild(); item; item = nextItem(item) )
+ if ( KopeteMetaContactLVI *li = dynamic_cast<KopeteMetaContactLVI*>(item) )
+ if ( li->metaContact() == m )
+ li->catchEvent(event);
+ }
+}
+
+QDragObject *KopeteContactListView::dragObject()
+{
+ // Discover what the drag started on.
+ // If it's a MetaContactLVI, it was either on the MCLVI itself
+ // or on one of the child contacts
+ // Once we know this,
+ // we set the pixmap for the drag to the MC's pixmap
+ // or the child contact's small icon
+
+ QListViewItem *currentLVI = currentItem();
+ if( !currentLVI )
+ return 0L;
+
+ KopeteMetaContactLVI *metaLVI = dynamic_cast<KopeteMetaContactLVI*>( currentLVI );
+ if( !metaLVI )
+ return 0L;
+
+ QPixmap pm;
+ Kopete::Contact *c = metaLVI->contactForPoint( m_startDragPos );
+ KMultipleDrag *drag = new KMultipleDrag( this );
+ drag->addDragObject( new QStoredDrag("application/x-qlistviewitem", 0L ) );
+
+ QStoredDrag *d = new QStoredDrag("kopete/x-metacontact", 0L );
+ d->setEncodedData( metaLVI->metaContact()->metaContactId().utf8() );
+ drag->addDragObject( d );
+
+ if ( c ) // dragging a contact
+ {
+ QStoredDrag *d = new QStoredDrag("kopete/x-contact", 0L );
+ d->setEncodedData( QString( c->protocol()->pluginId() +QChar( 0xE000 )+ c->account()->accountId() +QChar( 0xE000 )+ c->contactId() ).utf8() );
+ drag->addDragObject( d );
+
+ pm = c->onlineStatus().iconFor( c, 12 ); // FIXME: fixed icon scaling
+ }
+ else // dragging a metacontact
+ {
+ // FIXME: first start at rendering the whole MC incl small icons
+ // into a pixmap to drag - anyone know how to complete this?
+ //QPainter p( pm );
+ //source_metaLVI->paintCell( p, cg?, width(), 0, 0 );
+ pm = SmallIcon( metaLVI->metaContact()->statusIcon() );
+ }
+
+ KABC::Addressee address = KABC::StdAddressBook::self()->findByUid(
+ metaLVI->metaContact()->metaContactId()
+ );
+
+ if( !address.isEmpty() )
+ {
+ drag->addDragObject( new QTextDrag( address.fullEmail(), 0L ) );
+ KABC::VCardConverter converter;
+ QString vcard = converter.createVCard( address );
+ if( !vcard.isNull() )
+ {
+ QStoredDrag *vcardDrag = new QStoredDrag("text/x-vcard", 0L );
+ vcardDrag->setEncodedData( vcard.utf8() );
+ drag->addDragObject( vcardDrag );
+ }
+ }
+
+ //QSize s = pm.size();
+ drag->setPixmap( pm /*, QPoint( s.width() , s.height() )*/ );
+
+ return drag;
+}
+
+void KopeteContactListView::slotViewSelectionChanged()
+{
+ QPtrList<Kopete::MetaContact> contacts;
+ QPtrList<Kopete::Group> groups;
+
+ m_selectedContacts.clear();
+ m_selectedGroups.clear();
+
+ QListViewItemIterator it( this );
+ while ( it.current() )
+ {
+ QListViewItem *item = it.current();
+ ++it;
+
+ if ( item->isSelected() )
+ {
+ KopeteMetaContactLVI *metaLVI=dynamic_cast<KopeteMetaContactLVI*>(item);
+ if(metaLVI)
+ {
+ m_selectedContacts.append( metaLVI );
+ if(!contacts.contains(metaLVI->metaContact()))
+ contacts.append( metaLVI->metaContact() );
+ }
+ KopeteGroupViewItem *groupLVI=dynamic_cast<KopeteGroupViewItem*>(item);
+ if(groupLVI)
+ {
+ m_selectedGroups.append( groupLVI );
+ if(!groups.contains(groupLVI->group()))
+ groups.append( groupLVI->group() );
+
+ }
+ }
+ }
+
+ // will cause slotListSelectionChanged to be called to update our actions.
+ Kopete::ContactList::self()->setSelectedItems(contacts , groups);
+}
+
+void KopeteContactListView::slotListSelectionChanged()
+{
+ QPtrList<Kopete::MetaContact> contacts = Kopete::ContactList::self()->selectedMetaContacts();
+ QPtrList<Kopete::Group> groups = Kopete::ContactList::self()->selectedGroups();
+
+ //TODO: update the list to select the items that should be selected.
+ // make sure slotViewSelectionChanged is *not* called.
+ updateActionsForSelection( contacts, groups );
+}
+
+void KopeteContactListView::updateActionsForSelection(
+ QPtrList<Kopete::MetaContact> contacts, QPtrList<Kopete::Group> groups )
+{
+ bool singleContactSelected = groups.isEmpty() && contacts.count() == 1;
+ bool inkabc=false;
+ if(singleContactSelected)
+ {
+ QString kabcid=contacts.first()->metaContactId();
+ inkabc= !kabcid.isEmpty() && !kabcid.contains(":");
+ }
+
+ actionSendFile->setEnabled( singleContactSelected && contacts.first()->canAcceptFiles());
+ actionAddContact->setEnabled( singleContactSelected && !contacts.first()->isTemporary());
+ actionSendEmail->setEnabled( inkabc );
+
+ if( singleContactSelected )
+ {
+ actionRename->setText(i18n("Rename Contact"));
+ actionRemove->setText(i18n("Remove Contact"));
+ actionSendMessage->setText(i18n("Send Single Message..."));
+ actionRename->setEnabled(true);
+ actionRemove->setEnabled(true);
+ actionAddContact->setText(i18n("&Add Subcontact"));
+ actionAddContact->setEnabled(!contacts.first()->isTemporary());
+ }
+ else if( groups.count() == 1 && contacts.isEmpty() )
+ {
+ actionRename->setText(i18n("Rename Group"));
+ actionRemove->setText(i18n("Remove Group"));
+ actionSendMessage->setText(i18n("Send Message to Group"));
+ actionRename->setEnabled(true);
+ actionRemove->setEnabled(true);
+ actionSendMessage->setEnabled(true);
+ actionAddContact->setText(i18n("&Add Contact to Group"));
+ actionAddContact->setEnabled(groups.first()->type()==Kopete::Group::Normal);
+ }
+ else
+ {
+ actionRename->setText(i18n("Rename"));
+ actionRemove->setText(i18n("Remove"));
+ actionRename->setEnabled(false);
+ actionRemove->setEnabled(contacts.count()+groups.count());
+ actionAddContact->setEnabled(false);
+ }
+
+ actionMove->setCurrentItem( -1 );
+ actionCopy->setCurrentItem( -1 );
+
+ actionProperties->setEnabled( ( groups.count() + contacts.count() ) == 1 );
+}
+
+void KopeteContactListView::slotSendMessage()
+{
+ Kopete::MetaContact *m=Kopete::ContactList::self()->selectedMetaContacts().first();
+ Kopete::Group *group = Kopete::ContactList::self()->selectedGroups().first();
+ if(m)
+ m->sendMessage();
+ else
+ if(group)
+ group->sendMessage();
+}
+
+void KopeteContactListView::slotStartChat()
+{
+ Kopete::MetaContact *m=Kopete::ContactList::self()->selectedMetaContacts().first();
+ if(m)
+ m->startChat();
+}
+
+void KopeteContactListView::slotSendFile()
+{
+ Kopete::MetaContact *m=Kopete::ContactList::self()->selectedMetaContacts().first();
+ if(m)
+ m->sendFile(KURL());
+}
+
+ void KopeteContactListView::slotSendEmail()
+{
+ //I borrowed this from slotSendMessage
+ Kopete::MetaContact *m=Kopete::ContactList::self()->selectedMetaContacts().first();
+ if ( !m->metaContactId().isEmpty( ) ) // check if in kabc
+ {
+ KABC::Addressee addressee = KABC::StdAddressBook::self()->findByUid( m->metaContactId() );
+ if ( !addressee.isEmpty() )
+ {
+ QString emailAddr = addressee.fullEmail();
+
+ kdDebug( 14000 ) << "Email: " << emailAddr << "!" << endl;
+ if ( !emailAddr.isEmpty() )
+ kapp->invokeMailer( emailAddr, QString::null );
+ else
+ KMessageBox::queuedMessageBox( this, KMessageBox::Sorry, i18n( "There is no email address set for this contact in the KDE address book." ), i18n( "No Email Address in Address Book" ) );
+ }
+ else
+ KMessageBox::queuedMessageBox( this, KMessageBox::Sorry, i18n( "This contact was not found in the KDE address book. Check that a contact is selected in the properties dialog." ), i18n( "Not Found in Address Book" ) );
+ }
+ else
+ KMessageBox::queuedMessageBox( this, KMessageBox::Sorry, i18n( "This contact is not associated with a KDE address book entry, where the email address is stored. Check that a contact is selected in the properties dialog." ), i18n( "Not Found in Address Book" ) );
+}
+
+void KopeteContactListView::slotMoveToGroup()
+{
+ KopeteMetaContactLVI *metaLVI=dynamic_cast<KopeteMetaContactLVI*>(currentItem());
+ if(!metaLVI)
+ return;
+ Kopete::MetaContact *m=metaLVI->metaContact();
+ Kopete::Group *g=metaLVI->group();
+
+ //FIXME What if two groups have the same name?
+ Kopete::Group *to = actionMove->currentItem() ?
+ Kopete::ContactList::self()->findGroup( actionMove->currentText() ) :
+ Kopete::Group::topLevel();
+
+ if( !to || to->type() == Kopete::Group::Temporary )
+ return;
+
+ if(m->isTemporary())
+ {
+ if( KMessageBox::questionYesNo( Kopete::UI::Global::mainWidget(),
+ i18n( "<qt>Would you like to add this contact to your contact list?</qt>" ),
+ i18n( "Kopete" ), i18n("Add"), i18n("Do Not Add"),
+ "addTemporaryWhenMoving" ) == KMessageBox::Yes )
+ {
+ m->setTemporary(false,to);
+
+ insertUndoItem( new UndoItem( UndoItem::MetaContactAdd , m ) );
+ }
+ }
+ else if( !m->groups().contains( to ) )
+ {
+ m->moveToGroup( g, to );
+
+ insertUndoItem( new UndoItem( UndoItem::MetaContactCopy , m , to ) );
+
+ UndoItem *u=new UndoItem( UndoItem::MetaContactRemove, m, g );
+ u->isStep=false;
+ insertUndoItem(u);
+ }
+
+ actionMove->setCurrentItem( -1 );
+}
+
+void KopeteContactListView::slotCopyToGroup()
+{
+ Kopete::MetaContact *m =
+ Kopete::ContactList::self()->selectedMetaContacts().first();
+
+ if(!m)
+ return;
+
+ //FIXME! what if two groups have the same name?
+ Kopete::Group *to = actionCopy->currentItem() ?
+ Kopete::ContactList::self()->findGroup( actionCopy->currentText() ) :
+ Kopete::Group::topLevel();
+
+ if( !to || to->type() == Kopete::Group::Temporary )
+ return;
+
+ if( m->isTemporary() )
+ return;
+
+ if( !m->groups().contains( to ) )
+ {
+ m->addToGroup( to );
+
+ insertUndoItem( new UndoItem( UndoItem::MetaContactCopy , m , to ) );
+ }
+
+ actionCopy->setCurrentItem( -1 );
+}
+
+
+
+void KopeteContactListView::slotRemove()
+{
+ QPtrList<Kopete::MetaContact> contacts = Kopete::ContactList::self()->selectedMetaContacts();
+ QPtrList<Kopete::Group> groups = Kopete::ContactList::self()->selectedGroups();
+
+ if(groups.count() + contacts.count() == 0)
+ return;
+
+ QStringList items;
+ for( Kopete::Group *it = groups.first(); it; it = groups.next() )
+ {
+ if(!it->displayName().isEmpty())
+ items.append( it->displayName() );
+ }
+ for( Kopete::MetaContact *it = contacts.first(); it; it = contacts.next() )
+ {
+ if(!it->displayName().isEmpty() )
+ items.append( it->displayName() );
+ }
+
+ if( items.count() <= 1 )
+ {
+ // we are deleting an empty contact
+ QString msg;
+ if( !contacts.isEmpty() )
+ {
+ msg = i18n( "<qt>Are you sure you want to remove the contact <b>%1</b>" \
+ " from your contact list?</qt>" )
+ .arg( contacts.first()->displayName() ) ;
+ }
+ else if( !groups.isEmpty() )
+ {
+ msg = i18n( "<qt>Are you sure you want to remove the group <b>%1</b> " \
+ "and all contacts that are contained within it?</qt>" )
+ .arg( groups.first()->displayName() );
+ }
+ else
+ return; // this should never happen
+
+ if( KMessageBox::warningContinueCancel( this, msg, i18n( "Remove" ), KGuiItem(i18n("Remove"),"editdelete") ,
+ "askRemovingContactOrGroup" , KMessageBox::Notify | KMessageBox::Dangerous ) !=
+ KMessageBox::Continue )
+ {
+ return;
+ }
+ }
+ else
+ {
+ QString msg = groups.isEmpty() ?
+ i18n( "Are you sure you want to remove these contacts " \
+ "from your contact list?" ) :
+ i18n( "Are you sure you want to remove these groups and " \
+ "contacts from your contact list?" );
+
+ if( KMessageBox::warningContinueCancelList( this, msg, items, i18n("Remove"),
+ KGuiItem(i18n("Remove"),"editdelete"), "askRemovingContactOrGroup",
+ KMessageBox::Notify | KMessageBox::Dangerous ) != KMessageBox::Continue )
+ {
+ return;
+ }
+ }
+
+ bool undo_step=true; //only the first undo item we will add will be a step
+
+ for( Kopete::MetaContact *mc = contacts.first(); mc; mc = contacts.next() )
+ {
+ if(mc->groups().count()==1 || mc->isTemporary() )
+ Kopete::ContactList::self()->removeMetaContact( mc );
+ else
+ {
+ //try to guess from what group we are removing that contact.
+ QListViewItemIterator lvi_it( this );
+ while ( lvi_it.current() )
+ {
+ QListViewItem *item = lvi_it.current();
+ ++lvi_it;
+
+ if ( item->isSelected() )
+ {
+ KopeteMetaContactLVI *metaLVI=dynamic_cast<KopeteMetaContactLVI*>(item);
+ if(metaLVI && metaLVI->metaContact() == mc )
+ {
+ if(mc->groups().count()==1)
+ {
+ Kopete::ContactList::self()->removeMetaContact( mc );
+ break;
+ }
+ else
+ {
+ mc->removeFromGroup(metaLVI->group());
+ insertUndoItem( new UndoItem( UndoItem::MetaContactRemove , mc , metaLVI->group() ) );
+ m_undo->isStep=undo_step; //if there is several selected contacts.
+ undo_step=false;
+ }
+ //let's continue, it's possible this contact is selected several times
+ }
+ }
+ }
+ }
+ }
+
+ for( Kopete::Group *it = groups.first(); it; it = groups.next() )
+ {
+ QPtrList<Kopete::MetaContact> list = it->members();
+ for( list.first(); list.current(); list.next() )
+ {
+ Kopete::MetaContact *mc = list.current();
+ if(mc->groups().count()==1)
+ Kopete::ContactList::self()->removeMetaContact(mc);
+ else
+ mc->removeFromGroup(it);
+ }
+
+ if( !it->members().isEmpty() )
+ {
+ kdDebug(14000) << "KopeteContactListView::slotRemove(): "
+ << "all subMetaContacts are not removed... Aborting" << endl;
+ continue;
+ }
+
+ Kopete::ContactList::self()->removeGroup( it );
+ }
+}
+
+void KopeteContactListView::slotRename()
+{
+ if ( KopeteMetaContactLVI *metaLVI = dynamic_cast<KopeteMetaContactLVI *>( currentItem() ) )
+ {
+ metaLVI->setRenameEnabled( 0, true);
+ metaLVI->startRename( 0 );
+ }
+ else if ( KopeteGroupViewItem *groupLVI = dynamic_cast<KopeteGroupViewItem *>( currentItem() ) )
+ {
+ if ( !KopetePrefs::prefs()->sortByGroup() )
+ return;
+ groupLVI->setRenameEnabled( 0, true);
+ groupLVI->startRename( 0 );
+ }
+}
+
+void KopeteContactListView::slotAddContact()
+{
+ if( !sender() )
+ return;
+
+ Kopete::MetaContact *metacontact =
+ Kopete::ContactList::self()->selectedMetaContacts().first();
+ Kopete::Group *group =
+ Kopete::ContactList::self()->selectedGroups().first();
+ Kopete::Account *account = dynamic_cast<Kopete::Account*>( sender()->parent() );
+
+ if ( ( metacontact && metacontact->isTemporary() ) ||
+ (group && group->type()!=Kopete::Group::Normal ) )
+ return;
+
+
+ if( account && ( metacontact || group) )
+ {
+ KDialogBase *addDialog = new KDialogBase( this, "addDialog", true,
+ i18n( "Add Contact" ), KDialogBase::Ok|KDialogBase::Cancel,
+ KDialogBase::Ok, true );
+
+ AddContactPage *addContactPage =
+ account->protocol()->createAddContactWidget( addDialog, account );
+
+ if (!addContactPage)
+ {
+ kdDebug(14000) << k_funcinfo <<
+ "Error while creating addcontactpage" << endl;
+ }
+ else
+ {
+ addDialog->setMainWidget( addContactPage );
+ if( addDialog->exec() == QDialog::Accepted )
+ {
+ if( addContactPage->validateData() )
+ {
+ if(!metacontact)
+ {
+ metacontact = new Kopete::MetaContact();
+ metacontact->addToGroup( group );
+ if (addContactPage->apply( account, metacontact ))
+ {
+ Kopete::ContactList::self()->addMetaContact( metacontact );
+ }
+ else
+ {
+ delete metacontact;
+ }
+ }
+ else
+ {
+ addContactPage->apply( account, metacontact );
+ }
+ }
+ }
+ }
+ addDialog->deleteLater();
+ }
+}
+
+void KopeteContactListView::slotAddTemporaryContact()
+{
+ Kopete::MetaContact *metacontact =
+ Kopete::ContactList::self()->selectedMetaContacts().first();
+ if( metacontact )
+ {
+/* int r=KMessageBox::questionYesNo( Kopete::UI::Global::mainWidget(),
+ i18n( "<qt>Would you like to add this contact to your contact list?</qt>" ),
+ i18n( "Kopete" ), i18n("Add"), i18n("Do Not Add"),
+ "addTemporaryWhenMoving" );
+
+ if(r==KMessageBox::Yes)*/
+ if(metacontact->isTemporary() )
+ metacontact->setTemporary( false );
+ }
+}
+
+void KopeteContactListView::slotProperties()
+{
+// kdDebug(14000) << k_funcinfo << "Called" << endl;
+
+ KopeteMetaContactLVI *metaLVI =
+ dynamic_cast<KopeteMetaContactLVI *>( currentItem() );
+ KopeteGroupViewItem *groupLVI =
+ dynamic_cast<KopeteGroupViewItem *>( currentItem() );
+
+ if(metaLVI)
+ {
+
+ KopeteMetaLVIProps *propsDialog =
+ new KopeteMetaLVIProps( metaLVI, 0L, "propsDialog" );
+
+ propsDialog->exec(); // modal
+ delete propsDialog;
+
+ /*
+ if( metaLVI->group()->useCustomIcon() )
+ {
+ metaLVI->updateCustomIcons( mShowAsTree );
+ }
+ else
+ {
+ }
+ */
+ metaLVI->repaint();
+ }
+ else if(groupLVI)
+ {
+ KopeteGVIProps *propsDialog =
+ new KopeteGVIProps( groupLVI, 0L, "propsDialog");
+
+ propsDialog->exec(); // modal
+ delete propsDialog;
+
+ groupLVI->updateIcon();
+ }
+}
+
+void KopeteContactListView::slotItemRenamed( QListViewItem */*item*/ )
+{
+ //everithing is now done in KopeteMetaContactLVI::rename
+
+/* KopeteMetaContactLVI *metaLVI = dynamic_cast<KopeteMetaContactLVI *>( item );
+ Kopete::MetaContact *m= metaLVI ? metaLVI->metaContact() : 0L ;
+ if ( m )
+ {
+ m->setDisplayName( metaLVI->text( 0 ) );
+ }
+ else
+ {
+ //group are handled differently in KopeteGroupViewItem
+ // kdWarning( 14000 ) << k_funcinfo << "Unknown list view item '" << item
+ // << "' renamed, ignoring item" << endl;
+ }
+ */
+}
+
+void KopeteContactListView::insertUndoItem( KopeteContactListView::UndoItem *u)
+{
+ u->next=m_undo;
+ m_undo=u;
+ actionUndo->setEnabled(true);
+ while(m_redo)
+ {
+ UndoItem *i=m_redo->next;
+ delete m_redo;
+ m_redo=i;
+ }
+ actionRedo->setEnabled(false);
+ undoTimer.start(10*60*1000);
+}
+
+
+void KopeteContactListView::slotUndo()
+{
+ bool step = false;
+ while(m_undo && !step)
+ {
+ bool success=false;
+ switch (m_undo->type)
+ {
+ case UndoItem::MetaContactAdd:
+ {
+ Kopete::MetaContact *m=m_undo->metacontact;
+ if(m)
+ {
+ m->setTemporary(true);
+ success=true;
+ }
+ break;
+ }
+ case UndoItem::MetaContactCopy:
+ {
+ Kopete::MetaContact *m=m_undo->metacontact;
+ Kopete::Group *to=m_undo->group;
+ if( m && to )
+ {
+ m->removeFromGroup( to );
+ success=true;
+ }
+ break;
+ }
+ case UndoItem::MetaContactRemove:
+ {
+ Kopete::MetaContact *m=m_undo->metacontact;
+ Kopete::Group *g=m_undo->group;
+ if( m && g )
+ {
+ m->addToGroup( g );
+ success=true;
+ }
+ break;
+ }
+ case UndoItem::MetaContactRename:
+ {
+ Kopete::MetaContact *m=m_undo->metacontact;
+ if( m )
+ {
+ // make a copy
+ QStringList undoArgs = m_undo->args;
+ Kopete::MetaContact::PropertySource undoSource = m_undo->nameSource;
+ // set undo undo
+ // set the source first
+ m_undo->nameSource = m->displayNameSource();
+ if ( m->displayNameSource() == Kopete::MetaContact::SourceCustom )
+ {
+ m_undo->args[0] = m->customDisplayName();
+ }
+ else if ( m->displayNameSource() == Kopete::MetaContact::SourceContact )
+ {
+ Kopete::Contact* c = m->displayNameSourceContact();
+ m_undo->args[0] = c->contactId();
+ m_undo->args[1] = c->protocol()->pluginId();
+ m_undo->args[2] = c->account()->accountId();
+ }
+ // source kabc requires no arguments
+
+ // do the undo
+ if ( undoSource == Kopete::MetaContact::SourceContact )
+ { // do undo
+ Kopete::Contact *c = Kopete::ContactList::self()->findContact( undoArgs[1], undoArgs[2], undoArgs[0]);
+ if (!c)
+ {
+ success=false;
+ break;
+ }
+ // do undo
+ m->setDisplayNameSourceContact(c);
+ m->setDisplayNameSource(Kopete::MetaContact::SourceContact);
+ }
+ else if ( undoSource == Kopete::MetaContact::SourceCustom )
+ {
+ m->setDisplayName(undoArgs[0]);
+ m->setDisplayNameSource(Kopete::MetaContact::SourceCustom);
+ }
+ else if ( undoSource == Kopete::MetaContact::SourceKABC )
+ {
+ m->setDisplayNameSource(Kopete::MetaContact::SourceKABC);
+ }
+ success=true;
+ }
+ break;
+ }
+ case UndoItem::GroupRename:
+ {
+ if( m_undo->group )
+ {
+ const QString old=m_undo->group->displayName();
+ m_undo->group->setDisplayName( m_undo->args[0] );
+ m_undo->args[0]=old;
+ success=true;
+ }
+ break;
+ }
+ case UndoItem::MetaContactChange:
+ {
+ Kopete::Contact *c=Kopete::ContactList::self()->findContact(m_undo->args[0] , m_undo->args[1], m_undo->args[2] ) ;
+ if(c)
+ {
+ success=true;
+ if(m_undo->metacontact)
+ c->setMetaContact(m_undo->metacontact);
+ else
+ {
+ Kopete::MetaContact *m=new Kopete::MetaContact;
+ m->addToGroup(m_undo->group);
+ m->setDisplayName(m_undo->args[3]);
+ c->setMetaContact(m);
+ Kopete::ContactList::self()->addMetaContact(m);
+ }
+ m_undo->metacontact=c->metaContact(); //for the redo
+ }
+ break;
+ }
+ case UndoItem::ContactAdd:
+ {
+ Kopete::Contact *c=Kopete::ContactList::self()->findContact(m_undo->args[0] , m_undo->args[1], m_undo->args[2] ) ;
+ if(c)
+ {
+ success=true;
+ Kopete::MetaContact *m=new Kopete::MetaContact;
+ m->setTemporary(true);
+ c->setMetaContact(m);
+ Kopete::ContactList::self()->addMetaContact(m);
+ m_undo->metacontact=c->metaContact();
+ }
+ break;
+ }
+ }
+
+ if(success) //the undo item has been correctly performed
+ {
+ step=m_undo->isStep;
+ UndoItem *u=m_undo->next;
+ m_undo->next=m_redo;
+ m_redo=m_undo;
+ m_undo=u;
+ }
+ else //something has been corrupted, clear all undo items
+ {
+ while(m_undo)
+ {
+ UndoItem *u=m_undo->next;
+ delete m_undo;
+ m_undo=u;
+ }
+ }
+ }
+ actionUndo->setEnabled(m_undo);
+ actionRedo->setEnabled(m_redo);
+ undoTimer.start(10*60*1000);
+}
+
+void KopeteContactListView::slotRedo()
+{
+ bool step = false;
+ while(m_redo && (!step || !m_redo->isStep ))
+ {
+ bool success=false;
+ switch (m_redo->type)
+ {
+ case UndoItem::MetaContactAdd:
+ {
+ Kopete::MetaContact *m=m_redo->metacontact;
+ if(m && m_redo->group)
+ {
+ m->setTemporary(false,m_redo->group);
+ success=true;
+ }
+ break;
+ }
+ case UndoItem::MetaContactCopy:
+ {
+ Kopete::MetaContact *m=m_redo->metacontact;
+ Kopete::Group *to=m_redo->group;
+ if( m && to )
+ {
+ m->addToGroup( to );
+ success=true;
+ }
+ break;
+ }
+ case UndoItem::MetaContactRemove:
+ {
+ Kopete::MetaContact *m=m_redo->metacontact;
+ Kopete::Group *g=m_redo->group;
+ if( m && g )
+ {
+ m->removeFromGroup( g );
+ success=true;
+ }
+ break;
+ }
+ case UndoItem::MetaContactRename:
+ {
+ /*
+ Kopete::MetaContact *m=m_redo->metacontact;
+ if( m )
+ {
+ const QString old=m->displayName();
+ if( m_redo->args[1].isEmpty() )
+ {
+ const QString name = m_redo->args[0];
+ m_redo->args[0] = m->displayNameSource()->contactId();
+ m_redo->args[1] = m->displayNameSource()->protocol()->pluginId();
+ m_redo->args[2] = m->displayNameSource()->account()->accountId();
+ m->setDisplayName( name );
+ }
+ else
+ {
+ const QString oldName = m->displayName();
+ QPtrList< Kopete::Contact > cList = m->contacts();
+ QPtrListIterator< Kopete::Contact > it (cList);
+ Kopete::Contact *c = Kopete::ContactList::self()->findContact( args[0], args[2], args[1]);
+ if ( !c)
+ return;
+ m->setNameSourceContact(c);
+ break;
+
+ m_redo->args[0] = oldName;
+ m_redo->args[1] = "";
+ m_redo->args[2] = "";
+ }
+ success=true;
+ }
+ */ //Why is this code commented ? - Olivier 2006-04
+ break;
+ }
+ case UndoItem::GroupRename:
+ {
+ if( m_redo->group )
+ {
+ const QString old=m_redo->group->displayName();
+ m_redo->group->setDisplayName( m_redo->args[0] );
+ m_redo->args[0]=old;
+ success=true;
+ }
+ break;
+ }
+ case UndoItem::MetaContactChange:
+ case UndoItem::ContactAdd:
+ {
+ Kopete::Contact *c=Kopete::ContactList::self()->findContact(m_redo->args[0] , m_redo->args[1], m_redo->args[2] ) ;
+ if(c && m_redo->metacontact)
+ {
+ success=true;
+ c->setMetaContact(m_redo->metacontact);
+ m_redo->metacontact=c->metaContact();
+ }
+ break;
+ }
+ }
+
+ if(success) //the undo item has been correctly performed
+ {
+ step=true;
+ UndoItem *u=m_redo->next;
+ m_redo->next=m_undo;
+ m_undo=m_redo;
+ m_redo=u;
+ }
+ else //something has been corrupted, clear all undo items
+ {
+ while(m_redo)
+ {
+ UndoItem *u=m_redo->next;
+ delete m_redo;
+ m_redo=u;
+ }
+ }
+ }
+ actionUndo->setEnabled(m_undo);
+ actionRedo->setEnabled(m_redo);
+ undoTimer.start(10*60*1000);
+}
+
+void KopeteContactListView::slotTimeout()
+{
+ undoTimer.stop();
+
+ //we will keep one (complete) undo action
+ UndoItem *Sdel=m_undo;
+ while(Sdel && !Sdel->isStep)
+ Sdel=Sdel->next;
+
+ if(Sdel) while( Sdel->next )
+ {
+ UndoItem *u=Sdel->next->next;
+ delete Sdel->next;
+ Sdel->next=u;
+ }
+ actionUndo->setEnabled(m_undo);
+ while(m_redo)
+ {
+ UndoItem *i=m_redo->next;
+ delete m_redo;
+ m_redo=i;
+ }
+ actionRedo->setEnabled(false);
+}
+
+#include "kopetecontactlistview.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
diff --git a/kopete/kopete/contactlist/kopetecontactlistview.h b/kopete/kopete/contactlist/kopetecontactlistview.h
new file mode 100644
index 00000000..43c60ebe
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetecontactlistview.h
@@ -0,0 +1,252 @@
+/*
+ kopetecontactlistview.h
+
+ Kopete Contactlist GUI
+
+ Copyright (c) 2001-2002 by Duncan Mac-Vicar Prett <duncan@kde.org>
+ Copyright (c) 2002 by Nick Betcher <nbetcher@usinternet.com>
+ Copyright (c) 2002 by Stefan Gehn <metz AT gehn.net>
+ Copyright (c) 2002-2005 by Olivier Goffart <ogoffart @ kde.org>
+ Copyright (c) 2004 by Richard Smith <kde@metafoo.co.uk>
+
+ Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KOPETE_CONTACTLISTVIEW_H
+#define KOPETE_CONTACTLISTVIEW_H
+
+#include "kopetelistview.h"
+#include "kopetemetacontact.h"
+
+#include <qpixmap.h>
+#include <qptrlist.h>
+#include <qstringlist.h>
+#include <qrect.h>
+#include <qtimer.h>
+#include <qguardedptr.h>
+
+class KopeteMetaContactLVI;
+class KopeteGroupViewItem;
+class KopeteStatusGroupViewItem;
+class KRootPixmap;
+class KActionCollection;
+class KAction;
+class KListAction;
+class KActionMenu;
+
+class KopeteContactListViewPrivate;
+
+namespace Kopete
+{
+class Contact;
+class MetaContact;
+class Group;
+class MessageEvent;
+}
+
+/**
+ * @author Duncan Mac-Vicar P. <duncan@kde.org>
+ */
+class KopeteContactListView : public Kopete::UI::ListView::ListView
+{
+ Q_OBJECT
+
+public:
+ KopeteContactListView( QWidget *parent = 0, const char *name = 0 );
+ ~KopeteContactListView();
+
+ /**
+ * Init MetaContact related actions
+ */
+ void initActions(KActionCollection*);
+
+ /**
+ * Add a given group name and return it
+ */
+ void addGroup( const QString &groupName );
+
+ /**
+ * Are we displaying as a tree view (true), or in a flat list (false)?
+ * @todo make this an enum
+ */
+ bool showAsTree() { return mShowAsTree; }
+
+public slots:
+ /**
+ * Remove all KopeteMetaContactLVI of a metaContact
+ */
+ void removeContact( Kopete::MetaContact *contact );
+
+ /**
+ * Prompt the user for the group name (slot)
+ */
+ void addGroup();
+
+protected:
+ virtual void contentsMousePressEvent( QMouseEvent *e );
+
+ virtual bool acceptDrag(QDropEvent *e) const;
+
+ /**
+ * Start a drag operation
+ * @return a KMultipleDrag containing: 1) A QStoredDrag of type "application/x-qlistviewitem", 2) If the MC is associated with a KABC entry, i) a QTextDrag containing their email address, and ii) their vCard representation.
+ */
+ virtual QDragObject *dragObject();
+
+ /**
+ * Since KDE 3.1.1 , the original find Drop return 0L for afterme if the group is open.
+ * This woraround allow us to keep the highlight of the item, and give always a correct position
+ */
+ virtual void findDrop(const QPoint &pos, QListViewItem *&parent, QListViewItem *&after);
+
+ /**
+ * The selected items have changed; update our actions to show what's possible.
+ */
+ void updateActionsForSelection( QPtrList<Kopete::MetaContact> contacts, QPtrList<Kopete::Group> groups );
+
+private slots:
+ /**
+ * When an account is added, so we add it to the menu action
+ */
+ void slotAddSubContactActionNewAccount(Kopete::Account*);
+ /**
+ * When an account is destroyed, the child add subcontact action is deleted
+ * so we remove it from the menu action
+ */
+ void slotAddSubContactActionAccountDeleted(const Kopete::Account *);
+
+ void slotViewSelectionChanged();
+ void slotListSelectionChanged();
+ void slotContextMenu(KListView*,QListViewItem *item, const QPoint &point );
+ void slotExpanded( QListViewItem *item );
+ void slotCollapsed( QListViewItem *item );
+
+ void slotSettingsChanged( void );
+ void slotUpdateAllGroupIcons();
+ void slotExecuted( QListViewItem *item, const QPoint &pos, int c );
+
+ void slotAddedToGroup( Kopete::MetaContact *mc, Kopete::Group *to );
+ void slotRemovedFromGroup( Kopete::MetaContact *mc, Kopete::Group *from );
+ void slotMovedToGroup( Kopete::MetaContact *mc, Kopete::Group *from, Kopete::Group *to );
+
+ /**
+ * A meta contact was added to the contact list - update the view
+ */
+ void slotMetaContactAdded( Kopete::MetaContact *mc );
+ void slotMetaContactDeleted( Kopete::MetaContact *mc );
+ void slotMetaContactSelected( bool sel );
+
+ void slotGroupAdded(Kopete::Group *);
+
+ void slotContactStatusChanged( Kopete::MetaContact *mc );
+
+ void slotDropped(QDropEvent *e, QListViewItem *parent, QListViewItem*);
+
+ void slotShowAddContactDialog();
+ void slotNewMessageEvent(Kopete::MessageEvent *);
+
+ /**
+ * Handle renamed items by renaming the meta contact
+ */
+ void slotItemRenamed( QListViewItem *item );
+
+ /** Actions related slots **/
+ void slotSendMessage();
+ void slotStartChat();
+ void slotSendFile();
+ void slotSendEmail();
+ void slotMoveToGroup();
+ void slotCopyToGroup();
+ void slotRemove();
+ void slotRename();
+ void slotAddContact();
+ void slotAddTemporaryContact();
+ void slotProperties();
+ void slotUndo();
+ void slotRedo();
+
+ void slotTimeout();
+
+private:
+ bool mShowAsTree;
+
+ // TODO: do we really need to store these?
+ QPtrList<KopeteMetaContactLVI> m_selectedContacts;
+ QPtrList<KopeteGroupViewItem> m_selectedGroups;
+
+ bool mSortByGroup;
+ KRootPixmap *root;
+
+ QRect m_onItem;
+
+ QPoint m_startDragPos;
+
+ /* ACTIONS */
+ KAction *actionSendMessage;
+ KAction *actionStartChat;
+ KAction *actionSendFile;
+ KAction *actionSendEmail;
+ KListAction *actionMove;
+ KListAction *actionCopy;
+ KAction *actionRename;
+ KAction *actionRemove;
+ KAction *actionAddTemporaryContact;
+ KAction *actionProperties;
+ KAction *actionUndo;
+ KAction *actionRedo;
+
+ KopeteContactListViewPrivate *d;
+
+ void moveDraggedContactToGroup( Kopete::MetaContact *contact, Kopete::Group *from, Kopete::Group *to );
+ void addDraggedContactToGroup( Kopete::MetaContact *contact, Kopete::Group *group );
+ void addDraggedContactToMetaContact( Kopete::Contact *contact, Kopete::MetaContact *parent );
+ void addDraggedContactByInfo( const QString &protocolId, const QString &accountId,
+ const QString &contactId, QListViewItem *after );
+
+public:
+ struct UndoItem;
+ UndoItem *m_undo;
+ UndoItem *m_redo;
+ void insertUndoItem(UndoItem *u);
+ QTimer undoTimer;
+
+public:
+ // This is public so the chatwinodw can handle sub actions
+ // FIXME: do we not believe in accessor functions any more?
+ KActionMenu *actionAddContact;
+ QMap<const Kopete::Account *, KAction *> m_accountAddContactMap;
+};
+
+struct KopeteContactListView::UndoItem
+{
+ enum Type { MetaContactAdd, MetaContactRemove , MetaContactCopy , MetaContactRename, MetaContactChange, ContactAdd, GroupRename } type;
+ QStringList args;
+ QGuardedPtr<Kopete::MetaContact> metacontact;
+ QGuardedPtr<Kopete::Group> group;
+ UndoItem *next;
+ bool isStep;
+ Kopete::MetaContact::PropertySource nameSource;
+
+ UndoItem() : isStep(true) {}
+ UndoItem(Type t, Kopete::MetaContact *m=0L ,Kopete::Group *g=0L)
+ {
+ isStep=true;
+ type=t;
+ metacontact=m;
+ group=g;
+ next=0L;
+ }
+};
+
+
+#endif
+// vim: set noet ts=4 sts=4 sw=4:
diff --git a/kopete/kopete/contactlist/kopetegrouplistaction.cpp b/kopete/kopete/contactlist/kopetegrouplistaction.cpp
new file mode 100644
index 00000000..1556f9b6
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetegrouplistaction.cpp
@@ -0,0 +1,66 @@
+/*
+ kopetegrouplistcation.cpp - the action used for Move To and copy To
+
+ Copyright (c) 2002-2004 by Olivier Goffart <ogoffart @ kde.org>
+ Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
+
+ Kopete (c) 2001-2005 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+/* This code was previously in libkopete/ui/kopetestdactions.cpp */
+
+#include "kopetegrouplistaction.h"
+
+#include <kdebug.h>
+#include <kguiitem.h>
+#include <klocale.h>
+#include <kaction.h>
+#include <kwin.h>
+#include <kcmultidialog.h>
+
+#include "kopetecontactlist.h"
+#include "kopetegroup.h"
+
+KopeteGroupListAction::KopeteGroupListAction( const QString &text, const QString &pix, const KShortcut &cut, const QObject *receiver,
+ const char *slot, QObject *parent, const char *name )
+: KListAction( text, pix, cut, parent, name )
+{
+ connect( this, SIGNAL( activated() ), receiver, slot );
+
+ connect( Kopete::ContactList::self(), SIGNAL( groupAdded( Kopete::Group * ) ), this, SLOT( slotUpdateList() ) );
+ connect( Kopete::ContactList::self(), SIGNAL( groupRemoved( Kopete::Group * ) ), this, SLOT( slotUpdateList() ) );
+ connect( Kopete::ContactList::self(), SIGNAL( groupRenamed(Kopete::Group*, const QString& ) ), this, SLOT( slotUpdateList() ) );
+ slotUpdateList();
+}
+
+KopeteGroupListAction::~KopeteGroupListAction()
+{
+}
+
+void KopeteGroupListAction::slotUpdateList()
+{
+ QStringList groupList;
+
+ // Add groups to our list
+ QPtrList<Kopete::Group> groups = Kopete::ContactList::self()->groups();
+ for ( Kopete::Group *it = groups.first(); it; it = groups.next() )
+ {
+ if(it->type() == Kopete::Group::Normal)
+ groupList.append( it->displayName() );
+ }
+
+ groupList.sort();
+ groupList.prepend(QString::null); //add a separator;
+ groupList.prepend( i18n("Top Level") ); //the top-level group, with the id 0
+ setItems( groupList );
+}
+
+#include "kopetegrouplistaction.moc"
diff --git a/kopete/kopete/contactlist/kopetegrouplistaction.h b/kopete/kopete/contactlist/kopetegrouplistaction.h
new file mode 100644
index 00000000..3576f3ed
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetegrouplistaction.h
@@ -0,0 +1,44 @@
+/*
+ kopetegrouplistaction.h
+
+ Copyright (c) 2005 Olivier Goffart <ogoffart@ kde.org>
+
+
+ Kopete (c) 2005 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KOPETEGRLISTACT_H
+#define KOPETEGRLISTACT_H
+
+
+#include <kaction.h>
+
+
+/**
+ * Action used for Copy To and Move To
+ */
+class KopeteGroupListAction : public KListAction
+{
+ Q_OBJECT
+
+public:
+ KopeteGroupListAction( const QString &, const QString &, const KShortcut &,
+ const QObject *, const char *, QObject *, const char * );
+ ~KopeteGroupListAction();
+
+protected slots:
+ void slotUpdateList();
+private:
+ QStringList m_groupList;
+};
+
+#endif
diff --git a/kopete/kopete/contactlist/kopetegroupviewitem.cpp b/kopete/kopete/contactlist/kopetegroupviewitem.cpp
new file mode 100644
index 00000000..21b1cf79
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetegroupviewitem.cpp
@@ -0,0 +1,286 @@
+/*
+ kopeteonlinestatus.cpp - Kopete Online Status
+
+ Copyright (c) 2002-2004 by Olivier Goffart <ogoffart @ kde.org>
+ Copyright (c) 2003 by Martijn Klingens <klingens@kde.org>
+
+ Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#include <qpainter.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kapplication.h>
+
+#include "kopetecontactlistview.h"
+#include "kopetegroupviewitem.h"
+#include "kopetegroup.h"
+#include "kopeteonlinestatus.h"
+#include "kopeteprefs.h"
+#include "kopetemetacontactlvi.h"
+#include "kopetemetacontact.h"
+
+#include <memory>
+
+//using namespace Kopete::UI;
+
+class KopeteGroupViewItem::Private
+{
+public:
+ Kopete::UI::ListView::ImageComponent *image;
+ Kopete::UI::ListView::DisplayNameComponent *name;
+ Kopete::UI::ListView::TextComponent *count;
+ std::auto_ptr<Kopete::UI::ListView::ToolTipSource> toolTipSource;
+};
+
+namespace Kopete {
+namespace UI {
+namespace ListView {
+
+class GroupToolTipSource : public ToolTipSource
+{
+public:
+ GroupToolTipSource( KopeteGroupViewItem *gp )
+ : group( gp )
+ {
+ }
+ QString operator()( ComponentBase *, const QPoint &, QRect & )
+ {
+ return group->toolTip();
+ }
+private:
+ KopeteGroupViewItem *group;
+};
+
+} // END namespace ListView
+} // END namespace UI
+} // END namespace Kopete
+
+KopeteGroupViewItem::KopeteGroupViewItem( Kopete::Group *group_, QListView *parent, const char *name )
+: Kopete::UI::ListView::Item( parent, group_, name )
+{
+ m_group = group_;
+ initLVI();
+}
+
+KopeteGroupViewItem::KopeteGroupViewItem( Kopete::Group *group_, QListViewItem *parent, const char *name )
+ : Kopete::UI::ListView::Item( parent, group_, name )
+{
+ m_group = group_;
+ initLVI();
+}
+
+KopeteGroupViewItem::~KopeteGroupViewItem()
+{
+ delete d;
+}
+
+void KopeteGroupViewItem::initLVI()
+{
+ d = new Private;
+
+ d->toolTipSource.reset( new Kopete::UI::ListView::GroupToolTipSource( this ) );
+
+ using namespace Kopete::UI::ListView;
+ Component *hbox = new BoxComponent( this, BoxComponent::Horizontal );
+ d->image = new ImageComponent( hbox );
+ d->name = new DisplayNameComponent( hbox );
+ d->count = new TextComponent( hbox );
+
+ d->image->setToolTipSource( d->toolTipSource.get() );
+ d->name->setToolTipSource( d->toolTipSource.get() );
+ d->count->setToolTipSource( d->toolTipSource.get() );
+
+ connect( m_group, SIGNAL( displayNameChanged( Kopete::Group*, const QString& ) ),
+ this, SLOT( refreshDisplayName() ) );
+
+ connect( KopetePrefs::prefs(), SIGNAL( contactListAppearanceChanged() ),
+ SLOT( slotConfigChanged() ) );
+ connect( kapp, SIGNAL( appearanceChanged() ), SLOT( slotConfigChanged() ) );
+
+ connect( m_group, SIGNAL( iconAppearanceChanged() ), SLOT( updateIcon() ) );
+
+ refreshDisplayName();
+ slotConfigChanged();
+}
+
+Kopete::Group* KopeteGroupViewItem::group() const
+{
+ return m_group;
+}
+
+QString KopeteGroupViewItem::toolTip() const
+{
+ // TODO: add icon, and some more information than that which
+ // is already displayed in the list view item
+ // FIXME: post-KDE-3.3, make this better i18n-able
+ // currently it can't cause more problems than the contact list itself, at least.
+ return "<b>" + d->name->text() + "</b> " + d->count->text();
+}
+
+void KopeteGroupViewItem::slotConfigChanged()
+{
+ updateIcon();
+ updateVisibility();
+
+ d->name->setColor( KopetePrefs::prefs()->contactListGroupNameColor() );
+
+ QFont font = listView()->font();
+ if ( KopetePrefs::prefs()->contactListUseCustomFonts() )
+ font = KopetePrefs::prefs()->contactListCustomNormalFont();
+ d->name->setFont( font );
+
+ d->count->setFont( KopetePrefs::prefs()->contactListSmallFont() );
+}
+
+void KopeteGroupViewItem::refreshDisplayName()
+{
+ totalMemberCount = 0;
+ onlineMemberCount = 0;
+
+ for ( QListViewItem *lvi = firstChild(); lvi; lvi = lvi->nextSibling() )
+ {
+ if ( KopeteMetaContactLVI *kc = dynamic_cast<KopeteMetaContactLVI*>( lvi ) )
+ {
+ totalMemberCount++;
+ if ( kc->metaContact()->isOnline() )
+ onlineMemberCount++;
+ }
+ }
+
+ d->name->setText( m_group->displayName() );
+ d->count->setText( i18n( "(NUMBER OF ONLINE CONTACTS/NUMBER OF CONTACTS IN GROUP)", "(%1/%2)" )
+ .arg( QString::number( onlineMemberCount ), QString::number( totalMemberCount ) ) );
+
+ updateVisibility();
+
+ // Sorting in this slot is extremely expensive as it's called dozens of times and
+ // the sorting itself is rather slow. Therefore we call delayedSort, which tries
+ // to group multiple sort requests into one.
+ using namespace Kopete::UI::ListView;
+ if ( ListView::ListView *lv = dynamic_cast<ListView::ListView *>( listView() ) )
+ lv->delayedSort();
+ else
+ listView()->sort();
+}
+
+QString KopeteGroupViewItem::key( int, bool ) const
+{
+ //Groups are placed after topLevel contact.
+ //Exepted Temporary group which is the first group
+ if ( group()->type() != Kopete::Group::Normal )
+ return "0" + d->name->text();
+ return "M" + d->name->text();
+}
+
+void KopeteGroupViewItem::startRename( int /*col*/ )
+{
+ //kdDebug(14000) << k_funcinfo << endl;
+ KListViewItem::startRename( 0 );
+}
+
+void KopeteGroupViewItem::okRename( int col )
+{
+ //kdDebug(14000) << k_funcinfo << endl;
+ KListViewItem::okRename(col);
+ setRenameEnabled( 0, false );
+}
+
+void KopeteGroupViewItem::cancelRename( int col )
+{
+ //kdDebug(14000) << k_funcinfo << endl;
+ KListViewItem::cancelRename(col);
+ setRenameEnabled( 0, false );
+}
+
+void KopeteGroupViewItem::updateVisibility()
+{
+ //FIXME: A contact can ve visible if he has a unknwon status (it's not online)
+ // or if he has an event (blinking icon). If such as contact is not with
+ // others inline contact in the group. the group will stay hidden.
+ int visibleUsers = onlineMemberCount;
+ if ( KopetePrefs::prefs()->showOffline() )
+ visibleUsers = totalMemberCount;
+
+ bool visible = KopetePrefs::prefs()->showEmptyGroups() || ( visibleUsers > 0 );
+
+ if ( isVisible() != visible )
+ {
+ setTargetVisibility( visible );
+ if ( visible )
+ {
+ // When calling setVisible(true) EVERY child item will be shown,
+ // even if they should be hidden.
+ // We just re-update the visibility of all child items
+ for ( QListViewItem *lvi = firstChild(); lvi; lvi = lvi->nextSibling() )
+ {
+ if ( KopeteMetaContactLVI *kmc = dynamic_cast<KopeteMetaContactLVI *>( lvi ) )
+ kmc->updateVisibility();
+ }
+ }
+ }
+}
+
+void KopeteGroupViewItem::updateIcon()
+{
+ // TODO: clever caching
+ if ( isOpen() )
+ {
+ if ( group()->useCustomIcon() && !group()->icon( Kopete::ContactListElement::Open ).isEmpty() )
+ open = SmallIcon( group()->icon( Kopete::ContactListElement::Open ) );
+ else
+ open = SmallIcon( KOPETE_GROUP_DEFAULT_OPEN_ICON );
+
+ d->image->setPixmap( open );
+ }
+ else
+ {
+ if ( group()->useCustomIcon() && !group()->icon( Kopete::ContactListElement::Closed ).isEmpty() )
+ closed = SmallIcon( group()->icon( Kopete::ContactListElement::Closed ) );
+ else
+ closed = SmallIcon( KOPETE_GROUP_DEFAULT_CLOSED_ICON );
+
+ d->image->setPixmap( closed );
+ }
+}
+
+QString KopeteGroupViewItem::text( int column ) const
+{
+ if ( column == 0 )
+ return d->name->text();
+ else
+ return KListViewItem::text( column );
+}
+
+void KopeteGroupViewItem::setText( int column, const QString &text )
+{
+ if ( column == 0 )
+ {
+ KopeteContactListView *lv = dynamic_cast<KopeteContactListView *>( listView() );
+ if ( lv )
+ {
+ KopeteContactListView::UndoItem *u=new KopeteContactListView::UndoItem(KopeteContactListView::UndoItem::GroupRename, 0L, m_group);
+ u->args << m_group->displayName();
+ lv->insertUndoItem(u);
+ }
+ group()->setDisplayName( text );
+ }
+ else
+ KListViewItem::setText( column, text );
+}
+
+#include "kopetegroupviewitem.moc"
+// vim: set noet ts=4 sts=4 sw=4:
+
+
diff --git a/kopete/kopete/contactlist/kopetegroupviewitem.h b/kopete/kopete/contactlist/kopetegroupviewitem.h
new file mode 100644
index 00000000..777ea2e8
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetegroupviewitem.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+ kopetegroupviewitem.h - description
+ -------------------
+ begin : lun oct 28 2002
+ copyright : (C) 2002 by Olivier Goffart
+ email : ogoffart @ 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KOPETEGROUPVIEWITEM_H
+#define KOPETEGROUPVIEWITEM_H
+
+#include "kopetelistviewitem.h"
+#include <qpixmap.h>
+
+#define KOPETE_GROUP_DEFAULT_OPEN_ICON "folder_open"
+#define KOPETE_GROUP_DEFAULT_CLOSED_ICON "folder"
+
+namespace Kopete
+{
+class Group;
+}
+
+/**
+ * @author Olivier Goffart
+ */
+class KopeteGroupViewItem : public Kopete::UI::ListView::Item
+{
+ Q_OBJECT
+public:
+ KopeteGroupViewItem( Kopete::Group *group , QListView *parent, const char *name = 0 );
+ KopeteGroupViewItem( Kopete::Group *group , QListViewItem *parent, const char *name = 0 );
+ ~KopeteGroupViewItem();
+
+ Kopete::Group * group() const;
+
+ virtual void startRename( int col );
+
+ /**
+ * reimplemented from KListViewItem to take into account our alternate text storage
+ */
+ virtual QString text( int column ) const;
+ virtual void setText( int column, const QString &text );
+
+ QString toolTip() const;
+
+public slots:
+ void refreshDisplayName();
+ void updateIcon();
+ void updateVisibility();
+
+protected:
+ virtual void okRename( int col );
+ virtual void cancelRename( int col );
+
+private:
+ void initLVI();
+
+ Kopete::Group *m_group;
+ QPixmap open, closed;
+
+ QString key( int column, bool ascending ) const;
+
+ unsigned int onlineMemberCount;
+ unsigned int totalMemberCount;
+
+ class Private;
+ Private *d;
+
+private slots:
+ void slotConfigChanged();
+};
+
+#endif
diff --git a/kopete/kopete/contactlist/kopetegvipropswidget.ui b/kopete/kopete/contactlist/kopetegvipropswidget.ui
new file mode 100644
index 00000000..4dbb1599
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetegvipropswidget.ui
@@ -0,0 +1,156 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KopeteGVIPropsWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KopeteGVIPropsWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>220</width>
+ <height>223</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;General</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>lblDisplayName</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>edtDisplayName</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>edtDisplayName</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>grpIcons</cstring>
+ </property>
+ <property name="title">
+ <string>Icons</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIconButton" row="1" column="1">
+ <property name="name">
+ <cstring>icnbOpen</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lblOpen</cstring>
+ </property>
+ <property name="text">
+ <string>O&amp;pen:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>icnbOpen</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>lblClosed</cstring>
+ </property>
+ <property name="text">
+ <string>C&amp;losed:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>icnbClosed</cstring>
+ </property>
+ </widget>
+ <widget class="KIconButton" row="2" column="1">
+ <property name="name">
+ <cstring>icnbClosed</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>chkUseCustomIcons</cstring>
+ </property>
+ <property name="text">
+ <string>Use custom &amp;icons</string>
+ </property>
+ </widget>
+ <spacer row="1" column="2">
+ <property name="name">
+ <cstring>spacerHorizontal1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<tabstops>
+ <tabstop>tabWidget</tabstop>
+ <tabstop>edtDisplayName</tabstop>
+ <tabstop>chkUseCustomIcons</tabstop>
+ <tabstop>icnbOpen</tabstop>
+ <tabstop>icnbClosed</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kicondialog.h</includehint>
+ <includehint>kicondialog.h</includehint>
+</includehints>
+</UI>
diff --git a/kopete/kopete/contactlist/kopetelviprops.cpp b/kopete/kopete/contactlist/kopetelviprops.cpp
new file mode 100644
index 00000000..bf5431bf
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetelviprops.cpp
@@ -0,0 +1,570 @@
+/*
+ kopetelviprops.cpp
+
+ Kopete Contactlist Properties GUI for Groups and MetaContacts
+
+ Copyright (c) 2002-2003 by Stefan Gehn <metz AT gehn.net>
+ Copyright (c) 2004 by Will Stephenson <lists@stevello.free-online.co.uk>
+ Copyright (c) 2004-2005 by Duncan Mac-Vicar P. <duncan@kde.org>
+
+ Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#include "kopetelviprops.h"
+
+#include <kdebug.h>
+
+#include <qapplication.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qtabwidget.h>
+#include <qcombobox.h>
+
+#include <kdialogbase.h>
+#include <kfiledialog.h>
+#include <kicondialog.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kurlrequester.h>
+#include <kabc/addresseedialog.h>
+#include <kabc/stdaddressbook.h>
+#include <kabc/addressee.h>
+#include <kstandarddirs.h>
+#include <kurlrequester.h>
+
+#include "kabcpersistence.h"
+#include "kopeteaddrbookexport.h"
+#include "kopetecontact.h"
+#include "kopetegroup.h"
+#include "kopetegroupviewitem.h"
+#include "kopetemetacontactlvi.h"
+#include "kopeteaccount.h"
+#include "kopeteprotocol.h"
+#include "addressbooklinkwidget.h"
+#include "addressbookselectordialog.h"
+
+#include "customnotificationprops.h"
+#include "customnotifications.h"
+
+const char MC_OFF[] = "metacontact_offline";
+const char MC_ON[] = "metacontact_online";
+const char MC_AW[] = "metacontact_away";
+const char MC_UNK[] = "metacontact_unknown";
+
+
+KopeteGVIProps::KopeteGVIProps(KopeteGroupViewItem *gvi, QWidget *parent, const char *name)
+: KDialogBase(parent, name, true, i18n("Properties of Group %1").arg(gvi->group()->displayName()), Ok|Cancel, Ok, false)
+{
+ mainWidget = new KopeteGVIPropsWidget(this, "mainWidget");
+ mainWidget->icnbOpen->setIconSize(KIcon::SizeSmall);
+ mainWidget->icnbClosed->setIconSize(KIcon::SizeSmall);
+
+ mNotificationProps = new CustomNotificationProps( this, gvi->group() );
+ mainWidget->tabWidget->addTab( mNotificationProps->widget(), i18n( "Custom &Notifications" ) );
+
+ setMainWidget(mainWidget);
+ item = gvi;
+ m_dirty = false;
+
+ mainWidget->edtDisplayName->setText( item->group()->displayName() );
+
+ mainWidget->chkUseCustomIcons->setChecked( item->group()->useCustomIcon() );
+
+ QString openName = item->group()->icon( Kopete::ContactListElement::Open );
+ if(openName.isEmpty())
+ openName = KOPETE_GROUP_DEFAULT_OPEN_ICON;
+ QString closeName = item->group()->icon( Kopete::ContactListElement::Closed );
+ if(closeName.isEmpty())
+ closeName = KOPETE_GROUP_DEFAULT_CLOSED_ICON;
+ mainWidget->icnbOpen->setIcon( openName );
+ mainWidget->icnbClosed->setIcon( closeName );
+
+ connect( this, SIGNAL(okClicked()), this, SLOT( slotOkClicked() ) );
+ connect( mainWidget->chkUseCustomIcons, SIGNAL( toggled( bool ) ),
+ this, SLOT( slotUseCustomIconsToggled( bool ) ) );
+ connect( mainWidget->icnbOpen, SIGNAL( iconChanged( QString ) ),
+ SLOT( slotIconChanged() ) );
+ connect( mainWidget->icnbClosed, SIGNAL( iconChanged( QString ) ),
+ SLOT( slotIconChanged() ) );
+ slotUseCustomIconsToggled( mainWidget->chkUseCustomIcons->isChecked() );
+}
+
+KopeteGVIProps::~KopeteGVIProps()
+{
+}
+
+void KopeteGVIProps::slotOkClicked()
+{
+ if( mainWidget->edtDisplayName->text() != item->group()->displayName() )
+ {
+ item->group()->setDisplayName( mainWidget->edtDisplayName->text() );
+ item->refreshDisplayName();
+ }
+
+ item->group()->setUseCustomIcon( mainWidget->chkUseCustomIcons->isChecked() );
+
+ // only call setIcon if the icon was changed
+ if( m_dirty )
+ {
+ item->group()->setIcon( mainWidget->icnbOpen->icon(),
+ Kopete::ContactListElement::Open );
+
+ item->group()->setIcon( mainWidget->icnbClosed->icon(),
+ Kopete::ContactListElement::Closed );
+ }
+
+ mNotificationProps->storeCurrentCustoms();
+}
+
+void KopeteGVIProps::slotUseCustomIconsToggled(bool on)
+{
+ mainWidget->lblOpen->setEnabled( on );
+ mainWidget->icnbOpen->setEnabled( on );
+ mainWidget->lblClosed->setEnabled( on );
+ mainWidget->icnbClosed->setEnabled( on );
+}
+
+void KopeteGVIProps::slotIconChanged()
+{
+ m_dirty = true;
+}
+
+// =============================================================================
+
+
+KopeteMetaLVIProps::KopeteMetaLVIProps(KopeteMetaContactLVI *lvi, QWidget *parent, const char *name)
+: KDialogBase(parent, name, true, i18n("Properties of Meta Contact %1").arg(lvi->metaContact()->displayName()), Ok|Cancel, Ok, false)
+{
+ m_countPhotoCapable = 0;
+ mainWidget = new KopeteMetaLVIPropsWidget( this, "mainWidget" );
+ mainWidget->icnbOffline->setIconSize( KIcon::SizeSmall );
+ mainWidget->icnbOnline->setIconSize( KIcon::SizeSmall );
+ mainWidget->icnbAway->setIconSize( KIcon::SizeSmall );
+ mainWidget->icnbUnknown->setIconSize( KIcon::SizeSmall );
+
+ mNotificationProps = new CustomNotificationProps( this, lvi->metaContact() );
+ // add a button to the notification props to get the sound from KABC
+ // the widget's vert box layout, horiz box layout containing button, spacer, followed by a spacer
+ QBoxLayout * vb = static_cast<QVBoxLayout*>( mNotificationProps->widget()->layout() );
+
+ QHBoxLayout* hb = new QHBoxLayout( vb, -1, "soundFromKABClayout" );
+ mFromKABC = new QPushButton( i18n( "Sync KABC..." ), mNotificationProps->widget(), "getSoundFromKABC" );
+ hb->addWidget( mFromKABC ); // [ [Button] <-xxxxx-> ]
+ hb->addStretch();
+ vb->addStretch(); // vert spacer keeps the rest snug
+
+ mainWidget->tabWidget->addTab( mNotificationProps->widget(), i18n( "Custom &Notifications" ) );
+ setMainWidget( mainWidget );
+ item = lvi;
+
+ connect( mainWidget->radioNameKABC, SIGNAL(toggled(bool)), SLOT(slotEnableAndDisableWidgets()));
+ connect( mainWidget->radioNameContact, SIGNAL(toggled(bool)), SLOT(slotEnableAndDisableWidgets()));
+ connect( mainWidget->radioNameCustom, SIGNAL(toggled(bool)), SLOT(slotEnableAndDisableWidgets()));
+ connect( mainWidget->radioPhotoKABC, SIGNAL(toggled(bool)), SLOT(slotEnableAndDisableWidgets()));
+ connect( mainWidget->radioPhotoContact, SIGNAL(toggled(bool)), SLOT(slotEnableAndDisableWidgets()));
+ connect( mainWidget->radioPhotoCustom, SIGNAL(toggled(bool)), SLOT(slotEnableAndDisableWidgets()));
+ connect( mainWidget->cmbPhotoUrl, SIGNAL(urlSelected(const QString &)), SLOT(slotEnableAndDisableWidgets()));
+ connect( mainWidget->cmbAccountPhoto, SIGNAL(activated ( int )), SLOT(slotEnableAndDisableWidgets()));
+
+
+ mainWidget->btnClearPhoto->setIconSet( SmallIconSet( QApplication::reverseLayout() ? "locationbar_erase" : "clear_left" ) );
+ connect( mainWidget->btnClearPhoto, SIGNAL( clicked() ), this, SLOT( slotClearPhotoClicked() ) );
+ connect( mainWidget->widAddresseeLink, SIGNAL( addresseeChanged( const KABC::Addressee & ) ), SLOT( slotAddresseeChanged( const KABC::Addressee & ) ) );
+ mainWidget->chkUseCustomIcons->setChecked( item->metaContact()->useCustomIcon() );
+
+ QString offlineName = item->metaContact()->icon( Kopete::ContactListElement::Offline );
+ if(offlineName.isEmpty())
+ offlineName = QString::fromLatin1(MC_OFF); // Default
+
+ QString onlineName = item->metaContact()->icon( Kopete::ContactListElement::Online );
+ if(onlineName.isEmpty())
+ onlineName = QString::fromLatin1(MC_ON); // Default
+
+ QString awayName = item->metaContact()->icon( Kopete::ContactListElement::Away );
+ if(awayName.isEmpty())
+ awayName = QString::fromLatin1(MC_AW); // Default
+
+ QString unknownName = item->metaContact()->icon( Kopete::ContactListElement::Unknown );
+ if(unknownName.isEmpty())
+ unknownName = QString::fromLatin1(MC_UNK); // Default
+
+ mainWidget->icnbOffline->setIcon( offlineName );
+ mainWidget->icnbOnline->setIcon( onlineName );
+ mainWidget->icnbAway->setIcon( awayName );
+ mainWidget->icnbUnknown->setIcon( unknownName );
+
+ mainWidget->widAddresseeLink->setMetaContact( lvi->metaContact() );
+
+ mAddressBookUid = item->metaContact()->metaContactId();
+
+ mExport = 0L;
+
+ if ( !mAddressBookUid.isEmpty() )
+ {
+ KABC::AddressBook *ab = Kopete::KABCPersistence::self()->addressBook();
+ KABC::Addressee a = ab->findByUid( mAddressBookUid );
+ mainWidget->widAddresseeLink->setAddressee( a );
+
+ if ( !a.isEmpty() )
+ {
+ mainWidget->btnImportKABC->setEnabled( true );
+ mainWidget->btnExportKABC->setEnabled( true );
+ mExport = new KopeteAddressBookExport( this, item->metaContact() );
+
+ mSound = a.sound();
+ mFromKABC->setEnabled( !( mSound.isIntern() || mSound.url().isEmpty() ) );
+ }
+ }
+
+ slotLoadNameSources();
+ slotLoadPhotoSources();
+
+ connect( this, SIGNAL(okClicked()), this, SLOT( slotOkClicked() ) );
+ connect( mainWidget->chkUseCustomIcons, SIGNAL( toggled( bool ) ),
+ this, SLOT( slotUseCustomIconsToggled( bool ) ) );
+ connect( mainWidget->btnImportKABC, SIGNAL( clicked() ),
+ this, SLOT( slotImportClicked() ) );
+ connect( mainWidget->btnExportKABC, SIGNAL( clicked() ),
+ this, SLOT( slotExportClicked() ) );
+ connect( mFromKABC, SIGNAL( clicked() ),
+ this, SLOT( slotFromKABCClicked() ) );
+ connect( mNotificationProps->widget()->customSound, SIGNAL( openFileDialog( KURLRequester * )),
+ SLOT( slotOpenSoundDialog( KURLRequester * )));
+
+ slotUseCustomIconsToggled( mainWidget->chkUseCustomIcons->isChecked() );
+ slotEnableAndDisableWidgets();
+}
+
+KopeteMetaLVIProps::~KopeteMetaLVIProps()
+{
+}
+
+
+void KopeteMetaLVIProps::slotLoadNameSources()
+{
+ Kopete::Contact* trackingName = item->metaContact()->displayNameSourceContact();
+ QPtrList< Kopete::Contact > cList = item->metaContact()->contacts();
+ QPtrListIterator<Kopete::Contact> it( cList );
+ mainWidget->cmbAccountName->clear();
+ for( ; it.current(); ++it )
+ {
+ QString acct = it.current()->property( Kopete::Global::Properties::self()->nickName() ).value().toString() + " <" + it.current()->contactId() + ">";
+ QPixmap acctIcon = it.current()->account()->accountIcon();
+ mainWidget->cmbAccountName->insertItem( acctIcon, acct );
+
+ // Select this item if it's the one we're tracking.
+ if( it.current() == trackingName )
+ {
+ mainWidget->cmbAccountName->setCurrentItem( mainWidget->cmbAccountName->count() - 1 );
+ }
+ }
+
+ mainWidget->edtDisplayName->setText( item->metaContact()->customDisplayName() );
+
+ Kopete::MetaContact::PropertySource nameSource = item->metaContact()->displayNameSource();
+
+ mainWidget->radioNameContact->setChecked(nameSource == Kopete::MetaContact::SourceContact);
+ mainWidget->radioNameKABC->setChecked(nameSource == Kopete::MetaContact::SourceKABC);
+ mainWidget->radioNameCustom->setChecked(nameSource == Kopete::MetaContact::SourceCustom);
+
+}
+
+void KopeteMetaLVIProps::slotLoadPhotoSources()
+{
+ // fill photo contact sources
+ QPtrList< Kopete::Contact > cList = item->metaContact()->contacts();
+ m_withPhotoContacts.clear();
+ Kopete::Contact* trackingPhoto = item->metaContact()->photoSourceContact();
+ mainWidget->cmbAccountPhoto->clear();
+ QPtrListIterator<Kopete::Contact> itp( cList );
+ for( ; itp.current(); ++itp )
+ {
+ Kopete::Contact *citem = itp.current();
+ if ( citem->hasProperty( Kopete::Global::Properties::self()->photo().key() ) )
+ {
+ QString acct = citem->property( Kopete::Global::Properties::self()->nickName() ).value().toString() + " <" + citem->contactId() + ">";
+ QPixmap acctIcon = citem->account()->accountIcon();
+ mainWidget->cmbAccountPhoto->insertItem( acctIcon, acct );
+
+ // Select this item if it's the one we're tracking.
+ if( citem == trackingPhoto )
+ {
+ mainWidget->cmbAccountPhoto->setCurrentItem( mainWidget->cmbAccountPhoto->count() - 1 );
+ }
+ m_withPhotoContacts.insert(mainWidget->cmbAccountPhoto->count() - 1 , citem );
+ }
+ }
+#if KDE_IS_VERSION(3,4,0)
+ mainWidget->cmbPhotoUrl->setKURL(item->metaContact()->customPhoto().url());
+#else
+ mainWidget->cmbPhotoUrl->setURL(item->metaContact()->customPhoto().url());
+#endif
+
+ Kopete::MetaContact::PropertySource photoSource = item->metaContact()->photoSource();
+
+ mainWidget->radioPhotoContact->setChecked(photoSource == Kopete::MetaContact::SourceContact);
+ mainWidget->radioPhotoKABC->setChecked(photoSource == Kopete::MetaContact::SourceKABC);
+ mainWidget->radioPhotoCustom->setChecked(photoSource == Kopete::MetaContact::SourceCustom);
+
+ mainWidget->chkSyncPhoto->setChecked(item->metaContact()->isPhotoSyncedWithKABC());
+}
+
+void KopeteMetaLVIProps::slotEnableAndDisableWidgets()
+{
+ KABC::AddressBook *ab = Kopete::KABCPersistence::self()->addressBook();
+ KABC::Addressee a = ab->findByUid( mAddressBookUid );
+ bool validLink = ! a.isEmpty();
+ // kabc source requires a kabc link
+ mainWidget->radioNameKABC->setEnabled(validLink);
+ // kabc source requires a kabc link
+ mainWidget->radioPhotoKABC->setEnabled(validLink);
+ // sync with kabc has no sense if we use kabc as source (sync kabc with kabc? uh?)
+ // it has also no sense if they are no kabc link
+ if( selectedPhotoSource() == Kopete::MetaContact::SourceKABC || !validLink )
+ {
+ mainWidget->chkSyncPhoto->setEnabled(false);
+ }
+ else
+ {
+ mainWidget->chkSyncPhoto->setEnabled(true);
+ }
+
+ mainWidget->radioNameContact->setEnabled(item->metaContact()->contacts().count());
+ mainWidget->radioPhotoContact->setEnabled(!m_withPhotoContacts.isEmpty());
+
+ mainWidget->cmbAccountName->setEnabled(selectedNameSource() == Kopete::MetaContact::SourceContact);
+ mainWidget->edtDisplayName->setEnabled(selectedNameSource() == Kopete::MetaContact::SourceCustom);
+
+ mainWidget->cmbAccountPhoto->setEnabled(selectedPhotoSource() == Kopete::MetaContact::SourceContact);
+ mainWidget->cmbPhotoUrl->setEnabled(selectedPhotoSource() == Kopete::MetaContact::SourceCustom);
+
+ if ( m_withPhotoContacts.isEmpty() )
+ {
+ mainWidget->cmbAccountPhoto->clear();
+ mainWidget->cmbAccountPhoto->insertItem(i18n("No Contacts with Photo Support"));
+ mainWidget->cmbAccountPhoto->setEnabled(false);
+ }
+
+ QImage photo;
+ switch ( selectedPhotoSource() )
+ {
+ case Kopete::MetaContact::SourceKABC:
+ photo = Kopete::photoFromKABC(mAddressBookUid);
+ break;
+ case Kopete::MetaContact::SourceContact:
+ photo = Kopete::photoFromContact(selectedPhotoSourceContact());
+ break;
+ case Kopete::MetaContact::SourceCustom:
+ photo = QImage(KURL::decode_string(mainWidget->cmbPhotoUrl->url()));
+ break;
+ }
+ if( !photo.isNull() )
+ mainWidget->photoLabel->setPixmap(QPixmap(photo.smoothScale( 64, 92, QImage::ScaleMin )));
+ else
+ mainWidget->photoLabel->setPixmap( QPixmap() );
+}
+
+Kopete::MetaContact::PropertySource KopeteMetaLVIProps::selectedNameSource() const
+{
+ if ( mainWidget->radioNameKABC->isChecked() )
+ return Kopete::MetaContact::SourceKABC;
+ if ( mainWidget->radioNameContact->isChecked() )
+ return Kopete::MetaContact::SourceContact;
+ if ( mainWidget->radioNameCustom->isChecked() )
+ return Kopete::MetaContact::SourceCustom;
+ else
+ return Kopete::MetaContact::SourceCustom;
+}
+
+Kopete::MetaContact::PropertySource KopeteMetaLVIProps::selectedPhotoSource() const
+{
+ if ( mainWidget->radioPhotoKABC->isChecked() )
+ return Kopete::MetaContact::SourceKABC;
+ if ( mainWidget->radioPhotoContact->isChecked() )
+ return Kopete::MetaContact::SourceContact;
+ if ( mainWidget->radioPhotoCustom->isChecked() )
+ return Kopete::MetaContact::SourceCustom;
+ else
+ return Kopete::MetaContact::SourceCustom;
+}
+
+Kopete::Contact* KopeteMetaLVIProps::selectedNameSourceContact() const
+{
+ Kopete::Contact *c= item->metaContact()->contacts().at( mainWidget->cmbAccountName->currentItem() );
+ return c ? c : 0L;
+}
+
+Kopete::Contact* KopeteMetaLVIProps::selectedPhotoSourceContact() const
+{
+ if (m_withPhotoContacts.isEmpty())
+ return 0L;
+ Kopete::Contact *c = m_withPhotoContacts[mainWidget->cmbAccountPhoto->currentItem() ];
+ return c ? c : 0L;
+}
+
+void KopeteMetaLVIProps::slotOkClicked()
+{
+ // update meta contact's UID
+ item->metaContact()->setMetaContactId( mAddressBookUid );
+ //this has to be done first, in the case something is synced with KABC (see bug 109494)
+
+ // set custom display name
+ if( mainWidget->edtDisplayName->text() != item->metaContact()->customDisplayName() )
+ item->metaContact()->setDisplayName( mainWidget->edtDisplayName->text() );
+
+ item->metaContact()->setDisplayNameSource(selectedNameSource());
+ item->metaContact()->setDisplayNameSourceContact( selectedNameSourceContact() );
+
+ // set photo source
+ item->metaContact()->setPhotoSource(selectedPhotoSource());
+ item->metaContact()->setPhotoSourceContact( selectedPhotoSourceContact() );
+ if ( !mainWidget->cmbPhotoUrl->url().isEmpty())
+ item->metaContact()->setPhoto(KURL::fromPathOrURL((mainWidget->cmbPhotoUrl->url())));
+ item->metaContact()->setPhotoSyncedWithKABC( mainWidget->chkSyncPhoto->isChecked() );
+
+ item->metaContact()->setUseCustomIcon(
+ mainWidget->chkUseCustomIcons->isChecked() );
+
+ // only call setIcon if any of the icons is not set to default icon
+ if(
+ mainWidget->icnbOffline->icon() != MC_OFF ||
+ mainWidget->icnbOnline->icon() != MC_ON ||
+ mainWidget->icnbAway->icon() != MC_AW ||
+ mainWidget->icnbUnknown->icon() != MC_UNK )
+ {
+ item->metaContact()->setIcon( mainWidget->icnbOffline->icon(),
+ Kopete::ContactListElement::Offline );
+
+ item->metaContact()->setIcon( mainWidget->icnbOnline->icon(),
+ Kopete::ContactListElement::Online );
+
+ item->metaContact()->setIcon( mainWidget->icnbAway->icon(),
+ Kopete::ContactListElement::Away );
+
+ item->metaContact()->setIcon( mainWidget->icnbUnknown->icon(),
+ Kopete::ContactListElement::Unknown );
+ }
+
+ mNotificationProps->storeCurrentCustoms();
+}
+
+void KopeteMetaLVIProps::slotUseCustomIconsToggled(bool on)
+{
+ mainWidget->lblOffline->setEnabled( on );
+ mainWidget->lblOnline->setEnabled( on );
+ mainWidget->lblAway->setEnabled( on );
+ mainWidget->lblUnknown->setEnabled( on );
+
+ mainWidget->icnbOffline->setEnabled( on );
+ mainWidget->icnbOnline->setEnabled( on );
+ mainWidget->icnbAway->setEnabled( on );
+ mainWidget->icnbUnknown->setEnabled( on );
+}
+
+void KopeteMetaLVIProps::slotAddresseeChanged( const KABC::Addressee & a )
+{
+ if ( !a.isEmpty() )
+ {
+ mSound = a.sound();
+ mFromKABC->setEnabled( !( mSound.isIntern() || mSound.url().isEmpty() ) );
+ mainWidget->btnExportKABC->setEnabled( true );
+ mainWidget->btnImportKABC->setEnabled( true );
+ // set/update the MC's addressee uin field
+ mAddressBookUid = a.uid();
+ }
+ else
+ {
+ mainWidget->btnExportKABC->setEnabled( false );
+ mainWidget->btnImportKABC->setEnabled( false );
+ mAddressBookUid = QString::null;
+ mainWidget->radioNameContact->setChecked( true );
+ mainWidget->radioPhotoContact->setChecked( true );
+ }
+ slotEnableAndDisableWidgets();
+}
+
+void KopeteMetaLVIProps::slotExportClicked()
+{
+ item->metaContact()->setMetaContactId( mAddressBookUid );
+ delete mExport;
+ mExport = new KopeteAddressBookExport( this, item->metaContact() );
+ if ( mExport->showDialog() == QDialog::Accepted )
+ mExport->exportData();
+}
+
+void KopeteMetaLVIProps::slotImportClicked()
+{
+ item->metaContact()->setMetaContactId( mAddressBookUid );
+ if ( Kopete::KABCPersistence::self()->syncWithKABC( item->metaContact() ) )
+ KMessageBox::queuedMessageBox( this, KMessageBox::Information,
+ i18n( "No contacts were imported from the address book." ),
+ i18n( "No Change" ) );
+}
+
+void KopeteMetaLVIProps::slotFromKABCClicked()
+{
+ mNotificationProps->widget()->customSound->setURL( mSound.url() );
+}
+
+void KopeteMetaLVIProps::slotOpenSoundDialog( KURLRequester *requester )
+{
+ // taken from kdelibs/kio/kfile/knotifydialog.cpp
+ // only need to init this once
+ requester->disconnect( SIGNAL( openFileDialog( KURLRequester * )),
+ this, SLOT( slotOpenSoundDialog( KURLRequester * )));
+
+ KFileDialog *fileDialog = requester->fileDialog();
+ //fileDialog->setCaption( i18n("Select Sound File") );
+ QStringList filters;
+ filters << "audio/x-wav" << "audio/x-mp3" << "application/ogg"
+ << "audio/x-adpcm";
+ fileDialog->setMimeFilter( filters );
+
+ // find the first "sound"-resource that contains files
+ QStringList soundDirs =
+ KGlobal::dirs()->findDirs("data", "kopete/sounds");
+ soundDirs += KGlobal::dirs()->resourceDirs( "sound" );
+
+ if ( !soundDirs.isEmpty() ) {
+ KURL soundURL;
+ QDir dir;
+ dir.setFilter( QDir::Files | QDir::Readable );
+ QStringList::ConstIterator it = soundDirs.begin();
+ while ( it != soundDirs.end() ) {
+ dir = *it;
+ if ( dir.isReadable() && dir.count() > 2 ) {
+ soundURL.setPath( *it );
+ fileDialog->setURL( soundURL );
+ break;
+ }
+ ++it;
+ }
+ }
+}
+
+void KopeteMetaLVIProps::slotClearPhotoClicked()
+{
+#if KDE_IS_VERSION(3,4,0)
+ mainWidget->cmbPhotoUrl->setKURL( KURL() );
+#else
+ mainWidget->cmbPhotoUrl->setURL( QString::null );
+#endif
+ item->metaContact()->setPhoto( KURL() );
+
+ slotEnableAndDisableWidgets();
+}
+
+#include "kopetelviprops.moc"
diff --git a/kopete/kopete/contactlist/kopetelviprops.h b/kopete/kopete/contactlist/kopetelviprops.h
new file mode 100644
index 00000000..9a2ebf34
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetelviprops.h
@@ -0,0 +1,102 @@
+/*
+ kopetelviprops.h
+
+ Kopete Contactlist Properties GUI for Groups and MetaContacts
+
+ Copyright (c) 2002-2003 by Stefan Gehn <metz AT gehn.net>
+ Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KOPETELVIPROPS_H
+#define KOPETELVIPROPS_H
+
+#include <kdialogbase.h>
+#include <kabc/sound.h>
+
+#include "kopetemetacontact.h"
+
+#include "kopetegvipropswidget.h"
+#include "kopetemetalvipropswidget.h"
+
+class QButtonGroup;
+
+class AddressBookLinkWidget;
+class CustomNotificationProps;
+class KPushButton;
+class KopeteGroupViewItem;
+class KopeteMetaContactLVI;
+class KopeteAddressBookExport;
+class KURLRequester;
+
+namespace KABC { class Addressee; }
+namespace Kopete { class Contact; }
+
+class KopeteGVIProps: public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ KopeteGVIProps(KopeteGroupViewItem *gvi, QWidget *parent, const char *name=0L);
+ ~KopeteGVIProps();
+
+ private:
+ CustomNotificationProps * mNotificationProps;
+ KopeteGVIPropsWidget *mainWidget;
+ KopeteGroupViewItem *item;
+ bool m_dirty;
+
+ private slots:
+ void slotOkClicked();
+ void slotUseCustomIconsToggled(bool on);
+ void slotIconChanged();
+};
+
+
+class KopeteMetaLVIProps: public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ KopeteMetaLVIProps(KopeteMetaContactLVI *gvi, QWidget *parent, const char *name=0L);
+ ~KopeteMetaLVIProps();
+
+ private:
+ CustomNotificationProps * mNotificationProps;
+ QPushButton *mFromKABC;
+ KopeteMetaLVIPropsWidget *mainWidget;
+ AddressBookLinkWidget *linkWidget;
+ KopeteMetaContactLVI *item;
+ KopeteAddressBookExport *mExport;
+ KABC::Sound mSound;
+ int m_countPhotoCapable;
+ QMap<int, Kopete::Contact *> m_withPhotoContacts;
+ QString mAddressBookUid; // the currently selected addressbook UID
+
+ Kopete::MetaContact::PropertySource selectedNameSource() const;
+ Kopete::MetaContact::PropertySource selectedPhotoSource() const;
+ Kopete::Contact* selectedNameSourceContact() const;
+ Kopete::Contact* selectedPhotoSourceContact() const;
+ private slots:
+ void slotOkClicked();
+ void slotUseCustomIconsToggled( bool on );
+ void slotClearPhotoClicked();
+ void slotAddresseeChanged( const KABC::Addressee & );
+ void slotExportClicked();
+ void slotImportClicked();
+ void slotFromKABCClicked();
+ void slotOpenSoundDialog( KURLRequester *requester );
+ void slotLoadNameSources();
+ void slotLoadPhotoSources();
+ void slotEnableAndDisableWidgets();
+};
+
+#endif
diff --git a/kopete/kopete/contactlist/kopetemetacontactlvi.cpp b/kopete/kopete/contactlist/kopetemetacontactlvi.cpp
new file mode 100644
index 00000000..86dc4b40
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetemetacontactlvi.cpp
@@ -0,0 +1,1102 @@
+/*
+ kopetemetacontactlvi.cpp - Kopete Meta Contact KListViewItem
+
+ Copyright (c) 2004 by Richard Smith <kde@metafoo.co.uk>
+ Copyright (c) 2002-2004 by Martijn Klingens <klingens@kde.org>
+ Copyright (c) 2002-2005 by Olivier Goffart <ogoffart@ kde.org>
+ Copyright (c) 2002 by Duncan Mac-Vicar P <duncan@kde.org>
+
+ Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#include <qpainter.h>
+#include <qtimer.h>
+#include <qvariant.h>
+#include <qmime.h>
+#include <qstylesheet.h>
+
+#include "knotification.h"
+#include <kdebug.h>
+#include <kiconeffect.h>
+#include <kimageeffect.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpassivepopup.h>
+#include <kpopupmenu.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kapplication.h>
+
+#include <kabc/addressbook.h>
+#include <kabc/addressee.h>
+
+#include <kdeversion.h>
+#include <kinputdialog.h>
+
+
+#include "addcontactpage.h"
+#include "kopeteaccount.h"
+#include "kopeteaccountmanager.h"
+#include "kopetecontactlist.h"
+#include "kopetecontactlistview.h"
+#include "kopeteemoticons.h"
+#include "kopeteuiglobal.h"
+#include "kopetegroup.h"
+#include "kopetegroupviewitem.h"
+#include "kopetemetacontact.h"
+#include "kopetemetacontactlvi.h"
+#include "kopetepluginmanager.h"
+#include "kopeteprefs.h"
+#include "kopetestdaction.h"
+#include "systemtray.h"
+#include "kopeteglobal.h"
+#include "kopetecontact.h"
+#include "kabcpersistence.h"
+
+#include <memory>
+
+using namespace Kopete::UI;
+
+namespace Kopete {
+namespace UI {
+namespace ListView {
+
+class MetaContactToolTipSource : public ToolTipSource
+{
+public:
+ MetaContactToolTipSource( MetaContact *mc )
+ : metaContact( mc )
+ {
+ }
+ QString operator()( ComponentBase *, const QPoint &, QRect & )
+ {
+
+ // We begin with the meta contact display name at the top of the tooltip
+ QString toolTip = QString::fromLatin1("<qt><table cellpadding=\"0\" cellspacing=\"1\">");
+
+ toolTip += QString::fromLatin1("<tr><td>");
+
+ if ( ! metaContact->photo().isNull() )
+ {
+ QString photoName = QString::fromLatin1("kopete-metacontact-photo:%1").arg( KURL::encode_string( metaContact->metaContactId() ));
+ //QMimeSourceFactory::defaultFactory()->setImage( "contactimg", metaContact->photo() );
+ toolTip += QString::fromLatin1("<img src=\"%1\">").arg( photoName );
+ }
+
+ toolTip += QString::fromLatin1("</td><td>");
+
+ QString displayName;
+ Kopete::Emoticons *e = Kopete::Emoticons::self();
+ QValueList<Emoticons::Token> t = e->tokenize( metaContact->displayName());
+ QValueList<Emoticons::Token>::iterator it;
+ for( it = t.begin(); it != t.end(); ++it )
+ {
+ if( (*it).type == Kopete::Emoticons::Image )
+ {
+ displayName += (*it).picHTMLCode;
+ } else if( (*it).type == Kopete::Emoticons::Text )
+ {
+ displayName += QStyleSheet::escape( (*it).text );
+ }
+ }
+
+ toolTip += QString::fromLatin1("<b><font size=\"+1\">%1</font></b><br><br>").arg( displayName );
+
+ QPtrList<Contact> contacts = metaContact->contacts();
+ if ( contacts.count() == 1 )
+ {
+ return toolTip + contacts.first()->toolTip() + QString::fromLatin1("</td></tr></table></qt>");
+ }
+
+ toolTip += QString::fromLatin1("<table>");
+
+ // We are over a metacontact with > 1 child contacts, and not over a specific contact
+ // Iterate through children and display a summary tooltip
+ for(Contact *c = contacts.first(); c; c = contacts.next())
+ {
+ QString iconName = QString::fromLatin1("kopete-contact-icon:%1:%2:%3")
+ .arg( KURL::encode_string( c->protocol()->pluginId() ),
+ KURL::encode_string( c->account()->accountId() ),
+ KURL::encode_string( c->contactId() )
+ );
+
+ toolTip += i18n("<tr><td>STATUS ICON <b>PROTOCOL NAME</b> (ACCOUNT NAME)</td><td>STATUS DESCRIPTION</td></tr>",
+ "<tr><td><img src=\"%1\">&nbsp;<nobr><b>%2</b></nobr>&nbsp;<nobr>(%3)</nobr></td><td align=\"right\"><nobr>%4</nobr></td></tr>")
+ .arg( iconName, Kopete::Emoticons::parseEmoticons(c->property(Kopete::Global::Properties::self()->nickName()).value().toString()) , c->contactId(), c->onlineStatus().description() );
+ }
+
+ return toolTip + QString::fromLatin1("</table></td></tr></table></qt>");
+ }
+private:
+ MetaContact *metaContact;
+};
+
+} // END namespace ListView
+} // END namespace UI
+} // END namespace Kopete
+
+class KopeteMetaContactLVI::Private
+{
+public:
+ Private() : metaContactIcon( 0L ), nameText( 0L ), extraText( 0L ), contactIconBox( 0L ),
+ currentMode( -1 ), currentIconMode( -1 ) {}
+ ListView::ImageComponent *metaContactIcon;
+ ListView::DisplayNameComponent *nameText;
+ ListView::DisplayNameComponent *extraText;
+ ListView::BoxComponent *contactIconBox;
+ ListView::BoxComponent *spacerBox;
+ std::auto_ptr<ListView::ToolTipSource> toolTipSource;
+ // metacontact icon size
+ int iconSize;
+ // protocol icon size
+ int contactIconSize;
+ int currentMode;
+ int currentIconMode;
+
+ QPtrList<Kopete::MessageEvent> events;
+};
+
+KopeteMetaContactLVI::KopeteMetaContactLVI( Kopete::MetaContact *contact, KopeteGroupViewItem *parent )
+: ListView::Item( parent, contact, "MetaContactLVI" )
+//: QObject( contact, "MetaContactLVI" ), KListViewItem( parent )
+{
+ m_metaContact = contact;
+ m_isTopLevel = false;
+ m_parentGroup = parent;
+ m_parentView = 0L;
+
+ initLVI();
+ parent->refreshDisplayName();
+}
+
+KopeteMetaContactLVI::KopeteMetaContactLVI( Kopete::MetaContact *contact, QListViewItem *parent )
+: ListView::Item( parent, contact, "MetaContactLVI" )
+//: QObject( contact, "MetaContactLVI" ), KListViewItem( parent )
+{
+ m_metaContact = contact;
+
+ m_isTopLevel = true;
+ m_parentGroup = 0L;
+ m_parentView = 0L;
+
+ initLVI();
+}
+
+KopeteMetaContactLVI::KopeteMetaContactLVI( Kopete::MetaContact *contact, QListView *parent )
+: ListView::Item( parent, contact, "MetaContactLVI" )
+//: QObject( contact, "MetaContactLVI" ), KListViewItem( parent )
+{
+ m_metaContact = contact;
+
+ m_isTopLevel = true;
+ m_parentGroup = 0L;
+ m_parentView = parent;
+
+ initLVI();
+}
+
+void KopeteMetaContactLVI::initLVI()
+{
+ d = new Private;
+
+ d->toolTipSource.reset( new ListView::MetaContactToolTipSource( m_metaContact ) );
+
+ m_oldStatus = m_metaContact->status();
+
+ connect( m_metaContact, SIGNAL( displayNameChanged( const QString &, const QString & ) ),
+ SLOT( slotDisplayNameChanged() ) );
+
+ connect( m_metaContact, SIGNAL( photoChanged() ),
+ SLOT( slotPhotoChanged() ) );
+
+ connect( m_metaContact, SIGNAL( onlineStatusChanged( Kopete::MetaContact *, Kopete::OnlineStatus::StatusType ) ),
+ SLOT( slotPhotoChanged() ) );
+
+ connect( m_metaContact, SIGNAL( onlineStatusChanged( Kopete::MetaContact *, Kopete::OnlineStatus::StatusType ) ),
+ this, SLOT(slotIdleStateChanged( ) ) );
+
+ connect( m_metaContact, SIGNAL( contactStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus & ) ),
+ SLOT( slotContactStatusChanged( Kopete::Contact * ) ) );
+
+ connect( m_metaContact, SIGNAL( contactAdded( Kopete::Contact * ) ),
+ SLOT( slotContactAdded( Kopete::Contact * ) ) );
+
+ connect( m_metaContact, SIGNAL( contactRemoved( Kopete::Contact * ) ),
+ SLOT( slotContactRemoved( Kopete::Contact * ) ) );
+
+ connect( m_metaContact, SIGNAL( iconAppearanceChanged() ),
+ SLOT( slotUpdateMetaContact() ) );
+
+ connect( m_metaContact, SIGNAL( useCustomIconChanged( bool ) ),
+ SLOT( slotUpdateMetaContact() ) );
+
+ connect( m_metaContact, SIGNAL( contactIdleStateChanged( Kopete::Contact * ) ),
+ SLOT( slotIdleStateChanged( Kopete::Contact * ) ) );
+
+ connect( KopetePrefs::prefs(), SIGNAL( contactListAppearanceChanged() ),
+ SLOT( slotConfigChanged() ) );
+
+ connect( kapp, SIGNAL( appearanceChanged() ), SLOT( slotConfigChanged() ) );
+
+ mBlinkTimer = new QTimer( this, "mBlinkTimer" );
+ connect( mBlinkTimer, SIGNAL( timeout() ), SLOT( slotBlink() ) );
+ mIsBlinkIcon = false;
+
+ //if ( !mBlinkIcon )
+ // mBlinkIcon = new QPixmap( KGlobal::iconLoader()->loadIcon( QString::fromLatin1( "newmsg" ), KIcon::Small ) );
+
+ slotConfigChanged(); // this calls slotIdleStateChanged(), which sets up the constituent components, spacing, fonts and indirectly, the contact icon
+ slotDisplayNameChanged();
+ updateContactIcons();
+}
+
+KopeteMetaContactLVI::~KopeteMetaContactLVI()
+{
+ delete d;
+ //if ( m_parentGroup )
+ // m_parentGroup->refreshDisplayName();
+}
+
+void KopeteMetaContactLVI::movedToDifferentGroup()
+{
+ KopeteContactListView *lv = dynamic_cast<KopeteContactListView *>( listView() );
+ if ( !lv )
+ return;
+
+ if ( m_parentGroup )
+ m_parentGroup->refreshDisplayName();
+
+ // create a spacer if wanted
+ // I assume that the safety property that allows the delete in slotConfigChanged holds here - Will
+ delete d->spacerBox->component( 0 );
+ if ( KListViewItem::parent() && KopetePrefs::prefs()->contactListIndentContacts() &&
+ !KopetePrefs::prefs()->treeView() )
+ {
+ new ListView::SpacerComponent( d->spacerBox, 20, 0 );
+ }
+
+ KopeteGroupViewItem *group_item = dynamic_cast<KopeteGroupViewItem*>(KListViewItem::parent());
+ if ( group_item )
+ {
+ m_isTopLevel = false;
+ m_parentGroup = group_item;
+ m_parentView = 0L;
+ group_item->refreshDisplayName();
+ }
+ else
+ {
+ m_isTopLevel = true;
+ m_parentGroup = 0L;
+ m_parentView = lv;
+ }
+}
+
+void KopeteMetaContactLVI::rename( const QString& newName )
+{
+ QString oldName = m_metaContact->displayName();
+ KopeteContactListView *lv = dynamic_cast<KopeteContactListView *>( listView() );
+ if ( lv )
+ {
+ KopeteContactListView::UndoItem *u=new KopeteContactListView::UndoItem(KopeteContactListView::UndoItem::MetaContactRename, m_metaContact);
+ // HACK but args are strings not ints
+ u->nameSource = m_metaContact->displayNameSource();
+ // additional args
+ if ( m_metaContact->displayNameSource() == Kopete::MetaContact::SourceCustom )
+ {
+ u->args << m_metaContact->customDisplayName();
+ }
+ else if ( m_metaContact->displayNameSource() == Kopete::MetaContact::SourceContact )
+ {
+ Kopete::Contact* c = m_metaContact->displayNameSourceContact();
+ if(c)
+ u->args << c->contactId() << c->protocol()->pluginId() << c->account()->accountId();
+ }
+ // source kabc requires no arguments
+
+ lv->insertUndoItem(u);
+ }
+
+ if ( newName.isEmpty() )
+ {
+ // fallback to KABC
+ if ( !m_metaContact->metaContactId().isEmpty() )
+ {
+ m_metaContact->setDisplayNameSource(Kopete::MetaContact::SourceKABC);
+ if ( ! m_metaContact->displayName().isEmpty() )
+ {
+ slotDisplayNameChanged();
+ return;
+ }
+ }
+ // bad luck with KABC
+ m_metaContact->setDisplayNameSource(Kopete::MetaContact::SourceContact);
+ // TODO iterate though all subcontacts to check non empty nick
+ m_metaContact->setDisplayNameSourceContact( m_metaContact->contacts().first() );
+ slotDisplayNameChanged();
+ }
+ else // user changed name manually, set source to custom
+ {
+ m_metaContact->setDisplayNameSource( Kopete::MetaContact::SourceCustom );
+ m_metaContact->setDisplayName( newName );
+ slotDisplayNameChanged();
+ }
+
+ kdDebug( 14000 ) << k_funcinfo << "newName=" << newName << endl;
+}
+
+void KopeteMetaContactLVI::slotContactStatusChanged( Kopete::Contact *c )
+{
+ updateContactIcon( c );
+
+ // FIXME: All this code should be in kopetemetacontact.cpp.. having it in the LVI makes it all fire
+ // multiple times if the user is in multiple groups - Jason
+
+ // comparing the status of the previous and new preferred contact is the determining factor in deciding to notify
+ Kopete::OnlineStatus newStatus;
+ if ( m_metaContact->preferredContact() )
+ newStatus = m_metaContact->preferredContact()->onlineStatus();
+ else
+ {
+ // the last child contact has gone offline or otherwise unreachable, so take the changed contact's online status
+ newStatus = c->onlineStatus();
+ }
+
+ // ensure we are not suppressing notifications, because connecting or disconnected
+ if ( !(c->account()->suppressStatusNotification()
+ || ( c->account()->myself()->onlineStatus().status() == Kopete::OnlineStatus::Connecting )
+ || !c->account()->isConnected() ) )
+ {
+ if ( !c->account()->isAway() || KopetePrefs::prefs()->soundIfAway() )
+ {
+ //int winId = KopeteSystemTray::systemTray() ? KopeteSystemTray::systemTray()->winId() : 0;
+
+ QString text = i18n( "<qt><i>%1</i> is now %2.</qt>" )
+ .arg( Kopete::Emoticons::parseEmoticons( QStyleSheet::escape(m_metaContact->displayName()) ) ,
+ QStyleSheet::escape(c->onlineStatus().description()));
+
+ // figure out what's happened
+ enum ChangeType { noChange, noEvent, signedIn, changedStatus, signedOut };
+ ChangeType t = noChange;
+ //kdDebug( 14000 ) << k_funcinfo << m_metaContact->displayName() <<
+ //" - Old MC Status: " << m_oldStatus.status() << ", New MC Status: " << newStatus.status() << endl;
+ // first, exclude changes due to blocking or subscription changes at the protocol level
+ if ( ( m_oldStatus.status() == Kopete::OnlineStatus::Unknown
+ || newStatus.status() == Kopete::OnlineStatus::Unknown ) )
+ t = noEvent; // This means the contact's changed from or to unknown - due to a protocol state change, not a contact state change
+ else // we're dealing with a genuine contact state change
+ {
+ if ( m_oldStatus.status() == Kopete::OnlineStatus::Offline )
+ {
+ if ( newStatus.status() != Kopete::OnlineStatus::Offline )
+ {
+ //kdDebug( 14000 ) << "signed in" << endl;
+ t = signedIn; // contact has gone from offline to something else, it's a sign-in
+ }
+ }
+ else if ( m_oldStatus.status() == Kopete::OnlineStatus::Online
+ || m_oldStatus.status() == Kopete::OnlineStatus::Away
+ || m_oldStatus.status() == Kopete::OnlineStatus::Invisible)
+ {
+ if ( newStatus.status() == Kopete::OnlineStatus::Offline )
+ {
+ //kdDebug( 14000 ) << "signed OUT" << endl;
+ t = signedOut; // contact has gone from an online state to an offline state, it's a sign out
+ }
+ else if ( m_oldStatus > newStatus || m_oldStatus < newStatus ) // operator!= is useless because it's an identity operator, not an equivalence operator
+ {
+ // contact has changed online states, it's a status change,
+ // and the preferredContact changed status, or there is a new preferredContacat
+ // so it's worth notifying
+ //kdDebug( 14000 ) << "changed status" << endl;
+ t = changedStatus;
+ }
+ }
+ else if ( m_oldStatus != newStatus )
+ {
+ //kdDebug( 14000 ) << "non-event" << endl;
+ // catch-all for any other status change we don't know about
+ t = noEvent;
+ }
+ // if none of the above were true, t will still be noChange
+ }
+
+ // now issue the appropriate notification
+ switch ( t )
+ {
+ case noEvent:
+ case noChange:
+ break;
+ case signedIn:
+ connect(KNotification::event(m_metaContact, "kopete_contact_online", text, m_metaContact->photo(), KopeteSystemTray::systemTray(), i18n( "Chat" )) ,
+ SIGNAL(activated(unsigned int )) , this, SLOT( execute() ) );
+ break;
+ case changedStatus:
+ connect(KNotification::event(m_metaContact, "kopete_contact_status_change", text, m_metaContact->photo(), KopeteSystemTray::systemTray(), i18n( "Chat" )) ,
+ SIGNAL(activated(unsigned int )) , this, SLOT( execute() ));
+ break;
+ case signedOut:
+ KNotification::event(m_metaContact, "kopete_contact_offline", text, m_metaContact->photo(), KopeteSystemTray::systemTray());
+ break;
+ }
+ }
+ //blink if the metacontact icon has changed.
+ if ( !mBlinkTimer->isActive() && d->metaContactIcon /*&& d->metaContactIcon->pixmap() != m_oldStatusIcon */)
+ {
+ mIsBlinkIcon = false;
+ m_blinkLeft = 9;
+ mBlinkTimer->start( 400, false );
+ }
+ }
+ else
+ {
+ //the status icon probably changed, but we didn't blink.
+ //So the olfStatusIcon will not be set to the real after the blink.
+ //we set it now.
+ if( !mBlinkTimer->isActive() )
+ m_oldStatusIcon=d->metaContactIcon ? d->metaContactIcon->pixmap() : QPixmap();
+ }
+
+ // make a note of the current status for the next time we get a status change
+ m_oldStatus = newStatus;
+
+ if ( m_parentGroup )
+ m_parentGroup->refreshDisplayName();
+ updateVisibility();
+}
+
+void KopeteMetaContactLVI::slotUpdateMetaContact()
+{
+ slotIdleStateChanged( 0 );
+ updateVisibility();
+
+ if ( m_parentGroup )
+ m_parentGroup->refreshDisplayName();
+}
+
+void KopeteMetaContactLVI::execute() const
+{
+ if ( d->events.first() )
+ d->events.first()->apply();
+ else
+ m_metaContact->execute();
+
+ //The selection is removed, but the contact still hihjlihted, remove the selection in the contactlist (see bug 106090)
+ Kopete::ContactList::self()->setSelectedItems( QPtrList<Kopete::MetaContact>() , QPtrList<Kopete::Group>() );
+}
+
+void KopeteMetaContactLVI::slotDisplayNameChanged()
+{
+ if ( d->nameText )
+ {
+ d->nameText->setText( m_metaContact->displayName() );
+
+ // delay the sort if we can
+ if ( ListView::ListView *lv = dynamic_cast<ListView::ListView *>( listView() ) )
+ lv->delayedSort();
+ else
+ listView()->sort();
+ }
+}
+
+void KopeteMetaContactLVI::slotPhotoChanged()
+{
+ if ( d->metaContactIcon && d->currentIconMode == KopetePrefs::PhotoPic )
+ {
+ m_oldStatusIcon= d->metaContactIcon->pixmap();
+ QPixmap photoPixmap;
+ //QPixmap defaultIcon( KGlobal::iconLoader()->loadIcon( "vcard", KIcon::Desktop ) );
+ QImage photoImg = m_metaContact->photo();
+ if ( !photoImg.isNull() && (photoImg.width() > 0) && (photoImg.height() > 0) )
+ {
+ int photoSize = d->iconSize;
+
+ photoImg = photoImg.smoothScale( photoSize, photoSize, QImage::ScaleMin );
+
+ KImageEffect *effect = 0L;
+ switch ( m_metaContact->status() )
+ {
+ case Kopete::OnlineStatus::Online:
+ break;
+ case Kopete::OnlineStatus::Away:
+ effect = new KImageEffect();
+ effect->fade(photoImg, 0.5, Qt::white);
+ break;
+ case Kopete::OnlineStatus::Offline:
+ effect = new KImageEffect();
+ effect->fade(photoImg, 0.4, Qt::white);
+ effect->toGray(photoImg);
+ break;
+ case Kopete::OnlineStatus::Unknown:
+ default:
+ effect = new KImageEffect();
+ effect->fade(photoImg, 0.8, Qt::white);
+ }
+ delete effect;
+
+ photoPixmap = photoImg;
+ }
+ else
+ {
+ photoPixmap=SmallIcon(m_metaContact->statusIcon(), d->iconSize);
+ }
+ d->metaContactIcon->setPixmap( photoPixmap, false);
+ if(mBlinkTimer->isActive())
+ m_originalBlinkIcon=photoPixmap;
+ }
+}
+
+/*
+void KopeteMetaContactLVI::slotRemoveThisUser()
+{
+ kdDebug( 14000 ) << k_funcinfo << " Removing user" << endl;
+ //m_metaContact->removeThisUser();
+
+ if ( KMessageBox::warningContinueCancel( Kopete::UI::Global::mainWidget(),
+ i18n( "Are you sure you want to remove %1 from your contact list?" ).
+ arg( m_metaContact->displayName() ), i18n( "Remove Contact" ), KGuiItem(i18n("Remove"),"delete_user") )
+ == KMessageBox::Continue )
+ {
+ Kopete::ContactList::self()->removeMetaContact( m_metaContact );
+ }
+}
+
+void KopeteMetaContactLVI::slotRemoveFromGroup()
+{
+ if ( m_metaContact->isTemporary() )
+ return;
+
+ m_metaContact->removeFromGroup( group() );
+}
+*/
+
+void KopeteMetaContactLVI::startRename( int /*col*/ )
+{
+ KListViewItem::startRename( 0 );
+}
+
+void KopeteMetaContactLVI::okRename( int col )
+{
+ KListViewItem::okRename( col );
+ setRenameEnabled( 0, false );
+}
+
+void KopeteMetaContactLVI::cancelRename( int col )
+{
+ KListViewItem::cancelRename( col );
+ setRenameEnabled( 0, false );
+}
+
+/*
+void KopeteMetaContactLVI::slotMoveToGroup()
+{
+ if ( m_actionMove && !m_metaContact->isTemporary() )
+ {
+ if ( m_actionMove->currentItem() == 0 )
+ {
+ // we are moving to top-level
+ if ( group() != Kopete::Group::toplevel )
+ m_metaContact->moveToGroup( group(), Kopete::Group::toplevel );
+ }
+ else
+ {
+ Kopete::Group *to = Kopete::ContactList::self()->getGroup( m_actionMove->currentText() );
+ if ( !m_metaContact->groups().contains( to ) )
+ m_metaContact->moveToGroup( group(), to );
+ }
+ }
+}
+
+void KopeteMetaContactLVI::slotAddToGroup()
+{
+ if ( m_actionCopy )
+ {
+ kdDebug( 14000 ) << "KopeteMetaContactLVI::slotAddToGroup " << endl;
+ if ( m_actionCopy->currentItem() == 0 )
+ {
+ // we are adding to top-level
+ m_metaContact->addToGroup( Kopete::Group::toplevel );
+ }
+ else
+ {
+ m_metaContact->addToGroup( Kopete::ContactList::self()->getGroup( m_actionCopy->currentText() ) );
+ }
+ }
+}
+*/
+
+//FIXME: this is not used... remove?
+void KopeteMetaContactLVI::slotAddToNewGroup()
+{
+ if ( m_metaContact->isTemporary() )
+ return;
+
+ QString groupName = KInputDialog::getText(
+ i18n( "New Group" ), i18n( "Please enter the name for the new group:" ) );
+
+ if ( !groupName.isEmpty() )
+ m_metaContact->addToGroup( Kopete::ContactList::self()->findGroup( groupName ) );
+}
+
+void KopeteMetaContactLVI::slotConfigChanged()
+{
+ setDisplayMode( KopetePrefs::prefs()->contactListDisplayMode(),
+ KopetePrefs::prefs()->contactListIconMode() );
+
+ // create a spacer if wanted
+ delete d->spacerBox->component( 0 );
+ if ( KListViewItem::parent() && KopetePrefs::prefs()->contactListIndentContacts() &&
+ !KopetePrefs::prefs()->treeView() )
+ {
+ new ListView::SpacerComponent( d->spacerBox, 20, 0 );
+ }
+
+ if ( KopetePrefs::prefs()->contactListUseCustomFonts() )
+ {
+ d->nameText->setFont( KopetePrefs::prefs()->contactListCustomNormalFont() );
+ if ( d->extraText )
+ d->extraText->setFont( KopetePrefs::prefs()->contactListSmallFont() );
+ }
+ else
+ {
+ QFont font=listView()->font();
+ d->nameText->setFont( font );
+ if(d->extraText)
+ {
+ if ( font.pixelSize() != -1 )
+ font.setPixelSize( (font.pixelSize() * 3) / 4 );
+ else
+ font.setPointSizeFloat( font.pointSizeFloat() * 0.75 );
+ d->extraText->setFont( font );
+ }
+ }
+
+ updateVisibility();
+ updateContactIcons();
+ slotIdleStateChanged( 0 );
+ if(d->nameText)
+ d->nameText->redraw();
+ if(d->extraText)
+ d->extraText->redraw();
+}
+
+void KopeteMetaContactLVI::setMetaContactToolTipSourceForComponent( ListView::Component *comp )
+{
+ if ( comp )
+ comp->setToolTipSource( d->toolTipSource.get() );
+}
+
+void KopeteMetaContactLVI::setDisplayMode( int mode, int iconmode )
+{
+ if ( mode == d->currentMode && iconmode == d->currentIconMode )
+ return;
+
+ d->currentMode = mode;
+ d->currentIconMode = iconmode;
+
+ // empty...
+ while ( component( 0 ) )
+ delete component( 0 );
+
+ d->nameText = 0L;
+ d->extraText = 0L;
+ d->metaContactIcon = 0L;
+ d->contactIconSize = 12;
+ if (mode == KopetePrefs::Detailed) {
+ d->iconSize = iconmode == KopetePrefs::IconPic ? KIcon::SizeMedium : KIcon::SizeLarge;
+ } else {
+ d->iconSize = iconmode == KopetePrefs::IconPic ? IconSize( KIcon::Small ) : KIcon::SizeMedium;
+ }
+ disconnect( Kopete::KABCPersistence::self()->addressBook() , 0 , this , 0);
+
+ // generate our contents
+ using namespace ListView;
+ Component *hbox = new BoxComponent( this, BoxComponent::Horizontal );
+ d->spacerBox = new BoxComponent( hbox, BoxComponent::Horizontal );
+
+ if (iconmode == KopetePrefs::PhotoPic) {
+ Component *imageBox = new BoxComponent( hbox, BoxComponent::Vertical );
+ new VSpacerComponent( imageBox );
+ d->metaContactIcon = new ImageComponent( imageBox, d->iconSize + 2 , d->iconSize + 2 );
+ new VSpacerComponent( imageBox );
+ if(!metaContact()->photoSource() && !Kopete::KABCPersistence::self()->addressBook()->findByUid( metaContact()->metaContactId() ).isEmpty() )
+ { //if the photo is the one of the kaddressbook, track every change in the adressbook, it might be the photo of our contact.
+ connect( Kopete::KABCPersistence::self()->addressBook() , SIGNAL(addressBookChanged (AddressBook *) ) ,
+ this , SLOT(slotPhotoChanged()));
+ }
+ } else {
+ d->metaContactIcon = new ImageComponent( hbox );
+ }
+
+ if( mode == KopetePrefs::Detailed )
+ {
+ d->contactIconSize = IconSize( KIcon::Small );
+ Component *vbox = new BoxComponent( hbox, BoxComponent::Vertical );
+ d->nameText = new DisplayNameComponent( vbox );
+ d->extraText = new DisplayNameComponent( vbox );
+
+ Component *box = new BoxComponent( vbox, BoxComponent::Horizontal );
+ d->contactIconBox = new BoxComponent( box, BoxComponent::Horizontal );
+ }
+ else if( mode == KopetePrefs::RightAligned ) // old right-aligned contact
+ {
+ d->nameText = new DisplayNameComponent( hbox );
+ new HSpacerComponent( hbox );
+ d->contactIconBox = new BoxComponent( hbox, BoxComponent::Horizontal );
+ }
+ else // older left-aligned contact
+ {
+ d->nameText = new DisplayNameComponent( hbox );
+ d->contactIconBox = new BoxComponent( hbox, BoxComponent::Horizontal );
+ }
+
+ // set some components to have the metacontact tooltip
+ setMetaContactToolTipSourceForComponent( d->metaContactIcon );
+ setMetaContactToolTipSourceForComponent( d->nameText );
+ setMetaContactToolTipSourceForComponent( d->extraText );
+
+ // update the display name
+ slotDisplayNameChanged();
+ slotPhotoChanged();
+ slotIdleStateChanged( 0 );
+
+ // finally, re-add all contacts so their icons appear. remove them first for consistency.
+ QPtrList<Kopete::Contact> contacts = m_metaContact->contacts();
+ for ( QPtrListIterator<Kopete::Contact> it( contacts ); it.current(); ++it )
+ {
+ slotContactRemoved( *it );
+ slotContactAdded( *it );
+ }
+ m_oldStatusIcon=d->metaContactIcon ? d->metaContactIcon->pixmap() : QPixmap();
+ if( mBlinkTimer->isActive() )
+ m_originalBlinkIcon=m_oldStatusIcon;
+}
+
+void KopeteMetaContactLVI::updateVisibility()
+{
+ if ( KopetePrefs::prefs()->showOffline() || !d->events.isEmpty() )
+ setTargetVisibility( true );
+ else if ( !m_metaContact->isOnline() && !mBlinkTimer->isActive() )
+ setTargetVisibility( false );
+ else
+ setTargetVisibility( true );
+}
+
+void KopeteMetaContactLVI::slotContactPropertyChanged( Kopete::Contact *contact,
+ const QString &key, const QVariant &old, const QVariant &newVal )
+{
+// if ( key == QString::fromLatin1("awayMessage") )
+// kdDebug( 14000 ) << k_funcinfo << "contact=" << contact->contactId() << ", isonline=" << contact->isOnline() << ", alloffline=" << !m_metaContact->isOnline() << ", oldvalue=" << old.toString() << ", newvalue=" << newVal.toString() << endl;
+ if ( key == QString::fromLatin1("awayMessage") && d->extraText && old != newVal )
+ {
+ bool allOffline = !m_metaContact->isOnline();
+ if ( newVal.toString().isEmpty() || ( !contact->isOnline() && !allOffline ) )
+ {
+ // try to find a more suitable away message to be displayed when:
+ // -new away message is empty or
+ // -contact who set it is offline and there are contacts online in the metacontact
+ bool allAwayMessagesEmpty = true;
+ QPtrList<Kopete::Contact> contacts = m_metaContact->contacts();
+ for ( Kopete::Contact *c = contacts.first(); c; c = contacts.next() )
+ {
+// kdDebug( 14000 ) << k_funcinfo << "ccontact=" << c->contactId() << ", isonline=" << c->isOnline() << ", awaymsg=" << c->property( key ).value().toString() << endl;
+ QString awayMessage( c->property( key ).value().toString() );
+ if ( ( allOffline || c->isOnline() ) && !awayMessage.isEmpty() )
+ {
+ // display this contact's away message when:
+ // -this contact's away message is not empty and
+ // -this contact is online or there are no contacts online at all
+ allAwayMessagesEmpty = false;
+ d->extraText->setText( awayMessage );
+ break;
+ }
+ }
+ if ( allAwayMessagesEmpty )
+ d->extraText->setText( QString::null );
+ }
+ else
+ {
+ // just use new away message when:
+ // -new away message is not empty and
+ // -contact who set it is online or there are no contacts online at all
+ d->extraText->setText( newVal.toString() );
+ }
+ } // wtf? KopeteMetaContact also connects this signals and emits photoChanged! why no connect photoChanged to slotPhotoChanged?
+ /*else if ( key == QString::fromLatin1("photo") && (m_metaContact->photoSourceContact() == contact) && (m_metaContact->photoSource() == Kopete::MetaContact::SourceContact))
+ {
+ slotPhotoChanged();
+ }*/
+}
+
+void KopeteMetaContactLVI::slotContactAdded( Kopete::Contact *c )
+{
+ connect( c, SIGNAL( propertyChanged( Kopete::Contact *, const QString &,
+ const QVariant &, const QVariant & ) ),
+ this, SLOT( slotContactPropertyChanged( Kopete::Contact *, const QString &,
+ const QVariant &, const QVariant & ) ) );
+ connect( c->account() , SIGNAL( colorChanged(const QColor& ) ) , this, SLOT( updateContactIcons() ) );
+
+ updateContactIcon( c );
+
+ slotContactPropertyChanged( c, QString::fromLatin1("awayMessage"),
+ QVariant(), c->property( QString::fromLatin1("awayMessage") ).value() );
+}
+
+void KopeteMetaContactLVI::slotContactRemoved( Kopete::Contact *c )
+{
+ disconnect( c, SIGNAL( propertyChanged( Kopete::Contact *, const QString &,
+ const QVariant &, const QVariant & ) ),
+ this, SLOT( slotContactPropertyChanged( Kopete::Contact *,
+ const QString &, const QVariant &, const QVariant & ) ) );
+ disconnect( c->account() , SIGNAL( colorChanged(const QColor& ) ) , this, SLOT( updateContactIcons() ) );
+
+ if ( ListView::Component *comp = contactComponent( c ) )
+ delete comp;
+
+ slotContactPropertyChanged( c, QString::fromLatin1("awayMessage"),
+ c->property( QString::fromLatin1("awayMessage") ).value(), QVariant() );
+}
+
+void KopeteMetaContactLVI::updateContactIcons()
+{
+ // show offline contacts setting may have changed
+ QPtrList<Kopete::Contact> contacts = m_metaContact->contacts();
+ for ( QPtrListIterator<Kopete::Contact> it( contacts ); it.current(); ++it )
+ updateContactIcon( *it );
+}
+
+void KopeteMetaContactLVI::updateContactIcon( Kopete::Contact *c )
+{
+ KGlobal::config()->setGroup( QString::fromLatin1("ContactList") );
+ bool bHideOffline = KGlobal::config()->readBoolEntry(
+ QString::fromLatin1("HideOfflineContacts"), false );
+ if ( KopetePrefs::prefs()->showOffline() )
+ bHideOffline = false;
+
+ ListView::ContactComponent *comp = contactComponent( c );
+ bool bShow = !bHideOffline || c->isOnline();
+ if ( bShow && !comp )
+ (void)new ListView::ContactComponent( d->contactIconBox, c, d->contactIconSize );
+ else if ( !bShow && comp )
+ delete comp;
+ else if ( comp )
+ comp->updatePixmap();
+}
+
+Kopete::Contact *KopeteMetaContactLVI::contactForPoint( const QPoint &p ) const
+{
+ if ( ListView::ContactComponent *comp = dynamic_cast<ListView::ContactComponent*>( d->contactIconBox->componentAt( p ) ) )
+ return comp->contact();
+ return 0L;
+}
+
+ListView::ContactComponent *KopeteMetaContactLVI::contactComponent( const Kopete::Contact *c ) const
+{
+ for ( uint n = 0; n < d->contactIconBox->components(); ++n )
+ {
+ if ( ListView::ContactComponent *comp = dynamic_cast<ListView::ContactComponent*>( d->contactIconBox->component( n ) ) )
+ {
+ if ( comp->contact() == c )
+ return comp;
+ }
+ }
+ return 0;
+}
+
+QRect KopeteMetaContactLVI::contactRect( const Kopete::Contact *c ) const
+{
+ if ( ListView::Component *comp = contactComponent( c ) )
+ return comp->rect();
+ return QRect();
+}
+
+Kopete::Group *KopeteMetaContactLVI::group()
+{
+ if ( m_parentGroup && m_parentGroup->group() != Kopete::Group::topLevel() )
+ return m_parentGroup->group();
+ else
+ return Kopete::Group::topLevel();
+}
+
+QString KopeteMetaContactLVI::key( int, bool ) const
+{
+ char importanceChar;
+ switch ( m_metaContact->status() )
+ {
+ case Kopete::OnlineStatus::Online:
+ importanceChar = 'A';
+ break;
+ case Kopete::OnlineStatus::Away:
+ importanceChar = 'B';
+ break;
+ case Kopete::OnlineStatus::Offline:
+ importanceChar = 'C';
+ break;
+ case Kopete::OnlineStatus::Unknown:
+ default:
+ importanceChar = 'D';
+ }
+
+ return importanceChar + d->nameText->text().lower();
+}
+
+bool KopeteMetaContactLVI::isTopLevel() const
+{
+ return m_isTopLevel;
+}
+
+bool KopeteMetaContactLVI::isGrouped() const
+{
+ if ( m_parentView )
+ return true;
+
+ if ( !m_parentGroup || !m_parentGroup->group() )
+ return false;
+
+ if ( m_parentGroup->group() == Kopete::Group::temporary() && !KopetePrefs::prefs()->sortByGroup() )
+ return false;
+
+ return true;
+}
+
+void KopeteMetaContactLVI::slotIdleStateChanged( Kopete::Contact *c )
+{
+ bool doWeHaveToGrayThatContact = KopetePrefs::prefs()->greyIdleMetaContacts() && ( m_metaContact->idleTime() >= 10 * 60 );
+ if ( doWeHaveToGrayThatContact )
+ {
+ d->nameText->setColor( KopetePrefs::prefs()->idleContactColor() );
+ if ( d->extraText )
+ d->extraText->setColor( KopetePrefs::prefs()->idleContactColor() );
+ }
+ else
+ {
+ d->nameText->setDefaultColor();
+ if ( d->extraText )
+ d->extraText->setDefaultColor();
+ }
+
+ if(d->metaContactIcon && d->currentIconMode==KopetePrefs::IconPic)
+ {
+ m_oldStatusIcon=d->metaContactIcon->pixmap();
+
+ QPixmap icon = SmallIcon( m_metaContact->statusIcon(), d->iconSize );
+ if ( doWeHaveToGrayThatContact )
+ {
+ // TODO: QPixmapCache this result
+ KIconEffect::semiTransparent( icon );
+ }
+
+ d->metaContactIcon->setPixmap( icon );
+ if(mBlinkTimer->isActive())
+ m_originalBlinkIcon=icon;
+ }
+ // we only need to update the contact icon if one was supplied;
+ // if none was supplied, we only need to update the MC appearance
+ if ( c )
+ updateContactIcon( c );
+ else
+ return;
+}
+
+void KopeteMetaContactLVI::catchEvent( Kopete::MessageEvent *event )
+{
+ d->events.append( event );
+
+ connect( event, SIGNAL( done( Kopete::MessageEvent* ) ),
+ this, SLOT( slotEventDone( Kopete::MessageEvent * ) ) );
+
+ if ( mBlinkTimer->isActive() )
+ mBlinkTimer->stop();
+
+ m_oldStatusIcon= d->metaContactIcon ? d->metaContactIcon->pixmap() : QPixmap();
+
+ mBlinkTimer->start( 400, false );
+
+ //show the contact if it was hidden because offline.
+ updateVisibility();
+ }
+
+void KopeteMetaContactLVI::slotBlink()
+{
+ bool haveEvent = !d->events.isEmpty();
+ if ( mIsBlinkIcon )
+ {
+ if(d->metaContactIcon)
+ d->metaContactIcon->setPixmap( m_originalBlinkIcon );
+ if ( !haveEvent && m_blinkLeft <= 0 )
+ {
+ mBlinkTimer->stop();
+ m_oldStatusIcon=d->metaContactIcon ? d->metaContactIcon->pixmap() : QPixmap();
+ updateVisibility();
+ m_originalBlinkIcon=QPixmap(); //i hope this help to reduce memory consuption
+ }
+ }
+ else
+ {
+ if(d->metaContactIcon)
+ m_originalBlinkIcon=d->metaContactIcon->pixmap();
+ if ( haveEvent )
+ {
+ if(d->metaContactIcon)
+ d->metaContactIcon->setPixmap( SmallIcon( "newmsg", d->iconSize ) );
+ }
+ else
+ {
+ if(d->metaContactIcon)
+ d->metaContactIcon->setPixmap( m_oldStatusIcon );
+ m_blinkLeft--;
+ }
+ }
+
+ mIsBlinkIcon = !mIsBlinkIcon;
+}
+
+void KopeteMetaContactLVI::slotEventDone( Kopete::MessageEvent *event )
+{
+ d->events.remove( event );
+
+ if ( d->events.isEmpty() )
+ {
+ if ( mBlinkTimer->isActive() )
+ {
+ mBlinkTimer->stop();
+ //If the contact gone offline while the timer was actif,
+ //the visibility has not been correctly updated. so do it now
+ updateVisibility();
+ }
+
+ if(d->metaContactIcon)
+ d->metaContactIcon->setPixmap( m_originalBlinkIcon );
+ m_originalBlinkIcon=QPixmap(); //i hope this help to reduce memory consuption
+ mIsBlinkIcon = false;
+ }
+}
+
+QString KopeteMetaContactLVI::text( int column ) const
+{
+ if ( column == 0 )
+ return d->nameText->text();
+ else
+ return KListViewItem::text( column );
+}
+
+void KopeteMetaContactLVI::setText( int column, const QString &text )
+{
+ if ( column == 0 )
+ rename( text );
+ else
+ KListViewItem::setText( column, text );
+}
+
+#include "kopetemetacontactlvi.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
diff --git a/kopete/kopete/contactlist/kopetemetacontactlvi.h b/kopete/kopete/contactlist/kopetemetacontactlvi.h
new file mode 100644
index 00000000..767330ba
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetemetacontactlvi.h
@@ -0,0 +1,191 @@
+/*
+ kopetemetacontactlvi.h - Kopete Meta Contact KListViewItem
+
+ Copyright (c) 2004 by Richard Smith <kde@metafoo.co.uk>
+ Copyright (c) 2002-2003 by Olivier Goffart <ogoffart @ kde.org>
+ Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
+ Copyright (c) 2002 by Duncan Mac-Vicar P <duncan@kde.org>
+
+ Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef __kopetemetacontactlvi_h__
+#define __kopetemetacontactlvi_h__
+
+#include "kopetelistviewitem.h"
+
+#include <qobject.h>
+#include <qpixmap.h>
+#include <qptrdict.h>
+
+#include <klistview.h>
+
+class QVariant;
+
+class KAction;
+class KListAction;
+
+namespace Kopete
+{
+class Account;
+class MetaContact;
+class Contact;
+class Group;
+class MessageEvent;
+}
+
+class AddContactPage;
+class KopeteGroupViewItem;
+
+
+/**
+ * @author Martijn Klingens <klingens@kde.org>
+ */
+class KopeteMetaContactLVI : public Kopete::UI::ListView::Item
+{
+ Q_OBJECT
+
+public:
+ KopeteMetaContactLVI( Kopete::MetaContact *contact, KopeteGroupViewItem *parent );
+ KopeteMetaContactLVI( Kopete::MetaContact *contact, QListViewItem *parent );
+ KopeteMetaContactLVI( Kopete::MetaContact *contact, QListView *parent );
+ ~KopeteMetaContactLVI();
+
+ /**
+ * metacontact this visual item represents
+ */
+ Kopete::MetaContact *metaContact() const
+ { return m_metaContact; };
+
+ /**
+ * true if the item is at top level and not under a group
+ */
+ bool isTopLevel() const;
+
+ /**
+ * parent when top-level
+ */
+ QListView *parentView() const { return m_parentView; };
+
+ /**
+ * parent when not top-level
+ */
+ KopeteGroupViewItem *parentGroup() const { return m_parentGroup; };
+
+ /**
+ * call this when the item has been moved to a different group
+ */
+ void movedToDifferentGroup();
+ void rename( const QString& name );
+ void startRename( int );
+
+ Kopete::Group *group();
+
+ /**
+ * Returns the Kopete::Contact of the small little icon at the point p
+ * @param p must be in the list view item's coordinate system.
+ * Returns a null pointer if p is not on a small icon.
+ * (This is used for e.g. the context-menu of a contact when
+ * right-clicking an icon, or the tooltips)
+ */
+ Kopete::Contact *contactForPoint( const QPoint &p ) const;
+
+ /**
+ * Returns the QRect small little icon used for the Kopete::Contact.
+ * The behavior is undefined if @param c doesn't point to a valid
+ * Kopete::Contact for this list view item.
+ * The returned QRect is using the list view item's coordinate
+ * system and should probably be transformed into the list view's
+ * coordinates before being of any practical use.
+ * Note that the returned Rect is always vertically stretched to fill
+ * the full list view item's height, only the width is relative to
+ * the actual icon width.
+ */
+ QRect contactRect( const Kopete::Contact *c ) const;
+
+ bool isGrouped() const;
+
+ /**
+ * reimplemented from KListViewItem to take into account our alternate text storage
+ */
+ virtual QString text( int column ) const;
+ virtual void setText( int column, const QString &text );
+
+public slots:
+ /**
+ * Call the meta contact's execute as I don't want to expose m_contact
+ * directly.
+ */
+ void execute() const;
+
+ void catchEvent( Kopete::MessageEvent * );
+
+ void updateVisibility();
+
+private slots:
+ void slotUpdateMetaContact();
+ void slotContactStatusChanged( Kopete::Contact * );
+ void slotContactPropertyChanged( Kopete::Contact *, const QString &, const QVariant &, const QVariant & );
+ void slotContactAdded( Kopete::Contact * );
+ void slotContactRemoved( Kopete::Contact * );
+
+ void slotDisplayNameChanged();
+ void slotPhotoChanged();
+
+ void slotAddToNewGroup();
+ void slotIdleStateChanged( Kopete::Contact * =0L);
+
+ void slotConfigChanged();
+
+ void slotEventDone( Kopete::MessageEvent* );
+ void slotBlink();
+
+ void updateContactIcons();
+
+protected:
+ void okRename(int col);
+ void cancelRename(int col);
+
+private:
+ void initLVI();
+ void setDisplayMode( int mode, int iconMode );
+ void setMetaContactToolTipSourceForComponent( Kopete::UI::ListView::Component *comp );
+ QString key( int column, bool ascending ) const;
+ void updateContactIcon( Kopete::Contact * );
+ Kopete::UI::ListView::ContactComponent *contactComponent( const Kopete::Contact *c ) const;
+
+ Kopete::MetaContact *m_metaContact;
+ KopeteGroupViewItem *m_parentGroup;
+ QListView *m_parentView;
+ bool m_isTopLevel;
+
+ int m_pixelWide;
+
+ Kopete::OnlineStatus m_oldStatus;
+ QPixmap m_oldStatusIcon;
+ QPixmap m_originalBlinkIcon;
+
+ QTimer *mBlinkTimer;
+
+ QPtrDict<Kopete::Account> m_addContactActions;
+
+ bool mIsBlinkIcon;
+ int m_blinkLeft;
+
+ class Private;
+ Private *d;
+};
+
+#endif
+
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/kopete/contactlist/kopetemetalvipropswidget.ui b/kopete/kopete/contactlist/kopetemetalvipropswidget.ui
new file mode 100644
index 00000000..e191d4b9
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetemetalvipropswidget.ui
@@ -0,0 +1,587 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KopeteMetaLVIPropsWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KopeteMetaLVIPropsWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>530</width>
+ <height>457</height>
+ </rect>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>grpAddressbook</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Address Book Link</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="Kopete::UI::AddressBookLinkWidget">
+ <property name="name">
+ <cstring>widAddresseeLink</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>btnExportKABC</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>E&amp;xport Details...</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Export contact's details to the KDE Address Book</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>107</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>btnImportKABC</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Import Contacts</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Import contacts from the KDE Address Book</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QButtonGroup" row="1" column="0">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Display Name Source</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioNameKABC</cstring>
+ </property>
+ <property name="text">
+ <string>Use addressbook &amp;name (needs addressbook link)</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioNameContact</cstring>
+ </property>
+ <property name="text">
+ <string>From contact:</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>cmbAccountName</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Contact to synchronize the displayname with.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioNameCustom</cstring>
+ </property>
+ <property name="text">
+ <string>Cus&amp;tom:</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>50</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>edtDisplayName</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QButtonGroup" row="2" column="0">
+ <property name="name">
+ <cstring>buttonGroup2</cstring>
+ </property>
+ <property name="title">
+ <string>Photo Source</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="1" rowspan="3" colspan="1">
+ <property name="name">
+ <cstring>photoLabel</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>64</width>
+ <height>92</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>64</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>Box</enum>
+ </property>
+ <property name="lineWidth">
+ <number>1</number>
+ </property>
+ <property name="text">
+ <string>Photo</string>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>radioPhotoKABC</cstring>
+ </property>
+ <property name="text">
+ <string>U&amp;se addressbook photo (needs addressbook link)</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="0">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioPhotoContact</cstring>
+ </property>
+ <property name="text">
+ <string>From contact:</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>cmbAccountPhoto</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Contact to synchronize the displayname with.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioPhotoCustom</cstring>
+ </property>
+ <property name="text">
+ <string>Custom:</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer9_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KURLComboRequester">
+ <property name="name">
+ <cstring>cmbPhotoUrl</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnClearPhoto</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0">
+ <property name="name">
+ <cstring>chkSyncPhoto</cstring>
+ </property>
+ <property name="text">
+ <string>S&amp;ync photo to addressbook</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Ad&amp;vanced</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>grpIcons</cstring>
+ </property>
+ <property name="title">
+ <string>Icons</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>lblAway</cstring>
+ </property>
+ <property name="text">
+ <string>Awa&amp;y:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>icnbAway</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lblOnline</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Online:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>icnbOnline</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>chkUseCustomIcons</cstring>
+ </property>
+ <property name="text">
+ <string>Use custom status &amp;icons</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Check to set custom icons for this contact</string>
+ </property>
+ </widget>
+ <widget class="KIconButton" row="2" column="1">
+ <property name="name">
+ <cstring>icnbAway</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KIconButton" row="1" column="1">
+ <property name="name">
+ <cstring>icnbOnline</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KIconButton" row="1" column="3">
+ <property name="name">
+ <cstring>icnbOffline</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KIconButton" row="2" column="3">
+ <property name="name">
+ <cstring>icnbUnknown</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>lblOffline</cstring>
+ </property>
+ <property name="text">
+ <string>O&amp;ffline:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>icnbOffline</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>lblUnknown</cstring>
+ </property>
+ <property name="text">
+ <string>Un&amp;known:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>icnbUnknown</cstring>
+ </property>
+ </widget>
+ <spacer row="1" column="4">
+ <property name="name">
+ <cstring>spacerHorizontal1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>170</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>tabWidget</tabstop>
+ <tabstop>btnExportKABC</tabstop>
+ <tabstop>btnImportKABC</tabstop>
+ <tabstop>edtDisplayName</tabstop>
+ <tabstop>cmbAccountName</tabstop>
+ <tabstop>cmbAccountPhoto</tabstop>
+ <tabstop>chkSyncPhoto</tabstop>
+ <tabstop>chkUseCustomIcons</tabstop>
+ <tabstop>icnbOnline</tabstop>
+ <tabstop>icnbAway</tabstop>
+ <tabstop>icnbOffline</tabstop>
+ <tabstop>icnbUnknown</tabstop>
+</tabstops>
+<customwidgets>
+ <customwidget>
+ <class>Kopete::UI::AddressBookLinkWidget</class>
+ <header>addressbooklinkwidget.h</header>
+ </customwidget>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>addressbooklinkwidget.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kicondialog.h</includehint>
+ <includehint>kicondialog.h</includehint>
+ <includehint>kicondialog.h</includehint>
+ <includehint>kicondialog.h</includehint>
+</includehints>
+</UI>
diff --git a/kopete/kopete/contactlist/kopetestatusgroupviewitem.cpp b/kopete/kopete/contactlist/kopetestatusgroupviewitem.cpp
new file mode 100644
index 00000000..9dc910dd
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetestatusgroupviewitem.cpp
@@ -0,0 +1,51 @@
+/*
+ kopetestatusgroupviewitem.cpp
+
+ Class to show a status folder
+
+ Copyright (c) 2001-2003 by Duncan Mac-Vicar Prett <duncan@kde.org>
+
+ Kopete (c) 2002 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#include <kdebug.h>
+#include "kopetestatusgroupviewitem.h"
+
+KopeteStatusGroupViewItem::KopeteStatusGroupViewItem( Kopete::OnlineStatus::StatusType status_ , QListView *parent, const char *name )
+ : QListViewItem(parent,name)
+{
+ m_status = status_;
+}
+
+KopeteStatusGroupViewItem::~KopeteStatusGroupViewItem()
+{
+}
+
+QString KopeteStatusGroupViewItem::key( int, bool ) const
+{
+ switch (m_status)
+ {
+ case Kopete::OnlineStatus::Online :
+ return "A";
+ break;
+ case Kopete::OnlineStatus::Away :
+ return "B";
+ break;
+ case Kopete::OnlineStatus::Offline :
+ return "C";
+ break;
+ case Kopete::OnlineStatus::Unknown :
+ default:
+ return "D";
+ }
+}
+
diff --git a/kopete/kopete/contactlist/kopetestatusgroupviewitem.h b/kopete/kopete/contactlist/kopetestatusgroupviewitem.h
new file mode 100644
index 00000000..8b1a930f
--- /dev/null
+++ b/kopete/kopete/contactlist/kopetestatusgroupviewitem.h
@@ -0,0 +1,43 @@
+/*
+ kopetestatusgroupviewitem.h
+
+ Class to show a status folder
+
+ Copyright (c) 2001-2003 by Duncan Mac-Vicar Prett <duncan@kde.org>
+
+ Kopete (c) 2002 by the Kopete developers <kopete-devel@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. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KOPETESTATUSGROUPVIEWITEM_H
+#define KOPETESTATUSGROUPVIEWITEM_H
+
+#include <klistview.h>
+#include "kopetemetacontact.h"
+
+/**
+ *@author Duncan Mac-Vicar Prett <duncan@kde.org>
+ */
+
+ class KopeteStatusGroupViewItem : public QListViewItem
+{
+public:
+ KopeteStatusGroupViewItem( Kopete::OnlineStatus::StatusType status_ , QListView *parent, const char *name=0);
+ ~KopeteStatusGroupViewItem();
+
+private:
+
+ Kopete::OnlineStatus::StatusType m_status;
+ QString key( int column, bool ascending ) const;
+
+};
+
+#endif