bool SortFilterProxyModel::lessThan (const QModelIndex& right, const QModelIndex& left) const // sort in reverse order ok { if (GetType (left) != Core::CLETContact || GetType (right) != Core::CLETContact) return QSortFilterProxyModel::lessThan (left, right); ICLEntry *lE = GetEntry (left); ICLEntry *rE = GetEntry (right); if (lE->GetEntryType () == ICLEntry::ETPrivateChat && rE->GetEntryType () == ICLEntry::ETPrivateChat && lE->GetParentCLEntry () == rE->GetParentCLEntry ()) { IMUCPerms *lp = qobject_cast<IMUCPerms*> (lE->GetParentCLEntry ()); if (lp) { bool less = lp->IsLessByPerm (lE->GetObject (), rE->GetObject ()); bool more = lp->IsLessByPerm (rE->GetObject (), lE->GetObject ()); if (less || more) return more; } } State lState = lE->GetStatus ().State_; State rState = rE->GetStatus ().State_; if (lState == rState || !OrderByStatus_) return lE->GetEntryName ().localeAwareCompare (rE->GetEntryName ()) < 0; else return IsLess (lState, rState); }
void Plugin::hookEntryStatusChanged (IHookProxy_ptr, QObject *entryObj, QString) { if (!IsGoodEntry (entryObj)) return; ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); const QString& id = entry->GetEntryID (); const EntryStatus& status = entry->GetStatus (); if (!LastState_.contains (id)) { LastState_ [id] = status.State_; return; } const State oldState = LastState_ [id]; LastState_ [id] = status.State_; switch (oldState) { case SOffline: case SProbe: case SError: case SInvalid: case SConnecting: return; case SOnline: LastAvailable_ [id] = QDateTime::currentDateTime (); default: LastOnline_ [id] = QDateTime::currentDateTime (); ScheduleSave (); } }
bool SortFilterProxyModel::lessThan (const QModelIndex& right, const QModelIndex& left) const // sort in reverse order ok { const auto leftType = GetType (left); if (leftType == Core::CLETAccount) return QSortFilterProxyModel::lessThan (left, right); else if (leftType == Core::CLETCategory) { const bool leftIsMuc = left.data (Core::CLRIsMUCCategory).toBool (); const bool rightIsMuc = right.data (Core::CLRIsMUCCategory).toBool (); if ((leftIsMuc && rightIsMuc) || (!leftIsMuc && !rightIsMuc)) return QSortFilterProxyModel::lessThan (left, right); else return rightIsMuc; } ICLEntry *lE = GetEntry (left); ICLEntry *rE = GetEntry (right); if (lE->GetEntryType () == ICLEntry::ETPrivateChat && rE->GetEntryType () == ICLEntry::ETPrivateChat && lE->GetParentCLEntry () == rE->GetParentCLEntry ()) if (IMUCPerms *lp = qobject_cast<IMUCPerms*> (lE->GetParentCLEntry ())) { bool less = lp->IsLessByPerm (lE->GetObject (), rE->GetObject ()); bool more = lp->IsLessByPerm (rE->GetObject (), lE->GetObject ()); if (less || more) return more; } State lState = lE->GetStatus ().State_; State rState = rE->GetStatus ().State_; if (lState == rState || !OrderByStatus_) return lE->GetEntryName ().localeAwareCompare (rE->GetEntryName ()) < 0; else return IsLess (lState, rState); }
void Plugin::hookTooltipBeforeVariants (IHookProxy_ptr proxy, QObject *entryObj) { if (!IsGoodEntry (entryObj)) return; ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); const QString& id = entry->GetEntryID (); QString addition; const State curState = entry->GetStatus ().State_; if (curState != SOnline) { const QDateTime& avail = LastAvailable_.value (id); if (avail.isValid ()) addition += tr ("Was available: %1") .arg (avail.toString ()); } if (curState == SOffline || curState == SError || curState == SInvalid) { const QDateTime& online = LastOnline_.value (id); if (LastOnline_.contains (id)) { if (!addition.isEmpty ()) addition += "<br/>"; addition += tr ("Was online: %1") .arg (online.toString ()); } } if (addition.isEmpty ()) return; const QString& tip = proxy->GetValue ("tooltip").toString (); proxy->SetValue ("tooltip", tip + "<br/><br/>" + addition + "<br/>"); }
bool SortFilterProxyModel::filterAcceptsRow (int row, const QModelIndex& parent) const { if (MUCMode_) { if (!MUCEntry_) return false; const QModelIndex& idx = sourceModel ()->index (row, 0, parent); switch (GetType (idx)) { case Core::CLETAccount: { QObject *acc = qobject_cast<ICLEntry*> (MUCEntry_)->GetParentAccount (); return acc == idx.data (Core::CLRAccountObject).value<QObject*> (); } case Core::CLETCategory: return idx.data ().toString () == qobject_cast<IMUCEntry*> (MUCEntry_)->GetGroupName (); default: break; } } else if (!ShowOffline_) { const QModelIndex& idx = sourceModel ()->index (row, 0, parent); if (!filterRegExp ().isEmpty ()) return GetType (idx) == Core::CLETContact ? idx.data ().toString ().contains (filterRegExp ()) : true; if (GetType (idx) == Core::CLETContact) { ICLEntry *entry = GetEntry (idx); const State state = entry->GetStatus ().State_; if (state == SOffline && !idx.data (Core::CLRUnreadMsgCount).toInt ()) return false; } } return QSortFilterProxyModel::filterAcceptsRow (row, parent); }
bool SortFilterProxyModel::filterAcceptsRow (int row, const QModelIndex& parent) const { if (MUCMode_) { if (!MUCEntry_) return false; const QModelIndex& idx = sourceModel ()->index (row, 0, parent); switch (GetType (idx)) { case Core::CLETAccount: { QObject *acc = qobject_cast<ICLEntry*> (MUCEntry_)->GetParentAccount (); return acc == idx.data (Core::CLRAccountObject).value<QObject*> (); } case Core::CLETCategory: { const QString& gName = idx.data ().toString (); return gName == qobject_cast<IMUCEntry*> (MUCEntry_)->GetGroupName () || qobject_cast<ICLEntry*> (MUCEntry_)->Groups ().contains (gName); } default: break; } } else { const QModelIndex& idx = sourceModel ()->index (row, 0, parent); if (!filterRegExp ().isEmpty ()) return GetType (idx) == Core::CLETContact ? idx.data ().toString ().contains (filterRegExp ()) : true; if (idx.data (Core::CLRUnreadMsgCount).toInt ()) return true; const auto type = GetType (idx); if (type == Core::CLETContact) { ICLEntry *entry = GetEntry (idx); const State state = entry->GetStatus ().State_; if (!ShowOffline_ && state == SOffline && !idx.data (Core::CLRUnreadMsgCount).toInt ()) return false; if (HideMUCParts_ && entry->GetEntryType () == ICLEntry::ETPrivateChat) return false; } else if (type == Core::CLETCategory) { if (!sourceModel ()->rowCount (idx)) return false; if (!ShowOffline_ && !idx.data (Core::CLRNumOnline).toInt ()) return false; } else if (type == Core::CLETAccount) { const auto& accObj = idx.data (Core::CLRAccountObject).value<QObject*> (); auto acc = qobject_cast<IAccount*> (accObj); return acc->IsShownInRoster (); } } return QSortFilterProxyModel::filterAcceptsRow (row, parent); }
void ContactListDelegate::DrawContact (QPainter *painter, QStyleOptionViewItemV4 option, const QModelIndex& index) const { QObject *entryObj = index.data (Core::CLREntryObject).value<QObject*> (); ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); const bool isMUC = entry->GetEntryType () == ICLEntry::ETMUC; QStyle *style = option.widget ? option.widget->style () : QApplication::style (); const QRect& r = option.rect; const int sHeight = r.height (); const int iconSize = sHeight - 2 * CPadding; const int clientIconSize = (iconSize > 16) ? 16 : iconSize; const QIcon& stateIcon = index.data (Qt::DecorationRole).value<QIcon> (); QString name = index.data (Qt::DisplayRole).value<QString> (); const QString status = entry->GetStatus ().StatusString_.replace ('\n', ' '); const QImage& avatarImg = ShowAvatars_ ? Core::Instance ().GetAvatar (entry, iconSize) : QImage (); const int unreadNum = index.data (Core::CLRUnreadMsgCount).toInt (); const QString& unreadStr = unreadNum ? QString (" %1 :: ").arg (unreadNum) : QString (); if (ShowStatuses_ && !status.isEmpty ()) name += " (" + status + ")"; const bool selected = option.state & QStyle::State_Selected; const QColor fgColor = selected ? option.palette.color (QPalette::HighlightedText) : option.palette.color (QPalette::Text); QFont unreadFont; int unreadSpace = 0; if (unreadNum) { unreadFont = option.font; unreadFont.setBold (true); unreadSpace = CPadding + QFontMetrics (unreadFont).width (unreadStr); } const int textShift = 2 * CPadding + iconSize + unreadSpace; const QStringList& vars = entry->Variants (); QList<QIcon> clientIcons; if (!isMUC && ShowClientIcons_) { const auto& iconsMap = Core::Instance ().GetClientIconForEntry (entry); for (int i = 0; i < std::min (vars.size (), 4); ++i) clientIcons << iconsMap [vars.at (i)]; clientIcons.erase (std::remove_if (clientIcons.begin (), clientIcons.end (), [] (const QIcon& icon) { return icon.isNull (); }), clientIcons.end ()); } if (entry->GetEntryType () == ICLEntry::ETPrivateChat) { const QByteArray& aff = index.data (Core::CLRAffiliation).toByteArray (); const QIcon& icon = Core::Instance ().GetAffIcon (aff); if (!icon.isNull ()) clientIcons.prepend (icon); } if (!vars.isEmpty ()) { const QMap<QString, QVariant>& addInfo = entry->GetClientInfo (vars.first ()); if (addInfo.contains ("user_activity")) { const QMap<QString, QVariant>& actInfo = addInfo ["user_activity"].toMap (); const QString& iconName = ActivityIconset_ + '/' + GetActivityIconName (actInfo ["general"].toString (), actInfo ["specific"].toString ()); QIcon icon = ActivityIconCache_ [iconName]; if (icon.isNull ()) icon = QIcon (Core::Instance () .GetResourceLoader (Core::RLTActivityIconLoader)-> GetIconPath (iconName)); if (!icon.isNull ()) { clientIcons.prepend (icon); ActivityIconCache_ [iconName] = icon; } } if (addInfo.contains ("user_mood")) { const QMap<QString, QVariant>& moodInfo = addInfo ["user_mood"].toMap (); QString iconName = moodInfo ["mood"].toString (); iconName [0] = iconName.at (0).toUpper (); iconName.prepend (MoodIconset_ + '/'); QIcon icon = MoodIconCache_ [iconName]; if (icon.isNull ()) icon = QIcon (Core::Instance () .GetResourceLoader (Core::RLTMoodIconLoader)-> GetIconPath (iconName)); if (!icon.isNull ()) { clientIcons.prepend (icon); MoodIconCache_ [iconName] = icon; } } if (addInfo.contains ("user_tune")) LoadSystemIcon ("/notification_roster_tune", clientIcons); ISupportGeolocation *geoloc = qobject_cast<ISupportGeolocation*> (entry->GetParentAccount ()); if (geoloc) { const GeolocationInfo_t& info = geoloc-> GetUserGeolocationInfo (entryObj, vars.value (0, QString ())); if (!info.isEmpty ()) LoadSystemIcon ("/geolocation", clientIcons); } } const int clientsIconsWidth = clientIcons.isEmpty () ? 0 : clientIcons.size () * (clientIconSize + CPadding); /* text for width is total width minus shift of the text from * the left (textShift) minus space for avatar (if present) with * paddings minus space for client icons and paddings between * them: there are N-1 paddings inbetween if there are N icons. */ const int textWidth = r.width () - textShift - (isMUC || !ShowAvatars_ ? 0 : (iconSize + 2 * CPadding)) - clientsIconsWidth; QPixmap pixmap (r.size ()); pixmap.fill (Qt::transparent); QPainter p (&pixmap); if (selected || (option.state & QStyle::State_MouseOver)) { QStyleOptionViewItemV4 bgOpt = option; bgOpt.rect.moveTopLeft (QPoint (0, 0)); style->drawPrimitive (QStyle::PE_PanelItemViewItem, &bgOpt, &p, option.widget); } p.setPen (fgColor); if (unreadNum) { p.setFont (unreadFont); p.drawText (textShift - unreadSpace, CPadding, textWidth, r.height () - 2 * CPadding, Qt::AlignVCenter | Qt::AlignLeft, unreadStr); } p.setFont (option.font); p.drawText (textShift, CPadding, textWidth, r.height () - 2 * CPadding, Qt::AlignVCenter | Qt::AlignLeft, option.fontMetrics.elidedText (name, Qt::ElideRight, textWidth)); const QPixmap& stateIconPx = stateIcon.pixmap (iconSize, iconSize); p.drawPixmap (QPoint (CPadding, (sHeight - stateIconPx.height ()) / 2), stateIconPx); if (!avatarImg.isNull ()) p.drawPixmap (QPoint (textShift + textWidth + clientsIconsWidth + CPadding, CPadding), QPixmap::fromImage (avatarImg)); int currentShift = textShift + textWidth + CPadding; Q_FOREACH (const QIcon& icon, clientIcons) { p.drawPixmap (QPoint (currentShift, (sHeight - stateIconPx.height ()) / 2), icon.pixmap (clientIconSize, clientIconSize)); currentShift += clientIconSize + CPadding; }
void ContactListDelegate::DrawContact (QPainter *painter, QStyleOptionViewItemV4 option, const QModelIndex& index) const { QObject *entryObj = index.data (Core::CLREntryObject).value<QObject*> (); ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); const bool isMUC = entry->GetEntryType () == ICLEntry::ETMUC; QStyle *style = option.widget ? option.widget->style () : QApplication::style (); const QRect& r = option.rect; const int sHeight = r.height (); const int iconSize = sHeight - 2 * CPadding; const QIcon& stateIcon = index.data (Qt::DecorationRole).value<QIcon> (); QString name = index.data (Qt::DisplayRole).value<QString> (); const QString& status = entry->GetStatus ().StatusString_; const QImage& avatarImg = ShowAvatars_ ? Core::Instance ().GetAvatar (entry, iconSize) : QImage (); const int unreadNum = index.data (Core::CLRUnreadMsgCount).toInt (); const QString& unreadStr = unreadNum ? QString (" %1 :: ").arg (unreadNum) : QString (); if (!status.isEmpty ()) name += " (" + status + ")"; const bool selected = option.state & QStyle::State_Selected; const QColor fgColor = selected ? option.palette.color (QPalette::HighlightedText) : option.palette.color (QPalette::Text); QFont unreadFont; int unreadSpace = 0; if (unreadNum) { unreadFont = option.font; unreadFont.setBold (true); unreadSpace = CPadding + QFontMetrics (unreadFont).width (unreadStr); } const int textShift = 2 * CPadding + iconSize + unreadSpace; const QList<QIcon>& clientIcons = isMUC || !ShowClientIcons_ ? QList<QIcon> () : Core::Instance ().GetClientIconForEntry (entry).values (); const int clientsIconsWidth = isMUC|| !ShowClientIcons_ ? 0 : clientIcons.size () * (iconSize + CPadding) - CPadding; /* text for width is total width minus shift of the text from * the left (textShift) minus space for avatar (if present) with * paddings minus space for client icons and paddings between * them: there are N-1 paddings inbetween if there are N icons. */ const int textWidth = r.width () - textShift - (isMUC || !ShowAvatars_ ? 0 : (iconSize + 2 * CPadding)) - clientsIconsWidth; QPixmap pixmap (r.size ()); pixmap.fill (Qt::transparent); QPainter p (&pixmap); p.translate (-r.topLeft ()); if (selected || (option.state & QStyle::State_MouseOver)) style->drawPrimitive (QStyle::PE_PanelItemViewItem, &option, &p, option.widget); p.setPen (fgColor); if (unreadNum) { p.setFont (unreadFont); p.drawText (r.left () + textShift - unreadSpace, r.top () + CPadding, textWidth, r.height () - 2 * CPadding, Qt::AlignVCenter | Qt::AlignLeft, unreadStr); } p.setFont (option.font); p.drawText (r.left () + textShift, r.top () + CPadding, textWidth, r.height () - 2 * CPadding, Qt::AlignVCenter | Qt::AlignLeft, option.fontMetrics.elidedText (name, Qt::ElideRight, textWidth)); p.drawPixmap (r.topLeft () + QPoint (CPadding, CPadding), stateIcon.pixmap (iconSize, iconSize)); if (!avatarImg.isNull ()) p.drawPixmap (r.topLeft () + QPoint (textShift + textWidth + clientsIconsWidth + CPadding, CPadding), QPixmap::fromImage (avatarImg)); int currentShift = textShift + textWidth + CPadding; Q_FOREACH (const QIcon& icon, clientIcons) { p.drawPixmap (r.topLeft () + QPoint (currentShift, CPadding), icon.pixmap (iconSize, iconSize)); currentShift += iconSize + CPadding; }