1
// vim: set tabstop=4 shiftwidth=4 noexpandtab:
3
Gwenview: an image viewer
4
Copyright 2008 AurĆ©lien GĆ¢teau <agateau@kde.org>
6
This program is free software; you can redistribute it and/or
7
modify it under the terms of the GNU General Public License
8
as published by the Free Software Foundation; either version 2
9
of the License, or (at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
22
#include "tagwidget.moc"
27
#include <QHBoxLayout>
31
#include <QSortFilterProxyModel>
33
#include <QVBoxLayout>
37
#include <kpushbutton.h>
40
#include <lib/semanticinfo/tagitemdelegate.h>
41
#include <lib/semanticinfo/tagmodel.h>
46
class TagCompleterModel : public QSortFilterProxyModel {
48
TagCompleterModel(QObject* parent)
49
: QSortFilterProxyModel(parent)
54
void setTagInfo(const TagInfo& tagInfo) {
55
mExcludedTagSet.clear();
56
TagInfo::ConstIterator
59
for(; it!=end; ++it) {
61
mExcludedTagSet << it.key();
68
void setSemanticInfoBackEnd(AbstractSemanticInfoBackEnd* backEnd) {
69
setSourceModel(TagModel::createAllTagsModel(this, backEnd));
74
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const {
75
QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent);
76
SemanticInfoTag tag = sourceIndex.data(TagModel::TagRole).toString();
77
return !mExcludedTagSet.contains(tag);
82
TagSet mExcludedTagSet;
87
* A simple class to eat return keys. We use it to avoid propagating the return
88
* key from our KLineEdit to a dialog using TagWidget.
89
* We can't use KLineEdit::setTrapReturnKey() because it does not play well
90
* with QCompleter, it only deals with KCompletion.
92
class ReturnKeyEater : public QObject {
94
ReturnKeyEater(QObject* parent = 0)
99
virtual bool eventFilter(QObject*, QEvent* event) {
100
if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
101
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
102
switch (keyEvent->key()) {
114
struct TagWidgetPrivate {
117
QListView* mListView;
118
QComboBox* mComboBox;
119
KPushButton* mAddButton;
120
AbstractSemanticInfoBackEnd* mBackEnd;
121
TagCompleterModel* mTagCompleterModel;
122
TagModel* mAssignedTagModel;
125
void setupWidgets() {
126
mListView = new QListView;
127
TagItemDelegate* delegate = new TagItemDelegate(mListView);
128
QObject::connect(delegate, SIGNAL(removeTagRequested(const SemanticInfoTag&)),
129
that, SLOT(removeTag(const SemanticInfoTag&)));
130
QObject::connect(delegate, SIGNAL(assignTagToAllRequested(const SemanticInfoTag&)),
131
that, SLOT(assignTag(const SemanticInfoTag&)));
132
mListView->setItemDelegate(delegate);
133
mListView->setModel(mAssignedTagModel);
135
mComboBox = new QComboBox;
136
mComboBox->setEditable(true);
137
mComboBox->setInsertPolicy(QComboBox::NoInsert);
139
mTagCompleterModel = new TagCompleterModel(that);
140
QCompleter* completer = new QCompleter(that);
141
completer->setCaseSensitivity(Qt::CaseInsensitive);
142
completer->setModel(mTagCompleterModel);
143
mComboBox->setCompleter(completer);
145
mComboBox->setModel(mTagCompleterModel);
147
mAddButton = new KPushButton;
148
mAddButton->setIcon(KIcon("list-add"));
149
mAddButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
150
QObject::connect(mAddButton, SIGNAL(clicked()),
151
that, SLOT(addTagFromComboBox()));
153
QVBoxLayout* layout = new QVBoxLayout(that);
154
layout->setMargin(0);
155
layout->addWidget(mListView);
157
QHBoxLayout* hLayout = new QHBoxLayout;
158
hLayout->addWidget(mComboBox);
159
hLayout->addWidget(mAddButton);
160
layout->addLayout(hLayout);
162
that->setTabOrder(mComboBox, mListView);
166
void fillTagModel() {
169
mAssignedTagModel->clear();
170
TagInfo::ConstIterator
171
it = mTagInfo.constBegin(),
172
end = mTagInfo.constEnd();
173
for(; it!=end; ++it) {
174
mAssignedTagModel->addTag(
177
it.value() ? TagModel::FullyAssigned : TagModel::PartiallyAssigned);
182
void updateCompleterModel() {
183
mTagCompleterModel->setTagInfo(mTagInfo);
188
TagWidget::TagWidget(QWidget* parent)
190
, d(new TagWidgetPrivate) {
193
d->mAssignedTagModel = new TagModel(this);
195
installEventFilter(new ReturnKeyEater(this));
197
connect(d->mComboBox->lineEdit(), SIGNAL(returnPressed()),
198
SLOT(addTagFromComboBox()) );
202
TagWidget::~TagWidget() {
207
void TagWidget::setSemanticInfoBackEnd(AbstractSemanticInfoBackEnd* backEnd) {
208
d->mBackEnd = backEnd;
209
d->mAssignedTagModel->setSemanticInfoBackEnd(backEnd);
210
d->mTagCompleterModel->setSemanticInfoBackEnd(backEnd);
214
void TagWidget::setTagInfo(const TagInfo& tagInfo) {
215
d->mTagInfo = tagInfo;
217
d->updateCompleterModel();
221
void TagWidget::addTagFromComboBox() {
222
Q_ASSERT(d->mBackEnd);
223
QString label = d->mComboBox->currentText();
224
if (label.isEmpty()) {
227
assignTag(d->mBackEnd->tagForLabel(label.trimmed()));
229
// Use a QTimer because if the tag is new, it will be inserted in the model
230
// and QComboBox will sometimes select it. At least it does so when the
232
QTimer::singleShot(0, d->mComboBox, SLOT(clearEditText()));
236
void TagWidget::assignTag(const SemanticInfoTag& tag) {
237
d->mTagInfo[tag] = true;
238
d->mAssignedTagModel->addTag(tag);
239
d->updateCompleterModel();
241
emit tagAssigned(tag);
245
void TagWidget::removeTag(const SemanticInfoTag& tag) {
246
d->mTagInfo.remove(tag);
247
d->mAssignedTagModel->removeTag(tag);
248
d->updateCompleterModel();
250
emit tagRemoved(tag);