diff options
Diffstat (limited to 'share/qtcreator/qml/qmljsdebugger')
64 files changed, 5994 insertions, 0 deletions
diff --git a/share/qtcreator/qml/qmljsdebugger/editor/abstractformeditortool.cpp b/share/qtcreator/qml/qmljsdebugger/editor/abstractformeditortool.cpp new file mode 100644 index 0000000000..557a301112 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/abstractformeditortool.cpp @@ -0,0 +1,204 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 "abstractformeditortool.h" +#include "qdeclarativeviewobserver.h" +#include "qdeclarativeviewobserver_p.h" + +#include <QDeclarativeEngine> + +#include <QtDebug> +#include <QGraphicsItem> +#include <QDeclarativeItem> + +namespace QmlJSDebugger { + +AbstractFormEditorTool::AbstractFormEditorTool(QDeclarativeViewObserver *editorView) + : QObject(editorView), m_observer(editorView) +{ +} + + +AbstractFormEditorTool::~AbstractFormEditorTool() +{ + +} + +QDeclarativeViewObserver *AbstractFormEditorTool::observer() const +{ + return m_observer; +} + +QDeclarativeView *AbstractFormEditorTool::view() const +{ + return m_observer->declarativeView(); +} + +QGraphicsScene* AbstractFormEditorTool::scene() const +{ + return view()->scene(); +} + +void AbstractFormEditorTool::updateSelectedItems() +{ + selectedItemsChanged(items()); +} + +QList<QGraphicsItem*> AbstractFormEditorTool::items() const +{ + return observer()->selectedItems(); +} + +void AbstractFormEditorTool::enterContext(QGraphicsItem *itemToEnter) +{ + observer()->data->enterContext(itemToEnter); +} + +bool AbstractFormEditorTool::topItemIsMovable(const QList<QGraphicsItem*> & itemList) +{ + QGraphicsItem *firstSelectableItem = topMovableGraphicsItem(itemList); + if (firstSelectableItem == 0) + return false; + + QDeclarativeItem *declarativeItem = dynamic_cast<QDeclarativeItem*>(firstSelectableItem->toGraphicsObject()); + + if (declarativeItem != 0) + return true; + + return false; + +} + +bool AbstractFormEditorTool::topSelectedItemIsMovable(const QList<QGraphicsItem*> &itemList) +{ + QList<QGraphicsItem*> selectedItems = observer()->selectedItems(); + + foreach (QGraphicsItem *item, itemList) { + QDeclarativeItem *declarativeItem = toQDeclarativeItem(item); + if (declarativeItem + && selectedItems.contains(declarativeItem) + /*&& (declarativeItem->qmlItemNode().hasShowContent() || selectNonContentItems)*/) + return true; + } + + return false; + +} + +bool AbstractFormEditorTool::topItemIsResizeHandle(const QList<QGraphicsItem*> &/*itemList*/) +{ + return false; +} + +QDeclarativeItem *AbstractFormEditorTool::toQDeclarativeItem(QGraphicsItem *item) +{ + return dynamic_cast<QDeclarativeItem*>(item->toGraphicsObject()); +} + +QGraphicsItem *AbstractFormEditorTool::topMovableGraphicsItem(const QList<QGraphicsItem*> &itemList) +{ + foreach (QGraphicsItem *item, itemList) { + if (item->flags().testFlag(QGraphicsItem::ItemIsMovable)) + return item; + } + return 0; +} + +QDeclarativeItem *AbstractFormEditorTool::topMovableDeclarativeItem(const QList<QGraphicsItem*> &itemList) +{ + foreach (QGraphicsItem *item, itemList) { + QDeclarativeItem *declarativeItem = toQDeclarativeItem(item); + if (declarativeItem /*&& (declarativeItem->qmlItemNode().hasShowContent())*/) + return declarativeItem; + } + + return 0; +} + +QList<QGraphicsObject*> AbstractFormEditorTool::toGraphicsObjectList(const QList<QGraphicsItem*> &itemList) +{ + QList<QGraphicsObject*> gfxObjects; + foreach(QGraphicsItem *item, itemList) { + QGraphicsObject *obj = item->toGraphicsObject(); + if (obj) + gfxObjects << obj; + } + + return gfxObjects; +} + +QList<QObject*> AbstractFormEditorTool::toObjectList(const QList<QGraphicsItem*> &itemList) +{ + QList<QObject*> objects; + foreach(QGraphicsItem *item, itemList) { + QObject *obj = item->toGraphicsObject(); + if (obj) + objects << obj; + } + + return objects; +} + +QString AbstractFormEditorTool::titleForItem(QGraphicsItem *item) +{ + QString className("QGraphicsItem"); + QString objectStringId; + + QString constructedName; + + QGraphicsObject *gfxObject = item->toGraphicsObject(); + if (gfxObject) { + className = gfxObject->metaObject()->className(); + + className.replace(QRegExp("_QMLTYPE_\\d+"), ""); + className.replace(QRegExp("_QML_\\d+"), ""); + if (className.startsWith(QLatin1String("QDeclarative"))) + className = className.replace(QLatin1String("QDeclarative"), ""); + + QDeclarativeItem *declarativeItem = qobject_cast<QDeclarativeItem*>(gfxObject); + if (declarativeItem) { + objectStringId = QDeclarativeViewObserver::idStringForObject(declarativeItem); + } + + if (!objectStringId.isEmpty()) { + constructedName = objectStringId + " (" + className + ")"; + } else { + if (!gfxObject->objectName().isEmpty()) { + constructedName = gfxObject->objectName() + " (" + className + ")"; + } else { + constructedName = className; + } + } + } + + return constructedName; +} + + +} diff --git a/share/qtcreator/qml/qmljsdebugger/editor/abstractformeditortool.h b/share/qtcreator/qml/qmljsdebugger/editor/abstractformeditortool.h new file mode 100644 index 0000000000..63f50c876f --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/abstractformeditortool.h @@ -0,0 +1,106 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 ABSTRACTFORMEDITORTOOL_H +#define ABSTRACTFORMEDITORTOOL_H + +#include <qglobal.h> +#include <QList> +#include <QObject> + +QT_BEGIN_NAMESPACE +class QMouseEvent; +class QGraphicsItem; +class QDeclarativeItem; +class QKeyEvent; +class QGraphicsScene; +class QGraphicsObject; +class QWheelEvent; +class QDeclarativeView; +QT_END_NAMESPACE + +namespace QmlJSDebugger { + +class QDeclarativeViewObserver; + +class FormEditorView; + +class AbstractFormEditorTool : public QObject +{ + Q_OBJECT +public: + AbstractFormEditorTool(QDeclarativeViewObserver* observer); + + virtual ~AbstractFormEditorTool(); + + virtual void mousePressEvent(QMouseEvent *event) = 0; + virtual void mouseMoveEvent(QMouseEvent *event) = 0; + virtual void mouseReleaseEvent(QMouseEvent *event) = 0; + virtual void mouseDoubleClickEvent(QMouseEvent *event) = 0; + + virtual void hoverMoveEvent(QMouseEvent *event) = 0; + virtual void wheelEvent(QWheelEvent *event) = 0; + + virtual void keyPressEvent(QKeyEvent *event) = 0; + virtual void keyReleaseEvent(QKeyEvent *keyEvent) = 0; + virtual void itemsAboutToRemoved(const QList<QGraphicsItem*> &itemList) = 0; + + virtual void clear() = 0; + + void updateSelectedItems(); + QList<QGraphicsItem*> items() const; + + void enterContext(QGraphicsItem *itemToEnter); + + bool topItemIsMovable(const QList<QGraphicsItem*> &itemList); + bool topItemIsResizeHandle(const QList<QGraphicsItem*> &itemList); + bool topSelectedItemIsMovable(const QList<QGraphicsItem*> &itemList); + + static QString titleForItem(QGraphicsItem *item); + static QList<QObject*> toObjectList(const QList<QGraphicsItem*> &itemList); + static QList<QGraphicsObject*> toGraphicsObjectList(const QList<QGraphicsItem*> &itemList); + static QGraphicsItem* topMovableGraphicsItem(const QList<QGraphicsItem*> &itemList); + static QDeclarativeItem* topMovableDeclarativeItem(const QList<QGraphicsItem*> &itemList); + static QDeclarativeItem *toQDeclarativeItem(QGraphicsItem *item); + +protected: + virtual void selectedItemsChanged(const QList<QGraphicsItem*> &objectList) = 0; + + QDeclarativeViewObserver *observer() const; + QDeclarativeView *view() const; + QGraphicsScene* scene() const; + +private: + QDeclarativeViewObserver *m_observer; + QList<QGraphicsItem*> m_itemList; +}; + +} + +#endif // ABSTRACTFORMEDITORTOOL_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/boundingrecthighlighter.cpp b/share/qtcreator/qml/qmljsdebugger/editor/boundingrecthighlighter.cpp new file mode 100644 index 0000000000..c1daee8b19 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/boundingrecthighlighter.cpp @@ -0,0 +1,241 @@ +#include "boundingrecthighlighter.h" +#include "qdeclarativeviewobserver.h" +#include "qmlobserverconstants.h" + +#include <QGraphicsPolygonItem> +#include <QTimer> +#include <QObject> + +#include <QDebug> + +namespace QmlJSDebugger { + +const qreal AnimDelta = 0.025f; +const int AnimInterval = 30; +const int AnimFrames = 10; + +BoundingBox::BoundingBox(QGraphicsObject *itemToHighlight, QGraphicsItem *parentItem, QObject *parent) + : QObject(parent), + highlightedObject(itemToHighlight), + highlightPolygon(0), + highlightPolygonEdge(0) +{ + highlightPolygon = new BoundingBoxPolygonItem(parentItem); + highlightPolygonEdge = new BoundingBoxPolygonItem(parentItem); + + highlightPolygon->setPen(QPen(QColor(0, 22, 159))); + highlightPolygonEdge->setPen(QPen(QColor(158, 199, 255))); + + highlightPolygon->setFlag(QGraphicsItem::ItemIsSelectable, false); + highlightPolygonEdge->setFlag(QGraphicsItem::ItemIsSelectable, false); +} + +BoundingBox::~BoundingBox() +{ + highlightedObject.clear(); +} + +BoundingBoxPolygonItem::BoundingBoxPolygonItem(QGraphicsItem *item) : QGraphicsPolygonItem(item) +{ + QPen pen; + pen.setColor(QColor(108, 141, 221)); + pen.setWidth(1); + setPen(pen); +} + +int BoundingBoxPolygonItem::type() const +{ + return Constants::EditorItemType; +} + +BoundingRectHighlighter::BoundingRectHighlighter(QDeclarativeViewObserver *view) : + LayerItem(view->declarativeView()->scene()), + m_view(view), + m_animFrame(0) +{ + m_animTimer = new QTimer(this); + m_animTimer->setInterval(AnimInterval); + connect(m_animTimer, SIGNAL(timeout()), SLOT(animTimeout())); +} + +BoundingRectHighlighter::~BoundingRectHighlighter() +{ + +} + +void BoundingRectHighlighter::animTimeout() +{ + ++m_animFrame; + if (m_animFrame == AnimFrames) { + m_animTimer->stop(); + } + + qreal alpha = m_animFrame / float(AnimFrames); + + foreach(BoundingBox *box, m_boxes) { + box->highlightPolygonEdge->setOpacity(alpha); + } +} + +void BoundingRectHighlighter::clear() +{ + if (m_boxes.length()) { + m_animTimer->stop(); + + foreach(BoundingBox *box, m_boxes) { + freeBoundingBox(box); + } + } +} + +BoundingBox *BoundingRectHighlighter::boxFor(QGraphicsObject *item) const +{ + foreach(BoundingBox *box, m_boxes) { + if (box->highlightedObject.data() == item) { + return box; + } + } + return 0; +} + +void BoundingRectHighlighter::highlight(QList<QGraphicsObject*> items) +{ + if (items.isEmpty()) + return; + + bool animate = false; + + QList<BoundingBox *> newBoxes; + foreach(QGraphicsObject *itemToHighlight, items) { + BoundingBox *box = boxFor(itemToHighlight); + if (!box) { + box = createBoundingBox(itemToHighlight); + animate = true; + } + + newBoxes << box; + } + qSort(newBoxes); + + if (newBoxes != m_boxes) { + clear(); + m_boxes << newBoxes; + } + + highlightAll(animate); +} + +void BoundingRectHighlighter::highlight(QGraphicsObject* itemToHighlight) +{ + if (!itemToHighlight) + return; + + bool animate = false; + + BoundingBox *box = boxFor(itemToHighlight); + if (!box) { + box = createBoundingBox(itemToHighlight); + m_boxes << box; + animate = true; + qSort(m_boxes); + } + + highlightAll(animate); +} + +BoundingBox *BoundingRectHighlighter::createBoundingBox(QGraphicsObject *itemToHighlight) +{ + if (!m_freeBoxes.isEmpty()) { + BoundingBox *box = m_freeBoxes.last(); + if (box->highlightedObject.isNull()) { + box->highlightedObject = itemToHighlight; + box->highlightPolygon->show(); + box->highlightPolygonEdge->show(); + m_freeBoxes.removeLast(); + return box; + } + } + + BoundingBox *box = new BoundingBox(itemToHighlight, this, this); + + connect(itemToHighlight, SIGNAL(xChanged()), this, SLOT(refresh())); + connect(itemToHighlight, SIGNAL(yChanged()), this, SLOT(refresh())); + connect(itemToHighlight, SIGNAL(widthChanged()), this, SLOT(refresh())); + connect(itemToHighlight, SIGNAL(heightChanged()), this, SLOT(refresh())); + connect(itemToHighlight, SIGNAL(rotationChanged()), this, SLOT(refresh())); + connect(itemToHighlight, SIGNAL(destroyed(QObject*)), this, SLOT(itemDestroyed(QObject*))); + + return box; +} + +void BoundingRectHighlighter::removeBoundingBox(BoundingBox *box) +{ + delete box; + box = 0; +} + +void BoundingRectHighlighter::freeBoundingBox(BoundingBox *box) +{ + if (!box->highlightedObject.isNull()) { + disconnect(box->highlightedObject.data(), SIGNAL(xChanged()), this, SLOT(refresh())); + disconnect(box->highlightedObject.data(), SIGNAL(yChanged()), this, SLOT(refresh())); + disconnect(box->highlightedObject.data(), SIGNAL(widthChanged()), this, SLOT(refresh())); + disconnect(box->highlightedObject.data(), SIGNAL(heightChanged()), this, SLOT(refresh())); + disconnect(box->highlightedObject.data(), SIGNAL(rotationChanged()), this, SLOT(refresh())); + } + + box->highlightedObject.clear(); + box->highlightPolygon->hide(); + box->highlightPolygonEdge->hide(); + m_boxes.removeOne(box); + m_freeBoxes << box; +} + +void BoundingRectHighlighter::itemDestroyed(QObject *obj) +{ + foreach(BoundingBox *box, m_boxes) { + if (box->highlightedObject.data() == obj) { + freeBoundingBox(box); + break; + } + } +} + +void BoundingRectHighlighter::highlightAll(bool animate) +{ + foreach(BoundingBox *box, m_boxes) { + if (box && box->highlightedObject.isNull()) { + // clear all highlights + clear(); + return; + } + QGraphicsObject *item = box->highlightedObject.data(); + QRectF itemAndChildRect = item->boundingRect() | item->childrenBoundingRect(); + + QPolygonF boundingRectInSceneSpace(item->mapToScene(itemAndChildRect)); + QPolygonF boundingRectInLayerItemSpace = mapFromScene(boundingRectInSceneSpace); + QRectF bboxRect = m_view->adjustToScreenBoundaries(boundingRectInLayerItemSpace.boundingRect()); + QRectF edgeRect = bboxRect; + edgeRect.adjust(-1, -1, 1, 1); + + box->highlightPolygon->setPolygon(QPolygonF(bboxRect)); + box->highlightPolygonEdge->setPolygon(QPolygonF(edgeRect)); + + if (animate) + box->highlightPolygonEdge->setOpacity(0); + } + + if (animate) { + m_animFrame = 0; + m_animTimer->start(); + } +} + +void BoundingRectHighlighter::refresh() +{ + if (!m_boxes.isEmpty()) + highlightAll(true); +} + + +} // namespace QmlJSDebugger diff --git a/share/qtcreator/qml/qmljsdebugger/editor/boundingrecthighlighter.h b/share/qtcreator/qml/qmljsdebugger/editor/boundingrecthighlighter.h new file mode 100644 index 0000000000..2463d78d2c --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/boundingrecthighlighter.h @@ -0,0 +1,78 @@ +#ifndef BOUNDINGRECTHIGHLIGHTER_H +#define BOUNDINGRECTHIGHLIGHTER_H + +#include <QObject> +#include <QWeakPointer> + +#include "layeritem.h" + +QT_FORWARD_DECLARE_CLASS(QGraphicsItem); +QT_FORWARD_DECLARE_CLASS(QPainter); +QT_FORWARD_DECLARE_CLASS(QWidget); +QT_FORWARD_DECLARE_CLASS(QStyleOptionGraphicsItem); +QT_FORWARD_DECLARE_CLASS(QTimer); + +namespace QmlJSDebugger { + +class QDeclarativeViewObserver; +class BoundingBox; + +class BoundingRectHighlighter : public LayerItem +{ + Q_OBJECT +public: + explicit BoundingRectHighlighter(QDeclarativeViewObserver *view); + ~BoundingRectHighlighter(); + void clear(); + void highlight(QList<QGraphicsObject*> items); + void highlight(QGraphicsObject* item); + +private slots: + void refresh(); + void animTimeout(); + void itemDestroyed(QObject *); + +private: + BoundingBox *boxFor(QGraphicsObject *item) const; + void highlightAll(bool animate); + BoundingBox *createBoundingBox(QGraphicsObject *itemToHighlight); + void removeBoundingBox(BoundingBox *box); + void freeBoundingBox(BoundingBox *box); + +private: + Q_DISABLE_COPY(BoundingRectHighlighter); + + QDeclarativeViewObserver *m_view; + QList<BoundingBox* > m_boxes; + QList<BoundingBox* > m_freeBoxes; + QTimer *m_animTimer; + qreal m_animScale; + int m_animFrame; + +}; + +class BoundingBox : public QObject +{ + Q_OBJECT +public: + explicit BoundingBox(QGraphicsObject *itemToHighlight, QGraphicsItem *parentItem, QObject *parent = 0); + ~BoundingBox(); + QWeakPointer<QGraphicsObject> highlightedObject; + QGraphicsPolygonItem *highlightPolygon; + QGraphicsPolygonItem *highlightPolygonEdge; + +private: + Q_DISABLE_COPY(BoundingBox); + +}; + +class BoundingBoxPolygonItem : public QGraphicsPolygonItem +{ +public: + explicit BoundingBoxPolygonItem(QGraphicsItem *item); + int type() const; +}; + +} // namespace QmlJSDebugger + +#endif // BOUNDINGRECTHIGHLIGHTER_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/colorpickertool.cpp b/share/qtcreator/qml/qmljsdebugger/editor/colorpickertool.cpp new file mode 100644 index 0000000000..bf52075fc7 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/colorpickertool.cpp @@ -0,0 +1,89 @@ +#include "colorpickertool.h" +#include "qdeclarativeviewobserver.h" + +#include <QMouseEvent> +#include <QKeyEvent> +#include <QRectF> +#include <QRgb> +#include <QImage> +#include <QApplication> +#include <QPalette> + +namespace QmlJSDebugger { + +ColorPickerTool::ColorPickerTool(QDeclarativeViewObserver *view) : + AbstractFormEditorTool(view) +{ + m_selectedColor.setRgb(0,0,0); +} + +ColorPickerTool::~ColorPickerTool() +{ + +} + +void ColorPickerTool::mousePressEvent(QMouseEvent * /*event*/) +{ +} + +void ColorPickerTool::mouseMoveEvent(QMouseEvent *event) +{ + pickColor(event->pos()); +} + +void ColorPickerTool::mouseReleaseEvent(QMouseEvent *event) +{ + pickColor(event->pos()); +} + +void ColorPickerTool::mouseDoubleClickEvent(QMouseEvent * /*event*/) +{ +} + + +void ColorPickerTool::hoverMoveEvent(QMouseEvent * /*event*/) +{ +} + +void ColorPickerTool::keyPressEvent(QKeyEvent * /*event*/) +{ +} + +void ColorPickerTool::keyReleaseEvent(QKeyEvent * /*keyEvent*/) +{ +} +void ColorPickerTool::wheelEvent(QWheelEvent * /*event*/) +{ +} + +void ColorPickerTool::itemsAboutToRemoved(const QList<QGraphicsItem*> &/*itemList*/) +{ +} + +void ColorPickerTool::clear() +{ + view()->setCursor(Qt::CrossCursor); +} + +void ColorPickerTool::selectedItemsChanged(const QList<QGraphicsItem*> &/*itemList*/) +{ +} + +void ColorPickerTool::pickColor(const QPoint &pos) +{ + QRgb fillColor = view()->backgroundBrush().color().rgb(); + if (view()->backgroundBrush().style() == Qt::NoBrush) + fillColor = view()->palette().color(QPalette::Base).rgb(); + + QRectF target(0,0, 1, 1); + QRect source(pos.x(), pos.y(), 1, 1); + QImage img(1, 1, QImage::Format_ARGB32); + img.fill(fillColor); + QPainter painter(&img); + view()->render(&painter, target, source); + m_selectedColor = QColor::fromRgb(img.pixel(0, 0)); + + emit selectedColorChanged(m_selectedColor); +} + +} // namespace QmlJSDebugger diff --git a/share/qtcreator/qml/qmljsdebugger/editor/colorpickertool.h b/share/qtcreator/qml/qmljsdebugger/editor/colorpickertool.h new file mode 100644 index 0000000000..748ad581aa --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/colorpickertool.h @@ -0,0 +1,53 @@ +#ifndef COLORPICKERTOOL_H +#define COLORPICKERTOOL_H + +#include "abstractformeditortool.h" + +#include <QColor> + +QT_FORWARD_DECLARE_CLASS(QPoint); + +namespace QmlJSDebugger { + +class ColorPickerTool : public AbstractFormEditorTool +{ + Q_OBJECT +public: + explicit ColorPickerTool(QDeclarativeViewObserver *view); + + virtual ~ColorPickerTool(); + + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); + + void hoverMoveEvent(QMouseEvent *event); + + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *keyEvent); + + void wheelEvent(QWheelEvent *event); + + void itemsAboutToRemoved(const QList<QGraphicsItem*> &itemList); + + void clear(); + +signals: + void selectedColorChanged(const QColor &color); + +protected: + + void selectedItemsChanged(const QList<QGraphicsItem*> &itemList); + +private: + void pickColor(const QPoint &pos); + +private: + QColor m_selectedColor; + +}; + +} // namespace QmlJSDebugger + +#endif // COLORPICKERTOOL_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/editor.pri b/share/qtcreator/qml/qmljsdebugger/editor/editor.pri new file mode 100644 index 0000000000..150ca7dd08 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/editor.pri @@ -0,0 +1,37 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/abstractformeditortool.h \ + $$PWD/selectiontool.h \ + $$PWD/layeritem.h \ + $$PWD/singleselectionmanipulator.h \ + $$PWD/rubberbandselectionmanipulator.h \ + $$PWD/selectionrectangle.h \ + $$PWD/selectionindicator.h \ + $$PWD/boundingrecthighlighter.h \ + $$PWD/subcomponenteditortool.h \ + $$PWD/subcomponentmasklayeritem.h \ + $$PWD/zoomtool.h \ + $$PWD/colorpickertool.h \ + $$PWD/qmltoolbar.h \ + $$PWD/toolbarcolorbox.h + +SOURCES += \ + $$PWD/abstractformeditortool.cpp \ + $$PWD/selectiontool.cpp \ + $$PWD/layeritem.cpp \ + $$PWD/singleselectionmanipulator.cpp \ + $$PWD/rubberbandselectionmanipulator.cpp \ + $$PWD/selectionrectangle.cpp \ + $$PWD/selectionindicator.cpp \ + $$PWD/boundingrecthighlighter.cpp \ + $$PWD/subcomponenteditortool.cpp \ + $$PWD/subcomponentmasklayeritem.cpp \ + $$PWD/zoomtool.cpp \ + $$PWD/colorpickertool.cpp \ + $$PWD/qmltoolbar.cpp \ + $$PWD/toolbarcolorbox.cpp + +RESOURCES += $$PWD/editor.qrc + +DEFINES += QWEAKPOINTER_ENABLE_ARROW diff --git a/share/qtcreator/qml/qmljsdebugger/editor/editor.qrc b/share/qtcreator/qml/qmljsdebugger/editor/editor.qrc new file mode 100644 index 0000000000..77744d57bb --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/editor.qrc @@ -0,0 +1,24 @@ +<RCC> + <qresource prefix="/qml"> + <file>images/resize_handle.png</file> + <file>images/select.png</file> + <file>images/select-marquee.png</file> + <file>images/color-picker.png</file> + <file>images/play.png</file> + <file>images/pause.png</file> + <file>images/from-qml.png</file> + <file>images/to-qml.png</file> + <file>images/color-picker-hicontrast.png</file> + <file>images/zoom.png</file> + <file>images/color-picker-24.png</file> + <file>images/from-qml-24.png</file> + <file>images/pause-24.png</file> + <file>images/play-24.png</file> + <file>images/to-qml-24.png</file> + <file>images/zoom-24.png</file> + <file>images/select-24.png</file> + <file>images/select-marquee-24.png</file> + <file>images/observermode.png</file> + <file>images/observermode-24.png</file> + </qresource> +</RCC> diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/color-picker-24.png b/share/qtcreator/qml/qmljsdebugger/editor/images/color-picker-24.png Binary files differnew file mode 100644 index 0000000000..cff47212a4 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/color-picker-24.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/color-picker-hicontrast.png b/share/qtcreator/qml/qmljsdebugger/editor/images/color-picker-hicontrast.png Binary files differnew file mode 100644 index 0000000000..b953d08a68 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/color-picker-hicontrast.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/color-picker.png b/share/qtcreator/qml/qmljsdebugger/editor/images/color-picker.png Binary files differnew file mode 100644 index 0000000000..026c31b3e1 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/color-picker.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/from-qml-24.png b/share/qtcreator/qml/qmljsdebugger/editor/images/from-qml-24.png Binary files differnew file mode 100644 index 0000000000..0ad21f3dbb --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/from-qml-24.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/from-qml.png b/share/qtcreator/qml/qmljsdebugger/editor/images/from-qml.png Binary files differnew file mode 100644 index 0000000000..666382c06d --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/from-qml.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/observermode-24.png b/share/qtcreator/qml/qmljsdebugger/editor/images/observermode-24.png Binary files differnew file mode 100644 index 0000000000..5e74d867c0 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/observermode-24.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/observermode.png b/share/qtcreator/qml/qmljsdebugger/editor/images/observermode.png Binary files differnew file mode 100644 index 0000000000..daed21c944 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/observermode.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/pause-24.png b/share/qtcreator/qml/qmljsdebugger/editor/images/pause-24.png Binary files differnew file mode 100644 index 0000000000..d9a2f6f814 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/pause-24.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/pause.png b/share/qtcreator/qml/qmljsdebugger/editor/images/pause.png Binary files differnew file mode 100644 index 0000000000..114d89b12b --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/pause.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/play-24.png b/share/qtcreator/qml/qmljsdebugger/editor/images/play-24.png Binary files differnew file mode 100644 index 0000000000..e2b9fbcf51 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/play-24.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/play.png b/share/qtcreator/qml/qmljsdebugger/editor/images/play.png Binary files differnew file mode 100644 index 0000000000..011598a746 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/play.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/reload.png b/share/qtcreator/qml/qmljsdebugger/editor/images/reload.png Binary files differnew file mode 100644 index 0000000000..7042bec9ae --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/reload.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/resize_handle.png b/share/qtcreator/qml/qmljsdebugger/editor/images/resize_handle.png Binary files differnew file mode 100644 index 0000000000..2934f25b74 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/resize_handle.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/select-24.png b/share/qtcreator/qml/qmljsdebugger/editor/images/select-24.png Binary files differnew file mode 100644 index 0000000000..5388a9d16a --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/select-24.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/select-marquee-24.png b/share/qtcreator/qml/qmljsdebugger/editor/images/select-marquee-24.png Binary files differnew file mode 100644 index 0000000000..0111ddae45 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/select-marquee-24.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/select-marquee.png b/share/qtcreator/qml/qmljsdebugger/editor/images/select-marquee.png Binary files differnew file mode 100644 index 0000000000..92fe40d1ad --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/select-marquee.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/select.png b/share/qtcreator/qml/qmljsdebugger/editor/images/select.png Binary files differnew file mode 100644 index 0000000000..672285582b --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/select.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/to-qml-24.png b/share/qtcreator/qml/qmljsdebugger/editor/images/to-qml-24.png Binary files differnew file mode 100644 index 0000000000..b72450ddd4 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/to-qml-24.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/to-qml.png b/share/qtcreator/qml/qmljsdebugger/editor/images/to-qml.png Binary files differnew file mode 100644 index 0000000000..2ab951fd08 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/to-qml.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/zoom-24.png b/share/qtcreator/qml/qmljsdebugger/editor/images/zoom-24.png Binary files differnew file mode 100644 index 0000000000..03462001ec --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/zoom-24.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/images/zoom.png b/share/qtcreator/qml/qmljsdebugger/editor/images/zoom.png Binary files differnew file mode 100644 index 0000000000..17f0da6d64 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/images/zoom.png diff --git a/share/qtcreator/qml/qmljsdebugger/editor/layeritem.cpp b/share/qtcreator/qml/qmljsdebugger/editor/layeritem.cpp new file mode 100644 index 0000000000..285b3e3074 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/layeritem.cpp @@ -0,0 +1,78 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 "layeritem.h" +#include "qmlobserverconstants.h" + +#include <QGraphicsScene> + +namespace QmlJSDebugger { + +LayerItem::LayerItem(QGraphicsScene* scene) + : QGraphicsObject() +{ + scene->addItem(this); + setZValue(1); + setFlag(QGraphicsItem::ItemIsMovable, false); +} + +LayerItem::~LayerItem() +{ +} + +void LayerItem::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) +{ +} + +int LayerItem::type() const +{ + return Constants::EditorItemType; +} + +QRectF LayerItem::boundingRect() const +{ + return childrenBoundingRect(); +} + +QList<QGraphicsItem*> LayerItem::findAllChildItems() const +{ + return findAllChildItems(this); +} + +QList<QGraphicsItem*> LayerItem::findAllChildItems(const QGraphicsItem *item) const +{ + QList<QGraphicsItem*> itemList(item->childItems()); + + foreach (QGraphicsItem *childItem, item->childItems()) + itemList += findAllChildItems(childItem); + + return itemList; +} + +} // namespace QmlJSDebugger diff --git a/share/qtcreator/qml/qmljsdebugger/editor/layeritem.h b/share/qtcreator/qml/qmljsdebugger/editor/layeritem.h new file mode 100644 index 0000000000..c699cb8bc9 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/layeritem.h @@ -0,0 +1,57 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 LAYERITEM_H +#define LAYERITEM_H + +#include <QGraphicsObject> +#include <QWeakPointer> + +namespace QmlJSDebugger { + +class FormEditorScene; + +class LayerItem : public QGraphicsObject +{ +public: + LayerItem(QGraphicsScene* scene); + ~LayerItem(); + void paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ); + QRectF boundingRect() const; + int type() const; + + QList<QGraphicsItem*> findAllChildItems() const; + +protected: + QList<QGraphicsItem*> findAllChildItems(const QGraphicsItem *item) const; +}; + +} + +#endif // LAYERITEM_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/qmltoolbar.cpp b/share/qtcreator/qml/qmljsdebugger/editor/qmltoolbar.cpp new file mode 100644 index 0000000000..355a13b6c3 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/qmltoolbar.cpp @@ -0,0 +1,323 @@ +#include <QLabel> +#include <QIcon> +#include <QAction> +#include <QMenu> + +#include "qmltoolbar.h" +#include "toolbarcolorbox.h" + +#include <QDebug> + +namespace QmlJSDebugger { + +QmlToolbar::QmlToolbar(QWidget *parent) + : QToolBar(parent) + , m_emitSignals(true) + , m_isRunning(false) + , m_animationSpeed(1.0f) + , m_previousAnimationSpeed(0.0f) + , ui(new Ui) +{ + ui->playIcon = QIcon(QLatin1String(":/qml/images/play-24.png")); + ui->pauseIcon = QIcon(QLatin1String(":/qml/images/pause-24.png")); + + ui->designmode = new QAction(QIcon(QLatin1String(":/qml/images/observermode-24.png")), tr("Observer Mode"), this); + ui->play = new QAction(ui->pauseIcon, tr("Play/Pause Animations"), this); + ui->select = new QAction(QIcon(QLatin1String(":/qml/images/select-24.png")), tr("Select"), this); + ui->selectMarquee = new QAction(QIcon(QLatin1String(":/qml/images/select-marquee-24.png")), tr("Select (Marquee)"), this); + ui->zoom = new QAction(QIcon(QLatin1String(":/qml/images/zoom-24.png")), tr("Zoom"), this); + ui->colorPicker = new QAction(QIcon(QLatin1String(":/qml/images/color-picker-24.png")), tr("Color Picker"), this); + ui->toQml = new QAction(QIcon(QLatin1String(":/qml/images/to-qml-24.png")), tr("Apply Changes to QML Viewer"), this); + ui->fromQml = new QAction(QIcon(QLatin1String(":/qml/images/from-qml-24.png")), tr("Apply Changes to Document"), this); + ui->designmode->setCheckable(true); + ui->designmode->setChecked(false); + + ui->play->setCheckable(false); + ui->select->setCheckable(true); + ui->selectMarquee->setCheckable(true); + ui->zoom->setCheckable(true); + ui->colorPicker->setCheckable(true); + + setWindowTitle(tr("Tools")); + + addAction(ui->designmode); + addAction(ui->play); + addSeparator(); + + addAction(ui->select); + // disabled because multi selection does not do anything useful without design mode + //addAction(ui->selectMarquee); + addSeparator(); + addAction(ui->zoom); + addAction(ui->colorPicker); + //addAction(ui->fromQml); + + ui->colorBox = new ToolBarColorBox(this); + ui->colorBox->setMinimumSize(24, 24); + ui->colorBox->setMaximumSize(28, 28); + ui->colorBox->setColor(Qt::black); + addWidget(ui->colorBox); + + setWindowFlags(Qt::Tool); + + QMenu *playSpeedMenu = new QMenu(this); + QActionGroup *playSpeedMenuActions = new QActionGroup(this); + playSpeedMenuActions->setExclusive(true); + playSpeedMenu->addAction(tr("Animation Speed")); + playSpeedMenu->addSeparator(); + ui->defaultAnimSpeedAction = playSpeedMenu->addAction(tr("1x"), this, SLOT(changeToDefaultAnimSpeed())); + ui->defaultAnimSpeedAction->setCheckable(true); + ui->defaultAnimSpeedAction->setChecked(true); + playSpeedMenuActions->addAction(ui->defaultAnimSpeedAction); + + ui->halfAnimSpeedAction = playSpeedMenu->addAction(tr("0.5x"), this, SLOT(changeToHalfAnimSpeed())); + ui->halfAnimSpeedAction->setCheckable(true); + playSpeedMenuActions->addAction(ui->halfAnimSpeedAction); + + ui->fourthAnimSpeedAction = playSpeedMenu->addAction(tr("0.25x"), this, SLOT(changeToFourthAnimSpeed())); + ui->fourthAnimSpeedAction->setCheckable(true); + playSpeedMenuActions->addAction(ui->fourthAnimSpeedAction); + + ui->eighthAnimSpeedAction = playSpeedMenu->addAction(tr("0.125x"), this, SLOT(changeToEighthAnimSpeed())); + ui->eighthAnimSpeedAction->setCheckable(true); + playSpeedMenuActions->addAction(ui->eighthAnimSpeedAction); + + ui->tenthAnimSpeedAction = playSpeedMenu->addAction(tr("0.1x"), this, SLOT(changeToTenthAnimSpeed())); + ui->tenthAnimSpeedAction->setCheckable(true); + playSpeedMenuActions->addAction(ui->tenthAnimSpeedAction); + + ui->menuPauseAction = playSpeedMenu->addAction(tr("Pause"), this, SLOT(updatePauseAction())); + ui->menuPauseAction->setCheckable(true); + ui->menuPauseAction->setIcon(ui->pauseIcon); + playSpeedMenuActions->addAction(ui->menuPauseAction); + ui->play->setMenu(playSpeedMenu); + + connect(ui->designmode, SIGNAL(toggled(bool)), SLOT(setDesignModeBehaviorOnClick(bool))); + + connect(ui->colorPicker, SIGNAL(triggered()), SLOT(activateColorPickerOnClick())); + + connect(ui->play, SIGNAL(triggered()), SLOT(activatePlayOnClick())); + + connect(ui->zoom, SIGNAL(triggered()), SLOT(activateZoomOnClick())); + connect(ui->colorPicker, SIGNAL(triggered()), SLOT(activateColorPickerOnClick())); + connect(ui->select, SIGNAL(triggered()), SLOT(activateSelectToolOnClick())); + connect(ui->selectMarquee, SIGNAL(triggered()), SLOT(activateMarqueeSelectToolOnClick())); + + connect(ui->toQml, SIGNAL(triggered()), SLOT(activateToQml())); + connect(ui->fromQml, SIGNAL(triggered()), SLOT(activateFromQml())); +} + +QmlToolbar::~QmlToolbar() +{ + delete ui; +} + +void QmlToolbar::activateColorPicker() +{ + m_emitSignals = false; + activateColorPickerOnClick(); + m_emitSignals = true; +} + +void QmlToolbar::activateSelectTool() +{ + m_emitSignals = false; + activateSelectToolOnClick(); + m_emitSignals = true; +} + +void QmlToolbar::activateMarqueeSelectTool() +{ + m_emitSignals = false; + activateMarqueeSelectToolOnClick(); + m_emitSignals = true; +} + +void QmlToolbar::activateZoom() +{ + m_emitSignals = false; + activateZoomOnClick(); + m_emitSignals = true; +} + +void QmlToolbar::setAnimationSpeed(qreal slowdownFactor) +{ + m_emitSignals = false; + if (slowdownFactor != 0) { + m_animationSpeed = slowdownFactor; + + if (slowdownFactor == 1.0f) { + ui->defaultAnimSpeedAction->setChecked(true); + } else if (slowdownFactor == 2.0f) { + ui->halfAnimSpeedAction->setChecked(true); + } else if (slowdownFactor == 4.0f) { + ui->fourthAnimSpeedAction->setChecked(true); + } else if (slowdownFactor == 8.0f) { + ui->eighthAnimSpeedAction->setChecked(true); + } else if (slowdownFactor == 10.0f) { + ui->tenthAnimSpeedAction->setChecked(true); + } + updatePlayAction(); + } else { + ui->menuPauseAction->setChecked(true); + updatePauseAction(); + } + + m_emitSignals = true; +} + +void QmlToolbar::changeToDefaultAnimSpeed() +{ + m_animationSpeed = 1.0f; + updatePlayAction(); +} + +void QmlToolbar::changeToHalfAnimSpeed() +{ + m_animationSpeed = 2.0f; + updatePlayAction(); +} + +void QmlToolbar::changeToFourthAnimSpeed() +{ + m_animationSpeed = 4.0f; + updatePlayAction(); +} + +void QmlToolbar::changeToEighthAnimSpeed() +{ + m_animationSpeed = 8.0f; + updatePlayAction(); +} + +void QmlToolbar::changeToTenthAnimSpeed() +{ + m_animationSpeed = 10.0f; + updatePlayAction(); +} + + +void QmlToolbar::setDesignModeBehavior(bool inDesignMode) +{ + m_emitSignals = false; + ui->designmode->setChecked(inDesignMode); + setDesignModeBehaviorOnClick(inDesignMode); + m_emitSignals = true; +} + +void QmlToolbar::setDesignModeBehaviorOnClick(bool checked) +{ + ui->play->setEnabled(checked); + ui->select->setEnabled(checked); + ui->selectMarquee->setEnabled(checked); + ui->zoom->setEnabled(checked); + ui->colorPicker->setEnabled(checked); + ui->toQml->setEnabled(checked); + ui->fromQml->setEnabled(checked); + + if (m_emitSignals) + emit designModeBehaviorChanged(checked); +} + +void QmlToolbar::setColorBoxColor(const QColor &color) +{ + ui->colorBox->setColor(color); +} + +void QmlToolbar::activatePlayOnClick() +{ + if (m_isRunning) { + updatePauseAction(); + } else { + updatePlayAction(); + } +} + +void QmlToolbar::updatePlayAction() +{ + m_isRunning = true; + ui->play->setIcon(ui->pauseIcon); + if (m_animationSpeed != m_previousAnimationSpeed) + m_previousAnimationSpeed = m_animationSpeed; + + if (m_emitSignals) + emit animationSpeedChanged(m_animationSpeed); +} + +void QmlToolbar::updatePauseAction() +{ + m_isRunning = false; + ui->play->setIcon(ui->playIcon); + if (m_emitSignals) + emit animationSpeedChanged(0.0f); +} + +void QmlToolbar::activateColorPickerOnClick() +{ + ui->zoom->setChecked(false); + ui->select->setChecked(false); + ui->selectMarquee->setChecked(false); + + ui->colorPicker->setChecked(true); + if (m_activeTool != Constants::ColorPickerMode) { + m_activeTool = Constants::ColorPickerMode; + if (m_emitSignals) + emit colorPickerSelected(); + } +} + +void QmlToolbar::activateSelectToolOnClick() +{ + ui->zoom->setChecked(false); + ui->selectMarquee->setChecked(false); + ui->colorPicker->setChecked(false); + + ui->select->setChecked(true); + if (m_activeTool != Constants::SelectionToolMode) { + m_activeTool = Constants::SelectionToolMode; + if (m_emitSignals) + emit selectToolSelected(); + } +} + +void QmlToolbar::activateMarqueeSelectToolOnClick() +{ + ui->zoom->setChecked(false); + ui->select->setChecked(false); + ui->colorPicker->setChecked(false); + + ui->selectMarquee->setChecked(true); + if (m_activeTool != Constants::MarqueeSelectionToolMode) { + m_activeTool = Constants::MarqueeSelectionToolMode; + if (m_emitSignals) + emit marqueeSelectToolSelected(); + } +} + +void QmlToolbar::activateZoomOnClick() +{ + ui->select->setChecked(false); + ui->selectMarquee->setChecked(false); + ui->colorPicker->setChecked(false); + + ui->zoom->setChecked(true); + if (m_activeTool != Constants::ZoomMode) { + m_activeTool = Constants::ZoomMode; + if (m_emitSignals) + emit zoomToolSelected(); + } +} + +void QmlToolbar::activateFromQml() +{ + if (m_emitSignals) + emit applyChangesFromQmlFileSelected(); +} + +void QmlToolbar::activateToQml() +{ + if (m_emitSignals) + emit applyChangesToQmlFileSelected(); +} + +} diff --git a/share/qtcreator/qml/qmljsdebugger/editor/qmltoolbar.h b/share/qtcreator/qml/qmljsdebugger/editor/qmltoolbar.h new file mode 100644 index 0000000000..77685b9b4f --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/qmltoolbar.h @@ -0,0 +1,96 @@ +#ifndef QMLTOOLBAR_H +#define QMLTOOLBAR_H + +#include <QToolBar> +#include <QIcon> +#include "qmlobserverconstants.h" + +namespace QmlJSDebugger { + +class ToolBarColorBox; + +class QmlToolbar : public QToolBar +{ + Q_OBJECT + +public: + explicit QmlToolbar(QWidget *parent = 0); + ~QmlToolbar(); + +public slots: + void setDesignModeBehavior(bool inDesignMode); + void setColorBoxColor(const QColor &color); + void activateColorPicker(); + void activateSelectTool(); + void activateMarqueeSelectTool(); + void activateZoom(); + void setAnimationSpeed(qreal slowdownFactor = 0.0f); + +signals: + void animationSpeedChanged(qreal slowdownFactor = 1.0f); + + void designModeBehaviorChanged(bool inDesignMode); + void colorPickerSelected(); + void selectToolSelected(); + void marqueeSelectToolSelected(); + void zoomToolSelected(); + + void applyChangesToQmlFileSelected(); + void applyChangesFromQmlFileSelected(); + +private slots: + void setDesignModeBehaviorOnClick(bool inDesignMode); + void activatePlayOnClick(); + void activateColorPickerOnClick(); + void activateSelectToolOnClick(); + void activateMarqueeSelectToolOnClick(); + void activateZoomOnClick(); + + void activateFromQml(); + void activateToQml(); + + void changeToDefaultAnimSpeed(); + void changeToHalfAnimSpeed(); + void changeToFourthAnimSpeed(); + void changeToEighthAnimSpeed(); + void changeToTenthAnimSpeed(); + + void updatePlayAction(); + void updatePauseAction(); + +private: + class Ui { + public: + QAction *designmode; + QAction *play; + QAction *select; + QAction *selectMarquee; + QAction *zoom; + QAction *colorPicker; + QAction *toQml; + QAction *fromQml; + QIcon playIcon; + QIcon pauseIcon; + ToolBarColorBox *colorBox; + + QAction *defaultAnimSpeedAction; + QAction *halfAnimSpeedAction; + QAction *fourthAnimSpeedAction; + QAction *eighthAnimSpeedAction; + QAction *tenthAnimSpeedAction; + QAction *menuPauseAction; + }; + + bool m_emitSignals; + bool m_isRunning; + qreal m_animationSpeed; + qreal m_previousAnimationSpeed; + + Constants::DesignTool m_activeTool; + + Ui *ui; +}; + +} + +#endif // QMLTOOLBAR_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/rubberbandselectionmanipulator.cpp b/share/qtcreator/qml/qmljsdebugger/editor/rubberbandselectionmanipulator.cpp new file mode 100644 index 0000000000..379ba98c44 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/rubberbandselectionmanipulator.cpp @@ -0,0 +1,144 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 "rubberbandselectionmanipulator.h" +#include "qdeclarativeviewobserver_p.h" + +#include <QDebug> + +namespace QmlJSDebugger { + +RubberBandSelectionManipulator::RubberBandSelectionManipulator(QGraphicsObject *layerItem, QDeclarativeViewObserver *editorView) + : m_selectionRectangleElement(layerItem), + m_editorView(editorView), + m_beginFormEditorItem(0), + m_isActive(false) +{ + m_selectionRectangleElement.hide(); +} + +void RubberBandSelectionManipulator::clear() +{ + m_selectionRectangleElement.clear(); + m_isActive = false; + m_beginPoint = QPointF(); + m_itemList.clear(); + m_oldSelectionList.clear(); +} + +QGraphicsItem *RubberBandSelectionManipulator::topFormEditorItem(const QList<QGraphicsItem*> &itemList) +{ + if (itemList.isEmpty()) + return 0; + + return itemList.first(); +} + +void RubberBandSelectionManipulator::begin(const QPointF& beginPoint) +{ + m_beginPoint = beginPoint; + m_selectionRectangleElement.setRect(m_beginPoint, m_beginPoint); + m_selectionRectangleElement.show(); + m_isActive = true; + m_beginFormEditorItem = topFormEditorItem(QDeclarativeViewObserverPrivate::get(m_editorView)->selectableItems(beginPoint)); + m_oldSelectionList = m_editorView->selectedItems(); +} + +void RubberBandSelectionManipulator::update(const QPointF& updatePoint) +{ + m_selectionRectangleElement.setRect(m_beginPoint, updatePoint); +} + +void RubberBandSelectionManipulator::end() +{ + m_oldSelectionList.clear(); + m_selectionRectangleElement.hide(); + m_isActive = false; +} + +void RubberBandSelectionManipulator::select(SelectionType selectionType) +{ + QList<QGraphicsItem*> itemList = QDeclarativeViewObserverPrivate::get(m_editorView)->selectableItems(m_selectionRectangleElement.rect(), + Qt::IntersectsItemShape); + QList<QGraphicsItem*> newSelectionList; + + foreach (QGraphicsItem* item, itemList) { + if (item + && item->parentItem() + && !newSelectionList.contains(item) + //&& m_beginFormEditorItem->childItems().contains(item) // TODO activate this test + ) + { + newSelectionList.append(item); + } + } + + if (newSelectionList.isEmpty() && m_beginFormEditorItem) + newSelectionList.append(m_beginFormEditorItem); + + QList<QGraphicsItem*> resultList; + + switch(selectionType) { + case AddToSelection: { + resultList.append(m_oldSelectionList); + resultList.append(newSelectionList); + } + break; + case ReplaceSelection: { + resultList.append(newSelectionList); + } + break; + case RemoveFromSelection: { + QSet<QGraphicsItem*> oldSelectionSet(m_oldSelectionList.toSet()); + QSet<QGraphicsItem*> newSelectionSet(newSelectionList.toSet()); + resultList.append(oldSelectionSet.subtract(newSelectionSet).toList()); + } + } + + m_editorView->setSelectedItems(resultList); +} + + +void RubberBandSelectionManipulator::setItems(const QList<QGraphicsItem*> &itemList) +{ + m_itemList = itemList; +} + +QPointF RubberBandSelectionManipulator::beginPoint() const +{ + return m_beginPoint; +} + +bool RubberBandSelectionManipulator::isActive() const +{ + return m_isActive; + +} + +} diff --git a/share/qtcreator/qml/qmljsdebugger/editor/rubberbandselectionmanipulator.h b/share/qtcreator/qml/qmljsdebugger/editor/rubberbandselectionmanipulator.h new file mode 100644 index 0000000000..e681569577 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/rubberbandselectionmanipulator.h @@ -0,0 +1,82 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 RUBBERBANDSELECTIONMANIPULATOR_H +#define RUBBERBANDSELECTIONMANIPULATOR_H + + +#include "selectionrectangle.h" + +namespace QmlJSDebugger { + +class QDeclarativeViewObserver; + +class RubberBandSelectionManipulator +{ +public: + enum SelectionType { + ReplaceSelection, + AddToSelection, + RemoveFromSelection + }; + + + RubberBandSelectionManipulator(QGraphicsObject *layerItem, QDeclarativeViewObserver *editorView); + + void setItems(const QList<QGraphicsItem*> &itemList); + + void begin(const QPointF& beginPoint); + void update(const QPointF& updatePoint); + void end(); + + void clear(); + + void select(SelectionType selectionType); + + QPointF beginPoint() const; + + bool isActive() const; + +protected: + QGraphicsItem *topFormEditorItem(const QList<QGraphicsItem*> &itemList); + + +private: + QList<QGraphicsItem*> m_itemList; + QList<QGraphicsItem*> m_oldSelectionList; + SelectionRectangle m_selectionRectangleElement; + QPointF m_beginPoint; + QDeclarativeViewObserver *m_editorView; + QGraphicsItem *m_beginFormEditorItem; + bool m_isActive; +}; + +} + +#endif // RUBBERBANDSELECTIONMANIPULATOR_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/selectionindicator.cpp b/share/qtcreator/qml/qmljsdebugger/editor/selectionindicator.cpp new file mode 100644 index 0000000000..5782f2a5ee --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/selectionindicator.cpp @@ -0,0 +1,127 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 "selectionindicator.h" +#include "qdeclarativeviewobserver_p.h" +#include "qmlobserverconstants.h" + +#include <QPen> +#include <cmath> +#include <QGraphicsScene> +#include <QDebug> + +namespace QmlJSDebugger { + +SelectionIndicator::SelectionIndicator(QDeclarativeViewObserver *editorView, QGraphicsObject *layerItem) + : m_layerItem(layerItem), m_view(editorView) +{ +} + +SelectionIndicator::~SelectionIndicator() +{ + clear(); +} + +void SelectionIndicator::show() +{ + foreach (QGraphicsPolygonItem *item, m_indicatorShapeHash.values()) + item->show(); +} + +void SelectionIndicator::hide() +{ + foreach (QGraphicsPolygonItem *item, m_indicatorShapeHash.values()) + item->hide(); +} + +void SelectionIndicator::clear() +{ + if (!m_layerItem.isNull()) { + QHashIterator<QGraphicsItem*, QGraphicsPolygonItem *> iter(m_indicatorShapeHash); + while(iter.hasNext()) { + iter.next(); + m_layerItem->scene()->removeItem(iter.value()); + delete iter.value(); + } + } + + m_indicatorShapeHash.clear(); + +} + +QPolygonF SelectionIndicator::addBoundingRectToPolygon(QGraphicsItem *item, QPolygonF &polygon) +{ + // ### remove this if statement when QTBUG-12172 gets fixed + if (item->boundingRect() != QRectF(0,0,0,0)) { + QPolygonF bounding = item->mapToScene(item->boundingRect()); + if (bounding.isClosed()) //avoid crashes if there is an infinite scale. + polygon = polygon.united(bounding); + } + + foreach(QGraphicsItem *child, item->childItems()) { + if (!QDeclarativeViewObserverPrivate::get(m_view)->isEditorItem(child)) + addBoundingRectToPolygon(child, polygon); + } + return polygon; +} + +void SelectionIndicator::setItems(const QList<QWeakPointer<QGraphicsObject> > &itemList) +{ + clear(); + + // set selections to also all children if they are not editor items + + foreach (QWeakPointer<QGraphicsObject> obj, itemList) { + if (obj.isNull()) + continue; + + QGraphicsItem *item = obj.data(); + + QGraphicsPolygonItem *newSelectionIndicatorGraphicsItem = new QGraphicsPolygonItem(m_layerItem.data()); + if (!m_indicatorShapeHash.contains(item)) { + m_indicatorShapeHash.insert(item, newSelectionIndicatorGraphicsItem); + + QPolygonF boundingShapeInSceneSpace; + addBoundingRectToPolygon(item, boundingShapeInSceneSpace); + + QRectF boundingRect = m_view->adjustToScreenBoundaries(boundingShapeInSceneSpace.boundingRect()); + QPolygonF boundingRectInLayerItemSpace = m_layerItem->mapFromScene(boundingRect); + + QPen pen; + pen.setColor(QColor(108, 141, 221)); + newSelectionIndicatorGraphicsItem->setData(Constants::EditorItemDataKey, QVariant(true)); + newSelectionIndicatorGraphicsItem->setFlag(QGraphicsItem::ItemIsSelectable, false); + newSelectionIndicatorGraphicsItem->setPolygon(boundingRectInLayerItemSpace); + newSelectionIndicatorGraphicsItem->setPen(pen); + } + } +} + +} //namespace QmlJSDebugger + diff --git a/share/qtcreator/qml/qmljsdebugger/editor/selectionindicator.h b/share/qtcreator/qml/qmljsdebugger/editor/selectionindicator.h new file mode 100644 index 0000000000..ecfeda86a0 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/selectionindicator.h @@ -0,0 +1,66 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 SELECTIONINDICATOR_H +#define SELECTIONINDICATOR_H + +#include <QWeakPointer> +#include <QGraphicsPolygonItem> +#include <QGraphicsObject> + +namespace QmlJSDebugger { + +class QDeclarativeViewObserver; + +class SelectionIndicator +{ +public: + SelectionIndicator(QDeclarativeViewObserver* editorView, QGraphicsObject *layerItem); + ~SelectionIndicator(); + + void show(); + void hide(); + + void clear(); + + void setItems(const QList<QWeakPointer<QGraphicsObject> > &itemList); + +private: + QPolygonF addBoundingRectToPolygon(QGraphicsItem *item, QPolygonF &polygon); + +private: + QHash<QGraphicsItem*, QGraphicsPolygonItem *> m_indicatorShapeHash; + QWeakPointer<QGraphicsObject> m_layerItem; + QDeclarativeViewObserver *m_view; + +}; + +} + +#endif // SELECTIONINDICATOR_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/selectionrectangle.cpp b/share/qtcreator/qml/qmljsdebugger/editor/selectionrectangle.cpp new file mode 100644 index 0000000000..dc8ee26cce --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/selectionrectangle.cpp @@ -0,0 +1,95 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 "selectionrectangle.h" +#include "qmlobserverconstants.h" + +#include <QPen> +#include <QGraphicsScene> +#include <QtDebug> +#include <cmath> +#include <QGraphicsScene> + +namespace QmlJSDebugger { + +class SelectionRectShape : public QGraphicsRectItem +{ +public: + SelectionRectShape(QGraphicsItem *parent = 0) : QGraphicsRectItem(parent) {} + int type() const { return Constants::EditorItemType; } +}; + +SelectionRectangle::SelectionRectangle(QGraphicsObject *layerItem) + : m_controlShape(new SelectionRectShape(layerItem)), + m_layerItem(layerItem) +{ + m_controlShape->setPen(QPen(Qt::black)); + m_controlShape->setBrush(QColor(128, 128, 128, 50)); +} + +SelectionRectangle::~SelectionRectangle() +{ + if (m_layerItem) + m_layerItem->scene()->removeItem(m_controlShape); +} + +void SelectionRectangle::clear() +{ + hide(); +} +void SelectionRectangle::show() +{ + m_controlShape->show(); +} + +void SelectionRectangle::hide() +{ + m_controlShape->hide(); +} + +QRectF SelectionRectangle::rect() const +{ + return m_controlShape->mapFromScene(m_controlShape->rect()).boundingRect(); +} + +void SelectionRectangle::setRect(const QPointF &firstPoint, + const QPointF &secondPoint) +{ + double firstX = std::floor(firstPoint.x()) + 0.5; + double firstY = std::floor(firstPoint.y()) + 0.5; + double secondX = std::floor(secondPoint.x()) + 0.5; + double secondY = std::floor(secondPoint.y()) + 0.5; + QPointF topLeftPoint(firstX < secondX ? firstX : secondX, firstY < secondY ? firstY : secondY); + QPointF bottomRightPoint(firstX > secondX ? firstX : secondX, firstY > secondY ? firstY : secondY); + + QRectF rect(topLeftPoint, bottomRightPoint); + m_controlShape->setRect(rect); +} + +} diff --git a/share/qtcreator/qml/qmljsdebugger/editor/selectionrectangle.h b/share/qtcreator/qml/qmljsdebugger/editor/selectionrectangle.h new file mode 100644 index 0000000000..03346d7bb9 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/selectionrectangle.h @@ -0,0 +1,62 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 SELECTIONRECTANGLE_H +#define SELECTIONRECTANGLE_H + +#include <QWeakPointer> +#include <QGraphicsRectItem> +#include <QGraphicsObject> + +namespace QmlJSDebugger { + +class SelectionRectangle +{ +public: + SelectionRectangle(QGraphicsObject *layerItem); + ~SelectionRectangle(); + + void show(); + void hide(); + + void clear(); + + void setRect(const QPointF &firstPoint, + const QPointF &secondPoint); + + QRectF rect() const; + +private: + QGraphicsRectItem *m_controlShape; + QWeakPointer<QGraphicsObject> m_layerItem; +}; + +} + +#endif // SELECTIONRECTANGLE_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/selectiontool.cpp b/share/qtcreator/qml/qmljsdebugger/editor/selectiontool.cpp new file mode 100644 index 0000000000..b677a10577 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/selectiontool.cpp @@ -0,0 +1,447 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 "selectiontool.h" +#include "layeritem.h" + +//#include "resizehandleitem.h" +#include "qdeclarativeviewobserver_p.h" + +#include <QDeclarativeEngine> + +#include <QApplication> +#include <QWheelEvent> +#include <QMouseEvent> +#include <QClipboard> +#include <QMenu> +#include <QAction> +#include <QDeclarativeItem> +#include <QGraphicsObject> + +#include <QDebug> + +namespace QmlJSDebugger { + +SelectionTool::SelectionTool(QDeclarativeViewObserver *editorView) + : AbstractFormEditorTool(editorView), + m_rubberbandSelectionMode(false), + m_rubberbandSelectionManipulator(QDeclarativeViewObserverPrivate::get(editorView)->manipulatorLayer, editorView), + m_singleSelectionManipulator(editorView), + m_selectionIndicator(editorView, QDeclarativeViewObserverPrivate::get(editorView)->manipulatorLayer), + //m_resizeIndicator(editorView->manipulatorLayer()), + m_selectOnlyContentItems(true) +{ + +} + +SelectionTool::~SelectionTool() +{ +} + +void SelectionTool::setRubberbandSelectionMode(bool value) +{ + m_rubberbandSelectionMode = value; +} + +SingleSelectionManipulator::SelectionType SelectionTool::getSelectionType(Qt::KeyboardModifiers modifiers) +{ + SingleSelectionManipulator::SelectionType selectionType = SingleSelectionManipulator::ReplaceSelection; + if (modifiers.testFlag(Qt::ControlModifier)) { + selectionType = SingleSelectionManipulator::RemoveFromSelection; + } else if (modifiers.testFlag(Qt::ShiftModifier)) { + selectionType = SingleSelectionManipulator::AddToSelection; + } + return selectionType; +} + +bool SelectionTool::alreadySelected(const QList<QGraphicsItem*> &itemList) const +{ + const QList<QGraphicsItem*> selectedItems = QDeclarativeViewObserverPrivate::get(observer())->selectedItems(); + + if (selectedItems.isEmpty()) + return false; + + foreach(QGraphicsItem *item, itemList) { + if (selectedItems.contains(item)) { + return true; + } + } + + return false; +} + +void SelectionTool::mousePressEvent(QMouseEvent *event) +{ + QList<QGraphicsItem*> itemList = QDeclarativeViewObserverPrivate::get(observer())->selectableItems(event->pos()); + SingleSelectionManipulator::SelectionType selectionType = getSelectionType(event->modifiers()); + + if (event->buttons() & Qt::LeftButton) { + m_mousePressTimer.start(); + + if (m_rubberbandSelectionMode) { + m_rubberbandSelectionManipulator.begin(event->pos()); + } else { + + if (itemList.isEmpty()) { + QDeclarativeViewObserverPrivate::get(observer())->setSelectedItems(itemList); + return; + } + + if ((selectionType == SingleSelectionManipulator::InvertSelection + || selectionType == SingleSelectionManipulator::ReplaceSelection) + && alreadySelected(itemList)) + { + //view()->changeToMoveTool(event->pos()); + return; + } + + QGraphicsItem* item = itemList.first(); + + if (item->children().isEmpty()) { + m_singleSelectionManipulator.begin(event->pos()); + m_singleSelectionManipulator.select(selectionType, m_selectOnlyContentItems); + } else { + m_mousePressTimer.start(); + + if (itemList.isEmpty()) { + observer()->setSelectedItems(itemList); + return; + } + + if (item->children().isEmpty()) { + m_singleSelectionManipulator.begin(event->pos()); + m_singleSelectionManipulator.select(selectionType, m_selectOnlyContentItems); + } else { + m_singleSelectionManipulator.begin(event->pos()); + m_singleSelectionManipulator.select(selectionType, m_selectOnlyContentItems); + m_singleSelectionManipulator.end(event->pos()); + //view()->changeToMoveTool(event->pos()); + } + + m_singleSelectionManipulator.begin(event->pos()); + m_singleSelectionManipulator.select(selectionType, m_selectOnlyContentItems); + m_singleSelectionManipulator.end(event->pos()); + //view()->changeToMoveTool(event->pos()); + + } + } + + } else if (event->buttons() & Qt::RightButton) { + createContextMenu(itemList, event->globalPos()); + } +} + +void SelectionTool::createContextMenu(QList<QGraphicsItem*> itemList, QPoint globalPos) +{ + if (!QDeclarativeViewObserverPrivate::get(observer())->mouseInsideContextItem()) + return; + + QMenu contextMenu; + connect(&contextMenu, SIGNAL(hovered(QAction*)), this, SLOT(contextMenuElementHovered(QAction*))); + + m_contextMenuItemList = itemList; + + contextMenu.addAction("Items"); + contextMenu.addSeparator(); + int shortcutKey = Qt::Key_1; + bool addKeySequence = true; + int i = 0; + + foreach(QGraphicsItem * const item, itemList) { + QString itemTitle = titleForItem(item); + QAction *elementAction = contextMenu.addAction(itemTitle, this, SLOT(contextMenuElementSelected())); + + if (observer()->selectedItems().contains(item)) { + QFont boldFont = elementAction->font(); + boldFont.setBold(true); + elementAction->setFont(boldFont); + } + + elementAction->setData(i); + if (addKeySequence) + elementAction->setShortcut(QKeySequence(shortcutKey)); + + shortcutKey++; + if (shortcutKey > Qt::Key_9) + addKeySequence = false; + + ++i; + } + // add root item separately +// QString itemTitle = QString(tr("%1")).arg(titleForItem(view()->currentRootItem())); +// contextMenu.addAction(itemTitle, this, SLOT(contextMenuElementSelected())); +// m_contextMenuItemList.append(view()->currentRootItem()); + + contextMenu.exec(globalPos); + m_contextMenuItemList.clear(); +} + +void SelectionTool::contextMenuElementSelected() +{ + QAction *senderAction = static_cast<QAction*>(sender()); + int itemListIndex = senderAction->data().toInt(); + if (itemListIndex >= 0 && itemListIndex < m_contextMenuItemList.length()) { + + QPointF updatePt(0, 0); + QGraphicsItem *item = m_contextMenuItemList.at(itemListIndex); + m_singleSelectionManipulator.begin(updatePt); + m_singleSelectionManipulator.select(SingleSelectionManipulator::InvertSelection, + QList<QGraphicsItem*>() << item, + false); + m_singleSelectionManipulator.end(updatePt); + enterContext(item); + } +} + +void SelectionTool::contextMenuElementHovered(QAction *action) +{ + int itemListIndex = action->data().toInt(); + if (itemListIndex >= 0 && itemListIndex < m_contextMenuItemList.length()) { + QGraphicsObject *item = m_contextMenuItemList.at(itemListIndex)->toGraphicsObject(); + QDeclarativeViewObserverPrivate::get(observer())->highlight(item); + } +} + +void SelectionTool::mouseMoveEvent(QMouseEvent *event) +{ + if (m_singleSelectionManipulator.isActive()) { + QPointF mouseMovementVector = m_singleSelectionManipulator.beginPoint() - event->pos(); + + if ((mouseMovementVector.toPoint().manhattanLength() > Constants::DragStartDistance) + && (m_mousePressTimer.elapsed() > Constants::DragStartTime)) + { + m_singleSelectionManipulator.end(event->pos()); + //view()->changeToMoveTool(m_singleSelectionManipulator.beginPoint()); + return; + } + } else if (m_rubberbandSelectionManipulator.isActive()) { + QPointF mouseMovementVector = m_rubberbandSelectionManipulator.beginPoint() - event->pos(); + + if ((mouseMovementVector.toPoint().manhattanLength() > Constants::DragStartDistance) + && (m_mousePressTimer.elapsed() > Constants::DragStartTime)) { + m_rubberbandSelectionManipulator.update(event->pos()); + + if (event->modifiers().testFlag(Qt::ControlModifier)) + m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::RemoveFromSelection); + else if (event->modifiers().testFlag(Qt::ShiftModifier)) + m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::AddToSelection); + else + m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::ReplaceSelection); + } + } +} + +void SelectionTool::hoverMoveEvent(QMouseEvent * event) +{ +// ### commented out until move tool is re-enabled +// QList<QGraphicsItem*> itemList = view()->items(event->pos()); +// if (!itemList.isEmpty() && !m_rubberbandSelectionMode) { +// +// foreach(QGraphicsItem *item, itemList) { +// if (item->type() == Constants::ResizeHandleItemType) { +// ResizeHandleItem* resizeHandle = ResizeHandleItem::fromGraphicsItem(item); +// if (resizeHandle) +// view()->changeTool(Constants::ResizeToolMode); +// return; +// } +// } +// if (topSelectedItemIsMovable(itemList)) +// view()->changeTool(Constants::MoveToolMode); +// } + QList<QGraphicsItem*> selectableItemList = QDeclarativeViewObserverPrivate::get(observer())->selectableItems(event->pos()); + if (!selectableItemList.isEmpty()) { + QGraphicsObject *item = selectableItemList.first()->toGraphicsObject(); + if (item) + QDeclarativeViewObserverPrivate::get(observer())->highlight(item); + + return; + } + + QDeclarativeViewObserverPrivate::get(observer())->clearHighlight(); +} + +void SelectionTool::mouseReleaseEvent(QMouseEvent *event) +{ + if (m_singleSelectionManipulator.isActive()) { + m_singleSelectionManipulator.end(event->pos()); + } + else if (m_rubberbandSelectionManipulator.isActive()) { + + QPointF mouseMovementVector = m_rubberbandSelectionManipulator.beginPoint() - event->pos(); + if (mouseMovementVector.toPoint().manhattanLength() < Constants::DragStartDistance) { + m_singleSelectionManipulator.begin(event->pos()); + + if (event->modifiers().testFlag(Qt::ControlModifier)) + m_singleSelectionManipulator.select(SingleSelectionManipulator::RemoveFromSelection, m_selectOnlyContentItems); + else if (event->modifiers().testFlag(Qt::ShiftModifier)) + m_singleSelectionManipulator.select(SingleSelectionManipulator::AddToSelection, m_selectOnlyContentItems); + else + m_singleSelectionManipulator.select(SingleSelectionManipulator::InvertSelection, m_selectOnlyContentItems); + + m_singleSelectionManipulator.end(event->pos()); + } else { + m_rubberbandSelectionManipulator.update(event->pos()); + + if (event->modifiers().testFlag(Qt::ControlModifier)) + m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::RemoveFromSelection); + else if (event->modifiers().testFlag(Qt::ShiftModifier)) + m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::AddToSelection); + else + m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::ReplaceSelection); + + m_rubberbandSelectionManipulator.end(); + } + } +} + +void SelectionTool::mouseDoubleClickEvent(QMouseEvent * /*event*/) +{ + +} + +void SelectionTool::keyPressEvent(QKeyEvent *event) +{ + switch(event->key()) { + case Qt::Key_Left: + case Qt::Key_Right: + case Qt::Key_Up: + case Qt::Key_Down: + // disabled for now, cannot move stuff yet. + //view()->changeTool(Constants::MoveToolMode); + //view()->currentTool()->keyPressEvent(event); + break; + } +} + +void SelectionTool::keyReleaseEvent(QKeyEvent * /*keyEvent*/) +{ + +} + +void SelectionTool::wheelEvent(QWheelEvent *event) +{ + if (event->orientation() == Qt::Horizontal || m_rubberbandSelectionMode) + return; + + QList<QGraphicsItem*> itemList = QDeclarativeViewObserverPrivate::get(observer())->selectableItems(event->pos()); + + int selectedIdx = 0; + if (!observer()->selectedItems().isEmpty()) { + selectedIdx = itemList.indexOf(observer()->selectedItems().first()); + if (selectedIdx >= 0) { + if (event->delta() > 0) { + selectedIdx++; + if (selectedIdx == itemList.length()) + selectedIdx = 0; + } else if (event->delta() < 0) { + selectedIdx--; + if (selectedIdx == -1) + selectedIdx = itemList.length() - 1; + } + } else { + selectedIdx = 0; + } + } + + QPointF updatePt(0, 0); + m_singleSelectionManipulator.begin(updatePt); + m_singleSelectionManipulator.select(SingleSelectionManipulator::ReplaceSelection, + QList<QGraphicsItem*>() << itemList.at(selectedIdx), + false); + m_singleSelectionManipulator.end(updatePt); + +} + +void SelectionTool::setSelectOnlyContentItems(bool selectOnlyContentItems) +{ + m_selectOnlyContentItems = selectOnlyContentItems; +} + +void SelectionTool::itemsAboutToRemoved(const QList<QGraphicsItem*> &/*itemList*/) +{ + +} + +void SelectionTool::clear() +{ + view()->setCursor(Qt::ArrowCursor); + m_rubberbandSelectionManipulator.clear(), + m_singleSelectionManipulator.clear(); + m_selectionIndicator.clear(); + //m_resizeIndicator.clear(); +} + +void SelectionTool::selectedItemsChanged(const QList<QGraphicsItem*> &itemList) +{ + foreach(QWeakPointer<QGraphicsObject> obj, m_selectedItemList) { + if (!obj.isNull()) { + disconnect(obj.data(), SIGNAL(xChanged()), this, SLOT(repaintBoundingRects())); + disconnect(obj.data(), SIGNAL(yChanged()), this, SLOT(repaintBoundingRects())); + disconnect(obj.data(), SIGNAL(widthChanged()), this, SLOT(repaintBoundingRects())); + disconnect(obj.data(), SIGNAL(heightChanged()), this, SLOT(repaintBoundingRects())); + disconnect(obj.data(), SIGNAL(rotationChanged()), this, SLOT(repaintBoundingRects())); + } + } + + QList<QGraphicsObject*> objects = toGraphicsObjectList(itemList); + m_selectedItemList.clear(); + + foreach(QGraphicsObject *obj, objects) { + m_selectedItemList.append(obj); + connect(obj, SIGNAL(xChanged()), this, SLOT(repaintBoundingRects())); + connect(obj, SIGNAL(yChanged()), this, SLOT(repaintBoundingRects())); + connect(obj, SIGNAL(widthChanged()), this, SLOT(repaintBoundingRects())); + connect(obj, SIGNAL(heightChanged()), this, SLOT(repaintBoundingRects())); + connect(obj, SIGNAL(rotationChanged()), this, SLOT(repaintBoundingRects())); + } + + m_selectionIndicator.setItems(m_selectedItemList); + //m_resizeIndicator.setItems(toGraphicsObjectList(itemList)); +} + +void SelectionTool::repaintBoundingRects() +{ + m_selectionIndicator.setItems(m_selectedItemList); +} + +void SelectionTool::selectUnderPoint(QMouseEvent *event) +{ + m_singleSelectionManipulator.begin(event->pos()); + + if (event->modifiers().testFlag(Qt::ControlModifier)) + m_singleSelectionManipulator.select(SingleSelectionManipulator::RemoveFromSelection, m_selectOnlyContentItems); + else if (event->modifiers().testFlag(Qt::ShiftModifier)) + m_singleSelectionManipulator.select(SingleSelectionManipulator::AddToSelection, m_selectOnlyContentItems); + else + m_singleSelectionManipulator.select(SingleSelectionManipulator::InvertSelection, m_selectOnlyContentItems); + + m_singleSelectionManipulator.end(event->pos()); +} + +} diff --git a/share/qtcreator/qml/qmljsdebugger/editor/selectiontool.h b/share/qtcreator/qml/qmljsdebugger/editor/selectiontool.h new file mode 100644 index 0000000000..63461da296 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/selectiontool.h @@ -0,0 +1,110 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 SELECTIONTOOL_H +#define SELECTIONTOOL_H + + +#include "abstractformeditortool.h" +#include "rubberbandselectionmanipulator.h" +#include "singleselectionmanipulator.h" +#include "selectionindicator.h" + +#include <QHash> +#include <QList> +#include <QTime> +#include <QAction> + +QT_FORWARD_DECLARE_CLASS(QGraphicsItem); +QT_FORWARD_DECLARE_CLASS(QMouseEvent); +QT_FORWARD_DECLARE_CLASS(QKeyEvent); + +namespace QmlJSDebugger { + +class SelectionTool : public AbstractFormEditorTool +{ + Q_OBJECT + +public: + SelectionTool(QDeclarativeViewObserver* editorView); + ~SelectionTool(); + + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); + void hoverMoveEvent(QMouseEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *keyEvent); + void wheelEvent(QWheelEvent *event); + + void itemsAboutToRemoved(const QList<QGraphicsItem*> &itemList); + // QVariant itemChange(const QList<QGraphicsItem*> &itemList, +// QGraphicsItem::GraphicsItemChange change, +// const QVariant &value ); + +// void update(); + + void clear(); + + void selectedItemsChanged(const QList<QGraphicsItem*> &itemList); + + void selectUnderPoint(QMouseEvent *event); + + void setSelectOnlyContentItems(bool selectOnlyContentItems); + + void setRubberbandSelectionMode(bool value); + +private slots: + void contextMenuElementSelected(); + void contextMenuElementHovered(QAction *action); + void repaintBoundingRects(); + +private: + void createContextMenu(QList<QGraphicsItem*> itemList, QPoint globalPos); + SingleSelectionManipulator::SelectionType getSelectionType(Qt::KeyboardModifiers modifiers); + bool alreadySelected(const QList<QGraphicsItem*> &itemList) const; + +private: + bool m_rubberbandSelectionMode; + RubberBandSelectionManipulator m_rubberbandSelectionManipulator; + SingleSelectionManipulator m_singleSelectionManipulator; + SelectionIndicator m_selectionIndicator; + //ResizeIndicator m_resizeIndicator; + QTime m_mousePressTimer; + bool m_selectOnlyContentItems; + + QList<QWeakPointer<QGraphicsObject> > m_selectedItemList; + + QList<QGraphicsItem*> m_contextMenuItemList; +}; + +} + +#endif // SELECTIONTOOL_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/singleselectionmanipulator.cpp b/share/qtcreator/qml/qmljsdebugger/editor/singleselectionmanipulator.cpp new file mode 100644 index 0000000000..d006481549 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/singleselectionmanipulator.cpp @@ -0,0 +1,134 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 "singleselectionmanipulator.h" +#include "qdeclarativeviewobserver.h" +#include "qdeclarativeviewobserver_p.h" +#include <QtDebug> + +namespace QmlJSDebugger { + +SingleSelectionManipulator::SingleSelectionManipulator(QDeclarativeViewObserver *editorView) + : m_editorView(editorView), + m_isActive(false) +{ +} + + +void SingleSelectionManipulator::begin(const QPointF &beginPoint) +{ + m_beginPoint = beginPoint; + m_isActive = true; + m_oldSelectionList = QDeclarativeViewObserverPrivate::get(m_editorView)->selectedItems(); +} + +void SingleSelectionManipulator::update(const QPointF &/*updatePoint*/) +{ + m_oldSelectionList.clear(); +} + +void SingleSelectionManipulator::clear() +{ + m_beginPoint = QPointF(); + m_oldSelectionList.clear(); +} + + +void SingleSelectionManipulator::end(const QPointF &/*updatePoint*/) +{ + m_oldSelectionList.clear(); + m_isActive = false; +} + +void SingleSelectionManipulator::select(SelectionType selectionType, const QList<QGraphicsItem*> &items, bool /*selectOnlyContentItems*/) +{ + QGraphicsItem *selectedItem = 0; + + foreach(QGraphicsItem* item, items) + { + //FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item); + if (item + /*&& !formEditorItem->qmlItemNode().isRootNode() + && (formEditorItem->qmlItemNode().hasShowContent() || !selectOnlyContentItems)*/) + { + selectedItem = item; + break; + } + } + + QList<QGraphicsItem*> resultList; + + switch(selectionType) { + case AddToSelection: { + resultList.append(m_oldSelectionList); + if (selectedItem && !m_oldSelectionList.contains(selectedItem)) + resultList.append(selectedItem); + } + break; + case ReplaceSelection: { + if (selectedItem) + resultList.append(selectedItem); + } + break; + case RemoveFromSelection: { + resultList.append(m_oldSelectionList); + if (selectedItem) + resultList.removeAll(selectedItem); + } + break; + case InvertSelection: { + if (selectedItem + && !m_oldSelectionList.contains(selectedItem)) + { + resultList.append(selectedItem); + } + } + } + + m_editorView->setSelectedItems(resultList); +} + +void SingleSelectionManipulator::select(SelectionType selectionType, bool selectOnlyContentItems) +{ + QList<QGraphicsItem*> itemList = QDeclarativeViewObserverPrivate::get(m_editorView)->selectableItems(m_beginPoint); + select(selectionType, itemList, selectOnlyContentItems); +} + + +bool SingleSelectionManipulator::isActive() const +{ + return m_isActive; +} + +QPointF SingleSelectionManipulator::beginPoint() const +{ + return m_beginPoint; +} + +} diff --git a/share/qtcreator/qml/qmljsdebugger/editor/singleselectionmanipulator.h b/share/qtcreator/qml/qmljsdebugger/editor/singleselectionmanipulator.h new file mode 100644 index 0000000000..e4ff0f346a --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/singleselectionmanipulator.h @@ -0,0 +1,76 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 SINGLESELECTIONMANIPULATOR_H +#define SINGLESELECTIONMANIPULATOR_H + +#include <QPointF> +#include <QList> + +QT_FORWARD_DECLARE_CLASS(QGraphicsItem); + +namespace QmlJSDebugger { + +class QDeclarativeViewObserver; + +class SingleSelectionManipulator +{ +public: + SingleSelectionManipulator(QDeclarativeViewObserver *editorView); + + enum SelectionType { + ReplaceSelection, + AddToSelection, + RemoveFromSelection, + InvertSelection + }; + + void begin(const QPointF& beginPoint); + void update(const QPointF& updatePoint); + void end(const QPointF& updatePoint); + + void select(SelectionType selectionType, const QList<QGraphicsItem*> &items, bool selectOnlyContentItems); + void select(SelectionType selectionType, bool selectOnlyContentItems); + + void clear(); + + QPointF beginPoint() const; + + bool isActive() const; + +private: + QList<QGraphicsItem*> m_oldSelectionList; + QPointF m_beginPoint; + QDeclarativeViewObserver *m_editorView; + bool m_isActive; +}; + +} + +#endif // SINGLESELECTIONMANIPULATOR_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/subcomponenteditortool.cpp b/share/qtcreator/qml/qmljsdebugger/editor/subcomponenteditortool.cpp new file mode 100644 index 0000000000..5089944ddb --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/subcomponenteditortool.cpp @@ -0,0 +1,320 @@ +#include "subcomponenteditortool.h" +#include "qdeclarativeviewobserver_p.h" +#include "subcomponentmasklayeritem.h" +#include "layeritem.h" + +#include <QGraphicsItem> +#include <QGraphicsObject> +#include <QTimer> +#include <QMouseEvent> +#include <QKeyEvent> + +#include <QDebug> + + +namespace QmlJSDebugger { + +const qreal MaxOpacity = 0.5f; + +SubcomponentEditorTool::SubcomponentEditorTool(QDeclarativeViewObserver *view) + : AbstractFormEditorTool(view), + m_animIncrement(0.05f), + m_animTimer(new QTimer(this)) +{ + m_mask = new SubcomponentMaskLayerItem(view, QDeclarativeViewObserverPrivate::get(view)->manipulatorLayer); + connect(m_animTimer, SIGNAL(timeout()), SLOT(animate())); + m_animTimer->setInterval(20); +} + +SubcomponentEditorTool::~SubcomponentEditorTool() +{ + +} + +void SubcomponentEditorTool::mousePressEvent(QMouseEvent * /*event*/) +{ + +} + +void SubcomponentEditorTool::mouseMoveEvent(QMouseEvent * /*event*/) +{ + +} + +bool SubcomponentEditorTool::containsCursor(const QPoint &mousePos) const +{ + if (!m_currentContext.size()) + return false; + + QPointF scenePos = view()->mapToScene(mousePos); + QRectF itemRect = m_currentContext.top()->boundingRect() | m_currentContext.top()->childrenBoundingRect(); + QRectF polyRect = m_currentContext.top()->mapToScene(itemRect).boundingRect(); + + return polyRect.contains(scenePos); +} + +void SubcomponentEditorTool::mouseReleaseEvent(QMouseEvent * /*event*/) +{ + +} + +void SubcomponentEditorTool::mouseDoubleClickEvent(QMouseEvent *event) +{ + if (event->buttons() & Qt::LeftButton + && !containsCursor(event->pos()) + && m_currentContext.size() > 1) + { + aboutToPopContext(); + } +} + +void SubcomponentEditorTool::hoverMoveEvent(QMouseEvent *event) +{ + if (!containsCursor(event->pos()) && m_currentContext.size() > 1) { + QDeclarativeViewObserverPrivate::get(observer())->clearHighlight(); + } +} + +void SubcomponentEditorTool::wheelEvent(QWheelEvent * /*event*/) +{ + +} + +void SubcomponentEditorTool::keyPressEvent(QKeyEvent * /*event*/) +{ + +} + +void SubcomponentEditorTool::keyReleaseEvent(QKeyEvent * /*keyEvent*/) +{ + +} + +void SubcomponentEditorTool::itemsAboutToRemoved(const QList<QGraphicsItem*> &/*itemList*/) +{ + +} + +void SubcomponentEditorTool::animate() +{ + if (m_animIncrement > 0) { + if (m_mask->opacity() + m_animIncrement < MaxOpacity) { + m_mask->setOpacity(m_mask->opacity() + m_animIncrement); + } else { + m_animTimer->stop(); + m_mask->setOpacity(MaxOpacity); + } + } else { + if (m_mask->opacity() + m_animIncrement > 0) { + m_mask->setOpacity(m_mask->opacity() + m_animIncrement); + } else { + m_animTimer->stop(); + m_mask->setOpacity(0); + popContext(); + emit contextPathChanged(m_path); + } + } + +} + +void SubcomponentEditorTool::clear() +{ + m_currentContext.clear(); + m_mask->setCurrentItem(0); + m_animTimer->stop(); + m_mask->hide(); + m_path.clear(); + + emit contextPathChanged(m_path); + emit cleared(); +} + +void SubcomponentEditorTool::selectedItemsChanged(const QList<QGraphicsItem*> &/*itemList*/) +{ + +} + +void SubcomponentEditorTool::setCurrentItem(QGraphicsItem* contextItem) +{ + if (!contextItem) + return; + + QGraphicsObject *gfxObject = contextItem->toGraphicsObject(); + if (!gfxObject) + return; + + //QString parentClassName = gfxObject->metaObject()->className(); + //if (parentClassName.contains(QRegExp("_QMLTYPE_\\d+"))) + + bool containsSelectableItems = false; + foreach(QGraphicsItem *item, gfxObject->childItems()) { + if (item->type() == Constants::EditorItemType + || item->type() == Constants::ResizeHandleItemType) + { + continue; + } + containsSelectableItems = true; + break; + } + + if (containsSelectableItems) { + m_mask->setCurrentItem(gfxObject); + m_mask->setOpacity(0); + m_mask->show(); + m_animIncrement = 0.05f; + m_animTimer->start(); + + QDeclarativeViewObserverPrivate::get(observer())->clearHighlight(); + observer()->setSelectedItems(QList<QGraphicsItem*>()); + + pushContext(gfxObject); + } +} + +QGraphicsItem *SubcomponentEditorTool::firstChildOfContext(QGraphicsItem *item) const +{ + if (!item) + return 0; + + if (isDirectChildOfContext(item)) + return item; + + QGraphicsItem *parent = item->parentItem(); + while (parent) { + if (isDirectChildOfContext(parent)) + return parent; + parent = parent->parentItem(); + } + + return 0; +} + +bool SubcomponentEditorTool::isChildOfContext(QGraphicsItem *item) const +{ + return (firstChildOfContext(item) != 0); +} + +bool SubcomponentEditorTool::isDirectChildOfContext(QGraphicsItem *item) const +{ + return (item->parentItem() == m_currentContext.top()); +} + +bool SubcomponentEditorTool::itemIsChildOfQmlSubComponent(QGraphicsItem *item) const +{ + if (item->parentItem() && item->parentItem() != m_currentContext.top()) { + QGraphicsObject *parent = item->parentItem()->toGraphicsObject(); + QString parentClassName = parent->metaObject()->className(); + + if (parentClassName.contains(QRegExp("_QMLTYPE_\\d+"))) { + return true; + } else { + return itemIsChildOfQmlSubComponent(parent); + } + } + + return false; +} + +void SubcomponentEditorTool::pushContext(QGraphicsObject *contextItem) +{ + connect(contextItem, SIGNAL(destroyed(QObject*)), this, SLOT(contextDestroyed(QObject*))); + connect(contextItem, SIGNAL(xChanged()), this, SLOT(resizeMask())); + connect(contextItem, SIGNAL(yChanged()), this, SLOT(resizeMask())); + connect(contextItem, SIGNAL(widthChanged()), this, SLOT(resizeMask())); + connect(contextItem, SIGNAL(heightChanged()), this, SLOT(resizeMask())); + connect(contextItem, SIGNAL(rotationChanged()), this, SLOT(resizeMask())); + + m_currentContext.push(contextItem); + QString title = titleForItem(contextItem); + emit contextPushed(title); + + m_path << title; + emit contextPathChanged(m_path); +} + +void SubcomponentEditorTool::aboutToPopContext() +{ + if (m_currentContext.size() > 2) { + popContext(); + emit contextPathChanged(m_path); + } else { + m_animIncrement = -0.05f; + m_animTimer->start(); + } +} + +QGraphicsObject *SubcomponentEditorTool::popContext() +{ + QGraphicsObject *popped = m_currentContext.pop(); + m_path.removeLast(); + + emit contextPopped(); + + disconnect(popped, SIGNAL(xChanged()), this, SLOT(resizeMask())); + disconnect(popped, SIGNAL(yChanged()), this, SLOT(resizeMask())); + disconnect(popped, SIGNAL(scaleChanged()), this, SLOT(resizeMask())); + disconnect(popped, SIGNAL(widthChanged()), this, SLOT(resizeMask())); + disconnect(popped, SIGNAL(heightChanged()), this, SLOT(resizeMask())); + + if (m_currentContext.size() > 1) { + QGraphicsObject *item = m_currentContext.top(); + m_mask->setCurrentItem(item); + m_mask->setOpacity(MaxOpacity); + m_mask->setVisible(true); + } else { + m_mask->setVisible(false); + } + + return popped; +} + +void SubcomponentEditorTool::resizeMask() +{ + QGraphicsObject *item = m_currentContext.top(); + m_mask->setCurrentItem(item); +} + +QGraphicsObject *SubcomponentEditorTool::currentRootItem() const +{ + return m_currentContext.top(); +} + +void SubcomponentEditorTool::contextDestroyed(QObject *contextToDestroy) +{ + disconnect(contextToDestroy, SIGNAL(destroyed(QObject*)), this, SLOT(contextDestroyed(QObject*))); + + // pop out the whole context - it might not be safe anymore. + while (m_currentContext.size() > 1) { + m_currentContext.pop(); + m_path.removeLast(); + emit contextPopped(); + } + m_mask->setVisible(false); + + emit contextPathChanged(m_path); +} + +QGraphicsObject *SubcomponentEditorTool::setContext(int contextIndex) +{ + Q_ASSERT(contextIndex >= 0); + + // sometimes we have to delete the context while user was still clicking around, + // so just bail out. + if (contextIndex >= m_currentContext.size() -1) + return 0; + + while (m_currentContext.size() - 1 > contextIndex) { + popContext(); + } + emit contextPathChanged(m_path); + + return m_currentContext.top(); +} + +int SubcomponentEditorTool::contextIndex() const +{ + return m_currentContext.size() - 1; +} + + +} // namespace QmlJSDebugger diff --git a/share/qtcreator/qml/qmljsdebugger/editor/subcomponenteditortool.h b/share/qtcreator/qml/qmljsdebugger/editor/subcomponenteditortool.h new file mode 100644 index 0000000000..c1652ddb24 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/subcomponenteditortool.h @@ -0,0 +1,83 @@ +#ifndef SUBCOMPONENTEDITORTOOL_H +#define SUBCOMPONENTEDITORTOOL_H + +#include "abstractformeditortool.h" +#include <QStack> +#include <QStringList> + +QT_FORWARD_DECLARE_CLASS(QGraphicsObject) +QT_FORWARD_DECLARE_CLASS(QPoint) +QT_FORWARD_DECLARE_CLASS(QTimer) + +namespace QmlJSDebugger { + +class SubcomponentMaskLayerItem; + +class SubcomponentEditorTool : public AbstractFormEditorTool +{ + Q_OBJECT + +public: + SubcomponentEditorTool(QDeclarativeViewObserver *view); + ~SubcomponentEditorTool(); + + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); + + void hoverMoveEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); + + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *keyEvent); + void itemsAboutToRemoved(const QList<QGraphicsItem*> &itemList); + + void clear(); + + bool containsCursor(const QPoint &mousePos) const; + bool itemIsChildOfQmlSubComponent(QGraphicsItem *item) const; + + bool isChildOfContext(QGraphicsItem *item) const; + bool isDirectChildOfContext(QGraphicsItem *item) const; + QGraphicsItem *firstChildOfContext(QGraphicsItem *item) const; + + void setCurrentItem(QGraphicsItem *contextObject); + + void pushContext(QGraphicsObject *contextItem); + + QGraphicsObject *currentRootItem() const; + QGraphicsObject *setContext(int contextIndex); + int contextIndex() const; + +signals: + void exitContextRequested(); + void cleared(); + void contextPushed(const QString &contextTitle); + void contextPopped(); + void contextPathChanged(const QStringList &path); + +protected: + void selectedItemsChanged(const QList<QGraphicsItem*> &itemList); + +private slots: + void animate(); + void contextDestroyed(QObject *context); + void resizeMask(); + +private: + QGraphicsObject *popContext(); + void aboutToPopContext(); + +private: + QStack<QGraphicsObject *> m_currentContext; + QStringList m_path; + + qreal m_animIncrement; + SubcomponentMaskLayerItem *m_mask; + QTimer *m_animTimer; +}; + +} // namespace QmlJSDebugger + +#endif // SUBCOMPONENTEDITORTOOL_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/subcomponentmasklayeritem.cpp b/share/qtcreator/qml/qmljsdebugger/editor/subcomponentmasklayeritem.cpp new file mode 100644 index 0000000000..1e8ff42466 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/subcomponentmasklayeritem.cpp @@ -0,0 +1,80 @@ +#include "subcomponentmasklayeritem.h" +#include "qmlobserverconstants.h" +#include "qdeclarativeviewobserver.h" +#include <QPolygonF> + +namespace QmlJSDebugger { + +SubcomponentMaskLayerItem::SubcomponentMaskLayerItem(QDeclarativeViewObserver *observer, QGraphicsItem *parentItem) : + QGraphicsPolygonItem(parentItem), + m_observer(observer), + m_currentItem(0), + m_borderRect(new QGraphicsRectItem(this)) +{ + m_borderRect->setRect(0,0,0,0); + m_borderRect->setPen(QPen(QColor(60, 60, 60), 1)); + m_borderRect->setData(Constants::EditorItemDataKey, QVariant(true)); + + setBrush(QBrush(QColor(160,160,160))); + setPen(Qt::NoPen); +} + +int SubcomponentMaskLayerItem::type() const +{ + return Constants::EditorItemType; +} + +static QRectF resizeRect(const QRectF &newRect, const QRectF &oldRect) +{ + QRectF result = newRect; + if (oldRect.left() < newRect.left()) + result.setLeft(oldRect.left()); + + if (oldRect.top() < newRect.top()) + result.setTop(oldRect.top()); + + if (oldRect.right() > newRect.right()) + result.setRight(oldRect.right()); + + if (oldRect.bottom() > newRect.bottom()) + result.setBottom(oldRect.bottom()); + + return result; +} + + +void SubcomponentMaskLayerItem::setCurrentItem(QGraphicsItem *item) +{ + QGraphicsItem *prevItem = m_currentItem; + m_currentItem = item; + + if (!m_currentItem) + return; + + QPolygonF viewPoly(QRectF(m_observer->declarativeView()->rect())); + viewPoly = m_observer->declarativeView()->mapToScene(viewPoly.toPolygon()); + + QRectF itemRect = item->boundingRect() | item->childrenBoundingRect(); + QPolygonF itemPoly(itemRect); + itemPoly = item->mapToScene(itemPoly); + + // if updating the same item as before, resize the rectangle only bigger, not smaller. + if (prevItem == item && prevItem != 0) { + m_itemPolyRect = resizeRect(itemPoly.boundingRect(), m_itemPolyRect); + } else { + m_itemPolyRect = itemPoly.boundingRect(); + } + QRectF borderRect = m_itemPolyRect; + borderRect.adjust(-1, -1, 1, 1); + m_borderRect->setRect(borderRect); + + itemPoly = viewPoly.subtracted(QPolygonF(m_itemPolyRect)); + setPolygon(itemPoly); +} + +QGraphicsItem *SubcomponentMaskLayerItem::currentItem() const +{ + return m_currentItem; +} + +} // namespace QmlJSDebugger diff --git a/share/qtcreator/qml/qmljsdebugger/editor/subcomponentmasklayeritem.h b/share/qtcreator/qml/qmljsdebugger/editor/subcomponentmasklayeritem.h new file mode 100644 index 0000000000..37759ebf71 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/subcomponentmasklayeritem.h @@ -0,0 +1,29 @@ +#ifndef SUBCOMPONENTMASKLAYERITEM_H +#define SUBCOMPONENTMASKLAYERITEM_H + +#include <QGraphicsPolygonItem> + +namespace QmlJSDebugger { + +class QDeclarativeViewObserver; + +class SubcomponentMaskLayerItem : public QGraphicsPolygonItem +{ +public: + explicit SubcomponentMaskLayerItem(QDeclarativeViewObserver *observer, QGraphicsItem *parentItem = 0); + int type() const; + void setCurrentItem(QGraphicsItem *item); + void setBoundingBox(const QRectF &boundingBox); + QGraphicsItem *currentItem() const; + QRectF itemRect() const; + +private: + QDeclarativeViewObserver *m_observer; + QGraphicsItem *m_currentItem; + QGraphicsRectItem *m_borderRect; + QRectF m_itemPolyRect; +}; + +} // namespace QmlJSDebugger + +#endif // SUBCOMPONENTMASKLAYERITEM_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/toolbarcolorbox.cpp b/share/qtcreator/qml/qmljsdebugger/editor/toolbarcolorbox.cpp new file mode 100644 index 0000000000..dd6eb7e4a7 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/toolbarcolorbox.cpp @@ -0,0 +1,96 @@ +#include "toolbarcolorbox.h" +#include "qmlobserverconstants.h" + +#include <QPixmap> +#include <QPainter> +#include <QMenu> +#include <QAction> +#include <QContextMenuEvent> +#include <QClipboard> +#include <QApplication> +#include <QColorDialog> +#include <QDrag> +#include <QMimeData> + +#include <QDebug> + +namespace QmlJSDebugger { + +ToolBarColorBox::ToolBarColorBox(QWidget *parent) : + QLabel(parent) +{ + m_copyHexColor = new QAction(QIcon(QLatin1String(":/qml/images/color-picker-hicontrast.png")), tr("Copy"), this); + connect(m_copyHexColor, SIGNAL(triggered()), SLOT(copyColorToClipboard())); + setScaledContents(false); +} + +void ToolBarColorBox::setColor(const QColor &color) +{ + m_color = color; + + QPixmap pix = createDragPixmap(width()); + setPixmap(pix); + update(); +} + +void ToolBarColorBox::mousePressEvent(QMouseEvent *event) +{ + m_dragBeginPoint = event->pos(); + m_dragStarted = false; +} + +void ToolBarColorBox::mouseMoveEvent(QMouseEvent *event) +{ + if (event->buttons() & Qt::LeftButton + && QPoint(event->pos() - m_dragBeginPoint).manhattanLength() > Constants::DragStartDistance + && !m_dragStarted) + { + m_dragStarted = true; + QDrag *drag = new QDrag(this); + QMimeData *mimeData = new QMimeData; + + mimeData->setText(m_color.name()); + drag->setMimeData(mimeData); + drag->setPixmap(createDragPixmap()); + + drag->exec(); + } +} + +QPixmap ToolBarColorBox::createDragPixmap(int size) const +{ + QPixmap pix(size, size); + QPainter p(&pix); + + QColor borderColor1 = QColor(143, 143 ,143); + QColor borderColor2 = QColor(43, 43, 43); + + p.setBrush(QBrush(m_color)); + p.setPen(QPen(QBrush(borderColor2),1)); + + p.fillRect(0, 0, size, size, borderColor1); + p.drawRect(1,1, size - 3, size - 3); + return pix; +} + +void ToolBarColorBox::contextMenuEvent(QContextMenuEvent *ev) +{ + QMenu contextMenu; + contextMenu.addAction(m_copyHexColor); + contextMenu.exec(ev->globalPos()); +} + +void ToolBarColorBox::mouseDoubleClickEvent(QMouseEvent *) +{ + QColorDialog dialog(m_color); + dialog.show(); +} + +void ToolBarColorBox::copyColorToClipboard() +{ + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(m_color.name()); +} + + +} // namespace QmlJSDebugger diff --git a/share/qtcreator/qml/qmljsdebugger/editor/toolbarcolorbox.h b/share/qtcreator/qml/qmljsdebugger/editor/toolbarcolorbox.h new file mode 100644 index 0000000000..d4be7921bb --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/toolbarcolorbox.h @@ -0,0 +1,41 @@ +#ifndef ToolBarColorBox_H +#define ToolBarColorBox_H + +#include <QLabel> +#include <QColor> +#include <QPoint> + +QT_FORWARD_DECLARE_CLASS(QContextMenuEvent); +QT_FORWARD_DECLARE_CLASS(QAction); + +namespace QmlJSDebugger { + +class ToolBarColorBox : public QLabel +{ + Q_OBJECT +public: + explicit ToolBarColorBox(QWidget *parent = 0); + void setColor(const QColor &color); + +protected: + void contextMenuEvent(QContextMenuEvent *ev); + void mouseDoubleClickEvent(QMouseEvent *); + void mousePressEvent(QMouseEvent *ev); + void mouseMoveEvent(QMouseEvent *ev); +private slots: + void copyColorToClipboard(); + +private: + QPixmap createDragPixmap(int size = 24) const; + +private: + bool m_dragStarted; + QPoint m_dragBeginPoint; + QAction *m_copyHexColor; + QColor m_color; + +}; + +} // namespace QmlJSDebugger + +#endif // ToolBarColorBox_H diff --git a/share/qtcreator/qml/qmljsdebugger/editor/zoomtool.cpp b/share/qtcreator/qml/qmljsdebugger/editor/zoomtool.cpp new file mode 100644 index 0000000000..2bb152e2d6 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/zoomtool.cpp @@ -0,0 +1,287 @@ +#include "zoomtool.h" +#include "qdeclarativeviewobserver_p.h" + +#include <QMouseEvent> +#include <QWheelEvent> +#include <QKeyEvent> +#include <QRectF> +#include <QMenu> +#include <QAction> + +#include <QDebug> + +namespace QmlJSDebugger { + +ZoomTool::ZoomTool(QDeclarativeViewObserver *view) : + AbstractFormEditorTool(view), + m_rubberbandManipulator(reinterpret_cast<QGraphicsObject *>(QDeclarativeViewObserverPrivate::get(view)->manipulatorLayer), view), + m_smoothZoomMultiplier(0.05f), + m_currentScale(1.0f) +{ + m_zoomTo100Action = new QAction(tr("Zoom to &100%"), this); + m_zoomInAction = new QAction(tr("Zoom In"), this); + m_zoomOutAction = new QAction(tr("Zoom Out"), this); + m_zoomInAction->setShortcut(QKeySequence(Qt::Key_Plus)); + m_zoomOutAction->setShortcut(QKeySequence(Qt::Key_Minus)); + + connect(m_zoomTo100Action, SIGNAL(triggered()), SLOT(zoomTo100())); + connect(m_zoomInAction, SIGNAL(triggered()), SLOT(zoomIn())); + connect(m_zoomOutAction, SIGNAL(triggered()), SLOT(zoomOut())); +} + +ZoomTool::~ZoomTool() +{ + +} + +void ZoomTool::mousePressEvent(QMouseEvent *event) +{ + m_mousePos = event->pos(); + + QPointF scenePos = view()->mapToScene(event->pos()); + + if (event->buttons() & Qt::RightButton) { + QMenu contextMenu; + contextMenu.addAction(m_zoomTo100Action); + contextMenu.addSeparator(); + contextMenu.addAction(m_zoomInAction); + contextMenu.addAction(m_zoomOutAction); + contextMenu.exec(event->globalPos()); + } else if (event->buttons() & Qt::LeftButton) { + m_dragBeginPos = scenePos; + m_dragStarted = false; + } +} + +void ZoomTool::mouseMoveEvent(QMouseEvent *event) +{ + m_mousePos = event->pos(); + + QPointF scenePos = view()->mapToScene(event->pos()); + + if (event->buttons() & Qt::LeftButton + && QPointF(scenePos - m_dragBeginPos).manhattanLength() > Constants::DragStartDistance / 3 + && !m_dragStarted) + { + m_dragStarted = true; + m_rubberbandManipulator.begin(m_dragBeginPos); + return; + } + + if (m_dragStarted) + m_rubberbandManipulator.update(scenePos); + +} + +void ZoomTool::mouseReleaseEvent(QMouseEvent *event) +{ + m_mousePos = event->pos(); + QPointF scenePos = view()->mapToScene(event->pos()); + + if (m_dragStarted) { + m_rubberbandManipulator.end(); + + int x1 = qMin(scenePos.x(), m_rubberbandManipulator.beginPoint().x()); + int x2 = qMax(scenePos.x(), m_rubberbandManipulator.beginPoint().x()); + int y1 = qMin(scenePos.y(), m_rubberbandManipulator.beginPoint().y()); + int y2 = qMax(scenePos.y(), m_rubberbandManipulator.beginPoint().y()); + + QPointF scenePosTopLeft = QPoint(x1, y1); + QPointF scenePosBottomRight = QPoint(x2, y2); + + QRectF sceneArea(scenePosTopLeft, scenePosBottomRight); + + m_currentScale = qMin(view()->rect().width() / sceneArea.width(), + view()->rect().height() / sceneArea.height()); + + + QTransform transform; + transform.scale(m_currentScale, m_currentScale); + + view()->setTransform(transform); + view()->setSceneRect(sceneArea); + } else { + Qt::KeyboardModifier modifierKey = Qt::ControlModifier; +#ifdef Q_WS_MAC + modifierKey = Qt::AltModifier; +#endif + if (event->modifiers() & modifierKey) { + zoomOut(); + } else { + zoomIn(); + } + } +} + +void ZoomTool::zoomIn() +{ + m_currentScale = nextZoomScale(ZoomIn); + scaleView(view()->mapToScene(m_mousePos)); +} + +void ZoomTool::zoomOut() +{ + m_currentScale = nextZoomScale(ZoomOut); + scaleView(view()->mapToScene(m_mousePos)); +} + +void ZoomTool::mouseDoubleClickEvent(QMouseEvent *event) +{ + m_mousePos = event->pos(); +} + + +void ZoomTool::hoverMoveEvent(QMouseEvent *event) +{ + m_mousePos = event->pos(); +} + + +void ZoomTool::keyPressEvent(QKeyEvent * /*event*/) +{ +} + +void ZoomTool::wheelEvent(QWheelEvent *event) +{ + if (event->orientation() != Qt::Vertical) + return; + + Qt::KeyboardModifier smoothZoomModifier = Qt::ControlModifier; + if (event->modifiers() & smoothZoomModifier) { + int numDegrees = event->delta() / 8; + m_currentScale += m_smoothZoomMultiplier * (numDegrees / 15.0f); + + scaleView(view()->mapToScene(m_mousePos)); + + } else if (!event->modifiers()) { + if (event->delta() > 0) { + m_currentScale = nextZoomScale(ZoomIn); + } else if (event->delta() < 0) { + m_currentScale = nextZoomScale(ZoomOut); + } + scaleView(view()->mapToScene(m_mousePos)); + } +} + +void ZoomTool::keyReleaseEvent(QKeyEvent *event) +{ + switch(event->key()) { + case Qt::Key_Plus: + zoomIn(); + break; + case Qt::Key_Minus: + zoomOut(); + break; + case Qt::Key_1: + case Qt::Key_2: + case Qt::Key_3: + case Qt::Key_4: + case Qt::Key_5: + case Qt::Key_6: + case Qt::Key_7: + case Qt::Key_8: + case Qt::Key_9: + { + m_currentScale = ((event->key() - Qt::Key_0) * 1.0f); + scaleView(view()->mapToScene(m_mousePos)); // view()->mapToScene(view()->rect().center()) + break; + } + + default: + break; + } + +} + +void ZoomTool::itemsAboutToRemoved(const QList<QGraphicsItem*> &/*itemList*/) +{ +} + +void ZoomTool::clear() +{ + view()->setCursor(Qt::ArrowCursor); +} + +void ZoomTool::selectedItemsChanged(const QList<QGraphicsItem*> &/*itemList*/) +{ +} + +void ZoomTool::scaleView(const QPointF ¢erPos) +{ + + QTransform transform; + transform.scale(m_currentScale, m_currentScale); + view()->setTransform(transform); + + QPointF adjustedCenterPos = centerPos; + QSize rectSize(view()->rect().width() / m_currentScale, + view()->rect().height() / m_currentScale); + + QRectF sceneRect; + if (qAbs(m_currentScale - 1.0f) < Constants::ZoomSnapDelta) { + adjustedCenterPos.rx() = rectSize.width() / 2; + adjustedCenterPos.ry() = rectSize.height() / 2; + } + + if (m_currentScale < 1.0f) { + adjustedCenterPos.rx() = rectSize.width() / 2; + adjustedCenterPos.ry() = rectSize.height() / 2; + sceneRect.setRect(view()->rect().width() / 2 -rectSize.width() / 2, + view()->rect().height() / 2 -rectSize.height() / 2, + rectSize.width(), + rectSize.height()); + } else { + sceneRect.setRect(adjustedCenterPos.x() - rectSize.width() / 2, + adjustedCenterPos.y() - rectSize.height() / 2, + rectSize.width(), + rectSize.height()); + } + + view()->setSceneRect(sceneRect); +} + +void ZoomTool::zoomTo100() +{ + m_currentScale = 1.0f; + scaleView(view()->mapToScene(view()->rect().center())); +} + +qreal ZoomTool::nextZoomScale(ZoomDirection direction) const +{ + static QList<qreal> zoomScales = + QList<qreal>() + << 0.125f + << 1.0f / 6.0f + << 0.25f + << 1.0f / 3.0f + << 0.5f + << 2.0f / 3.0f + << 1.0f + << 2.0f + << 3.0f + << 4.0f + << 5.0f + << 6.0f + << 7.0f + << 8.0f + << 12.0f + << 16.0f + << 32.0f + << 48.0f; + + if (direction == ZoomIn) { + for(int i = 0; i < zoomScales.length(); ++i) { + if (zoomScales[i] > m_currentScale || i == zoomScales.length() - 1) + return zoomScales[i]; + } + } else { + for(int i = zoomScales.length() - 1; i >= 0; --i) { + if (zoomScales[i] < m_currentScale || i == 0) + return zoomScales[i]; + } + } + + return 1.0f; +} + +} // namespace QmlJSDebugger diff --git a/share/qtcreator/qml/qmljsdebugger/editor/zoomtool.h b/share/qtcreator/qml/qmljsdebugger/editor/zoomtool.h new file mode 100644 index 0000000000..299efee3ea --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/editor/zoomtool.h @@ -0,0 +1,65 @@ +#ifndef ZOOMTOOL_H +#define ZOOMTOOL_H + +#include "abstractformeditortool.h" +#include "rubberbandselectionmanipulator.h" + +QT_FORWARD_DECLARE_CLASS(QAction); + +namespace QmlJSDebugger { + +class ZoomTool : public AbstractFormEditorTool +{ + Q_OBJECT +public: + enum ZoomDirection { + ZoomIn, + ZoomOut + }; + + explicit ZoomTool(QDeclarativeViewObserver *view); + + virtual ~ZoomTool(); + + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); + + void hoverMoveEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); + + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *keyEvent); + void itemsAboutToRemoved(const QList<QGraphicsItem*> &itemList); + + void clear(); +protected: + void selectedItemsChanged(const QList<QGraphicsItem*> &itemList); + +private slots: + void zoomTo100(); + void zoomIn(); + void zoomOut(); + +private: + qreal nextZoomScale(ZoomDirection direction) const; + void scaleView(const QPointF ¢erPos); + +private: + bool m_dragStarted; + QPoint m_mousePos; // in view coords + QPointF m_dragBeginPos; + QAction *m_zoomTo100Action; + QAction *m_zoomInAction; + QAction *m_zoomOutAction; + RubberBandSelectionManipulator m_rubberbandManipulator; + + qreal m_smoothZoomMultiplier; + qreal m_currentScale; + +}; + +} // namespace QmlJSDebugger + +#endif // ZOOMTOOL_H diff --git a/share/qtcreator/qml/qmljsdebugger/include/jsdebuggeragent.h b/share/qtcreator/qml/qmljsdebugger/include/jsdebuggeragent.h new file mode 100644 index 0000000000..39b559cabe --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/include/jsdebuggeragent.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtSCriptTools module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** 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. +** +** 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. +** +** 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. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSCRIPTDEBUGGERAGENT_P_H +#define QSCRIPTDEBUGGERAGENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtScript/qscriptengineagent.h> +#include <QtScript/QScriptValue> +#include <QtCore/QEventLoop> +#include <QtCore/QSet> +#include <private/qdeclarativedebugservice_p.h> +#include <QtCore/QStringList> + +#include "qmljsdebugger_global.h" + +QT_FORWARD_DECLARE_CLASS(QScriptContext); +QT_FORWARD_DECLARE_CLASS(QDeclarativeEngine); + +namespace QmlJSDebugger { + +class JSAgentWatchData; + +class QMLJSDEBUGGER_EXPORT JSDebuggerAgent : public QDeclarativeDebugService , public QScriptEngineAgent +{ + Q_OBJECT +public: + JSDebuggerAgent(QScriptEngine *engine); + JSDebuggerAgent(QDeclarativeEngine *engine); + ~JSDebuggerAgent(); + + // reimplemented + void scriptLoad(qint64 id, const QString &program, + const QString &fileName, int baseLineNumber); + void scriptUnload(qint64 id); + + void contextPush(); + void contextPop(); + + void functionEntry(qint64 scriptId); + void functionExit(qint64 scriptId, + const QScriptValue &returnValue); + + void positionChange(qint64 scriptId, + int lineNumber, int columnNumber); + + void exceptionThrow(qint64 scriptId, + const QScriptValue &exception, + bool hasHandler); + void exceptionCatch(qint64 scriptId, + const QScriptValue &exception); + + bool supportsExtension(Extension extension) const; + QVariant extension(Extension extension, + const QVariant &argument = QVariant()); + + void messageReceived(const QByteArray &); + void enabledChanged(bool); + +public slots: +// void pauses(); + +private: + class SetupExecEnv; + friend class SetupExecEnv; + + enum State { + NoState, + SteppingIntoState, + SteppingOverState, + SteppingOutState, + Stopped + }; + State state; + int stepDepth; + int stepCount; + + void continueExec(); + void stopped(bool becauseOfException = false, const QScriptValue &exception = QScriptValue()); + + + void recordKnownObjects(const QList<JSAgentWatchData> &); + QList<JSAgentWatchData> getLocals(QScriptContext *); + + QEventLoop loop; + QHash <qint64, QString> filenames; + QSet< QPair<QString, qint32> > breakpointList; + QStringList watchExpressions; + QSet<qint64> knownObjectIds; + + Q_DISABLE_COPY(JSDebuggerAgent) +}; + +} // namespace QmlJSDebugger + +#endif diff --git a/share/qtcreator/qml/qmljsdebugger/include/qdeclarativeobserverservice.h b/share/qtcreator/qml/qmljsdebugger/include/qdeclarativeobserverservice.h new file mode 100644 index 0000000000..121a847684 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/include/qdeclarativeobserverservice.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** 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. +** +** 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. +** +** 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. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEDESIGNDEBUGSERVER_H +#define QDECLARATIVEDESIGNDEBUGSERVER_H + +#include <private/qdeclarativedebugservice_p.h> +#include "qmlobserverconstants.h" +#include "qmljsdebugger_global.h" + +#include <QHash> + +QT_FORWARD_DECLARE_CLASS(QColor) +QT_FORWARD_DECLARE_CLASS(QDeclarativeEngine) +QT_FORWARD_DECLARE_CLASS(QDeclarativeContext) +QT_FORWARD_DECLARE_CLASS(QDeclarativeWatcher) +QT_FORWARD_DECLARE_CLASS(QDataStream) + +namespace QmlJSDebugger { + +class QMLJSDEBUGGER_EXPORT QDeclarativeObserverService : public QDeclarativeDebugService +{ + Q_OBJECT +public: + QDeclarativeObserverService(); + static QDeclarativeObserverService *instance(); + + void setDesignModeBehavior(bool inDesignMode); + void setCurrentObjects(QList<QObject*> items); + void setAnimationSpeed(qreal slowdownFactor); + void setCurrentTool(QmlJSDebugger::Constants::DesignTool toolId); + void reloaded(); + QString idStringForObject(QObject *obj) const; + +public Q_SLOTS: + void selectedColorChanged(const QColor &color); + void contextPathUpdated(const QStringList &contextPath); + +Q_SIGNALS: + void debuggingClientChanged(bool hasDebuggingClient); + + void currentObjectsChanged(const QList<QObject*> &objects); + void designModeBehaviorChanged(bool inDesignMode); + void reloadRequested(); + void selectToolRequested(); + void selectMarqueeToolRequested(); + void zoomToolRequested(); + void colorPickerToolRequested(); + + void objectCreationRequested(const QString &qml, QObject *parent, + const QStringList &imports, const QString &filename = QString()); + void objectReparentRequested(QObject *object, QObject *newParent); + + // 1 = normal speed, + // 0 = paused, + // 1 < x < 16 = slowdown by some factor + void animationSpeedChangeRequested(qreal speedFactor); + + void contextPathIndexChanged(int contextPathIndex); + void clearComponentCacheRequested(); + +protected: + virtual void enabledChanged(bool enabled); + virtual void messageReceived(const QByteArray &); + +private: + QHash<int, QString> m_stringIdForObjectId; +}; + +} // namespace QmlJSDebugger + +#endif // QDECLARATIVEDESIGNDEBUGSERVER_H diff --git a/share/qtcreator/qml/qmljsdebugger/include/qdeclarativeviewobserver.h b/share/qtcreator/qml/qmljsdebugger/include/qdeclarativeviewobserver.h new file mode 100644 index 0000000000..02aee970a2 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/include/qdeclarativeviewobserver.h @@ -0,0 +1,129 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 QDECLARATIVEVIEWOBSERVER_H +#define QDECLARATIVEVIEWOBSERVER_H + +#include "qmljsdebugger_global.h" +#include "qmlobserverconstants.h" +#include <qdeclarativeview.h> +#include <QWeakPointer> + +QT_FORWARD_DECLARE_CLASS(QDeclarativeItem); +QT_FORWARD_DECLARE_CLASS(QMouseEvent); +QT_FORWARD_DECLARE_CLASS(QToolBar); + +namespace QmlJSDebugger { + +class CrumblePath; +class QDeclarativeViewObserverPrivate; + +class QMLJSDEBUGGER_EXPORT QDeclarativeViewObserver : public QObject +{ + Q_OBJECT +public: + + explicit QDeclarativeViewObserver(QDeclarativeView *view, QObject *parent = 0); + ~QDeclarativeViewObserver(); + + void setSelectedItems(QList<QGraphicsItem *> items); + QList<QGraphicsItem *> selectedItems(); + + QDeclarativeView *declarativeView(); + + QToolBar *toolbar() const; + static QString idStringForObject(QObject *obj); + QRectF adjustToScreenBoundaries(const QRectF &boundingRectInSceneSpace); + void setDebugMode(bool isDebugMode); + +public Q_SLOTS: + void setDesignModeBehavior(bool value); + bool designModeBehavior(); + + void changeAnimationSpeed(qreal slowdownFactor); + void continueExecution(qreal slowdownFactor = 1.0f); + void pauseExecution(); + + void setObserverContext(int contextIndex); + +Q_SIGNALS: + void designModeBehaviorChanged(bool inDesignMode); + void reloadRequested(); + void marqueeSelectToolActivated(); + void selectToolActivated(); + void zoomToolActivated(); + void colorPickerActivated(); + void selectedColorChanged(const QColor &color); + + void executionStarted(qreal slowdownFactor); + void executionPaused(); + + void inspectorContextCleared(); + void inspectorContextPushed(const QString &contextTitle); + void inspectorContextPopped(); + +protected: + bool eventFilter(QObject *obj, QEvent *event); + + bool leaveEvent(QEvent *); + bool mousePressEvent(QMouseEvent *event); + bool mouseMoveEvent(QMouseEvent *event); + bool mouseReleaseEvent(QMouseEvent *event); + bool keyPressEvent(QKeyEvent *event); + bool keyReleaseEvent(QKeyEvent *keyEvent); + bool mouseDoubleClickEvent(QMouseEvent *event); + bool wheelEvent(QWheelEvent *event); + + void setSelectedItemsForTools(QList<QGraphicsItem *> items); + +private: + Q_DISABLE_COPY(QDeclarativeViewObserver) + Q_PRIVATE_SLOT(d_func(), void _q_reloadView()) + Q_PRIVATE_SLOT(d_func(), void _q_onStatusChanged(QDeclarativeView::Status)) + Q_PRIVATE_SLOT(d_func(), void _q_onCurrentObjectsChanged(QList<QObject*>)) + Q_PRIVATE_SLOT(d_func(), void _q_applyChangesFromClient()) + Q_PRIVATE_SLOT(d_func(), void _q_createQmlObject(const QString &, QObject *, const QStringList &, const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_reparentQmlObject(QObject *, QObject *)) + Q_PRIVATE_SLOT(d_func(), void _q_changeToSingleSelectTool()) + Q_PRIVATE_SLOT(d_func(), void _q_changeToMarqueeSelectTool()) + Q_PRIVATE_SLOT(d_func(), void _q_changeToZoomTool()) + Q_PRIVATE_SLOT(d_func(), void _q_changeToColorPickerTool()) + Q_PRIVATE_SLOT(d_func(), void _q_changeContextPathIndex(int index)) + Q_PRIVATE_SLOT(d_func(), void _q_clearComponentCache()); + + inline QDeclarativeViewObserverPrivate *d_func() { return data.data(); } + QScopedPointer<QDeclarativeViewObserverPrivate> data; + friend class QDeclarativeViewObserverPrivate; + friend class AbstractFormEditorTool; + +}; + +} //namespace QmlJSDebugger + +#endif // QDECLARATIVEVIEWOBSERVER_H diff --git a/share/qtcreator/qml/qmljsdebugger/include/qmljsdebugger_global.h b/share/qtcreator/qml/qmljsdebugger/include/qmljsdebugger_global.h new file mode 100644 index 0000000000..6aba5be426 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/include/qmljsdebugger_global.h @@ -0,0 +1,43 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 QMLJSDEBUGGER_GLOBAL_H +#define QMLJSDEBUGGER_GLOBAL_H + +#include <QtCore/qglobal.h> + +# if defined(BUILD_QMLJSDEBUGGER_LIB) +# define QMLJSDEBUGGER_EXPORT Q_DECL_EXPORT +# elif defined(BUILD_QMLJSDEBUGGER_STATIC_LIB) +# define QMLJSDEBUGGER_EXPORT +# else +# define QMLJSDEBUGGER_EXPORT Q_DECL_IMPORT +#endif + +#endif // QMLJSDEBUGGER_GLOBAL_H diff --git a/share/qtcreator/qml/qmljsdebugger/include/qmlobserverconstants.h b/share/qtcreator/qml/qmljsdebugger/include/qmlobserverconstants.h new file mode 100644 index 0000000000..8709cfef00 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/include/qmlobserverconstants.h @@ -0,0 +1,68 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 QMLOBSERVERCONSTANTS_H +#define QMLOBSERVERCONSTANTS_H + +namespace QmlJSDebugger { +namespace Constants { + +enum DesignTool { + NoTool = 0, + SelectionToolMode = 1, + MarqueeSelectionToolMode = 2, + MoveToolMode = 3, + ResizeToolMode = 4, + ColorPickerMode = 5, + ZoomMode = 6 +}; + +enum ToolFlags { + NoToolFlags = 0, + UseCursorPos = 1 +}; + +static const int DragStartTime = 50; + +static const int DragStartDistance = 20; + +static const double ZoomSnapDelta = 0.04; + +static const int EditorItemDataKey = 1000; + +enum GraphicsItemTypes { + EditorItemType = 0xEAAA, + ResizeHandleItemType = 0xEAEA +}; + + +} // namespace Constants +} // namespace QmlJSDebugger + +#endif // QMLOBSERVERCONSTANTS_H diff --git a/share/qtcreator/qml/qmljsdebugger/jsdebuggeragent.cpp b/share/qtcreator/qml/qmljsdebugger/jsdebuggeragent.cpp new file mode 100644 index 0000000000..4258882e10 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/jsdebuggeragent.cpp @@ -0,0 +1,519 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtSCriptTools module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** 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. +** +** 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. +** +** 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. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "jsdebuggeragent.h" + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qset.h> +#include <QtScript/qscriptengine.h> +#include <QtScript/QScriptContextInfo> +#include <QtCore/QDebug> +#include <QtCore/QUrl> +#include <QtCore/QDateTime> +#include <QtScript/qscriptvalueiterator.h> +#include <private/qdeclarativeengine_p.h> + +namespace QmlJSDebugger { + +class JSDebuggerAgent::SetupExecEnv { + JSDebuggerAgent* agent; + JSDebuggerAgent::State previousState; + bool hadException; +public: + SetupExecEnv(JSDebuggerAgent *a) + : agent(a), + previousState(a->state), + hadException(a->engine()->hasUncaughtException()) + { + agent->state = JSDebuggerAgent::Stopped; + } + + ~SetupExecEnv() { + if (!hadException && agent->engine()->hasUncaughtException()) + agent->engine()->clearExceptions(); + agent->state = previousState; + } +}; + +class JSAgentWatchData { +public: + QByteArray exp; + QString name; + QString value; + QString type; + bool hasChildren; + quint64 objectId; + + static JSAgentWatchData fromScriptValue(const QString &expression, const QScriptValue &value) + { + JSAgentWatchData data; + data.exp = expression.toUtf8(); + data.name = expression; + data.hasChildren = false; + data.value = value.toString(); + data.objectId = value.objectId(); + if (value.isArray()) { + data.type = QLatin1String("Array"); + data.value = QString::fromLatin1("[Array of length %1]").arg(value.property("length").toString()); + data.hasChildren = true; + } else if (value.isBool()) { + data.type = QLatin1String("Bool"); +// data.value = value.toBool() ? QLatin1String("true") : QLatin1String("false"); + } else if (value.isDate()) { + data.type = QLatin1String("Date"); + data.value = value.toDateTime().toString(); + } else if (value.isError()) { + data.type = QLatin1String("Error"); + } else if (value.isFunction()) { + data.type = QLatin1String("Function"); + } else if (value.isUndefined()) { + data.type = QLatin1String("<undefined>"); + } else if (value.isNumber()) { + data.type = QLatin1String("Number"); + } else if (value.isRegExp()) { + data.type = QLatin1String("RegExp"); + } else if (value.isString()) { + data.type = QLatin1String("String"); + } else if (value.isVariant()) { + data.type = QLatin1String("Variant"); + } else if (value.isQObject()) { + const QObject *obj = value.toQObject(); + data.value = QString::fromLatin1("[%1]").arg(obj->metaObject()->className()); + data.type = QLatin1String("Object"); + data.hasChildren = true; + } else if (value.isObject()) { + data.type = QLatin1String("Object"); + data.hasChildren = true; + data.type = QLatin1String("Object"); + data.value = QLatin1String("[Object]"); + } else if (value.isNull()) { + data.type = QLatin1String("<null>"); + } else { + data.type = QLatin1String("<unknown>"); + } + return data; + } +}; + + +QDataStream& operator<<(QDataStream& s, const JSAgentWatchData& data) +{ + return s << data.exp << data.name << data.value << data.type << data.hasChildren << data.objectId; +} + +static QList<JSAgentWatchData> expandObject(const QScriptValue &object) +{ + QList<JSAgentWatchData> result; + QScriptValueIterator it(object); + QByteArray expPrefix = '@' + QByteArray::number(object.objectId(), 16) + "->"; + while (it.hasNext()) { + it.next(); + if (it.flags() & QScriptValue::SkipInEnumeration) + continue; + if (object.isQObject() && it.value().isFunction()) { + // cosmetics: skip all signals and slot, there is too many of them, + // and it is not usefull in the debugger. + continue; + } + JSAgentWatchData data = JSAgentWatchData::fromScriptValue(it.name(), it.value()); + data.exp.prepend(expPrefix); + result << data; + } + return result; +} + +void JSDebuggerAgent::recordKnownObjects(const QList<JSAgentWatchData>& list) +{ + foreach (const JSAgentWatchData &data, list) + knownObjectIds << data.objectId; +} + +QList<JSAgentWatchData> JSDebuggerAgent::getLocals(QScriptContext *ctx) +{ + QList<JSAgentWatchData> locals; + if (ctx) { + QScriptValue activationObject = ctx->activationObject(); + QScriptValue thisObject = ctx->thisObject(); + locals = expandObject(activationObject); + if (thisObject.isObject() && thisObject.objectId() != engine()->globalObject().objectId()) + locals.prepend(JSAgentWatchData::fromScriptValue("this", thisObject)); + recordKnownObjects(locals); + knownObjectIds << activationObject.objectId(); + } + return locals; +} + +/*! + Constructs a new agent for the given \a engine. The agent will + report debugging-related events (e.g. step completion) to the given + \a backend. +*/ +JSDebuggerAgent::JSDebuggerAgent(QScriptEngine *engine) + : QDeclarativeDebugService("JSDebugger"), QScriptEngineAgent(engine) + , state(NoState) +{} + +JSDebuggerAgent::JSDebuggerAgent(QDeclarativeEngine *engine) + : QDeclarativeDebugService("JSDebugger") + , QScriptEngineAgent(QDeclarativeEnginePrivate::getScriptEngine(engine)) + , state(NoState) +{} + +/*! + Destroys this QScriptDebuggerAgent. +*/ +JSDebuggerAgent::~JSDebuggerAgent() +{} + +/*! + \reimp +*/ +void JSDebuggerAgent::scriptLoad(qint64 id, const QString & program, + const QString &fileName, int ) +{ + Q_UNUSED(program); + filenames.insert(id, QUrl(fileName).toLocalFile()); +} + +/*! + \reimp +*/ +void JSDebuggerAgent::scriptUnload(qint64 id) +{ + filenames.remove(id); +} + +/*! + \reimp +*/ +void JSDebuggerAgent::contextPush() +{ +} + +/*! + \reimp +*/ +void JSDebuggerAgent::contextPop() +{ +} + +/*! + \reimp +*/ +void JSDebuggerAgent::functionEntry(qint64 scriptId) +{ + Q_UNUSED(scriptId); + stepDepth++; +} + +/*! + \reimp +*/ +void JSDebuggerAgent::functionExit(qint64 scriptId, const QScriptValue &returnValue) +{ + Q_UNUSED(scriptId); + Q_UNUSED(returnValue); + stepDepth--; +} + +/*! + \reimp +*/ +void JSDebuggerAgent::positionChange(qint64 scriptId, + int lineNumber, int columnNumber) +{ + Q_UNUSED(columnNumber); + + if(state == Stopped) + return; //no re-entrency + + // check breakpoints + if (!breakpointList.isEmpty()) { + QHash<qint64, QString>::const_iterator it = filenames.constFind(scriptId); + if (it == filenames.constEnd()) { + // It is possible that the scripts are loaded before the agent is attached + QString filename = QUrl(QScriptContextInfo(engine()->currentContext()).fileName()).toLocalFile(); + QPair<QString, qint32> key = qMakePair(filename, lineNumber); + it = filenames.insert(scriptId, filename); + } + QPair<QString, qint32> key = qMakePair(*it, lineNumber); + if (breakpointList.contains(key)) { + stopped(); + return; + } + } + + switch (state) { + case NoState: + case Stopped: + // Do nothing + break; + case SteppingOutState: + if (stepDepth >= 0) + break; + //fallthough + case SteppingOverState: + if (stepDepth > 0) + break; + //fallthough + case SteppingIntoState: + stopped(); + break; + } + +} + +/*! + \reimp +*/ +void JSDebuggerAgent::exceptionThrow(qint64 scriptId, + const QScriptValue &exception, + bool hasHandler) +{ + Q_UNUSED(scriptId); + Q_UNUSED(exception); + Q_UNUSED(hasHandler); +// qDebug() << Q_FUNC_INFO << exception.toString() << hasHandler; +#if 0 //sometimes, we get exceptions that we should just ignore. + if (!hasHandler && state != Stopped) + stopped(true, exception); +#endif +} + +/*! + \reimp +*/ +void JSDebuggerAgent::exceptionCatch(qint64 scriptId, + const QScriptValue &exception) +{ + Q_UNUSED(scriptId); + Q_UNUSED(exception); +} + +bool JSDebuggerAgent::supportsExtension(QScriptEngineAgent::Extension extension) const +{ + return extension == QScriptEngineAgent::DebuggerInvocationRequest; +} + +QVariant JSDebuggerAgent::extension(QScriptEngineAgent::Extension extension, const QVariant& argument) +{ + if (extension == QScriptEngineAgent::DebuggerInvocationRequest) { + stopped(); + return QVariant(); + } + return QScriptEngineAgent::extension(extension, argument); +} + + + +void JSDebuggerAgent::messageReceived(const QByteArray& message) +{ + QDataStream ds(message); + QByteArray command; + ds >> command; + if (command == "BREAKPOINTS") { + ds >> breakpointList; + } else if (command == "WATCH_EXPRESSIONS") { + ds >> watchExpressions; + } else if (command == "STEPOVER") { + stepDepth = 0; + state = SteppingOverState; + continueExec(); + } else if (command == "STEPINTO" || command == "INTERRUPT") { + stepDepth = 0; + state = SteppingIntoState; + continueExec(); + } else if (command == "STEPOUT") { + stepDepth = 0; + state = SteppingOutState; + continueExec(); + } else if (command == "CONTINUE") { + state = NoState; + continueExec(); + } else if (command == "EXEC") { + SetupExecEnv execEnv(this); + + QByteArray id; + QString expr; + ds >> id >> expr; + + JSAgentWatchData data = JSAgentWatchData::fromScriptValue(expr, engine()->evaluate(expr)); + knownObjectIds << data.objectId; + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("RESULT") << id << data; + sendMessage(reply); + } else if (command == "EXPAND") { + SetupExecEnv execEnv(this); + + QByteArray requestId; + quint64 objectId; + ds >> requestId >> objectId; + QScriptValue v; + if (knownObjectIds.contains(objectId)) + v = engine()->objectById(objectId); + + QList<JSAgentWatchData> result = expandObject(v); + recordKnownObjects(result); + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("EXPANDED") << requestId << result; + sendMessage(reply); + + } else if (command == "ACTIVATE_FRAME") { + SetupExecEnv execEnv(this); + + int frameId; + ds >> frameId; + + int deep = 0; + QScriptContext *ctx = engine()->currentContext(); + while (ctx && deep < frameId) { + ctx = ctx->parentContext(); + deep++; + } + + QList<JSAgentWatchData> locals = getLocals(ctx); + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("LOCALS") << frameId << locals; + sendMessage(reply); + } else if (command == "SET_PROPERTY") { + SetupExecEnv execEnv(this); + + QByteArray id; + qint64 objectId; + QString property; + QString value; + ds >> id >> objectId >> property >> value; + + if (knownObjectIds.contains(objectId)) { + QScriptValue object; + object = engine()->objectById(objectId); + + if(object.isObject()) { + QScriptValue result = engine()->evaluate(value); + object.setProperty(property, result); + } + } + + //TODO: feedback + } else if (command == "PING") { + int ping; + ds >> ping; + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("PONG") << ping; + sendMessage(reply); + } else { + qDebug() << Q_FUNC_INFO << "Unknown command" << command; + } + + QDeclarativeDebugService::messageReceived(message); +} + +void JSDebuggerAgent::stopped(bool becauseOfException, const QScriptValue& exception) +{ + knownObjectIds.clear(); + state = Stopped; + QList<QPair<QString, QPair<QString, qint32> > > backtrace; + + for (QScriptContext* ctx = engine()->currentContext(); ctx; ctx = ctx->parentContext()) { + QScriptContextInfo info(ctx); + + QString functionName = info.functionName(); + if (functionName.isEmpty()) { + if (ctx->parentContext()) { + switch (info.functionType()) { + case QScriptContextInfo::ScriptFunction: + functionName = QLatin1String("<anonymous>"); + break; + case QScriptContextInfo::NativeFunction: + functionName = QLatin1String("<native>"); + break; + case QScriptContextInfo::QtFunction: + case QScriptContextInfo::QtPropertyFunction: + functionName = QLatin1String("<native slot>"); + break; + } + } else { + functionName = QLatin1String("<global>"); + } + } + int lineNumber = info.lineNumber(); + if (lineNumber == -1) // if the line number is unknown, fallback to the function line number + lineNumber = info.functionStartLineNumber(); + backtrace.append(qMakePair(functionName, qMakePair( QUrl(info.fileName()).toLocalFile(), lineNumber ) ) ); + } + QList<JSAgentWatchData> watches; + foreach (const QString &expr, watchExpressions) + watches << JSAgentWatchData::fromScriptValue(expr, engine()->evaluate(expr)); + recordKnownObjects(watches); + + QList<JSAgentWatchData> locals = getLocals(engine()->currentContext()); + + if (!becauseOfException) { + // Clear any exceptions occurred during locals evaluation. + engine()->clearExceptions(); + } + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("STOPPED") << backtrace << watches << locals << becauseOfException << exception.toString(); + sendMessage(reply); + + loop.exec(QEventLoop::ExcludeUserInputEvents); +} + +void JSDebuggerAgent::continueExec() +{ + loop.quit(); +} + +void JSDebuggerAgent::enabledChanged(bool on) +{ + engine()->setAgent(on ? this : 0); +} + +} // namespace QmlJSDebugger diff --git a/share/qtcreator/qml/qmljsdebugger/private_headers.pri b/share/qtcreator/qml/qmljsdebugger/private_headers.pri new file mode 100644 index 0000000000..fc35396178 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/private_headers.pri @@ -0,0 +1,17 @@ +# Try to find location of Qt private headers (see README) +isEmpty(QT_PRIVATE_HEADERS) { + QT_PRIVATE_HEADERS = $$[QT_INSTALL_HEADERS] +} + +INCLUDEPATH += \ + $${QT_PRIVATE_HEADERS} \ + $${QT_PRIVATE_HEADERS}/QtCore \ + $${QT_PRIVATE_HEADERS}/QtGui \ + $${QT_PRIVATE_HEADERS}/QtScript \ + $${QT_PRIVATE_HEADERS}/QtDeclarative +DEPENDPATH += \ + $${QT_PRIVATE_HEADERS} \ + $${QT_PRIVATE_HEADERS}/QtCore \ + $${QT_PRIVATE_HEADERS}/QtGui \ + $${QT_PRIVATE_HEADERS}/QtScript \ + $${QT_PRIVATE_HEADERS}/QtDeclarative diff --git a/share/qtcreator/qml/qmljsdebugger/qdeclarativeobserverservice.cpp b/share/qtcreator/qml/qmljsdebugger/qdeclarativeobserverservice.cpp new file mode 100644 index 0000000000..16b5145e74 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/qdeclarativeobserverservice.cpp @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** 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. +** +** 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. +** +** 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. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeobserverservice.h" + +#include <QStringList> +#include <QColor> + +#include <QDebug> + +namespace QmlJSDebugger { + +Q_GLOBAL_STATIC(QDeclarativeObserverService, serviceInstance) + +QDeclarativeObserverService::QDeclarativeObserverService() + : QDeclarativeDebugService(QLatin1String("QDeclarativeObserverMode")) +{ +} + +QDeclarativeObserverService *QDeclarativeObserverService::instance() +{ + return serviceInstance(); +} + +void QDeclarativeObserverService::enabledChanged(bool enabled) +{ + emit debuggingClientChanged(enabled); +} + +void QDeclarativeObserverService::messageReceived(const QByteArray &message) +{ + QDataStream ds(message); + + QByteArray type; + ds >> type; + + if (type == "SET_CURRENT_OBJECTS") { + int itemCount = 0; + ds >> itemCount; + + QList<QObject*> selectedObjects; + for(int i = 0; i < itemCount; ++i) { + int debugId = -1; + ds >> debugId; + QObject *obj = objectForId(debugId); + + if (obj) + selectedObjects << obj; + } + + emit currentObjectsChanged(selectedObjects); + + } else if (type == "RELOAD") { + emit reloadRequested(); + } else if (type == "SET_ANIMATION_SPEED") { + qreal speed; + ds >> speed; + emit animationSpeedChangeRequested(speed); + } else if (type == "CHANGE_TOOL") { + QByteArray toolName; + ds >> toolName; + if (toolName == "COLOR_PICKER") { + emit colorPickerToolRequested(); + } else if (toolName == "SELECT") { + emit selectToolRequested(); + } else if (toolName == "SELECT_MARQUEE") { + emit selectMarqueeToolRequested(); + } else if (toolName == "ZOOM") { + emit zoomToolRequested(); + } + } else if (type == "SET_DESIGN_MODE") { + bool inDesignMode; + ds >> inDesignMode; + emit designModeBehaviorChanged(inDesignMode); + } else if (type == "CREATE_OBJECT") { + QString qml; + int parentId; + QString filename; + QStringList imports; + ds >> qml >> parentId >> imports >> filename; + emit objectCreationRequested(qml, objectForId(parentId), imports, filename); + } else if (type == "DESTROY_OBJECT") { + int debugId; + ds >> debugId; + if (QObject* obj = objectForId(debugId)) + obj->deleteLater(); + } else if (type == "MOVE_OBJECT") { + int debugId, newParent; + ds >> debugId >> newParent; + emit objectReparentRequested(objectForId(debugId), objectForId(newParent)); + } else if (type == "OBJECT_ID_LIST") { + int itemCount; + ds >> itemCount; + m_stringIdForObjectId.clear(); + for(int i = 0; i < itemCount; ++i) { + int itemDebugId; + QString itemIdString; + ds >> itemDebugId + >> itemIdString; + + m_stringIdForObjectId.insert(itemDebugId, itemIdString); + } + } else if (type == "SET_CONTEXT_PATH_IDX") { + int contextPathIndex; + ds >> contextPathIndex; + emit contextPathIndexChanged(contextPathIndex); + } else if (type == "CLEAR_COMPONENT_CACHE") { + emit clearComponentCacheRequested(); + } +} + +void QDeclarativeObserverService::setDesignModeBehavior(bool inDesignMode) +{ + QByteArray message; + QDataStream ds(&message, QIODevice::WriteOnly); + + ds << QByteArray("SET_DESIGN_MODE") + << inDesignMode; + + sendMessage(message); +} + +void QDeclarativeObserverService::setCurrentObjects(QList<QObject*> objects) +{ + QByteArray message; + QDataStream ds(&message, QIODevice::WriteOnly); + + ds << QByteArray("CURRENT_OBJECTS_CHANGED") + << objects.length(); + + foreach(QObject *object, objects) { + int id = idForObject(object); + ds << id; + } + + sendMessage(message); +} + +void QDeclarativeObserverService::setCurrentTool(QmlJSDebugger::Constants::DesignTool toolId) +{ + QByteArray message; + QDataStream ds(&message, QIODevice::WriteOnly); + + ds << QByteArray("TOOL_CHANGED") + << toolId; + + sendMessage(message); +} + +void QDeclarativeObserverService::setAnimationSpeed(qreal slowdownFactor) +{ + + QByteArray message; + QDataStream ds(&message, QIODevice::WriteOnly); + + ds << QByteArray("ANIMATION_SPEED_CHANGED") + << slowdownFactor; + + sendMessage(message); +} + +void QDeclarativeObserverService::reloaded() +{ + QByteArray message; + QDataStream ds(&message, QIODevice::WriteOnly); + + ds << QByteArray("RELOADED"); + + sendMessage(message); +} + +void QDeclarativeObserverService::selectedColorChanged(const QColor &color) +{ + QByteArray message; + QDataStream ds(&message, QIODevice::WriteOnly); + + ds << QByteArray("COLOR_CHANGED") + << color; + + sendMessage(message); +} + +void QDeclarativeObserverService::contextPathUpdated(const QStringList &contextPath) +{ + QByteArray message; + QDataStream ds(&message, QIODevice::WriteOnly); + + ds << QByteArray("CONTEXT_PATH_UPDATED") + << contextPath; + + sendMessage(message); +} + +QString QDeclarativeObserverService::idStringForObject(QObject *obj) const +{ + int id = idForObject(obj); + QString idString = m_stringIdForObjectId.value(id, QString()); + return idString; +} + +} // namespace QmlJSDebugger diff --git a/share/qtcreator/qml/qmljsdebugger/qdeclarativeviewobserver.cpp b/share/qtcreator/qml/qmljsdebugger/qdeclarativeviewobserver.cpp new file mode 100644 index 0000000000..81cd9b018b --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/qdeclarativeviewobserver.cpp @@ -0,0 +1,804 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 "qdeclarativeviewobserver.h" +#include "qdeclarativeviewobserver_p.h" +#include "qdeclarativeobserverservice.h" +#include "selectiontool.h" +#include "zoomtool.h" +#include "colorpickertool.h" +#include "layeritem.h" +#include "boundingrecthighlighter.h" +#include "subcomponenteditortool.h" +#include "qmltoolbar.h" +#include "jsdebuggeragent.h" + +#include <QDeclarativeItem> +#include <QDeclarativeEngine> +#include <QDeclarativeContext> +#include <QDeclarativeExpression> +#include <QWidget> +#include <QMouseEvent> +#include <QGraphicsObject> +#include <QApplication> + +#include <QAbstractAnimation> +#include <private/qdeclarativeengine_p.h> +#include <private/qabstractanimation_p.h> + +namespace QmlJSDebugger { + +const int SceneChangeUpdateInterval = 5000; + +QDeclarativeViewObserverPrivate::QDeclarativeViewObserverPrivate(QDeclarativeViewObserver *q) : + q(q), + designModeBehavior(false), + executionPaused(false), + slowdownFactor(1.0f), + jsDebuggerAgent(0), + toolbar(0) +{ +} + +QDeclarativeViewObserverPrivate::~QDeclarativeViewObserverPrivate() +{ +} + +QDeclarativeViewObserver::QDeclarativeViewObserver(QDeclarativeView *view, QObject *parent) : + QObject(parent), data(new QDeclarativeViewObserverPrivate(this)) +{ + data->view = view; + data->manipulatorLayer = new LayerItem(view->scene()); + data->selectionTool = new SelectionTool(this); + data->zoomTool = new ZoomTool(this); + data->colorPickerTool = new ColorPickerTool(this); + data->boundingRectHighlighter = new BoundingRectHighlighter(this); + data->subcomponentEditorTool = new SubcomponentEditorTool(this); + data->currentTool = data->selectionTool; + + data->view->setMouseTracking(true); + data->view->viewport()->installEventFilter(this); + + data->debugService = QDeclarativeObserverService::instance(); + connect(data->debugService, SIGNAL(designModeBehaviorChanged(bool)), SLOT(setDesignModeBehavior(bool))); + connect(data->debugService, SIGNAL(reloadRequested()), SLOT(_q_reloadView())); + connect(data->debugService, + SIGNAL(currentObjectsChanged(QList<QObject*>)), + SLOT(_q_onCurrentObjectsChanged(QList<QObject*>))); + connect(data->debugService, SIGNAL(animationSpeedChangeRequested(qreal)), SLOT(changeAnimationSpeed(qreal))); + connect(data->debugService, SIGNAL(colorPickerToolRequested()), SLOT(_q_changeToColorPickerTool())); + connect(data->debugService, SIGNAL(selectMarqueeToolRequested()), SLOT(_q_changeToMarqueeSelectTool())); + connect(data->debugService, SIGNAL(selectToolRequested()), SLOT(_q_changeToSingleSelectTool())); + connect(data->debugService, SIGNAL(zoomToolRequested()), SLOT(_q_changeToZoomTool())); + connect(data->debugService, + SIGNAL(objectCreationRequested(QString,QObject*,QStringList,QString)), + SLOT(_q_createQmlObject(QString,QObject*,QStringList,QString))); + connect(data->debugService, + SIGNAL(objectReparentRequested(QObject *, QObject *)), + SLOT(_q_reparentQmlObject(QObject *, QObject *))); + connect(data->debugService, SIGNAL(contextPathIndexChanged(int)), SLOT(_q_changeContextPathIndex(int))); + connect(data->debugService, SIGNAL(clearComponentCacheRequested()), SLOT(_q_clearComponentCache())); + connect(data->view, SIGNAL(statusChanged(QDeclarativeView::Status)), SLOT(_q_onStatusChanged(QDeclarativeView::Status))); + + connect(data->colorPickerTool, SIGNAL(selectedColorChanged(QColor)), SIGNAL(selectedColorChanged(QColor))); + connect(data->colorPickerTool, SIGNAL(selectedColorChanged(QColor)), + data->debugService, SLOT(selectedColorChanged(QColor))); + + connect(data->subcomponentEditorTool, SIGNAL(cleared()), SIGNAL(inspectorContextCleared())); + connect(data->subcomponentEditorTool, SIGNAL(contextPushed(QString)), SIGNAL(inspectorContextPushed(QString))); + connect(data->subcomponentEditorTool, SIGNAL(contextPopped()), SIGNAL(inspectorContextPopped())); + connect(data->subcomponentEditorTool, SIGNAL(contextPathChanged(QStringList)), data->debugService, SLOT(contextPathUpdated(QStringList))); + + data->createToolbar(); + + data->_q_changeToSingleSelectTool(); + + // always start debug mode - that's what this design view is for. + setDebugMode(true); +} + +QDeclarativeViewObserver::~QDeclarativeViewObserver() +{ +} + +void QDeclarativeViewObserver::setObserverContext(int contextIndex) +{ + if (data->subcomponentEditorTool->contextIndex() != contextIndex) { + QGraphicsObject *object = data->subcomponentEditorTool->setContext(contextIndex); + if (object) + data->debugService->setCurrentObjects(QList<QObject*>() << object); + } +} + +void QDeclarativeViewObserverPrivate::_q_reloadView() +{ + subcomponentEditorTool->clear(); + clearHighlight(); + emit q->reloadRequested(); +} + +void QDeclarativeViewObserverPrivate::clearEditorItems() +{ + clearHighlight(); + setSelectedItems(QList<QGraphicsItem*>()); +} + +bool QDeclarativeViewObserver::eventFilter(QObject *obj, QEvent *event) + { + switch (event->type()) { + case QEvent::Leave: { + if (leaveEvent(event)) + return true; + break; + } + case QEvent::MouseButtonPress: { + if (mousePressEvent(static_cast<QMouseEvent*>(event))) + return true; + break; + } + case QEvent::MouseMove: { + if (mouseMoveEvent(static_cast<QMouseEvent*>(event))) + return true; + break; + } + case QEvent::MouseButtonRelease: { + if (mouseReleaseEvent(static_cast<QMouseEvent*>(event))) + return true; + break; + } + case QEvent::KeyPress: { + if (keyPressEvent(static_cast<QKeyEvent*>(event))) + return true; + break; + } + case QEvent::KeyRelease: { + if (keyReleaseEvent(static_cast<QKeyEvent*>(event))) + return true; + break; + } + case QEvent::MouseButtonDblClick: { + if (mouseDoubleClickEvent(static_cast<QMouseEvent*>(event))) + return true; + break; + } + case QEvent::Wheel: { + if (wheelEvent(static_cast<QWheelEvent*>(event))) + return true; + break; + } + default: { + break; + } + } //switch + + // standard event processing + return QObject::eventFilter(obj, event); +} + +bool QDeclarativeViewObserver::leaveEvent(QEvent * /*event*/) +{ + if (!data->designModeBehavior) + return false; + data->clearHighlight(); + return true; +} + +bool QDeclarativeViewObserver::mousePressEvent(QMouseEvent *event) +{ + if (!data->designModeBehavior) + return false; + data->cursorPos = event->pos(); + data->currentTool->mousePressEvent(event); + return true; +} + +bool QDeclarativeViewObserver::mouseMoveEvent(QMouseEvent *event) +{ + if (!data->designModeBehavior) { + data->clearEditorItems(); + return false; + } + data->cursorPos = event->pos(); + + QList<QGraphicsItem*> selItems = data->selectableItems(event->pos()); + if (!selItems.isEmpty()) { + declarativeView()->setToolTip(AbstractFormEditorTool::titleForItem(selItems.first())); + } else { + declarativeView()->setToolTip(QString()); + } + if (event->buttons()) { + data->subcomponentEditorTool->mouseMoveEvent(event); + data->currentTool->mouseMoveEvent(event); + } else { + data->subcomponentEditorTool->hoverMoveEvent(event); + data->currentTool->hoverMoveEvent(event); + } + return true; +} + +bool QDeclarativeViewObserver::mouseReleaseEvent(QMouseEvent *event) +{ + if (!data->designModeBehavior) + return false; + data->subcomponentEditorTool->mouseReleaseEvent(event); + + data->cursorPos = event->pos(); + data->currentTool->mouseReleaseEvent(event); + + data->debugService->setCurrentObjects(AbstractFormEditorTool::toObjectList(selectedItems())); + return true; +} + +bool QDeclarativeViewObserver::keyPressEvent(QKeyEvent *event) +{ + if (!data->designModeBehavior) { + return false; + } + data->currentTool->keyPressEvent(event); + return true; +} + +bool QDeclarativeViewObserver::keyReleaseEvent(QKeyEvent *event) +{ + if (!data->designModeBehavior) { + return false; + } + + switch(event->key()) { + case Qt::Key_V: + data->_q_changeToSingleSelectTool(); + break; +// disabled because multiselection does not do anything useful without design mode +// case Qt::Key_M: +// data->_q_changeToMarqueeSelectTool(); +// break; + case Qt::Key_I: + data->_q_changeToColorPickerTool(); + break; + case Qt::Key_Z: + data->_q_changeToZoomTool(); + break; + case Qt::Key_Enter: + case Qt::Key_Return: + if (!data->selectedItems().isEmpty()) + data->subcomponentEditorTool->setCurrentItem(data->selectedItems().first()); + break; + case Qt::Key_Space: + if (data->executionPaused) { + continueExecution(data->slowdownFactor); + } else { + pauseExecution(); + } + break; + default: + break; + } + + data->currentTool->keyReleaseEvent(event); + return true; +} + +void QDeclarativeViewObserverPrivate::_q_createQmlObject(const QString &qml, QObject *parent, const QStringList &importList, const QString &filename) +{ + if (!parent) + return; + + QString imports; + foreach(const QString &s, importList) { + imports += s + "\n"; + } + + QDeclarativeContext *parentContext = view->engine()->contextForObject(parent); + QDeclarativeComponent component(view->engine(), q); + QByteArray constructedQml = QString(imports + qml).toLatin1(); + + component.setData(constructedQml, filename); + QObject *newObject = component.create(parentContext); + if (newObject) { + newObject->setParent(parent); + QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent); + QDeclarativeItem *newItem = qobject_cast<QDeclarativeItem*>(newObject); + if (parentItem && newItem) { + newItem->setParentItem(parentItem); + } + } +} + +void QDeclarativeViewObserverPrivate::_q_reparentQmlObject(QObject *object, QObject *newParent) +{ + if (!newParent) + return; + + object->setParent(newParent); + QDeclarativeItem *newParentItem = qobject_cast<QDeclarativeItem*>(newParent); + QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(object); + if (newParentItem && item) { + item->setParentItem(newParentItem); + } +} + +void QDeclarativeViewObserverPrivate::_q_clearComponentCache() +{ + view->engine()->clearComponentCache(); +} + +QGraphicsItem *QDeclarativeViewObserverPrivate::currentRootItem() const +{ + return subcomponentEditorTool->currentRootItem(); +} + +bool QDeclarativeViewObserver::mouseDoubleClickEvent(QMouseEvent *event) +{ + if (!data->designModeBehavior) + return false; + + if (data->currentToolMode != Constants::SelectionToolMode + && data->currentToolMode != Constants::MarqueeSelectionToolMode) + return true; + + QGraphicsItem *itemToEnter = 0; + QList<QGraphicsItem*> itemList = data->view->items(event->pos()); + data->filterForSelection(itemList); + + if (data->selectedItems().isEmpty() && !itemList.isEmpty()) { + itemToEnter = itemList.first(); + } else if (!data->selectedItems().isEmpty() && !itemList.isEmpty()) { + itemToEnter = itemList.first(); + } + + if (itemToEnter) + itemToEnter = data->subcomponentEditorTool->firstChildOfContext(itemToEnter); + + data->subcomponentEditorTool->setCurrentItem(itemToEnter); + data->subcomponentEditorTool->mouseDoubleClickEvent(event); + + if ((event->buttons() & Qt::LeftButton) && itemToEnter) { + QGraphicsObject *objectToEnter = itemToEnter->toGraphicsObject(); + if (objectToEnter) + data->debugService->setCurrentObjects(QList<QObject*>() << objectToEnter); + } + + return true; +} + +bool QDeclarativeViewObserver::wheelEvent(QWheelEvent *event) +{ + if (!data->designModeBehavior) + return false; + data->currentTool->wheelEvent(event); + return true; +} + +void QDeclarativeViewObserverPrivate::enterContext(QGraphicsItem *itemToEnter) +{ + QGraphicsItem *itemUnderCurrentContext = itemToEnter; + if (itemUnderCurrentContext) + itemUnderCurrentContext = subcomponentEditorTool->firstChildOfContext(itemToEnter); + + if (itemUnderCurrentContext) + subcomponentEditorTool->setCurrentItem(itemToEnter); +} + +void QDeclarativeViewObserver::setDesignModeBehavior(bool value) +{ + emit designModeBehaviorChanged(value); + + data->toolbar->setDesignModeBehavior(value); + data->debugService->setDesignModeBehavior(value); + + data->designModeBehavior = value; + if (data->subcomponentEditorTool) { + data->subcomponentEditorTool->clear(); + data->clearHighlight(); + data->setSelectedItems(QList<QGraphicsItem*>()); + + if (data->view->rootObject()) + data->subcomponentEditorTool->pushContext(data->view->rootObject()); + } + + if (!data->designModeBehavior) + data->clearEditorItems(); +} + +bool QDeclarativeViewObserver::designModeBehavior() +{ + return data->designModeBehavior; +} + +void QDeclarativeViewObserverPrivate::changeTool(Constants::DesignTool tool, Constants::ToolFlags /*flags*/) +{ + switch(tool) { + case Constants::SelectionToolMode: + _q_changeToSingleSelectTool(); + break; + case Constants::NoTool: + default: + currentTool = 0; + break; + } +} + +void QDeclarativeViewObserverPrivate::setSelectedItemsForTools(QList<QGraphicsItem *> items) +{ + currentSelection.clear(); + foreach(QGraphicsItem *item, items) { + if (item) { + QGraphicsObject *obj = item->toGraphicsObject(); + if (obj) + currentSelection << obj; + } + } + currentTool->updateSelectedItems(); +} + +void QDeclarativeViewObserverPrivate::setSelectedItems(QList<QGraphicsItem *> items) +{ + setSelectedItemsForTools(items); + debugService->setCurrentObjects(AbstractFormEditorTool::toObjectList(items)); +} + +QList<QGraphicsItem *> QDeclarativeViewObserverPrivate::selectedItems() +{ + QList<QGraphicsItem *> selection; + foreach(const QWeakPointer<QGraphicsObject> &selectedObject, currentSelection) { + if (selectedObject.isNull()) { + currentSelection.removeOne(selectedObject); + } else { + selection << selectedObject.data(); + } + } + + return selection; +} + +void QDeclarativeViewObserver::setSelectedItems(QList<QGraphicsItem *> items) +{ + data->setSelectedItems(items); +} + +QList<QGraphicsItem *> QDeclarativeViewObserver::selectedItems() +{ + return data->selectedItems(); +} + +QDeclarativeView *QDeclarativeViewObserver::declarativeView() +{ + return data->view; +} + +void QDeclarativeViewObserverPrivate::clearHighlight() +{ + boundingRectHighlighter->clear(); +} + +void QDeclarativeViewObserverPrivate::highlight(QGraphicsObject * item, ContextFlags flags) +{ + highlight(QList<QGraphicsObject*>() << item, flags); +} + +void QDeclarativeViewObserverPrivate::highlight(QList<QGraphicsObject *> items, ContextFlags flags) +{ + if (items.isEmpty()) + return; + + QList<QGraphicsObject*> objectList; + foreach(QGraphicsItem *item, items) { + QGraphicsItem *child = item; + if (flags & ContextSensitive) + child = subcomponentEditorTool->firstChildOfContext(item); + + if (child) { + QGraphicsObject *childObject = child->toGraphicsObject(); + if (childObject) + objectList << childObject; + } + } + + boundingRectHighlighter->highlight(objectList); +} + +bool QDeclarativeViewObserverPrivate::mouseInsideContextItem() const +{ + return subcomponentEditorTool->containsCursor(cursorPos.toPoint()); +} + +QList<QGraphicsItem*> QDeclarativeViewObserverPrivate::selectableItems(const QPointF &scenePos) const +{ + QList<QGraphicsItem*> itemlist = view->scene()->items(scenePos); + return filterForCurrentContext(itemlist); +} + +QList<QGraphicsItem*> QDeclarativeViewObserverPrivate::selectableItems(const QPoint &pos) const +{ + QList<QGraphicsItem*> itemlist = view->items(pos); + return filterForCurrentContext(itemlist); +} + +QList<QGraphicsItem*> QDeclarativeViewObserverPrivate::selectableItems(const QRectF &sceneRect, Qt::ItemSelectionMode selectionMode) const +{ + QList<QGraphicsItem*> itemlist = view->scene()->items(sceneRect, selectionMode); + + return filterForCurrentContext(itemlist); +} + +void QDeclarativeViewObserverPrivate::_q_changeToSingleSelectTool() +{ + currentToolMode = Constants::SelectionToolMode; + selectionTool->setRubberbandSelectionMode(false); + + changeToSelectTool(); + + emit q->selectToolActivated(); + debugService->setCurrentTool(Constants::SelectionToolMode); +} + +void QDeclarativeViewObserverPrivate::changeToSelectTool() +{ + if (currentTool == selectionTool) + return; + + currentTool->clear(); + currentTool = selectionTool; + currentTool->clear(); + currentTool->updateSelectedItems(); +} + +void QDeclarativeViewObserverPrivate::_q_changeToMarqueeSelectTool() +{ + changeToSelectTool(); + currentToolMode = Constants::MarqueeSelectionToolMode; + selectionTool->setRubberbandSelectionMode(true); + + emit q->marqueeSelectToolActivated(); + debugService->setCurrentTool(Constants::MarqueeSelectionToolMode); +} + +void QDeclarativeViewObserverPrivate::_q_changeToZoomTool() +{ + currentToolMode = Constants::ZoomMode; + currentTool->clear(); + currentTool = zoomTool; + currentTool->clear(); + + emit q->zoomToolActivated(); + debugService->setCurrentTool(Constants::ZoomMode); +} + +void QDeclarativeViewObserverPrivate::_q_changeToColorPickerTool() +{ + if (currentTool == colorPickerTool) + return; + + currentToolMode = Constants::ColorPickerMode; + currentTool->clear(); + currentTool = colorPickerTool; + currentTool->clear(); + + emit q->colorPickerActivated(); + debugService->setCurrentTool(Constants::ColorPickerMode); +} + +void QDeclarativeViewObserverPrivate::_q_changeContextPathIndex(int index) +{ + subcomponentEditorTool->setContext(index); +} + +void QDeclarativeViewObserver::changeAnimationSpeed(qreal slowdownFactor) +{ + data->slowdownFactor = slowdownFactor; + + if (data->slowdownFactor != 0) { + continueExecution(data->slowdownFactor); + } else { + pauseExecution(); + } +} + +void QDeclarativeViewObserver::continueExecution(qreal slowdownFactor) +{ + Q_ASSERT(slowdownFactor > 0); + + data->slowdownFactor = slowdownFactor; + static const qreal animSpeedSnapDelta = 0.01f; + bool useStandardSpeed = (qAbs(1.0f - data->slowdownFactor) < animSpeedSnapDelta); + + QUnifiedTimer *timer = QUnifiedTimer::instance(); + timer->setSlowdownFactor(data->slowdownFactor); + timer->setSlowModeEnabled(!useStandardSpeed); + data->executionPaused = false; + + emit executionStarted(data->slowdownFactor); + data->debugService->setAnimationSpeed(data->slowdownFactor); +} + +void QDeclarativeViewObserver::pauseExecution() +{ + QUnifiedTimer *timer = QUnifiedTimer::instance(); + timer->setSlowdownFactor(0); + timer->setSlowModeEnabled(true); + data->executionPaused = true; + + emit executionPaused(); + data->debugService->setAnimationSpeed(0); +} + +void QDeclarativeViewObserverPrivate::_q_applyChangesFromClient() +{ + +} + + +QList<QGraphicsItem*> QDeclarativeViewObserverPrivate::filterForSelection(QList<QGraphicsItem*> &itemlist) const +{ + foreach(QGraphicsItem *item, itemlist) { + if (isEditorItem(item) || !subcomponentEditorTool->isChildOfContext(item)) + itemlist.removeOne(item); + } + + return itemlist; +} + +QList<QGraphicsItem*> QDeclarativeViewObserverPrivate::filterForCurrentContext(QList<QGraphicsItem*> &itemlist) const +{ + foreach(QGraphicsItem *item, itemlist) { + + if (isEditorItem(item) || !subcomponentEditorTool->isDirectChildOfContext(item)) { + + // if we're a child, but not directly, replace with the parent that is directly in context. + if (QGraphicsItem *contextParent = subcomponentEditorTool->firstChildOfContext(item)) { + if (contextParent != item) { + if (itemlist.contains(contextParent)) { + itemlist.removeOne(item); + } else { + itemlist.replace(itemlist.indexOf(item), contextParent); + } + } + } else { + itemlist.removeOne(item); + } + } + } + + return itemlist; +} + +bool QDeclarativeViewObserverPrivate::isEditorItem(QGraphicsItem *item) const +{ + return (item->type() == Constants::EditorItemType + || item->type() == Constants::ResizeHandleItemType + || item->data(Constants::EditorItemDataKey).toBool()); +} + +void QDeclarativeViewObserverPrivate::_q_onStatusChanged(QDeclarativeView::Status status) +{ + if (status == QDeclarativeView::Ready) { + if (view->rootObject()) { + if (subcomponentEditorTool->contextIndex() != -1) + subcomponentEditorTool->clear(); + subcomponentEditorTool->pushContext(view->rootObject()); + emit q->executionStarted(1.0f); + + } + debugService->reloaded(); + } +} + +void QDeclarativeViewObserverPrivate::_q_onCurrentObjectsChanged(QList<QObject*> objects) +{ + QList<QGraphicsItem*> items; + QList<QGraphicsObject*> gfxObjects; + foreach(QObject *obj, objects) { + QDeclarativeItem* declarativeItem = qobject_cast<QDeclarativeItem*>(obj); + if (declarativeItem) { + items << declarativeItem; + QGraphicsObject *gfxObj = declarativeItem->toGraphicsObject(); + if (gfxObj) + gfxObjects << gfxObj; + } + } + setSelectedItemsForTools(items); + clearHighlight(); + highlight(gfxObjects, QDeclarativeViewObserverPrivate::IgnoreContext); +} + +QString QDeclarativeViewObserver::idStringForObject(QObject *obj) +{ + return QDeclarativeObserverService::instance()->idStringForObject(obj); +} + +// adjusts bounding boxes on edges of screen to be visible +QRectF QDeclarativeViewObserver::adjustToScreenBoundaries(const QRectF &boundingRectInSceneSpace) +{ + int marginFromEdge = 1; + QRectF boundingRect(boundingRectInSceneSpace); + if (qAbs(boundingRect.left()) - 1 < 2) { + boundingRect.setLeft(marginFromEdge); + } + + QRect rect = data->view->rect(); + if (boundingRect.right() >= rect.right() ) { + boundingRect.setRight(rect.right() - marginFromEdge); + } + + if (qAbs(boundingRect.top()) - 1 < 2) { + boundingRect.setTop(marginFromEdge); + } + + if (boundingRect.bottom() >= rect.bottom() ) { + boundingRect.setBottom(rect.bottom() - marginFromEdge); + } + + return boundingRect; +} + +QToolBar *QDeclarativeViewObserver::toolbar() const +{ + return data->toolbar; +} + +void QDeclarativeViewObserverPrivate::createToolbar() +{ + toolbar = new QmlToolbar(q->declarativeView()); + QObject::connect(q, SIGNAL(selectedColorChanged(QColor)), toolbar, SLOT(setColorBoxColor(QColor))); + + QObject::connect(q, SIGNAL(designModeBehaviorChanged(bool)), toolbar, SLOT(setDesignModeBehavior(bool))); + + QObject::connect(toolbar, SIGNAL(designModeBehaviorChanged(bool)), q, SLOT(setDesignModeBehavior(bool))); + QObject::connect(toolbar, SIGNAL(animationSpeedChanged(qreal)), q, SLOT(changeAnimationSpeed(qreal))); + QObject::connect(toolbar, SIGNAL(colorPickerSelected()), q, SLOT(_q_changeToColorPickerTool())); + QObject::connect(toolbar, SIGNAL(zoomToolSelected()), q, SLOT(_q_changeToZoomTool())); + QObject::connect(toolbar, SIGNAL(selectToolSelected()), q, SLOT(_q_changeToSingleSelectTool())); + QObject::connect(toolbar, SIGNAL(marqueeSelectToolSelected()), q, SLOT(_q_changeToMarqueeSelectTool())); + + QObject::connect(toolbar, SIGNAL(applyChangesFromQmlFileSelected()), q, SLOT(_q_applyChangesFromClient())); + + QObject::connect(q, SIGNAL(executionStarted(qreal)), toolbar, SLOT(setAnimationSpeed(qreal))); + QObject::connect(q, SIGNAL(executionPaused()), toolbar, SLOT(setAnimationSpeed())); + + QObject::connect(q, SIGNAL(selectToolActivated()), toolbar, SLOT(activateSelectTool())); + + // disabled features + //connect(d->m_toolbar, SIGNAL(applyChangesToQmlFileSelected()), SLOT(applyChangesToClient())); + //connect(q, SIGNAL(resizeToolActivated()), d->m_toolbar, SLOT(activateSelectTool())); + //connect(q, SIGNAL(moveToolActivated()), d->m_toolbar, SLOT(activateSelectTool())); + + QObject::connect(q, SIGNAL(colorPickerActivated()), toolbar, SLOT(activateColorPicker())); + QObject::connect(q, SIGNAL(zoomToolActivated()), toolbar, SLOT(activateZoom())); + QObject::connect(q, SIGNAL(marqueeSelectToolActivated()), toolbar, SLOT(activateMarqueeSelectTool())); +} + +void QDeclarativeViewObserver::setDebugMode(bool isDebugMode) +{ + if (isDebugMode && !data->jsDebuggerAgent) + data->jsDebuggerAgent = new JSDebuggerAgent(QDeclarativeEnginePrivate::getScriptEngine(data->view->engine())); +} + +} //namespace QmlJSDebugger + +#include <moc_qdeclarativeviewobserver.cpp> diff --git a/share/qtcreator/qml/qmljsdebugger/qdeclarativeviewobserver_p.h b/share/qtcreator/qml/qmljsdebugger/qdeclarativeviewobserver_p.h new file mode 100644 index 0000000000..a276c4350e --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/qdeclarativeviewobserver_p.h @@ -0,0 +1,141 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 QDECLARATIVEDESIGNVIEW_P_H +#define QDECLARATIVEDESIGNVIEW_P_H + +#include <QWeakPointer> +#include <QPointF> +#include <QTimer> + +#include "qdeclarativeviewobserver.h" +#include "qdeclarativeobserverservice.h" + +namespace QmlJSDebugger { + +class JSDebuggerAgent; +class QDeclarativeViewObserver; +class SelectionTool; +class ZoomTool; +class ColorPickerTool; +class LayerItem; +class BoundingRectHighlighter; +class SubcomponentEditorTool; +class QmlToolbar; +class CrumblePath; +class AbstractFormEditorTool; + +class QDeclarativeViewObserverPrivate +{ +public: + + enum ContextFlags { + IgnoreContext, + ContextSensitive + }; + + QDeclarativeViewObserverPrivate(QDeclarativeViewObserver *); + ~QDeclarativeViewObserverPrivate(); + + QDeclarativeView *view; + QDeclarativeViewObserver *q; + QDeclarativeObserverService *debugService; + + QPointF cursorPos; + QList<QWeakPointer<QGraphicsObject> > currentSelection; + + Constants::DesignTool currentToolMode; + AbstractFormEditorTool *currentTool; + + SelectionTool *selectionTool; + ZoomTool *zoomTool; + ColorPickerTool *colorPickerTool; + SubcomponentEditorTool *subcomponentEditorTool; + LayerItem *manipulatorLayer; + + BoundingRectHighlighter *boundingRectHighlighter; + + bool designModeBehavior; + + bool executionPaused; + qreal slowdownFactor; + + JSDebuggerAgent *jsDebuggerAgent; + + QmlToolbar *toolbar; + + void clearEditorItems(); + void createToolbar(); + void changeToSelectTool(); + QList<QGraphicsItem*> filterForCurrentContext(QList<QGraphicsItem*> &itemlist) const; + QList<QGraphicsItem*> filterForSelection(QList<QGraphicsItem*> &itemlist) const; + + QList<QGraphicsItem*> selectableItems(const QPoint &pos) const; + QList<QGraphicsItem*> selectableItems(const QPointF &scenePos) const; + QList<QGraphicsItem*> selectableItems(const QRectF &sceneRect, Qt::ItemSelectionMode selectionMode) const; + + void setSelectedItemsForTools(QList<QGraphicsItem *> items); + void setSelectedItems(QList<QGraphicsItem *> items); + QList<QGraphicsItem *> selectedItems(); + + void changeTool(Constants::DesignTool tool, + Constants::ToolFlags flags = Constants::NoToolFlags); + + void clearHighlight(); + void highlight(QList<QGraphicsObject *> item, ContextFlags flags = ContextSensitive); + void highlight(QGraphicsObject *item, ContextFlags flags = ContextSensitive); + + bool mouseInsideContextItem() const; + bool isEditorItem(QGraphicsItem *item) const; + + QGraphicsItem *currentRootItem() const; + + void enterContext(QGraphicsItem *itemToEnter); + + void _q_reloadView(); + void _q_onStatusChanged(QDeclarativeView::Status status); + void _q_onCurrentObjectsChanged(QList<QObject*> objects); + void _q_applyChangesFromClient(); + void _q_createQmlObject(const QString &qml, QObject *parent, + const QStringList &imports, const QString &filename = QString()); + void _q_reparentQmlObject(QObject *, QObject *); + + void _q_changeToSingleSelectTool(); + void _q_changeToMarqueeSelectTool(); + void _q_changeToZoomTool(); + void _q_changeToColorPickerTool(); + void _q_changeContextPathIndex(int index); + void _q_clearComponentCache(); + + static QDeclarativeViewObserverPrivate *get(QDeclarativeViewObserver *v) { return v->d_func(); } +}; + +} // namespace QmlJSDebugger + +#endif // QDECLARATIVEDESIGNVIEW_P_H diff --git a/share/qtcreator/qml/qmljsdebugger/qmljsdebugger-lib.pri b/share/qtcreator/qml/qmljsdebugger/qmljsdebugger-lib.pri new file mode 100644 index 0000000000..f8e482e38c --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/qmljsdebugger-lib.pri @@ -0,0 +1,35 @@ +QT += declarative script +INCLUDEPATH += $$PWD $$PWD/include editor +DEPENDPATH += $$PWD $$PWD/include editor + +contains(CONFIG, dll) { + DEFINES += BUILD_QMLJSDEBUGGER_LIB +} else { + DEFINES += BUILD_QMLJSDEBUGGER_STATIC_LIB +} + +include($$PWD/private_headers.pri) + +## Input +HEADERS += \ + $$PWD/include/jsdebuggeragent.h \ + $$PWD/include/qmljsdebugger_global.h + +SOURCES += \ + $$PWD/jsdebuggeragent.cpp + +contains(DEFINES, QMLOBSERVER) { + include($$PWD/editor/editor.pri) + + HEADERS += \ + $$PWD/include/qdeclarativeviewobserver.h \ + $$PWD/include/qdeclarativeobserverservice.h \ + $$PWD/include/qmlobserverconstants.h \ + $$PWD/qdeclarativeviewobserver_p.h + + SOURCES += \ + $$PWD/qdeclarativeviewobserver.cpp \ + $$PWD/qdeclarativeobserverservice.cpp +} + +OTHER_FILES += $$PWD/qmljsdebugger.pri diff --git a/share/qtcreator/qml/qmljsdebugger/qmljsdebugger.pri b/share/qtcreator/qml/qmljsdebugger/qmljsdebugger.pri new file mode 100644 index 0000000000..a4abeb9cd5 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/qmljsdebugger.pri @@ -0,0 +1,5 @@ +INCLUDEPATH += $$PWD/include +DEPENDPATH += $PPWD/include +QT += declarative script + +LIBS *= -l$$qtLibraryName(QmlJSDebugger) diff --git a/share/qtcreator/qml/qmljsdebugger/qmljsdebugger.pro b/share/qtcreator/qml/qmljsdebugger/qmljsdebugger.pro new file mode 100644 index 0000000000..5f3eb50958 --- /dev/null +++ b/share/qtcreator/qml/qmljsdebugger/qmljsdebugger.pro @@ -0,0 +1,10 @@ +TEMPLATE = lib +CONFIG+=dll +TARGET = QmlJSDebugger + +DEFINES += QMLOBSERVER + +unix:QMAKE_CXXFLAGS_DEBUG += -O3 + +include(../../../src/qtcreatorlibrary.pri) +include(qmljsdebugger-lib.pri) |