+QVariant UiStyle::nickViewItemData(const QModelIndex &index, int role) const {
+ NetworkModel::ItemType type = (NetworkModel::ItemType)index.data(NetworkModel::ItemTypeRole).toInt();
+
+ if(role == Qt::DecorationRole) {
+ if(!_showNickViewIcons)
+ return QVariant();
+
+ switch(type) {
+ case NetworkModel::UserCategoryItemType:
+ {
+ int categoryId = index.data(TreeModel::SortRole).toInt();
+ if(categoryId <= _opIconLimit)
+ return _categoryOpIcon;
+ if(categoryId <= _voiceIconLimit)
+ return _categoryVoiceIcon;
+ return _userOnlineIcon;
+ }
+ case NetworkModel::IrcUserItemType:
+ if(index.data(NetworkModel::ItemActiveRole).toBool())
+ return _userOnlineIcon;
+ else
+ return _userAwayIcon;
+ default:
+ return QVariant();
+ }
+ }
+
+ QTextCharFormat fmt = _listItemFormats.value(NickViewItem);
+
+ switch(type) {
+ case NetworkModel::IrcUserItemType:
+ fmt.merge(_listItemFormats.value(NickViewItem | IrcUserItem));
+ if(!index.data(NetworkModel::ItemActiveRole).toBool()) {
+ fmt.merge(_listItemFormats.value(NickViewItem | UserAway));
+ fmt.merge(_listItemFormats.value(NickViewItem | IrcUserItem | UserAway));
+ }
+ break;
+ case NetworkModel::UserCategoryItemType:
+ fmt.merge(_listItemFormats.value(NickViewItem | UserCategoryItem));
+ break;
+ default:
+ return QVariant();
+ }
+
+ return itemData(role, fmt);
+}
+
+QVariant UiStyle::itemData(int role, const QTextCharFormat &format) const {
+ switch(role) {
+ case Qt::FontRole:
+ return format.font();
+ case Qt::ForegroundRole:
+ return format.property(QTextFormat::ForegroundBrush);
+ case Qt::BackgroundRole:
+ return format.property(QTextFormat::BackgroundBrush);
+ default:
+ return QVariant();
+ }
+}
+
+/******** Caching *******/
+
+QTextCharFormat UiStyle::format(quint64 key) const {
+ return _formats.value(key, QTextCharFormat());
+}
+
+QTextCharFormat UiStyle::cachedFormat(quint32 formatType, quint32 messageLabel) const {
+ return _formatCache.value(formatType | ((quint64)messageLabel << 32), QTextCharFormat());
+}
+
+void UiStyle::setCachedFormat(const QTextCharFormat &format, quint32 formatType, quint32 messageLabel) {
+ _formatCache[formatType | ((quint64)messageLabel << 32)] = format;
+}
+
+QFontMetricsF *UiStyle::fontMetrics(quint32 ftype, quint32 label) {
+ // QFontMetricsF is not assignable, so we need to store pointers :/
+ quint64 key = ftype | ((quint64)label << 32);
+
+ if(_metricsCache.contains(key))
+ return _metricsCache.value(key);
+
+ return (_metricsCache[key] = new QFontMetricsF(format(ftype, label).font()));
+}
+
+/******** Generate formats ********/
+
+// NOTE: This and the following functions are intimately tied to the values in FormatType. Don't change this
+// until you _really_ know what you do!
+QTextCharFormat UiStyle::format(quint32 ftype, quint32 label_) {
+ if(ftype == Invalid)
+ return QTextCharFormat();
+
+ quint64 label = (quint64)label_ << 32;
+
+ // check if we have exactly this format readily cached already
+ QTextCharFormat fmt = cachedFormat(ftype, label_);
+ if(fmt.properties().count())
+ return fmt;
+
+ mergeFormat(fmt, ftype, label & Q_UINT64_C(0xffff000000000000));
+
+ for(quint64 mask = Q_UINT64_C(0x0000000100000000); mask <= (quint64)Selected << 32; mask <<=1) {
+ if(label & mask)
+ mergeFormat(fmt, ftype, mask | Q_UINT64_C(0xffff000000000000));
+ }
+
+ setCachedFormat(fmt, ftype, label_);
+ return fmt;
+}
+
+void UiStyle::mergeFormat(QTextCharFormat &fmt, quint32 ftype, quint64 label) {
+ mergeSubElementFormat(fmt, ftype & 0x00ff, label);
+
+ // TODO: allow combinations for mirc formats and colors (each), e.g. setting a special format for "bold and italic"
+ // or "foreground 01 and background 03"
+ if((ftype & 0xfff00)) { // element format
+ for(quint32 mask = 0x00100; mask <= 0x40000; mask <<= 1) {
+ if(ftype & mask) {
+ mergeSubElementFormat(fmt, ftype & (mask | 0xff), label);
+ }
+ }
+ }
+
+ // Now we handle color codes
+ // We assume that those can't be combined with subelement and message types.
+ if(_allowMircColors) {
+ if(ftype & 0x00400000)
+ mergeSubElementFormat(fmt, ftype & 0x0f400000, label); // foreground
+ if(ftype & 0x00800000)
+ mergeSubElementFormat(fmt, ftype & 0xf0800000, label); // background
+ if((ftype & 0x00c00000) == 0x00c00000)
+ mergeSubElementFormat(fmt, ftype & 0xffc00000, label); // combination
+ }
+
+ // URL
+ if(ftype & Url)
+ mergeSubElementFormat(fmt, ftype & (Url | 0x000000ff), label);
+}
+
+// Merge a subelement format into an existing message format
+void UiStyle::mergeSubElementFormat(QTextCharFormat& fmt, quint32 ftype, quint64 label) {
+ quint64 key = ftype | label;
+ fmt.merge(format(key & Q_UINT64_C(0x0000ffffffffff00))); // label + subelement
+ fmt.merge(format(key & Q_UINT64_C(0x0000ffffffffffff))); // label + subelement + msgtype
+ fmt.merge(format(key & Q_UINT64_C(0xffffffffffffff00))); // label + subelement + nickhash
+ fmt.merge(format(key & Q_UINT64_C(0xffffffffffffffff))); // label + subelement + nickhash + msgtype
+}
+
+UiStyle::FormatType UiStyle::formatType(Message::Type msgType) {
+ switch(msgType) {
+ case Message::Plain:
+ return PlainMsg;
+ case Message::Notice:
+ return NoticeMsg;
+ case Message::Action:
+ return ActionMsg;
+ case Message::Nick:
+ return NickMsg;
+ case Message::Mode:
+ return ModeMsg;
+ case Message::Join:
+ return JoinMsg;
+ case Message::Part:
+ return PartMsg;
+ case Message::Quit:
+ return QuitMsg;
+ case Message::Kick:
+ return KickMsg;
+ case Message::Kill:
+ return KillMsg;
+ case Message::Server:
+ return ServerMsg;
+ case Message::Info:
+ return InfoMsg;
+ case Message::Error:
+ return ErrorMsg;
+ case Message::DayChange:
+ return DayChangeMsg;
+ case Message::Topic:
+ return TopicMsg;
+ case Message::NetsplitJoin:
+ return NetsplitJoinMsg;
+ case Message::NetsplitQuit:
+ return NetsplitQuitMsg;
+ }
+ //Q_ASSERT(false); // we need to handle all message types
+ qWarning() << Q_FUNC_INFO << "Unknown message type:" << msgType;
+ return ErrorMsg;
+}
+
+UiStyle::FormatType UiStyle::formatType(const QString & code) {