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
void ItemLibrarySectionModel::updateItemIconSize(const QSize &itemIconSize)
{
304
    foreach (ItemLibraryItemModel *item, m_sectionEntries.elements()) {
305 306 307 308 309 310
        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);
}

Thomas Hartmann's avatar
Thomas Hartmann committed
386
Import entryToImport(const ItemLibraryEntry &entry)
387
{
Thomas Hartmann's avatar
Thomas Hartmann committed
388 389 390
    return Import::createLibraryImport(entry.requiredImport(), QString::number(entry.majorVersion()) + QLatin1Char('.') +
                                                               QString::number(entry.minorVersion()));

391 392 393
}

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

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

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

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

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

Thomas Hartmann's avatar
Thomas Hartmann committed
411
        if (valid && (entry.requiredImport().isEmpty() || model->hasImport(entryToImport(entry), true) || entry.forceImport())) {
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 441
            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);
        }
442
    }
443 444 445 446 447 448 449 450

    updateVisibility();
}


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

453 454

QMimeData *ItemLibraryModel::getMimeData(int libId)
455
{
456 457 458 459 460 461 462 463 464 465 466 467 468
    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());
    }
469

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

472
    return mimeData;
473 474
}

475 476

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

481

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

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

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

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

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

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

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

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

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

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

544 545
} // namespace Internal
} // namespace QmlDesigner
546