1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2019-03-27
7 * Description : a tool to export items to a local storage
8 *
9 * Copyright (C) 2006-2009 by Johannes Wienke <languitar at semipol dot de>
10 * Copyright (C) 2011-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
11 * Copyright (C) 2019-2020 by Maik Qualmann <metzpinguin at gmail dot com>
12 *
13 * This program is free software; you can redistribute it
14 * and/or modify it under the terms of the GNU General
15 * Public License as published by the Free Software Foundation;
16 * either version 2, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * ============================================================ */
24
25 #include "fcexportwidget.h"
26
27 // Qt includes
28
29 #include <QApplication>
30 #include <QRadioButton>
31 #include <QButtonGroup>
32 #include <QVBoxLayout>
33 #include <QCheckBox>
34 #include <QGroupBox>
35 #include <QComboBox>
36 #include <QSpinBox>
37 #include <QLabel>
38
39 // KDE includes
40
41 #include <klocalizedstring.h>
42
43 // Local includes
44
45 #include "digikam_debug.h"
46 #include "dfileselector.h"
47 #include "wstoolutils.h"
48 #include "ditemslist.h"
49 #include "dlayoutbox.h"
50 #include "fctask.h"
51
52 namespace DigikamGenericFileCopyPlugin
53 {
54
55 class Q_DECL_HIDDEN FCExportWidget::Private
56 {
57 public:
58
Private()59 explicit Private()
60 : iface (nullptr),
61 selector (nullptr),
62 imageList (nullptr),
63 overwrite (nullptr),
64 albumPath (nullptr),
65 targetButtonGroup (nullptr),
66 fileCopyButton (nullptr),
67 symLinkButton (nullptr),
68 relativeButton (nullptr),
69 imageChangeGroupBox (nullptr),
70 changeImagesProp (nullptr),
71 removeMetadataProp (nullptr),
72 imageCompression (nullptr),
73 imageResize (nullptr),
74 imageFormat (nullptr)
75 {
76 }
77
78 DInfoInterface* iface;
79 DFileSelector* selector;
80 DItemsList* imageList;
81 QCheckBox* overwrite;
82 QCheckBox* albumPath;
83
84 QButtonGroup* targetButtonGroup;
85 QRadioButton* fileCopyButton;
86 QRadioButton* symLinkButton;
87 QRadioButton* relativeButton;
88
89 QUrl targetUrl;
90
91 QGroupBox* imageChangeGroupBox;
92 QCheckBox* changeImagesProp;
93 QCheckBox* removeMetadataProp;
94
95 QSpinBox* imageCompression;
96 QSpinBox* imageResize;
97 QComboBox* imageFormat;
98 };
99
FCExportWidget(DInfoInterface * const iface,QWidget * const parent)100 FCExportWidget::FCExportWidget(DInfoInterface* const iface, QWidget* const parent)
101 : QWidget(parent),
102 d (new Private)
103 {
104 d->iface = iface;
105
106 // setup local target selection
107
108 const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
109
110 DHBox* const hbox = new DHBox(this);
111 QLabel* const locationLabel = new QLabel(hbox);
112 locationLabel->setText(i18n("Target location: "));
113 d->selector = new DFileSelector(hbox);
114 d->selector->setFileDlgMode(QFileDialog::Directory);
115 d->selector->setFileDlgOptions(QFileDialog::ShowDirsOnly);
116 d->selector->setFileDlgTitle(i18n("Target Folder"));
117 d->selector->setWhatsThis(i18n("Sets the target address to copy the items to."));
118
119 QLabel* const targetLabel = new QLabel(i18n("Target File behavior:"), this);
120 d->targetButtonGroup = new QButtonGroup(this);
121 d->fileCopyButton = new QRadioButton(i18n("Copy files"), this);
122 d->symLinkButton = new QRadioButton(i18n("Create symlinks"), this);
123 d->relativeButton = new QRadioButton(i18n("Create relative symlinks"), this);
124
125 d->overwrite = new QCheckBox(i18n("Overwrite existing items in the target"), this);
126 d->albumPath = new QCheckBox(i18n("Use the album path of the items in the target"), this);
127
128 if (!d->iface->supportAlbums())
129 {
130 d->albumPath->hide();
131 }
132
133 d->targetButtonGroup->addButton(d->fileCopyButton, FCContainer::CopyFile);
134 d->targetButtonGroup->addButton(d->symLinkButton, FCContainer::FullSymLink);
135 d->targetButtonGroup->addButton(d->relativeButton, FCContainer::RelativeSymLink);
136 d->targetButtonGroup->setExclusive(true);
137 d->fileCopyButton->setChecked(true);
138
139 //---------------------------------------------
140
141 d->changeImagesProp = new QCheckBox(i18n("Adjust image properties"), this);
142 d->changeImagesProp->setChecked(false);
143 d->changeImagesProp->setWhatsThis(i18n("If you enable this option, "
144 "all images to be sent can be "
145 "resized and recompressed."));
146
147 //---------------------------------------------
148
149 d->imageChangeGroupBox = new QGroupBox(i18n("Image Properties"), this);
150
151 d->imageResize = new QSpinBox(d->imageChangeGroupBox);
152 d->imageResize->setRange(300, 6000);
153 d->imageResize->setSingleStep(1);
154 d->imageResize->setValue(1024);
155 d->imageResize->setSuffix(i18n(" px"));
156 d->imageResize->setWhatsThis(i18n("Select the length of the images that are to be sent. "
157 "The aspect ratio is preserved."));
158 d->imageChangeGroupBox->setEnabled(false);
159
160 QLabel* const labelImageResize = new QLabel(i18n("Image Length:"), d->imageChangeGroupBox);
161 labelImageResize->setBuddy(d->imageResize);
162
163 //---------------------------------------------
164
165 QLabel* const labelImageFormat = new QLabel(d->imageChangeGroupBox);
166 labelImageFormat->setWordWrap(false);
167 labelImageFormat->setText(i18n("Image Format:"));
168
169 d->imageFormat = new QComboBox(d->imageChangeGroupBox);
170 d->imageFormat->setEditable(false);
171 d->imageFormat->setWhatsThis(i18n("Select your preferred format to convert image."));
172 d->imageFormat->addItem(i18nc("Image format: JPEG", "Jpeg"), FCContainer::JPEG);
173 d->imageFormat->addItem(i18nc("Image format: PNG", "Png"), FCContainer::PNG);
174 labelImageFormat->setBuddy(d->imageFormat);
175
176 //---------------------------------------------
177
178 d->imageCompression = new QSpinBox(d->imageChangeGroupBox);
179 d->imageCompression->setRange(1, 100);
180 d->imageCompression->setSingleStep(1);
181 d->imageCompression->setValue(75);
182 d->imageCompression->setWhatsThis(i18n("<p>The new compression value of JPEG images to be sent:</p>"
183 "<p><b>1</b>: very high compression<br/>"
184 "<b>25</b>: high compression<br/>"
185 "<b>50</b>: medium compression<br/>"
186 "<b>75</b>: low compression (default value)<br/>"
187 "<b>100</b>: no compression</p>"));
188
189 QLabel* const labelImageCompression = new QLabel(i18n("Image quality:"), d->imageChangeGroupBox);
190 labelImageCompression->setBuddy(d->imageCompression);
191
192 //---------------------------------------------
193
194 d->removeMetadataProp = new QCheckBox(i18n("Remove all metadata"), d->imageChangeGroupBox);
195 d->removeMetadataProp->setWhatsThis(i18n("If you enable this option, all metadata "
196 "as Exif, Iptc, and Xmp will be removed."));
197
198 //---------------------------------------------
199
200 QGridLayout* const grid2 = new QGridLayout(d->imageChangeGroupBox);
201 grid2->addWidget(labelImageResize, 0, 0, 1, 1);
202 grid2->addWidget(d->imageResize, 0, 1, 1, 2);
203 grid2->addWidget(labelImageFormat, 1, 0, 1, 1);
204 grid2->addWidget(d->imageFormat, 1, 1, 1, 2);
205 grid2->addWidget(labelImageCompression, 2, 0, 1, 1);
206 grid2->addWidget(d->imageCompression, 2, 1, 1, 2);
207 grid2->addWidget(d->removeMetadataProp, 3, 0, 1, 2);
208 grid2->setColumnStretch(2, 10);
209 grid2->setSpacing(spacing);
210 grid2->setAlignment(Qt::AlignTop);
211
212 //---------------------------------------------
213
214 // setup image list
215 d->imageList = new DItemsList(this);
216 d->imageList->setObjectName(QLatin1String("FCExport ImagesList"));
217 d->imageList->setIface(d->iface);
218 d->imageList->loadImagesFromCurrentSelection();
219 d->imageList->setAllowRAW(true);
220 d->imageList->listView()->setWhatsThis(i18n("This is the list of items to copy "
221 "to the specified target."));
222
223 // layout dialog
224 QVBoxLayout* const layout = new QVBoxLayout(this);
225
226 layout->addWidget(hbox);
227 layout->addWidget(targetLabel);
228 layout->addWidget(d->fileCopyButton);
229 layout->addWidget(d->symLinkButton);
230 layout->addWidget(d->relativeButton);
231 layout->addWidget(d->overwrite);
232 layout->addWidget(d->albumPath);
233 layout->addWidget(d->imageList);
234 layout->addWidget(d->changeImagesProp);
235 layout->addWidget(d->imageChangeGroupBox);
236 layout->setSpacing(spacing);
237 layout->setContentsMargins(QMargins());
238
239 // ------------------------------------------------------------------------
240
241 connect(d->selector->lineEdit(), SIGNAL(textEdited(QString)),
242 this, SLOT(slotLabelUrlChanged()));
243
244 connect(d->selector, SIGNAL(signalUrlSelected(QUrl)),
245 this, SLOT(slotLabelUrlChanged()));
246
247 connect(d->fileCopyButton, SIGNAL(toggled(bool)),
248 this, SLOT(slotFileCopyButtonChanged(bool)));
249
250 connect(d->changeImagesProp, SIGNAL(toggled(bool)),
251 d->imageChangeGroupBox, SLOT(setEnabled(bool)));
252
253 }
254
~FCExportWidget()255 FCExportWidget::~FCExportWidget()
256 {
257 delete d;
258 }
259
imagesList() const260 DItemsList* FCExportWidget::imagesList() const
261 {
262 return d->imageList;
263 }
264
targetUrl() const265 QUrl FCExportWidget::targetUrl() const
266 {
267 return d->targetUrl;
268 }
269
getSettings() const270 FCContainer FCExportWidget::getSettings() const
271 {
272 FCContainer settings;
273
274 settings.iface = d->iface;
275 settings.destUrl = d->targetUrl;
276 settings.behavior = d->targetButtonGroup->checkedId();
277 settings.imageFormat = d->imageFormat->currentIndex();
278 settings.imageResize = d->imageResize->value();
279 settings.imageCompression = d->imageCompression->value();
280 settings.overwrite = d->overwrite->isChecked();
281 settings.albumPath = d->albumPath->isChecked();
282 settings.removeMetadata = d->removeMetadataProp->isChecked();
283 settings.changeImageProperties = d->changeImagesProp->isChecked();
284
285 return settings;
286 }
287
setSettings(const FCContainer & settings)288 void FCExportWidget::setSettings(const FCContainer& settings)
289 {
290 d->targetUrl = settings.destUrl;
291 d->selector->setFileDlgPath(d->targetUrl.toLocalFile());
292 QAbstractButton* const button = d->targetButtonGroup->button(settings.behavior);
293
294 if (button)
295 {
296 button->setChecked(true);
297 }
298
299 d->imageFormat->setCurrentIndex(settings.imageFormat);
300 d->imageResize->setValue(settings.imageResize);
301 d->imageCompression->setValue(settings.imageCompression);
302 d->overwrite->setChecked(settings.overwrite);
303 d->albumPath->setChecked(settings.albumPath);
304 d->removeMetadataProp->setChecked(settings.removeMetadata);
305 d->changeImagesProp->setChecked(settings.changeImageProperties);
306 }
307
slotLabelUrlChanged()308 void FCExportWidget::slotLabelUrlChanged()
309 {
310 d->targetUrl = QUrl::fromLocalFile(d->selector->fileDlgPath());
311
312 emit signalTargetUrlChanged(d->targetUrl);
313 }
314
slotFileCopyButtonChanged(bool enabled)315 void FCExportWidget::slotFileCopyButtonChanged(bool enabled)
316 {
317 if (!enabled)
318 {
319 d->changeImagesProp->setChecked(false);
320 }
321
322 d->changeImagesProp->setEnabled(enabled);
323
324 // The changeImagesProp is by default and on each change unchecked
325
326 d->imageChangeGroupBox->setEnabled(false);
327 }
328
329 } // namespace DigikamGenericFileCopyPlugin
330