1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2003-03-09
7 * Description : Album properties dialog.
8 *
9 * Copyright (C) 2003-2004 by Renchi Raju <renchi dot raju at gmail dot com>
10 * Copyright (C) 2005 by Tom Albers <tomalbers at kde dot nl>
11 * Copyright (C) 2006-2021 by Gilles Caulier <caulier dot gilles 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)
17 * any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * ============================================================ */
25
26 #include "albumpropsedit.h"
27
28 // Qt includes
29
30 #include <QCheckBox>
31 #include <QDateTime>
32 #include <QGridLayout>
33 #include <QLabel>
34 #include <QPointer>
35 #include <QRegExp>
36 #include <QValidator>
37 #include <QApplication>
38 #include <QStyle>
39 #include <QComboBox>
40 #include <QLineEdit>
41 #include <QStandardPaths>
42 #include <QMessageBox>
43 #include <QDialogButtonBox>
44 #include <QVBoxLayout>
45 #include <QPushButton>
46 #include <QPlainTextEdit>
47
48 // KDE includes
49
50 #include <klocalizedstring.h>
51
52 // Local includes
53
54 #include "dlayoutbox.h"
55 #include "coredb.h"
56 #include "album.h"
57 #include "albummanager.h"
58 #include "applicationsettings.h"
59 #include "collectionmanager.h"
60 #include "coredbaccess.h"
61 #include "dxmlguiwindow.h"
62 #include "dexpanderbox.h"
63 #include "ddatepicker.h"
64
65 namespace Digikam
66 {
67
68 class Q_DECL_HIDDEN AlbumDatePicker : public DDatePicker
69 {
70 Q_OBJECT
71
72 public:
73
AlbumDatePicker(QWidget * const widget)74 explicit AlbumDatePicker(QWidget* const widget)
75 : DDatePicker(widget)
76 {
77 }
78
~AlbumDatePicker()79 ~AlbumDatePicker() override
80 {
81 }
82
dateLineEnterPressed()83 void dateLineEnterPressed()
84 {
85 lineEnterPressed();
86 }
87 };
88
89 // --------------------------------------------------------------------------------
90
91 class Q_DECL_HIDDEN AlbumPropsEdit::Private
92 {
93
94 public:
95
Private()96 explicit Private()
97 : buttons (nullptr),
98 topLabel (nullptr),
99 categoryCombo (nullptr),
100 parentCombo (nullptr),
101 titleEdit (nullptr),
102 commentsEdit (nullptr),
103 datePicker (nullptr),
104 album (nullptr)
105 {
106 }
107
108 QDialogButtonBox* buttons;
109
110 QLabel* topLabel;
111 QComboBox* categoryCombo;
112 QComboBox* parentCombo;
113 QLineEdit* titleEdit;
114 QPlainTextEdit* commentsEdit;
115
116 AlbumDatePicker* datePicker;
117
118 PAlbum* album;
119 };
120
AlbumPropsEdit(PAlbum * const album,bool create)121 AlbumPropsEdit::AlbumPropsEdit(PAlbum* const album, bool create)
122 : QDialog(nullptr),
123 d (new Private)
124 {
125 setModal(true);
126 setWindowTitle(create ? i18nc("@title: album properties", "New Album") : i18nc("@title: album properties", "Edit Album"));
127
128 d->buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
129 d->buttons->button(QDialogButtonBox::Ok)->setDefault(true);
130
131 d->album = album;
132 QWidget* const page = new QWidget(this);
133 QLabel* const logo = new QLabel(page);
134
135 logo->setPixmap(QIcon::fromTheme(QLatin1String("digikam")).pixmap(QSize(48,48)));
136
137 d->topLabel = new QLabel(page);
138 d->topLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
139 d->topLabel->setWordWrap(false);
140
141 if (create)
142 {
143 slotNewAlbumTextChanged(0);
144 }
145 else
146 {
147 d->topLabel->setText(i18nc("@label: album properties", "\"%1\"\nAlbum Properties", album->title()));
148 }
149
150 // --------------------------------------------------------
151
152 DLineWidget* const topLine = new DLineWidget(Qt::Horizontal);
153
154 QLabel* const titleLabel = new QLabel(page);
155 titleLabel->setText(i18nc("@label: album properties", "&Title:"));
156
157 d->titleEdit = new QLineEdit(page);
158 d->titleEdit->setClearButtonEnabled(true);
159 titleLabel->setBuddy(d->titleEdit);
160
161 QRegExp titleRx(QLatin1String("[^/:]+"));
162 QValidator* const titleValidator = new QRegExpValidator(titleRx, this);
163 d->titleEdit->setValidator(titleValidator);
164 d->titleEdit->setPlaceholderText(i18nc("@label: album properties", "Enter album title here..."));
165
166 QLabel* const categoryLabel = new QLabel(page);
167 categoryLabel->setText(i18nc("@label: album properties", "Ca&tegory:"));
168
169 d->categoryCombo = new QComboBox(page);
170 d->categoryCombo->setEditable(true);
171 categoryLabel->setBuddy(d->categoryCombo);
172
173 QLabel* const parentLabel = new QLabel(page);
174 parentLabel->setText(i18nc("@label: album properties", "Ch&ild Of:"));
175
176 d->parentCombo = new QComboBox(page);
177 parentLabel->setBuddy(d->parentCombo);
178
179 QLabel* const commentsLabel = new QLabel(page);
180 commentsLabel->setText(i18nc("@label: album properties", "Ca&ption:"));
181
182 d->commentsEdit = new QPlainTextEdit(page);
183 commentsLabel->setBuddy(d->commentsEdit);
184 d->commentsEdit->setWordWrapMode(QTextOption::WordWrap);
185 d->commentsEdit->setPlaceholderText(i18nc("@label: album properties", "Enter album caption here..."));
186
187 QLabel* const dateLabel = new QLabel(page);
188 dateLabel->setText(i18nc("@label: album properties", "Album &date:"));
189
190 d->datePicker = new AlbumDatePicker(page);
191 dateLabel->setBuddy(d->datePicker);
192
193 DHBox* const buttonRow = new DHBox(page);
194 QPushButton* const dateLowButton = new QPushButton(i18nc("@action: Selects the date of the oldest image", "&Oldest"), buttonRow);
195 dateLowButton->setWhatsThis(i18nc("@info", "Use this button to select the date of the oldest image from album."));
196 QPushButton* const dateAvgButton = new QPushButton(i18nc("@action: Calculates the average date", "&Average"), buttonRow);
197 dateAvgButton->setWhatsThis(i18nc("@info", "Use this button to calculate the average date of images from album."));
198 QPushButton* const dateHighButton = new QPushButton(i18nc("@action: Selects the date of the newest image", "Newest"), buttonRow);
199 dateHighButton->setWhatsThis(i18nc("@info", "Use this button to select the date of the newest image from album."));
200
201 if (create)
202 {
203 setTabOrder(d->titleEdit, d->categoryCombo);
204 setTabOrder(d->categoryCombo, d->parentCombo);
205 setTabOrder(d->parentCombo, d->commentsEdit);
206 setTabOrder(d->commentsEdit, d->datePicker);
207 }
208 else
209 {
210 setTabOrder(d->titleEdit, d->categoryCombo);
211 setTabOrder(d->categoryCombo, d->commentsEdit);
212 setTabOrder(d->commentsEdit, d->datePicker);
213 d->parentCombo->hide();
214 parentLabel->hide();
215 }
216
217 d->commentsEdit->setTabChangesFocus(true);
218
219 // --------------------------------------------------------
220
221 QGridLayout* const grid = new QGridLayout();
222 grid->addWidget(logo, 0, 0, 1, 1);
223 grid->addWidget(d->topLabel, 0, 1, 1, 1);
224 grid->addWidget(topLine, 1, 0, 1, 2);
225 grid->addWidget(titleLabel, 2, 0, 1, 1);
226 grid->addWidget(d->titleEdit, 2, 1, 1, 1);
227 grid->addWidget(categoryLabel, 3, 0, 1, 1);
228 grid->addWidget(d->categoryCombo, 3, 1, 1, 1);
229
230 if (create)
231 {
232 grid->addWidget(parentLabel, 4, 0, 1, 1);
233 grid->addWidget(d->parentCombo, 4, 1, 1, 1);
234 grid->addWidget(commentsLabel, 5, 0, 1, 1, Qt::AlignLeft | Qt::AlignTop);
235 grid->addWidget(d->commentsEdit, 5, 1, 1, 1);
236 grid->addWidget(dateLabel, 6, 0, 1, 1, Qt::AlignLeft | Qt::AlignTop);
237 grid->addWidget(d->datePicker, 6, 1, 1, 1);
238 grid->addWidget(buttonRow, 7, 1, 1, 1);
239 }
240 else
241 {
242 grid->addWidget(commentsLabel, 4, 0, 1, 1, Qt::AlignLeft | Qt::AlignTop);
243 grid->addWidget(d->commentsEdit, 4, 1, 1, 1);
244 grid->addWidget(dateLabel, 5, 0, 1, 1, Qt::AlignLeft | Qt::AlignTop);
245 grid->addWidget(d->datePicker, 5, 1, 1, 1);
246 grid->addWidget(buttonRow, 6, 1, 1, 1);
247 }
248
249 grid->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
250 grid->setContentsMargins(QMargins());
251 page->setLayout(grid);
252
253 QVBoxLayout* const vbx = new QVBoxLayout(this);
254 vbx->addWidget(page);
255 vbx->addWidget(d->buttons);
256 setLayout(vbx);
257
258 // Initialize ---------------------------------------------
259
260 ApplicationSettings* const settings = ApplicationSettings::instance();
261
262 if (settings)
263 {
264 d->categoryCombo->addItem(QString());
265 QStringList Categories = settings->getAlbumCategoryNames();
266 d->categoryCombo->addItems(Categories);
267 int categoryIndex = Categories.indexOf(album->category());
268
269 if (categoryIndex != -1)
270 {
271 // + 1 because of the empty item
272
273 d->categoryCombo->setCurrentIndex(categoryIndex + 1);
274 }
275 }
276
277 if (create)
278 {
279 d->titleEdit->setText(i18nc("@label: album properties", "New Album"));
280 d->datePicker->setDate(QDate::currentDate());
281 d->parentCombo->addItem(i18nc("@item: album properties", "Selected Album (Default)"));
282 d->parentCombo->addItem(i18nc("@item: top level folder of album","Root of current collection"));
283 }
284 else
285 {
286 d->titleEdit->setText(album->title());
287 d->commentsEdit->setPlainText(album->caption());
288 d->datePicker->setDate(album->date());
289 }
290
291 d->titleEdit->selectAll();
292 d->titleEdit->setFocus();
293
294 // -- slots connections -------------------------------------------
295
296 connect(d->titleEdit, SIGNAL(textChanged(QString)),
297 this, SLOT(slotTitleChanged(QString)));
298
299 connect(dateLowButton, SIGNAL(clicked()),
300 this, SLOT(slotDateLowButtonClicked()));
301
302 connect(dateAvgButton, SIGNAL(clicked()),
303 this, SLOT(slotDateAverageButtonClicked()));
304
305 connect(dateHighButton, SIGNAL(clicked()),
306 this, SLOT(slotDateHighButtonClicked()));
307
308 connect(d->parentCombo, SIGNAL(activated(int)),
309 this, SLOT(slotNewAlbumTextChanged(int)));
310
311 connect(d->buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()),
312 this, SLOT(accept()));
313
314 connect(d->buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()),
315 this, SLOT(reject()));
316
317 connect(d->buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()),
318 this, SLOT(slotHelp()));
319 }
320
~AlbumPropsEdit()321 AlbumPropsEdit::~AlbumPropsEdit()
322 {
323 delete d;
324 }
325
title() const326 QString AlbumPropsEdit::title() const
327 {
328 return d->titleEdit->text().trimmed();
329 }
330
comments() const331 QString AlbumPropsEdit::comments() const
332 {
333 return d->commentsEdit->toPlainText();
334 }
335
date() const336 QDate AlbumPropsEdit::date() const
337 {
338 // See bug #267944 : update calendar view if user enter a date in text field.
339
340 d->datePicker->dateLineEnterPressed();
341
342 return d->datePicker->date();
343 }
344
parent() const345 int AlbumPropsEdit::parent() const
346 {
347 return d->parentCombo->currentIndex();
348 }
349
category() const350 QString AlbumPropsEdit::category() const
351 {
352 QString name = d->categoryCombo->currentText();
353
354 if (name.isEmpty())
355 {
356 name = i18nc("@info: album properties", "Uncategorized Album");
357 }
358
359 return name;
360 }
361
albumCategories() const362 QStringList AlbumPropsEdit::albumCategories() const
363 {
364 QStringList Categories;
365 ApplicationSettings* const settings = ApplicationSettings::instance();
366
367 if (settings)
368 {
369 Categories = settings->getAlbumCategoryNames();
370 }
371
372 QString currentCategory = d->categoryCombo->currentText();
373
374 if (Categories.indexOf(currentCategory) == -1)
375 {
376 Categories.append(currentCategory);
377 }
378
379 Categories.sort();
380
381 return Categories;
382 }
383
editProps(PAlbum * const album,QString & title,QString & comments,QDate & date,QString & category,QStringList & albumCategories)384 bool AlbumPropsEdit::editProps(PAlbum* const album, QString& title,
385 QString& comments, QDate& date, QString& category,
386 QStringList& albumCategories)
387 {
388 QPointer<AlbumPropsEdit> dlg = new AlbumPropsEdit(album);
389
390 bool ok = (dlg->exec() == QDialog::Accepted);
391
392 title = dlg->title();
393 comments = dlg->comments();
394 date = dlg->date();
395 category = dlg->category();
396 albumCategories = dlg->albumCategories();
397
398 delete dlg;
399 return ok;
400 }
401
createNew(PAlbum * const parent,QString & title,QString & comments,QDate & date,QString & category,QStringList & albumCategories,int & parentSelector)402 bool AlbumPropsEdit::createNew(PAlbum* const parent, QString& title, QString& comments,
403 QDate& date, QString& category, QStringList& albumCategories,
404 int& parentSelector)
405 {
406 QPointer<AlbumPropsEdit> dlg = new AlbumPropsEdit(parent, true);
407
408 bool ok = (dlg->exec() == QDialog::Accepted);
409
410 title = dlg->title();
411 comments = dlg->comments();
412 date = dlg->date();
413 category = dlg->category();
414 albumCategories = dlg->albumCategories();
415 parentSelector = dlg->parent();
416
417 delete dlg;
418 return ok;
419 }
420
slotTitleChanged(const QString & newtitle)421 void AlbumPropsEdit::slotTitleChanged(const QString& newtitle)
422 {
423 QRegExp emptyTitle = QRegExp(QLatin1String("^\\s*$"));
424 bool enable = (!emptyTitle.exactMatch(newtitle) && !newtitle.isEmpty());
425 d->buttons->button(QDialogButtonBox::Ok)->setEnabled(enable);
426 }
427
slotNewAlbumTextChanged(int index)428 void AlbumPropsEdit::slotNewAlbumTextChanged(int index)
429 {
430 QString title;
431
432 if (index == 0)
433 {
434 title = d->album->title();
435 }
436 else
437 {
438 title = CollectionManager::instance()->albumRootLabel(d->album->albumRootId());
439 }
440
441 d->topLabel->setText(i18nc("@label: album properties", "Create new Album in\n\"%1\"", title));
442 }
443
slotDateLowButtonClicked()444 void AlbumPropsEdit::slotDateLowButtonClicked()
445 {
446 setCursor(Qt::WaitCursor);
447
448 QDate lowDate = CoreDbAccess().db()->getAlbumLowestDate(d->album->id());
449
450 if (lowDate.isValid())
451 {
452 d->datePicker->setDate(lowDate);
453 }
454
455 setCursor(Qt::ArrowCursor);
456 }
457
slotDateHighButtonClicked()458 void AlbumPropsEdit::slotDateHighButtonClicked()
459 {
460 setCursor(Qt::WaitCursor);
461
462 QDate highDate = CoreDbAccess().db()->getAlbumHighestDate(d->album->id());
463
464 if (highDate.isValid())
465 {
466 d->datePicker->setDate(highDate);
467 }
468
469 setCursor(Qt::ArrowCursor);
470 }
471
slotDateAverageButtonClicked()472 void AlbumPropsEdit::slotDateAverageButtonClicked()
473 {
474 setCursor(Qt::WaitCursor);
475
476 QDate avDate = CoreDbAccess().db()->getAlbumAverageDate(d->album->id());
477
478 setCursor(Qt::ArrowCursor);
479
480 if (avDate.isValid())
481 {
482 d->datePicker->setDate(avDate);
483 }
484 else
485 {
486 QMessageBox::critical(this, i18nc("@title: album properties", "Could Not Calculate Average"),
487 i18nc("@info: album properties", "Could not calculate date average for this album."));
488 }
489 }
490
slotHelp()491 void AlbumPropsEdit::slotHelp()
492 {
493 DXmlGuiWindow::openHandbook();
494 }
495
496 } // namespace Digikam
497
498 #include "albumpropsedit.moc"
499