Baloo Widgets

widgetfactory.cpp
1 /*
2  Copyright (C) 2012-2014 Vishesh Handa <[email protected]>
3 
4  Code largely copied/adapted from KFileMetadataProvider
5  Copyright (C) 2010 by Peter Penz <[email protected]>
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 
22 
23 #include "widgetfactory.h"
24 #include "tagwidget.h"
25 #include "kcommentwidget_p.h"
26 #include "KRatingWidget"
27 
28 #include <KFileMetaData/UserMetaData>
29 #include <KFileMetaData/PropertyInfo>
30 
31 #include <QLabel>
32 #include <QCollator>
33 #include <QTime>
34 #include <QUrl>
35 #include <QLocale>
36 
37 #include <KJob>
38 #include <KFormat>
39 #include <KLocalizedString>
40 #include <KStringHandler>
41 
42 using namespace Baloo;
43 
44 WidgetFactory::WidgetFactory(QObject* parent)
45  : QObject(parent)
46  , m_readOnly( false )
47  , m_dateFormat(QLocale::LongFormat)
48 {
49 }
50 
51 WidgetFactory::~WidgetFactory()
52 {
53 }
54 
55 //
56 // Widget Creation
57 //
58 static QString formatDateTime(const QVariant& value, QLocale::FormatType dateFormat)
59 {
60  const QString valueString = value.toString();
61  QDateTime dt = QDateTime::fromString(valueString, Qt::ISODate);
62 
63  if (dt.isValid()) {
64  KFormat form;
65  QTime time = dt.time();
66  // Check if Date/DateTime
67  if (!time.hour() && !time.minute() && !time.second()){
68  return form.formatRelativeDate(dt.date(), dateFormat);
69  } else {
70  return form.formatRelativeDateTime(dt, dateFormat);
71  }
72  }
73 
74  return valueString;
75 }
76 
77 static QString toString(const QVariant& value, QLocale::FormatType dateFormat)
78 {
79  switch (value.type()) {
80  case QVariant::Int:
81  return QLocale().toString(value.toInt());
82  case QVariant::Double:
83  return QLocale().toString(value.toDouble());
85  return value.toStringList().join(i18nc("String list separator", ", "));
86  case QVariant::Date:
87  case QVariant::DateTime: {
88  return formatDateTime(value, dateFormat);
89  }
90  case QVariant::List: {
92  for (const QVariant& var : value.toList()) {
93  list << toString(var, dateFormat);
94  }
95  return list.join(i18nc("String list separator", ", "));
96  }
97 
98  default:
99  return value.toString();
100  }
101 }
102 
103 QWidget* WidgetFactory::createWidget(const QString& prop, const QVariant& value, QWidget* parent)
104 {
105  QWidget* widget = nullptr;
106  const int maxUrlLength = 80;
107 
108  if (prop == QLatin1String("rating")) {
109  widget = createRatingWidget( value.toInt(), parent );
110  }
111  else if (prop == QLatin1String("userComment")) {
112  widget = createCommentWidget( value.toString(), parent );
113  }
114  else if (prop == QLatin1String("tags")) {
115  QStringList tags = value.toStringList();
116  QCollator coll;
117  coll.setNumericMode(true);
118  std::sort(tags.begin(), tags.end(), [&](const QString& s1, const QString& s2){ return coll.compare(s1, s2) < 0; });
119  widget = createTagWidget( tags, parent );
120  }
121  else {
122  QString valueString;
123  QLabel* valueWidget = createValueWidget(parent);
124 
126  if (pi.name() == QLatin1String("originUrl")) {
127  auto url = value.toUrl();
128  valueString = url.toString();
129  // Shrink link label
130  auto labelString = KStringHandler::csqueeze(valueString, maxUrlLength);
131  valueString = QStringLiteral("<a href=\"%1\">%2</a>").arg(valueString, labelString);
132  valueWidget->setTextFormat(Qt::RichText);
134 
135  } else if (pi.name() != QLatin1String("empty")) {
136  if (pi.valueType() == QVariant::DateTime || pi.valueType() == QVariant::Date) {
137  valueString = formatDateTime(value, m_dateFormat);
138  } else {
139  valueString = pi.formatAsDisplayString(value);
140  }
141  } else {
142  valueString = toString(value, m_dateFormat);
143  }
144 
145  valueWidget->setText(valueString);
146  widget = valueWidget;
147  }
148 
149  widget->setForegroundRole(parent->foregroundRole());
150  widget->setFont(parent->font());
151  widget->setObjectName(prop);
152  return widget;
153 }
154 
155 QWidget* WidgetFactory::createTagWidget(const QStringList& tags, QWidget* parent)
156 {
157  TagWidget* tagWidget = new TagWidget(parent);
158  tagWidget->setReadyOnly(m_readOnly);
159  tagWidget->setSelectedTags(tags);
160 
161  connect(tagWidget, &TagWidget::selectionChanged, this, &WidgetFactory::slotTagsChanged);
162  connect(tagWidget, &TagWidget::tagClicked, this, &WidgetFactory::slotTagClicked);
163 
164  m_tagWidget = tagWidget;
165  m_prevTags = tags;
166 
167  return tagWidget;
168 }
169 
170 QWidget* WidgetFactory::createCommentWidget(const QString& comment, QWidget* parent)
171 {
172  KCommentWidget* commentWidget = new KCommentWidget(parent);
173  commentWidget->setText(comment);
174  commentWidget->setReadOnly(m_readOnly);
175 
176  connect(commentWidget, &KCommentWidget::commentChanged, this, &WidgetFactory::slotCommentChanged);
177 
178  m_commentWidget = commentWidget;
179 
180  return commentWidget;
181 }
182 
183 QWidget* WidgetFactory::createRatingWidget(int rating, QWidget* parent)
184 {
185  KRatingWidget* ratingWidget = new KRatingWidget(parent);
186  const Qt::Alignment align = (ratingWidget->layoutDirection() == Qt::LeftToRight) ?
188  ratingWidget->setAlignment(align);
189  ratingWidget->setRating(rating);
190  const QFontMetrics metrics(parent->font());
191  ratingWidget->setPixmapSize(metrics.height());
192 
193  connect(ratingWidget, static_cast<void (KRatingWidget::*)(uint)>(&KRatingWidget::ratingChanged), this, &WidgetFactory::slotRatingChanged);
194 
195  m_ratingWidget = ratingWidget;
196 
197  return ratingWidget;
198 }
199 
200 
201 // The default size hint of QLabel tries to return a square size.
202 // This does not work well in combination with layouts that use
203 // heightForWidth(): In this case it is possible that the content
204 // of a label might get clipped. By specifying a size hint
205 // with a maximum width that is necessary to contain the whole text,
206 // using heightForWidth() assures having a non-clipped text.
207 class ValueWidget : public QLabel
208 {
209 public:
210  explicit ValueWidget(QWidget* parent = nullptr);
211  QSize sizeHint() const override;
212 };
213 
214 ValueWidget::ValueWidget(QWidget* parent) :
215  QLabel(parent)
216 {
217 }
218 
220 {
221  QFontMetrics metrics(font());
222  // TODO: QLabel internally provides already a method sizeForWidth(),
223  // that would be sufficient. However this method is not accessible.
224  return metrics.size(Qt::TextSingleLine, text());
225 }
226 
227 QLabel* WidgetFactory::createValueWidget(QWidget* parent)
228 {
229  ValueWidget* valueWidget = new ValueWidget(parent);
230  valueWidget->setTextInteractionFlags(Qt::TextSelectableByMouse);
231  valueWidget->setTextFormat(Qt::PlainText);
232  valueWidget->setWordWrap(true);
233  valueWidget->setAlignment(Qt::AlignTop | Qt::AlignLeft);
234  connect(valueWidget, &ValueWidget::linkActivated, this, &WidgetFactory::slotLinkActivated);
235 
236  return valueWidget;
237 }
238 
239 //
240 // Data Synchronization
241 //
242 
243 void WidgetFactory::slotCommentChanged(const QString& comment)
244 {
245  for (const KFileItem& item : qAsConst(m_items)) {
246  QUrl url = item.targetUrl();
247  if (!url.isLocalFile()) {
248  continue;
249  }
250  KFileMetaData::UserMetaData md(url.toLocalFile());
251  md.setUserComment(comment);
252  }
253  Q_EMIT dataChangeStarted();
254  Q_EMIT dataChangeFinished();
255 }
256 
257 void WidgetFactory::slotRatingChanged(uint rating)
258 {
259  for (const KFileItem& item : qAsConst(m_items)) {
260  QUrl url = item.targetUrl();
261  if (!url.isLocalFile()) {
262  continue;
263  }
264  KFileMetaData::UserMetaData md(url.toLocalFile());
265  md.setRating(rating);
266  }
267  Q_EMIT dataChangeStarted();
268  Q_EMIT dataChangeFinished();
269 }
270 
271 void WidgetFactory::slotTagsChanged(const QStringList& tags)
272 {
273  if (m_tagWidget) {
274  for (const KFileItem& item : qAsConst(m_items)) {
275  QUrl url = item.targetUrl();
276  if (!url.isLocalFile()) {
277  continue;
278  }
279  KFileMetaData::UserMetaData md(url.toLocalFile());
280 
281  // When multiple tags are selected one doesn't want to loose the old tags
282  // of any of the resources. Unless specifically removed.
283  QStringList newTags = md.tags() + tags;
284  newTags.removeDuplicates();
285 
286  for (const QString& tag : m_prevTags) {
287  if (!tags.contains(tag)) {
288  newTags.removeAll(tag);
289  }
290  }
291  md.setTags(newTags);
292  }
293 
294  m_prevTags = tags;
295  Q_EMIT dataChangeStarted();
296  Q_EMIT dataChangeFinished();
297  }
298 }
299 
300 //
301 // Notifications
302 //
303 
304 void WidgetFactory::slotLinkActivated(const QString& url)
305 {
306  Q_EMIT urlActivated(QUrl::fromUserInput(url));
307 }
308 
309 void WidgetFactory::slotTagClicked(const QString& tag)
310 {
311  QUrl url;
312  url.setScheme(QStringLiteral("tags"));
313  url.setPath(tag);
314 
315  Q_EMIT urlActivated(url);
316 }
317 
318 
319 //
320 // Accessor Methods
321 //
322 void WidgetFactory::setReadOnly(bool value)
323 {
324  m_readOnly = value;
325 }
326 
327 void WidgetFactory::setItems(const KFileItemList& items)
328 {
329  m_items = items;
330 }
331 
332 Baloo::DateFormats WidgetFactory::dateFormat() const
333 {
334  return static_cast<Baloo::DateFormats>(m_dateFormat);
335 }
336 
337 void Baloo::WidgetFactory::setDateFormat(const Baloo::DateFormats format)
338 {
339  m_dateFormat = static_cast<QLocale::FormatType>(format);
340 }
341 
QUrl toUrl() const const
int minute() const const
void setRating(int rating)
void setAlignment(Qt::Alignment align)
QString toString(qlonglong i) const const
QList< QVariant > toList() const const
int removeDuplicates()
RichText
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
void setPixmapSize(int size)
QTime time() const const
QString join(const QString &separator) const const
void tagClicked(const QString &)
This signal is emitted whenever a tag is clicked.
TagWidget(QWidget *parent=nullptr)
Constructor.
Definition: tagwidget.cpp:114
LeftToRight
QUrl fromUserInput(const QString &userInput)
QPalette::ColorRole foregroundRole() const const
typedef Alignment
int second() const const
void setPath(const QString &path, QUrl::ParsingMode mode)
int toInt(bool *ok) const const
void setReadyOnly(bool readOnly=true)
Set the TagWidget as read only.
Definition: tagwidget.cpp:160
static PropertyInfo fromName(const QString &name)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void setForegroundRole(QPalette::ColorRole role)
void setObjectName(const QString &name)
void setScheme(const QString &scheme)
void setTextFormat(Qt::TextFormat)
KCOREADDONS_EXPORT QString csqueeze(const QString &str, int maxlen=40)
void setText(const QString &)
void ratingChanged(unsigned int rating)
TextBrowserInteraction
Qt::LayoutDirection layoutDirection() const
void setNumericMode(bool on)
QString toLocalFile() const const
int hour() const const
QList::iterator end()
void setFont(const QFont &)
QDateTime fromString(const QString &string, Qt::DateFormat format)
void selectionChanged(const QStringList &tags)
Emitted whenever the selection of tags changes.
virtual QSize sizeHint() const const
bool isValid() const const
Allows to change a selection of tags.
Definition: tagwidget.h:41
void setTextInteractionFlags(Qt::TextInteractionFlags flags)
QString formatRelativeDateTime(const QDateTime &dateTime, QLocale::FormatType format) const
QDate date() const const
QStringList toStringList() const const
char * toString(const T &value)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
TextSingleLine
QString formatRelativeDate(const QDate &date, QLocale::FormatType format) const
double toDouble(bool *ok) const const
int compare(const QString &s1, const QString &s2) const const
QVariant::Type type() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
QString toString() const const
void setSelectedTags(const QStringList &tags)
Set the list of selected tags.
Definition: tagwidget.cpp:150
QList::iterator begin()
Q_EMITQ_EMIT
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
bool isLocalFile() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Thu Oct 21 2021 23:07:11 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.