Пример #1
0
	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);
	}
Пример #2
0
	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 ();
		}
	}
Пример #3
0
	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);
	}
Пример #4
0
	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/>");
	}
Пример #5
0
	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);
	}
Пример #6
0
	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;
		}
Пример #8
0
	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;
		}