~ubuntu-branches/ubuntu/precise/gwenview/precise-proposed

« back to all changes in this revision

Viewing changes to app/semanticinfocontextmanageritem.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2011-12-15 14:17:54 UTC
  • mto: This revision was merged to the branch mainline in revision 12.
  • Revision ID: package-import@ubuntu.com-20111215141754-z043hyx69dulbggf
Tags: upstream-4.7.90
ImportĀ upstreamĀ versionĀ 4.7.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// vim: set tabstop=4 shiftwidth=4 noexpandtab:
 
1
// vim: set tabstop=4 shiftwidth=4 expandtab:
2
2
/*
3
3
Gwenview: an image viewer
4
4
Copyright 2008 AurĆ©lien GĆ¢teau <agateau@kde.org>
41
41
 
42
42
// Local
43
43
#include "contextmanager.h"
44
 
#include "documentpanel.h"
 
44
#include "viewmainpage.h"
45
45
#include "sidebar.h"
46
46
#include "ui_semanticinfosidebaritem.h"
47
47
#include "ui_semanticinfodialog.h"
54
54
#include <lib/semanticinfo/semanticinfodirmodel.h>
55
55
#include <lib/semanticinfo/sorteddirmodel.h>
56
56
 
57
 
namespace Gwenview {
 
57
namespace Gwenview
 
58
{
58
59
 
59
60
static const int RATING_INDICATOR_HIDE_DELAY = 3000;
60
61
 
61
 
 
62
62
struct SemanticInfoDialog : public KDialog, public Ui_SemanticInfoDialog {
63
 
        SemanticInfoDialog(QWidget* parent)
64
 
        : KDialog(parent) {
65
 
                setButtons(None);
66
 
                QWidget* mainWidget = new QWidget;
67
 
                setMainWidget(mainWidget);
68
 
                setupUi(mainWidget);
69
 
                mainWidget->layout()->setMargin(0);
70
 
                setWindowTitle(mainWidget->windowTitle());
71
 
 
72
 
                restoreDialogSize(configGroup());
73
 
        }
74
 
 
75
 
        ~SemanticInfoDialog() {
76
 
                KConfigGroup group = configGroup();
77
 
                saveDialogSize(group);
78
 
        }
79
 
 
80
 
        KConfigGroup configGroup() const {
81
 
                KSharedConfigPtr config = KGlobal::config();
82
 
                return KConfigGroup(config, "SemanticInfoDialog");
83
 
        }
 
63
    SemanticInfoDialog(QWidget* parent)
 
64
        : KDialog(parent) {
 
65
        setButtons(None);
 
66
        QWidget* mainWidget = new QWidget;
 
67
        setMainWidget(mainWidget);
 
68
        setupUi(mainWidget);
 
69
        mainWidget->layout()->setMargin(0);
 
70
        setWindowTitle(mainWidget->windowTitle());
 
71
 
 
72
        restoreDialogSize(configGroup());
 
73
    }
 
74
 
 
75
    ~SemanticInfoDialog() {
 
76
        KConfigGroup group = configGroup();
 
77
        saveDialogSize(group);
 
78
    }
 
79
 
 
80
    KConfigGroup configGroup() const {
 
81
        KSharedConfigPtr config = KGlobal::config();
 
82
        return KConfigGroup(config, "SemanticInfoDialog");
 
83
    }
84
84
};
85
85
 
86
 
 
87
 
class RatingIndicator : public HudWidget {
 
86
class RatingIndicator : public HudWidget
 
87
{
88
88
public:
89
 
        RatingIndicator(QWidget* parent)
90
 
        : HudWidget(parent)
91
 
        , mRatingWidget(new KRatingWidget)
92
 
        , mHideTimer(new QTimer(this))
93
 
        {
94
 
                init(mRatingWidget, OptionNone);
95
 
                WidgetFloater* floater = new WidgetFloater(parent);
96
 
                floater->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
97
 
                floater->setVerticalMargin(
98
 
                        KDialog::marginHint()
99
 
                        + parent->style()->pixelMetric(QStyle::PM_ScrollBarExtent)
100
 
                        );
101
 
                floater->setChildWidget(this);
102
 
 
103
 
                mHideTimer->setInterval(RATING_INDICATOR_HIDE_DELAY);
104
 
                mHideTimer->setSingleShot(true);
105
 
                connect(mHideTimer, SIGNAL(timeout()), SLOT(deleteLater()));
106
 
                hide();
107
 
        }
108
 
 
109
 
        void setRating(int rating) {
110
 
                mRatingWidget->setRating(rating);
111
 
        }
112
 
 
113
 
        void show() {
114
 
                HudWidget::show();
115
 
                raise();
116
 
                mHideTimer->start();
117
 
        }
 
89
    RatingIndicator(QWidget* parent)
 
90
        : HudWidget(parent)
 
91
        , mRatingWidget(new KRatingWidget)
 
92
        , mHideTimer(new QTimer(this)) {
 
93
        init(mRatingWidget, OptionNone);
 
94
        WidgetFloater* floater = new WidgetFloater(parent);
 
95
        floater->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
 
96
        floater->setVerticalMargin(
 
97
            KDialog::marginHint()
 
98
            + parent->style()->pixelMetric(QStyle::PM_ScrollBarExtent)
 
99
        );
 
100
        floater->setChildWidget(this);
 
101
 
 
102
        mHideTimer->setInterval(RATING_INDICATOR_HIDE_DELAY);
 
103
        mHideTimer->setSingleShot(true);
 
104
        connect(mHideTimer, SIGNAL(timeout()), SLOT(deleteLater()));
 
105
        hide();
 
106
    }
 
107
 
 
108
    void setRating(int rating)
 
109
    {
 
110
        mRatingWidget->setRating(rating);
 
111
    }
 
112
 
 
113
    void show()
 
114
    {
 
115
        HudWidget::show();
 
116
        raise();
 
117
        mHideTimer->start();
 
118
    }
118
119
 
119
120
private:
120
 
        KRatingWidget* mRatingWidget;
121
 
        QTimer* mHideTimer;
 
121
    KRatingWidget* mRatingWidget;
 
122
    QTimer* mHideTimer;
122
123
};
123
124
 
124
 
 
125
125
struct SemanticInfoContextManagerItemPrivate : public Ui_SemanticInfoSideBarItem {
126
 
        SemanticInfoContextManagerItem* that;
127
 
        SideBarGroup* mGroup;
128
 
        KActionCollection* mActionCollection;
129
 
        DocumentPanel* mDocumentPanel;
130
 
        QPointer<SemanticInfoDialog> mSemanticInfoDialog;
131
 
        TagInfo mTagInfo;
132
 
        KAction* mEditTagsAction;
133
 
        QSignalMapper* mRatingMapper;
134
 
        /** A list of all actions, so that we can disable them when necessary */
135
 
        QList<KAction*> mActions;
136
 
        QPointer<RatingIndicator> mRatingIndicator;
137
 
 
138
 
        void setupGroup() {
139
 
                mGroup = new SideBarGroup(i18n("Semantic Information"));
140
 
                that->setWidget(mGroup);
141
 
                EventWatcher::install(mGroup, QEvent::Show, that, SLOT(update()));
142
 
 
143
 
                QWidget* container = new QWidget;
144
 
                setupUi(container);
145
 
                container->layout()->setMargin(0);
146
 
                mGroup->addWidget(container);
147
 
 
148
 
                QObject::connect(mRatingWidget, SIGNAL(ratingChanged(int)),
149
 
                        that, SLOT(slotRatingChanged(int)));
150
 
                QObject::connect(mRatingMapper, SIGNAL(mapped(int)),
151
 
                        mRatingWidget, SLOT(setRating(int)) );
152
 
 
153
 
                mDescriptionTextEdit->installEventFilter(that);
154
 
 
155
 
                QObject::connect(mTagLabel, SIGNAL(linkActivated(const QString&)),
156
 
                        mEditTagsAction, SLOT(trigger()) );
157
 
        }
158
 
 
159
 
 
160
 
        void setupActions() {
161
 
                KActionCategory* edit = new KActionCategory(i18nc("@title actions category","Edit"), mActionCollection);
162
 
 
163
 
                mEditTagsAction = edit->addAction("edit_tags");
164
 
                mEditTagsAction->setText(i18nc("@action", "Edit Tags"));
165
 
                mEditTagsAction->setShortcut(Qt::CTRL | Qt::Key_T);
166
 
                QObject::connect(mEditTagsAction, SIGNAL(triggered()),
167
 
                        that, SLOT(showSemanticInfoDialog()) );
168
 
                mActions << mEditTagsAction;
169
 
 
170
 
                mRatingMapper = new QSignalMapper(that);
171
 
                for (int rating=0; rating <= 5; ++rating) {
172
 
                        KAction* action = edit->addAction(QString("rate_%1").arg(rating));
173
 
                        if (rating == 0) {
174
 
                                action->setText(i18nc("@action Rating value of zero", "Zero"));
175
 
                        } else {
176
 
                                action->setText(QString(rating, QChar(0x22C6))); /* 0x22C6 is the 'star' character */
177
 
                        }
178
 
                        action->setShortcut(Qt::Key_0 + rating);
179
 
                        QObject::connect(action, SIGNAL(triggered()), mRatingMapper, SLOT(map()) );
180
 
                        mRatingMapper->setMapping(action, rating * 2);
181
 
                        mActions << action;
182
 
                }
183
 
                QObject::connect(mRatingMapper, SIGNAL(mapped(int)), that, SLOT(slotRatingChanged(int)) );
184
 
        }
185
 
 
186
 
 
187
 
        void updateTagLabel() {
188
 
                if (that->contextManager()->selectedFileItemList().isEmpty()) {
189
 
                        mTagLabel->clear();
190
 
                        return;
191
 
                }
192
 
 
193
 
                AbstractSemanticInfoBackEnd* backEnd = that->contextManager()->dirModel()->semanticInfoBackEnd();
194
 
 
195
 
                TagInfo::ConstIterator
196
 
                        it = mTagInfo.constBegin(),
197
 
                        end = mTagInfo.constEnd();
198
 
                QMap<QString, QString> labelMap;
199
 
                for (; it!=end; ++it) {
200
 
                        SemanticInfoTag tag = it.key();
201
 
                        QString label = backEnd->labelForTag(tag);
202
 
                        if (!it.value()) {
203
 
                                // Tag is not present for all urls
204
 
                                label += '*';
205
 
                        }
206
 
                        labelMap[label.toLower()] = label;
207
 
                }
208
 
                QStringList labels(labelMap.values());
209
 
 
210
 
                QString editLink = i18n("Edit");
211
 
                QString text = labels.join(", ") + QString(" <a href='edit'>%1</a>").arg(editLink);
212
 
                mTagLabel->setText(text);
213
 
        }
214
 
 
215
 
 
216
 
        void updateSemanticInfoDialog() {
217
 
                mSemanticInfoDialog->mTagWidget->setEnabled(!that->contextManager()->selectedFileItemList().isEmpty());
218
 
                mSemanticInfoDialog->mTagWidget->setTagInfo(mTagInfo);
219
 
        }
 
126
    SemanticInfoContextManagerItem* q;
 
127
    SideBarGroup* mGroup;
 
128
    KActionCollection* mActionCollection;
 
129
    ViewMainPage* mViewMainPage;
 
130
    QPointer<SemanticInfoDialog> mSemanticInfoDialog;
 
131
    TagInfo mTagInfo;
 
132
    KAction* mEditTagsAction;
 
133
    QSignalMapper* mRatingMapper;
 
134
    /** A list of all actions, so that we can disable them when necessary */
 
135
    QList<KAction*> mActions;
 
136
    QPointer<RatingIndicator> mRatingIndicator;
 
137
 
 
138
    void setupGroup()
 
139
    {
 
140
        mGroup = new SideBarGroup(i18n("Semantic Information"));
 
141
        q->setWidget(mGroup);
 
142
        EventWatcher::install(mGroup, QEvent::Show, q, SLOT(update()));
 
143
 
 
144
        QWidget* container = new QWidget;
 
145
        setupUi(container);
 
146
        container->layout()->setMargin(0);
 
147
        mGroup->addWidget(container);
 
148
 
 
149
        QObject::connect(mRatingWidget, SIGNAL(ratingChanged(int)),
 
150
                         q, SLOT(slotRatingChanged(int)));
 
151
        QObject::connect(mRatingMapper, SIGNAL(mapped(int)),
 
152
                         mRatingWidget, SLOT(setRating(int)));
 
153
 
 
154
        mDescriptionTextEdit->installEventFilter(q);
 
155
 
 
156
        QObject::connect(mTagLabel, SIGNAL(linkActivated(QString)),
 
157
                         mEditTagsAction, SLOT(trigger()));
 
158
    }
 
159
 
 
160
    void setupActions()
 
161
    {
 
162
        KActionCategory* edit = new KActionCategory(i18nc("@title actions category", "Edit"), mActionCollection);
 
163
 
 
164
        mEditTagsAction = edit->addAction("edit_tags");
 
165
        mEditTagsAction->setText(i18nc("@action", "Edit Tags"));
 
166
        mEditTagsAction->setShortcut(Qt::CTRL | Qt::Key_T);
 
167
        QObject::connect(mEditTagsAction, SIGNAL(triggered()),
 
168
                         q, SLOT(showSemanticInfoDialog()));
 
169
        mActions << mEditTagsAction;
 
170
 
 
171
        mRatingMapper = new QSignalMapper(q);
 
172
        for (int rating = 0; rating <= 5; ++rating) {
 
173
            KAction* action = edit->addAction(QString("rate_%1").arg(rating));
 
174
            if (rating == 0) {
 
175
                action->setText(i18nc("@action Rating value of zero", "Zero"));
 
176
            } else {
 
177
                action->setText(QString(rating, QChar(0x22C6))); /* 0x22C6 is the 'star' character */
 
178
            }
 
179
            action->setShortcut(Qt::Key_0 + rating);
 
180
            QObject::connect(action, SIGNAL(triggered()), mRatingMapper, SLOT(map()));
 
181
            mRatingMapper->setMapping(action, rating * 2);
 
182
            mActions << action;
 
183
        }
 
184
        QObject::connect(mRatingMapper, SIGNAL(mapped(int)), q, SLOT(slotRatingChanged(int)));
 
185
    }
 
186
 
 
187
    void updateTagLabel()
 
188
    {
 
189
        if (q->contextManager()->selectedFileItemList().isEmpty()) {
 
190
            mTagLabel->clear();
 
191
            return;
 
192
        }
 
193
 
 
194
        AbstractSemanticInfoBackEnd* backEnd = q->contextManager()->dirModel()->semanticInfoBackEnd();
 
195
 
 
196
        TagInfo::ConstIterator
 
197
        it = mTagInfo.constBegin(),
 
198
        end = mTagInfo.constEnd();
 
199
        QMap<QString, QString> labelMap;
 
200
        for (; it != end; ++it) {
 
201
            SemanticInfoTag tag = it.key();
 
202
            QString label = backEnd->labelForTag(tag);
 
203
            if (!it.value()) {
 
204
                // Tag is not present for all urls
 
205
                label += '*';
 
206
            }
 
207
            labelMap[label.toLower()] = label;
 
208
        }
 
209
        QStringList labels(labelMap.values());
 
210
 
 
211
        QString editLink = i18n("Edit");
 
212
        QString text = labels.join(", ") + QString(" <a href='edit'>%1</a>").arg(editLink);
 
213
        mTagLabel->setText(text);
 
214
    }
 
215
 
 
216
    void updateSemanticInfoDialog()
 
217
    {
 
218
        mSemanticInfoDialog->mTagWidget->setEnabled(!q->contextManager()->selectedFileItemList().isEmpty());
 
219
        mSemanticInfoDialog->mTagWidget->setTagInfo(mTagInfo);
 
220
    }
220
221
};
221
222
 
222
 
 
223
 
SemanticInfoContextManagerItem::SemanticInfoContextManagerItem(ContextManager* manager, KActionCollection* actionCollection, DocumentPanel* documentPanel)
 
223
SemanticInfoContextManagerItem::SemanticInfoContextManagerItem(ContextManager* manager, KActionCollection* actionCollection, ViewMainPage* documentPanel)
224
224
: AbstractContextManagerItem(manager)
225
 
, d(new SemanticInfoContextManagerItemPrivate) {
226
 
        d->that = this;
227
 
        d->mActionCollection = actionCollection;
228
 
        d->mDocumentPanel = documentPanel;
229
 
 
230
 
        connect(contextManager(), SIGNAL(selectionChanged()),
231
 
                SLOT(slotSelectionChanged()) );
232
 
        connect(contextManager(), SIGNAL(selectionDataChanged()),
233
 
                SLOT(update()) );
234
 
        connect(contextManager(), SIGNAL(currentDirUrlChanged()),
235
 
                SLOT(update()) );
236
 
 
237
 
        d->setupActions();
238
 
        d->setupGroup();
239
 
}
240
 
 
241
 
 
242
 
SemanticInfoContextManagerItem::~SemanticInfoContextManagerItem() {
243
 
        delete d;
244
 
}
245
 
 
246
 
 
247
 
inline int ratingForVariant(const QVariant& variant) {
248
 
        if (variant.isValid()) {
249
 
                return variant.toInt();
250
 
        } else {
251
 
                return 0;
252
 
        }
253
 
}
254
 
 
255
 
 
256
 
void SemanticInfoContextManagerItem::slotSelectionChanged() {
257
 
        if (d->mRatingIndicator) {
258
 
                d->mRatingIndicator->deleteLater();
259
 
        }
260
 
        update();
261
 
}
262
 
 
263
 
 
264
 
void SemanticInfoContextManagerItem::update() {
265
 
        KFileItemList itemList = contextManager()->selectedFileItemList();
266
 
 
267
 
        bool first = true;
268
 
        int rating = 0;
269
 
        QString description;
270
 
        SortedDirModel* dirModel = contextManager()->dirModel();
271
 
 
272
 
        // This hash stores for how many items the tag is present
273
 
        // If you have 3 items, and only 2 have the "Holiday" tag,
274
 
        // then tagHash["Holiday"] will be 2 at the end of the loop.
275
 
        typedef QHash<QString, int> TagHash;
276
 
        TagHash tagHash;
277
 
 
278
 
        Q_FOREACH(const KFileItem& item, itemList) {
279
 
                QModelIndex index = dirModel->indexForItem(item);
280
 
 
281
 
                QVariant value = dirModel->data(index, SemanticInfoDirModel::RatingRole);
282
 
                if (first) {
283
 
                        rating = ratingForVariant(value);
284
 
                } else if (rating != ratingForVariant(value)) {
285
 
                        // Ratings aren't the same, reset
286
 
                        rating = 0;
287
 
                }
288
 
 
289
 
                QString indexDescription = index.data(SemanticInfoDirModel::DescriptionRole).toString();
290
 
                if (first) {
291
 
                        description = indexDescription;
292
 
                } else if (description != indexDescription) {
293
 
                        description.clear();
294
 
                }
295
 
 
296
 
                // Fill tagHash, incrementing the tag count if it's already there
297
 
                TagSet tagSet = TagSet::fromVariant(index.data(SemanticInfoDirModel::TagsRole));
298
 
                Q_FOREACH(const QString& tag, tagSet) {
299
 
                        TagHash::Iterator it = tagHash.find(tag);
300
 
                        if (it == tagHash.end()) {
301
 
                                tagHash[tag] = 1;
302
 
                        } else {
303
 
                                ++it.value();
304
 
                        }
305
 
                }
306
 
 
307
 
                first = false;
308
 
        }
309
 
        {
310
 
                SignalBlocker blocker(d->mRatingWidget);
311
 
                d->mRatingWidget->setRating(rating);
312
 
        }
313
 
        d->mDescriptionTextEdit->setText(description);
314
 
 
315
 
        // Init tagInfo from tagHash
316
 
        d->mTagInfo.clear();
317
 
        int itemCount = itemList.count();
318
 
        TagHash::ConstIterator
319
 
                it = tagHash.constBegin(),
320
 
                end = tagHash.constEnd();
321
 
        for (; it!=end; ++it) {
322
 
                QString tag = it.key();
323
 
                int count = it.value();
324
 
                d->mTagInfo[tag] = count == itemCount;
325
 
        }
326
 
 
327
 
        bool enabled = !contextManager()->selectedFileItemList().isEmpty();
328
 
        Q_FOREACH(KAction* action, d->mActions) {
329
 
                action->setEnabled(enabled);
330
 
        }
331
 
        d->updateTagLabel();
332
 
        if (d->mSemanticInfoDialog) {
333
 
                d->updateSemanticInfoDialog();
334
 
        }
335
 
}
336
 
 
337
 
 
338
 
void SemanticInfoContextManagerItem::slotRatingChanged(int rating) {
339
 
        KFileItemList itemList = contextManager()->selectedFileItemList();
340
 
 
341
 
        // Show rating indicator in view mode, and only if sidebar is not visible
342
 
        if (d->mDocumentPanel->isVisible() && !d->mRatingWidget->isVisible()) {
343
 
                delete d->mRatingIndicator.data();
344
 
                d->mRatingIndicator = new RatingIndicator(d->mDocumentPanel->documentView());
345
 
                d->mRatingIndicator->setRating(rating);
346
 
                d->mRatingIndicator->show();
347
 
        }
348
 
 
349
 
        SortedDirModel* dirModel = contextManager()->dirModel();
350
 
        Q_FOREACH(const KFileItem& item, itemList) {
351
 
                QModelIndex index = dirModel->indexForItem(item);
352
 
                dirModel->setData(index, rating, SemanticInfoDirModel::RatingRole);
353
 
        }
354
 
}
355
 
 
356
 
 
357
 
void SemanticInfoContextManagerItem::storeDescription() {
358
 
        if (!d->mDescriptionTextEdit->document()->isModified()) {
359
 
                return;
360
 
        }
361
 
        d->mDescriptionTextEdit->document()->setModified(false);
362
 
        QString description = d->mDescriptionTextEdit->toPlainText();
363
 
        KFileItemList itemList = contextManager()->selectedFileItemList();
364
 
 
365
 
        SortedDirModel* dirModel = contextManager()->dirModel();
366
 
        Q_FOREACH(const KFileItem& item, itemList) {
367
 
                QModelIndex index = dirModel->indexForItem(item);
368
 
                dirModel->setData(index, description, SemanticInfoDirModel::DescriptionRole);
369
 
        }
370
 
}
371
 
 
372
 
 
373
 
void SemanticInfoContextManagerItem::assignTag(const SemanticInfoTag& tag) {
374
 
        KFileItemList itemList = contextManager()->selectedFileItemList();
375
 
 
376
 
        SortedDirModel* dirModel = contextManager()->dirModel();
377
 
        Q_FOREACH(const KFileItem& item, itemList) {
378
 
                QModelIndex index = dirModel->indexForItem(item);
379
 
                TagSet tags = TagSet::fromVariant( dirModel->data(index, SemanticInfoDirModel::TagsRole) );
380
 
                if (!tags.contains(tag)) {
381
 
                        tags << tag;
382
 
                        dirModel->setData(index, tags.toVariant(), SemanticInfoDirModel::TagsRole);
383
 
                }
384
 
        }
385
 
}
386
 
 
387
 
 
388
 
void SemanticInfoContextManagerItem::removeTag(const SemanticInfoTag& tag) {
389
 
        KFileItemList itemList = contextManager()->selectedFileItemList();
390
 
 
391
 
        SortedDirModel* dirModel = contextManager()->dirModel();
392
 
        Q_FOREACH(const KFileItem& item, itemList) {
393
 
                QModelIndex index = dirModel->indexForItem(item);
394
 
                TagSet tags = TagSet::fromVariant( dirModel->data(index, SemanticInfoDirModel::TagsRole) );
395
 
                if (tags.contains(tag)) {
396
 
                        tags.remove(tag);
397
 
                        dirModel->setData(index, tags.toVariant(), SemanticInfoDirModel::TagsRole);
398
 
                }
399
 
        }
400
 
}
401
 
 
402
 
 
403
 
void SemanticInfoContextManagerItem::showSemanticInfoDialog() {
404
 
        if (!d->mSemanticInfoDialog) {
405
 
                d->mSemanticInfoDialog = new SemanticInfoDialog(d->mGroup);
406
 
                d->mSemanticInfoDialog->setAttribute(Qt::WA_DeleteOnClose, true);
407
 
 
408
 
                connect(d->mSemanticInfoDialog->mPreviousButton, SIGNAL(clicked()),
409
 
                        d->mActionCollection->action("go_previous"), SLOT(trigger()) );
410
 
                connect(d->mSemanticInfoDialog->mNextButton, SIGNAL(clicked()),
411
 
                        d->mActionCollection->action("go_next"), SLOT(trigger()) );
412
 
                connect(d->mSemanticInfoDialog->mButtonBox, SIGNAL(rejected()),
413
 
                        d->mSemanticInfoDialog, SLOT(close()));
414
 
 
415
 
                AbstractSemanticInfoBackEnd* backEnd = contextManager()->dirModel()->semanticInfoBackEnd();
416
 
                d->mSemanticInfoDialog->mTagWidget->setSemanticInfoBackEnd(backEnd);
417
 
                connect(d->mSemanticInfoDialog->mTagWidget, SIGNAL(tagAssigned(const SemanticInfoTag&)),
418
 
                        SLOT(assignTag(const SemanticInfoTag&)) );
419
 
                connect(d->mSemanticInfoDialog->mTagWidget, SIGNAL(tagRemoved(const SemanticInfoTag&)),
420
 
                        SLOT(removeTag(const SemanticInfoTag&)) );
421
 
        }
422
 
        d->updateSemanticInfoDialog();
423
 
        d->mSemanticInfoDialog->show();
424
 
}
425
 
 
426
 
 
427
 
bool SemanticInfoContextManagerItem::eventFilter(QObject*, QEvent* event) {
428
 
        if (event->type() == QEvent::FocusOut) {
429
 
                storeDescription();
430
 
        }
431
 
        return false;
432
 
}
433
 
 
 
225
, d(new SemanticInfoContextManagerItemPrivate)
 
226
{
 
227
    d->q = this;
 
228
    d->mActionCollection = actionCollection;
 
229
    d->mViewMainPage = documentPanel;
 
230
 
 
231
    connect(contextManager(), SIGNAL(selectionChanged()),
 
232
            SLOT(slotSelectionChanged()));
 
233
    connect(contextManager(), SIGNAL(selectionDataChanged()),
 
234
            SLOT(update()));
 
235
    connect(contextManager(), SIGNAL(currentDirUrlChanged()),
 
236
            SLOT(update()));
 
237
 
 
238
    d->setupActions();
 
239
    d->setupGroup();
 
240
}
 
241
 
 
242
SemanticInfoContextManagerItem::~SemanticInfoContextManagerItem()
 
243
{
 
244
    delete d;
 
245
}
 
246
 
 
247
inline int ratingForVariant(const QVariant& variant)
 
248
{
 
249
    if (variant.isValid()) {
 
250
        return variant.toInt();
 
251
    } else {
 
252
        return 0;
 
253
    }
 
254
}
 
255
 
 
256
void SemanticInfoContextManagerItem::slotSelectionChanged()
 
257
{
 
258
    if (d->mRatingIndicator) {
 
259
        d->mRatingIndicator->deleteLater();
 
260
    }
 
261
    update();
 
262
}
 
263
 
 
264
void SemanticInfoContextManagerItem::update()
 
265
{
 
266
    KFileItemList itemList = contextManager()->selectedFileItemList();
 
267
 
 
268
    bool first = true;
 
269
    int rating = 0;
 
270
    QString description;
 
271
    SortedDirModel* dirModel = contextManager()->dirModel();
 
272
 
 
273
    // This hash stores for how many items the tag is present
 
274
    // If you have 3 items, and only 2 have the "Holiday" tag,
 
275
    // then tagHash["Holiday"] will be 2 at the end of the loop.
 
276
    typedef QHash<QString, int> TagHash;
 
277
    TagHash tagHash;
 
278
 
 
279
    Q_FOREACH(const KFileItem & item, itemList) {
 
280
        QModelIndex index = dirModel->indexForItem(item);
 
281
 
 
282
        QVariant value = dirModel->data(index, SemanticInfoDirModel::RatingRole);
 
283
        if (first) {
 
284
            rating = ratingForVariant(value);
 
285
        } else if (rating != ratingForVariant(value)) {
 
286
            // Ratings aren't the same, reset
 
287
            rating = 0;
 
288
        }
 
289
 
 
290
        QString indexDescription = index.data(SemanticInfoDirModel::DescriptionRole).toString();
 
291
        if (first) {
 
292
            description = indexDescription;
 
293
        } else if (description != indexDescription) {
 
294
            description.clear();
 
295
        }
 
296
 
 
297
        // Fill tagHash, incrementing the tag count if it's already there
 
298
        TagSet tagSet = TagSet::fromVariant(index.data(SemanticInfoDirModel::TagsRole));
 
299
        Q_FOREACH(const QString & tag, tagSet) {
 
300
            TagHash::Iterator it = tagHash.find(tag);
 
301
            if (it == tagHash.end()) {
 
302
                tagHash[tag] = 1;
 
303
            } else {
 
304
                ++it.value();
 
305
            }
 
306
        }
 
307
 
 
308
        first = false;
 
309
    }
 
310
    {
 
311
        SignalBlocker blocker(d->mRatingWidget);
 
312
        d->mRatingWidget->setRating(rating);
 
313
    }
 
314
    d->mDescriptionTextEdit->setText(description);
 
315
 
 
316
    // Init tagInfo from tagHash
 
317
    d->mTagInfo.clear();
 
318
    int itemCount = itemList.count();
 
319
    TagHash::ConstIterator
 
320
    it = tagHash.constBegin(),
 
321
    end = tagHash.constEnd();
 
322
    for (; it != end; ++it) {
 
323
        QString tag = it.key();
 
324
        int count = it.value();
 
325
        d->mTagInfo[tag] = count == itemCount;
 
326
    }
 
327
 
 
328
    bool enabled = !contextManager()->selectedFileItemList().isEmpty();
 
329
    Q_FOREACH(KAction * action, d->mActions) {
 
330
        action->setEnabled(enabled);
 
331
    }
 
332
    d->updateTagLabel();
 
333
    if (d->mSemanticInfoDialog) {
 
334
        d->updateSemanticInfoDialog();
 
335
    }
 
336
}
 
337
 
 
338
void SemanticInfoContextManagerItem::slotRatingChanged(int rating)
 
339
{
 
340
    KFileItemList itemList = contextManager()->selectedFileItemList();
 
341
 
 
342
    // Show rating indicator in view mode, and only if sidebar is not visible
 
343
    if (d->mViewMainPage->isVisible() && !d->mRatingWidget->isVisible()) {
 
344
        delete d->mRatingIndicator.data();
 
345
        // FIXME QGV
 
346
        //d->mRatingIndicator = new RatingIndicator(d->mViewMainPage->documentView());
 
347
        d->mRatingIndicator = new RatingIndicator(d->mViewMainPage);
 
348
        d->mRatingIndicator->setRating(rating);
 
349
        d->mRatingIndicator->show();
 
350
    }
 
351
 
 
352
    SortedDirModel* dirModel = contextManager()->dirModel();
 
353
    Q_FOREACH(const KFileItem & item, itemList) {
 
354
        QModelIndex index = dirModel->indexForItem(item);
 
355
        dirModel->setData(index, rating, SemanticInfoDirModel::RatingRole);
 
356
    }
 
357
}
 
358
 
 
359
void SemanticInfoContextManagerItem::storeDescription()
 
360
{
 
361
    if (!d->mDescriptionTextEdit->document()->isModified()) {
 
362
        return;
 
363
    }
 
364
    d->mDescriptionTextEdit->document()->setModified(false);
 
365
    QString description = d->mDescriptionTextEdit->toPlainText();
 
366
    KFileItemList itemList = contextManager()->selectedFileItemList();
 
367
 
 
368
    SortedDirModel* dirModel = contextManager()->dirModel();
 
369
    Q_FOREACH(const KFileItem & item, itemList) {
 
370
        QModelIndex index = dirModel->indexForItem(item);
 
371
        dirModel->setData(index, description, SemanticInfoDirModel::DescriptionRole);
 
372
    }
 
373
}
 
374
 
 
375
void SemanticInfoContextManagerItem::assignTag(const SemanticInfoTag& tag)
 
376
{
 
377
    KFileItemList itemList = contextManager()->selectedFileItemList();
 
378
 
 
379
    SortedDirModel* dirModel = contextManager()->dirModel();
 
380
    Q_FOREACH(const KFileItem & item, itemList) {
 
381
        QModelIndex index = dirModel->indexForItem(item);
 
382
        TagSet tags = TagSet::fromVariant(dirModel->data(index, SemanticInfoDirModel::TagsRole));
 
383
        if (!tags.contains(tag)) {
 
384
            tags << tag;
 
385
            dirModel->setData(index, tags.toVariant(), SemanticInfoDirModel::TagsRole);
 
386
        }
 
387
    }
 
388
}
 
389
 
 
390
void SemanticInfoContextManagerItem::removeTag(const SemanticInfoTag& tag)
 
391
{
 
392
    KFileItemList itemList = contextManager()->selectedFileItemList();
 
393
 
 
394
    SortedDirModel* dirModel = contextManager()->dirModel();
 
395
    Q_FOREACH(const KFileItem & item, itemList) {
 
396
        QModelIndex index = dirModel->indexForItem(item);
 
397
        TagSet tags = TagSet::fromVariant(dirModel->data(index, SemanticInfoDirModel::TagsRole));
 
398
        if (tags.contains(tag)) {
 
399
            tags.remove(tag);
 
400
            dirModel->setData(index, tags.toVariant(), SemanticInfoDirModel::TagsRole);
 
401
        }
 
402
    }
 
403
}
 
404
 
 
405
void SemanticInfoContextManagerItem::showSemanticInfoDialog()
 
406
{
 
407
    if (!d->mSemanticInfoDialog) {
 
408
        d->mSemanticInfoDialog = new SemanticInfoDialog(d->mGroup);
 
409
        d->mSemanticInfoDialog->setAttribute(Qt::WA_DeleteOnClose, true);
 
410
 
 
411
        connect(d->mSemanticInfoDialog->mPreviousButton, SIGNAL(clicked()),
 
412
                d->mActionCollection->action("go_previous"), SLOT(trigger()));
 
413
        connect(d->mSemanticInfoDialog->mNextButton, SIGNAL(clicked()),
 
414
                d->mActionCollection->action("go_next"), SLOT(trigger()));
 
415
        connect(d->mSemanticInfoDialog->mButtonBox, SIGNAL(rejected()),
 
416
                d->mSemanticInfoDialog, SLOT(close()));
 
417
 
 
418
        AbstractSemanticInfoBackEnd* backEnd = contextManager()->dirModel()->semanticInfoBackEnd();
 
419
        d->mSemanticInfoDialog->mTagWidget->setSemanticInfoBackEnd(backEnd);
 
420
        connect(d->mSemanticInfoDialog->mTagWidget, SIGNAL(tagAssigned(SemanticInfoTag)),
 
421
                SLOT(assignTag(SemanticInfoTag)));
 
422
        connect(d->mSemanticInfoDialog->mTagWidget, SIGNAL(tagRemoved(SemanticInfoTag)),
 
423
                SLOT(removeTag(SemanticInfoTag)));
 
424
    }
 
425
    d->updateSemanticInfoDialog();
 
426
    d->mSemanticInfoDialog->show();
 
427
}
 
428
 
 
429
bool SemanticInfoContextManagerItem::eventFilter(QObject*, QEvent* event)
 
430
{
 
431
    if (event->type() == QEvent::FocusOut) {
 
432
        storeDescription();
 
433
    }
 
434
    return false;
 
435
}
434
436
 
435
437
} // namespace