File indexing completed on 2024-04-28 04:21:18

0001 // SPDX-FileCopyrightText: 2014-2020 The KPhotoAlbum Development Team
0002 // SPDX-FileCopyrightText: 2021 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
0003 //
0004 // SPDX-License-Identifier: GPL-2.0-or-later
0005 
0006 // Qt includes
0007 #include <QCalendarWidget>
0008 #include <QComboBox>
0009 #include <QHBoxLayout>
0010 #include <QHeaderView>
0011 #include <QLabel>
0012 #include <QLineEdit>
0013 #include <QLocale>
0014 #include <QPushButton>
0015 #include <QShortcut>
0016 #include <QTableWidget>
0017 #include <QVBoxLayout>
0018 
0019 // KDE includes
0020 #include <KColorScheme>
0021 #include <KLocalizedString>
0022 #include <KPageWidgetModel>
0023 
0024 // Local includes
0025 #include "BirthdayPage.h"
0026 #include "DateTableWidgetItem.h"
0027 
0028 #include <DB/Category.h>
0029 #include <DB/CategoryCollection.h>
0030 #include <DB/ImageDB.h>
0031 #include <MainWindow/DirtyIndicator.h>
0032 
0033 Settings::BirthdayPage::BirthdayPage(QWidget *parent)
0034     : QWidget(parent)
0035 {
0036     QVBoxLayout *mainLayout = new QVBoxLayout(this);
0037 
0038     QHBoxLayout *dataLayout = new QHBoxLayout;
0039     mainLayout->addLayout(dataLayout);
0040 
0041     QVBoxLayout *itemsLayout = new QVBoxLayout;
0042     dataLayout->addLayout(itemsLayout);
0043 
0044     QHBoxLayout *itemsHeaderLayout = new QHBoxLayout;
0045     itemsLayout->addLayout(itemsHeaderLayout);
0046 
0047     QLabel *categoryText = new QLabel(i18n("Category:"));
0048     itemsHeaderLayout->addWidget(categoryText);
0049 
0050     m_categoryBox = new QComboBox;
0051     itemsHeaderLayout->addWidget(m_categoryBox);
0052     connect(m_categoryBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &BirthdayPage::changeCategory);
0053 
0054     m_filter = new QLineEdit;
0055     itemsHeaderLayout->addWidget(m_filter);
0056     connect(m_filter, &QLineEdit::textChanged, this, &BirthdayPage::resetCategory);
0057     const auto filterShortcut = new QShortcut(Qt::AltModifier + Qt::Key_F, m_filter, SLOT(setFocus()));
0058     m_filter->setPlaceholderText(i18nc("@label:textedit", "Filter ... (%1)", filterShortcut->key().toString(QKeySequence::NativeText)));
0059 
0060     if (QLocale().dateFormat(QLocale::ShortFormat).contains(QString::fromUtf8("yyyy"))) {
0061         m_dateFormats << QLocale().dateFormat(QLocale::ShortFormat);
0062     } else {
0063         m_dateFormats << QLocale().dateFormat(QLocale::ShortFormat).replace(QString::fromUtf8("yy"), QString::fromUtf8("yyyy"));
0064     }
0065     m_dateFormats << QLocale().dateFormat(QLocale::ShortFormat)
0066                   << QLocale().dateFormat(QLocale::LongFormat);
0067 
0068     m_dataView = new QTableWidget;
0069     m_dataView->setColumnCount(2);
0070     m_dataView->verticalHeader()->hide();
0071     m_dataView->setShowGrid(false);
0072     itemsLayout->addWidget(m_dataView);
0073     connect(m_dataView, &QTableWidget::cellClicked, this, &BirthdayPage::editDate);
0074 
0075     QVBoxLayout *calendarLayout = new QVBoxLayout;
0076     dataLayout->addLayout(calendarLayout);
0077 
0078     calendarLayout->addStretch();
0079 
0080     m_birthdayOfLabel = new QLabel;
0081     calendarLayout->addWidget(m_birthdayOfLabel);
0082 
0083     m_dateInput = new QLineEdit;
0084     calendarLayout->addWidget(m_dateInput);
0085     connect(m_dateInput, &QLineEdit::textEdited, this, &BirthdayPage::checkDateInput);
0086     connect(m_dateInput, &QLineEdit::editingFinished, this, &BirthdayPage::checkDate);
0087 
0088     m_calendar = new QCalendarWidget;
0089     calendarLayout->addWidget(m_calendar);
0090     connect(m_calendar, &QCalendarWidget::clicked, this, &BirthdayPage::setDate);
0091 
0092     m_unsetButton = new QPushButton(i18n("Remove birthday"));
0093     calendarLayout->addWidget(m_unsetButton);
0094     connect(m_unsetButton, &QPushButton::clicked, this, &BirthdayPage::removeDate);
0095 
0096     calendarLayout->addStretch();
0097 
0098     QLabel *info = new QLabel(i18n("Set the date of birth for items (say people) here, "
0099                                    "and then see their age when viewing the images."));
0100     mainLayout->addWidget(info);
0101 
0102     m_noDateString = QString::fromUtf8("---");
0103     m_boldFont.setBold(true);
0104 
0105     disableCalendar();
0106 }
0107 
0108 void Settings::BirthdayPage::pageChange(KPageWidgetItem *page)
0109 {
0110     if (page->widget() == this) {
0111         m_lastItem = nullptr;
0112         reload();
0113     }
0114 }
0115 
0116 void Settings::BirthdayPage::reload()
0117 {
0118     m_dateInput->setText(QString());
0119     m_calendar->setSelectedDate(QDate::currentDate());
0120 
0121     disableCalendar();
0122 
0123     m_categoryBox->blockSignals(true);
0124     m_categoryBox->clear();
0125 
0126     int defaultIndex = 0;
0127     int index = 0;
0128 
0129     for (const DB::CategoryPtr &category : DB::ImageDB::instance()->categoryCollection()->categories()) {
0130         if (category->isSpecialCategory()) {
0131             continue;
0132         }
0133         m_categoryBox->addItem(category->name());
0134         if (category->name() == i18n("People")) {
0135             defaultIndex = index;
0136         }
0137         ++index;
0138     }
0139 
0140     m_categoryBox->setCurrentIndex(defaultIndex);
0141     changeCategory(defaultIndex);
0142 
0143     m_categoryBox->blockSignals(false);
0144 }
0145 
0146 void Settings::BirthdayPage::resetCategory()
0147 {
0148     changeCategory(m_categoryBox->currentIndex());
0149 }
0150 
0151 void Settings::BirthdayPage::changeCategory(int index)
0152 {
0153     m_lastItem = nullptr;
0154     m_dataView->clear();
0155     m_dataView->setSortingEnabled(false);
0156     m_dataView->setHorizontalHeaderLabels(QStringList() << i18n("Name") << i18n("Birthday"));
0157 
0158     const QString categoryName = m_categoryBox->itemText(index);
0159     const DB::CategoryPtr category = DB::ImageDB::instance()->categoryCollection()->categoryForName(categoryName);
0160     QStringList items = category->items();
0161 
0162     m_dataView->setRowCount(items.count());
0163     int row = 0;
0164 
0165     for (const QString &text : items) {
0166         if (!m_filter->text().isEmpty()
0167             && text.indexOf(m_filter->text(), 0, Qt::CaseInsensitive) == -1) {
0168             m_dataView->setRowCount(m_dataView->rowCount() - 1);
0169             continue;
0170         }
0171 
0172         QTableWidgetItem *nameItem = new QTableWidgetItem(text);
0173         nameItem->setFlags(nameItem->flags() & ~Qt::ItemIsEditable & ~Qt::ItemIsSelectable);
0174         m_dataView->setItem(row, 0, nameItem);
0175 
0176         QDate dateForItem;
0177         if (m_changedData.contains(categoryName)) {
0178             if (m_changedData[categoryName].contains(text)) {
0179                 dateForItem = m_changedData[categoryName][text];
0180             } else {
0181                 dateForItem = category->birthDate(text);
0182             }
0183         } else {
0184             dateForItem = category->birthDate(text);
0185         }
0186 
0187         DateTableWidgetItem *dateItem = new DateTableWidgetItem(textForDate(dateForItem));
0188         dateItem->setData(Qt::UserRole, dateForItem);
0189         dateItem->setFlags(dateItem->flags() & ~Qt::ItemIsEditable & ~Qt::ItemIsSelectable);
0190         m_dataView->setItem(row, 1, dateItem);
0191 
0192         row++;
0193     }
0194 
0195     m_dataView->setSortingEnabled(true);
0196     m_dataView->sortItems(0);
0197 
0198     disableCalendar();
0199 }
0200 
0201 QString Settings::BirthdayPage::textForDate(const QDate &date) const
0202 {
0203     if (date.isNull()) {
0204         return m_noDateString;
0205     } else {
0206         return QLocale().toString(date, m_dateFormats.at(0));
0207     }
0208 }
0209 
0210 void Settings::BirthdayPage::editDate(int row, int)
0211 {
0212     m_dateInput->setEnabled(true);
0213     m_calendar->setEnabled(true);
0214     m_unsetButton->setEnabled(m_dataView->item(row, 1)->text() != m_noDateString);
0215 
0216     if (m_lastItem != nullptr) {
0217         m_lastItem->setFont(m_font);
0218         m_dataView->item(m_lastItem->row(), 1)->setFont(m_font);
0219     }
0220 
0221     m_dataView->item(row, 0)->setFont(m_boldFont);
0222     m_dataView->item(row, 1)->setFont(m_boldFont);
0223 
0224     m_birthdayOfLabel->setText(i18n("Birthday of %1:", m_dataView->item(row, 0)->text()));
0225 
0226     QString dateString = m_dataView->item(row, 1)->text();
0227     if (dateString != m_noDateString) {
0228         m_dateInput->setText(dateString);
0229         m_calendar->setSelectedDate(m_dataView->item(row, 1)->data(Qt::UserRole).toDate());
0230     } else {
0231         m_dateInput->setText(QString());
0232         m_dateInput->setPlaceholderText(i18n("Enter a date..."));
0233         m_calendar->setSelectedDate(QDate::currentDate());
0234     }
0235 
0236     m_lastItem = m_dataView->item(row, 0);
0237 }
0238 
0239 QDate Settings::BirthdayPage::parseDate(QString date)
0240 {
0241     QDate parsedDate = QDate();
0242     for (const QString &format : m_dateFormats) {
0243         parsedDate = QDate::fromString(date, format);
0244         if (parsedDate.isValid()) {
0245             return parsedDate;
0246         }
0247     }
0248     return parsedDate;
0249 }
0250 
0251 void Settings::BirthdayPage::checkDateInput(QString date)
0252 {
0253     QDate parsedDate = parseDate(date);
0254     if (parsedDate.isValid() || date.isEmpty()) {
0255         m_calendar->setSelectedDate(parsedDate);
0256         m_dateInput->setPalette(palette());
0257         // re-enable palette propagation:
0258         m_dateInput->setAttribute(Qt::WA_SetPalette);
0259     } else {
0260         auto errorPalette = m_dateInput->palette();
0261         KColorScheme::adjustForeground(errorPalette, KColorScheme::ForegroundRole::NegativeText, QPalette::Text);
0262         KColorScheme::adjustBackground(errorPalette, KColorScheme::BackgroundRole::NegativeBackground, QPalette::Base);
0263         m_dateInput->setPalette(errorPalette);
0264     }
0265 }
0266 
0267 void Settings::BirthdayPage::checkDate()
0268 {
0269     QDate parsedDate = parseDate(m_dateInput->text());
0270     if (parsedDate.isValid()) {
0271         setDate(parsedDate);
0272     }
0273 }
0274 
0275 void Settings::BirthdayPage::setDate(const QDate &date)
0276 {
0277     const QString currentCategory = m_categoryBox->currentText();
0278     if (!m_changedData.contains(currentCategory)) {
0279         m_changedData[currentCategory] = QMap<QString, QDate>();
0280     }
0281 
0282     const QString currentItem = m_dataView->item(m_dataView->currentRow(), 0)->text();
0283     m_changedData[currentCategory][currentItem] = date;
0284 
0285     m_dataView->item(m_dataView->currentRow(), 1)->setText(textForDate(date));
0286     m_dataView->item(m_dataView->currentRow(), 1)->setData(Qt::UserRole, date);
0287 
0288     m_unsetButton->setEnabled(true);
0289 }
0290 
0291 void Settings::BirthdayPage::disableCalendar()
0292 {
0293     m_dateInput->setEnabled(false);
0294     m_calendar->setEnabled(false);
0295     m_unsetButton->setEnabled(false);
0296     m_birthdayOfLabel->setText(i18n("<i>Select an item on the left to edit the birthday</i>"));
0297 }
0298 
0299 void Settings::BirthdayPage::discardChanges()
0300 {
0301     m_changedData.clear();
0302 }
0303 
0304 void Settings::BirthdayPage::saveSettings()
0305 {
0306     QMapIterator<QString, QMap<QString, QDate>> changedCategory(m_changedData);
0307     while (changedCategory.hasNext()) {
0308         changedCategory.next();
0309         DB::CategoryPtr category = DB::ImageDB::instance()->categoryCollection()->categoryForName(changedCategory.key());
0310 
0311         QMapIterator<QString, QDate> changedItem(changedCategory.value());
0312         while (changedItem.hasNext()) {
0313             changedItem.next();
0314             category->setBirthDate(changedItem.key(), changedItem.value());
0315         }
0316     }
0317 
0318     if (m_changedData.size() > 0) {
0319         MainWindow::DirtyIndicator::markDirty();
0320         m_changedData.clear();
0321     }
0322 }
0323 
0324 void Settings::BirthdayPage::removeDate()
0325 {
0326     m_dateInput->setText(QString());
0327     m_calendar->setSelectedDate(QDate::currentDate());
0328     setDate(QDate());
0329 }
0330 
0331 #include "moc_BirthdayPage.cpp"