Baloo Widgets

kedittagsdialog.cpp
1 /*****************************************************************************
2  * Copyright (C) 2009 by Peter Penz <[email protected]> *
3  * Copyright (C) 2014 by Vishesh Handa <[email protected]> *
4  * Copyright (C) 2017 by James D. Smith <[email protected] *
5  * *
6  * This library is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Library General Public *
8  * License version 2 as published by the Free Software Foundation. *
9  * *
10  * This library is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
13  * Library General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU Library General Public License *
16  * along with this library; see the file COPYING.LIB. If not, write to *
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
18  * Boston, MA 02110-1301, USA. *
19  *****************************************************************************/
20 
21 #include "kedittagsdialog_p.h"
22 
23 #include <KLocalizedString>
24 
25 #include <QLineEdit>
26 #include <QHBoxLayout>
27 #include <QLabel>
28 #include <QTreeWidget>
29 #include <QPushButton>
30 #include <QTimer>
31 #include <QVBoxLayout>
32 #include <QWidget>
33 #include <QUrl>
34 #include <QDialogButtonBox>
35 #include <QDebug>
36 
37 #include <Baloo/TagListJob>
38 
39 KEditTagsDialog::KEditTagsDialog(const QStringList& tags,
40  QWidget *parent) :
41  QDialog(parent),
42  m_tags(tags),
43  m_tagTree(nullptr),
44  m_newTagEdit(nullptr)
45 {
46  const QString captionText = (tags.count() > 0) ?
47  i18nc("@title:window", "Edit Tags") :
48  i18nc("@title:window", "Add Tags");
49  setWindowTitle(captionText);
50  QDialogButtonBox* buttonBox = new QDialogButtonBox(this);
51 
52  buttonBox->addButton(i18n("Save"), QDialogButtonBox::AcceptRole);
54 
55  connect(buttonBox, &QDialogButtonBox::accepted, this, &KEditTagsDialog::slotAcceptedButtonClicked);
57 
58  QVBoxLayout* topLayout = new QVBoxLayout;
59  setLayout(topLayout);
60 
61  QLabel* label = new QLabel(i18nc("@label:textbox",
62  "Configure which tags should "
63  "be applied."), this);
64 
65  m_tagTree = new QTreeWidget();
66  m_tagTree->setSortingEnabled(true);
67  m_tagTree->setSelectionMode(QAbstractItemView::NoSelection);
68  m_tagTree->setHeaderHidden(true);
69 
70  QLabel* newTagLabel = new QLabel(i18nc("@label", "Create new tag:"));
71  m_newTagEdit = new QLineEdit(this);
72  m_newTagEdit->setClearButtonEnabled(true);
73  m_newTagEdit->setFocus();
74  connect(m_newTagEdit, &QLineEdit::textEdited, this, &KEditTagsDialog::slotTextEdited);
75  connect(m_tagTree, &QTreeWidget::itemActivated, this, &KEditTagsDialog::slotItemActivated);
76 
77  QHBoxLayout* newTagLayout = new QHBoxLayout();
78  newTagLayout->addWidget(newTagLabel);
79  newTagLayout->addWidget(m_newTagEdit, 1);
80 
81  topLayout->addWidget(label);
82  topLayout->addWidget(m_tagTree);
83  topLayout->addLayout(newTagLayout);
84  topLayout->addWidget(buttonBox);
85 
86  resize(sizeHint());
87 
88  Baloo::TagListJob* job = new Baloo::TagListJob();
89  connect(job, &Baloo::TagListJob::finished, [this] (KJob* job) {
90  Baloo::TagListJob* tjob = static_cast<Baloo::TagListJob*>(job);
91  m_allTags = tjob->tags();
92  loadTagWidget();
93  });
94 
95  job->start();
96 }
97 
98 KEditTagsDialog::~KEditTagsDialog()
99 {
100 }
101 
102 QStringList KEditTagsDialog::tags() const
103 {
104  return m_tags;
105 }
106 
107 void KEditTagsDialog::slotAcceptedButtonClicked()
108 {
109  m_tags.clear();
110 
111  for (const QTreeWidgetItem* item : m_allTagTreeItems.values()) {
112  if (item->checkState(0) == Qt::Checked) {
113  m_tags << qvariant_cast<QString>(item->data(0, Qt::UserRole));
114  }
115  }
116 
117  accept();
118 }
119 
120 void KEditTagsDialog::slotItemActivated(const QTreeWidgetItem* item, int column)
121 {
122  Q_UNUSED(column)
123 
124  const QString tag = qvariant_cast<QString>(item->data(0, Qt::UserRole));
125  m_newTagEdit->setText(tag + QLatin1Char('/'));
126  m_newTagEdit->setFocus();
127 }
128 
129 void KEditTagsDialog::slotTextEdited(const QString& text)
130 {
131  // Remove unnecessary spaces from a new tag is
132  // mandatory, as the user cannot see the difference
133  // between a tag "Test" and "Test ".
134  QString tagText = text.simplified();
135  while (tagText.endsWith(QLatin1String("//"))) {
136  tagText.chop(1);
137  m_newTagEdit->setText(tagText);
138  return;
139  }
140 
141  // Remove all tree items related to the previous new tag
142  const QStringList splitTag = m_newTag.split(QLatin1Char('/'), QString::SkipEmptyParts);
143  for (int i = splitTag.size() - 1; i >= 0 && i < splitTag.size(); --i) {
144  QString itemTag = m_newTag.section(QLatin1Char('/'), 0, i, QString::SectionSkipEmpty);
145  QTreeWidgetItem* item = m_allTagTreeItems.value(itemTag);
146 
147  if (!m_allTags.contains(m_newTag) && (item->childCount() == 0)) {
148  if (i != 0) {
149  QTreeWidgetItem* parentItem = item->parent();
150  parentItem->removeChild(item);
151  } else {
152  const int row = m_tagTree->indexOfTopLevelItem(item);
153  m_tagTree->takeTopLevelItem(row);
154  }
155 
156  m_allTagTreeItems.remove(itemTag);
157  }
158 
159  if (!m_tags.contains(itemTag)) {
160  item->setCheckState(0, Qt::Unchecked);
161  }
162 
163  item->setExpanded(false);
164  }
165 
166  if (!tagText.isEmpty()) {
167  m_newTag = tagText;
168  modifyTagWidget(tagText);
169  m_tagTree->sortItems(0, Qt::SortOrder::AscendingOrder);
170  } else {
171  m_newTag.clear();
172  m_allTagTreeItems.clear();
173  m_tagTree->clear();
174  loadTagWidget();
175  }
176 }
177 
178 void KEditTagsDialog::loadTagWidget()
179 {
180  for (const QString &tag : m_tags) {
181  modifyTagWidget(tag);
182  }
183 
184  for (const QString &tag : m_allTags) {
185  modifyTagWidget(tag);
186  }
187 
188  m_tagTree->sortItems(0, Qt::SortOrder::AscendingOrder);
189 }
190 
191 void KEditTagsDialog::modifyTagWidget(const QString &tag)
192 {
193  const QStringList splitTag = tag.split(QLatin1Char('/'), QString::SkipEmptyParts);
194  for (int i = 0; i < splitTag.size(); ++i) {
195  QTreeWidgetItem* item = new QTreeWidgetItem();
196  QString itemTag = tag.section(QLatin1Char('/'), 0, i, QString::SectionSkipEmpty);
197 
198  if (!m_allTagTreeItems.contains(itemTag)) {
199  item->setText(0, splitTag.at(i));
200  item->setIcon(0, QIcon::fromTheme(QLatin1String("tag")));
201  item->setData(0, Qt::UserRole, itemTag);
202  m_allTagTreeItems.insert(itemTag, item);
203  QString parentTag = tag.section(QLatin1Char('/'), 0, (i - 1), QString::SectionSkipEmpty);
204  QTreeWidgetItem* parentItem = m_allTagTreeItems.value(parentTag);
205 
206  if (i != 0) {
207  parentItem->addChild(item);
208  } else {
209  m_tagTree->addTopLevelItem(item);
210  }
211  } else {
212  item = m_allTagTreeItems.value(itemTag);
213  }
214 
215  if (!m_allTags.contains(tag)) {
216  m_tagTree->scrollToItem(item, QAbstractItemView::PositionAtCenter);
217  }
218 
219  if (((item->childCount() != 0) && m_tags.contains(tag)) || (m_newTag == tag)) {
220  item->setExpanded(true);
221  } else if (item->parent() && m_tags.contains(tag)) {
222  item->parent()->setExpanded(true);
223  }
224 
225  const bool check = (m_tags.contains(itemTag) || (m_newTag == itemTag));
226  item->setCheckState(0, check ? Qt::Checked : Qt::Unchecked);
227  }
228 }
void clear()
void itemActivated(QTreeWidgetItem *item, int column)
virtual void reject()
void addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role)
const T & at(int i) const const
void setIcon(int column, const QIcon &icon)
QString simplified() const const
virtual void setData(int column, int role, const QVariant &value)
void chop(int n)
int size() const const
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
int count(const T &value) const const
void removeChild(QTreeWidgetItem *child)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString label(StandardShortcut id)
UserRole
bool isEmpty() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
void addChild(QTreeWidgetItem *child)
void textEdited(const QString &text)
QTreeWidgetItem * parent() const const
QString i18n(const char *text, const TYPE &arg...)
void setExpanded(bool expand)
void setCheckState(int column, Qt::CheckState state)
virtual Q_SCRIPTABLE void start()=0
void setText(int column, const QString &text)
QString section(QChar sep, int start, int end, QString::SectionFlags flags) const const
QIcon fromTheme(const QString &name)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int childCount() const const
void addLayout(QLayout *layout, int stretch)
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.