Logo Search packages:      
Sourcecode: kmess version File versions  Download package

kmessview.cpp

/***************************************************************************
                          kmessview.cpp  -  description
                             -------------------
    begin                : Thu Jan 9 2003
    copyright            : (C) 2003 by Mike K. Bennett
                           (C) 2005 by Diederik van der Boor
    email                : mkb137b@hotmail.com
                           vdboor --at-- codingdomain.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "kmessview.h"

#include <qheader.h>
#include <qlabel.h>
#include <qstringlist.h>
#include <qtooltip.h>
#include <qstylesheet.h>
#include <qframe.h>
#include <qlayout.h>
#include <qpalette.h>
#include <qpushbutton.h>
#include <qimage.h>

#include <kdebug.h>
#include <kiconloader.h>
#include <kiconeffect.h>
#include <klistview.h>
#include <klocale.h>
#include <kurllabel.h>
#include <kaction.h>
#include <kpopupmenu.h>
#include <ksqueezedtextlabel.h>
#include <klineedit.h>
#include <krun.h>
#include <kurl.h>

#include "contact/contact.h"
#include "contact/contactlist.h"
#include "contact/group.h"
#include "dialogs/contactpropertiesdialog.h"

#include "contactlistviewitem.h"
#include "currentaccount.h"
#include "grouplistviewitem.h"
#include "kmessdebug.h"
#include "specialgroups.h"

#ifdef KMESSDEBUG_KMESSVIEW
#define KMESSDEBUG_KMESSVIEW_GENERAL
#endif


// The constructor
KMessView::KMessView(QWidget *parent, const char *name )
  : KMessViewInterface(parent,name),
    connected_(false),
    currentAccount_(0),
    initialized_(false)
{
  toolTip_ = new ToolTip(this, 0);

  // Capture focus events without subclassing the widget from the .UI file
  personalMessageInput_->installEventFilter(this);
  currentAccountDisplayPic_->installEventFilter(this);

  // Fake an event to configure the personal message input
  QEvent ev(QEvent::FocusOut);
  eventFilter(personalMessageInput_, &ev);

  // I actually want to implement a tooltip like filelight has,
  // but this makes things easier already.
  // It causes a dialog to display tooltips faster.
  QToolTip::setWakeUpDelay(200);
}



// The destructor
KMessView::~KMessView()
{
  delete toolTip_;

#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "DESTROYED KMessView " << endl;
#endif
}



// The currently playing song was changed.
void KMessView::changedSong( const QString &artist, const QString &/*album*/, const QString &track, bool playing )
{
  if( playing )
  {
    // Show status line
    if( ! nowListeningFrame_->isVisible() )
    {
      nowListeningFrame_->setHidden(false);
      nowListeningFrame_->setMaximumHeight(40);
    }

    // Update label
    QString longTitle = artist + (artist.isEmpty() ? "" : " - ") + track;
    nowListeningLabel_->setText( i18n("Now listening to %1").arg(longTitle) );
  }
  else
  {
    // Hide status line
    nowListeningFrame_->setHidden(true);
    nowListeningFrame_->setMaximumHeight(0);
  }
}



// The program is connected to the server.  Store the user account and
//  update the user information.
void KMessView::connected()
{
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView - connected" << endl;
#endif
  connected_ = true;

  // Run the update functions with the current user data
  slotUpdateEmailDisplay();
  slotUpdateUserStatus();
  slotUpdateNoEmails();
  slotUpdateDisplayPicture();

  // Enable the labels
  onlineStatusLabel_->setEnabled(true);
  emailLabel_->setEnabled(true);

  // Hide the now listening until something is playing
  changedSong( QString::null, QString::null, QString::null, false );

  // Restore the personal message text
  const QString &message = currentAccount_->getPersonalMessage();
  if( message.isEmpty() )
  {
    personalMessageInput_->setText( i18n("<Enter your personal message here>") );
  }
  else
  {
    personalMessageInput_->setText( message );
  }
}



// Called when the program has disconnected from the server.
void KMessView::disconnected()
{
  KIconLoader *loader = KGlobal::iconLoader();

  connected_ = false;

  // Disable and reset the labels
  onlineStatusLabel_->setText( i18n("Disconnected") );
  onlineStatusLabel_->setEnabled(false);
  currentAccountDisplayPic_->setPixmap( loader->loadIcon( "offline", KIcon::User ) );
  emailLabel_->setText("");
  emailLabel_->setEnabled(false);

  // Clear the contact list
  // (all current items still reffer to non-existing contacts)
  contactListView_->clear();
  personalMessageInput_->clear();

  // Add the existing groups of the contactlist to this view
  QPtrList<Group>          groupList( currentAccount_->getContactList()->getGroupList() );
  QPtrListIterator<Group>  it( groupList );
  while(it.current() != 0)
  {
    slotGroupAdded(it.current());
    ++it;
  }
}



// Fix the sort positions, by making them incremental again.
void KMessView::fixGroupSortPositions()
{
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView::fixGroupSortPositions" << endl;
#endif

  Group             *group;
  GroupListViewItem *groupItem  = findFirstGroup();
  int               newPosition = 0;

  while(groupItem != 0)
  {
    group = groupItem->getGroup();

    if(! group->isSpecialGroup())
    {
      // This does not change the list sorting
      // (since we found the items in this sequence),
      // but it ensures the sort-index is unique.
      group->setSortPosition(++newPosition);

#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
        kdDebug() << "KMessView: Group "   << group->getName()
                  << " has sort position " << newPosition      << endl;
#endif
    }

    groupItem = findNextGroup(groupItem);
  }
}



// Return the contact associated with the given item
Contact * KMessView::getContactByItem(QListViewItem *item) const
{
  if(item == 0)
  {
    // Happens when contactListView_->currentItem() is null.
    return 0;
  }

#ifdef KMESSTEST
  ASSERT( dynamic_cast<KMessListViewItem*>(item) != 0 );
#endif

  // Check the type
  int type = static_cast<KMessListViewItem*>(item) -> getType();

  switch(type)
  {
    case KMessListViewItem::LISTTYPE_CONTACT :
    {
      return static_cast<ContactListViewItem*>(item) -> getContact();
    }
  }

  return 0;
}



// Find out whether the contact is added to the group item
ContactListViewItem* KMessView::getContactItemInGroup(const QListViewItem *groupItem, const Contact *contact) const
{
  QListViewItem       *currentItem;
  ContactListViewItem *contactItem;
  int type;

  // Get the first item
  currentItem = groupItem->firstChild();

  while(currentItem != 0)
  {
    // Check the type
    type = static_cast<KMessListViewItem*>( currentItem )->getType();

    switch(type)
    {
      case KMessListViewItem::LISTTYPE_CONTACT :
      {
        // Check if this is the requested contact
        contactItem = static_cast<ContactListViewItem*>( currentItem );
        if(contactItem->getContact() == contact)
        {
          return contactItem;
        }
      }
    }

    // Get the next item
    currentItem = currentItem->nextSibling();
  }

  return 0;
}



// Return the group associated with the given item
Group * KMessView::getGroupByItem(QListViewItem *item) const
{
  if(item == 0)
  {
    // Happens when contactListView_->currentItem() is null.
    return 0;
  }

#ifdef KMESSTEST
  ASSERT( dynamic_cast<KMessListViewItem*>(item) != 0 );
#endif

  int            type;
  QListViewItem *realItem;

  // Find the root node
  realItem = item;
  while(realItem->parent() != 0)
  {
    realItem = realItem->parent();
  }

  // Check the type
  type = static_cast<KMessListViewItem*>(realItem) -> getType();

  switch(type)
  {
    case KMessListViewItem::LISTTYPE_GROUP :
    {
      return static_cast<GroupListViewItem*>(realItem) -> getGroup();
    }
  }

  return 0;
}



// Return the special group the contact should be placed in.
QString KMessView::getMetaGroupId(const Contact *contact) const
{
  if( contact->isFriend() )
  {
    // If a contact is in the friends list, show on top
    return SpecialGroups::INDIVIDUALS;
  }
  else if( contact->isAllowed() )
  {
    // If the contact is only allowed, show in "allowed" group
    return SpecialGroups::ALLOWED;
  }
  else if (contact->isBlocked() || contact->isReverse())
  {
    // The contact is either blocked, or *only* at the reverse list
    return SpecialGroups::REMOVED;
  }
  else
  {
    // Contact no longer visible in *any* list, is really removed.
    return QString::null;
  }
}



// Initialize the class
bool KMessView::initialize()
{
  bool         success;
  KIconLoader *loader = KGlobal::iconLoader();

  if ( initialized_ )
  {
    kdDebug() << "KMessView already initialized." << endl;
    return false;
  }

  success = initContactListView();
  if(! success)
  {
    kdDebug() << "KMessView - Couldn't initialize contact list view." << endl;
    return false;
  }

  success = initContactPopup();
  if(! success)
  {
    kdDebug() << "KMessView - Couldn't initialize contact popup." << endl;
    return false;
  }

  success = initGroupPopup();
  if(! success)
  {
    kdDebug() << "KMessView - Couldn't initialize group popup." << endl;
    return false;
  }

  // Set an icon for the email label
  // Using "knotify" icon because it's available everywhere. "multimedia" is SUSE-specific.
  emailPixmapLabel_->setPixmap( loader->loadIcon("mail_generic", KIcon::NoGroup) );
  nowListeningPixmapLabel_->setPixmap( loader->loadIcon("knotify", KIcon::NoGroup) );


  // Connect signals for the current-account
  currentAccount_ = CurrentAccount::instance();

  connect( currentAccount_, SIGNAL(            changedMsnObject() ),
           this,            SLOT  (    slotUpdateDisplayPicture() ) );  // Changed users display pic
  connect( currentAccount_, SIGNAL(             changedNoEmails() ),    // Changed e-mail count
           this,            SLOT  (          slotUpdateNoEmails() ) );
  connect( currentAccount_, SIGNAL(               changedStatus() ),    // Changed status
           this,            SLOT  (        slotUpdateUserStatus() ) );
  connect( currentAccount_, SIGNAL(         changedFriendlyName() ),    // Changed name
           this,            SLOT  (        slotUpdateUserStatus() ) );
  connect( currentAccount_, SIGNAL( changedEmailDisplaySettings() ),    // Changed e-mail display settings
           this,            SLOT  (      slotUpdateEmailDisplay() ) );
  connect( currentAccount_, SIGNAL(      changedDisplaySettings() ),    // Changed group-display settings
           this,            SLOT  (   slotUpdateDisplaySettings() ) );
  connect( currentAccount_, SIGNAL(             changedViewMode() ),    // Changed the requested view mode
           this,            SLOT  (          slotUpdateViewMode() ) );

  // Connect signals for the contactlist
  const ContactList *contactList = currentAccount_->getContactList();

  connect( contactList, SIGNAL(             contactAdded(Contact*)       ),   // A contact was added.
           this,          SLOT(         slotContactAdded(Contact*)       ) );
  connect( contactList, SIGNAL(           contactOffline(Contact*,bool)  ),   // A contact went offline
           this,          SLOT( slotContactChangedOnline(Contact*)       ) );
  connect( contactList, SIGNAL(            contactOnline(Contact*,bool)  ),   // A contact went online
           this,          SLOT( slotContactChangedOnline(Contact*)       ) );
  connect( contactList, SIGNAL(             contactMoved(Contact*)       ),   // A contact was moved
           this,          SLOT(         slotContactMoved(Contact*)       ) );
  connect( contactList, SIGNAL(           contactRemoved(const Contact*) ),   // A contact was removed
           this,          SLOT(       slotContactRemoved(const Contact*) ) );
  connect( contactList, SIGNAL(               groupAdded(Group*)         ),   // A group was added
           this,          SLOT(           slotGroupAdded(Group*)         ) );
  connect( contactList, SIGNAL(             groupRemoved(const Group*)   ),   // A group was removed
           this,          SLOT(         slotGroupRemoved(const Group*)   ) );

  // Add the existing groups of the contactlist to this view
  QPtrList<Group>          groupList( contactList->getGroupList() );
  QPtrListIterator<Group>  it( groupList );
  while(it.current() != 0)
  {
    slotGroupAdded(it.current());
    ++it;
  }
  // Assign a ref. number to group positions
  fixGroupSortPositions();

  return true;
}



// The personal status message received an event.
bool KMessView::eventFilter(QObject *obj, QEvent *event)
{
  if( obj != personalMessageInput_
  &&  obj != currentAccountDisplayPic_ )
  {
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
    kdWarning() << "KMessView::eventFilter: Received event '" << event->type() << "' from object '" << obj->name() << "'." << endl;
#endif
    return false;
  }

  QEvent::Type eventType = event->type();

  if( obj == currentAccountDisplayPic_ )
  {
    if( eventType == QEvent::MouseButtonPress )
    {
      QImage glowingImage( currentAccount_->getImagePath() );
      KIconEffect::toGamma( glowingImage, 0.8 );
      currentAccountDisplayPic_->setPixmap( QPixmap( glowingImage ) );
    }
    else if( eventType == QEvent::MouseButtonRelease )
    {
      currentAccountDisplayPic_->setPixmap( QPixmap( currentAccount_->getImagePath() ) );
      emit showSettings();
    }
  }
  else if( obj == personalMessageInput_ )
  {
    if( eventType == QEvent::Enter )
    {
      // Mouse enters widget's boundaries
      // Just a bit different from the original client, already change the background line web-forms also do.
      // personalMessageInput_->setFrameShape( QLineEdit::StyledPanel );
      personalMessageInput_->setBackgroundColor( Qt::white );
    }
    else if( eventType == QEvent::Leave )
    {
      // Mouse leaves the widget.
      if( ! personalMessageInput_->hasFocus() )
      {
        // personalMessageInput_->setFrameShape( QLineEdit::NoFrame );
        personalMessageInput_->setBackgroundColor( this->backgroundColor() );
      }
    }
    else if( eventType == QEvent::FocusIn )
    {
      // Personal status mesage got the focus
      personalMessageInput_->setBackgroundColor( Qt::white );
      //personalMessageInput_->setFrameShape( QLineEdit::StyledPanel );
  
      // Clear if there is no status message, but a placeholder label
      if( currentAccount_->getPersonalMessage().isEmpty() )
      {
        personalMessageInput_->clear();
      }
      else
      {
        // Select all text for editing
        personalMessageInput_->selectAll();
      }
    }
    else if( event->type() == QEvent::FocusOut )
    {
      // Lost the focus
      //personalMessageInput_->setFrameShape( QLineEdit::NoFrame );
      personalMessageInput_->setBackgroundColor( this->backgroundColor() );
    }
  }

  return false;  // don't stop processing.
}



// Find the first group in the first
GroupListViewItem * KMessView::findFirstGroup() const
{
  QListViewItem *currentItem = contactListView_->firstChild();
  int            type;

  while(currentItem != 0)
  {
    // Check for the given type
    type = static_cast<KMessListViewItem*>( currentItem )->getType();

    switch(type)
    {
      case KMessListViewItem::LISTTYPE_GROUP :
      {
        return static_cast<GroupListViewItem*>( currentItem );
      }
    }

    // Get next item
    currentItem = currentItem->nextSibling();
  }

  return 0;
}



// Find the next group in the list
GroupListViewItem * KMessView::findNextGroup(GroupListViewItem *previousGroup) const
{
  QListViewItem *currentItem = previousGroup;
  int            type;

  // Get next item
  currentItem = currentItem->nextSibling();

  while(currentItem != 0)
  {
    // Check for the given type
    type = static_cast<KMessListViewItem*>( currentItem )->getType();

    switch(type)
    {
      case KMessListViewItem::LISTTYPE_GROUP :
      {
        return static_cast<GroupListViewItem*>( currentItem );
      }
    }

    // Get next item
    currentItem = currentItem->nextSibling();
  }

  return 0;
}



// Initialize the contact list view
bool KMessView::initContactListView()
{
  KIconLoader *loader = KGlobal::iconLoader();

  // Hide the column header
  contactListView_->header()->hide();
  contactListView_->setStaticBackground(true);   // Workarround for the smudge
//  contactListView_->setRootIsDecorated(true);
//  contactListView_->setPaletteForegroundColor( QColor( "#000000" ) );


  // Set a background pixmap
  backgroundPixmap_ = loader->loadIcon( "background", KIcon::User, 0, KIcon::DefaultState, 0L, true );

  if(! backgroundPixmap_.isNull())
  {
    contactListView_->setPaletteBackgroundPixmap( backgroundPixmap_ );
  }

  return true;
}



// Initialize the contact popup
bool KMessView::initContactPopup()
{
  // Initialize context menu actions
  chatWithContact_   = new KAction( i18n("Cha&t"),              "kontact_contacts", 0, this, "chat"            );
  emailContact_      = new KAction( i18n("&Send email"),        "mail_generic",     0, this, "email"           );
  msnProfile_        = new KAction( i18n("&View Profile"),      "identity",         0, this, "profile"         );
  contactProperties_ = new KAction( i18n("&Properties"),        "edit_user",        0, this, "properties"      );

  addContact_        = new KAction( i18n("&Add Contact"),       "add",              0, this, "add"             );
  allowContact_      = new KAction( i18n("A&llow Contact"),     "apply",            0, this, "allow"           );
  blockContact_      = new KAction( i18n("&Block Contact"),     "button_cancel",    0, this, "block"           );
  unblockContact_    = new KAction( i18n("&Unblock Contact"),   "button_ok",        0, this, "unblock"         );
  removeContact_     = new KAction( i18n("&Delete Contact"),    "delete_user",      0, this, "remove"          );
  removeFromGroup_   = new KAction( i18n("&Remove from group"), 0,                  0, this, "removeFromGroup" );

  // Connect the actions
  connect( chatWithContact_,   SIGNAL(activated()),   this,  SLOT(slotForwardStartChat())      );
  connect( emailContact_,      SIGNAL(activated()),   this,  SLOT(slotEmailContact())          );
  connect( msnProfile_,        SIGNAL(activated()),   this,  SLOT(slotShowContactProfile())    );
  connect( contactProperties_, SIGNAL(activated()),   this,  SLOT(slotShowContactProperties()) );

  connect( addContact_,        SIGNAL(activated()),   this,  SLOT(slotForwardAddContact())     );
  connect( allowContact_,      SIGNAL(activated()),   this,  SLOT(slotForwardAllowContact())   );
  connect( blockContact_,      SIGNAL(activated()),   this,  SLOT(slotForwardBlockContact())   );
  connect( unblockContact_,    SIGNAL(activated()),   this,  SLOT(slotForwardUnblockContact()) );
  connect( removeContact_,     SIGNAL(activated()),   this,  SLOT(slotForwardRemoveContact())  );
  connect( removeFromGroup_,   SIGNAL(activated()),   this,  SLOT(slotForwardRemoveFromGroup()));


  // Initialize sub menu's
  moveContactToGroup_ = new KActionMenu(i18n("&Move to Group"), this, "moveToGroup");
  copyContactToGroup_ = new KActionMenu(i18n("&Copy to Group"), this, "copyToGroup");

  // Initialize the popup menu
  contactActionPopup_ = new KPopupMenu(this);
  contactActionPopup_->insertTitle("KMess", 0);

  chatWithContact_   ->plug(contactActionPopup_);
  emailContact_      ->plug(contactActionPopup_);
  msnProfile_        ->plug(contactActionPopup_);
  contactProperties_ ->plug(contactActionPopup_);
  contactActionPopup_->insertSeparator();

  addContact_        ->plug(contactActionPopup_);
  allowContact_      ->plug(contactActionPopup_);

  blockContact_      ->plug(contactActionPopup_);
  unblockContact_    ->plug(contactActionPopup_);

  moveContactToGroup_->plug(contactActionPopup_);
  copyContactToGroup_->plug(contactActionPopup_);
  removeFromGroup_   ->plug(contactActionPopup_);
  removeContact_     ->plug(contactActionPopup_);


  return true;
}



// Initialize the group popup
bool KMessView::initGroupPopup()
{
  // Initialize context menu actions
  moveGroupDown_ = new KAction(i18n("Move Group &Down"), "1downarrow",   0, this, "movedown" );
  moveGroupUp_   = new KAction(i18n("Move Group &Up"),   "1uparrow",     0, this, "moveup"   );
  removeGroup_   = new KAction(i18n("Re&move Group"),    "editdelete",   0, this, "remove"   );
  renameGroup_   = new KAction(i18n("Re&name Group"),    "edit",         0, this, "rename"   );

  // Connect the actions
  connect( moveGroupDown_, SIGNAL(activated()),   this,  SLOT(slotMoveGroupDown())      );
  connect( moveGroupUp_,   SIGNAL(activated()),   this,  SLOT(slotMoveGroupUp())        );
  connect( removeGroup_,   SIGNAL(activated()),   this,  SLOT(slotForwardRemoveGroup()) );
  connect( renameGroup_,   SIGNAL(activated()),   this,  SLOT(slotForwardRenameGroup()) );

  // Initialize the popup menu
  groupActionPopup_ = new KPopupMenu(this);
  groupActionPopup_->insertTitle("KMess", 0);

  moveGroupUp_     ->plug(groupActionPopup_);
  moveGroupDown_   ->plug(groupActionPopup_);
  groupActionPopup_->insertSeparator();

  renameGroup_     ->plug(groupActionPopup_);
  removeGroup_     ->plug(groupActionPopup_);

  return true;
}

// Rebuild the contents of the move-contact menu.
void KMessView::rebuildCopyMenu(const Contact *contact)
{
  bool               inGroup;
  KAction           *copyAction = 0;
  QStringList        groupIds   = contact->getGroupIds();
  GroupListViewItem *groupItem  = findFirstGroup();

  while(groupItem != 0)
  {
    // First remove the item, because there is no way to tell whether
    // it was already added (besides, this fixes the sorting)
    copyContactToGroup_->remove(groupItem->getCopyAction());

    // add the item
    copyAction = groupItem->getCopyAction();  // is null for special groups

    if(copyAction != 0)
    {
      inGroup = groupIds.contains(groupItem->getGroup()->getId());
      if(! inGroup)
      {
        copyContactToGroup_->insert(copyAction);
      }
    }

    groupItem = findNextGroup(groupItem);
  }
}

// Rebuild the contents of the move-contact menu.
void KMessView::rebuildMoveMenu(const Contact *contact)
{
  bool               inGroup;
  KAction           *moveAction = 0;
  QStringList        groupIds   = contact->getGroupIds();
  GroupListViewItem *groupItem  = findFirstGroup();

  while(groupItem != 0)
  {
    // First remove the item, because there is no way to tell whether
    // it was already added (besides, this fixes the sorting)
    moveContactToGroup_->remove(groupItem->getMoveAction());

    // add the item
    moveAction = groupItem->getMoveAction();  // is null for special groups

    if(moveAction != 0)
    {
      inGroup = groupIds.contains(groupItem->getGroup()->getId());
      if(! inGroup)
      {
        moveContactToGroup_->insert(moveAction);
      }
    }

    groupItem = findNextGroup(groupItem);
  }
}



// The email label was clicked so open the user's preferred email url
void KMessView::slotEmailLabelClicked()
{
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView::slotEmailLabelClicked" << endl;
#endif

  currentAccount_->openMailAtInbox();
}



// Called when a contact was added.
void KMessView::slotContactAdded(Contact *contact)
{
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView::slotContactAdded" << endl;
#endif

  ContactListViewItem *item = 0;
  GroupListViewItem   *groupItem;

  Group       *group;
  QString      metaGroupId;
  QStringList  groupIds     = contact->getGroupIds();
  bool         addToOnline  = contact->isOnline();
  bool         addToOffline = contact->isOffline();
  bool         foundGroup   = false;
  bool         isIndividual = false;


  // Use meta-group id for non-grouped contacts
  if(groupIds.isEmpty())
  {
    metaGroupId = getMetaGroupId(contact);

    if(! metaGroupId.isNull())
    {
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
      kdDebug() << "KMessView::slotContactAdded: using meta group " << metaGroupId << endl;
#endif

      // Use meta group ID
      groupIds.append(metaGroupId);
      isIndividual = (metaGroupId == SpecialGroups::INDIVIDUALS);

      // Only add to online/offline if the contact
      // is visible in any other normal list.
      addToOnline  = (addToOnline  && isIndividual);
      addToOffline = (addToOffline && isIndividual);
    }
  }


  // Add a contact node to every related group
  groupItem = findFirstGroup();

  while(groupItem != 0)
  {
    group = groupItem->getGroup();

    // If the contact is a member of the group, add it
    if( groupIds.contains(group->getId()) )
    {
      groupItem->addContactItem(contact);
      foundGroup = true;
    }
    else if( (addToOnline  && group->getId() == SpecialGroups::ONLINE) ||
             (addToOffline && group->getId() == SpecialGroups::OFFLINE)  )
    {
      // Also make sure the contact is always added to the online/offline group.
      groupItem->addContactItem(contact);
    }

    groupItem = findNextGroup(groupItem);
  }


  // Also add item to root if not found
  if(! foundGroup)
  {
    // Add it to the list directly.
    item = new ContactListViewItem(contactListView_, contact);
  }
}



// Called when a contact went online or offline
void KMessView::slotContactChangedOnline(Contact *contact)
{
  // Move the contact to the other group.
  slotContactMoved(contact);
}



// Called when a contact is moved to a different position
void KMessView::slotContactMoved(Contact *contact)
{
  // Create the iterator
  QListViewItem       *currentItem;
  ContactListViewItem *contactItem;

  GroupListViewItem   *metaGroupItem = 0;
  GroupListViewItem   *groupItem     = 0;
  QString              groupId;
  int                  nodeType;

  QString     metaGroupId;
  QStringList groupIds       = contact->getGroupIds();
  bool        addToOnline    = contact->isOnline();
  bool        addToOffline   = contact->isOffline();
  bool        contactInGroup = false;
  bool        contactFound   = false;
  bool        isIndividual   = false;


  // Use meta-group id for non-grouped contacts
  if(groupIds.isEmpty())
  {
    metaGroupId = getMetaGroupId(contact);

    if(metaGroupId.isNull())
    {
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
      kdDebug() << "KMessView::slotContactMoved: contact has no groups, also no meta-group." << endl;
#endif
    }
    else
    {
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
      kdDebug() << "KMessView::slotContactMoved: contact has no groups, using meta group '" << metaGroupId << "'." << endl;
#endif

      // Use meta group
      groupIds.append(metaGroupId);
      isIndividual = (metaGroupId == SpecialGroups::INDIVIDUALS);

      // Only add to online/offline if the contact
      // is visible in any other normal list.
      addToOnline  = (addToOnline  && isIndividual);
      addToOffline = (addToOffline && isIndividual);
    }
  }


#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView::slotContactMoved "
            << contact->getHandle() << " moved to '" << groupIds.join(",") << "'." << endl;
#endif


  currentItem = contactListView_->firstChild();

  while(currentItem != 0)
  {
    // Check for the given type
    nodeType = static_cast<KMessListViewItem*>( currentItem )->getType();

    switch(nodeType)
    {
      case KMessListViewItem::LISTTYPE_GROUP :
      {
        // Read group properties
        groupItem      = static_cast<GroupListViewItem*>( currentItem );
        groupId        = groupItem->getGroup()->getId();

        // Does the contact exist here / should it exist here?
        contactItem    = getContactItemInGroup(currentItem, contact);
        contactInGroup = groupIds.contains(groupId);

        // Contact not found in this groupItem?
        if(contactItem == 0)
        {
          if((contactInGroup) ||
            (addToOnline  && groupId == SpecialGroups::ONLINE) ||
            (addToOffline && groupId == SpecialGroups::OFFLINE))
          {
            // Add to current group
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
            kdDebug() << "KMessView::slotContactMoved: Adding contact to '" << groupId << "'." << endl;
#endif
            groupItem->addContactItem(contact);

            // Only register contact if it's a normal group
            if(contactInGroup)
            {
              contactFound = true;
            }
          }
        }
        else // contactItem not found
        {
          if(contactInGroup)
          {
            // Found in the list
            contactFound = true;
          }
          else if(! (addToOnline  && groupId == SpecialGroups::ONLINE) &&  // unless "keep here, in online group"
                  ! (addToOffline && groupId == SpecialGroups::OFFLINE))   // and    "keep here, in offline group"
          {
            // Remove from current group.
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
            kdDebug() << "KMessView::slotContactMoved: Contact removed from '" << groupId << "'." << endl;
#endif
            groupItem->detachContactItem(contactItem);
            delete contactItem;
            groupItem->recountContacts();
          }
        }

        // If we found the meta-group, store it
        if(groupId == metaGroupId)
        {
          metaGroupItem = groupItem;
        }

        break;
      }
      case KMessListViewItem::LISTTYPE_CONTACT :
      {
        // Found a contact in the root.
        contactItem = static_cast<ContactListViewItem*>( currentItem );
        if(contactItem->getContact() == contact)
        {
          if(isIndividual)
          {
            // Found in the list
            contactFound = true;
          }
          else
          {
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
            kdDebug() << "KMessView::slotContactMoved: Contact removed from root." << endl;
#endif
            // Jump to nextSibling before we delete the object
            currentItem = currentItem->nextSibling();

            // Delete the object
            delete contactItem;
            continue;
          }
        }

        break;
      }
    }

    currentItem = currentItem->nextSibling();
  }


  // If the item was not found, add it to a special group
  if(! contactFound)
  {
    if(isIndividual)
    {
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
      kdDebug() << "KMessView::slotContactMoved: Contact not found in group nodes, but is individual, adding to root." << endl;
#endif
      // Add it to the list directly.
      contactItem = new ContactListViewItem(contactListView_, contact);
    }
    else if(metaGroupItem != 0)
    {
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
      kdDebug() << "KMessView::slotContactMoved: Contact not found in group nodes, adding to meta '" << metaGroupId << "'." << endl;
#endif
      // Add the contact to the meta-group
      metaGroupItem->addContactItem(contact);
    }
    else
    {
      if( ! groupIds.isEmpty() )
      {
        // No longer displayed, but still part of some groups?? Problem!
        kdWarning() << "KMessView: Contact " << contact->getHandle() << " is no longer displayed, "
                    << "but still a member of the groups '" << groupIds << "'!" << endl;
      }
      else
      {
        // the contact is removed from all lists,
        // only exists in kmess memory, no not display.
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
        kdDebug() << "KMessView::slotContactMoved: Contact " << contact->getHandle() << " no longer displayed." << endl;
#endif
      }
    }
  }
}



// Called when a contact is removed
void KMessView::slotContactRemoved(const Contact *contact)
{
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView::slotContactRemoved" << endl;
#endif

  QListViewItemIterator iterator(contactListView_);
  GroupListViewItem    *currentGroup = 0;
  ContactListViewItem  *contactItem;
  int type;

  while(iterator.current() != 0)
  {
    // Check for the given type
    type = static_cast<KMessListViewItem*>( iterator.current() )->getType();

    switch(type)
    {
      case KMessListViewItem::LISTTYPE_GROUP :
      {
        currentGroup = static_cast<GroupListViewItem*>( iterator.current() );
        break;
      }
      case KMessListViewItem::LISTTYPE_CONTACT :
      {
        // Check whether the object references a contact
        contactItem = static_cast<ContactListViewItem*>( iterator.current() );
        if(contactItem->getContact() == contact)
        {
          // Detach from current group
          if(currentGroup != 0)
          {
            currentGroup->detachContactItem(contactItem);
          }

          // remove it
          delete contactItem;  // is iterator.current()

          // Update group contact counter
          if(currentGroup != 0)
          {
            currentGroup->recountContacts();
          }
        }
        break;
      }
    }
    ++iterator;
  }
}



// A list item was right clicked.
void KMessView::slotContextMenu(QListViewItem *item, const QPoint &point, int /*col*/)
{
  Contact *contact = getContactByItem(item);
  Group   *group   = getGroupByItem(item);

  // A contact was pressed
  if(contact != 0)
  {
    bool isAllowed = contact->isAllowed();
    bool isBlocked = contact->isBlocked();
    bool isReverse = contact->isReverse();
    bool isFriend  = contact->isFriend();
    bool isOnline  = contact->isOnline();

    // Only chat if contact is friends list, and not blocked.
    chatWithContact_      ->setEnabled( isFriend && ! isBlocked && isOnline );

    moveContactToGroup_   ->setEnabled(   isFriend );

    // Only if the contact is not in the 'Implicit' group (group 0) or there is only one group;
    // (this means it will be the fifth ('Implicit', Online, Offline, Allowed, Removed);
    if(contact->getGroupIds()[0] == 0 ) 
    {
      copyContactToGroup_ ->setEnabled( false );
    }
    else if( contact->getGroupIds()[0] != 0 &&
             currentAccount_->getContactList()->getGroupList().count() == 5 ) 
    {
      copyContactToGroup_ ->setEnabled( false );
      moveContactToGroup_ ->setEnabled( false );
    }
    else
    {
      copyContactToGroup_ ->setEnabled( isFriend );
    }

    // Only if not added yet
    addContact_           ->setEnabled( ! isFriend );

    // Only allow if contact is on the "removed" group.
    allowContact_         ->setEnabled( ! isFriend && ! isAllowed && ! isBlocked );

    // Only one of these is enabled:
    blockContact_         ->setEnabled( ! isBlocked );
    unblockContact_       ->setEnabled(   isBlocked );

    // Only if the contact is on the friends list, or no longer
    // added to reverse list (otherwise an "contact has added you" message appears)
    removeContact_        ->setEnabled(   isFriend || ! isReverse );

    // Only if the contact is in the 'Implicit' group
    if(contact->getGroupIds()[0]==0)
    {
        removeFromGroup_  ->setEnabled(false);
    }
    else
    {
        removeFromGroup_  ->setEnabled(true);
    }

    // Rebuild the copy-to-group list
    rebuildCopyMenu(contact);

    // Rebuild the move-to-group list
    rebuildMoveMenu(contact);

    // Show the popup
    contactActionPopup_->changeTitle(0, contact->getHandle()); // Not name, because most msn names are too weird.
    contactActionPopup_->popup(point);
  }
  // A group was pressed
  else if( group != 0 && ! group->isSpecialGroup() )
  {
    int pos = group->getSortPosition();
    const ContactList *cl = currentAccount_->getContactList();

    moveGroupUp_   ->setEnabled( cl->getGroupBySortPosition( pos - 1 ) != 0 );
    moveGroupDown_ ->setEnabled( cl->getGroupBySortPosition( pos + 1 ) != 0 );

    // Show the popup
    groupActionPopup_->changeTitle( 0, i18n("Group") + ": " + group->getName() );
    groupActionPopup_->popup(point);
  }
}



// E-mail the current contact
void KMessView::slotEmailContact()
{
  Contact *contact = getContactByItem( contactListView_->currentItem() );
  if( KMESS_NULL(contact) ) return;

  currentAccount_->openMailAtCompose( contact->getHandle() );
}


// An item was clicked
void KMessView::slotItemClicked( QListViewItem *item )
{
  // Avoid accidental clicks
  if( ! KGlobalSettings::singleClick() )
  {
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
    kdDebug() << "KMessView::slotItemClicked() - Accidental click detected!" << endl;
#endif
    return;
  }

  // Forward the event to the execution slot
  slotItemExecuted( item );
}


// An item was double-clicked
void KMessView::slotItemDoubleClicked( QListViewItem *item )
{
  // Avoid accidental double-clicks
  if( KGlobalSettings::singleClick() )
  {
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
    kdDebug() << "KMessView::slotItemDoubleClicked() - Accidental double-click detected!" << endl;
#endif
    return;
  }

  // Forward the event to the execution slot
  slotItemExecuted( item );
}



// A list item was executed
void KMessView::slotItemExecuted(QListViewItem *item)
{
  // Handle group click events
  if( item != 0 && item->isExpandable() && item->childCount() > 0 )
  {
    // Open the group if it's collapsed, close it if it's expanded.
    Group *group = getGroupByItem( item );
    group->setExpanded( ! group->isExpanded() );
    return;
  }

  Contact *contact = getContactByItem(item);
  if(contact == 0) {
    return;  // e.g. not a contact.
  }

  // If the contact is online
  if(contact->isOnline())
  {
    // Tell the Chat Master class that we'd like to start a chat.
    emit requestChat( contact->getHandle() );
  }
}



// Forward the "add contact" menu action
void KMessView::slotForwardAddContact()
{
  Contact *contact = getContactByItem( contactListView_->currentItem() );
  if( KMESS_NULL(contact) ) return;

  emit addContact( contact->getHandle() );
}



// Forward the "allow contact" menu action
void KMessView::slotForwardAllowContact()
{
  Contact *contact = getContactByItem( contactListView_->currentItem() );
  if( KMESS_NULL(contact) ) return;

  emit allowContact( contact->getHandle() );
}



// Forward the "block contact" menu action
void KMessView::slotForwardBlockContact()
{
  Contact *contact = getContactByItem( contactListView_->currentItem() );
  if( KMESS_NULL(contact) ) return;

  emit blockContact( contact->getHandle() );
}



// Called when a contact should be copied
void KMessView::slotForwardCopyContact(Group *newGroup)
{
  Contact *contact = getContactByItem( contactListView_->currentItem() );
  if( KMESS_NULL(contact) ) return;

  emit copyContact( contact->getHandle(), newGroup->getId() );
}



// Called when a contact should be moved
void KMessView::slotForwardMoveContact(Group *newGroup)
{
  Contact *contact    = getContactByItem( contactListView_->currentItem() );
  Group   *oldGroup   = getGroupByItem( contactListView_->currentItem() );
  QString  oldGroupId = (oldGroup != 0 ? oldGroup->getId() : "0");
  if( KMESS_NULL(contact) ) return;

  emit moveContact( contact->getHandle(), oldGroupId, newGroup->getId() );
}



// Forward the "remove contact" menu action
void KMessView::slotForwardRemoveContact()
{
  Contact *contact = getContactByItem( contactListView_->currentItem() );
  if( KMESS_NULL(contact) ) return;

  emit removeContact( contact->getHandle() );
}


void KMessView::slotForwardRemoveFromGroup()
{
  Contact *contact = getContactByItem( contactListView_->currentItem() );
  Group   *group   = getGroupByItem(   contactListView_->currentItem() );
  if( KMESS_NULL(contact) ) return;

  emit removeContactFromGroup( contact->getHandle(), group->getId() );
}


// Forward the "remove group" menu action
void KMessView::slotForwardRemoveGroup()
{
  Group *group = getGroupByItem( contactListView_->currentItem() );
  if( KMESS_NULL(group) ) return;

  emit removeGroup( group->getId() );
}




// Forward the "rename group" menu action
void KMessView::slotForwardRenameGroup()
{
  Group *group = getGroupByItem( contactListView_->currentItem() );
  if( KMESS_NULL(group) ) return;

  emit renameGroup( group->getId() );
}



// Forward the "start chat" menu action
void KMessView::slotForwardStartChat()
{
  slotItemExecuted( contactListView_->currentItem() );
}



// Forward the "unblock contact" menu action
void KMessView::slotForwardUnblockContact()
{
  Contact *contact = getContactByItem( contactListView_->currentItem() );
  if( KMESS_NULL(contact) ) return;

  emit unblockContact( contact->getHandle() );
}



// Called when a group was added
void KMessView::slotGroupAdded(Group *group)
{
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView::slotGroupAdded" << endl;
#endif

  GroupListViewItem *item;
  item = new GroupListViewItem(contactListView_, group);

  if(! group->isSpecialGroup() || group->getId() == SpecialGroups::INDIVIDUALS)
  {
    // Connect item move and copy signals
    connect(item, SIGNAL(moveToGroup(Group*)), this, SLOT(slotForwardMoveContact(Group*)));
    connect(item, SIGNAL(copyToGroup(Group*)), this, SLOT(slotForwardCopyContact(Group*)));
    // Hide normal group if user likes to sort contacts by online/offline state
    item->setVisible( currentAccount_->getShowContactsByGroup() );
  }
  else
  {
    // For special groups, determine whether to show the item or not.
    if(group->getId() == SpecialGroups::ALLOWED)
    {
      item->setVisible( currentAccount_->getShowAllowedContacts() );
    }
    else if(group->getId() == SpecialGroups::REMOVED)
    {
      item->setVisible( currentAccount_->getShowRemovedContacts() );
    }
    else if(group->getId() == SpecialGroups::ONLINE)
    {
      item->setVisible( ! currentAccount_->getShowContactsByGroup() );
    }
    else if(group->getId() == SpecialGroups::OFFLINE)
    {
      item->setVisible( ! currentAccount_->getShowContactsByGroup() &&
                          currentAccount_->getShowOfflineContacts() );
    }
  }
}



// Called when a group was removed
void KMessView::slotGroupRemoved(const Group *group)
{
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView::slotGroupRemoved" << endl;
#endif

  GroupListViewItem *groupItem = findFirstGroup();

  while(groupItem != 0)
  {
    // If the group is found
    if(groupItem->getGroup() == group)
    {
      // remove it
      delete groupItem;
      return; // don't expect to find another group.
    }

    groupItem = findNextGroup(groupItem);
  }
}



// Called when a group should move down
void KMessView::slotMoveGroupDown()
{
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView::slotMoveGroupDown()" << endl;
#endif

  Group *nextGroup;
  int    sortPosition;
  Group *group = getGroupByItem( contactListView_->currentItem() );

  if(group != 0)
  {
    fixGroupSortPositions();

    // Swap both sort positions
    sortPosition = group->getSortPosition();
    nextGroup    = currentAccount_->getContactList()->getGroupBySortPosition(sortPosition + 1);

    if(nextGroup != 0)
    {
      group     ->setSortPosition( nextGroup->getSortPosition() );
      nextGroup ->setSortPosition( sortPosition                 );
      contactListView_->sort();
    }
    else
    {
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
      kdDebug() << "KMessView::slotMoveGroupDown: Next group not found" << endl;
#endif
    }
  }
}



// Called when a group should move up
void KMessView::slotMoveGroupUp()
{
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView::slotMoveGroupUp()" << endl;
#endif

  Group *previousGroup;
  int    sortPosition;
  Group *group = getGroupByItem( contactListView_->currentItem() );

  if(group != 0)
  {
    fixGroupSortPositions();

    // Swap both sort positions
    sortPosition  = group->getSortPosition();
    if(sortPosition <= 1) return;  // Already on top.
    previousGroup = currentAccount_->getContactList()->getGroupBySortPosition(sortPosition - 1);

    if(previousGroup != 0)
    {
      group         ->setSortPosition( previousGroup->getSortPosition() );
      previousGroup ->setSortPosition( sortPosition                     );
      contactListView_->sort();
    }
    else
    {
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
      kdDebug() << "KMessView::slotMoveGroupUp: Previous group not found" << endl;
#endif
    }
  }
}



// Called when the enter key is pressed on the personal message input
void KMessView::slotPersonalMessageEnterPressed()
{
  personalMessageInput_->clearFocus();
}



// Called when the personal message input looses focus
void KMessView::slotPersonalMessageLostFocus()
{
  if( ! connected_ )
  {
    // Avoid "lost focus" saving an empty message events when the dialog closes.
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
    kdDebug() << "KMessView::slotPersonalMessageLostFocus() - Not connected, so not updating." << endl;
#endif
    return;
  }

  personalMessageInput_->clearFocus();
  contactListView_->setFocus();

  // It was the main window which has lost focus, not the pm input box itself, so don't update.
  if( ! isActiveWindow() || ! topLevelWidget()->isActiveWindow() )
  {
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
    kdDebug() << "KMessView::slotPersonalMessageLostFocus() - Not updating when main window loses focus." << endl;
#endif
    return;
  }

#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView::slotPersonalMessageLostFocus() - Updating personal message" << endl;
#endif

  // Get message
  QString message = personalMessageInput_->text();

  // Protect against weird situations where the label is seen as text.
  // The lost focus event is also sent when the while window looses focus
  if( message == i18n("<Enter your personal message here>") )
  {
    kdWarning() << "KMessView: Personal message label was about to be used as personal message!" << endl;
    return;
  }

  // Update message and save the changes
  currentAccount_->setPersonalMessage( message );
  // Commit changes to disk, now
  KConfig *config = kapp->config();
  currentAccount_->saveProperties( config );

  // Notify changes to the MSN server
  emit changePersonalMessage( message );

  // Restore placeholder.
  if( message.isEmpty() )
  {
    personalMessageInput_->setText( i18n("<Enter your personal message here>") );
  }
}



// Display the profile of the current contact
void KMessView::slotShowContactProfile()
{
  QString   urlPath;
  KRun      *run;

  Contact *contact = getContactByItem( contactListView_->currentItem() );
  if(contact != 0)
  {
    // Create a URL to the msn profile page.  (Unfortunately, this isn't internationalized)
    run = new KRun( KURL( "http://members.msn.com/default.msnw?mem=" + contact->getHandle() ));
  }
}



// Display the properties of the current contact
void KMessView::slotShowContactProperties()
{
  ContactPropertiesDialog *dialog;

  Contact *contact = getContactByItem( contactListView_->currentItem() );
  if(contact != 0)
  {
    dialog = new ContactPropertiesDialog( this, "contactProperties" );
    dialog->launch( contact );
    delete dialog;
  }
}


// Update the users display pic
void KMessView::slotUpdateDisplayPicture()
{
  QString image = "";

  if( currentAccount_->getShowImage() )
  {
    displayPicFrame_->show();
    image = currentAccount_->getImagePath();
    currentAccountDisplayPic_->setPixmap( QPixmap( image ) );
  }
  else // The user does not want to show a display pic, so just show an icon for their sign in status
  {
    displayPicFrame_->hide();
  }
}


// Change whether the allowed,removed groups are displayed.
void KMessView::slotUpdateDisplaySettings()
{
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView::slotUpdateDisplaySettings - changing visibility of groups" << endl;
#endif

  // Read the settings
  bool showAllowed = currentAccount_->getShowAllowedContacts();
  bool showRemoved = currentAccount_->getShowRemovedContacts();
  bool showByGroup = currentAccount_->getShowContactsByGroup();
  bool showOffline = currentAccount_->getShowOfflineContacts();

  QString            groupId;
  GroupListViewItem *groupItem = findFirstGroup();

  while(groupItem != 0)
  {
    groupId = groupItem->getGroup()->getId();

    // Hide or show the special groups
    if(groupId == SpecialGroups::ALLOWED)
    {
      groupItem->setVisible( showAllowed );
    }
    else if(groupId == SpecialGroups::REMOVED)
    {
      groupItem->setVisible( showRemoved );
    }
    else if(groupId == SpecialGroups::ONLINE)
    {
      groupItem->setVisible( ! showByGroup );
    }
    else if(groupId == SpecialGroups::OFFLINE)
    {
      groupItem->setVisible( ! showByGroup && showOffline );
    }
    else
    {
      // For convenience, hide normal groups if display mode has changed.
      // This feature is used from slotUpdateViewMode()
      if(! groupItem->getGroup()->isSpecialGroup())
      {
        groupItem->setVisible( showByGroup );
      }
    }

    groupItem = findNextGroup(groupItem);
  }
}



// Change whether or not the email label is displayed based on account settings.
void KMessView::slotUpdateEmailDisplay()
{
  if ( currentAccount_->getShowEmail() && currentAccount_->getEmailSupported() )
  {
    emailFrame_->setHidden(false);
    //emailFrame_->setMargin(statusLayout_->margin());
    emailFrame_->setMaximumHeight(40);
  }
  else
  {
    emailFrame_->setHidden(true);
    //emailFrame_->setMargin(0);
    emailFrame_->setMaximumHeight(0);
  }
}



// Update the email count.
void KMessView::slotUpdateNoEmails()
{
  QString message;

  // Update the label
  if ( currentAccount_->getNoEmails() == 1 )
  {
    message = i18n("You have 1 new e-mail in your inbox.");
  }
  else
  {
    message = i18n("You have %1 new emails in your inbox.")
              .arg(currentAccount_->getNoEmails());
  }
  emailLabel_->setText( message );
  // Set the user's preferred email website.
  emailLabel_->setURL( currentAccount_->getEmailUrl() );
}



// Update the user's status.
void KMessView::slotUpdateUserStatus()
{
 
  QString          friendlyName, status;
  QString          statusIdentifier;
  QString          image;

  // Avoid newlines, which cause problems to the layout.
  friendlyName = currentAccount_->getFriendlyName().replace( "\n", " " );
  status = currentAccount_->getStatus();

#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView - update user status to " << status << endl;
#endif

  // Update the onlineStatusLabel and pixmap
  if ( status == "AWY" )
  {
    statusIdentifier = i18n( "(Away)" );
    image = "away";
  }
  else if ( status == "BRB" )
  {
    statusIdentifier = i18n( "(Be Right Back)" );
    image = "berightback";
  }
  else if ( status == "BSY" )
  {
    statusIdentifier = i18n( "(Busy)" );
    image = "busy";
  }
  else if ( status == "FLN" )
  {
    statusIdentifier = "";
    image = "online";
  }
  else if ( status == "HDN" )
  {
    statusIdentifier = i18n("(Invisible)");
    image = "invisible";
  }
  else if ( status == "IDL" )
  {
    statusIdentifier = i18n( "(Away - Idle)" );
    image = "away";
  }
  else if ( status == "LUN" )
  {
    statusIdentifier = i18n( "(Out to Lunch)" );
    image = "lunch";
  }
  else if ( status == "NLN" )
  {
    statusIdentifier = "";
    image = "online";
  }
  else if ( status == "PHN" )
  {
    statusIdentifier = i18n( "(On the Phone)" );
    image = "onthephone";
  }
  else
  {
    kdDebug() << "KMessView - updateUserStatus() - The account had the invalid status " << status << "." << endl;
    return;
  }
  onlineStatusLabel_->setText( friendlyName + "  " + statusIdentifier );
  KIconLoader *loader = KGlobal::iconLoader();
  onlineStatusPixmapLabel_->setPixmap( loader->loadIcon( image, KIcon::User ) );
}



// Update the way contact groups are displayed
void KMessView::slotUpdateViewMode()
{
  // Make the groups visible, contacts are already added to the
  // online/offline groups to make this viewmode update
  // easier and faster. (no need to move the contacts)
  slotUpdateDisplaySettings();
}



KMessView::ToolTip::ToolTip(KMessView *kmessView, QToolTipGroup *group)
: QToolTip(kmessView->contactListView_->viewport(), group),
  kmessView_(kmessView)
{
#ifdef KMESSDEBUG_KMESSVIEW_GENERAL
  kdDebug() << "KMessView: Created tooltip" << endl;
#endif
}


KMessView::ToolTip::~ToolTip()
{
  
}


void KMessView::ToolTip::maybeTip(const QPoint &cursorPosition)
{
  // Get the list view item.
  KMessListViewItem *currentItem = static_cast<KMessListViewItem*>( kmessView_->contactListView_->itemAt(cursorPosition) );
  if( currentItem == 0 )
  {
    return;
  }

  // Display the tooltip text of the list view item.
  QString tipText = currentItem->getToolTipText();
  if( ! tipText.isEmpty() )
  {
    tip( kmessView_->contactListView_->itemRect(currentItem), tipText );
  }
}


#include "kmessview.moc"

Generated by  Doxygen 1.6.0   Back to index