1 /*============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2011-03-14
7  * Description : a DConfigDlgWdg to edit IPTC metadata
8  *
9  * Copyright (C) 2006-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  * Copyright (C) 2011 by Victor Dodon <dodon dot victor at gmail dot com>
11  *
12  * This program is free software; you can redistribute it
13  * and/or modify it under the terms of the GNU General
14  * Public License as published by the Free Software Foundation;
15  * either version 2, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * ============================================================ */
23 
24 #include "iptceditwidget.h"
25 
26 // Qt includes
27 
28 #include <QMenu>
29 #include <QCloseEvent>
30 #include <QKeyEvent>
31 #include <QUrl>
32 #include <QApplication>
33 
34 // KDE includes
35 
36 #include <ksharedconfig.h>
37 #include <kconfiggroup.h>
38 #include <klocalizedstring.h>
39 
40 // Local includes
41 
42 #include "digikam_debug.h"
43 #include "metadataedit.h"
44 #include "iptccategories.h"
45 #include "iptccontent.h"
46 #include "iptccredits.h"
47 #include "iptcenvelope.h"
48 #include "iptckeywords.h"
49 #include "iptcorigin.h"
50 #include "iptcproperties.h"
51 #include "iptcstatus.h"
52 #include "iptcsubjects.h"
53 #include "dmetadata.h"
54 
55 namespace DigikamGenericMetadataEditPlugin
56 {
57 
58 class Q_DECL_HIDDEN IPTCEditWidget::Private
59 {
60 
61 public:
62 
Private()63     explicit Private()
64     {
65         modified        = false;
66         isReadOnly      = false;
67         page_content    = nullptr;
68         page_properties = nullptr;
69         page_subjects   = nullptr;
70         page_keywords   = nullptr;
71         page_categories = nullptr;
72         page_credits    = nullptr;
73         page_status     = nullptr;
74         page_origin     = nullptr;
75         page_envelope   = nullptr;
76         contentPage     = nullptr;
77         propertiesPage  = nullptr;
78         subjectsPage    = nullptr;
79         keywordsPage    = nullptr;
80         categoriesPage  = nullptr;
81         creditsPage     = nullptr;
82         statusPage      = nullptr;
83         originPage      = nullptr;
84         envelopePage    = nullptr;
85         dlg             = nullptr;
86     }
87 
88     bool                  modified;
89     bool                  isReadOnly;
90 
91     DConfigDlgWdgItem*    page_content;
92     DConfigDlgWdgItem*    page_properties;
93     DConfigDlgWdgItem*    page_subjects;
94     DConfigDlgWdgItem*    page_keywords;
95     DConfigDlgWdgItem*    page_categories;
96     DConfigDlgWdgItem*    page_credits;
97     DConfigDlgWdgItem*    page_status;
98     DConfigDlgWdgItem*    page_origin;
99     DConfigDlgWdgItem*    page_envelope;
100 
101     IPTCContent*          contentPage;
102     IPTCProperties*       propertiesPage;
103     IPTCSubjects*         subjectsPage;
104     IPTCKeywords*         keywordsPage;
105     IPTCCategories*       categoriesPage;
106     IPTCCredits*          creditsPage;
107     IPTCStatus*           statusPage;
108     IPTCOrigin*           originPage;
109     IPTCEnvelope*         envelopePage;
110 
111     MetadataEditDialog*   dlg;
112 };
113 
IPTCEditWidget(MetadataEditDialog * const parent)114 IPTCEditWidget::IPTCEditWidget(MetadataEditDialog* const parent)
115     : DConfigDlgWdg(parent),
116       d            (new Private)
117 {
118     d->dlg           = parent;
119 
120     d->contentPage   = new IPTCContent(this);
121     d->page_content  = addPage(d->contentPage, i18nc("@item: iptc", "Content"));
122     d->page_content->setIcon(QIcon::fromTheme(QLatin1String("draw-text")));
123 
124     d->originPage  = new IPTCOrigin(this);
125     d->page_origin = addPage(d->originPage, i18nc("@item: iptc", "Origin"));
126     d->page_origin->setIcon(QIcon::fromTheme(QLatin1String("globe")));
127 
128     d->creditsPage  = new IPTCCredits(this);
129     d->page_credits = addPage(d->creditsPage, i18nc("@item: iptc", "Credits"));
130     d->page_credits->setIcon(QIcon::fromTheme(QLatin1String("address-book-new")));
131 
132     d->subjectsPage  = new IPTCSubjects(this);
133     d->page_subjects = addPage(d->subjectsPage, i18nc("@item: iptc", "Subjects"));
134     d->page_subjects->setIcon(QIcon::fromTheme(QLatin1String("feed-subscribe")));
135 
136     d->keywordsPage  = new IPTCKeywords(this);
137     d->page_keywords = addPage(d->keywordsPage, i18nc("@item: iptc", "Keywords"));
138     d->page_keywords->setIcon(QIcon::fromTheme(QLatin1String("bookmark-new")));
139 
140     d->categoriesPage  = new IPTCCategories(this);
141     d->page_categories = addPage(d->categoriesPage, i18nc("@item: iptc", "Categories"));
142     d->page_categories->setIcon(QIcon::fromTheme(QLatin1String("folder-pictures")));
143 
144     d->statusPage  = new IPTCStatus(this);
145     d->page_status = addPage(d->statusPage, i18nc("@item: iptc", "Status"));
146     d->page_status->setIcon(QIcon::fromTheme(QLatin1String("view-task")));
147 
148     d->propertiesPage  = new IPTCProperties(this);
149     d->page_properties = addPage(d->propertiesPage, i18nc("@item: iptc", "Properties"));
150     d->page_properties->setIcon(QIcon::fromTheme(QLatin1String("draw-freehand")));
151 
152     d->envelopePage  = new IPTCEnvelope(this);
153     d->page_envelope = addPage(d->envelopePage, i18nc("@item: iptc", "Envelope"));
154     d->page_envelope->setIcon(QIcon::fromTheme(QLatin1String("mail-mark-unread")));
155 
156     // ---------------------------------------------------------------
157 
158     connect(d->contentPage, SIGNAL(signalModified()),
159             this, SLOT(slotModified()));
160 
161     connect(d->propertiesPage, SIGNAL(signalModified()),
162             this, SLOT(slotModified()));
163 
164     connect(d->subjectsPage, SIGNAL(signalModified()),
165             this, SLOT(slotModified()));
166 
167     connect(d->keywordsPage, SIGNAL(signalModified()),
168             this, SLOT(slotModified()));
169 
170     connect(d->categoriesPage, SIGNAL(signalModified()),
171             this, SLOT(slotModified()));
172 
173     connect(d->creditsPage, SIGNAL(signalModified()),
174             this, SLOT(slotModified()));
175 
176     connect(d->statusPage, SIGNAL(signalModified()),
177             this, SLOT(slotModified()));
178 
179     connect(d->originPage, SIGNAL(signalModified()),
180             this, SLOT(slotModified()));
181 
182     connect(d->envelopePage, SIGNAL(signalModified()),
183             this, SLOT(slotModified()));
184 
185     // ------------------------------------------------------------
186 
187     readSettings();
188     slotItemChanged();
189 }
190 
~IPTCEditWidget()191 IPTCEditWidget::~IPTCEditWidget()
192 {
193     delete d;
194 }
195 
readSettings()196 void IPTCEditWidget::readSettings()
197 {
198     KSharedConfig::Ptr config = KSharedConfig::openConfig();
199     KConfigGroup group        = config->group(QLatin1String("All Metadata Edit Settings"));
200     showPage(group.readEntry(QLatin1String("All IPTC Edit Page"), 0));
201     d->contentPage->setCheckedSyncJFIFComment(group.readEntry(QLatin1String("All Sync JFIF Comment"), true));
202     d->contentPage->setCheckedSyncEXIFComment(group.readEntry(QLatin1String("All Sync EXIF Comment"), true));
203     d->originPage->setCheckedSyncEXIFDate(group.readEntry(QLatin1String("All Sync EXIF Date"), true));
204 }
205 
saveSettings()206 void IPTCEditWidget::saveSettings()
207 {
208     KSharedConfig::Ptr config = KSharedConfig::openConfig();
209     KConfigGroup group        = config->group(QLatin1String("All Metadata Edit Settings"));
210     group.writeEntry(QLatin1String("All IPTC Edit Page"),    activePageIndex());
211     group.writeEntry(QLatin1String("All Sync JFIF Comment"), d->contentPage->syncJFIFCommentIsChecked());
212     group.writeEntry(QLatin1String("All Sync EXIF Comment"), d->contentPage->syncEXIFCommentIsChecked());
213     group.writeEntry(QLatin1String("All Sync EXIF Date"),    d->originPage->syncEXIFDateIsChecked());
214     config->sync();
215 }
216 
slotItemChanged()217 void IPTCEditWidget::slotItemChanged()
218 {
219     d->page_content->setHeader(d->dlg->currentItemTitleHeader(i18nc("@info", "Content Information\n"
220                      "Use this panel to describe the visual content of the image")));
221     d->page_origin->setHeader(d->dlg->currentItemTitleHeader(i18nc("@info", "Origin Information\n"
222                      "Use this panel for formal descriptive information about the image")));
223     d->page_credits->setHeader(d->dlg->currentItemTitleHeader(i18nc("@info", "Credit Information\n"
224                      "Use this panel to record copyright information about the image")));
225     d->page_subjects->setHeader(d->dlg->currentItemTitleHeader(i18nc("@info", "Subject Information\n"
226                      "Use this panel to record subject information about the image")));
227     d->page_keywords->setHeader(d->dlg->currentItemTitleHeader(i18nc("@info", "Keyword Information\n"
228                      "Use this panel to record keywords relevant to the image")));
229     d->page_categories->setHeader(d->dlg->currentItemTitleHeader(i18nc("@info", "Category Information\n"
230                      "Use this panel to record categories relevant to the image")));
231     d->page_status->setHeader(d->dlg->currentItemTitleHeader(i18nc("@info", "Status Information\n"
232                      "Use this panel to record workflow information")));
233     d->page_properties->setHeader(d->dlg->currentItemTitleHeader(i18nc("@info", "Status Properties\n"
234                      "Use this panel to record workflow properties")));
235     d->page_envelope->setHeader(d->dlg->currentItemTitleHeader(i18nc("@info", "Envelope Information\n"
236                      "Use this panel to record editorial details")));
237 
238     QScopedPointer<DMetadata> meta(new DMetadata);
239     meta->load((*d->dlg->currentItem()).toLocalFile());
240 
241     d->contentPage->readMetadata(*meta);
242     d->originPage->readMetadata(*meta);
243     d->creditsPage->readMetadata(*meta);
244     d->subjectsPage->readMetadata(*meta);
245     d->keywordsPage->readMetadata(*meta);
246     d->categoriesPage->readMetadata(*meta);
247     d->statusPage->readMetadata(*meta);
248     d->propertiesPage->readMetadata(*meta);
249     d->envelopePage->readMetadata(*meta);
250 
251     d->isReadOnly = !DMetadata::canWriteIptc((*d->dlg->currentItem()).toLocalFile());
252     emit signalSetReadOnly(d->isReadOnly);
253 
254     d->page_content->setEnabled(!d->isReadOnly);
255     d->page_origin->setEnabled(!d->isReadOnly);
256     d->page_credits->setEnabled(!d->isReadOnly);
257     d->page_subjects->setEnabled(!d->isReadOnly);
258     d->page_keywords->setEnabled(!d->isReadOnly);
259     d->page_categories->setEnabled(!d->isReadOnly);
260     d->page_status->setEnabled(!d->isReadOnly);
261     d->page_properties->setEnabled(!d->isReadOnly);
262     d->page_envelope->setEnabled(!d->isReadOnly);
263 }
264 
apply()265 void IPTCEditWidget::apply()
266 {
267     if (d->modified && !d->isReadOnly)
268     {
269         QScopedPointer<DMetadata> meta(new DMetadata);
270         meta->load((*d->dlg->currentItem()).toLocalFile());
271 
272         d->contentPage->applyMetadata(*meta);
273         d->originPage->applyMetadata(*meta);
274         d->creditsPage->applyMetadata(*meta);
275         d->subjectsPage->applyMetadata(*meta);
276         d->keywordsPage->applyMetadata(*meta);
277         d->categoriesPage->applyMetadata(*meta);
278         d->statusPage->applyMetadata(*meta);
279         d->propertiesPage->applyMetadata(*meta);
280         d->envelopePage->applyMetadata(*meta);
281 
282         meta->applyChanges();
283 
284         d->modified = false;
285     }
286 }
287 
slotModified()288 void IPTCEditWidget::slotModified()
289 {
290     if (!d->isReadOnly)
291     {
292         d->modified = true;
293         emit signalModified();
294     }
295 }
296 
showPage(int page)297 void IPTCEditWidget::showPage(int page)
298 {
299     switch (page)
300     {
301         case 0:
302             setCurrentPage(d->page_content);
303             break;
304         case 1:
305             setCurrentPage(d->page_origin);
306             break;
307         case 2:
308             setCurrentPage(d->page_credits);
309             break;
310         case 3:
311             setCurrentPage(d->page_subjects);
312             break;
313         case 4:
314             setCurrentPage(d->page_keywords);
315             break;
316         case 5:
317             setCurrentPage(d->page_categories);
318             break;
319         case 6:
320             setCurrentPage(d->page_status);
321             break;
322         case 7:
323             setCurrentPage(d->page_properties);
324             break;
325         case 8:
326             setCurrentPage(d->page_envelope);
327             break;
328         default:
329             setCurrentPage(d->page_content);
330             break;
331     }
332 }
333 
activePageIndex() const334 int IPTCEditWidget::activePageIndex() const
335 {
336     DConfigDlgWdgItem* const cur = currentPage();
337 
338     if (cur == d->page_content)    return 0;
339     if (cur == d->page_origin)     return 1;
340     if (cur == d->page_credits)    return 2;
341     if (cur == d->page_subjects)   return 3;
342     if (cur == d->page_keywords)   return 4;
343     if (cur == d->page_categories) return 5;
344     if (cur == d->page_status)     return 6;
345     if (cur == d->page_properties) return 7;
346     if (cur == d->page_envelope)   return 8;
347 
348     return 0;
349 }
350 
isModified() const351 bool IPTCEditWidget::isModified() const
352 {
353     return d->modified;
354 }
355 
356 } // namespace DigikamGenericMetadataEditPlugin
357