File indexing completed on 2024-04-14 15:49:41

0001 // SPDX-FileCopyrightText: 2020 Simon Persson <simon.persson@mykolab.com>
0002 //
0003 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 
0005 #include "driveselectiondelegate.h"
0006 #include "driveselection.h"
0007 
0008 #include <QApplication>
0009 #include <QIcon>
0010 #include <QPainter>
0011 #include <QStyle>
0012 
0013 #include <KCapacityBar>
0014 #include <KFormat>
0015 #include <KIO/Global>
0016 #include <KLocalizedString>
0017 
0018 static const int cMargin = 6;
0019 
0020 DriveSelectionDelegate::DriveSelectionDelegate(QListView *pParent)
0021     : QStyledItemDelegate(pParent),
0022       mCapacityBar(new KCapacityBar(KCapacityBar::DrawTextInline)),
0023       mListView(pParent)
0024 {}
0025 
0026 DriveSelectionDelegate::~DriveSelectionDelegate()
0027 {
0028     delete mCapacityBar;
0029 }
0030 
0031 void DriveSelectionDelegate::paint(QPainter* pPainter, const QStyleOptionViewItem& pOption,
0032                                    const QModelIndex& pIndex) const {
0033     pPainter->save();
0034     pPainter->setRenderHint(QPainter::Antialiasing);
0035     QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &pOption, pPainter);
0036 
0037     auto lTotalSize = pIndex.data(DriveSelection::TotalSpace).toULongLong();
0038     auto lUsedSize = pIndex.data(DriveSelection::UsedSpace).toULongLong();
0039     bool lIsDisconnected = pIndex.data(DriveSelection::UDI).toString().isEmpty();
0040 
0041     auto lFontMetrics = mListView->fontMetrics();
0042 
0043     if(lTotalSize == 0 || lIsDisconnected) {
0044         mCapacityBar->setValue(0);
0045     } else {
0046         mCapacityBar->setValue(static_cast<int>((lUsedSize * 100) / lTotalSize));
0047     }
0048     mCapacityBar->drawCapacityBar(
0049         pPainter,
0050         pOption.rect.adjusted(
0051             cMargin,
0052             cMargin+lFontMetrics.height()+cMargin,
0053             -cMargin,
0054             4*cMargin + lFontMetrics.height() - pOption.rect.height()));
0055 
0056     if (pOption.state & QStyle::State_HasFocus)
0057         pPainter->setPen(pOption.palette.color(QPalette::HighlightedText));
0058     else
0059         pPainter->setPen(pOption.palette.color(QPalette::Text));
0060 
0061     KFormat lFormat;
0062     QString lDisplayLabel, lPartitionLabel, lDisconnectedLabel;
0063     int lTextEnd = pOption.rect.right() - cMargin;
0064     if(lIsDisconnected) {
0065         lDisconnectedLabel = xi18nc("@item:inlistbox this text is added if selected drive is disconnected", " (disconnected)");
0066     } else {
0067         lDisconnectedLabel = QString();
0068         if(lTotalSize > 0) {
0069             QString lFreeSpace = xi18nc("@label %1 is amount of free storage space of hard drive","%1 free",
0070                                         lFormat.formatByteSize(lTotalSize - lUsedSize));
0071             int lTextWidth = lFontMetrics.horizontalAdvance(lFreeSpace);
0072             lTextEnd -= lTextWidth + cMargin;
0073             QPoint lOffset = QPoint(-cMargin - lTextWidth, cMargin + lFontMetrics.height());
0074             pPainter->drawText(pOption.rect.topRight() + lOffset, lFreeSpace);
0075         }
0076     }
0077 
0078     QString lDeviceDescription = pIndex.data(DriveSelection::DeviceDescription).toString();
0079     QString lLabel = pIndex.data(DriveSelection::Label).toString();
0080     int lPartitionNumber = pIndex.data(DriveSelection::PartitionNumber).toInt();
0081     if(lLabel.isEmpty() || lLabel == lDeviceDescription) {
0082         if(pIndex.data(DriveSelection::PartitionsOnDrive).toInt() > 1) {
0083             lPartitionLabel = xi18nc("@item:inlistbox used for unnamed filesystems, more than one filesystem on device. %1 is partition number, %2 is device description, %3 is either empty or the \" (disconnected)\" text",
0084                                     "Partition %1 on %2%3", lPartitionNumber, lDeviceDescription, lDisconnectedLabel);
0085         } else {
0086             lPartitionLabel = xi18nc("@item:inlistbox used when there is only one unnamed filesystem on device. %1 is device description, %2 is either empty or the \" (disconnected)\" text",
0087                                     "%1%2", lDeviceDescription, lDisconnectedLabel);
0088         }
0089     } else {
0090         lPartitionLabel = xi18nc("@item:inlistbox %1 is filesystem label, %2 is the device description, %3 is either empty or the \" (disconnected)\" text",
0091                                 "%1 on %2%3", lLabel, lDeviceDescription, lDisconnectedLabel);
0092     }
0093 
0094     if(lTotalSize == 0) {
0095         lDisplayLabel = lPartitionLabel;
0096     } else {
0097         lDisplayLabel = xi18nc("@item:inlistbox %1 is drive(partition) label, %2 is storage capacity",
0098                               "%1: %2 total capacity", lPartitionLabel, lFormat.formatByteSize(lTotalSize));
0099     }
0100     lDisplayLabel = lFontMetrics.elidedText(lDisplayLabel, Qt::ElideMiddle, lTextEnd - pOption.rect.left() - cMargin);
0101     pPainter->drawText(pOption.rect.topLeft() + QPoint(cMargin, cMargin+lFontMetrics.height()), lDisplayLabel);
0102 
0103     int lIconSize = 48;
0104     QRect lWarningRect = warningRect(pOption.rect.adjusted(lIconSize + cMargin, 0, 0, 0), pIndex);
0105     if(!lWarningRect.isEmpty()) {
0106         QIcon lIcon = QIcon::fromTheme(QStringLiteral("dialog-warning"));
0107         lIcon.paint(pPainter, lWarningRect.left() - cMargin - lIconSize, lWarningRect.top(), lIconSize, lIconSize);
0108         pPainter->drawText(lWarningRect, Qt::AlignVCenter | Qt::TextWordWrap, warningText(pIndex));
0109     }
0110 
0111     pPainter->restore();
0112 }
0113 
0114 QSize DriveSelectionDelegate::sizeHint(const QStyleOptionViewItem& pOption, const QModelIndex& pIndex) const {
0115     Q_UNUSED(pOption)
0116     auto lFontMetrics = mListView->fontMetrics();
0117     QSize lSize;
0118     lSize.setWidth(cMargin*2 + lFontMetrics.horizontalAdvance(pIndex.data().toString()));
0119     lSize.setHeight(cMargin*5 + lFontMetrics.height());
0120     int lIconSize = 48;
0121     QRect lWarningRect = warningRect(mListView->rect().adjusted(lIconSize + cMargin, 0, 0, 0), pIndex);
0122     if(!lWarningRect.isEmpty()) {
0123         lSize.setHeight(lSize.height() + 2*cMargin + lWarningRect.height());
0124     }
0125     return lSize;
0126 }
0127 
0128 QRect DriveSelectionDelegate::warningRect(const QRect &pRect, const QModelIndex &pIndex) const {
0129     auto lFontMetrics = mListView->fontMetrics();
0130     QRect lTextLocation = pRect.adjusted(cMargin, 5*cMargin + lFontMetrics.height(), -cMargin, -cMargin);
0131     QString lWarningText = warningText(pIndex);
0132     if(lWarningText.isEmpty()) {
0133         return {};
0134     }
0135     QRect lTextBoundary = lFontMetrics.boundingRect(lTextLocation, Qt::TextWordWrap, lWarningText);
0136     int lIconSize = 48;
0137     if(lTextBoundary.height() < lIconSize) {
0138         lTextBoundary.setHeight(lIconSize);
0139     }
0140     return lTextBoundary;
0141 }
0142 
0143 QString DriveSelectionDelegate::warningText(const QModelIndex &pIndex) {
0144     bool lPermissionWarning = pIndex.data(DriveSelection::PermissionLossWarning).toBool();
0145     bool lSymlinkWarning = pIndex.data(DriveSelection::SymlinkLossWarning).toBool();
0146     if(lPermissionWarning && lSymlinkWarning) {
0147         return xi18nc("@item:inlistbox", "Warning: Symbolic links and file permissions can not be saved "
0148                                          "to this file system. File permissions only matters if there is more than one "
0149                                          "user of this computer or if you are backing up executable program files.");
0150     }
0151     if(lPermissionWarning) {
0152         return xi18nc("@item:inlistbox", "Warning: File permissions can not be saved to this file "
0153                                          "system. File permissions only matters if there is more than one "
0154                                          "user of this computer or if you are backing up executable program files.");
0155     }
0156     return {};
0157 }