itemlibrarywidget.cpp 17.7 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
7
8
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
con's avatar
con committed
9
** No Commercial Usage
10
**
con's avatar
con committed
11
12
13
14
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
15
16
17
18
19
20
21
22
23
24
**
** 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.
**
con's avatar
con committed
25
26
27
28
29
30
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
31
32
33
**
**************************************************************************/

34
#include "itemlibrarywidget.h"
35

36
#include <utils/filterlineedit.h>
37
#include <coreplugin/coreconstants.h>
38
#include "itemlibrarycomponents.h"
39
#include "itemlibrarymodel.h"
40
#include "itemlibraryimageprovider.h"
41
#include "customdraganddrop.h"
42
43
#include <model.h>
#include <metainfo.h>
44
#include "rewritingexception.h"
45

46
#include <QFileInfo>
47
#include <QFileIconProvider>
48
49
50
51
#include <QDirModel>
#include <QStackedWidget>
#include <QGridLayout>
#include <QTabBar>
52
#include <QImageReader>
53
#include <QMimeData>
Friedemann Kleint's avatar
Friedemann Kleint committed
54
#include <QWheelEvent>
55
#include <QMenu>
56
#include <QApplication>
57

58
59
60
#include <QDeclarativeView>
#include <QDeclarativeItem>
#include <private/qdeclarativeengine_p.h>
61
62
63
64
65
66
67


namespace QmlDesigner {

class MyFileIconProvider : public QFileIconProvider
{
public:
68
69
70
    MyFileIconProvider(const QSize &iconSize)
        : QFileIconProvider(),
          m_iconSize(iconSize)
71
    {}
72

73
74
75
    virtual QIcon icon ( const QFileInfo & info ) const
    {
        QPixmap pixmap(info.absoluteFilePath());
76
77
78
79
        if (pixmap.isNull()) {
            QIcon defaultIcon(QFileIconProvider::icon(info));
            pixmap = defaultIcon.pixmap(defaultIcon.actualSize(m_iconSize));
        }
80

81
82
83
84
85
86
        if (pixmap.width() == m_iconSize.width()
            && pixmap.height() == m_iconSize.height())
            return pixmap;

        if ((pixmap.width() > m_iconSize.width())
            || (pixmap.height() > m_iconSize.height()))
87
88
            return pixmap.scaled(m_iconSize, Qt::KeepAspectRatio,
                                 Qt::SmoothTransformation);
89
90
91
92
93
94
95
96
97

        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);
    }
98
99

private:
100
    QSize m_iconSize;
101
102
103
104
};


// ---------- ItemLibraryPrivate
105
class ItemLibraryWidgetPrivate {
106
public:
107
    ItemLibraryWidgetPrivate(QObject *object);
108
109
110

    Internal::ItemLibraryModel *m_itemLibraryModel;
    QDirModel *m_resourcesDirModel;
111
112
113
114
115

    QStackedWidget *m_stackedWidget;
    Utils::FilterLineEdit *m_lineEdit;
    QDeclarativeView *m_itemsView;
    Internal::ItemLibraryTreeView *m_resourcesView;
116
    QWeakPointer<ItemLibraryInfo> m_itemLibraryInfo;
117

118
119
    QSize m_itemIconSize, m_resIconSize;
    MyFileIconProvider m_iconProvider;
120
    Model *model;
121
122
};

123
ItemLibraryWidgetPrivate::ItemLibraryWidgetPrivate(QObject *object) :
124
    m_itemLibraryModel(0),
125
126
127
    m_resourcesDirModel(0),
    m_stackedWidget(0),
    m_lineEdit(0),
128
    m_itemsView(0),
129
    m_resourcesView(0),
130
131
    m_itemIconSize(24, 24),
    m_resIconSize(24, 24),
132
133
    m_iconProvider(m_resIconSize),
    model(0)
134
135
136
137
{
    Q_UNUSED(object);
}

138
ItemLibraryWidget::ItemLibraryWidget(QWidget *parent) :
139
    QFrame(parent),
140
141
    m_d(new ItemLibraryWidgetPrivate(this)),
    m_filterFlag(QtBasic)
142
{
143
    setWindowTitle(tr("Library", "Title of library view"));
144

145
    /* create Items view and its model */
146
    m_d->m_itemsView = new QDeclarativeView(this);
147
148
149
150
    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);
151
152
    m_d->m_itemsView->setResizeMode(QDeclarativeView::SizeRootObjectToView);
    m_d->m_itemLibraryModel = new Internal::ItemLibraryModel(QDeclarativeEnginePrivate::getScriptEngine(m_d->m_itemsView->engine()), this);
153
154
    m_d->m_itemLibraryModel->setItemIconSize(m_d->m_itemIconSize);

155
156
157
158
    QDeclarativeContext *rootContext = m_d->m_itemsView->rootContext();
    rootContext->setContextProperty(QLatin1String("itemLibraryModel"), m_d->m_itemLibraryModel);
    rootContext->setContextProperty(QLatin1String("itemLibraryIconWidth"), m_d->m_itemIconSize.width());
    rootContext->setContextProperty(QLatin1String("itemLibraryIconHeight"), m_d->m_itemIconSize.height());
159

160
161
162
163
164
    QColor highlightColor = palette().highlight().color();
    if (0.5*highlightColor.saturationF()+0.75-highlightColor.valueF() < 0)
        highlightColor.setHsvF(highlightColor.hsvHueF(),0.1 + highlightColor.saturationF()*2.0, highlightColor.valueF());
    m_d->m_itemsView->rootContext()->setContextProperty(QLatin1String("highlightColor"), highlightColor);

165
166
167
    // loading the qml has to come after all needed context properties are set
    m_d->m_itemsView->setSource(QUrl("qrc:/ItemLibrary/qml/ItemsView.qml"));

168
    QDeclarativeItem *rootItem = qobject_cast<QDeclarativeItem*>(m_d->m_itemsView->rootObject());
169
170
    connect(rootItem, SIGNAL(itemSelected(int)), this, SLOT(showItemInfo(int)));
    connect(rootItem, SIGNAL(itemDragged(int)), this, SLOT(startDragAndDrop(int)));
171
    connect(this, SIGNAL(scrollItemsView(QVariant)), rootItem, SLOT(scrollView(QVariant)));
172
    connect(this, SIGNAL(resetItemsView()), rootItem, SLOT(resetView()));
173

174
175
    /* create Resources view and its model */
    m_d->m_resourcesDirModel = new QDirModel(this);
176
    m_d->m_resourcesDirModel->setIconProvider(&m_d->m_iconProvider);
177
178
179
180
    m_d->m_resourcesView = new Internal::ItemLibraryTreeView(this);
    m_d->m_resourcesView->setModel(m_d->m_resourcesDirModel);
    m_d->m_resourcesView->setIconSize(m_d->m_resIconSize);

181
182
183
    /* create image provider for loading item icons */
    m_d->m_itemsView->engine()->addImageProvider(QLatin1String("qmldesigner_itemlibrary"), new Internal::ItemLibraryImageProvider);

184
185
186
187
188
189
190
191
    /* other widgets */
    QTabBar *tabBar = new QTabBar(this);
    tabBar->addTab(tr("Items", "Title of library items view"));
    tabBar->addTab(tr("Resources", "Title of library resources view"));
    tabBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    m_d->m_lineEdit = new Utils::FilterLineEdit(this);
    m_d->m_lineEdit->setObjectName(QLatin1String("itemLibrarySearchInput"));
192
    m_d->m_lineEdit->setPlaceholderText(tr("<Filter>", "Library search input hint text"));
193
194
    m_d->m_lineEdit->setDragEnabled(false);
    m_d->m_lineEdit->setMinimumWidth(75);
195
    m_d->m_lineEdit->setTextMargins(0, 0, 20, 0);
196
197
198
199
200
    QWidget *lineEditFrame = new QWidget(this);
    lineEditFrame->setObjectName(QLatin1String("itemLibrarySearchInputFrame"));
    QGridLayout *lineEditLayout = new QGridLayout(lineEditFrame);
    lineEditLayout->setMargin(2);
    lineEditLayout->setSpacing(0);
201
202
203
204
    lineEditLayout->addItem(new QSpacerItem(5, 3, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, 0, 1, 3);
    lineEditLayout->addItem(new QSpacerItem(5, 5, QSizePolicy::Fixed, QSizePolicy::Fixed), 1, 0);
    lineEditLayout->addWidget(m_d->m_lineEdit, 1, 1, 1, 1);
    lineEditLayout->addItem(new QSpacerItem(5, 5, QSizePolicy::Fixed, QSizePolicy::Fixed), 1, 2);
205
206
207
208
209
210
211
212
213
214
    connect(m_d->m_lineEdit, SIGNAL(filterChanged(QString)), this, SLOT(setSearchFilter(QString)));

    m_d->m_stackedWidget = new QStackedWidget(this);
    m_d->m_stackedWidget->addWidget(m_d->m_itemsView);
    m_d->m_stackedWidget->addWidget(m_d->m_resourcesView);
    connect(tabBar, SIGNAL(currentChanged(int)),
            m_d->m_stackedWidget, SLOT(setCurrentIndex(int)));
    connect(tabBar, SIGNAL(currentChanged(int)),
            this, SLOT(updateSearch()));

215
216
217
218
    QWidget *spacer = new QWidget(this);
    spacer->setObjectName(QLatin1String("itemLibrarySearchInputSpacer"));
    spacer->setFixedHeight(4);

219
220
221
222
    QGridLayout *layout = new QGridLayout(this);
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);
    layout->addWidget(tabBar, 0, 0, 1, 1);
223
224
225
    layout->addWidget(spacer, 1, 0);
    layout->addWidget(lineEditFrame, 2, 0, 1, 1);
    layout->addWidget(m_d->m_stackedWidget, 3, 0, 1, 1);
226
227
228
229
230

    setResourcePath(QDir::currentPath());
    setSearchFilter(QString());

    /* style sheets */
231
232
233
234
235
236
237
238
239
240
241
    {
        QFile file(":/qmldesigner/stylesheet.css");
        file.open(QFile::ReadOnly);
        QString styleSheet = QLatin1String(file.readAll());
        setStyleSheet(styleSheet);
    }

    {
        QFile file(":/qmldesigner/scrollbar.css");
        file.open(QFile::ReadOnly);
        QString styleSheet = QLatin1String(file.readAll());
242
        m_d->m_resourcesView->setStyleSheet(styleSheet);
243
244
245
    }
}

246
ItemLibraryWidget::~ItemLibraryWidget()
247
{
248
249
250
    /* workaround: delete the items view before the model is deleted.
       This prevents qml warnings when the item library is destructed. */
    delete m_d->m_itemsView;
251
    delete m_d->m_resourcesView;
252
253
254
    delete m_d;
}

255
void ItemLibraryWidget::setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo)
256
{
257
258
259
260
261
262
263
264
265
266
267
268
    if (m_d->m_itemLibraryInfo.data() == itemLibraryInfo)
        return;

    if (m_d->m_itemLibraryInfo)
        disconnect(m_d->m_itemLibraryInfo.data(), SIGNAL(entriesChanged()),
                   this, SLOT(updateModel()));
    m_d->m_itemLibraryInfo = itemLibraryInfo;
    if (itemLibraryInfo)
        connect(m_d->m_itemLibraryInfo.data(), SIGNAL(entriesChanged()),
                this, SLOT(updateModel()));

    updateModel();
269
    updateSearch();
270
271
}

272
273
274
275
276
277
278
279
280
void ItemLibraryWidget::updateImports()
{
    FilterChangeFlag filter;
    filter = QtBasic;
    if (m_d->model) {
        QStringList imports;
        foreach (const Import &import, m_d->model->imports())
            if (import.isLibraryImport())
                imports << import.url();
281
        if (imports.contains("com.nokia.symbian", Qt::CaseInsensitive))
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
            filter = Symbian;
        if (imports.contains("com.Meego", Qt::CaseInsensitive))
            filter = Meego;
    }

    setImportFilter(filter);
}

QList<QToolButton *> ItemLibraryWidget::createToolBarWidgets()
{
    QList<QToolButton *> buttons;
    buttons << new QToolButton();
    buttons.first()->setText("I ");
    buttons.first()->setIcon(QIcon(QLatin1String(Core::Constants::ICON_FILTER)));
    buttons.first()->setToolTip("Manage imports for components");
    buttons.first()->setPopupMode(QToolButton::InstantPopup);
    QMenu * menu = new QMenu;
    QAction * basicQtAction = new QAction(menu);
    basicQtAction->setCheckable(true);
    basicQtAction->setText("Basic Qt Quick only");
    QAction * symbianAction = new QAction(menu);
    symbianAction->setCheckable(true);
    symbianAction->setText("Symbian Components");
    QAction * meegoAction= new QAction(menu);
    meegoAction->setCheckable(true);
    meegoAction->setText("Meego Components");
    menu->addAction(basicQtAction);
    menu->addAction(meegoAction);
    menu->addAction(symbianAction);
    buttons.first()->setMenu(menu);

    connect(basicQtAction, SIGNAL(toggled(bool)), this, SLOT(onQtBasicOnlyChecked(bool)));
    connect(this, SIGNAL(qtBasicOnlyChecked(bool)), basicQtAction, SLOT(setChecked(bool)));

    connect(symbianAction, SIGNAL(toggled(bool)), this, SLOT(onSymbianChecked(bool)));
    connect(this, SIGNAL(symbianChecked(bool)), symbianAction, SLOT(setChecked(bool)));

    connect(meegoAction, SIGNAL(toggled(bool)), this, SLOT(onMeegoChecked(bool)));
    connect(this, SIGNAL(meegoChecked(bool)), meegoAction, SLOT(setChecked(bool)));

    updateImports();

    return buttons;
}

327
void ItemLibraryWidget::setSearchFilter(const QString &searchFilter)
328
{
329
    if (m_d->m_stackedWidget->currentIndex() == 0) {
330
        m_d->m_itemLibraryModel->setSearchText(searchFilter);
331
        emit resetItemsView();
332
333
334
335
336
337
338
339
340
341
342
343
344
        m_d->m_itemsView->update();
    } 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);
345
        m_d->m_resourcesView->expandToDepth(1);
346
        m_d->m_resourcesView->scrollToTop();
347
348
349
    }
}

350
351
352
void ItemLibraryWidget::setModel(Model *model)
{
    m_d->model = model;
353
354
    if (!model)
        return;
355
356
357
358
    setItemLibraryInfo(model->metaInfo().itemLibraryInfo());
    updateModel();
}

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
void ItemLibraryWidget::emitImportChecked()
{
    if (!m_d->model)
        return;

    bool qtOnlyImport = false;
    bool meegoImport = false;
    bool symbianImport = false;

    foreach (const Import &import, m_d->model->imports()) {
        if (import.isLibraryImport()) {
            if (import.url().contains(QString("meego"), Qt::CaseInsensitive))
                meegoImport = true;
            if (import.url().contains(QString("Qt"), Qt::CaseInsensitive) || import.url().contains(QString("QtQuick"), Qt::CaseInsensitive))
                qtOnlyImport = true;
            if (import.url().contains(QString("symbian"), Qt::CaseInsensitive))
                symbianImport = true;
        }
    }

    if (meegoImport || symbianImport)
        qtOnlyImport = false;

    emit qtBasicOnlyChecked(qtOnlyImport);
    emit meegoChecked(meegoImport);
    emit symbianChecked(symbianImport);
}
386
387
388

void ItemLibraryWidget::setImportFilter(FilterChangeFlag flag)
{
389
390

    static bool block = false;
391
392
393
394
395
    if (!m_d->model)
        return;
    if (flag == m_filterFlag)
        return;

396
397
398
    if (block == true)
        return;

399

400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
    FilterChangeFlag oldfilterFlag = m_filterFlag;

    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
    try {
        block = true;
        if (flag == QtBasic) {
            removeImport(QLatin1String("com.meego"));
            removeImport(QLatin1String("com.nokia.symbian"));
        } else  if (flag == Symbian) {
            removeImport(QLatin1String("com.meego"));
            addImport(QLatin1String("com.nokia.symbian"), QLatin1String("1.0"));
        }  else  if (flag == Meego) {
            removeImport(QLatin1String("com.nokia.symbian"));
            addImport(QLatin1String("com.meego"), QLatin1String("1.0"));
        }
        QApplication::restoreOverrideCursor();
        block = false;
        m_filterFlag = flag;
    } catch (RewritingException &xcetion) {
        QApplication::restoreOverrideCursor();
        m_filterFlag = oldfilterFlag;
        block = false;
        // do something about it
423
    }
424
425

    emitImportChecked();
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
}

void ItemLibraryWidget::onQtBasicOnlyChecked(bool b)
{
    if (b)
        setImportFilter(QtBasic);

}

void ItemLibraryWidget::onMeegoChecked(bool b)
{
    if (b)
        setImportFilter(Meego);
}

void ItemLibraryWidget::onSymbianChecked(bool b)
{
    if (b)
        setImportFilter(Symbian);
}



449
void ItemLibraryWidget::updateModel()
450
{
451
    m_d->m_itemLibraryModel->update(m_d->m_itemLibraryInfo.data(), m_d->model);
452
    updateImports();
453
454
455
    updateSearch();
}

456
void ItemLibraryWidget::updateSearch()
457
{
458
    setSearchFilter(m_d->m_lineEdit->text());
459
460
}

461
void ItemLibraryWidget::setResourcePath(const QString &resourcePath)
462
{
463
464
    if (m_d->m_resourcesView->model() == m_d->m_resourcesDirModel)
        m_d->m_resourcesView->setRootIndex(m_d->m_resourcesDirModel->index(resourcePath));
465
    updateSearch();
466
467
}

468
void ItemLibraryWidget::startDragAndDrop(int itemLibId)
469
{
470
471
472
473
474
475
476
477
    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);

478
    QDeclarativeItem *rootItem = qobject_cast<QDeclarativeItem*>(m_d->m_itemsView->rootObject());
479
    connect(rootItem, SIGNAL(stopDragAndDrop()), drag, SLOT(stopDrag()));
480
481

    drag->exec();
482
483
}

484
void ItemLibraryWidget::showItemInfo(int /*itemLibId*/)
485
{
486
//    qDebug() << "showing item info about id" << itemLibId;
487
488
}

489
void ItemLibraryWidget::wheelEvent(QWheelEvent *event)
490
491
492
493
494
495
496
497
498
{
    if (m_d->m_stackedWidget->currentIndex() == 0 &&
        m_d->m_itemsView->rect().contains(event->pos())) {
        emit scrollItemsView(event->delta());
        event->accept();
    } else
        QFrame::wheelEvent(event);
}

499
500
501
502
 void ItemLibraryWidget::removeImport(const QString &name)
 {
     if (!m_d->model)
         return;
503
504

     QList<Import> toBeRemovedImportList;
505
506
     foreach (const Import &import, m_d->model->imports())
         if (import.isLibraryImport() && import.url().compare(name, Qt::CaseInsensitive) == 0)
507
508
509
             toBeRemovedImportList.append(import);

     m_d->model->changeImports(QList<Import>(), toBeRemovedImportList);
510
511
512
513
514
515
 }

 void ItemLibraryWidget::addImport(const QString &name, const QString &version)
 {
     if (!m_d->model)
         return;
516
     m_d->model->changeImports(QList<Import>() << Import::createLibraryImport(name, version), QList<Import>());
517
518
 }

519
}