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