File indexing completed on 2024-10-27 04:50:58

0001 /*
0002  * This file is part of KMail.
0003  * SPDX-FileCopyrightText: 2011-2024 Laurent Montel <montel@kde.org>
0004  *
0005  * SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com>
0006  *
0007  * Parts based on KMail code by:
0008  * SPDX-FileCopyrightText: 2003 Ingo Kloecker <kloecker@kde.org>
0009  * SPDX-FileCopyrightText: 2007 Thomas McGuire <Thomas.McGuire@gmx.net>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  */
0013 
0014 #include "attachmentview.h"
0015 
0016 #include "kmkernel.h"
0017 
0018 #include <MessageComposer/AttachmentModel>
0019 
0020 #include <QContextMenuEvent>
0021 #include <QDrag>
0022 #include <QHBoxLayout>
0023 #include <QHeaderView>
0024 #include <QKeyEvent>
0025 #include <QLabel>
0026 #include <QSortFilterProxyModel>
0027 #include <QToolButton>
0028 
0029 #include <KLocalizedString>
0030 #include <QIcon>
0031 
0032 #include <KIO/Global>
0033 #include <MessageCore/AttachmentPart>
0034 using MessageCore::AttachmentPart;
0035 
0036 using namespace KMail;
0037 
0038 AttachmentView::AttachmentView(MessageComposer::AttachmentModel *model, QWidget *parent)
0039     : QTreeView(parent)
0040     , mModel(model)
0041     , mToolButton(new QToolButton(this))
0042     , mInfoAttachment(new QLabel(this))
0043     , mWidget(new QWidget())
0044     , grp(KMKernel::self()->config()->group(QStringLiteral("AttachmentView")))
0045 {
0046     auto lay = new QHBoxLayout(mWidget);
0047     lay->setContentsMargins({});
0048     connect(mToolButton, &QAbstractButton::toggled, this, &AttachmentView::slotShowHideAttchementList);
0049     mToolButton->setIcon(QIcon::fromTheme(QStringLiteral("mail-attachment")));
0050     mToolButton->setAutoRaise(true);
0051     mToolButton->setCheckable(true);
0052     lay->addWidget(mToolButton);
0053     mInfoAttachment->setContentsMargins({});
0054     mInfoAttachment->setTextFormat(Qt::PlainText);
0055     lay->addWidget(mInfoAttachment);
0056 
0057     connect(model, &MessageComposer::AttachmentModel::encryptEnabled, this, &AttachmentView::setEncryptEnabled);
0058     connect(model, &MessageComposer::AttachmentModel::signEnabled, this, &AttachmentView::setSignEnabled);
0059 
0060     auto sortModel = new QSortFilterProxyModel(this);
0061     sortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
0062     sortModel->setSourceModel(model);
0063     setModel(sortModel);
0064     connect(model, &MessageComposer::AttachmentModel::rowsInserted, this, &AttachmentView::hideIfEmpty);
0065     connect(model, &MessageComposer::AttachmentModel::rowsRemoved, this, &AttachmentView::hideIfEmpty);
0066     connect(model, &MessageComposer::AttachmentModel::rowsRemoved, this, &AttachmentView::selectNewAttachment);
0067     connect(model, &MessageComposer::AttachmentModel::dataChanged, this, &AttachmentView::updateAttachmentLabel);
0068 
0069     setRootIsDecorated(false);
0070     setUniformRowHeights(true);
0071     setSelectionMode(QAbstractItemView::ExtendedSelection);
0072     setDragDropMode(QAbstractItemView::DragDrop);
0073     setEditTriggers(QAbstractItemView::EditKeyPressed);
0074     setDropIndicatorShown(false);
0075     setSortingEnabled(true);
0076 
0077     header()->setSectionResizeMode(QHeaderView::Interactive);
0078     header()->setStretchLastSection(false);
0079     restoreHeaderState();
0080     setColumnWidth(0, 200);
0081 }
0082 
0083 AttachmentView::~AttachmentView()
0084 {
0085     saveHeaderState();
0086 }
0087 
0088 void AttachmentView::restoreHeaderState()
0089 {
0090     header()->restoreState(grp.readEntry("State", QByteArray()));
0091 }
0092 
0093 void AttachmentView::saveHeaderState()
0094 {
0095     grp.writeEntry("State", header()->saveState());
0096     grp.sync();
0097 }
0098 
0099 void AttachmentView::contextMenuEvent(QContextMenuEvent *event)
0100 {
0101     Q_UNUSED(event)
0102     Q_EMIT contextMenuRequested();
0103 }
0104 
0105 void AttachmentView::keyPressEvent(QKeyEvent *event)
0106 {
0107     if (event->key() == Qt::Key_Delete) {
0108         // Indexes are based on row numbers, and row numbers change when items are deleted.
0109         // Therefore, first we need to make a list of AttachmentParts to delete.
0110         AttachmentPart::List toRemove;
0111         const QModelIndexList selectedIndexes = selectionModel()->selectedRows();
0112         toRemove.reserve(selectedIndexes.count());
0113         for (const QModelIndex &index : selectedIndexes) {
0114             auto part = model()->data(index, MessageComposer::AttachmentModel::AttachmentPartRole).value<AttachmentPart::Ptr>();
0115             toRemove.append(part);
0116         }
0117         for (const AttachmentPart::Ptr &part : std::as_const(toRemove)) {
0118             mModel->removeAttachment(part);
0119         }
0120     } else {
0121         QTreeView::keyPressEvent(event);
0122     }
0123 }
0124 
0125 void AttachmentView::dragEnterEvent(QDragEnterEvent *event)
0126 {
0127     if (event->source() == this) {
0128         // Ignore drags from ourselves.
0129         event->ignore();
0130     } else {
0131         QTreeView::dragEnterEvent(event);
0132     }
0133 }
0134 
0135 void AttachmentView::setEncryptEnabled(bool enabled)
0136 {
0137     setColumnHidden(MessageComposer::AttachmentModel::EncryptColumn, !enabled);
0138 }
0139 
0140 void AttachmentView::setSignEnabled(bool enabled)
0141 {
0142     setColumnHidden(MessageComposer::AttachmentModel::SignColumn, !enabled);
0143 }
0144 
0145 void AttachmentView::hideIfEmpty()
0146 {
0147     const bool needToShowIt = (model()->rowCount() > 0);
0148     setVisible(needToShowIt);
0149     mToolButton->setChecked(needToShowIt);
0150     widget()->setVisible(needToShowIt);
0151     if (needToShowIt) {
0152         updateAttachmentLabel();
0153     } else {
0154         mInfoAttachment->clear();
0155     }
0156     Q_EMIT modified(true);
0157 }
0158 
0159 void AttachmentView::updateAttachmentLabel()
0160 {
0161     const MessageCore::AttachmentPart::List list = mModel->attachments();
0162     qint64 size = 0;
0163     for (const MessageCore::AttachmentPart::Ptr &part : list) {
0164         size += part->size();
0165     }
0166     mInfoAttachment->setText(i18np("1 attachment (%2)", "%1 attachments (%2)", model()->rowCount(), KIO::convertSize(qMax(0LL, size))));
0167 }
0168 
0169 void AttachmentView::selectNewAttachment()
0170 {
0171     if (selectionModel()->selectedRows().isEmpty()) {
0172         selectionModel()->select(selectionModel()->currentIndex(), QItemSelectionModel::Select | QItemSelectionModel::Rows);
0173     }
0174 }
0175 
0176 void AttachmentView::startDrag(Qt::DropActions supportedActions)
0177 {
0178     Q_UNUSED(supportedActions)
0179 
0180     const QModelIndexList selection = selectionModel()->selectedRows();
0181     if (!selection.isEmpty()) {
0182         QMimeData *mimeData = model()->mimeData(selection);
0183         auto drag = new QDrag(this);
0184         drag->setMimeData(mimeData);
0185         drag->exec(Qt::CopyAction);
0186     }
0187 }
0188 
0189 QWidget *AttachmentView::widget() const
0190 {
0191     return mWidget;
0192 }
0193 
0194 void AttachmentView::slotShowHideAttchementList(bool show)
0195 {
0196     setVisible(show);
0197     if (show) {
0198         mToolButton->setToolTip(i18n("Hide attachment list"));
0199     } else {
0200         mToolButton->setToolTip(i18n("Show attachment list"));
0201     }
0202 }
0203 
0204 #include "moc_attachmentview.cpp"