File indexing completed on 2025-03-09 04:51:37
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Christian Mollekopf <mollekopf@kolabsys.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0 0005 */ 0006 0007 #include "calendardelegate.h" 0008 #include "kohelper.h" 0009 #include "korganizer_debug.h" 0010 0011 #include <Akonadi/CollectionStatistics> 0012 #include <Akonadi/CollectionUtils> 0013 0014 #include <QApplication> 0015 #include <QFontDatabase> 0016 #include <QMouseEvent> 0017 #include <QPainter> 0018 #include <QPainterPath> 0019 0020 StyledCalendarDelegate::StyledCalendarDelegate(QObject *parent) 0021 : QStyledItemDelegate(parent) 0022 { 0023 mIcon.insert(Quickview, QIcon::fromTheme(QStringLiteral("quickview"))); 0024 } 0025 0026 StyledCalendarDelegate::~StyledCalendarDelegate() = default; 0027 0028 static QRect enableButtonRect(QRect rect, int pos = 1) 0029 { 0030 // 2px border on each side of the icon 0031 static int border = 2; 0032 const int side = rect.height() - (2 * border); 0033 const int offset = side * pos + border * (pos + 1); 0034 return rect.adjusted(rect.width() - (offset + side), border, -offset, -border); 0035 } 0036 0037 static QStyle *style(const QStyleOptionViewItem &option) 0038 { 0039 QWidget const *widget = nullptr; 0040 if (const auto v3 = qstyleoption_cast<const QStyleOptionViewItem *>(&option)) { 0041 widget = v3->widget; 0042 } 0043 QStyle *style = widget ? widget->style() : QApplication::style(); 0044 return style; 0045 } 0046 0047 static QStyleOptionButton buttonOpt(const QStyleOptionViewItem &opt, const QIcon &icon, const QModelIndex &index, int pos = 1) 0048 { 0049 Q_UNUSED(index) 0050 0051 QStyleOptionButton option; 0052 option.icon = icon; 0053 const QRect r = opt.rect; 0054 const int h = r.height() - 4; 0055 option.rect = enableButtonRect(r, pos); 0056 option.state = QStyle::State_Active | QStyle::State_Enabled; 0057 option.iconSize = QSize(h, h); 0058 return option; 0059 } 0060 0061 QList<StyledCalendarDelegate::Action> StyledCalendarDelegate::getActions(const QStyleOptionViewItem &, const QModelIndex &index) const 0062 { 0063 const Akonadi::Collection col = Akonadi::CollectionUtils::fromIndex(index); 0064 // qCDebug(KORGANIZER_LOG) << index.data().toString() << enabled; 0065 const bool isSearchCollection = col.resource().startsWith(QLatin1StringView("akonadi_search_resource")); 0066 const bool isKolabCollection = col.resource().startsWith(QLatin1StringView("akonadi_kolab_resource")); 0067 const bool isTopLevelCollection = (col.parentCollection() == Akonadi::Collection::root()); 0068 const bool isToplevelSearchCollection = (isTopLevelCollection && isSearchCollection); 0069 const bool isToplevelKolabCollection = (isTopLevelCollection && isKolabCollection); 0070 0071 QList<Action> buttons; 0072 if (!isToplevelSearchCollection && !isToplevelKolabCollection) { 0073 buttons << Quickview; 0074 } 0075 if (isSearchCollection && !isToplevelSearchCollection) { 0076 buttons << Total; 0077 } 0078 return buttons; 0079 } 0080 0081 void StyledCalendarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const 0082 { 0083 Q_ASSERT(index.isValid()); 0084 0085 const Akonadi::Collection col = Akonadi::CollectionUtils::fromIndex(index); 0086 0087 QStyleOptionViewItem opt = option; 0088 opt.font = QFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); 0089 opt.textElideMode = Qt::ElideLeft; 0090 0091 initStyleOption(&opt, index); 0092 QStyledItemDelegate::paint(painter, opt, index); 0093 0094 QStyle *s = style(option); 0095 0096 // Buttons 0097 { 0098 int i = 1; 0099 const auto lstActions = getActions(option, index); 0100 for (Action action : lstActions) { 0101 if (action != Total) { 0102 QStyleOptionButton buttonOption = buttonOpt(opt, mIcon.value(action), index, i); 0103 s->drawControl(QStyle::CE_PushButton, &buttonOption, painter, nullptr); 0104 } else { 0105 QStyleOptionButton buttonOption = buttonOpt(opt, QPixmap(), index, i); 0106 buttonOption.features = QStyleOptionButton::Flat; 0107 buttonOption.rect.setHeight(buttonOption.rect.height() + 4); 0108 if (col.statistics().count() > 0) { 0109 buttonOption.text = QString::number(col.statistics().count()); 0110 } 0111 s->drawControl(QStyle::CE_PushButton, &buttonOption, painter, nullptr); 0112 } 0113 i++; 0114 } 0115 } 0116 0117 // Color indicator 0118 if (opt.checkState) { 0119 QColor color = KOHelper::resourceColorKnown(col); 0120 if (!color.isValid()) { 0121 color = KOHelper::resourceColor(col); 0122 } 0123 if (color.isValid()) { 0124 painter->save(); 0125 painter->setRenderHint(QPainter::Antialiasing); 0126 QPen pen = painter->pen(); 0127 pen.setColor(color); 0128 QPainterPath path; 0129 path.addRoundedRect(enableButtonRect(opt.rect, 0), 5, 5); 0130 color.setAlpha(200); 0131 painter->fillPath(path, color); 0132 painter->strokePath(path, pen); 0133 painter->restore(); 0134 } 0135 } 0136 } 0137 0138 bool StyledCalendarDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) 0139 { 0140 Q_ASSERT(event); 0141 Q_ASSERT(model); 0142 0143 // double-click mouse starts the quickview dialog 0144 if (event->type() == QEvent::MouseButtonDblClick) { 0145 Q_EMIT action(index, Quickview); 0146 return true; 0147 } 0148 0149 int button = -1; 0150 // make sure that we have the right event type 0151 if ((event->type() == QEvent::MouseButtonRelease) || (event->type() == QEvent::MouseButtonPress)) { 0152 auto me = static_cast<QMouseEvent *>(event); 0153 0154 for (int i = 1; i < 4; i++) { 0155 if (enableButtonRect(option.rect, i).contains(me->pos())) { 0156 button = i; 0157 break; 0158 } 0159 } 0160 0161 if (me->button() != Qt::LeftButton || button < 0) { 0162 return QStyledItemDelegate::editorEvent(event, model, option, index); 0163 } 0164 0165 if (event->type() == QEvent::MouseButtonPress) { 0166 return true; 0167 } 0168 } else { 0169 return QStyledItemDelegate::editorEvent(event, model, option, index); 0170 } 0171 0172 Q_ASSERT(button > 0); 0173 QStyleOptionViewItem opt = option; 0174 opt.state |= QStyle::State_MouseOver; 0175 0176 QList<StyledCalendarDelegate::Action> actions = getActions(opt, index); 0177 if (actions.count() >= button) { 0178 const Action a = actions.at(button - 1); 0179 Q_EMIT action(index, a); 0180 return true; 0181 } 0182 return QStyledItemDelegate::editorEvent(event, model, option, index); 0183 } 0184 0185 QSize StyledCalendarDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const 0186 { 0187 QSize size = QStyledItemDelegate::sizeHint(option, index); 0188 // Without this adjustment toplevel resource folders get a slightly greater height, 0189 // which looks silly and breaks the toolbutton position. 0190 size.setHeight(qApp->style()->pixelMetric(QStyle::PM_SmallIconSize) + 4); 0191 return size; 0192 } 0193 0194 #include "moc_calendardelegate.cpp"