File indexing completed on 2024-06-16 04:50:35

0001 /*
0002     SPDX-FileCopyrightText: 2006-2008 Tobias Koenig <tokoe@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "agenttypewidget.h"
0008 
0009 #include <QApplication>
0010 #include <QHBoxLayout>
0011 #include <QListView>
0012 #include <QPainter>
0013 
0014 #include "agentfilterproxymodel.h"
0015 #include "agenttype.h"
0016 #include "agenttypemodel.h"
0017 
0018 namespace Akonadi
0019 {
0020 namespace Internal
0021 {
0022 /**
0023  * @internal
0024  */
0025 class AgentTypeWidgetDelegate : public QAbstractItemDelegate
0026 {
0027     Q_OBJECT
0028 public:
0029     explicit AgentTypeWidgetDelegate(QObject *parent = nullptr);
0030 
0031     void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
0032     QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
0033 
0034 private:
0035     void drawFocus(QPainter * /*painter*/, const QStyleOptionViewItem & /*option*/, QRect /*rect*/) const;
0036 };
0037 
0038 } // namespace Internal
0039 
0040 using Akonadi::Internal::AgentTypeWidgetDelegate;
0041 
0042 /**
0043  * @internal
0044  */
0045 class AgentTypeWidgetPrivate
0046 {
0047 public:
0048     explicit AgentTypeWidgetPrivate(AgentTypeWidget *parent)
0049         : mParent(parent)
0050     {
0051     }
0052 
0053     void currentAgentTypeChanged(const QModelIndex & /*currentIndex*/, const QModelIndex & /*previousIndex*/);
0054 
0055     void typeActivated(const QModelIndex &index)
0056     {
0057         if (index.flags() & (Qt::ItemIsSelectable | Qt::ItemIsEnabled)) {
0058             Q_EMIT mParent->activated();
0059         }
0060     }
0061 
0062     AgentTypeWidget *const mParent;
0063     QListView *mView = nullptr;
0064     AgentTypeModel *mModel = nullptr;
0065     AgentFilterProxyModel *proxyModel = nullptr;
0066 };
0067 
0068 void AgentTypeWidgetPrivate::currentAgentTypeChanged(const QModelIndex &currentIndex, const QModelIndex &previousIndex)
0069 {
0070     AgentType currentType;
0071     if (currentIndex.isValid()) {
0072         currentType = currentIndex.data(AgentTypeModel::TypeRole).value<AgentType>();
0073     }
0074 
0075     AgentType previousType;
0076     if (previousIndex.isValid()) {
0077         previousType = previousIndex.data(AgentTypeModel::TypeRole).value<AgentType>();
0078     }
0079 
0080     Q_EMIT mParent->currentChanged(currentType, previousType);
0081 }
0082 
0083 AgentTypeWidget::AgentTypeWidget(QWidget *parent)
0084     : QWidget(parent)
0085     , d(new AgentTypeWidgetPrivate(this))
0086 {
0087     auto layout = new QHBoxLayout(this);
0088     layout->setContentsMargins({});
0089 
0090     d->mView = new QListView(this);
0091     d->mView->setItemDelegate(new AgentTypeWidgetDelegate(d->mView));
0092     d->mView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
0093     d->mView->setAlternatingRowColors(true);
0094     layout->addWidget(d->mView);
0095 
0096     d->mModel = new AgentTypeModel(d->mView);
0097     d->proxyModel = new AgentFilterProxyModel(this);
0098     d->proxyModel->setSourceModel(d->mModel);
0099     d->proxyModel->sort(0);
0100     d->mView->setModel(d->proxyModel);
0101 
0102     d->mView->selectionModel()->setCurrentIndex(d->mView->model()->index(0, 0), QItemSelectionModel::Select);
0103     d->mView->scrollTo(d->mView->model()->index(0, 0));
0104     connect(d->mView->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](const QModelIndex &start, const QModelIndex &end) {
0105         d->currentAgentTypeChanged(start, end);
0106     });
0107     connect(d->mView, qOverload<const QModelIndex &>(&QListView::activated), this, [this](const QModelIndex &index) {
0108         d->typeActivated(index);
0109     });
0110 }
0111 
0112 AgentTypeWidget::~AgentTypeWidget() = default;
0113 
0114 AgentType AgentTypeWidget::currentAgentType() const
0115 {
0116     QItemSelectionModel *selectionModel = d->mView->selectionModel();
0117     if (!selectionModel) {
0118         return AgentType();
0119     }
0120 
0121     QModelIndex index = selectionModel->currentIndex();
0122     if (!index.isValid()) {
0123         return AgentType();
0124     }
0125 
0126     return index.data(AgentTypeModel::TypeRole).value<AgentType>();
0127 }
0128 
0129 AgentFilterProxyModel *AgentTypeWidget::agentFilterProxyModel() const
0130 {
0131     return d->proxyModel;
0132 }
0133 
0134 /**
0135  * AgentTypeWidgetDelegate
0136  */
0137 
0138 AgentTypeWidgetDelegate::AgentTypeWidgetDelegate(QObject *parent)
0139     : QAbstractItemDelegate(parent)
0140 {
0141 }
0142 
0143 void AgentTypeWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
0144 {
0145     if (!index.isValid()) {
0146         return;
0147     }
0148 
0149     painter->setRenderHint(QPainter::Antialiasing);
0150 
0151     const QString name = index.model()->data(index, Qt::DisplayRole).toString();
0152     const QString comment = index.model()->data(index, AgentTypeModel::DescriptionRole).toString();
0153 
0154     const QVariant data = index.model()->data(index, Qt::DecorationRole);
0155 
0156     QPixmap pixmap;
0157     if (data.isValid() && data.typeId() == QMetaType::QIcon) {
0158         pixmap = qvariant_cast<QIcon>(data).pixmap(64, 64);
0159     }
0160 
0161     const QFont oldFont = painter->font();
0162     QFont boldFont(oldFont);
0163     boldFont.setBold(true);
0164     painter->setFont(boldFont);
0165     QFontMetrics fm = painter->fontMetrics();
0166     int hn = fm.boundingRect(0, 0, 0, 0, Qt::AlignLeft, name).height();
0167     int wn = fm.boundingRect(0, 0, 0, 0, Qt::AlignLeft, name).width();
0168     painter->setFont(oldFont);
0169 
0170     fm = painter->fontMetrics();
0171     int hc = fm.boundingRect(0, 0, 0, 0, Qt::AlignLeft, comment).height();
0172     int wc = fm.boundingRect(0, 0, 0, 0, Qt::AlignLeft, comment).width();
0173     int wp = pixmap.width();
0174 
0175     QStyleOptionViewItem opt(option);
0176     opt.showDecorationSelected = true;
0177     QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter);
0178 
0179     QPen pen = painter->pen();
0180     QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ? QPalette::Normal : QPalette::Disabled;
0181     if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) {
0182         cg = QPalette::Inactive;
0183     }
0184     if (option.state & QStyle::State_Selected) {
0185         painter->setPen(option.palette.color(cg, QPalette::HighlightedText));
0186     } else {
0187         painter->setPen(option.palette.color(cg, QPalette::Text));
0188     }
0189 
0190     painter->setFont(option.font);
0191 
0192     painter->drawPixmap(option.rect.x() + 5, option.rect.y() + 5, pixmap);
0193 
0194     painter->setFont(boldFont);
0195     if (!name.isEmpty()) {
0196         painter->drawText(option.rect.x() + 5 + wp + 5, option.rect.y() + 7, wn, hn, Qt::AlignLeft, name);
0197     }
0198     painter->setFont(oldFont);
0199 
0200     if (!comment.isEmpty()) {
0201         painter->drawText(option.rect.x() + 5 + wp + 5, option.rect.y() + 7 + hn, wc, hc, Qt::AlignLeft, comment);
0202     }
0203 
0204     painter->setPen(pen);
0205 
0206     drawFocus(painter, option, option.rect);
0207 }
0208 
0209 QSize AgentTypeWidgetDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
0210 {
0211     if (!index.isValid()) {
0212         return QSize(0, 0);
0213     }
0214 
0215     const QString name = index.model()->data(index, Qt::DisplayRole).toString();
0216     const QString comment = index.model()->data(index, AgentTypeModel::DescriptionRole).toString();
0217 
0218     QFontMetrics fm = option.fontMetrics;
0219     int hn = fm.boundingRect(0, 0, 0, 0, Qt::AlignLeft, name).height();
0220     int wn = fm.boundingRect(0, 0, 0, 0, Qt::AlignLeft, name).width();
0221     int hc = fm.boundingRect(0, 0, 0, 0, Qt::AlignLeft, comment).height();
0222     int wc = fm.boundingRect(0, 0, 0, 0, Qt::AlignLeft, comment).width();
0223 
0224     int width = 0;
0225     int height = 0;
0226 
0227     if (!name.isEmpty()) {
0228         height += hn;
0229         width = qMax(width, wn);
0230     }
0231 
0232     if (!comment.isEmpty()) {
0233         height += hc;
0234         width = qMax(width, wc);
0235     }
0236 
0237     height = qMax(height, 64) + 10;
0238     width += 64 + 15;
0239 
0240     return QSize(width, height);
0241 }
0242 
0243 void AgentTypeWidgetDelegate::drawFocus(QPainter *painter, const QStyleOptionViewItem &option, QRect rect) const
0244 {
0245     if (option.state & QStyle::State_HasFocus) {
0246         QStyleOptionFocusRect o;
0247         o.QStyleOption::operator=(option);
0248         o.rect = rect;
0249         o.state |= QStyle::State_KeyboardFocusChange;
0250         QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ? QPalette::Normal : QPalette::Disabled;
0251         o.backgroundColor = option.palette.color(cg, (option.state & QStyle::State_Selected) ? QPalette::Highlight : QPalette::Window);
0252         QApplication::style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter);
0253     }
0254 }
0255 
0256 } // namespace Akonadi
0257 
0258 #include "agenttypewidget.moc"
0259 
0260 #include "moc_agenttypewidget.cpp"