itemlibrarymodel.cpp 14.3 KB
Newer Older
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6
**
hjk's avatar
hjk committed
7
** Contact: Nokia Corporation (info@qt.nokia.com)
8
9
10
11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12
13
14
15
16
17
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21
22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23
24
25
26
27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
Tobias Hunger's avatar
Tobias Hunger committed
29
** Nokia at info@qt.nokia.com.
30
31
32
**
**************************************************************************/

33
#include "itemlibrarymodel.h"
34
#include "itemlibraryinfo.h"
35
36
#include <model.h>
#include <nodemetainfo.h>
37

38
39
#include <QVariant>
#include <QMimeData>
40
#include <QPainter>
41
42
#include <QPen>
#include <qdebug.h>
43
44


45
46
47
namespace QmlDesigner {

namespace Internal {
48
49


50
51
template <class T>
ItemLibrarySortedModel<T>::ItemLibrarySortedModel(QObject *parent) :
52
    QDeclarativeListModel(parent)
53
54
55
{
}

56
57
58

template <class T>
ItemLibrarySortedModel<T>::~ItemLibrarySortedModel()
59
{
60
    clearElements();
61
62
63
}


64
65
66
67
68
69
template <class T>
void ItemLibrarySortedModel<T>::clearElements()
{
    while (m_elementOrder.count() > 0)
        removeElement(m_elementOrder.at(0).libId);
}
70
71


72
73
template <class T>
void ItemLibrarySortedModel<T>::addElement(T *element, int libId)
74
{
75
76
77
78
79
80
81
82
83
84
85
86
87
    struct order_struct orderEntry;
    orderEntry.libId = libId;
    orderEntry.visible = false;

    int pos = 0;
    while ((pos < m_elementOrder.count()) &&
           (*(m_elementModels.value(m_elementOrder.at(pos).libId)) < *element))
        ++pos;

    m_elementModels.insert(libId, element);
    m_elementOrder.insert(pos, orderEntry);

    setElementVisible(libId, true);
88
89
}

90
91
template <class T>
void ItemLibrarySortedModel<T>::removeElement(int libId)
92
{
93
94
95
96
97
98
99
100
101
    T *element = m_elementModels.value(libId);
    int pos = findElement(libId);

    setElementVisible(libId, false);

    m_elementModels.remove(libId);
    m_elementOrder.removeAt(pos);

    delete element;
102
103
}

104
105
106

template <class T>
bool ItemLibrarySortedModel<T>::elementVisible(int libId) const
107
{
108
109
    int pos = findElement(libId);
    return m_elementOrder.at(pos).visible;
110
111
112
}


113
template <class T>
114
bool ItemLibrarySortedModel<T>::setElementVisible(int libId, bool visible)
115
{
116
    int pos = findElement(libId);
117
    if (m_elementOrder.at(pos).visible == visible)
118
        return false;
119

120
    int visiblePos = visibleElementPosition(libId);
121
    if (visible)
122
        insert(visiblePos, *(m_elementModels.value(libId)));
123
    else
124
        remove(visiblePos);
125
126

    m_elementOrder[pos].visible = visible;
127
    return true;
128
129
130
}


131
132
template <class T>
const QMap<int, T *> &ItemLibrarySortedModel<T>::elements() const
133
{
134
135
136
137
138
139
140
141
    return m_elementModels;
}


template <class T>
T *ItemLibrarySortedModel<T>::elementModel(int libId)
{
    return m_elementModels.value(libId);
142
143
}

144
145
146

template <class T>
int ItemLibrarySortedModel<T>::findElement(int libId) const
147
{
148
149
150
151
152
153
154
    int i = 0;
    QListIterator<struct order_struct> it(m_elementOrder);

    while (it.hasNext()) {
        if (it.next().libId == libId)
            return i;
        ++i;
155
    }
156
157
158
159

    return -1;
}

160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
template <class T>
int ItemLibrarySortedModel<T>::visibleElementPosition(int libId) const
{
    int i = 0;
    QListIterator<struct order_struct> it(m_elementOrder);

    while (it.hasNext()) {
        struct order_struct order = it.next();
        if (order.libId == libId)
            return i;
        if (order.visible)
            ++i;
    }

    return -1;
}
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190



ItemLibraryItemModel::ItemLibraryItemModel(QScriptEngine *scriptEngine, int itemLibId, const QString &itemName)
    : QScriptValue(scriptEngine->newObject()),
      m_scriptEngine(scriptEngine),
      m_libId(itemLibId),
      m_name(itemName),
      m_iconSize(64, 64)
{
    QScriptValue pixmapScriptValue(m_scriptEngine->newVariant(QPixmap()));

    setProperty(QLatin1String("itemLibId"), itemLibId);
    setProperty(QLatin1String("itemName"), itemName);
    setProperty(QLatin1String("itemPixmap"), pixmapScriptValue);
191
192
}

193
194

ItemLibraryItemModel::~ItemLibraryItemModel()
195
{
196
    setProperty(QLatin1String("itemPixmap"), QVariant::Invalid);
197
198
}

199
200

int ItemLibraryItemModel::itemLibId() const
201
{
202
    return m_libId;
203
204
}

205
206

QString ItemLibraryItemModel::itemName() const
207
{
208
    return m_name;
209
210
}

211
void ItemLibraryItemModel::setItemIconPath(const QString &iconPath)
212
{
213
    m_iconPath = iconPath;
214

Kai Koehne's avatar
Kai Koehne committed
215
216
    setProperty(QLatin1String("itemLibraryIconPath"),
                QString(QLatin1String("image://qmldesigner_itemlibrary/") + iconPath));
217
}
218

219
220
221
222
void ItemLibraryItemModel::setItemIconSize(const QSize &itemIconSize)
{
    m_iconSize = itemIconSize;
//    qDebug() << "set icon size" << itemIconSize;
223
    setItemIconPath(m_iconPath);
224
225
}

226
227

bool ItemLibraryItemModel::operator<(const ItemLibraryItemModel &other) const
228
{
229
230
231
232
    return itemName() < other.itemName();
}


233
234


235
236
237
238
239
240
241
242
ItemLibrarySectionModel::ItemLibrarySectionModel(QScriptEngine *scriptEngine, int sectionLibId, const QString &sectionName, QObject *parent)
    : QScriptValue(scriptEngine->newObject()),
      m_name(sectionName),
      m_sectionEntries(parent)
{
    QScriptValue::setProperty(QLatin1String("sectionLibId"), sectionLibId);
    QScriptValue::setProperty(QLatin1String("sectionName"), sectionName);
    QScriptValue::setProperty(QLatin1String("sectionEntries"),
243
        scriptEngine->newVariant(QVariant::fromValue(static_cast<QDeclarativeListModel *>(&m_sectionEntries))));
244
}
245
246


247
248
249
250
251
QString ItemLibrarySectionModel::sectionName() const
{
    return m_name;
}

252

253
254
255
void ItemLibrarySectionModel::addSectionEntry(ItemLibraryItemModel *sectionEntry)
{
    m_sectionEntries.addElement(sectionEntry, sectionEntry->itemLibId());
256
257
}

258
259

void ItemLibrarySectionModel::removeSectionEntry(int itemLibId)
260
{
261
    m_sectionEntries.removeElement(itemLibId);
262
263
}

264

265
266
267
268
269
270
271
272
273
274
275
276
277
int ItemLibrarySectionModel::visibleItemIndex(int itemLibId)
{
    return m_sectionEntries.visibleElementPosition(itemLibId);
}


bool ItemLibrarySectionModel::isItemVisible(int itemLibId)
{
    return m_sectionEntries.elementVisible(itemLibId);
}


bool ItemLibrarySectionModel::updateSectionVisibility(const QString &searchText, bool *changed)
278
{
279
    bool haveVisibleItems = false;
280
281
282

    *changed = false;

283
284
    QMap<int, ItemLibraryItemModel *>::const_iterator itemIt = m_sectionEntries.elements().constBegin();
    while (itemIt != m_sectionEntries.elements().constEnd()) {
285

286
287
288
289
290
        bool itemVisible = itemIt.value()->itemName().toLower().contains(searchText),
            itemChanged = false;
        itemChanged = m_sectionEntries.setElementVisible(itemIt.key(), itemVisible);

        *changed |= itemChanged;
291

292
293
294
295
296
        if (itemVisible)
            haveVisibleItems = true;

        ++itemIt;
    }
297

298
299
    return haveVisibleItems;
}
300
301


302
303
304
305
306
307
308
309
310
void ItemLibrarySectionModel::updateItemIconSize(const QSize &itemIconSize)
{
    foreach (ItemLibraryItemModel *item, m_sectionEntries.elements().values()) {
        item->setItemIconSize(itemIconSize);
    }
}

bool ItemLibrarySectionModel::operator<(const ItemLibrarySectionModel &other) const
{
311
312
    if (sectionName() == QLatin1String("QML Components")) //Qml Components always come first
        return true;
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
    return sectionName() < other.sectionName();
}

ItemLibraryModel::ItemLibraryModel(QScriptEngine *scriptEngine, QObject *parent)
    : ItemLibrarySortedModel<ItemLibrarySectionModel>(parent),
      m_scriptEngine(scriptEngine),
      m_searchText(""),
      m_itemIconSize(64, 64),
      m_nextLibId(0)
{
}


ItemLibraryModel::~ItemLibraryModel()
{
}


QString ItemLibraryModel::searchText() const
{
    return m_searchText;
}


void ItemLibraryModel::setSearchText(const QString &searchText)
{
    QString lowerSearchText = searchText.toLower();

    if (m_searchText != lowerSearchText) {
        m_searchText = lowerSearchText;
        emit searchTextChanged();

        updateVisibility();
    }
}


void ItemLibraryModel::setItemIconSize(const QSize &itemIconSize)
{
    m_itemIconSize = itemIconSize;

    foreach (ItemLibrarySectionModel *section, elements().values())
        section->updateItemIconSize(itemIconSize);
}


359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
int ItemLibraryModel::getItemSectionIndex(int itemLibId)
{
    if (m_sections.contains(itemLibId))
        return elementModel(m_sections.value(itemLibId))->visibleItemIndex(itemLibId);
    else
        return -1;
}


int ItemLibraryModel::getSectionLibId(int itemLibId)
{
    return m_sections.value(itemLibId);
}


bool ItemLibraryModel::isItemVisible(int itemLibId)
{
    if (!m_sections.contains(itemLibId))
        return false;

    int sectionLibId = m_sections.value(itemLibId);
    if (!elementVisible(sectionLibId))
        return false;

    return elementModel(sectionLibId)->isItemVisible(itemLibId);
}

386
387
QString entryToImport(const ItemLibraryEntry &entry)
{
388
389
    return entry.requiredImport() + QLatin1Char(' ') + QString::number(entry.majorVersion())
            + QLatin1Char('.') + QString::number(entry.minorVersion());
390
391
392
}

void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
393
394
395
396
397
{
    QMap<QString, int> sections;

    clearElements();
    m_itemInfos.clear();
398
399
    m_sections.clear();
    m_nextLibId = 0;
400

401
402
403
    QStringList imports;
    foreach (const Import &import, model->imports())
        if (import.isLibraryImport())
404
            imports << import.url() + QLatin1Char(' ') + import.version();
405

406
    foreach (ItemLibraryEntry entry, itemLibraryInfo->entries()) {
407

408
409
         bool valid = model->metaInfo(entry.typeName(), entry.majorVersion(), entry.minorVersion()).isValid();

410
        if (valid && (entry.requiredImport().isEmpty() || imports.contains(entryToImport(entry), Qt::CaseInsensitive))) {
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
            QString itemSectionName = entry.category();
            ItemLibrarySectionModel *sectionModel;
            ItemLibraryItemModel *itemModel;
            int itemId = m_nextLibId++, sectionId;

            if (sections.contains(itemSectionName)) {
                sectionId = sections.value(itemSectionName);
                sectionModel = elementModel(sectionId);
            } else {
                sectionId = m_nextLibId++;
                sectionModel = new ItemLibrarySectionModel(m_scriptEngine.data(), sectionId, itemSectionName, this);
                addElement(sectionModel, sectionId);
                sections.insert(itemSectionName, sectionId);
            }

            m_itemInfos.insert(itemId, entry);

            itemModel = new ItemLibraryItemModel(m_scriptEngine.data(), itemId, entry.name());

            // delayed creation of (default) icons
            if (entry.iconPath().isEmpty())
                entry.setIconPath(QLatin1String(":/ItemLibrary/images/item-default-icon.png"));
            if (entry.dragIcon().isNull())
                entry.setDragIcon(createDragPixmap(getWidth(entry), getHeight(entry)));

            itemModel->setItemIconPath(entry.iconPath());
            itemModel->setItemIconSize(m_itemIconSize);
            sectionModel->addSectionEntry(itemModel);
            m_sections.insert(itemId, sectionId);
        }
441
    }
442
443
444
445
446
447
448
449

    updateVisibility();
}


QString ItemLibraryModel::getTypeName(int libId)
{
    return m_itemInfos.value(libId).typeName();
450
451
}

452
453

QMimeData *ItemLibraryModel::getMimeData(int libId)
454
{
455
456
457
458
459
460
461
462
463
464
465
466
467
    QMimeData *mimeData = new QMimeData();

    QByteArray data;
    QDataStream stream(&data, QIODevice::WriteOnly);
    stream << m_itemInfos.value(libId);
    mimeData->setData(QLatin1String("application/vnd.bauhaus.itemlibraryinfo"), data);

    const QIcon icon = m_itemInfos.value(libId).dragIcon();
    if (!icon.isNull()) {
        const QList<QSize> sizes = icon.availableSizes();
        if (!sizes.isEmpty())
            mimeData->setImageData(icon.pixmap(sizes.front()).toImage());
    }
468

469
    mimeData->removeFormat(QLatin1String("text/plain"));
470

471
    return mimeData;
472
473
}

474
475

QIcon ItemLibraryModel::getIcon(int libId)
476
{
477
478
479
    return m_itemInfos.value(libId).icon();
}

480

481
482
void ItemLibraryModel::updateVisibility()
{
483
484
    bool changed = false;

485
486
    QMap<int, ItemLibrarySectionModel *>::const_iterator sectionIt = elements().constBegin();
    while (sectionIt != elements().constEnd()) {
487

488
489
        ItemLibrarySectionModel *sectionModel = sectionIt.value();
        QString sectionSearchText = m_searchText;
490

491
492
        if (sectionModel->sectionName().toLower().contains(m_searchText))
            sectionSearchText = "";
493

494
495
496
497
498
499
500
501
        bool sectionChanged = false,
            sectionVisibility = sectionModel->updateSectionVisibility(sectionSearchText,
                                                                      &sectionChanged);
        if (sectionChanged) {
            changed = true;
            if (sectionVisibility)
                emit sectionVisibilityChanged(sectionIt.key());
        }
502

503
        changed |= setElementVisible(sectionIt.key(), sectionVisibility);
504
505
506
        ++sectionIt;
    }

507
508
    if (changed)
        emit visibilityChanged();
509
510
}

511
int ItemLibraryModel::getWidth(const ItemLibraryEntry &itemLibraryEntry)
512
{
513
    foreach (const ItemLibraryEntry::Property &property, itemLibraryEntry.properties())
514
515
516
517
518
519
520
    {
        if (property.name() == QLatin1String("width"))
            return property.value().toInt();
    }
    return 64;
}

521
int ItemLibraryModel::getHeight(const ItemLibraryEntry &itemLibraryEntry)
522
{
523
    foreach (const ItemLibraryEntry::Property &property, itemLibraryEntry.properties())
524
525
526
527
528
529
530
    {
        if (property.name() == QLatin1String("height"))
            return property.value().toInt();
    }
    return 64;
}

531
QPixmap ItemLibraryModel::createDragPixmap(int width, int height)
532
{
533
534
    QImage dragImage(10, 10, QImage::Format_ARGB32); // TODO: draw item drag icon
    dragImage.fill(0x00ffffff); //### todo for now we disable the preview image
535
536
    QPainter p(&dragImage);
    QPen pen(Qt::gray);
537
538
539
//    pen.setWidth(2);
//    p.setPen(pen);
//    p.drawRect(1, 1, dragImage.width() - 2, dragImage.height() - 2);
540
541
    return QPixmap::fromImage(dragImage);
}
542

543
544
} // namespace Internal
} // namespace QmlDesigner
545