itemlibrarymodel.cpp 11.4 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22 23 24 25
** Alternatively, 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29

30
#include "itemlibrarymodel.h"
31
#include "itemlibraryinfo.h"
32
#include "itemlibrarysection.h"
33
#include "itemlibraryitem.h"
34
#include "itemlibrarysection.h"
35

36 37
#include <model.h>
#include <nodemetainfo.h>
38

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

46
static bool inline registerItemLibrarySortedModel() {
47
    qmlRegisterType<QmlDesigner::ItemLibrarySectionModel>();
48 49
    return true;
}
50

51 52
namespace QmlDesigner {

53 54
static QHash<QString, bool> collapsedStateHash;

55

56 57 58 59 60 61 62 63 64
void ItemLibraryModel::setExpanded(bool expanded, const QString &section)
{
    if (collapsedStateHash.contains(section))
        collapsedStateHash.remove(section);

    if (!expanded) //default is true
        collapsedStateHash.insert(section, expanded);
}

65
ItemLibraryModel::ItemLibraryModel(QObject *parent)
66
    : QAbstractListModel(parent),
67 68 69
      m_itemIconSize(64, 64),
      m_nextLibId(0)
{
70
    addRoleNames();
71 72 73 74
}

ItemLibraryModel::~ItemLibraryModel()
{
75
    clearSections();
76 77
}

78 79 80 81 82 83 84 85 86 87 88 89 90 91
int ItemLibraryModel::rowCount(const QModelIndex & /*parent*/) const
{
    return visibleSectionCount();
}

QVariant ItemLibraryModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || index.row() +1 > visibleSectionCount())
        return QVariant();


    if (m_roleNames.contains(role)) {
        QVariant value = visibleSections().at(index.row())->property(m_roleNames.value(role));

92
        ItemLibrarySectionModel* model = qobject_cast<ItemLibrarySectionModel *>(value.value<QObject*>());
93 94 95 96 97 98 99 100 101 102 103 104 105 106
        if (model)
            return QVariant::fromValue(model);

        ItemLibraryModel* model2 = qobject_cast<ItemLibraryModel *>(value.value<QObject*>());
        if (model2)
            return QVariant::fromValue(model2);

        return value;
    }

    qWarning() << Q_FUNC_INFO << "invalid role requested";

    return QVariant();
}
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

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;

131
    foreach (ItemLibrarySection* itemLibrarySectionModel, sections()) {
132 133
        itemLibrarySectionModel->updateItemIconSize(itemIconSize);
    }
134 135
}

136 137 138 139 140
int ItemLibraryModel::getSectionLibId(int itemLibId)
{
    return m_sections.value(itemLibId);
}

Thomas Hartmann's avatar
Thomas Hartmann committed
141
Import entryToImport(const ItemLibraryEntry &entry)
142
{
143 144 145
    if (entry.majorVersion() == -1 && entry.minorVersion() == -1)
        return Import::createFileImport(entry.requiredImport());

Thomas Hartmann's avatar
Thomas Hartmann committed
146 147 148
    return Import::createLibraryImport(entry.requiredImport(), QString::number(entry.majorVersion()) + QLatin1Char('.') +
                                                               QString::number(entry.minorVersion()));

149 150 151
}

void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
152
{
153 154 155
    if (!model)
        return;

156 157
    QMap<QString, int> sections;

158
    clearSections();
159
    m_itemInfos.clear();
160 161
    m_sections.clear();
    m_nextLibId = 0;
162

163 164 165
    QStringList imports;
    foreach (const Import &import, model->imports())
        if (import.isLibraryImport())
166
            imports << import.url() + QLatin1Char(' ') + import.version();
167

168
    foreach (ItemLibraryEntry entry, itemLibraryInfo->entries()) {
169

170 171
         NodeMetaInfo metaInfo = model->metaInfo(entry.typeName(), -1, -1);
         bool valid = metaInfo.isValid() && metaInfo.majorVersion() == entry.majorVersion();
172

173
         if (valid
174
                 && (entry.requiredImport().isEmpty()
175
                     || model->hasImport(entryToImport(entry), true, true))) {
176
            QString itemSectionName = entry.category();
177
            ItemLibrarySection *sectionModel;
178
            ItemLibraryItem *itemModel;
179 180 181 182
            int itemId = m_nextLibId++, sectionId;

            if (sections.contains(itemSectionName)) {
                sectionId = sections.value(itemSectionName);
183
                sectionModel = section(sectionId);
184 185
            } else {
                sectionId = m_nextLibId++;
186
                sectionModel = new ItemLibrarySection(sectionId, itemSectionName, this);
187
                addSection(sectionModel, sectionId);
188 189 190 191 192
                sections.insert(itemSectionName, sectionId);
            }

            m_itemInfos.insert(itemId, entry);

193
            itemModel = new ItemLibraryItem(itemId, entry.name(), sectionModel);
194 195 196

            // delayed creation of (default) icons
            if (entry.iconPath().isEmpty())
197
                entry.setIconPath(QStringLiteral(":/ItemLibrary/images/item-default-icon.png"));
198 199 200 201 202 203 204 205
            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);
        }
206
    }
207 208 209 210 211 212 213 214

    updateVisibility();
}


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

217 218

QMimeData *ItemLibraryModel::getMimeData(int libId)
219
{
220 221 222 223 224
    QMimeData *mimeData = new QMimeData();

    QByteArray data;
    QDataStream stream(&data, QIODevice::WriteOnly);
    stream << m_itemInfos.value(libId);
225
    mimeData->setData(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo"), data);
226 227 228 229 230 231 232

    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());
    }
233

234
    mimeData->removeFormat(QStringLiteral("text/plain"));
235

236
    return mimeData;
237 238
}

239 240

QIcon ItemLibraryModel::getIcon(int libId)
241
{
242 243 244
    return m_itemInfos.value(libId).icon();
}

245
ItemLibrarySection *ItemLibraryModel::section(int libraryId)
246
{
247
    return m_sectionModels.value(libraryId);
248 249
}

250
QList<ItemLibrarySection *> ItemLibraryModel::sections() const
251
{
252 253 254
    return m_sectionModels.values();
}

255
void ItemLibraryModel::addSection(ItemLibrarySection *sectionModel, int sectionId)
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
{
    m_sectionModels.insert(sectionId, sectionModel);
    sectionModel->setVisible(true);
}

void ItemLibraryModel::clearSections()
{
    beginResetModel();
    qDeleteAll(m_sectionModels);
    m_sectionModels.clear();
    endResetModel();
}

void ItemLibraryModel::registerQmlTypes()
{
271
    qmlRegisterType<QmlDesigner::ItemLibrarySectionModel>();
272 273 274 275 276 277 278
    qmlRegisterType<QmlDesigner::ItemLibraryModel>();
}

int ItemLibraryModel::visibleSectionCount() const
{
    int visibleCount = 0;

279
    QMap<int, ItemLibrarySection*>::const_iterator sectionIterator = m_sectionModels.constBegin();
280
    while (sectionIterator != m_sectionModels.constEnd()) {
281
        ItemLibrarySection *sectionModel = sectionIterator.value();
282 283 284 285 286 287 288 289 290
        if (sectionModel->isVisible())
            ++visibleCount;
        ++sectionIterator;
        qDebug() << __FUNCTION__ << visibleCount;
    }

    return visibleCount;
}

291
QList<ItemLibrarySection *> ItemLibraryModel::visibleSections() const
292
{
293
    QList<ItemLibrarySection *> visibleSectionList;
294

295
    QMap<int, ItemLibrarySection*>::const_iterator sectionIterator = m_sectionModels.constBegin();
296
    while (sectionIterator != m_sectionModels.constEnd()) {
297
        ItemLibrarySection *sectionModel = sectionIterator.value();
298 299 300 301 302 303
        if (sectionModel->isVisible())
            visibleSectionList.append(sectionModel);
        ++sectionIterator;
    }

    return visibleSectionList;
304
}
305

306 307
void ItemLibraryModel::updateVisibility()
{
308 309
    beginResetModel();
    endResetModel();
310 311
    bool changed = false;

312
    QMap<int, ItemLibrarySection*>::const_iterator sectionIterator = m_sectionModels.constBegin();
313
    while (sectionIterator != m_sectionModels.constEnd()) {
314
        ItemLibrarySection *sectionModel = sectionIterator.value();
315

316
        QString sectionSearchText = m_searchText;
317

318
        if (sectionModel->sectionName().toLower().contains(m_searchText))
319
            sectionSearchText.clear();
320

321 322 323 324 325 326
        bool sectionChanged = false,
            sectionVisibility = sectionModel->updateSectionVisibility(sectionSearchText,
                                                                      &sectionChanged);
        if (sectionChanged) {
            changed = true;
            if (sectionVisibility)
327
                emit sectionVisibilityChanged(sectionIterator.key());
328
        }
329

330 331
        changed |= sectionModel->setVisible(sectionVisibility);
        ++sectionIterator;
332 333
    }

334 335
    if (changed)
        emit visibilityChanged();
336 337
}

338 339 340
void ItemLibraryModel::addRoleNames()
{
    int role = 0;
341 342
    for (int propertyIndex = 0; propertyIndex < ItemLibrarySection::staticMetaObject.propertyCount(); ++propertyIndex) {
        QMetaProperty property = ItemLibrarySection::staticMetaObject.property(propertyIndex);
343 344 345 346 347 348 349
        m_roleNames.insert(role, property.name());
        ++role;
    }

    setRoleNames(m_roleNames);
}

350
int ItemLibraryModel::getWidth(const ItemLibraryEntry &itemLibraryEntry)
351
{
352
    foreach (const ItemLibraryEntry::Property &property, itemLibraryEntry.properties())
353
    {
354
        if (property.name() == "width")
355 356
            return property.value().toInt();
    }
357

358 359 360
    return 64;
}

361
int ItemLibraryModel::getHeight(const ItemLibraryEntry &itemLibraryEntry)
362
{
363
    foreach (const ItemLibraryEntry::Property &property, itemLibraryEntry.properties())
364
    {
365
        if (property.name() == "height")
366 367
            return property.value().toInt();
    }
368

369 370 371
    return 64;
}

Thomas Hartmann's avatar
Thomas Hartmann committed
372
QPixmap ItemLibraryModel::createDragPixmap(int , int )
373
{
374 375
    QImage dragImage(10, 10, QImage::Format_ARGB32); // TODO: draw item drag icon
    dragImage.fill(0x00ffffff); //### todo for now we disable the preview image
376 377
    QPainter p(&dragImage);
    QPen pen(Qt::gray);
378 379 380
//    pen.setWidth(2);
//    p.setPen(pen);
//    p.drawRect(1, 1, dragImage.width() - 2, dragImage.height() - 2);
381 382
    return QPixmap::fromImage(dragImage);
}
383

384 385 386 387 388
void registerQmlTypes()
{
    registerItemLibrarySortedModel();
}

389
} // namespace QmlDesigner
390