File indexing completed on 2024-05-26 05:25:21

0001 /*
0002 
0003   SPDX-FileCopyrightText: 2012-2024 Laurent Montel <montel@kde.org>
0004 
0005   SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "favoritecollectionwidget.h"
0009 #include "kernel/mailkernel.h"
0010 #include "mailcommonsettings_base.h"
0011 
0012 #include <MessageCore/MessageCoreSettings>
0013 
0014 #include <Akonadi/CollectionStatisticsDelegate>
0015 #include <KActionCollection>
0016 #include <KActionMenu>
0017 #include <KLocalizedString>
0018 #include <KXMLGUIClient>
0019 
0020 #include <QActionGroup>
0021 #include <QApplication>
0022 #include <QFontDatabase>
0023 #include <QMimeData>
0024 #include <QMouseEvent>
0025 #include <QPainter>
0026 
0027 using namespace MailCommon;
0028 
0029 class Q_DECL_HIDDEN FavoriteCollectionWidget::FavoriteCollectionWidgetPrivate
0030 {
0031 public:
0032     FavoriteCollectionWidgetPrivate() = default;
0033 
0034     QColor textColor;
0035     QAction *listMode = nullptr;
0036     QAction *iconMode = nullptr;
0037     MailCommonSettings *settings = nullptr;
0038     Akonadi::CollectionStatisticsDelegate *delegate = nullptr;
0039 };
0040 
0041 FavoriteCollectionWidget::FavoriteCollectionWidget(MailCommon::MailCommonSettings *settings, KXMLGUIClient *xmlGuiClient, QWidget *parent)
0042     : Akonadi::EntityListView(xmlGuiClient, parent)
0043     , d(new FavoriteCollectionWidgetPrivate)
0044 {
0045     d->settings = settings;
0046     setFocusPolicy(Qt::NoFocus);
0047 
0048     d->delegate = new Akonadi::CollectionStatisticsDelegate(this);
0049     d->delegate->setProgressAnimationEnabled(true);
0050 
0051     setItemDelegate(d->delegate);
0052 
0053     d->delegate->setUnreadCountShown(true);
0054 
0055     readConfig();
0056 
0057     createMenu(xmlGuiClient->actionCollection());
0058 }
0059 
0060 FavoriteCollectionWidget::~FavoriteCollectionWidget() = default;
0061 
0062 void FavoriteCollectionWidget::updatePalette()
0063 {
0064     d->delegate->updatePalette();
0065 }
0066 
0067 void FavoriteCollectionWidget::mousePressEvent(QMouseEvent *e)
0068 {
0069     const bool buttonPressedIsMiddle = (e->button() == Qt::MiddleButton);
0070     Q_EMIT newTabRequested(buttonPressedIsMiddle);
0071     Akonadi::EntityListView::mousePressEvent(e);
0072 }
0073 
0074 void FavoriteCollectionWidget::updateMode()
0075 {
0076     switch (viewMode()) {
0077     case ListMode:
0078         d->listMode->setChecked(true);
0079         d->iconMode->setChecked(false);
0080         break;
0081     case IconMode:
0082         d->listMode->setChecked(false);
0083         d->iconMode->setChecked(true);
0084         break;
0085     }
0086 }
0087 
0088 void FavoriteCollectionWidget::createMenu(KActionCollection *ac)
0089 {
0090     auto iconSizeMenu = new KActionMenu(i18n("Icon size"), this);
0091     ac->addAction(QStringLiteral("favorite_icon_size"), iconSizeMenu);
0092 
0093     static const int icon_sizes[] = {16, 22, 32 /*, 48, 64, 128 */};
0094 
0095     auto grp = new QActionGroup(iconSizeMenu);
0096     QAction *act = nullptr;
0097     for (int i : icon_sizes) {
0098         act = new QAction(QStringLiteral("%1x%2").arg(i).arg(i), iconSizeMenu);
0099         iconSizeMenu->addAction(act);
0100         act->setCheckable(true);
0101         grp->addAction(act);
0102         if (iconSize().width() == i) {
0103             act->setChecked(true);
0104         }
0105         act->setData(QVariant(i));
0106         connect(act, &QAction::triggered, this, &FavoriteCollectionWidget::slotChangeIconSize);
0107     }
0108 
0109     auto modeFavoriteMenu = new KActionMenu(i18n("Mode"), this);
0110     ac->addAction(QStringLiteral("favorite_mode"), modeFavoriteMenu);
0111 
0112     grp = new QActionGroup(modeFavoriteMenu);
0113     d->listMode = new QAction(i18n("List Mode"), modeFavoriteMenu);
0114     modeFavoriteMenu->addAction(d->listMode);
0115     d->listMode->setCheckable(true);
0116     grp->addAction(d->listMode);
0117     if (viewMode() == ListMode) {
0118         d->listMode->setChecked(true);
0119     }
0120     d->listMode->setData(QVariant(MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode));
0121     connect(d->listMode, &QAction::triggered, this, &FavoriteCollectionWidget::slotChangeMode);
0122 
0123     d->iconMode = new QAction(i18n("Icon Mode"), modeFavoriteMenu);
0124     modeFavoriteMenu->addAction(d->iconMode);
0125     grp->addAction(d->iconMode);
0126     d->iconMode->setCheckable(true);
0127     if (viewMode() == IconMode) {
0128         d->iconMode->setChecked(true);
0129     }
0130     d->iconMode->setData(QVariant(MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode));
0131     connect(d->iconMode, &QAction::triggered, this, &FavoriteCollectionWidget::slotChangeMode);
0132 }
0133 
0134 void FavoriteCollectionWidget::slotChangeMode(bool)
0135 {
0136     auto act = qobject_cast<QAction *>(sender());
0137     if (!act) {
0138         return;
0139     }
0140 
0141     QVariant data = act->data();
0142 
0143     bool ok;
0144     const int mode = data.toInt(&ok);
0145     if (!ok) {
0146         return;
0147     }
0148 
0149     switch (mode) {
0150     case MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode:
0151         changeViewMode(IconMode);
0152         break;
0153     case MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode:
0154         changeViewMode(ListMode);
0155         break;
0156     }
0157 
0158     d->settings->setFavoriteCollectionViewMode(mode);
0159     d->settings->save();
0160 }
0161 
0162 void FavoriteCollectionWidget::changeViewMode(QListView::ViewMode mode)
0163 {
0164     setViewMode(mode);
0165     setDragEnabled(true);
0166     setAcceptDrops(true);
0167 }
0168 
0169 void FavoriteCollectionWidget::slotChangeIconSize(bool)
0170 {
0171     auto act = qobject_cast<QAction *>(sender());
0172     if (!act) {
0173         return;
0174     }
0175 
0176     QVariant data = act->data();
0177 
0178     bool ok;
0179     const int size = data.toInt(&ok);
0180     if (!ok) {
0181         return;
0182     }
0183 
0184     const QSize newIconSize(QSize(size, size));
0185     if (newIconSize == iconSize()) {
0186         return;
0187     }
0188     setIconSize(newIconSize);
0189     d->settings->setIconSize(iconSize().width());
0190     d->settings->save();
0191 }
0192 
0193 void FavoriteCollectionWidget::slotGeneralPaletteChanged()
0194 {
0195     const QPalette palette = viewport()->palette();
0196     QColor color = palette.text().color();
0197     color.setAlpha(128);
0198     d->textColor = color;
0199 }
0200 
0201 void FavoriteCollectionWidget::slotGeneralFontChanged()
0202 {
0203     // Custom/System font support
0204     if (MessageCore::MessageCoreSettings::self()->useDefaultFonts()) {
0205         setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont));
0206     }
0207 }
0208 
0209 void FavoriteCollectionWidget::readConfig()
0210 {
0211     setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont));
0212 
0213     int iIconSize = d->settings->iconSize();
0214     if (iIconSize < 16 || iIconSize > 32) {
0215         iIconSize = 22;
0216     }
0217     setIconSize(QSize(iIconSize, iIconSize));
0218 }
0219 
0220 void FavoriteCollectionWidget::paintEvent(QPaintEvent *event)
0221 {
0222     if (!model() || model()->rowCount() == 0) {
0223         QPainter p(viewport());
0224 
0225         QFont font = p.font();
0226         font.setItalic(true);
0227         p.setFont(font);
0228 
0229         if (!d->textColor.isValid()) {
0230             slotGeneralPaletteChanged();
0231         }
0232         p.setPen(d->textColor);
0233 
0234         p.drawText(QRect(0, 0, width(), height()), Qt::AlignCenter, i18n("Drop your favorite folders here..."));
0235     } else {
0236         Akonadi::EntityListView::paintEvent(event);
0237     }
0238 }
0239 
0240 static bool isCollection(const QMimeData *mimeData)
0241 {
0242     const QList<QUrl> urls = mimeData->urls();
0243     for (const QUrl &url : urls) {
0244         const Akonadi::Collection collection = Akonadi::Collection::fromUrl(url);
0245         if (collection.isValid()) {
0246             return true;
0247         }
0248     }
0249     return false;
0250 }
0251 
0252 bool FavoriteCollectionWidget::acceptEvent(QDropEvent *event) const
0253 {
0254     const bool draggingCollection = isCollection(event->mimeData());
0255     const bool droppingOnCollection = dropIndicatorPosition() == QAbstractItemView::OnItem;
0256     if (event->source() == this) {
0257         if (draggingCollection && !droppingOnCollection) { // Re-ordering favorites
0258             return true;
0259         }
0260     } else {
0261         if ((draggingCollection && !droppingOnCollection) // Adding a new favorite collection
0262             || (!draggingCollection && droppingOnCollection)) { // Dropping emails onto a favorite collection
0263             return true;
0264         }
0265     }
0266     event->ignore();
0267     return false;
0268 }
0269 
0270 void FavoriteCollectionWidget::dragEnterEvent(QDragEnterEvent *event)
0271 {
0272     if (event->source() == this) {
0273         QListView::dragEnterEvent(event); // Re-ordering favourites
0274     } else {
0275         Akonadi::EntityListView::dragEnterEvent(event); // Dropping emails onto a favorite collection
0276     }
0277 }
0278 
0279 void FavoriteCollectionWidget::dragMoveEvent(QDragMoveEvent *event)
0280 {
0281     // We need to ask QListView to update dropIndicatorPosition() first...
0282     QListView::dragMoveEvent(event);
0283     if (event->source() == this) {
0284         if (acceptEvent(event)) {
0285             event->setDropAction(Qt::MoveAction);
0286             event->accept(); // Re-ordering favourites
0287         }
0288     } else {
0289         if (acceptEvent(event)) {
0290             Akonadi::EntityListView::dragMoveEvent(event); // Dropping emails onto a favorite collection
0291         }
0292     }
0293 }
0294 
0295 void FavoriteCollectionWidget::dropEvent(QDropEvent *event)
0296 {
0297     if (event->source() == this) {
0298         if (acceptEvent(event)) {
0299             QListView::dropEvent(event); // Re-ordering favourites
0300         }
0301     } else {
0302         if (acceptEvent(event)) {
0303             if (dropIndicatorPosition() == QAbstractItemView::OnItem) {
0304                 Akonadi::EntityListView::dropEvent(event); // Dropping emails onto a favorite collection
0305             } else {
0306                 QListView::dropEvent(event); // Add new favorite
0307             }
0308         }
0309     }
0310 }
0311 
0312 void FavoriteCollectionWidget::startDrag(Qt::DropActions supportedActions)
0313 {
0314     // skip EntityListView logic (we want to reorder favorites, not trigger moving/copying of actual folders)
0315     QListView::startDrag(supportedActions);
0316 }
0317 
0318 bool FavoriteCollectionWidget::event(QEvent *e)
0319 {
0320     if (e->type() == QEvent::ApplicationPaletteChange) {
0321         updatePalette();
0322     }
0323     return Akonadi::EntityListView::event(e);
0324 }
0325 
0326 #include "moc_favoritecollectionwidget.cpp"