diff --git a/src/plugins/qmldesigner/components/itemlibrary/customdraganddrop.h b/src/plugins/qmldesigner/components/itemlibrary/customdraganddrop.h index e200d8427ea0d5b9460841e2a49aea2b981d767e..0daca6b5c7f4a931e5ceedeaa7ad444ccf80b318 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/customdraganddrop.h +++ b/src/plugins/qmldesigner/components/itemlibrary/customdraganddrop.h @@ -121,6 +121,11 @@ class CustomItemLibraryDrag : public QDrag { void exec() { QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::startCustomDrag(m_pixmap, m_preview, m_mimeData); } + public slots: + void stopDrag() { + QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::endCustomDrag(); + } + private: QPixmap m_pixmap, m_preview; QMimeData *m_mimeData; diff --git a/src/plugins/qmldesigner/components/itemlibrary/default-icon.png b/src/plugins/qmldesigner/components/itemlibrary/images/item-default-icon.png similarity index 100% rename from src/plugins/qmldesigner/components/itemlibrary/default-icon.png rename to src/plugins/qmldesigner/components/itemlibrary/images/item-default-icon.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.cpp index d778c56f8effebe4cc4086f5c72d07f8f098a4ad..da5f34c4e018af00ad54a4f6fe74978bde0b9c54 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.cpp @@ -52,6 +52,11 @@ #include <QFile> #include <QDirModel> #include <QFileIconProvider> +#include <QImageReader> + +#include <QmlView> +#include <QmlGraphicsItem> +#include <private/qmlengine_p.h> namespace QmlDesigner { @@ -59,119 +64,127 @@ namespace QmlDesigner { class MyFileIconProvider : public QFileIconProvider { public: - MyFileIconProvider() : QFileIconProvider() + MyFileIconProvider(const QSize &iconSize) + : QFileIconProvider(), + m_iconSize(iconSize) {} + virtual QIcon icon ( const QFileInfo & info ) const { QPixmap pixmap(info.absoluteFilePath()); - if (pixmap.isNull()) - return QFileIconProvider::icon(info); - else return pixmap; //pixmap.scaled(128, 128, Qt::KeepAspectRatio); - } -}; - - + if (pixmap.isNull()) { + QIcon defaultIcon(QFileIconProvider::icon(info)); + pixmap = defaultIcon.pixmap(defaultIcon.actualSize(m_iconSize)); + } -class GrabHelper { - Q_DISABLE_COPY(GrabHelper) -public: - GrabHelper(); - QPixmap grabItem(QGraphicsItem *item); + if (pixmap.width() == m_iconSize.width() + && pixmap.height() == m_iconSize.height()) + return pixmap; + + if ((pixmap.width() > m_iconSize.width()) + || (pixmap.height() > m_iconSize.height())) + return pixmap.scaled(m_iconSize, Qt::KeepAspectRatio); + + QPoint offset((m_iconSize.width() - pixmap.width()) / 2, + (m_iconSize.height() - pixmap.height()) / 2); + QImage newIcon(m_iconSize, QImage::Format_ARGB32_Premultiplied); + newIcon.fill(Qt::transparent); + QPainter painter(&newIcon); + painter.drawPixmap(offset, pixmap); + return QPixmap::fromImage(newIcon); + } private: - QGraphicsScene m_scene; - QGraphicsView m_view; + QSize m_iconSize; }; -GrabHelper::GrabHelper() -{ - m_view.setScene(&m_scene); - m_view.setFrameShape(QFrame::NoFrame); - m_view.setAlignment(Qt::AlignLeft|Qt::AlignTop); - m_view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - m_view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); -} - -QPixmap GrabHelper::grabItem(QGraphicsItem *item) -{ - if (item->scene()) { - qWarning("%s: WARNING: Attempt to grab item that is part of another scene!", Q_FUNC_INFO); - return QPixmap(); - } - // Temporarily add the item, resize the view widget and grab it. - m_scene.addItem(item); - item->setPos(0.0, 0.0); - const QSize size = item->boundingRect().size().toSize(); - QPixmap rc; - if (!size.isEmpty()) { // We have seen horses barf... - m_view.resize(size); - rc = QPixmap::grabWidget(&m_view); - } - m_scene.removeItem(item); - return rc; -} // ---------- ItemLibraryPrivate class ItemLibraryPrivate { public: ItemLibraryPrivate(QObject *object); - ~ItemLibraryPrivate(); Ui::ItemLibrary m_ui; Internal::ItemLibraryModel *m_itemLibraryModel; + QmlView *m_itemsView; QDirModel *m_resourcesDirModel; - QSortFilterProxyModel *m_filterProxy; - GrabHelper *m_grabHelper; QString m_resourcePath; + QSize m_itemIconSize, m_resIconSize; + MyFileIconProvider m_iconProvider; }; ItemLibraryPrivate::ItemLibraryPrivate(QObject *object) : m_itemLibraryModel(0), - m_grabHelper(0) + m_itemsView(0), + m_itemIconSize(32, 32), + m_resIconSize(32, 32), + m_iconProvider(m_resIconSize) { m_resourcePath = QDir::currentPath(); Q_UNUSED(object); } -ItemLibraryPrivate::~ItemLibraryPrivate() -{ - delete m_grabHelper; -} - ItemLibrary::ItemLibrary(QWidget *parent) : QFrame(parent), m_d(new ItemLibraryPrivate(this)) { m_d->m_ui.setupUi(this); - m_d->m_itemLibraryModel = new Internal::ItemLibraryModel(this); + layout()->setContentsMargins(3, 3, 3, 3); + layout()->setSpacing(3); + m_d->m_resourcesDirModel = new QDirModel(this); - m_d->m_filterProxy = new QSortFilterProxyModel(this); - m_d->m_filterProxy->setSourceModel(m_d->m_itemLibraryModel); - m_d->m_ui.ItemLibraryTreeView->setModel(m_d->m_filterProxy); - m_d->m_filterProxy->setDynamicSortFilter(true); - m_d->m_ui.ItemLibraryTreeView->setRealModel(m_d->m_itemLibraryModel); - m_d->m_ui.ItemLibraryTreeView->setIconSize(QSize(64, 64)); + + m_d->m_ui.ItemLibraryTreeView->setModel(m_d->m_resourcesDirModel); + m_d->m_ui.ItemLibraryTreeView->setIconSize(m_d->m_resIconSize); + m_d->m_ui.ItemLibraryTreeView->setColumnHidden(1, true); + m_d->m_ui.ItemLibraryTreeView->setColumnHidden(2, true); + m_d->m_ui.ItemLibraryTreeView->setColumnHidden(3, true); m_d->m_ui.ItemLibraryTreeView->setSortingEnabled(true); m_d->m_ui.ItemLibraryTreeView->setHeaderHidden(true); m_d->m_ui.ItemLibraryTreeView->setIndentation(10); - m_d->m_ui.ItemLibraryTreeView->setAnimated(true); m_d->m_ui.ItemLibraryTreeView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); m_d->m_ui.ItemLibraryTreeView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_d->m_ui.ItemLibraryTreeView->setAttribute(Qt::WA_MacShowFocusRect, false); - m_d->m_filterProxy->setFilterCaseSensitivity(Qt::CaseInsensitive); - m_d->m_filterProxy->setFilterRole(Qt::UserRole); - m_d->m_filterProxy->setSortRole(Qt::DisplayRole); - connect(m_d->m_ui.lineEdit, SIGNAL(textChanged(QString)), m_d->m_filterProxy, SLOT(setFilterRegExp(QString))); - connect(m_d->m_ui.lineEdit, SIGNAL(textChanged(QString)), this, SLOT(setNameFilter(QString))); - connect(m_d->m_ui.lineEdit, SIGNAL(textChanged(QString)), this, SLOT(expandAll())); - connect(m_d->m_ui.buttonItems, SIGNAL(toggled (bool)), this, SLOT(itemLibraryButton())); - connect(m_d->m_ui.buttonResources, SIGNAL(toggled (bool)), this, SLOT(resourcesButton())); - connect(m_d->m_ui.ItemLibraryTreeView, SIGNAL(itemActivated(const QString&)), this, SIGNAL(itemActivated(const QString&))); + m_d->m_ui.ItemLibraryTreeView->setRootIndex(m_d->m_resourcesDirModel->index(m_d->m_resourcePath)); + + const QString qmlSourcePath(":/ItemLibrary/qml/ItemsView.qml"); + QFile qmlSourceFile(qmlSourcePath); + qmlSourceFile.open(QFile::ReadOnly); + Q_ASSERT(qmlSourceFile.isOpen()); + QString qmlSource(qmlSourceFile.readAll()); + + m_d->m_itemsView = new QmlView(this); + m_d->m_itemsView->setQml(qmlSource, qmlSourcePath); + m_d->m_itemsView->setAttribute(Qt::WA_OpaquePaintEvent); + m_d->m_itemsView->setAttribute(Qt::WA_NoSystemBackground); + m_d->m_itemsView->setAcceptDrops(false); + m_d->m_itemsView->setFocusPolicy(Qt::ClickFocus); + m_d->m_itemsView->setContentResizable(true); + m_d->m_ui.ItemLibraryGridLayout->addWidget(m_d->m_itemsView, 0, 0); + + m_d->m_itemLibraryModel = new Internal::ItemLibraryModel(QmlEnginePrivate::getScriptEngine(m_d->m_itemsView->engine()), this); + m_d->m_itemLibraryModel->setItemIconSize(m_d->m_itemIconSize); + m_d->m_itemsView->rootContext()->setContextProperty(QLatin1String("itemLibraryModel"), m_d->m_itemLibraryModel); + m_d->m_itemsView->rootContext()->setContextProperty(QLatin1String("itemLibraryIconWidth"), m_d->m_itemIconSize.width()); + m_d->m_itemsView->rootContext()->setContextProperty(QLatin1String("itemLibraryIconHeight"), m_d->m_itemIconSize.height()); + + m_d->m_itemsView->execute(); + + connect(m_d->m_itemsView->root(), SIGNAL(itemSelected(int)), this, SLOT(showItemInfo(int))); + connect(m_d->m_itemsView->root(), SIGNAL(itemDragged(int)), this, SLOT(startDragAndDrop(int))); + connect(this, SIGNAL(expandAllItems()), m_d->m_itemsView->root(), SLOT(expandAll())); + + connect(m_d->m_ui.lineEdit, SIGNAL(textChanged(QString)), this, SLOT(setSearchFilter(QString))); m_d->m_ui.lineEdit->setDragEnabled(false); - setNameFilter(""); - MyFileIconProvider *fileIconProvider = new MyFileIconProvider(); - m_d->m_resourcesDirModel->setIconProvider(fileIconProvider); + connect(m_d->m_ui.buttonItems, SIGNAL(clicked()), this, SLOT(itemLibraryButtonToggled())); + connect(m_d->m_ui.buttonResources, SIGNAL(clicked()), this, SLOT(resourcesButtonToggled())); + + m_d->m_ui.buttonItems->setChecked(true); + itemLibraryButtonToggled(); + setSearchFilter(""); + + m_d->m_resourcesDirModel->setIconProvider(&m_d->m_iconProvider); setWindowTitle(tr("Library", "Title of library view")); @@ -194,8 +207,6 @@ ItemLibrary::ItemLibrary(QWidget *parent) : QString styleSheet = QLatin1String(file.readAll()); m_d->m_ui.ItemLibraryTreeView->setStyleSheet(styleSheet); } - - m_d->m_ui.buttonItems->setChecked(true); } ItemLibrary::~ItemLibrary() @@ -203,48 +214,44 @@ ItemLibrary::~ItemLibrary() delete m_d; } -void ItemLibrary::setNameFilter(const QString &nameFilter) -{ - QStringList nameFilterList; - nameFilterList.append(nameFilter + "*.gif"); - nameFilterList.append(nameFilter + "*.png"); - nameFilterList.append(nameFilter + "*.jpg"); - nameFilterList.append(nameFilter + "*."); - m_d->m_resourcesDirModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); - m_d->m_resourcesDirModel->setNameFilters(nameFilterList); - if (m_d->m_ui.ItemLibraryTreeView->model() == m_d->m_resourcesDirModel) - m_d->m_ui.ItemLibraryTreeView->setRootIndex(m_d->m_resourcesDirModel->index(m_d->m_resourcePath)); -} - -void ItemLibrary::itemLibraryButton() +void ItemLibrary::setSearchFilter(const QString &searchFilter) { if (m_d->m_ui.buttonItems->isChecked()) { - m_d->m_filterProxy->setSourceModel(m_d->m_itemLibraryModel); - m_d->m_ui.ItemLibraryTreeView->setModel(m_d->m_filterProxy); - m_d->m_ui.ItemLibraryTreeView->setIconSize(QSize(64, 64)); - m_d->m_ui.buttonResources->setChecked(false); - m_d->m_ui.ItemLibraryTreeView->setRealModel(m_d->m_itemLibraryModel); - expandAll(); + m_d->m_itemLibraryModel->setSearchText(searchFilter); + m_d->m_itemsView->update(); + emit expandAllItems(); + } else { + QStringList nameFilterList; + if (searchFilter.contains('.')) { + nameFilterList.append(QString("*%1*").arg(searchFilter)); + } else { + foreach (const QByteArray &extension, QImageReader::supportedImageFormats()) { + nameFilterList.append(QString("*%1*.%2").arg(searchFilter, QString::fromAscii(extension))); + } + } + + m_d->m_resourcesDirModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); + m_d->m_resourcesDirModel->setNameFilters(nameFilterList); + if (m_d->m_ui.ItemLibraryTreeView->model() == m_d->m_resourcesDirModel) + m_d->m_ui.ItemLibraryTreeView->setRootIndex(m_d->m_resourcesDirModel->index(m_d->m_resourcePath)); + m_d->m_ui.ItemLibraryTreeView->expandToDepth(1); } } -void ItemLibrary::resourcesButton() +void ItemLibrary::itemLibraryButtonToggled() { - if (m_d->m_ui.buttonResources->isChecked()) { - m_d->m_ui.ItemLibraryTreeView->setModel(m_d->m_resourcesDirModel); - m_d->m_ui.ItemLibraryTreeView->setIconSize(QSize(32, 32)); - m_d->m_ui.buttonItems->setChecked(false); - m_d->m_ui.ItemLibraryTreeView->setRootIndex(m_d->m_resourcesDirModel->index(m_d->m_resourcePath)); - m_d->m_ui.ItemLibraryTreeView->setColumnHidden(1, true); - m_d->m_ui.ItemLibraryTreeView->setColumnHidden(2, true); - m_d->m_ui.ItemLibraryTreeView->setColumnHidden(3, true); - expandAll(); - } + m_d->m_ui.LibraryStackedWidget->setCurrentIndex(0); + m_d->m_ui.buttonItems->setChecked(true); + m_d->m_ui.buttonResources->setChecked(false); + setSearchFilter(m_d->m_ui.lineEdit->text()); } -void ItemLibrary::addItemLibraryInfo(const ItemLibraryInfo &itemLibraryInfo) +void ItemLibrary::resourcesButtonToggled() { - m_d->m_itemLibraryModel->addItemLibraryInfo(itemLibraryInfo); + m_d->m_ui.LibraryStackedWidget->setCurrentIndex(1); + m_d->m_ui.buttonResources->setChecked(true); + m_d->m_ui.buttonItems->setChecked(false); + setSearchFilter(m_d->m_ui.lineEdit->text()); } void ItemLibrary::setResourcePath(const QString &resourcePath) @@ -252,70 +259,30 @@ void ItemLibrary::setResourcePath(const QString &resourcePath) m_d->m_resourcePath = resourcePath; } -void ItemLibrary::setMetaInfo(const MetaInfo &metaInfo) +void ItemLibrary::startDragAndDrop(int itemLibId) { - m_d->m_itemLibraryModel->clear(); - - foreach (const QString &type, metaInfo.itemLibraryItems()) { - NodeMetaInfo nodeInfo = metaInfo.nodeMetaInfo(type); - - QList<ItemLibraryInfo> itemLibraryRepresentationList = metaInfo.itemLibraryRepresentations(nodeInfo); - - if (!metaInfo.hasNodeMetaInfo(type)) - qWarning() << "ItemLibrary: type not declared: " << type; - if (!itemLibraryRepresentationList.isEmpty() && metaInfo.hasNodeMetaInfo(type)) { - foreach (ItemLibraryInfo itemLibraryRepresentation, itemLibraryRepresentationList) { - QImage image(64, 64, QImage::Format_RGB32); // = m_d->m_queryView->paintObject(nodeInfo, itemLibraryRepresentation.properties()); TODO - image.fill(0xffffffff); - if (!image.isNull()) { - QPainter p(&image); - QPen pen(Qt::gray); - pen.setWidth(2); - p.setPen(pen); - p.drawRect(1, 1, image.width() - 2, image.height() - 2); - } - QIcon icon = itemLibraryRepresentation.icon(); - if (itemLibraryRepresentation.icon().isNull()) - itemLibraryRepresentation.setIcon(QIcon(":/ItemLibrary/images/default-icon.png")); - - if (itemLibraryRepresentation.category().isEmpty()) - itemLibraryRepresentation.setCategory(nodeInfo.category()); - if (!image.isNull()) { - itemLibraryRepresentation.setDragIcon(QPixmap::fromImage(image)); - addItemLibraryInfo(itemLibraryRepresentation); - } - } - } else { - QImage image; // = m_d->m_queryView->paintObject(nodeInfo); TODO we have to render image - QIcon icon = nodeInfo.icon(); - if (icon.isNull()) - icon = QIcon(":/ItemLibrary/images/default-icon.png"); - - ItemLibraryInfo itemLibraryInfo; - itemLibraryInfo.setName(type); - itemLibraryInfo.setTypeName(nodeInfo.typeName()); - itemLibraryInfo.setCategory(nodeInfo.category()); - itemLibraryInfo.setIcon(icon); - itemLibraryInfo.setMajorVersion(nodeInfo.majorVersion()); - itemLibraryInfo.setMinorVersion(nodeInfo.minorVersion()); - itemLibraryInfo.setDragIcon(QPixmap::fromImage(image)); - addItemLibraryInfo(itemLibraryInfo); - } - } - expandAll(); + QMimeData *mimeData = m_d->m_itemLibraryModel->getMimeData(itemLibId); + CustomItemLibraryDrag *drag = new CustomItemLibraryDrag(this); + const QImage image = qvariant_cast<QImage>(mimeData->imageData()); + + drag->setPixmap(m_d->m_itemLibraryModel->getIcon(itemLibId).pixmap(32, 32)); + drag->setPreview(QPixmap::fromImage(image)); + drag->setMimeData(mimeData); + + connect(m_d->m_itemsView->root(), SIGNAL(stopDragAndDrop()), drag, SLOT(stopDrag())); + + drag->exec(); } -void ItemLibrary::expandAll() +void ItemLibrary::showItemInfo(int /*itemLibId*/) { - m_d->m_ui.ItemLibraryTreeView->expandToDepth(1); +// qDebug() << "showing item info about id" << itemLibId; } -void ItemLibrary::contextMenuEvent (QContextMenuEvent *event) +void ItemLibrary::setMetaInfo(const MetaInfo &metaInfo) { - event->accept(); - QMenu menu; - menu.addAction(tr("About plugins...")); - menu.exec(event->globalPos()); + m_d->m_itemLibraryModel->update(metaInfo); } } + diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.h index 28295292e743359577319800c3d82168a2820b06..6adf53504dc4b3af6c5efd017bece852c11d7251 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.h @@ -48,6 +48,7 @@ class ItemLibrary : public QFrame { Q_OBJECT Q_DISABLE_COPY(ItemLibrary) + public: ItemLibrary(QWidget *parent = 0); virtual ~ItemLibrary(); @@ -55,28 +56,25 @@ public: void addItemLibraryInfo(const ItemLibraryInfo &ItemLibraryInfo); void setMetaInfo(const MetaInfo &metaInfo); - // Helper for creating widget box items. Note that this temporarily - // adds the item to a scene, so, the item must not be associated - // with a scene. - public Q_SLOTS: - void expandAll(); - void itemLibraryButton(); - void resourcesButton(); - void setNameFilter(const QString &nameFilter); + void itemLibraryButtonToggled(); + void resourcesButtonToggled(); + + void setSearchFilter(const QString &nameFilter); void setResourcePath(const QString &resourcePath); + + void startDragAndDrop(int itemLibId); + void showItemInfo(int itemLibId); + signals: void itemActivated(const QString& itemName); - -protected: - virtual void contextMenuEvent (QContextMenuEvent * event); + void expandAllItems(); private: ItemLibraryPrivate *m_d; }; -//class ItemLibraryFilter : public QObject - } #endif // ITEMLIBRARY_H + diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.pri b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.pri index b8212323f1109dca3c7651f11035a5c280f4d735..470a6295d7bd3973f7ef7e55c33cf5f1e971a02b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.pri +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.pri @@ -6,7 +6,8 @@ VPATH += $$PWD INCLUDEPATH += $$PWD # Input -HEADERS += itemlibrary.h itemlibrarymodel.h customdraganddrop.h +HEADERS += itemlibrary.h customdraganddrop.h itemlibrarymodel.h itemlibrarytreeview.h FORMS += itemlibrary.ui -SOURCES += itemlibrary.cpp itemlibrarymodel.cpp customdraganddrop.cpp +SOURCES += itemlibrary.cpp customdraganddrop.cpp itemlibrarymodel.cpp itemlibrarytreeview.cpp RESOURCES += itemlibrary.qrc + diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc index c1d136b81d404c61779512e32a7cae55a3b7a865..e4d27b04769854804c139603cbd73d3ef2e3b79d 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc @@ -1,5 +1,13 @@ <RCC> - <qresource prefix="/ItemLibrary/images" > - <file>default-icon.png</file> + <qresource prefix="/ItemLibrary" > + <file>qml/ItemsView.qml</file> + <file>qml/ItemsViewStyle.qml</file> + <file>qml/SectionView.qml</file> + <file>qml/ItemView.qml</file> + <file>qml/Scrollbar.qml</file> + <file>qml/Selector.qml</file> + + <file>images/item-default-icon.png</file> </qresource> </RCC> + diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.ui b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.ui index 029896d37b0db7d5f9fec7525832e3aeda48f637..0321e5323570c3ab7b40affda3c79167e7bd0b12 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.ui +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.ui @@ -7,104 +7,220 @@ <x>0</x> <y>0</y> <width>497</width> - <height>792</height> + <height>635</height> </rect> </property> <property name="windowTitle"> <string>ItemLibrary</string> </property> - <layout class="QGridLayout" name="gridLayout"> - <property name="leftMargin"> - <number>2</number> - </property> - <property name="topMargin"> - <number>6</number> - </property> - <property name="rightMargin"> - <number>2</number> - </property> - <property name="bottomMargin"> - <number>2</number> - </property> - <property name="horizontalSpacing"> - <number>4</number> - </property> - <item row="0" column="0"> - <spacer name="horizontalSpacer_2"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>6</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="buttonItems"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>80</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string>Items</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>6</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="buttonResources"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>80</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string>Resources</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>false</bool> + </property> + <property name="autoExclusive"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>6</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line_2"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>6</width> - <height>27</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Filter: </string> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QLineEdit" name="lineEdit"/> - </item> - <item row="0" column="3"> - <widget class="QToolButton" name="buttonItems"> - <property name="minimumSize"> - <size> - <width>80</width> - <height>30</height> - </size> - </property> - <property name="text"> - <string>Items</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> </widget> </item> - <item row="0" column="4"> - <widget class="QToolButton" name="buttonResources"> - <property name="minimumSize"> - <size> - <width>80</width> - <height>30</height> - </size> - </property> - <property name="text"> - <string>Resources</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>false</bool> - </property> - <property name="autoExclusive"> - <bool>false</bool> - </property> - </widget> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>6</width> + <height>6</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Filter: </string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit"/> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>6</width> + <height>6</height> + </size> + </property> + </spacer> + </item> + </layout> </item> - <item row="1" column="0" colspan="5"> + <item> <widget class="Line" name="line"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="2" column="0" colspan="5"> - <widget class="QmlDesigner::Internal::ItemLibraryTreeView" name="ItemLibraryTreeView"> - <property name="enabled"> - <bool>true</bool> + <item> + <widget class="QStackedWidget" name="LibraryStackedWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>1</number> </property> + <widget class="QWidget" name="page_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0"> + <layout class="QGridLayout" name="ItemLibraryGridLayout"/> + </item> + </layout> + </widget> + <widget class="QWidget" name="page_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="0" column="0"> + <widget class="QmlDesigner::Internal::ItemLibraryTreeView" name="ItemLibraryTreeView"> + <property name="enabled"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> </widget> </item> </layout> @@ -114,7 +230,7 @@ <customwidget> <class>QmlDesigner::Internal::ItemLibraryTreeView</class> <extends>QTreeView</extends> - <header>itemlibrarymodel.h</header> + <header>itemlibrarytreeview.h</header> </customwidget> </customwidgets> <resources/> diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index 89e81f8313e5a948db1629626ba701b87cd29d1a..b21a3830c36445108ff574f9fc16f9aac5bfa9f8 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -1,297 +1,460 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** 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. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** -**************************************************************************/ - #include "itemlibrarymodel.h" -#include "itemlibrary.h" -#include "customdraganddrop.h" - -#include <QtCore/QMimeData> -#include <QtCore/QDebug> +#include "metainfo.h" -#include <QtGui/QImage> -#include <QtGui/QPixmap> -#include <QtGui/QDrag> -#include <QSortFilterProxyModel> +#include <QVariant> +#include <QMimeData> #include <QPainter> -#include <QLabel> -#include <itemlibraryinfo.h> -#include <QDirModel> +#include <QPen> +#include <qdebug.h> -enum { debug = 0 }; -// Store data and a type enumeration along with the QStandardItem -enum ItemType { CategoryItem, WidgetItem }; -enum Roles { TypeRole = Qt::UserRole + 1, - DataRole = Qt::UserRole + 2, - DragPixmapRole = Qt::UserRole + 3}; +namespace QmlDesigner { + +namespace Internal { -static inline ItemType itemType(const QStandardItem *item) +template <class T> +ItemLibrarySortedModel<T>::ItemLibrarySortedModel(QObject *parent) : + QmlListModel(parent) { - return static_cast<ItemType>(item->data(TypeRole).toInt()); } -static inline QmlDesigner::ItemLibraryInfo widgetItemData(const QStandardItem *item) + +template <class T> +ItemLibrarySortedModel<T>::~ItemLibrarySortedModel() { - const QVariant data = item->data(DataRole); - if (!data.isValid()) - return QmlDesigner::ItemLibraryInfo(); - return qvariant_cast<QmlDesigner::ItemLibraryInfo>(data); + clearElements(); } +template <class T> +void ItemLibrarySortedModel<T>::clearElements() +{ + while (m_elementOrder.count() > 0) + removeElement(m_elementOrder.at(0).libId); +} -namespace QmlDesigner { -namespace Internal { -// Cache a drag pixmap on the icon using the DragPixmapRole data field. -static QImage cachedDragImage(const ItemLibraryInfo &ItemLibraryInfo, - QStandardItem *item) +template <class T> +void ItemLibrarySortedModel<T>::addElement(T *element, int libId) { - const QVariant cached = item->data(DragPixmapRole); - if (cached.type() != QVariant::Invalid) - return qvariant_cast<QImage>(cached); - // TODO: Grab using factory - const QIcon icon = ItemLibraryInfo.dragIcon(); - if (icon.isNull()) - return QImage(); - const QList<QSize> sizes = icon.availableSizes(); - if (sizes.isEmpty()) - return QImage(); - const QImage image = icon.pixmap(sizes.front()).toImage(); - item->setData(image, DragPixmapRole); - return image; + 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); } -ItemLibraryModel::ItemLibraryModel(QObject *parent) : - QStandardItemModel(parent) +template <class T> +void ItemLibrarySortedModel<T>::removeElement(int libId) { - setSupportedDragActions(Qt::CopyAction); + T *element = m_elementModels.value(libId); + int pos = findElement(libId); + struct order_struct orderEntry = m_elementOrder.at(pos); + + setElementVisible(libId, false); + + m_elementModels.remove(libId); + m_elementOrder.removeAt(pos); + + delete element; } -static inline QStandardItem *categoryToItem(const QString &g) + +template <class T> +bool ItemLibrarySortedModel<T>::elementVisible(int libId) const { - QStandardItem *rc = new QStandardItem(g); - rc->setFlags(Qt::ItemIsEnabled); - rc->setData(QVariant(CategoryItem), TypeRole); - rc->setData(g, Qt::UserRole); - return rc; + int pos = findElement(libId); + return m_elementOrder.at(pos).visible; } -static QStandardItem *customWidgetDataToItem(const ItemLibraryInfo &ItemLibraryInfo) +template <class T> +void ItemLibrarySortedModel<T>::setElementVisible(int libId, bool visible) { - QStandardItem *item = new QStandardItem(ItemLibraryInfo.name()); - const QIcon icon = ItemLibraryInfo.icon(); - if (!icon.isNull() && !icon.availableSizes().empty()) { - item->setIcon(icon); - if (icon.availableSizes().count() == 1) { - item->setSizeHint(icon.availableSizes().first() + QSize(1, 1)); - } + int pos = findElement(libId), + offset = 0; + + if (m_elementOrder.at(pos).visible == visible) + return; + + for (int i = 0; (i + offset) < pos;) { + if (m_elementOrder.at(i + offset).visible) + ++i; + else + ++offset; } - item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsDragEnabled|Qt::ItemIsSelectable); - item->setData(qVariantFromValue(ItemLibraryInfo), DataRole); - item->setData(QVariant(WidgetItem), TypeRole); - item->setData(ItemLibraryInfo.name(), Qt::UserRole); - return item; + if (visible) + insert(pos - offset, *(m_elementModels.value(libId))); + else + remove(pos - offset); + + m_elementOrder[pos].visible = visible; } -void ItemLibraryModel::addItemLibraryInfo(const ItemLibraryInfo &itemLibraryInfo) +template <class T> +const QMap<int, T *> &ItemLibrarySortedModel<T>::elements() const { - QStandardItem *categoryItem = findCategoryItem(itemLibraryInfo.category()); - if (!categoryItem) { - categoryItem = categoryToItem(itemLibraryInfo.category()); - appendRow(categoryItem); - } - categoryItem->appendRow(customWidgetDataToItem(itemLibraryInfo)); - QString filterList = categoryItem->data(Qt::UserRole).toString(); - filterList += itemLibraryInfo.name(); - categoryItem->setData(filterList, Qt::UserRole); + return m_elementModels; +} + + +template <class T> +T *ItemLibrarySortedModel<T>::elementModel(int libId) +{ + return m_elementModels.value(libId); } -QStandardItem *ItemLibraryModel::findCategoryItem(const QString &category) + +template <class T> +int ItemLibrarySortedModel<T>::findElement(int libId) const { - const QStandardItem *root = invisibleRootItem(); - const int rowCount = root->rowCount(); - for (int i = 0 ; i < rowCount; i++) { - QStandardItem *categoryItem = root->child(i, 0); - if (categoryItem->text() == category) - return categoryItem; + int i = 0; + QListIterator<struct order_struct> it(m_elementOrder); + + while (it.hasNext()) { + if (it.next().libId == libId) + return i; + ++i; } - return 0; + + return -1; +} + + + + +ItemLibraryItemModel::ItemLibraryItemModel(QScriptEngine *scriptEngine, int itemLibId, const QString &itemName) + : QScriptValue(scriptEngine->newObject()), + m_scriptEngine(scriptEngine), + m_libId(itemLibId), + m_name(itemName), + m_icon(), + m_iconSize(64, 64) +{ + QScriptValue pixmapScriptValue(m_scriptEngine->newVariant(QPixmap())); + + setProperty(QLatin1String("itemLibId"), itemLibId); + setProperty(QLatin1String("itemName"), itemName); + setProperty(QLatin1String("itemPixmap"), pixmapScriptValue); } -Qt::DropActions ItemLibraryModel::supportedDragActions() const + +ItemLibraryItemModel::~ItemLibraryItemModel() { - return Qt::CopyAction; + setProperty(QLatin1String("itemPixmap"), QVariant::Invalid); } -Qt::DropActions ItemLibraryModel::supportedDropActions() const + +int ItemLibraryItemModel::itemLibId() const { - return Qt::IgnoreAction; + return m_libId; } -QStringList ItemLibraryModel::mimeTypes () const + +QString ItemLibraryItemModel::itemName() const { - if (debug) - qDebug() << Q_FUNC_INFO; - return QStringList(QLatin1String("text/xml")); + return m_name; } -QByteArray ItemLibraryInfoToByteArray(const ItemLibraryInfo &ItemLibraryInfo) + +void ItemLibraryItemModel::setItemIcon(const QIcon &itemIcon) { - QByteArray byteArray; - QDataStream stream(&byteArray, QIODevice::WriteOnly); + m_icon = itemIcon; + + QScriptValue pixmapScriptValue(m_scriptEngine->newVariant(m_icon.pixmap(m_iconSize))); + setProperty(QLatin1String("itemPixmap"), pixmapScriptValue); +} - stream << ItemLibraryInfo; - return byteArray; +void ItemLibraryItemModel::setItemIconSize(const QSize &itemIconSize) +{ + m_iconSize = itemIconSize; +// qDebug() << "set icon size" << itemIconSize; + setItemIcon(m_icon); } -QMimeData *ItemLibraryModel::mimeData(const QModelIndexList &indexes) const + +bool ItemLibraryItemModel::operator<(const ItemLibraryItemModel &other) const { - if (debug) - qDebug() << Q_FUNC_INFO << indexes.size(); - if (indexes.size() != 1) - return 0; - QStandardItem *item = itemFromIndex (indexes.front()); - if (!item || itemType(item) != WidgetItem) - return 0; - QMimeData *mimeData = new QMimeData; + return itemName() < other.itemName(); +} + + - ItemLibraryInfo ItemLibraryInfo(widgetItemData(item)); - const QImage image = cachedDragImage(ItemLibraryInfo, item); - if (!image.isNull()) - mimeData->setImageData(image); +ItemLibrarySectionModel::ItemLibrarySectionModel(QScriptEngine *scriptEngine, int sectionLibId, const QString §ionName, 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"), + scriptEngine->newVariant(QVariant::fromValue(static_cast<QmlListModel *>(&m_sectionEntries)))); +} - mimeData->setData("application/vnd.bauhaus.itemlibraryinfo", ItemLibraryInfoToByteArray(ItemLibraryInfo)); - mimeData->removeFormat("text/plain"); +QString ItemLibrarySectionModel::sectionName() const +{ + return m_name; +} + - return mimeData; +void ItemLibrarySectionModel::addSectionEntry(ItemLibraryItemModel *sectionEntry) +{ + m_sectionEntries.addElement(sectionEntry, sectionEntry->itemLibId()); } -ItemLibraryTreeView::ItemLibraryTreeView(QWidget *parent) : - QTreeView(parent) + +void ItemLibrarySectionModel::removeSectionEntry(int itemLibId) { - setDragEnabled(true); - setDragDropMode(QAbstractItemView::DragOnly); - connect(this, SIGNAL(clicked(const QModelIndex &)), this, SLOT(activateItem(const QModelIndex &))); + m_sectionEntries.removeElement(itemLibId); } -// We need to implement startDrag ourselves since we cannot -// otherwise influence drag pixmap and hotspot in the standard -// implementation. -void ItemLibraryTreeView::startDrag(Qt::DropActions /* supportedActions */) + +bool ItemLibrarySectionModel::updateSectionVisibility(const QString &searchText) { - if (debug) - qDebug() << Q_FUNC_INFO; - QMimeData *mimeData = model()->mimeData(selectedIndexes()); - if (!mimeData) - return; + bool haveVisibleItems = false; + QMap<int, ItemLibraryItemModel *>::const_iterator itemIt = m_sectionEntries.elements().constBegin(); + while (itemIt != m_sectionEntries.elements().constEnd()) { - if (qobject_cast<QSortFilterProxyModel*>(model())) { - QModelIndex index = qobject_cast<QSortFilterProxyModel*>(model())->mapToSource(selectedIndexes().front()); + bool itemVisible = itemIt.value()->itemName().toLower().contains(searchText); + m_sectionEntries.setElementVisible(itemIt.key(), itemVisible); - QStandardItem *item = m_model->itemFromIndex(index); + if (itemVisible) + haveVisibleItems = true; + + ++itemIt; + } - if (!item) - return; + return haveVisibleItems; +} - CustomItemLibraryDrag *drag = new CustomItemLibraryDrag(this); - const QImage image = qvariant_cast<QImage>(mimeData->imageData()); - drag->setPixmap(item->icon().pixmap(32, 32)); - drag->setPreview(QPixmap::fromImage(image)); - drag->setMimeData(mimeData); - drag->exec(); +void ItemLibrarySectionModel::updateItemIconSize(const QSize &itemIconSize) +{ + foreach (ItemLibraryItemModel *item, m_sectionEntries.elements().values()) { + item->setItemIconSize(itemIconSize); + } +} + + +bool ItemLibrarySectionModel::operator<(const ItemLibrarySectionModel &other) const +{ + return sectionName() < other.sectionName(); +} + + + + + +ItemLibraryModel::ItemLibraryModel(QScriptEngine *scriptEngine, QObject *parent) + : ItemLibrarySortedModel<ItemLibrarySectionModel>(parent), + m_scriptEngine(scriptEngine), + m_metaInfo(0), + m_searchText(""), + m_itemIconSize(64, 64), + m_nextLibId(0) +{ +} + + +ItemLibraryModel::~ItemLibraryModel() +{ + if (m_metaInfo) + delete m_metaInfo; +} + + +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); +} + + +void ItemLibraryModel::update(const MetaInfo &metaInfo) +{ + QMap<QString, int> sections; + + clearElements(); + m_itemInfos.clear(); + + if (!m_metaInfo) { + m_metaInfo = new MetaInfo(metaInfo); } else { - QDirModel *dirModel = qobject_cast<QDirModel*>(model()); - Q_ASSERT(dirModel); - QFileInfo fileInfo = dirModel->fileInfo(selectedIndexes().front()); - QPixmap pixmap(fileInfo.absoluteFilePath()); - if (!pixmap.isNull()) { - CustomItemLibraryDrag *drag = new CustomItemLibraryDrag(this); - drag->setPreview(pixmap); - drag->setPixmap(QIcon(pixmap).pixmap(128, 128)); - QMimeData *mimeData = new QMimeData; - mimeData->setData("application/vnd.bauhaus.libraryresource", fileInfo.absoluteFilePath().toLatin1()); - drag->setMimeData(mimeData); - drag->exec(); + *m_metaInfo = metaInfo; + } + + foreach (const QString &type, metaInfo.itemLibraryItems()) { + foreach (const ItemLibraryInfo &itemLibraryRepresentation, itemLibraryRepresentations(type)) { + + QString itemSectionName = itemLibraryRepresentation.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, itemLibraryRepresentation); + + itemModel = new ItemLibraryItemModel(m_scriptEngine.data(), itemId, itemLibraryRepresentation.name()); + itemModel->setItemIcon(itemLibraryRepresentation.icon()); + itemModel->setItemIconSize(m_itemIconSize); + sectionModel->addSectionEntry(itemModel); } } + + updateVisibility(); +} + + +QString ItemLibraryModel::getTypeName(int libId) +{ + return m_itemInfos.value(libId).typeName(); } -static ItemLibraryInfo ItemLibraryInfoFromData(const QByteArray &data) + +QMimeData *ItemLibraryModel::getMimeData(int libId) { - QDataStream stream(data); + 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()); + } - ItemLibraryInfo itemLibraryInfo; - stream >> itemLibraryInfo; + mimeData->removeFormat(QLatin1String("text/plain")); - return itemLibraryInfo; + return mimeData; } -void ItemLibraryTreeView::activateItem( const QModelIndex & /*index*/) + +QIcon ItemLibraryModel::getIcon(int libId) { - QMimeData *mimeData = model()->mimeData(selectedIndexes()); - if (!mimeData) - return; + return m_itemInfos.value(libId).icon(); +} + - QString name; - if (qobject_cast<QSortFilterProxyModel*>(model())) { - QModelIndex index = qobject_cast<QSortFilterProxyModel*>(model())->mapToSource(selectedIndexes().front()); +void ItemLibraryModel::updateVisibility() +{ + QMap<int, ItemLibrarySectionModel *>::const_iterator sectionIt = elements().constBegin(); + while (sectionIt != elements().constEnd()) { - QStandardItem *item = m_model->itemFromIndex(index); + ItemLibrarySectionModel *sectionModel = sectionIt.value(); + QString sectionSearchText = m_searchText; - if (!item) - return; + if (sectionModel->sectionName().toLower().contains(m_searchText)) + sectionSearchText = ""; - ItemLibraryInfo itemLibraryInfo = ItemLibraryInfoFromData(mimeData->data("application/vnd.bauhaus.itemlibraryinfo")); - QString type = itemLibraryInfo.name(); + bool sectionVisibility = sectionModel->updateSectionVisibility(sectionSearchText); + setElementVisible(sectionIt.key(), sectionVisibility); - name = "item^" + type; - emit itemActivated(name); - } else { - QDirModel *dirModel = qobject_cast<QDirModel*>(model()); - Q_ASSERT(dirModel); - QFileInfo fileInfo = dirModel->fileInfo(selectedIndexes().front()); - QPixmap pixmap(fileInfo.absoluteFilePath()); - if (!pixmap.isNull()) { - name = "image^" + fileInfo.absoluteFilePath(); - emit itemActivated(name); + ++sectionIt; + } + + emit visibilityUpdated(); +} + + +QList<ItemLibraryInfo> ItemLibraryModel::itemLibraryRepresentations(const QString &type) +{ + NodeMetaInfo nodeInfo = m_metaInfo->nodeMetaInfo(type); + QList<ItemLibraryInfo> itemLibraryRepresentationList = m_metaInfo->itemLibraryRepresentations(nodeInfo); + + QImage dragImage(64, 64, QImage::Format_RGB32); // TODO: draw item drag icon + dragImage.fill(0xffffffff); + QPainter p(&dragImage); + QPen pen(Qt::gray); + pen.setWidth(2); + p.setPen(pen); + p.drawRect(1, 1, dragImage.width() - 2, dragImage.height() - 2); + QPixmap dragPixmap(QPixmap::fromImage(dragImage)); + + if (!m_metaInfo->hasNodeMetaInfo(type)) + qWarning() << "ItemLibrary: type not declared: " << type; + + static QIcon defaultIcon(QLatin1String(":/ItemLibrary/images/item-default-icon.png")); + + if (itemLibraryRepresentationList.isEmpty() || !m_metaInfo->hasNodeMetaInfo(type)) { + QIcon icon = nodeInfo.icon(); + if (icon.isNull()) + icon = defaultIcon; + + ItemLibraryInfo itemLibraryInfo; + itemLibraryInfo.setName(type); + itemLibraryInfo.setTypeName(nodeInfo.typeName()); + itemLibraryInfo.setCategory(nodeInfo.category()); + itemLibraryInfo.setIcon(icon); + itemLibraryInfo.setDragIcon(dragPixmap); + itemLibraryInfo.setMajorVersion(nodeInfo.majorVersion()); + itemLibraryInfo.setMinorVersion(nodeInfo.minorVersion()); + itemLibraryRepresentationList.append(itemLibraryInfo); + } + else { + foreach (ItemLibraryInfo itemLibraryRepresentation, itemLibraryRepresentationList) { + QIcon icon = itemLibraryRepresentation.icon(); + if (itemLibraryRepresentation.icon().isNull()) + itemLibraryRepresentation.setIcon(defaultIcon); + + if (itemLibraryRepresentation.dragIcon().isNull()) + itemLibraryRepresentation.setDragIcon(dragPixmap); + + if (itemLibraryRepresentation.category().isEmpty()) + itemLibraryRepresentation.setCategory(nodeInfo.category()); } } + + return itemLibraryRepresentationList; } } // namespace Internal } // namespace QmlDesigner + diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h index 4c4e00d13681606636db46a6fa1cda496f91a478..22a1beef7aab00b6eccdf75c007d6fa23eaaffec 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h @@ -1,91 +1,133 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** 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. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** -**************************************************************************/ - #ifndef ITEMLIBRARYMODEL_H #define ITEMLIBRARYMODEL_H -#include <QtGui/QStandardItemModel> -#include <QtGui/QTreeView> -#include <QDrag> -#include <QDebug> -#include <QTimeLine> +#include <QMap> +#include <QIcon> +#include <QVariant> +#include <QScriptEngine> +#include <private/qmllistmodel_p.h> -QT_BEGIN_NAMESPACE -class QLabel; -QT_END_NAMESPACE +class QMimeData; namespace QmlDesigner { +class MetaInfo; class ItemLibraryInfo; namespace Internal { -// QStandardItemModel-based model for the widget box. -class ItemLibraryModel : public QStandardItemModel -{ - Q_OBJECT +template <class T> +class ItemLibrarySortedModel: public QmlListModel { +public: + ItemLibrarySortedModel(QObject *parent = 0); + ~ItemLibrarySortedModel(); + + void clearElements(); + + void addElement(T *element, int libId); + void removeElement(int libId); + + bool elementVisible(int libId) const; + void setElementVisible(int libId, bool visible); + + const QMap<int, T *> &elements() const; + + T *elementModel(int libId); + int findElement(int libId) const; + +private: + struct order_struct { + int libId; + bool visible; + }; + + QMap<int, T *> m_elementModels; + QList<struct order_struct> m_elementOrder; +}; + + +class ItemLibraryItemModel: public QScriptValue { +public: + ItemLibraryItemModel(QScriptEngine *scriptEngine, int itemLibId, const QString &itemName); + ~ItemLibraryItemModel(); + + int itemLibId() const; + QString itemName() const; + + void setItemIcon(const QIcon &itemIcon); + void setItemIconSize(const QSize &itemIconSize); + + bool operator<(const ItemLibraryItemModel &other) const; + +private: + QWeakPointer<QScriptEngine> m_scriptEngine; + int m_libId; + QString m_name; + QIcon m_icon; + QSize m_iconSize; +}; + + +class ItemLibrarySectionModel: public QScriptValue { public: - explicit ItemLibraryModel(QObject *parent = 0); - void addItemLibraryInfo(const ItemLibraryInfo &ItemLibraryInfo); + ItemLibrarySectionModel(QScriptEngine *scriptEngine, int sectionLibId, const QString §ionName, QObject *parent = 0); + + QString sectionName() const; + void addSectionEntry(ItemLibraryItemModel *sectionEntry); + void removeSectionEntry(int itemLibId); - QStandardItem *findCategoryItem(const QString &category); + bool updateSectionVisibility(const QString &searchText); + void updateItemIconSize(const QSize &itemIconSize); - virtual Qt::DropActions supportedDragActions() const; - virtual Qt::DropActions supportedDropActions() const; + bool operator<(const ItemLibrarySectionModel &other) const; - virtual QStringList mimeTypes() const; - virtual QMimeData *mimeData(const QModelIndexList &indexes) const; +private: + QString m_name; + ItemLibrarySortedModel<ItemLibraryItemModel> m_sectionEntries; }; -// ItemLibraryTreeView with Drag implementation -class ItemLibraryTreeView : public QTreeView { + +class ItemLibraryModel: public ItemLibrarySortedModel<ItemLibrarySectionModel> { Q_OBJECT - public: - explicit ItemLibraryTreeView(QWidget *parent = 0); + Q_PROPERTY(QString searchText READ searchText WRITE setSearchText NOTIFY searchTextChanged) - virtual void startDrag(Qt::DropActions supportedActions); +public: + ItemLibraryModel(QScriptEngine *scriptEngine, QObject *parent = 0); + ~ItemLibraryModel(); + + QString searchText() const; + + void update(const MetaInfo &metaInfo); + + QString getTypeName(int libId); + QMimeData *getMimeData(int libId); + QIcon getIcon(int libId); - void setRealModel(QStandardItemModel *model) { m_model = model; } +public slots: + void setSearchText(const QString &searchText); + void setItemIconSize(const QSize &itemIconSize); signals: - void itemActivated(const QString &itemName); -private slots: - void activateItem( const QModelIndex & index); + void qmlModelChanged(); + void searchTextChanged(); + void visibilityUpdated(); private: - QPixmap m_smallImage, m_bigImage; - QStandardItemModel *m_model; -}; + void updateVisibility(); + QList<ItemLibraryInfo> itemLibraryRepresentations(const QString &type); + QWeakPointer<QScriptEngine> m_scriptEngine; + MetaInfo *m_metaInfo; + QMap<int, ItemLibraryInfo> m_itemInfos; + QString m_searchText; + QSize m_itemIconSize; + int m_nextLibId; +}; } // namespace Internal } // namespace QmlDesigner + #endif // ITEMLIBRARYMODEL_H + diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarytreeview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarytreeview.cpp new file mode 100644 index 0000000000000000000000000000000000000000..141c27f2b467e64236ad761d9c7aec80328c8a50 --- /dev/null +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarytreeview.cpp @@ -0,0 +1,109 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "itemlibrarytreeview.h" +#include "itemlibrary.h" +#include "customdraganddrop.h" + +#include <QtCore/QMimeData> +#include <QtCore/QDebug> + +#include <QtGui/QImage> +#include <QtGui/QPixmap> +#include <QtGui/QDrag> +#include <QPainter> +#include <QLabel> +#include <itemlibraryinfo.h> +#include <QDirModel> + + +enum { debug = 0 }; + + +namespace QmlDesigner { + +namespace Internal { + + +ItemLibraryTreeView::ItemLibraryTreeView(QWidget *parent) : + QTreeView(parent) +{ + setDragEnabled(true); + setDragDropMode(QAbstractItemView::DragOnly); + setUniformRowHeights(true); + connect(this, SIGNAL(clicked(const QModelIndex &)), this, SLOT(activateItem(const QModelIndex &))); +} + +// We need to implement startDrag ourselves since we cannot +// otherwise influence drag pixmap and hotspot in the standard +// implementation. +void ItemLibraryTreeView::startDrag(Qt::DropActions /* supportedActions */) +{ + if (debug) + qDebug() << Q_FUNC_INFO; + QMimeData *mimeData = model()->mimeData(selectedIndexes()); + if (!mimeData) + return; + + QDirModel *dirModel = qobject_cast<QDirModel*>(model()); + Q_ASSERT(dirModel); + QFileInfo fileInfo = dirModel->fileInfo(selectedIndexes().front()); + QPixmap pixmap(fileInfo.absoluteFilePath()); + if (!pixmap.isNull()) { + CustomItemLibraryDrag *drag = new CustomItemLibraryDrag(this); + drag->setPreview(pixmap); + drag->setPixmap(QIcon(pixmap).pixmap(128, 128)); + QMimeData *mimeData = new QMimeData; + mimeData->setData("application/vnd.bauhaus.libraryresource", fileInfo.absoluteFilePath().toLatin1()); + drag->setMimeData(mimeData); + drag->exec(); + } +} + +void ItemLibraryTreeView::activateItem( const QModelIndex & /*index*/) +{ + QMimeData *mimeData = model()->mimeData(selectedIndexes()); + if (!mimeData) + return; + + QString name; + QDirModel *dirModel = qobject_cast<QDirModel*>(model()); + Q_ASSERT(dirModel); + QFileInfo fileInfo = dirModel->fileInfo(selectedIndexes().front()); + QPixmap pixmap(fileInfo.absoluteFilePath()); + if (!pixmap.isNull()) { + name = "image^" + fileInfo.absoluteFilePath(); + emit itemActivated(name); + } +} + +} // namespace Internal + +} // namespace QmlDesigner + diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarytreeview.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarytreeview.h new file mode 100644 index 0000000000000000000000000000000000000000..61edc0367ce2e5127931e51a7b874ce737ea36a6 --- /dev/null +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarytreeview.h @@ -0,0 +1,66 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ITEMLIBRARYTREEVIEW_H +#define ITEMLIBRARYTREEVIEW_H + +#include <QtGui/QTreeView> +#include <QtGui/QStandardItemModel> +#include <QDrag> +#include <QDebug> +#include <QTimeLine> + +class QLabel; + +namespace QmlDesigner { + +namespace Internal { + +// ItemLibraryTreeView with Drag implementation +class ItemLibraryTreeView : public QTreeView { + Q_OBJECT +public: + explicit ItemLibraryTreeView(QWidget *parent = 0); + + virtual void startDrag(Qt::DropActions supportedActions); + +signals: + void itemActivated(const QString &itemName); + +private slots: + void activateItem( const QModelIndex &index); +}; + + +} // namespace Internal + +} // namespace QmlDesigner + +#endif // ITEMLIBRARYTREEVIEW_H + diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/ItemView.qml b/src/plugins/qmldesigner/components/itemlibrary/qml/ItemView.qml new file mode 100644 index 0000000000000000000000000000000000000000..2b507cd97f193e126d0e920ccc856b56229f55b3 --- /dev/null +++ b/src/plugins/qmldesigner/components/itemlibrary/qml/ItemView.qml @@ -0,0 +1,87 @@ +import Qt 4.6 + +Item { + id: itemView + + property var style + + width: GridView.view.cellWidth + height: style.cellHeight + + signal itemClicked() + signal itemDragged() + + Rectangle { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: 1 + color: style.gridLineColor + } + Rectangle { + anchors.bottom: parent.bottom + anchors.bottomMargin: -1 + anchors.left: parent.left + anchors.right: parent.right + height: 1 + color: style.gridLineColor + } + Rectangle { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + width: 1 + color: style.gridLineColor + } + Rectangle { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.bottomMargin: -1 + anchors.right: parent.right + anchors.rightMargin: -1 + width: 1 + color: style.gridLineColor + } + + Image { + id: itemIcon + + anchors.top: parent.top + anchors.topMargin: style.cellMargin + anchors.horizontalCenter: parent.horizontalCenter + + width: itemLibraryIconWidth + height: itemLibraryIconHeight + pixmap: itemPixmap + } + + Text { + id: text + + anchors.top: itemIcon.bottom + anchors.topMargin: itemView.style.cellSpacing + anchors.horizontalCenter: parent.horizontalCenter + width: style.textWidth + height: style.textHeight + + verticalAlignment: "AlignVCenter" + horizontalAlignment: "AlignHCenter" + text: itemName + // workaround: text color not updated when 'style' var finally assigned + color: style.itemNameTextColor + Component.onCompleted: text.color = style.itemNameTextColor + } + + MouseRegion { + id: mouseRegion + anchors.fill: parent + + onPositionChanged: { + itemDragged(); + } + onClicked: { + itemClicked(); + } + } +} + diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsView.qml b/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsView.qml new file mode 100644 index 0000000000000000000000000000000000000000..6b38d94d78f2beece2a8497d318adbbe263a064a --- /dev/null +++ b/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsView.qml @@ -0,0 +1,144 @@ +import Qt 4.6 + +/* + ListModel { + id: libraryModel + ListElement { + sectionTitle: "Section 1" + sectionEntries: [ + ListElement { itemLibId: 0; itemName: "Comp"; itemIconPath: "../images/default-icon.png" }, + ... + ] + } + ... + } +*/ + +/* workaround: ListView reports bogus viewportHeight + +ListView { + id: itemsView + + property string name: "itemsFlickable" + anchors.fill: parent + + interactive: false + + model: itemsView.model + delegate: sectionDelegate +} +*/ + + +Rectangle { + id: itemsView + + signal itemSelected(int itemLibId) + signal itemDragged(int itemLibId) + + function expandAll() { + expandAllEntries(); + scrollbar.handleBar.y = 0; + } + + signal expandAllEntries() + + property int entriesPerRow: Math.max(1, Math.floor((itemsFlickable.width - 2) / style.cellWidth)) + property int cellWidth: Math.floor((itemsFlickable.width - 2) / entriesPerRow) + property int cellHeight: style.cellHeight + + property var style + style: ItemsViewStyle {} + + color: style.backgroundColor + + /* workaround: without this, a completed drag and drop operation would + result in the drag being continued when QmlView re-gains + focus */ + signal stopDragAndDrop + MouseRegion { + anchors.fill: parent + hoverEnabled: true + onEntered: if (!pressed) itemsView.stopDragAndDrop + } + + Component { + id: sectionDelegate + + SectionView { + id: section + style: itemsView.style + + entriesPerRow: itemsView.entriesPerRow + cellWidth: itemsView.cellWidth + cellHeight: itemsView.cellHeight + + width: itemsFlickable.width + itemHighlight: selector + + onItemSelected: itemsView.itemSelected(itemLibId) + onItemDragged: itemsView.itemDragged(itemLibId) + + function focusSelection() { + itemSelection.focusSelection() + } + + Connection { + sender: itemsView + signal: "expandAllEntries()" + script: section.expand() + } + } + } + + Flickable { + id: itemsFlickable + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: scrollbar.left + anchors.rightMargin: 6 + clip: true + + interactive: false + viewportHeight: col.height + + onViewportHeightChanged: scrollbar.limitHandle() + + Column { + id: col + + Repeater { + model: itemLibraryModel + delegate: sectionDelegate + } + } + + Selector { + id: selector + z: -1 + style: itemsView.style + scrollFlickable: itemsFlickable + + onMoveScrollbarHandle: scrollbar.moveHandle(viewportPos) + + width: itemsView.cellWidth + height: itemsView.cellHeight + } + } + + Scrollbar { + id: scrollbar + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.right + anchors.leftMargin: -10 + anchors.right: parent.right + + scrollFlickable: itemsFlickable + style: itemsView.style + } +} + diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsViewStyle.qml b/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsViewStyle.qml new file mode 100644 index 0000000000000000000000000000000000000000..b31e8c58033a9ddce2700b865677862b3b51ccb7 --- /dev/null +++ b/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsViewStyle.qml @@ -0,0 +1,34 @@ +import Qt 4.6 + +Item { + property string backgroundColor: "#707070" + property string raisedBackgroundColor: "#e0e0e0" + + property string scrollbarBackgroundColor: "#505050" + property string scrollbarHandleColor: "#303030" + + property string itemNameTextColor: "#c0c0c0" + + property string sectionTitleTextColor: "#f0f0f0" + property string sectionTitleBackgroundColor: "#909090" + + property string gridLineColor: "#a0a0a0" + + property int sectionTitleHeight: 20 + property int sectionTitleSpacing: 2 + + property int selectionSectionOffset: sectionTitleHeight + sectionTitleSpacing + + property int iconWidth: 32 + property int iconHeight: 32 + + property int textWidth: 80 + property int textHeight: 15 + + property int cellSpacing: 7 + property int cellMargin: 10 + + property int cellWidth: textWidth + 2*cellMargin + property int cellHeight: itemLibraryIconHeight + textHeight + 2*cellMargin + cellSpacing +} + diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/Scrollbar.qml b/src/plugins/qmldesigner/components/itemlibrary/qml/Scrollbar.qml new file mode 100644 index 0000000000000000000000000000000000000000..cff81189a156a39c562c5481effe6b5e221ea32d --- /dev/null +++ b/src/plugins/qmldesigner/components/itemlibrary/qml/Scrollbar.qml @@ -0,0 +1,151 @@ +import Qt 4.6 + +Item { + id: bar + + property var handleBar: handle + + property var scrollFlickable + property var style + + property bool scrolling: (scrollFlickable.viewportHeight > scrollFlickable.height) + property int scrollHeight: height - handle.height + + Binding { + target: scrollFlickable + property: "viewportY" + value: Math.max(0, scrollFlickable.viewportHeight - scrollFlickable.height) * + handle.y / scrollHeight + } + + Rectangle { + anchors.fill: parent; + anchors.rightMargin: 1 + anchors.bottomMargin: 1 + color: "transparent" + border.width: 1; + border.color: "#8F8F8F"; + } + + function moveHandle(viewportPos) { + var pos; + + if (bar.scrollFlickable) {//.visibleArea.yPosition) { + pos = bar.scrollHeight * viewportPos / (bar.scrollFlickable.viewportHeight - bar.scrollFlickable.height); + } else + pos = 0; + +// handleMoveAnimation.to = Math.min(bar.scrollHeight, pos) +// handleMoveAnimation.start(); + handle.y = Math.min(bar.scrollHeight, pos) + } + + function limitHandle() { + // the following "if" is needed to get around NaN when starting up + if (scrollFlickable) + handle.y = Math.min(handle.height * scrollFlickable.visibleArea.yPosition, + scrollHeight); + else + handle.y = 0; + } +/* + NumberAnimation { + id: handleResetAnimation + target: handle + property: "y" + from: handle.y + to: 0 + duration: 500 + } +*/ + Connection { + sender: scrollFlickable + signal: "heightChanged" + script: { + /* since binding loops prevent setting the handle properly, + let's animate it to 0 */ + if (scrollFlickable.viewportY > (scrollFlickable.viewportHeight - scrollFlickable.height)) +// handleResetAnimation.start() + handle.y = 0 + } + } + + onScrollFlickableChanged: handle.y = 0 + +/* + Rectangle { + anchors.fill: parent + anchors.leftMargin: 3 + anchors.rightMargin: 3 + anchors.topMargin: 2 + anchors.bottomMargin: 2 + radius: width / 2 + color: style.scrollbarBackgroundColor + } +*/ + MouseRegion { + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: handle.top + onClicked: { +// handleMoveAnimation.to = Math.max(0, handle.y - 40) +// handleMoveAnimation.start(); + handle.y = Math.max(0, handle.y - 40) + } + } + + Item { + id: handle + + anchors.left: parent.left + anchors.right: parent.right + height: Math.max(width, bar.height * Math.min(1, scrollFlickable.visibleArea.heightRatio)) + +// radius: width / 2 +// color: style.scrollbarHandleColor + + Rectangle { + width: parent.height + height: parent.width + y: parent.height + + rotation: -90 + transformOrigin: Item.TopLeft + + gradient: Gradient { + GradientStop { position: 0.0; color: "#C6C6C6" } + GradientStop { position: 1.0; color: "#7E7E7E" } + } + } + + MouseRegion { + anchors.fill: parent + drag.target: parent + drag.axis: "YAxis" + drag.minimumY: 0 + drag.maximumY: scrollHeight + } + } + + MouseRegion { + anchors.left: parent.left + anchors.right: parent.right + anchors.top: handle.bottom + anchors.bottom: parent.bottom + onClicked: { +// handleMoveAnimation.to = Math.min(scrollHeight, handle.y + 40) +// handleMoveAnimation.start(); + handle.y = Math.min(scrollHeight, handle.y + 40) + } + } +/* + NumberAnimation { + id: handleMoveAnimation + target: handle + property: "y" + duration: 200 + } +*/ +} + diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/SectionView.qml b/src/plugins/qmldesigner/components/itemlibrary/qml/SectionView.qml new file mode 100644 index 0000000000000000000000000000000000000000..792ee332977d54eaa52eccda2fa8e5c1c9fc3bf9 --- /dev/null +++ b/src/plugins/qmldesigner/components/itemlibrary/qml/SectionView.qml @@ -0,0 +1,151 @@ +import Qt 4.6 + +Column { + id: sectionView + + property var style + property var itemHighlight + + property int entriesPerRow + property int cellWidth + property int cellHeight + + signal itemSelected(int itemLibId) + signal itemDragged(int itemLibId) + + function expand() { + gridFrame.state = ""; + } + + Component { + id: itemDelegate + + ItemView { + id: item + style: sectionView.style + + function selectItem() { + itemHighlight.select(sectionView, item, gridFrame.x, -gridView.viewportY); + sectionView.itemSelected(itemLibId); + } + + onItemClicked: selectItem() + onItemDragged: { + selectItem(); + sectionView.itemDragged(itemLibId); + } + } + } + + Rectangle { + width: parent.width + height: style.sectionTitleHeight + + color: style.sectionTitleBackgroundColor + radius: 2 + + Item { + id: arrow + + Rectangle { y: 0; x: 0; height: 1; width: 9; color: "#aeaeae" } + Rectangle { y: 1; x: 1; height: 1; width: 7; color: "#aeaeae" } + Rectangle { y: 2; x: 2; height: 1; width: 5; color: "#aeaeae" } + Rectangle { y: 3; x: 3; height: 1; width: 3; color: "#aeaeae" } + Rectangle { y: 4; x: 4; height: 1; width: 1; color: "#aeaeae" } + + anchors.left: parent.left + anchors.leftMargin: 5 + anchors.verticalCenter: parent.verticalCenter + width: 9 + height: 5 + + transformOrigin: Item.Center + } + Text { + id: text + + anchors.verticalCenter: parent.verticalCenter + anchors.left: arrow.right + anchors.leftMargin: 5 + + text: sectionName + color: style.sectionTitleTextColor + Component.onCompleted: text.color = style.sectionTitleTextColor + } + MouseRegion { + anchors.fill: parent + onClicked: { + if (itemHighlight.visible && + (itemHighlight.section == sectionView)) { + itemHighlight.unselect(); + sectionView.itemSelected(-1); + } + gridFrame.toggleVisibility() + } + } + } + + Item { height: 2; width: 1 } + + Item { + id: gridFrame + + function toggleVisibility() { + state = ((state == "hidden")? "":"hidden") + } + + clip: true + width: sectionView.entriesPerRow * sectionView.cellWidth + 1 + height: Math.ceil(sectionEntries.count / sectionView.entriesPerRow) * sectionView.cellHeight + 1 + anchors.horizontalCenter: parent.horizontalCenter + + GridView { + id: gridView + + Connection { + sender: itemLibraryModel + signal: "visibilityUpdated()" + script: gridView.positionViewAtIndex(0) + } + + anchors.fill: parent + anchors.rightMargin: 1 + anchors.bottomMargin: 1 + + cellWidth: sectionView.cellWidth + cellHeight: sectionView.cellHeight + model: sectionEntries + delegate: itemDelegate + interactive: false + highlightFollowsCurrentItem: false + } + + states: [ + State { + name: "hidden" + PropertyChanges { + target: gridFrame + height: 0 + opacity: 0 + } + PropertyChanges { + target: arrow + rotation: -90 + } + } + ] +/* + transitions: [ + Transition { + NumberAnimation { + matchProperties: "x,y,width,height,opacity,rotation" + duration: 200 + } + } + ] +*/ + } + + Item { height: 4; width: 1 } +} + diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/Selector.qml b/src/plugins/qmldesigner/components/itemlibrary/qml/Selector.qml new file mode 100644 index 0000000000000000000000000000000000000000..3de5a29a523ef8d96fac9bb941284bd0c9afda5d --- /dev/null +++ b/src/plugins/qmldesigner/components/itemlibrary/qml/Selector.qml @@ -0,0 +1,140 @@ +import Qt 4.6 + +Item { + id: selector + + property var style + property var scrollFlickable + + signal moveScrollbarHandle(int viewportPos) + + visible: false + + property var section: null + property var item: null + property int sectionXOffset: 0 + property int sectionYOffset: 0 + + property real staticX: (section && item)? (section.x + item.x + sectionXOffset):0; + property real staticY: (section && item)? (section.y + style.selectionSectionOffset + item.y + sectionYOffset):0; + + property bool animateMove: true + + Connection { + sender: itemLibraryModel + signal: "visibilityUpdated()" + script: selector.unselectNow() + } + + function select(section, item, sectionXOffset, sectionYOffset) { + + if (!selector.visible) { + selector.animateMove = false + } + + selector.item = item + selector.section = section + selector.sectionXOffset = sectionXOffset + selector.sectionYOffset = sectionYOffset + + if (!selector.visible) { +// print("no prev selection"); + +// selector.opacity = 0 + selector.visible = true +// selectAnimation.start(); + } + + focusSelection(); + } + + function focusSelection() { + var pos = -1; + + if (selector.staticY < scrollFlickable.viewportY) + pos = selector.staticY + else if ((selector.staticY + selector.height) > + (scrollFlickable.viewportY + scrollFlickable.height - 1)) + pos = selector.staticY + selector.height - scrollFlickable.height + 1 + + if (pos >= 0) { +/* + followSelectionAnimation.to = pos + followSelectionAnimation.start() +*/ + scrollFlickable.viewportY = pos; + selector.moveScrollbarHandle(pos) + } + } + + function unselect() { +// unselectAnimation.start(); + unselectNow(); + } + + function unselectNow() { + selector.section = null + selector.item = null + selector.sectionXOffset = 0 + selector.sectionYOffset = 0 + selector.visible = false + selector.opacity = 1 + } +/* + NumberAnimation { + id: selectAnimation + target: selector + property: "opacity" + from: 0 + to: 1 + duration: 200 + onRunningChanged: { + if (!running) + selector.animateMove = true + } + } + + NumberAnimation { + id: unselectAnimation + target: selector + property: "opacity" + from: 1 + to: 0 + duration: 150 + onRunningChanged: { + if (!running) + selector.unselectNow(); + } + } + + NumberAnimation { + id: followSelectionAnimation + target: scrollFlickable + property: "viewportY" + duration: 200 + } + + x: SpringFollow { + source: selector.staticX; + spring: selector.animateMove? 3.0:0.0; + damping: 0.35 + epsilon: 0.25 + } + + y: SpringFollow { + source: selector.staticY; + spring: selector.animateMove? 3.0:0.0; + damping: 0.35 + epsilon: 0.25 + } +*/ + + x: selector.staticX + y: selector.staticY + + Rectangle { + anchors.fill: parent + color: "steelblue" + } +} +