~ubuntu-branches/ubuntu/trusty/gwenview/trusty

« back to all changes in this revision

Viewing changes to lib/semanticinfo/tagwidget.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Rohan Garg
  • Date: 2011-07-20 13:46:34 UTC
  • Revision ID: james.westby@ubuntu.com-20110720134634-92930fdjeed4gdc9
Tags: upstream-4.6.90+repack
ImportĀ upstreamĀ versionĀ 4.6.90+repack

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// vim: set tabstop=4 shiftwidth=4 noexpandtab:
 
2
/*
 
3
Gwenview: an image viewer
 
4
Copyright 2008 AurĆ©lien GĆ¢teau <agateau@kde.org>
 
5
 
 
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.
 
10
 
 
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.
 
15
 
 
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.
 
19
 
 
20
*/
 
21
// Self
 
22
#include "tagwidget.moc"
 
23
 
 
24
// Qt
 
25
#include <QComboBox>
 
26
#include <QCompleter>
 
27
#include <QHBoxLayout>
 
28
#include <QKeyEvent>
 
29
#include <QLineEdit>
 
30
#include <QListView>
 
31
#include <QSortFilterProxyModel>
 
32
#include <QTimer>
 
33
#include <QVBoxLayout>
 
34
 
 
35
// KDE
 
36
#include <kdebug.h>
 
37
#include <kpushbutton.h>
 
38
 
 
39
// Local
 
40
#include <lib/semanticinfo/tagitemdelegate.h>
 
41
#include <lib/semanticinfo/tagmodel.h>
 
42
 
 
43
namespace Gwenview {
 
44
 
 
45
 
 
46
class TagCompleterModel : public QSortFilterProxyModel {
 
47
public:
 
48
        TagCompleterModel(QObject* parent)
 
49
        : QSortFilterProxyModel(parent)
 
50
        {
 
51
        }
 
52
 
 
53
 
 
54
        void setTagInfo(const TagInfo& tagInfo) {
 
55
                mExcludedTagSet.clear();
 
56
                TagInfo::ConstIterator
 
57
                        it = tagInfo.begin(),
 
58
                        end = tagInfo.end();
 
59
                for(; it!=end; ++it) {
 
60
                        if (it.value()) {
 
61
                                mExcludedTagSet << it.key();
 
62
                        }
 
63
                }
 
64
                invalidate();
 
65
        }
 
66
 
 
67
 
 
68
        void setSemanticInfoBackEnd(AbstractSemanticInfoBackEnd* backEnd) {
 
69
                setSourceModel(TagModel::createAllTagsModel(this, backEnd));
 
70
        }
 
71
 
 
72
 
 
73
protected:
 
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);
 
78
        }
 
79
 
 
80
 
 
81
private:
 
82
        TagSet mExcludedTagSet;
 
83
};
 
84
 
 
85
 
 
86
/**
 
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.
 
91
 */
 
92
class ReturnKeyEater : public QObject {
 
93
public:
 
94
        ReturnKeyEater(QObject* parent = 0)
 
95
        : QObject(parent)
 
96
        {}
 
97
 
 
98
protected:
 
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()) {
 
103
                        case Qt::Key_Return:
 
104
                        case Qt::Key_Enter:
 
105
                                return true;
 
106
                        default:
 
107
                                return false;
 
108
                        }
 
109
                }
 
110
                return false;
 
111
        }
 
112
};
 
113
 
 
114
struct TagWidgetPrivate {
 
115
        TagWidget* that;
 
116
        TagInfo mTagInfo;
 
117
        QListView* mListView;
 
118
        QComboBox* mComboBox;
 
119
        KPushButton* mAddButton;
 
120
        AbstractSemanticInfoBackEnd* mBackEnd;
 
121
        TagCompleterModel* mTagCompleterModel;
 
122
        TagModel* mAssignedTagModel;
 
123
 
 
124
 
 
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);
 
134
 
 
135
                mComboBox = new QComboBox;
 
136
                mComboBox->setEditable(true);
 
137
                mComboBox->setInsertPolicy(QComboBox::NoInsert);
 
138
 
 
139
                mTagCompleterModel = new TagCompleterModel(that);
 
140
                QCompleter* completer = new QCompleter(that);
 
141
                completer->setCaseSensitivity(Qt::CaseInsensitive);
 
142
                completer->setModel(mTagCompleterModel);
 
143
                mComboBox->setCompleter(completer);
 
144
 
 
145
                mComboBox->setModel(mTagCompleterModel);
 
146
 
 
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()));
 
152
 
 
153
                QVBoxLayout* layout = new QVBoxLayout(that);
 
154
                layout->setMargin(0);
 
155
                layout->addWidget(mListView);
 
156
 
 
157
                QHBoxLayout* hLayout = new QHBoxLayout;
 
158
                hLayout->addWidget(mComboBox);
 
159
                hLayout->addWidget(mAddButton);
 
160
                layout->addLayout(hLayout);
 
161
 
 
162
                that->setTabOrder(mComboBox, mListView);
 
163
        }
 
164
 
 
165
 
 
166
        void fillTagModel() {
 
167
                Q_ASSERT(mBackEnd);
 
168
 
 
169
                mAssignedTagModel->clear();
 
170
                TagInfo::ConstIterator
 
171
                        it = mTagInfo.constBegin(),
 
172
                        end = mTagInfo.constEnd();
 
173
                for(; it!=end; ++it) {
 
174
                        mAssignedTagModel->addTag(
 
175
                                it.key(),
 
176
                                QString(),
 
177
                                it.value() ? TagModel::FullyAssigned : TagModel::PartiallyAssigned);
 
178
                }
 
179
        }
 
180
 
 
181
 
 
182
        void updateCompleterModel() {
 
183
                mTagCompleterModel->setTagInfo(mTagInfo);
 
184
        }
 
185
};
 
186
 
 
187
 
 
188
TagWidget::TagWidget(QWidget* parent)
 
189
: QWidget(parent)
 
190
, d(new TagWidgetPrivate) {
 
191
        d->that = this;
 
192
        d->mBackEnd = 0;
 
193
        d->mAssignedTagModel = new TagModel(this);
 
194
        d->setupWidgets();
 
195
        installEventFilter(new ReturnKeyEater(this));
 
196
 
 
197
        connect(d->mComboBox->lineEdit(), SIGNAL(returnPressed()),
 
198
                SLOT(addTagFromComboBox()) );
 
199
}
 
200
 
 
201
 
 
202
TagWidget::~TagWidget() {
 
203
        delete d;
 
204
}
 
205
 
 
206
 
 
207
void TagWidget::setSemanticInfoBackEnd(AbstractSemanticInfoBackEnd* backEnd) {
 
208
        d->mBackEnd = backEnd;
 
209
        d->mAssignedTagModel->setSemanticInfoBackEnd(backEnd);
 
210
        d->mTagCompleterModel->setSemanticInfoBackEnd(backEnd);
 
211
}
 
212
 
 
213
 
 
214
void TagWidget::setTagInfo(const TagInfo& tagInfo) {
 
215
        d->mTagInfo = tagInfo;
 
216
        d->fillTagModel();
 
217
        d->updateCompleterModel();
 
218
}
 
219
 
 
220
 
 
221
void TagWidget::addTagFromComboBox() {
 
222
        Q_ASSERT(d->mBackEnd);
 
223
        QString label = d->mComboBox->currentText();
 
224
        if (label.isEmpty()) {
 
225
                return;
 
226
        }
 
227
        assignTag(d->mBackEnd->tagForLabel(label.trimmed()));
 
228
 
 
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
 
231
        // model is empty.
 
232
        QTimer::singleShot(0, d->mComboBox, SLOT(clearEditText()));
 
233
}
 
234
 
 
235
 
 
236
void TagWidget::assignTag(const SemanticInfoTag& tag) {
 
237
        d->mTagInfo[tag] = true;
 
238
        d->mAssignedTagModel->addTag(tag);
 
239
        d->updateCompleterModel();
 
240
 
 
241
        emit tagAssigned(tag);
 
242
}
 
243
 
 
244
 
 
245
void TagWidget::removeTag(const SemanticInfoTag& tag) {
 
246
        d->mTagInfo.remove(tag);
 
247
        d->mAssignedTagModel->removeTag(tag);
 
248
        d->updateCompleterModel();
 
249
 
 
250
        emit tagRemoved(tag);
 
251
}
 
252
 
 
253
 
 
254
} // namespace