1 // SPDX-FileCopyrightText: 2012-2020 The KPhotoAlbum Development Team
2 // SPDX-FileCopyrightText: 2021 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
3 //
4 // SPDX-License-Identifier: GPL-2.0-or-later
5
6 #include "Grid.h"
7
8 #include <kpaexif/Info.h>
9
10 #include <kpabase/SettingsData.h>
11
12 #include <QColor>
13 #include <QGridLayout>
14 #include <QLabel>
15 #include <QPainter>
16 #include <QPalette>
17 #include <QResizeEvent>
18 #include <QScrollBar>
19 #include <QTimer>
20
Grid(QWidget * parent)21 Exif::Grid::Grid(QWidget *parent)
22 : QScrollArea(parent)
23 {
24 setFocusPolicy(Qt::WheelFocus);
25 setWidgetResizable(true);
26 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
27 viewport()->installEventFilter(this);
28 setMinimumSize(800, 400);
29 }
30
31 class Background : public QWidget
32 {
33 protected:
paintEvent(QPaintEvent * event)34 void paintEvent(QPaintEvent *event) override
35 {
36 QPainter painter(this);
37 painter.fillRect(event->rect(), QColor(palette().window().color()));
38 }
39 };
40
setupUI(const QString & charset)41 void Exif::Grid::setupUI(const QString &charset)
42 {
43 delete this->widget();
44 m_labels.clear();
45 Background *widget = new Background;
46
47 QGridLayout *layout = new QGridLayout(widget);
48 layout->setSpacing(0);
49 int row = 0;
50
51 const QMap<QString, QStringList> map = Exif::Info::instance()->infoForDialog(m_fileName, charset);
52 const StringSet groups = exifGroups(map);
53
54 for (const QString &group : groups) {
55 layout->addWidget(headerLabel(group), row++, 0, 1, 4);
56
57 // Items of group
58 const QMap<QString, QStringList> items = itemsForGroup(group, map);
59 QStringList sorted = items.keys();
60 sorted.sort();
61 int elements = sorted.size();
62 int perCol = (elements + 1) / 2;
63 int count = 0;
64 for (const QString &key : sorted) {
65 const int subrow = (count % perCol);
66 const QPalette::ColorRole role = (subrow & 1) ? QPalette::Base : QPalette::AlternateBase;
67 QPair<QLabel *, QLabel *> pair = infoLabelPair(exifNameNoGroup(key), items[key].join(QLatin1String(", ")), role);
68
69 int col = (count / perCol) * 2;
70 layout->addWidget(pair.first, row + subrow, col);
71 layout->addWidget(pair.second, row + subrow, col + 1);
72 count++;
73 }
74 row += perCol;
75 }
76
77 setWidget(widget);
78 widget->show();
79 QTimer::singleShot(0, this, SLOT(updateWidgetSize()));
80 }
81
headerLabel(const QString & title)82 QLabel *Exif::Grid::headerLabel(const QString &title)
83 {
84 QLabel *label = new QLabel(title);
85
86 label->setBackgroundRole(QPalette::Dark);
87 label->setForegroundRole(QPalette::BrightText);
88 label->setAutoFillBackground(true);
89 label->setAlignment(Qt::AlignCenter);
90
91 return label;
92 }
93
infoLabelPair(const QString & title,const QString & value,const QPalette::ColorRole backgroundRole)94 QPair<QLabel *, QLabel *> Exif::Grid::infoLabelPair(const QString &title, const QString &value, const QPalette::ColorRole backgroundRole)
95 {
96 QLabel *keyLabel = new QLabel(title);
97 QLabel *valueLabel = new QLabel(value);
98
99 keyLabel->setBackgroundRole(backgroundRole);
100 valueLabel->setBackgroundRole(backgroundRole);
101 keyLabel->setAutoFillBackground(true);
102 valueLabel->setAutoFillBackground(true);
103 m_labels.append(qMakePair(keyLabel, valueLabel));
104 return qMakePair(keyLabel, valueLabel);
105 }
106
updateWidgetSize()107 void Exif::Grid::updateWidgetSize()
108 {
109 widget()->setFixedSize(viewport()->width(), widget()->height());
110 }
111
exifGroups(const QMap<QString,QStringList> & exifInfo)112 StringSet Exif::Grid::exifGroups(const QMap<QString, QStringList> &exifInfo)
113 {
114 StringSet result;
115 for (QMap<QString, QStringList>::ConstIterator it = exifInfo.begin(); it != exifInfo.end(); ++it) {
116 result.insert(groupName(it.key()));
117 }
118 return result;
119 }
120
itemsForGroup(const QString & group,const QMap<QString,QStringList> & exifInfo)121 QMap<QString, QStringList> Exif::Grid::itemsForGroup(const QString &group, const QMap<QString, QStringList> &exifInfo)
122 {
123 QMap<QString, QStringList> result;
124 for (QMap<QString, QStringList>::ConstIterator it = exifInfo.begin(); it != exifInfo.end(); ++it) {
125 if (groupName(it.key()) == group)
126 result.insert(it.key(), it.value());
127 }
128 return result;
129 }
130
groupName(const QString & exifName)131 QString Exif::Grid::groupName(const QString &exifName)
132 {
133 QStringList list = exifName.split(QString::fromLatin1("."));
134 list.pop_back();
135 return list.join(QString::fromLatin1("."));
136 }
137
exifNameNoGroup(const QString & fullName)138 QString Exif::Grid::exifNameNoGroup(const QString &fullName)
139 {
140 return fullName.split(QString::fromLatin1(".")).last();
141 }
142
scroll(int dy)143 void Exif::Grid::scroll(int dy)
144 {
145 verticalScrollBar()->setValue(verticalScrollBar()->value() + dy);
146 }
147
updateSearchString(const QString & search)148 void Exif::Grid::updateSearchString(const QString &search)
149 {
150 for (QPair<QLabel *, QLabel *> tuple : m_labels) {
151 const bool matches = tuple.first->text().contains(search, Qt::CaseInsensitive) && search.length() != 0;
152 const auto fgRole = matches ? QPalette::HighlightedText : QPalette::Text;
153 const auto bgRole = matches ? QPalette::Highlight : QPalette::Base;
154 tuple.first->setForegroundRole(fgRole);
155 tuple.first->setBackgroundRole(bgRole);
156 tuple.second->setForegroundRole(fgRole);
157 tuple.second->setBackgroundRole(bgRole);
158 QFont fnt = tuple.first->font();
159 fnt.setBold(matches);
160 tuple.first->setFont(fnt);
161 tuple.second->setFont(fnt);
162 }
163 }
164
keyPressEvent(QKeyEvent * e)165 void Exif::Grid::keyPressEvent(QKeyEvent *e)
166 {
167 switch (e->key()) {
168 case Qt::Key_Down:
169 scroll(20);
170 return;
171 case Qt::Key_Up:
172 scroll(-20);
173 return;
174 case Qt::Key_PageDown:
175 scroll(viewport()->height() - 20);
176 return;
177 case Qt::Key_PageUp:
178 scroll(-(viewport()->height() - 20));
179 return;
180 case Qt::Key_Escape:
181 QScrollArea::keyPressEvent(e); // Propagate to close dialog.
182 return;
183 }
184 }
185
eventFilter(QObject * object,QEvent * event)186 bool Exif::Grid::eventFilter(QObject *object, QEvent *event)
187 {
188 if (object == viewport() && event->type() == QEvent::Resize) {
189 QResizeEvent *re = static_cast<QResizeEvent *>(event);
190 widget()->setFixedSize(re->size().width(), widget()->height());
191 }
192 return false;
193 }
194
setFileName(const DB::FileName & fileName)195 void Exif::Grid::setFileName(const DB::FileName &fileName)
196 {
197 m_fileName = fileName;
198 setupUI(Settings::SettingsData::instance()->iptcCharset());
199 }
200 // vi:expandtab:tabstop=4 shiftwidth=4:
201