Commit 40148ad1 authored by Lasse Holmstedt's avatar Lasse Holmstedt

Added crumble path to QML observer for showing the current context

parent de4158bd
......@@ -160,33 +160,31 @@ 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) {
//QDeclarativeData *ddata = QDeclarativeData::get(declarativeItem);
//ddata->context->findObjectId(declarativeItem);
QDeclarativeContext *context = QDeclarativeEngine::contextForObject(declarativeItem);
if (context) {
// QDeclarativeContextData *cdata = QDeclarativeContextData::get(context);
// if (cdata)
// objectStringId = cdata->findObjectId(declarativeItem);
objectStringId = QDeclarativeDesignView::idStringForObject(declarativeItem);
}
objectStringId = QDeclarativeDesignView::idStringForObject(declarativeItem);
}
if (objectStringId.isEmpty())
objectStringId = gfxObject->objectName();
if (!objectStringId.isEmpty())
return tr("%1 (%2)").arg(objectStringId, className);
if (!objectStringId.isEmpty()) {
constructedName = objectStringId + " (" + className + ")";
} else {
if (!gfxObject->objectName().isEmpty())
constructedName = gfxObject->objectName() + " (" + className + ")";
}
}
return tr("(%1, type %2)").arg(className, QString::number(item->type()));
return className;
}
......
#include "crumblepath.h"
#include <QHBoxLayout>
#include <QPushButton>
#include <QStyle>
#include <QResizeEvent>
namespace QmlViewer {
static const int ArrowBorderSize = 12;
class CrumblePathButton : public QPushButton
{
public:
enum SegmentType {
LastSegment = 1,
MiddleSegment = 2,
FirstSegment = 4
};
explicit CrumblePathButton(const QString &title, QWidget *parent = 0);
void setSegmentType(int type);
private:
static QString middleSegmentSheet(bool useLeftPadding);
static QString lastSegmentSheet(bool useLeftPadding);
};
CrumblePathButton::CrumblePathButton(const QString &title, QWidget *parent)
: QPushButton(title, parent)
{
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
setToolTip(title);
setMinimumHeight(24);
setMaximumHeight(24);
setStyleSheet(lastSegmentSheet(true));
}
QString CrumblePathButton::middleSegmentSheet(bool useLeftPadding)
{
QString sheet = QString(
"QPushButton {"
"text-align: left;"
"color: #eeeeee;"
"border-image: url(:/qml/images/segment.png) 0 12 0 2;"
"border-width: 0 12px 0 2px;"
"padding-left:%1px;"
"}"
"QPushButton:hover {"
" border-image: url(:/qml/images/segment-hover.png) 0 12 0 2;"
"}"
"QPushButton:pressed {"
" border-image: url(:/qml/images/segment-selected.png) 0 12 0 2;"
"}"
).arg(useLeftPadding ? "18" : "4");
return sheet;
}
QString CrumblePathButton::lastSegmentSheet(bool useLeftPadding)
{
QString sheet = QString(
"QPushButton {"
"text-align: left;"
"color: #eeeeee;"
"border-image: url(:/qml/images/segment-end.png) 0 2 0 2;"
"border-width: 0 2px 0 2px;"
"padding-left:%1px;"
"}"
"QPushButton:hover {"
" border-image: url(:/qml/images/segment-hover-end.png) 0 2 0 2;"
"}"
"QPushButton:pressed {"
" border-image: url(:/qml/images/segment-selected-end.png) 0 2 0 2;"
"}"
).arg(useLeftPadding ? "18" : "4");
return sheet;
}
void CrumblePathButton::setSegmentType(int type)
{
bool useLeftPadding = !(type & FirstSegment);
if (type & LastSegment) {
setStyleSheet(lastSegmentSheet(useLeftPadding));
} else if (type & MiddleSegment) {
setStyleSheet(middleSegmentSheet(useLeftPadding));
}
}
//
// CrumblePath
//
CrumblePath::CrumblePath(QWidget *parent) :
QWidget(parent)
{
setMinimumHeight(24);
setMaximumHeight(24);
}
CrumblePath::~CrumblePath()
{
qDeleteAll(m_buttons);
m_buttons.clear();
}
void CrumblePath::pushElement(const QString &title)
{
CrumblePathButton *newButton = new CrumblePathButton(title, this);
newButton->hide();
connect(newButton, SIGNAL(clicked()), SLOT(mapClickToIndex()));
connect(newButton, SIGNAL(customContextMenuRequested(QPoint)), SLOT(mapContextMenuRequestToIndex()));
int segType = CrumblePathButton::MiddleSegment;
if (!m_buttons.isEmpty()) {
if (m_buttons.length() == 1)
segType = segType | CrumblePathButton::FirstSegment;
m_buttons.last()->setSegmentType(segType);
} else {
segType = CrumblePathButton::FirstSegment | CrumblePathButton::LastSegment;
newButton->setSegmentType(segType);
}
m_buttons.append(newButton);
resizeButtons();
}
void CrumblePath::popElement()
{
QWidget *last = m_buttons.last();
m_buttons.removeLast();
last->setParent(0);
last->deleteLater();
int segType = CrumblePathButton::MiddleSegment;
if (!m_buttons.isEmpty()) {
if (m_buttons.length() == 1)
segType = CrumblePathButton::FirstSegment | CrumblePathButton::LastSegment;
m_buttons.last()->setSegmentType(segType);
}
}
void CrumblePath::clear()
{
while (!m_buttons.isEmpty()) {
popElement();
}
}
void CrumblePath::resizeEvent(QResizeEvent *)
{
resizeButtons();
}
void CrumblePath::resizeButtons()
{
Q_ASSERT(!m_buttons.isEmpty());
int buttonWidth = 0;
if (m_buttons.length() > 1) {
QPoint nextElementPosition(0,0);
m_buttons[0]->raise();
// rearrange all items so that the first item is on top (added last).
for(int i = 0; i < m_buttons.length() ; ++i) {
QWidget *button = m_buttons[i];
buttonWidth = (width() + ArrowBorderSize * m_buttons.length()) / m_buttons.length();
button->setMaximumWidth(buttonWidth);
button->setGeometry(QRect(nextElementPosition, QSize(buttonWidth, button->height())));
nextElementPosition.rx() += button->width() - ArrowBorderSize;
button->show();
if (i > 0)
button->stackUnder(m_buttons[i - 1]);
}
} else {
QWidget *button = m_buttons[0];
int buttonWidth = 2 * width() / (3 * m_buttons.length());
button->setMaximumWidth(buttonWidth);
button->setGeometry(QRect(QPoint(0, 0), QSize(buttonWidth, button->height())));
button->show();
}
}
void CrumblePath::mapClickToIndex()
{
QObject *element = sender();
for (int i = 0; i < m_buttons.length(); ++i) {
if (m_buttons[i] == element) {
emit elementClicked(i);
return;
}
}
}
void CrumblePath::mapContextMenuRequestToIndex()
{
QObject *element = sender();
for (int i = 0; i < m_buttons.length(); ++i) {
if (m_buttons[i] == element) {
emit elementContextMenuRequested(i);
return;
}
}
}
} // namespace QmlViewer
#ifndef CRUMBLEPATH_H
#define CRUMBLEPATH_H
#include <QWidget>
#include <QList>
QT_FORWARD_DECLARE_CLASS(QResizeEvent);
namespace QmlViewer {
class CrumblePathButton;
class CrumblePath : public QWidget
{
Q_OBJECT
public:
explicit CrumblePath(QWidget *parent = 0);
~CrumblePath();
void pushElement(const QString &title);
void popElement();
void clear();
signals:
void elementClicked(int index);
void elementContextMenuRequested(int index);
protected:
void resizeEvent(QResizeEvent *);
private slots:
void mapClickToIndex();
void mapContextMenuRequestToIndex();
private:
void resizeButtons();
private:
QList<CrumblePathButton*> m_buttons;
};
} // namespace QmlViewer
#endif // CRUMBLEPATH_H
......@@ -15,7 +15,8 @@ HEADERS += \
$$PWD/zoomtool.h \
$$PWD/colorpickertool.h \
$$PWD/qmltoolbar.h \
$$PWD/toolbarcolorbox.h
$$PWD/toolbarcolorbox.h \
$$PWD/crumblepath.h
SOURCES += \
$$PWD/abstractformeditortool.cpp \
......@@ -31,7 +32,8 @@ SOURCES += \
$$PWD/zoomtool.cpp \
$$PWD/colorpickertool.cpp \
$$PWD/qmltoolbar.cpp \
$$PWD/toolbarcolorbox.cpp
$$PWD/toolbarcolorbox.cpp \
$$PWD/crumblepath.cpp
RESOURCES += $$PWD/editor.qrc
......
......@@ -10,5 +10,11 @@
<file>images/zoom.png</file>
<file>images/to-qml.png</file>
<file>images/designmode.png</file>
<file>images/segment-end.png</file>
<file>images/segment-selected.png</file>
<file>images/segment.png</file>
<file>images/segment-hover-end.png</file>
<file>images/segment-hover.png</file>
<file>images/segment-selected-end.png</file>
</qresource>
</RCC>
......@@ -195,9 +195,9 @@ void SelectionTool::createContextMenu(QList<QGraphicsItem*> itemList, QPoint glo
++i;
}
// add root item separately
QString itemTitle = QString(tr("%1 (root)")).arg(titleForItem(view()->currentRootItem()));
contextMenu.addAction(itemTitle, this, SLOT(contextMenuElementSelected()));
m_contextMenuItemList.append(view()->currentRootItem());
// 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();
......
......@@ -2,6 +2,7 @@
#include "qdeclarativedesignview.h"
#include "subcomponentmasklayeritem.h"
#include "layeritem.h"
#include "crumblepath.h"
#include <QGraphicsItem>
#include <QGraphicsObject>
......@@ -19,7 +20,8 @@ const qreal MaxOpacity = 0.5f;
SubcomponentEditorTool::SubcomponentEditorTool(QDeclarativeDesignView *view)
: AbstractFormEditorTool(view),
m_animIncrement(0.05f),
m_animTimer(new QTimer(this))
m_animTimer(new QTimer(this)),
m_crumblePathWidget(0)
{
m_mask = new SubcomponentMaskLayerItem(view, view->manipulatorLayer());
connect(m_animTimer, SIGNAL(timeout()), SLOT(animate()));
......@@ -122,6 +124,9 @@ void SubcomponentEditorTool::clear()
m_mask->setCurrentItem(0);
m_animTimer->stop();
m_mask->hide();
if (m_crumblePathWidget)
m_crumblePathWidget->clear();
}
void SubcomponentEditorTool::graphicsObjectsChanged(const QList<QGraphicsObject*> &/*itemList*/)
......@@ -225,6 +230,8 @@ void SubcomponentEditorTool::pushContext(QGraphicsObject *contextItem)
{
connect(contextItem, SIGNAL(destroyed(QObject*)), SLOT(contextDestroyed(QObject*)));
m_currentContext.push(contextItem);
if (m_crumblePathWidget)
m_crumblePathWidget->pushElement(titleForItem(contextItem));
}
void SubcomponentEditorTool::aboutToPopContext()
......@@ -241,6 +248,9 @@ QGraphicsObject *SubcomponentEditorTool::popContext()
{
QGraphicsObject *popped = m_currentContext.pop();
if (m_crumblePathWidget)
m_crumblePathWidget->popElement();
disconnect(popped, SIGNAL(xChanged()), this, SLOT(refresh()));
disconnect(popped, SIGNAL(yChanged()), this, SLOT(refresh()));
disconnect(popped, SIGNAL(scaleChanged()), this, SLOT(refresh()));
......@@ -251,6 +261,8 @@ QGraphicsObject *SubcomponentEditorTool::popContext()
m_mask->setCurrentItem(m_currentContext.top());
m_mask->setOpacity(MaxOpacity);
m_mask->setVisible(true);
} else {
m_mask->setVisible(false);
}
return popped;
......@@ -273,10 +285,42 @@ void SubcomponentEditorTool::contextDestroyed(QObject *contextToDestroy)
// pop out the whole context - it might not be safe anymore.
while (m_currentContext.size() > 1) {
m_currentContext.pop();
if (m_crumblePathWidget)
m_crumblePathWidget->popElement();
}
m_mask->setVisible(false);
}
void SubcomponentEditorTool::setCrumblePathWidget(CrumblePath *pathWidget)
{
m_crumblePathWidget = pathWidget;
if (m_crumblePathWidget) {
connect(m_crumblePathWidget, SIGNAL(elementClicked(int)), SLOT(setContext(int)));
connect(m_crumblePathWidget, SIGNAL(elementContextMenuRequested(int)), SLOT(openContextMenuForContext(int)));
}
}
void 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;
while (m_currentContext.size() - 1 > contextIndex) {
popContext();
}
}
void SubcomponentEditorTool::openContextMenuForContext(int /*contextIndex*/)
{
}
} // namespace QmlViewer
......@@ -10,6 +10,7 @@ QT_FORWARD_DECLARE_CLASS(QTimer)
namespace QmlViewer {
class CrumblePath;
class SubcomponentMaskLayerItem;
class SubcomponentEditorTool : public AbstractFormEditorTool
......@@ -48,6 +49,7 @@ public:
QGraphicsObject *popContext();
QGraphicsObject *currentRootItem() const;
void setCrumblePathWidget(CrumblePath *pathWidget);
signals:
void exitContextRequested();
......@@ -59,6 +61,8 @@ private slots:
void animate();
void contextDestroyed(QObject *context);
void refresh();
void setContext(int contextIndex);
void openContextMenuForContext(int contextIndex);
private:
void aboutToPopContext();
......@@ -70,6 +74,8 @@ private:
SubcomponentMaskLayerItem *m_mask;
QTimer *m_animTimer;
CrumblePath *m_crumblePathWidget;
};
} // namespace QmlViewer
......
......@@ -7,6 +7,7 @@
#include "boundingrecthighlighter.h"
#include "subcomponenteditortool.h"
#include "qmltoolbar.h"
#include "crumblepath.h"
#include <QDeclarativeItem>
#include <QDeclarativeEngine>
......@@ -31,12 +32,15 @@ QDeclarativeDesignView::QDeclarativeDesignView(QWidget *parent) :
m_slowdownFactor(1.0f),
m_toolbar(0)
{
m_crumblePath = new CrumblePath(0);
m_manipulatorLayer = new LayerItem(scene());
m_selectionTool = new SelectionTool(this);
m_zoomTool = new ZoomTool(this);
m_colorPickerTool = new ColorPickerTool(this);
m_boundingRectHighlighter = new BoundingRectHighlighter(this);
m_subcomponentEditorTool = new SubcomponentEditorTool(this);
m_subcomponentEditorTool->setCrumblePathWidget(m_crumblePath);
m_currentTool = m_selectionTool;
setMouseTracking(true);
......@@ -582,6 +586,11 @@ QRectF QDeclarativeDesignView::adjustToScreenBoundaries(const QRectF &boundingRe
return boundingRect;
}
CrumblePath *QDeclarativeDesignView::crumblePathWidget() const
{
return m_crumblePath;
}
QToolBar *QDeclarativeDesignView::toolbar() const
{
return m_toolbar;
......
......@@ -19,6 +19,7 @@ class LayerItem;
class BoundingRectHighlighter;
class SubcomponentEditorTool;
class QmlToolbar;
class CrumblePath;
class QDeclarativeDesignView : public QDeclarativeView
{
......@@ -52,6 +53,7 @@ public:
QList<QGraphicsItem*> selectableItems(const QRectF &sceneRect, Qt::ItemSelectionMode selectionMode) const;
QGraphicsItem *currentRootItem() const;
CrumblePath *crumblePathWidget() const;
QToolBar *toolbar() const;
static QString idStringForObject(QObject *obj);
QRectF adjustToScreenBoundaries(const QRectF &boundingRectInSceneSpace);
......@@ -127,6 +129,7 @@ private:
qreal m_slowdownFactor;
QmlToolbar *m_toolbar;
CrumblePath *m_crumblePath;
};
} //namespace QmlViewer
......
......@@ -55,6 +55,7 @@
#endif
#include "qdeclarativedesignview.h"
#include "crumblepath.h"
#include "qmlruntime.h"
#include <qdeclarativecontext.h>
#include <qdeclarativeengine.h>
......@@ -64,6 +65,7 @@
#include <private/qabstractanimation_p.h>
#include <private/qdeclarativeengine_p.h>
#include <QSplitter>
#include <QSettings>
#include <QXmlStreamReader>
#include <QBuffer>
......@@ -92,6 +94,7 @@
#include <QNetworkProxyFactory>
#include <QKeyEvent>
#include <QToolBar>
#include <QDockWidget>
#include <QMutex>
#include <QMutexLocker>
#include "proxysettings.h"
......@@ -585,6 +588,26 @@ QDeclarativeViewer::QDeclarativeViewer(QWidget *parent, Qt::WindowFlags flags)
canvas = new QmlViewer::QDeclarativeDesignView(this);
addToolBar(Qt::TopToolBarArea, canvas->toolbar());
QSplitter *crumblePathSplitter = new QSplitter(this);
crumblePathSplitter->setOrientation(Qt::Vertical);
crumblePathSplitter->addWidget(canvas->crumblePathWidget());
crumblePathSplitter->addWidget(canvas);
crumblePathSplitter->setHandleWidth(1);
crumblePathSplitter->setCollapsible(0, false);
crumblePathSplitter->setCollapsible(1, false);
// QDockWidget *crumblePathWidget = new QDockWidget("Context path", this);
// crumblePathWidget->setWidget();
// crumblePathWidget->setAllowedAreas(Qt::TopDockWidgetArea);
// crumblePathWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
// crumblePathWidget->setTitleBarWidget(new QWidget(this));
// crumblePathWidget->setMinimumHeight(24);
// crumblePathWidget->setMaximumHeight(24);
setDocumentMode(true);
setDockNestingEnabled(true);
//addDockWidget(Qt::TopDockWidgetArea, crumblePathWidget);
canvas->setAttribute(Qt::WA_OpaquePaintEvent);
canvas->setAttribute(Qt::WA_NoSystemBackground);
......@@ -605,7 +628,7 @@ QDeclarativeViewer::QDeclarativeViewer(QWidget *parent, Qt::WindowFlags flags)
setMenuBar(0);
}
setCentralWidget(canvas);