wdgtagselection.cpp 10.5 KB
Newer Older
Agata Cacko's avatar
Agata Cacko committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 *  Copyright (c) 2020 Agata Cacko cacko.azh@gmail.com
 *
 * SPDX-License-Identifier: LGPL-2.0-or-later
 */

#include "wdgtagselection.h"

#include <QProcessEnvironment>
#include <QFileInfo>
#include <QMessageBox>
#include <QStandardPaths>
#include <QGridLayout>
#include <QTableWidget>
#include <QPainter>
#include <QListWidget>
#include <QAction>
#include <QMouseEvent>
#include <QMenu>
#include <QPair>
21
#include <QTimer>
Agata Cacko's avatar
Agata Cacko committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#include <KisImportExportManager.h>
#include <KoDocumentInfo.h>
#include <KoFileDialog.h>
#include <kis_icon.h>
#include <KoResource.h>
#include <KoResourceServer.h>
#include <KoResourceServerProvider.h>
#include <KisTagModel.h>

#include<KisWrappableHBoxLayout.h>


#include "kis_icon.h"

37
KisWdgTagSelectionControllerOneResource::KisWdgTagSelectionControllerOneResource(KisTagSelectionWidget *widget, bool editable)
Agata Cacko's avatar
Agata Cacko committed
38
39
40
41
42
43
    : QObject(widget)
    , m_tagSelectionWidget(widget)
    , m_editable(editable)
{
    connect(widget, SIGNAL(sigAddTagToSelection(KoID)), this, SLOT(slotAddTag(KoID)));
    connect(widget, SIGNAL(sigRemoveTagFromSelection(KoID)), this, SLOT(slotRemoveTag(KoID)));
44
    connect(widget, SIGNAL(sigCreateNewTag(QString)), this, SLOT(slotCreateNewTag(QString)));
45
    m_tagSelectionWidget->setEnabled(false); // because there is no resource selected yet
46

Agata Cacko's avatar
Agata Cacko committed
47
48
49
50
51
52
53
}

KisWdgTagSelectionControllerOneResource::~KisWdgTagSelectionControllerOneResource()
{

}

54
void KisWdgTagSelectionControllerOneResource::setResourceIds(QString resourceType, QList<int> resourceIds)
Agata Cacko's avatar
Agata Cacko committed
55
{
56
    QString oldResourceType = m_resourceType;
57
    m_resourceIds = resourceIds;
58
59
    m_resourceType = resourceType;

60
61
    if (resourceType != "" && (oldResourceType != resourceType || !m_tagResourceModel || !m_tagModel)) {
        m_tagResourceModel.reset(new KisTagResourceModel(resourceType));
62
        m_tagResourceModel->setResourceFilter(KisTagResourceModel::ShowAllResources);
63
        m_tagModel.reset(new KisTagModel(resourceType));
64
        m_tagModel->sort(KisAllTagsModel::Name);
65
66
    }

67
    if (resourceIds.count() == 0) {
68
69
        QList<KoID> emptyList;
        m_tagSelectionWidget->setTagList(m_editable, emptyList, emptyList);
70
        m_tagSelectionWidget->setEnabled(false);
Agata Cacko's avatar
Agata Cacko committed
71
    } else {
72
        m_tagResourceModel->setResourcesFilter(m_resourceIds.toVector());
73
        m_tagSelectionWidget->setEnabled(true);
Agata Cacko's avatar
Agata Cacko committed
74
75
76
77
78
79
        updateView();
    }
}

void KisWdgTagSelectionControllerOneResource::slotRemoveTag(KoID tag)
{
80
    if (m_resourceIds.count() == 0) return;
Agata Cacko's avatar
Agata Cacko committed
81
82

    KisTagSP tagsp = m_tagModel->tagForUrl(tag.id());
Agata Cacko's avatar
Agata Cacko committed
83
84

    m_tagResourceModel->untagResources(tagsp, m_resourceIds.toVector());
Agata Cacko's avatar
Agata Cacko committed
85
86
87
88
89
    updateView();
}

void KisWdgTagSelectionControllerOneResource::slotAddTag(KoID tag)
{
90
    if (m_resourceIds.count() == 0) return;
Agata Cacko's avatar
Agata Cacko committed
91
92

    KisTagSP tagsp = m_tagModel->tagForUrl(tag.id());
93

Agata Cacko's avatar
Agata Cacko committed
94
    m_tagResourceModel->tagResources(tagsp, m_resourceIds.toVector());
Agata Cacko's avatar
Agata Cacko committed
95
96
97
    updateView();
}

98
99
100
101
102
103
104
void KisWdgTagSelectionControllerOneResource::slotCreateNewTag(QString tag)
{
    if (m_resourceIds.count() == 0 || m_resourceType == "" || tag == "") return;

    KisTagSP tagsp = m_tagModel->tagForUrl(tag);
    if (tagsp.isNull()) {
        QVector<KoResourceSP> vec;
105
        m_tagModel->addTag(tag, false, vec);
106
        tagsp = m_tagModel->tagForUrl(tag);
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    } else if (!tagsp->active()) { // if tag is active, simply use that tag
        // if you use this simple cast, the order of buttons must match order of options in the enum
        int response = QMessageBox::question(0, i18nc("Dialog title", "Overwrite tag?"), i18nc("Question to the user in a dialog about creating a tag",
                                                                                          "A tag with this unique name already exists. Do you want to replace it?"),
                                           i18nc("Option in a dialog to discard the previously existing tag and creating a new one in its place", "Replace (overwrite) tag"),
                                           i18nc("Option in a dialog to undelete (reactivate) existing tag with its old assigned resources", "Restore previous tag"), i18n("Cancel"));
        if (response == 0) { // Overwrite
            m_tagModel->addTag(tag, true, QVector<KoResourceSP>()); // will overwrite the tag
            tagsp = m_tagModel->tagForUrl(tag);
        } else if (response == 1) { // Restore/use previously existing one
            m_tagModel->setTagActive(tagsp);
        } else {
            updateView();
            return;
        }
122
    }
123

124
    KIS_ASSERT_RECOVER_RETURN(tagsp);
Agata Cacko's avatar
Agata Cacko committed
125
    m_tagResourceModel->tagResources(tagsp, m_resourceIds.toVector());
126
127
128
    updateView();
}

Agata Cacko's avatar
Agata Cacko committed
129
130
void KisWdgTagSelectionControllerOneResource::updateView()
{
131
132
133
134
135
136
    if (m_resourceIds.count() == 0) {
        QList<KoID> emptyList;
        m_tagSelectionWidget->setTagList(m_editable, emptyList, emptyList);
        return;
    }

137
138
139
140
141
142
143
144
145
146
147
148
    QMap<QString, int> tagsCounts;
    for (int i = 0; i < m_tagModel->rowCount(); i++) {
        QModelIndex idx = m_tagModel->index(i, 0);
        int id = m_tagModel->data(idx, Qt::UserRole + KisAllTagsModel::Id).toInt();
        if (id < 0) {
            continue;
        }
        QString tagUrl = m_tagModel->data(idx, Qt::UserRole + KisAllTagsModel::Url).toString();
        if (!tagsCounts.contains(tagUrl)) {
            tagsCounts.insert(tagUrl, 0);
        }
    }
Agata Cacko's avatar
Agata Cacko committed
149

150
151
152
153
154
155
156
157
    // IMPORTANT: this only works correctly because there was setResourcesFilter() called in setResourceIds() function
    // if at any moment there is situation this needs to work without setResourceIds(),
    // call m_tagResourceModel->setResourcesFilter(m_resourceIds.toVector()); before this loop
    // (it will make it slightly slower since it invalides filter in the proxy model)
    for (int i = 0; i < m_tagResourceModel->rowCount(); i++) {
        QModelIndex idx = m_tagResourceModel->index(i, 0);
        KisTagSP tag = m_tagResourceModel->data(idx, Qt::UserRole + KisAllTagResourceModel::Tag).value<KisTagSP>();
        tagsCounts[tag->url()] += 1;
Agata Cacko's avatar
Agata Cacko committed
158
    }
159
160
    QList<KoID> semiSelected;
    QList<KoID> selected;
Agata Cacko's avatar
Agata Cacko committed
161
    QList<KoID> toSelect;
162

Agata Cacko's avatar
Agata Cacko committed
163
164
    for (int i = 0; i < m_tagModel->rowCount(); i++) {
        QModelIndex idx = m_tagModel->index(i, 0);
165
166
167
168
        int id = m_tagModel->data(idx, Qt::UserRole + KisAllTagsModel::Id).toInt();
        if (id < 0) {
            continue;
        }
Agata Cacko's avatar
Agata Cacko committed
169
        QString tagUrl = m_tagModel->data(idx, Qt::UserRole + KisAllTagsModel::Url).toString();
170
171
172
173
174
175
176
177
178
        QString tagName = m_tagModel->data(idx, Qt::UserRole + KisAllTagsModel::Name).toString();
        KoID tag(tagUrl, tagName);
        if (tagsCounts[tagUrl] == m_resourceIds.count()) {
            selected << tag;
        } else if (tagsCounts[tagUrl] > 0) {
            semiSelected << tag;
            toSelect << tag; // we want to be able to add a tag to every resource even though some are already tagged
        } else {
            toSelect << tag;
Agata Cacko's avatar
Agata Cacko committed
179
180
        }
    }
181
182

    m_tagSelectionWidget->setTagList(m_editable, selected, toSelect, semiSelected);
Agata Cacko's avatar
Agata Cacko committed
183
184
}

185
KisWdgTagSelectionControllerBundleTags::KisWdgTagSelectionControllerBundleTags(KisTagSelectionWidget *widget, bool editable)
Agata Cacko's avatar
Agata Cacko committed
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
    : QObject(widget)
    , m_tagSelectionWidget(widget)
    , m_editable(editable)
{
    connect(widget, SIGNAL(sigAddTagToSelection(KoID)), this, SLOT(slotAddTag(KoID)));
    connect(widget, SIGNAL(sigRemoveTagFromSelection(KoID)), this, SLOT(slotRemoveTag(KoID)));
    updateView();
}

KisWdgTagSelectionControllerBundleTags::~KisWdgTagSelectionControllerBundleTags()
{

}

QList<int> KisWdgTagSelectionControllerBundleTags::getSelectedTagIds() const
{
    QList<int> selectedTags;
    Q_FOREACH(QString resourceType, m_selectedTagsByResourceType.keys()) {
        KisTagModel* model = new KisTagModel(m_resourceType);
        QList<KoID> tagList = m_selectedTagsByResourceType[resourceType];
        Q_FOREACH(KoID tag, tagList) {
            KisTagSP tagSP = model->tagForUrl(tag.id());
            selectedTags << tagSP->id();
        }
    }
    return selectedTags;
}

void KisWdgTagSelectionControllerBundleTags::slotRemoveTag(KoID custom)
{
    if (m_selectedTagsByResourceType.contains(m_resourceType)) {
        if (m_selectedTagsByResourceType[m_resourceType].contains(custom)) {
            m_selectedTagsByResourceType[m_resourceType].removeAll(custom);
            updateView();
        }
    }
}

void KisWdgTagSelectionControllerBundleTags::slotAddTag(KoID custom)
{
    if (!m_selectedTagsByResourceType.contains(m_resourceType)) {
        m_selectedTagsByResourceType.insert(m_resourceType, QList<KoID>());
    }
    if (!m_selectedTagsByResourceType[m_resourceType].contains(custom)) {
        m_selectedTagsByResourceType[m_resourceType].append(custom);
        updateView();
    }
}

void KisWdgTagSelectionControllerBundleTags::updateView()
{
    typedef QPair<QString, QString> resourceTypePair;
    QList<QPair<QString, QString>> resourceTypes = {
        resourceTypePair(i18n("Brush presets"), ResourceType::PaintOpPresets),
        resourceTypePair(i18n("Brush tips"), ResourceType::Brushes),
        resourceTypePair(i18n("Workspaces"), ResourceType::Workspaces),
        resourceTypePair(i18n("Patterns"), ResourceType::Patterns),
        resourceTypePair(i18n("Palettes"), ResourceType::Palettes),
        resourceTypePair(i18n("Layer styles"), ResourceType::LayerStyles),
        resourceTypePair(i18n("Gradients"), ResourceType::Gradients),
        resourceTypePair(i18n("Gamut masks"), ResourceType::GamutMasks),
        resourceTypePair(i18n("SeExpr scripts"), ResourceType::SeExprScripts),
    };

    KisTagModel* model = new KisTagModel(m_resourceType);

    QList<KoID> selected = m_selectedTagsByResourceType.contains(m_resourceType) ? m_selectedTagsByResourceType[m_resourceType] : QList<KoID>();
    QList<KoID> notSelected;


    for (int i = 0; i < model->rowCount(); i++) {
        QModelIndex idx = model->index(i, 0);
        KisTagSP tag = model->data(idx, Qt::UserRole + KisAllTagsModel::KisTagRole).value<KisTagSP>();

        if (tag.isNull() || tag->id() < 0) {
            continue;
        }

        KoID custom = KoID(tag->url(), tag->name());

        if (m_selectedTagsByResourceType.contains(m_resourceType)) {
            if (!m_selectedTagsByResourceType[m_resourceType].contains(custom)) {
                notSelected << custom;
            }
        } else { // no tags from this resource type are selected
            notSelected << custom;
        }
    }

    // m_selectedTags is already categorized correctly and is in KoID form

    m_tagSelectionWidget->setTagList(m_editable, selected, notSelected);

}

void KisWdgTagSelectionControllerBundleTags::setResourceType(const QString &resourceType)
{
    m_resourceType = resourceType;
    updateView();
}