1 /*
2  * SPDX-FileCopyrightText: 2006 Peter Penz <peter.penz19@gmail.com>
3  *
4  * SPDX-License-Identifier: GPL-2.0-or-later
5  */
6 
7 #include "previewssettingspage.h"
8 
9 #include "dolphin_generalsettings.h"
10 #include "configurepreviewplugindialog.h"
11 #include "settings/serviceitemdelegate.h"
12 #include "settings/servicemodel.h"
13 
14 #include <KIO/PreviewJob>
15 #include <KLocalizedString>
16 #include <KServiceTypeTrader>
17 
18 #include <QHBoxLayout>
19 #include <QLabel>
20 #include <QListView>
21 #include <QPainter>
22 #include <QScroller>
23 #include <QShowEvent>
24 #include <QSortFilterProxyModel>
25 #include <QSpinBox>
26 
27 // default settings
28 namespace {
29     const int DefaultMaxLocalPreviewSize = 0; // 0 MB
30     const int DefaultMaxRemotePreviewSize = 0; // 0 MB
31 }
32 
PreviewsSettingsPage(QWidget * parent)33 PreviewsSettingsPage::PreviewsSettingsPage(QWidget* parent) :
34     SettingsPageBase(parent),
35     m_initialized(false),
36     m_listView(nullptr),
37     m_enabledPreviewPlugins(),
38     m_localFileSizeBox(nullptr),
39     m_remoteFileSizeBox(nullptr)
40 {
41     QVBoxLayout* topLayout = new QVBoxLayout(this);
42 
43     QLabel* showPreviewsLabel = new QLabel(i18nc("@title:group", "Show previews in the view for:"), this);
44 
45     m_listView = new QListView(this);
46     QScroller::grabGesture(m_listView->viewport(), QScroller::TouchGesture);
47 
48     ServiceItemDelegate* delegate = new ServiceItemDelegate(m_listView, m_listView);
49     connect(delegate, &ServiceItemDelegate::requestServiceConfiguration,
50             this, &PreviewsSettingsPage::configureService);
51 
52     ServiceModel* serviceModel = new ServiceModel(this);
53     QSortFilterProxyModel* proxyModel = new QSortFilterProxyModel(this);
54     proxyModel->setSourceModel(serviceModel);
55     proxyModel->setSortRole(Qt::DisplayRole);
56     proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
57 
58     m_listView->setModel(proxyModel);
59     m_listView->setItemDelegate(delegate);
60     m_listView->setVerticalScrollMode(QListView::ScrollPerPixel);
61     m_listView->setUniformItemSizes(true);
62 
63     QLabel* localFileSizeLabel = new QLabel(i18n("Skip previews for local files above:"), this);
64 
65     m_localFileSizeBox = new QSpinBox(this);
66     m_localFileSizeBox->setSingleStep(1);
67     m_localFileSizeBox->setSuffix(i18nc("Mebibytes; used as a suffix in a spinbox showing e.g. '3 MiB'", " MiB"));
68     m_localFileSizeBox->setRange(0, 9999999); /* MB */
69     m_localFileSizeBox->setSpecialValueText(i18n("No limit"));
70 
71     QHBoxLayout* localFileSizeBoxLayout = new QHBoxLayout();
72     localFileSizeBoxLayout->addWidget(localFileSizeLabel);
73     localFileSizeBoxLayout->addStretch(0);
74     localFileSizeBoxLayout->addWidget(m_localFileSizeBox);
75 
76     QLabel* remoteFileSizeLabel = new QLabel(i18nc("@label", "Skip previews for remote files above:"), this);
77 
78     m_remoteFileSizeBox = new QSpinBox(this);
79     m_remoteFileSizeBox->setSingleStep(1);
80     m_remoteFileSizeBox->setSuffix(i18nc("Mebibytes; used as a suffix in a spinbox showing e.g. '3 MiB'", " MiB"));
81     m_remoteFileSizeBox->setRange(0, 9999999); /* MB */
82     m_remoteFileSizeBox->setSpecialValueText(i18n("No previews"));
83 
84     QHBoxLayout* remoteFileSizeBoxLayout = new QHBoxLayout();
85     remoteFileSizeBoxLayout->addWidget(remoteFileSizeLabel);
86     remoteFileSizeBoxLayout->addStretch(0);
87     remoteFileSizeBoxLayout->addWidget(m_remoteFileSizeBox);
88 
89     topLayout->addWidget(showPreviewsLabel);
90     topLayout->addWidget(m_listView);
91     topLayout->addLayout(localFileSizeBoxLayout);
92     topLayout->addLayout(remoteFileSizeBoxLayout);
93 
94     loadSettings();
95 
96     connect(m_listView, &QListView::clicked, this, &PreviewsSettingsPage::changed);
97     connect(m_localFileSizeBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &PreviewsSettingsPage::changed);
98     connect(m_remoteFileSizeBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &PreviewsSettingsPage::changed);
99 }
100 
~PreviewsSettingsPage()101 PreviewsSettingsPage::~PreviewsSettingsPage()
102 {
103 }
104 
applySettings()105 void PreviewsSettingsPage::applySettings()
106 {
107     const QAbstractItemModel* model = m_listView->model();
108     const int rowCount = model->rowCount();
109     if (rowCount > 0) {
110         m_enabledPreviewPlugins.clear();
111         for (int i = 0; i < rowCount; ++i) {
112             const QModelIndex index = model->index(i, 0);
113             const bool checked = model->data(index, Qt::CheckStateRole).toBool();
114             if (checked) {
115                 const QString enabledPlugin = model->data(index, Qt::UserRole).toString();
116                 m_enabledPreviewPlugins.append(enabledPlugin);
117             }
118         }
119     }
120 
121     KConfigGroup globalConfig(KSharedConfig::openConfig(), QStringLiteral("PreviewSettings"));
122     globalConfig.writeEntry("Plugins", m_enabledPreviewPlugins);
123 
124     if (!m_localFileSizeBox->value()) {
125         globalConfig.deleteEntry("MaximumSize", KConfigBase::Normal | KConfigBase::Global);
126     } else {
127         const qulonglong maximumLocalSize = static_cast<qulonglong>(m_localFileSizeBox->value()) * 1024 * 1024;
128         globalConfig.writeEntry("MaximumSize",
129                                 maximumLocalSize,
130                                 KConfigBase::Normal | KConfigBase::Global);
131     }
132 
133     const qulonglong maximumRemoteSize = static_cast<qulonglong>(m_remoteFileSizeBox->value()) * 1024 * 1024;
134     globalConfig.writeEntry("MaximumRemoteSize",
135                             maximumRemoteSize,
136                             KConfigBase::Normal | KConfigBase::Global);
137 
138     globalConfig.sync();
139 }
140 
restoreDefaults()141 void PreviewsSettingsPage::restoreDefaults()
142 {
143     m_localFileSizeBox->setValue(DefaultMaxLocalPreviewSize);
144     m_remoteFileSizeBox->setValue(DefaultMaxRemotePreviewSize);
145 }
146 
showEvent(QShowEvent * event)147 void PreviewsSettingsPage::showEvent(QShowEvent* event)
148 {
149     if (!event->spontaneous() && !m_initialized) {
150         loadPreviewPlugins();
151         m_initialized = true;
152     }
153     SettingsPageBase::showEvent(event);
154 }
155 
configureService(const QModelIndex & index)156 void PreviewsSettingsPage::configureService(const QModelIndex& index)
157 {
158     const QAbstractItemModel* model = index.model();
159     const QString pluginName = model->data(index).toString();
160     const QString desktopEntryName = model->data(index, ServiceModel::DesktopEntryNameRole).toString();
161 
162     ConfigurePreviewPluginDialog* dialog = new ConfigurePreviewPluginDialog(pluginName, desktopEntryName, this);
163     dialog->setAttribute(Qt::WA_DeleteOnClose);
164     dialog->show();
165 }
166 
loadPreviewPlugins()167 void PreviewsSettingsPage::loadPreviewPlugins()
168 {
169     QAbstractItemModel* model = m_listView->model();
170 
171     const KService::List plugins = KServiceTypeTrader::self()->query(QStringLiteral("ThumbCreator"));
172     for (const KService::Ptr& service : plugins) {
173         const bool configurable = service->property(QStringLiteral("Configurable"), QVariant::Bool).toBool();
174         const bool show = m_enabledPreviewPlugins.contains(service->desktopEntryName());
175 
176         model->insertRow(0);
177         const QModelIndex index = model->index(0, 0);
178         model->setData(index, show, Qt::CheckStateRole);
179         model->setData(index, configurable, ServiceModel::ConfigurableRole);
180         model->setData(index, service->name(), Qt::DisplayRole);
181         model->setData(index, service->desktopEntryName(), ServiceModel::DesktopEntryNameRole);
182     }
183 
184     model->sort(Qt::DisplayRole);
185 }
186 
loadSettings()187 void PreviewsSettingsPage::loadSettings()
188 {
189     const KConfigGroup globalConfig(KSharedConfig::openConfig(), QStringLiteral("PreviewSettings"));
190     m_enabledPreviewPlugins = globalConfig.readEntry("Plugins", KIO::PreviewJob::defaultPlugins());
191 
192     const qulonglong defaultLocalPreview = static_cast<qulonglong>(DefaultMaxLocalPreviewSize) * 1024 * 1024;
193     const qulonglong maxLocalByteSize = globalConfig.readEntry("MaximumSize", defaultLocalPreview);
194     const int maxLocalMByteSize = maxLocalByteSize / (1024 * 1024);
195     m_localFileSizeBox->setValue(maxLocalMByteSize);
196 
197     const qulonglong defaultRemotePreview = static_cast<qulonglong>(DefaultMaxRemotePreviewSize) * 1024 * 1024;
198     const qulonglong maxRemoteByteSize = globalConfig.readEntry("MaximumRemoteSize", defaultRemotePreview);
199     const int maxRemoteMByteSize = maxRemoteByteSize / (1024 * 1024);
200     m_remoteFileSizeBox->setValue(maxRemoteMByteSize);
201 }
202