diff options
Diffstat (limited to 'src/plugins/qmljstools')
36 files changed, 2920 insertions, 135 deletions
diff --git a/src/plugins/qmljstools/images/collapse.png b/src/plugins/qmljstools/images/collapse.png Binary files differnew file mode 100644 index 0000000000..64ae3720c1 --- /dev/null +++ b/src/plugins/qmljstools/images/collapse.png diff --git a/src/plugins/qmljstools/images/error.png b/src/plugins/qmljstools/images/error.png Binary files differnew file mode 100644 index 0000000000..39768b9f39 --- /dev/null +++ b/src/plugins/qmljstools/images/error.png diff --git a/src/plugins/qmljstools/images/expand.png b/src/plugins/qmljstools/images/expand.png Binary files differnew file mode 100644 index 0000000000..7959bfc97e --- /dev/null +++ b/src/plugins/qmljstools/images/expand.png diff --git a/src/plugins/qmljstools/images/log.png b/src/plugins/qmljstools/images/log.png Binary files differnew file mode 100644 index 0000000000..e4766f228b --- /dev/null +++ b/src/plugins/qmljstools/images/log.png diff --git a/src/plugins/qmljstools/images/prompt.png b/src/plugins/qmljstools/images/prompt.png Binary files differnew file mode 100644 index 0000000000..a333a87198 --- /dev/null +++ b/src/plugins/qmljstools/images/prompt.png diff --git a/src/plugins/qmljstools/images/warning.png b/src/plugins/qmljstools/images/warning.png Binary files differnew file mode 100644 index 0000000000..3200efc4fd --- /dev/null +++ b/src/plugins/qmljstools/images/warning.png diff --git a/src/plugins/qmljstools/qmlconsoleedit.cpp b/src/plugins/qmljstools/qmlconsoleedit.cpp new file mode 100644 index 0000000000..be4d99c82b --- /dev/null +++ b/src/plugins/qmljstools/qmlconsoleedit.cpp @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "qmlconsoleedit.h" +#include "qmlconsoleitemmodel.h" +#include "qmlconsolemanager.h" + +#include <utils/qtcassert.h> + +#include <QUrl> +#include <QMenu> +#include <QKeyEvent> + +namespace QmlJSTools { +namespace Internal { + +/////////////////////////////////////////////////////////////////////// +// +// QmlConsoleEdit +// +/////////////////////////////////////////////////////////////////////// + +QmlConsoleEdit::QmlConsoleEdit(const QModelIndex &index, QWidget *parent) : + QTextEdit(parent), + m_historyIndex(index), + m_prompt(QLatin1String(":/qmljstools/images/prompt.png")), + m_startOfEditableArea(0) +{ + setFrameStyle(QFrame::NoFrame); + setUndoRedoEnabled(false); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("prompt")), m_prompt); + QTextImageFormat format; + format.setName(QLatin1String("prompt")); + format.setHeight(9); + format.setWidth(9); + textCursor().insertText(QLatin1String(" ")); + textCursor().insertImage(format); + textCursor().insertText(QLatin1String(" ")); + m_startOfEditableArea = textCursor().position(); + + ensureCursorVisible(); + setTextInteractionFlags(Qt::TextEditorInteraction); +} + +void QmlConsoleEdit::keyPressEvent(QKeyEvent *e) +{ + bool keyConsumed = false; + + switch (e->key()) { + case Qt::Key_Return: + case Qt::Key_Enter: { + m_interpreter.clearText(); + QString currentScript = getCurrentScript(); + m_interpreter.appendText(currentScript); + if (currentScript.isEmpty()) { + emit editingFinished(); + } else if (m_interpreter.canEvaluate()) { + QmlConsoleModel::evaluate(currentScript); + emit editingFinished(); + } + break; + } + + case Qt::Key_Backspace: + if (textCursor().selectionStart() <= m_startOfEditableArea) + keyConsumed = true; + break; + + case Qt::Key_Delete: + if (textCursor().selectionStart() < m_startOfEditableArea) + keyConsumed = true; + break; + + case Qt::Key_Home: { + QTextCursor c(textCursor()); + c.setPosition(m_startOfEditableArea); + setTextCursor(c); + keyConsumed = true; + break; + } + + case Qt::Key_Up: + handleUpKey(); + keyConsumed = true; + break; + + case Qt::Key_Down: + handleDownKey(); + keyConsumed = true; + break; + + // Ctrl+Left: Moves the cursor one word to the left. + // Left: Moves the cursor one character to the left. + case Qt::Key_Left: + if (textCursor().position() <= m_startOfEditableArea + || e->modifiers() & Qt::ControlModifier) { + QTextCursor c(textCursor()); + c.setPosition(m_startOfEditableArea); + setTextCursor(c); + keyConsumed = true; + } + break; + + // Ctrl+Right: Moves the cursor one word to the right. + // Right: Moves the cursor one character to the right. + case Qt::Key_Right: + if ( !(e->modifiers() & Qt::ControlModifier) + && textCursor().position() <= m_startOfEditableArea) { + QTextCursor c(textCursor()); + c.setPosition(m_startOfEditableArea); + setTextCursor(c); + keyConsumed = true; + } + break; + + // Ctrl+C, Ctrl+Insert: Allow to Copy the selected text to the clipboard. + case Qt::Key_C: + case Qt::Key_Insert: + if (textCursor().selectionStart() < m_startOfEditableArea && + !(e->modifiers() & Qt::ControlModifier)) + keyConsumed = true; + break; + + default: + // Disallow any other keys in the prompt area + if (textCursor().selectionStart() < m_startOfEditableArea) + keyConsumed = true; + break; + } + + if (!keyConsumed) + QTextEdit::keyPressEvent(e); +} + +void QmlConsoleEdit::contextMenuEvent(QContextMenuEvent *event) +{ + // TODO:: on right click the editor closes + return QTextEdit::contextMenuEvent(event); + + QTextCursor cursor = textCursor(); + bool editable = cursor.position() > m_startOfEditableArea; + QMenu *menu = new QMenu(); + QAction *a; + + a = menu->addAction(tr("Cu&t"), this, SLOT(cut())); + a->setEnabled(cursor.hasSelection() && editable); + + a = menu->addAction(tr("&Copy"), this, SLOT(copy())); + a->setEnabled(cursor.hasSelection()); + + a = menu->addAction(tr("&Paste"), this, SLOT(paste())); + a->setEnabled(canPaste() && editable); + + menu->addSeparator(); + a = menu->addAction(tr("Select &All"), this, SLOT(selectAll())); + a->setEnabled(!document()->isEmpty()); + + menu->addSeparator(); + menu->addAction(tr("C&lear"), this, SLOT(clear())); + + menu->exec(event->globalPos()); + + delete menu; +} + +void QmlConsoleEdit::focusOutEvent(QFocusEvent * /*e*/) +{ + emit editingFinished(); +} + +void QmlConsoleEdit::handleUpKey() +{ + QTC_ASSERT(m_historyIndex.isValid(), return); + int currentRow = m_historyIndex.row(); + const QAbstractItemModel *model = m_historyIndex.model(); + if (currentRow == model->rowCount() - 1) + m_cachedScript = getCurrentScript(); + + while (currentRow) { + currentRow--; + if (model->hasIndex(currentRow, 0)) { + QModelIndex index = model->index(currentRow, 0); + if (QmlConsoleItem::InputType == (QmlConsoleItem::ItemType)model->data( + index, QmlConsoleItemModel::TypeRole).toInt()) { + m_historyIndex = index; + replaceCurrentScript(model->data(index, Qt::DisplayRole).toString()); + break; + } + } + } +} + +void QmlConsoleEdit::handleDownKey() +{ + QTC_ASSERT(m_historyIndex.isValid(), return); + int currentRow = m_historyIndex.row(); + const QAbstractItemModel *model = m_historyIndex.model(); + while (currentRow < model->rowCount() - 1) { + currentRow++; + if (model->hasIndex(currentRow, 0)) { + QModelIndex index = model->index(currentRow, 0); + if (QmlConsoleItem::InputType == (QmlConsoleItem::ItemType)model->data( + index, QmlConsoleItemModel::TypeRole).toInt()) { + m_historyIndex = index; + if (currentRow == model->rowCount() - 1) + replaceCurrentScript(m_cachedScript); + else + replaceCurrentScript(model->data(index, Qt::DisplayRole).toString()); + break; + } + } + } +} + +QString QmlConsoleEdit::getCurrentScript() const +{ + QTextCursor cursor = textCursor(); + cursor.setPosition(m_startOfEditableArea); + cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + QString script = cursor.selectedText(); + return script.trimmed(); +} + +void QmlConsoleEdit::replaceCurrentScript(const QString &script) +{ + QTextCursor cursor = textCursor(); + cursor.setPosition(m_startOfEditableArea); + cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + cursor.removeSelectedText(); + cursor.insertText(script); + setTextCursor(cursor); +} + +} // Internal +} // QmlJSTools diff --git a/src/plugins/qmljstools/qmlconsoleedit.h b/src/plugins/qmljstools/qmlconsoleedit.h new file mode 100644 index 0000000000..00c7259080 --- /dev/null +++ b/src/plugins/qmljstools/qmlconsoleedit.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef QMLCONSOLEEDIT_H +#define QMLCONSOLEEDIT_H + +#include "qmljsinterpreter.h" + +#include <QTextEdit> +#include <QModelIndex> + +namespace QmlJSTools { +namespace Internal { + +class QmlConsoleEdit : public QTextEdit +{ + Q_OBJECT +public: + QmlConsoleEdit(const QModelIndex &index, QWidget *parent); + + QString getCurrentScript() const; + +protected: + void keyPressEvent(QKeyEvent *e); + void contextMenuEvent(QContextMenuEvent *event); + void focusOutEvent(QFocusEvent *e); + +signals: + void editingFinished(); + +protected: + void handleUpKey(); + void handleDownKey(); + + void replaceCurrentScript(const QString &script); + +private: + QModelIndex m_historyIndex; + QString m_cachedScript; + QImage m_prompt; + int m_startOfEditableArea; + QmlJSInterpreter m_interpreter; +}; + +} // QmlJSTools +} // Internal + +#endif // QMLCONSOLEEDIT_H diff --git a/src/plugins/qmljstools/qmlconsoleitem.cpp b/src/plugins/qmljstools/qmlconsoleitem.cpp new file mode 100644 index 0000000000..6de05bbf8c --- /dev/null +++ b/src/plugins/qmljstools/qmlconsoleitem.cpp @@ -0,0 +1,153 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ + +#include "qmlconsoleitem.h" + +namespace QmlJSTools { + +/////////////////////////////////////////////////////////////////////// +// +// QmlConsoleItem +// +/////////////////////////////////////////////////////////////////////// + +QmlConsoleItem::QmlConsoleItem(QmlConsoleItem *parent, QmlConsoleItem::ItemType itemType, + const QString &text) + : m_parentItem(parent), + itemType(itemType), + line(-1) + +{ + setText(text); +} + +QmlConsoleItem::~QmlConsoleItem() +{ + qDeleteAll(m_childItems); +} + +QmlConsoleItem *QmlConsoleItem::child(int number) +{ + return m_childItems.value(number); +} + +int QmlConsoleItem::childCount() const +{ + return m_childItems.size(); +} + +int QmlConsoleItem::childNumber() const +{ + if (m_parentItem) + return m_parentItem->m_childItems.indexOf(const_cast<QmlConsoleItem *>(this)); + + return 0; +} + +bool QmlConsoleItem::insertChildren(int position, int count) +{ + if (position < 0 || position > m_childItems.size()) + return false; + + for (int row = 0; row < count; ++row) { + QmlConsoleItem *item = new QmlConsoleItem(this, QmlConsoleItem::UndefinedType, + QString()); + m_childItems.insert(position, item); + } + + return true; +} + +void QmlConsoleItem::insertChild(QmlConsoleItem *item, bool sorted) +{ + if (!sorted) { + m_childItems.insert(m_childItems.count(), item); + return; + } + + int i = 0; + for (; i < m_childItems.count(); i++) { + if (item->m_text < m_childItems[i]->m_text) + break; + } + m_childItems.insert(i, item); +} + +bool QmlConsoleItem::insertChild(int position, QmlConsoleItem *item) +{ + if (position < 0 || position > m_childItems.size()) + return false; + + m_childItems.insert(position, item); + + return true; +} + +QmlConsoleItem *QmlConsoleItem::parent() +{ + return m_parentItem; +} + +bool QmlConsoleItem::removeChildren(int position, int count) +{ + if (position < 0 || position + count > m_childItems.size()) + return false; + + for (int row = 0; row < count; ++row) + delete m_childItems.takeAt(position); + + return true; +} + +bool QmlConsoleItem::detachChild(int position) +{ + if (position < 0 || position > m_childItems.size()) + return false; + + m_childItems.removeAt(position); + + return true; +} + +void QmlConsoleItem::setText(const QString &text) +{ + m_text = text; + for (int i = 0; i < m_text.length(); ++i) { + if (m_text.at(i).isPunct()) + m_text.insert(++i, QChar(0x200b)); // ZERO WIDTH SPACE + } +} + +const QString &QmlConsoleItem::text() const +{ + return m_text; +} + +} // QmlJSTools diff --git a/src/plugins/qmljstools/qmlconsoleitem.h b/src/plugins/qmljstools/qmlconsoleitem.h new file mode 100644 index 0000000000..dc4445e696 --- /dev/null +++ b/src/plugins/qmljstools/qmlconsoleitem.h @@ -0,0 +1,85 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ + +#ifndef QMLCONSOLEITEM_H +#define QMLCONSOLEITEM_H + +#include "qmljstools_global.h" + +#include <QList> +#include <QString> + +namespace QmlJSTools { + +class QMLJSTOOLS_EXPORT QmlConsoleItem +{ +public: + enum ItemType + { + UndefinedType = 0x01, // Can be used for unknown and for Return values + DebugType = 0x02, + WarningType = 0x04, + ErrorType = 0x08, + InputType = 0x10, + DefaultTypes = InputType | UndefinedType + }; + Q_DECLARE_FLAGS(ItemTypes, ItemType) + + QmlConsoleItem(QmlConsoleItem *parent, + QmlConsoleItem::ItemType type = QmlConsoleItem::UndefinedType, + const QString &data = QString()); + ~QmlConsoleItem(); + + QmlConsoleItem *child(int number); + int childCount() const; + bool insertChildren(int position, int count); + void insertChild(QmlConsoleItem *item, bool sorted); + bool insertChild(int position, QmlConsoleItem *item); + QmlConsoleItem *parent(); + bool removeChildren(int position, int count); + bool detachChild(int position); + int childNumber() const; + void setText(const QString &text); + const QString &text() const; + +private: + QmlConsoleItem *m_parentItem; + QList<QmlConsoleItem *> m_childItems; + QString m_text; + +public: + QmlConsoleItem::ItemType itemType; + QString file; + int line; +}; + +} // QmlJSTools + +#endif // QMLCONSOLEITEM_H diff --git a/src/plugins/qmljstools/qmlconsoleitemdelegate.cpp b/src/plugins/qmljstools/qmlconsoleitemdelegate.cpp new file mode 100644 index 0000000000..f1e6ba825d --- /dev/null +++ b/src/plugins/qmljstools/qmlconsoleitemdelegate.cpp @@ -0,0 +1,370 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "qmlconsoleitemdelegate.h" +#include "qmlconsoleedit.h" + +#include <QPainter> +#include <QTreeView> +#include <QScrollBar> + +const char CONSOLE_LOG_BACKGROUND_COLOR[] = "#E8EEF2"; +const char CONSOLE_WARNING_BACKGROUND_COLOR[] = "#F6F4EB"; +const char CONSOLE_ERROR_BACKGROUND_COLOR[] = "#F6EBE7"; +const char CONSOLE_EDITOR_BACKGROUND_COLOR[] = "#F7F7F7"; + +const char CONSOLE_LOG_BACKGROUND_SELECTED_COLOR[] = "#CDDEEA"; +const char CONSOLE_WARNING_BACKGROUND_SELECTED_COLOR[] = "#F3EED1"; +const char CONSOLE_ERROR_BACKGROUND_SELECTED_COLOR[] = "#F5D4CB"; +const char CONSOLE_EDITOR_BACKGROUND_SELECTED_COLOR[] = "#DEDEDE"; + +const char CONSOLE_LOG_TEXT_COLOR[] = "#333333"; +const char CONSOLE_WARNING_TEXT_COLOR[] = "#666666"; +const char CONSOLE_ERROR_TEXT_COLOR[] = "#1D5B93"; +const char CONSOLE_EDITOR_TEXT_COLOR[] = "#000000"; + +const char CONSOLE_BORDER_COLOR[] = "#C9C9C9"; + +const int ELLIPSIS_GRADIENT_WIDTH = 16; + +namespace QmlJSTools { +namespace Internal { + +/////////////////////////////////////////////////////////////////////// +// +// QmlConsoleItemDelegate +// +/////////////////////////////////////////////////////////////////////// + +QmlConsoleItemDelegate::QmlConsoleItemDelegate(QObject *parent) : + QStyledItemDelegate(parent), + m_logIcon(QLatin1String(":/qmljstools/images/log.png")), + m_warningIcon(QLatin1String(":/qmljstools/images/warning.png")), + m_errorIcon(QLatin1String(":/qmljstools/images/error.png")), + m_expandIcon(QLatin1String(":/qmljstools/images/expand.png")), + m_collapseIcon(QLatin1String(":/qmljstools/images/collapse.png")), + m_prompt(QLatin1String(":/qmljstools/images/prompt.png")), + m_cachedHeight(0) +{ +} + +void QmlConsoleItemDelegate::emitSizeHintChanged(const QModelIndex &index) +{ + emit sizeHintChanged(index); +} + +QColor QmlConsoleItemDelegate::drawBackground(QPainter *painter, const QRect &rect, + const QModelIndex &index, + bool selected) const +{ + painter->save(); + QmlConsoleItem::ItemType itemType = (QmlConsoleItem::ItemType)index.data( + QmlConsoleItemModel::TypeRole).toInt(); + QColor backgroundColor; + switch (itemType) { + case QmlConsoleItem::DebugType: + backgroundColor = selected ? QColor(CONSOLE_LOG_BACKGROUND_SELECTED_COLOR) : + QColor(CONSOLE_LOG_BACKGROUND_COLOR); + break; + case QmlConsoleItem::WarningType: + backgroundColor = selected ? QColor(CONSOLE_WARNING_BACKGROUND_SELECTED_COLOR) : + QColor(CONSOLE_WARNING_BACKGROUND_COLOR); + break; + case QmlConsoleItem::ErrorType: + backgroundColor = selected ? QColor(CONSOLE_ERROR_BACKGROUND_SELECTED_COLOR) : + QColor(CONSOLE_ERROR_BACKGROUND_COLOR); + break; + case QmlConsoleItem::InputType: + default: + backgroundColor = selected ? QColor(CONSOLE_EDITOR_BACKGROUND_SELECTED_COLOR) : + QColor(CONSOLE_EDITOR_BACKGROUND_COLOR); + break; + } + if (!(index.flags() & Qt::ItemIsEditable)) + painter->setBrush(backgroundColor); + painter->setPen(Qt::NoPen); + painter->drawRect(rect); + + // Separator lines + painter->setPen(QColor(CONSOLE_BORDER_COLOR)); + if (!(index.flags() & Qt::ItemIsEditable)) + painter->drawLine(0, rect.bottom(), rect.right(), + rect.bottom()); + painter->restore(); + return backgroundColor; +} + +void QmlConsoleItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + painter->save(); + + // Set Colors + QColor textColor; + QIcon taskIcon; + QmlConsoleItem::ItemType type = (QmlConsoleItem::ItemType)index.data( + QmlConsoleItemModel::TypeRole).toInt(); + switch (type) { + case QmlConsoleItem::DebugType: + textColor = QColor(CONSOLE_LOG_TEXT_COLOR); + taskIcon = m_logIcon; + break; + case QmlConsoleItem::WarningType: + textColor = QColor(CONSOLE_WARNING_TEXT_COLOR); + taskIcon = m_warningIcon; + break; + case QmlConsoleItem::ErrorType: + textColor = QColor(CONSOLE_ERROR_TEXT_COLOR); + taskIcon = m_errorIcon; + break; + case QmlConsoleItem::InputType: + textColor = QColor(CONSOLE_EDITOR_TEXT_COLOR); + taskIcon = m_prompt; + break; + default: + textColor = QColor(CONSOLE_EDITOR_TEXT_COLOR); + break; + } + + // Paint background + QColor backgroundColor = drawBackground(painter, opt.rect, index, + bool(opt.state & QStyle::State_Selected)); + + // Calculate positions + const QTreeView *view = qobject_cast<const QTreeView *>(opt.widget); + int level = 0; + QModelIndex idx(index); + while (idx.parent() != QModelIndex()) { + idx = idx.parent(); + level++; + } + int width = view->width() - level * view->indentation() - view->verticalScrollBar()->width(); + bool showTypeIcon = index.parent() == QModelIndex(); + bool showExpandableIcon = type == QmlConsoleItem::UndefinedType; + + QRect rect(opt.rect.x(), opt.rect.top(), width, opt.rect.height()); + ConsoleItemPositions positions(rect, opt.font, showTypeIcon, showExpandableIcon); + + // Paint TaskIconArea: + if (showTypeIcon) + painter->drawPixmap(positions.adjustedLeft(), positions.adjustedTop(), + taskIcon.pixmap(positions.typeIconWidth(), + positions.typeIconHeight())); + + // Set Text Color + painter->setPen(textColor); + // Paint TextArea: + // Layout the description + QString str = index.data(Qt::DisplayRole).toString(); + bool showFileLineInfo = true; + // show complete text if selected + if (view->selectionModel()->currentIndex() == index) { + QTextLayout tl(str, opt.font); + layoutText(tl, positions.textAreaWidth(), &showFileLineInfo); + tl.draw(painter, QPoint(positions.textAreaLeft(), positions.adjustedTop())); + } else { + QFontMetrics fm(opt.font); + painter->drawText(positions.textArea(), fm.elidedText(str, Qt::ElideRight, + positions.textAreaWidth())); + } + // skip if area is editable + if (showExpandableIcon) { + // Paint ExpandableIconArea: + QIcon expandCollapseIcon; + if (index.model()->rowCount(index)) { + if (view->isExpanded(index)) + expandCollapseIcon = m_collapseIcon; + else + expandCollapseIcon = m_expandIcon; + } + painter->drawPixmap(positions.expandCollapseIconLeft(), positions.adjustedTop(), + expandCollapseIcon.pixmap(positions.expandCollapseIconWidth(), + positions.expandCollapseIconHeight())); + } + + if (showFileLineInfo) { + // Check for file info + QString file = index.data(QmlConsoleItemModel::FileRole).toString(); + if (!file.isEmpty()) { + QFontMetrics fm(option.font); + // Paint FileArea + const int pos = file.lastIndexOf(QLatin1Char('/')); + if (pos != -1) + file = file.mid(pos +1); + const int realFileWidth = fm.width(file); + painter->setClipRect(positions.fileArea()); + painter->drawText(positions.fileAreaLeft(), positions.adjustedTop() + fm.ascent(), + file); + if (realFileWidth > positions.fileAreaWidth()) { + // draw a gradient to mask the text + int gradientStart = positions.fileAreaLeft() - 1; + QLinearGradient lg(gradientStart + ELLIPSIS_GRADIENT_WIDTH, 0, gradientStart, 0); + lg.setColorAt(0, Qt::transparent); + lg.setColorAt(1, backgroundColor); + painter->fillRect(gradientStart, positions.adjustedTop(), + ELLIPSIS_GRADIENT_WIDTH, positions.lineHeight(), lg); + } + + // Paint LineArea + QString lineText = index.data(QmlConsoleItemModel::LineRole).toString(); + painter->setClipRect(positions.lineArea()); + const int realLineWidth = fm.width(lineText); + painter->drawText(positions.lineAreaRight() - realLineWidth, + positions.adjustedTop() + fm.ascent(), lineText); + } + } + painter->setClipRect(opt.rect); + painter->restore(); +} + +QSize QmlConsoleItemDelegate::sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + + const QTreeView *view = qobject_cast<const QTreeView *>(opt.widget); + int level = 0; + QModelIndex idx(index); + while (idx.parent() != QModelIndex()) { + idx = idx.parent(); + level++; + } + int width = view->width() - level * view->indentation() - view->verticalScrollBar()->width(); + if (index.flags() & Qt::ItemIsEditable) + return QSize(width, view->height() * 1/2); + + const bool selected = (view->selectionModel()->currentIndex() == index); + if (!selected && option.font == m_cachedFont && m_cachedHeight > 0) + return QSize(width, m_cachedHeight); + + QmlConsoleItem::ItemType type = (QmlConsoleItem::ItemType)index.data( + QmlConsoleItemModel::TypeRole).toInt(); + bool showTypeIcon = index.parent() == QModelIndex(); + bool showExpandableIcon = type == QmlConsoleItem::UndefinedType; + + QRect rect(level * view->indentation(), 0, width, 0); + ConsoleItemPositions positions(rect, opt.font, showTypeIcon, showExpandableIcon); + + QFontMetrics fm(option.font); + qreal height = fm.height(); + + if (selected) { + QString str = index.data(Qt::DisplayRole).toString(); + + QTextLayout tl(str, option.font); + height = layoutText(tl, positions.textAreaWidth()); + } + + height += 2 * ConsoleItemPositions::ITEM_PADDING; + + if (height < positions.minimumHeight()) + height = positions.minimumHeight(); + + if (!selected) { + m_cachedHeight = height; + m_cachedFont = option.font; + } + + return QSize(width, height); +} + +QWidget *QmlConsoleItemDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &/*option*/, + const QModelIndex &index) const + +{ + QmlConsoleEdit *editor = new QmlConsoleEdit(index, parent); + connect(editor, SIGNAL(editingFinished()), this, SLOT(commitAndCloseEditor())); + return editor; +} + +void QmlConsoleItemDelegate::setEditorData(QWidget *editor, + const QModelIndex &index) const +{ + QmlConsoleEdit *edtr = qobject_cast<QmlConsoleEdit *>(editor); + edtr->insertPlainText(index.data(Qt::DisplayRole).toString()); +} + +void QmlConsoleItemDelegate::setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const +{ + QmlConsoleEdit *edtr = qobject_cast<QmlConsoleEdit *>(editor); + model->setData(index, edtr->getCurrentScript(), Qt::DisplayRole); + model->setData(index, QmlConsoleItem::InputType, QmlConsoleItemModel::TypeRole); +} + +void QmlConsoleItemDelegate::updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, + const QModelIndex &/*index*/) const +{ + QStyleOptionViewItemV4 opt = option; + editor->setGeometry(QRect(opt.rect.x(), opt.rect.top(), opt.rect.width(), opt.rect.bottom())); +} + +void QmlConsoleItemDelegate::currentChanged(const QModelIndex ¤t, + const QModelIndex &previous) +{ + emit sizeHintChanged(current); + emit sizeHintChanged(previous); +} + +void QmlConsoleItemDelegate::commitAndCloseEditor() +{ + QmlConsoleEdit *editor = qobject_cast<QmlConsoleEdit *>(sender()); + emit commitData(editor); + emit closeEditor(editor); +} + +qreal QmlConsoleItemDelegate::layoutText(QTextLayout &tl, int width, + bool *showFileLineInfo) const +{ + qreal height = 0; + tl.beginLayout(); + while (true) { + QTextLine line = tl.createLine(); + + if (!line.isValid()) + break; + line.setLeadingIncluded(true); + line.setLineWidth(width); + if (width < line.naturalTextWidth() && showFileLineInfo) + *showFileLineInfo = false; + line.setPosition(QPoint(0, height)); + height += line.height(); + } + tl.endLayout(); + return height; +} + +} // Internal +} // QmlJSTools diff --git a/src/plugins/qmljstools/qmlconsoleitemdelegate.h b/src/plugins/qmljstools/qmlconsoleitemdelegate.h new file mode 100644 index 0000000000..477618b474 --- /dev/null +++ b/src/plugins/qmljstools/qmlconsoleitemdelegate.h @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef QMLCONSOLEITEMDELEGATE_H +#define QMLCONSOLEITEMDELEGATE_H + +#include "qmlconsoleitemmodel.h" +#include "qmlconsolemanager.h" + +#include <QStyledItemDelegate> +#include <QTextLayout> + +namespace QmlJSTools { +namespace Internal { + +class QmlConsoleItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + QmlConsoleItemDelegate(QObject *parent); + + void emitSizeHintChanged(const QModelIndex &index); + QColor drawBackground(QPainter *painter, const QRect &rect, const QModelIndex &index, + bool selected) const; + +public slots: + void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); + +protected: + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + QSize sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const; + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + void setEditorData(QWidget *editor, const QModelIndex &index) const; + void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; + + void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + +private slots: + void commitAndCloseEditor(); + +private: + qreal layoutText(QTextLayout &tl, int width, bool *success = 0) const; + +private: + const QIcon m_logIcon; + const QIcon m_warningIcon; + const QIcon m_errorIcon; + const QIcon m_expandIcon; + const QIcon m_collapseIcon; + const QIcon m_prompt; + mutable int m_cachedHeight; + mutable QFont m_cachedFont; +}; + +/* + +----------------------------------------------------------------------------+ + | TYPEICONAREA EXPANDABLEICONAREA TEXTAREA FILEAREA LINEAREA | + +----------------------------------------------------------------------------+ + + */ +/* + +----------------------------------------------------------------------------+ + | PROMPTAREA EDITABLEAREA | + +----------------------------------------------------------------------------+ + + */ +class ConsoleItemPositions +{ +public: + ConsoleItemPositions(const QRect &rect, const QFont &font, bool showTaskIconArea, + bool showExpandableIconArea) + : m_x(rect.x()), + m_width(rect.width()), + m_top(rect.top()), + m_bottom(rect.bottom()), + m_maxFileLength(0), + m_maxLineLength(0), + m_showTaskIconArea(showTaskIconArea), + m_showExpandableIconArea(showExpandableIconArea) + { + m_fontHeight = QFontMetrics(font).height(); + QmlConsoleItemModel *model = QmlConsoleModel::qmlConsoleItemModel(); + m_maxFileLength = model->sizeOfFile(font); + m_maxLineLength = model->sizeOfLineNumber(font); + } + + int adjustedTop() const { return m_top + ITEM_PADDING; } + int adjustedLeft() const { return m_x + ITEM_PADDING; } + int adjustedRight() const { return m_width - ITEM_PADDING; } + int adjustedBottom() const { return m_bottom; } + int lineHeight() const { return m_fontHeight + 1; } + int minimumHeight() const { return typeIconHeight() + 2 * ITEM_PADDING; } + + // PROMPTAREA is same as TYPEICONAREA + int typeIconLeft() const { return adjustedLeft(); } + int typeIconWidth() const { return TASK_ICON_SIZE; } + int typeIconHeight() const { return TASK_ICON_SIZE; } + int typeIconRight() const { return m_showTaskIconArea ? typeIconLeft() + typeIconWidth() + : adjustedLeft(); } + QRect typeIcon() const { return QRect(typeIconLeft(), adjustedTop(), typeIconWidth(), + typeIconHeight()); } + + int expandCollapseIconLeft() const { return typeIconRight() + ITEM_SPACING; } + int expandCollapseIconWidth() const { return TASK_ICON_SIZE; } + int expandCollapseIconHeight() const { return TASK_ICON_SIZE; } + int expandCollapseIconRight() const { return m_showExpandableIconArea ? + expandCollapseIconLeft() + expandCollapseIconWidth() : typeIconRight(); } + QRect expandCollapseIcon() const { return QRect(expandCollapseIconLeft(), adjustedTop(), + expandCollapseIconWidth(), + expandCollapseIconHeight()); } + + int textAreaLeft() const { return expandCollapseIconRight() + ITEM_SPACING; } + int textAreaWidth() const { return textAreaRight() - textAreaLeft(); } + int textAreaRight() const { return fileAreaLeft() - ITEM_SPACING; } + QRect textArea() const { return QRect(textAreaLeft(), adjustedTop(), textAreaWidth(), + lineHeight()); } + + int fileAreaLeft() const { return fileAreaRight() - fileAreaWidth(); } + int fileAreaWidth() const { return m_maxFileLength; } + int fileAreaRight() const { return lineAreaLeft() - ITEM_SPACING; } + QRect fileArea() const { return QRect(fileAreaLeft(), adjustedTop(), fileAreaWidth(), + lineHeight()); } + + int lineAreaLeft() const { return lineAreaRight() - lineAreaWidth(); } + int lineAreaWidth() const { return m_maxLineLength; } + int lineAreaRight() const { return adjustedRight() - ITEM_SPACING; } + QRect lineArea() const { return QRect(lineAreaLeft(), adjustedTop(), lineAreaWidth(), + lineHeight()); } + +private: + int m_x; + int m_width; + int m_top; + int m_bottom; + int m_fontHeight; + int m_maxFileLength; + int m_maxLineLength; + bool m_showTaskIconArea; + bool m_showExpandableIconArea; + +public: + static const int TASK_ICON_SIZE = 16; + static const int ITEM_PADDING = 8; + static const int ITEM_SPACING = 4; + +}; + +} // namespace Internal +} // namespace QmlJSTools + +#endif // QMLCONSOLEITEMDELEGATE_H diff --git a/src/plugins/qmljstools/qmlconsoleitemmodel.cpp b/src/plugins/qmljstools/qmlconsoleitemmodel.cpp new file mode 100644 index 0000000000..b4475d30e1 --- /dev/null +++ b/src/plugins/qmljstools/qmlconsoleitemmodel.cpp @@ -0,0 +1,282 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ + +#include "qmlconsoleitemmodel.h" + +#include <utils/qtcassert.h> + +#include <QFontMetrics> + +namespace QmlJSTools { +namespace Internal { + +/////////////////////////////////////////////////////////////////////// +// +// QmlConsoleItemModel +// +/////////////////////////////////////////////////////////////////////// + +QmlConsoleItemModel::QmlConsoleItemModel(QObject *parent) : + QAbstractItemModel(parent), + m_hasEditableRow(false), + m_rootItem(new QmlConsoleItem(0)), + m_maxSizeOfFileName(0) +{ +} + +QmlConsoleItemModel::~QmlConsoleItemModel() +{ + delete m_rootItem; +} + +void QmlConsoleItemModel::clear() +{ + beginResetModel(); + reset(); + delete m_rootItem; + m_rootItem = new QmlConsoleItem(0); + endResetModel(); + + if (m_hasEditableRow) + appendEditableRow(); +} + +bool QmlConsoleItemModel::appendItem(QmlConsoleItem *item, int position) +{ + if (position < 0) + position = m_rootItem->childCount() - 1; + + if (position < 0) + position = 0; + + beginInsertRows(QModelIndex(), position, position); + bool success = m_rootItem->insertChild(position, item); + endInsertRows(); + + return success; +} + +bool QmlConsoleItemModel::appendMessage(QmlConsoleItem::ItemType itemType, + const QString &message, int position) +{ + return appendItem(new QmlConsoleItem(m_rootItem, itemType, message), position); +} + +void QmlConsoleItemModel::setHasEditableRow(bool hasEditableRow) +{ + if (m_hasEditableRow && !hasEditableRow) + removeEditableRow(); + + if (!m_hasEditableRow && hasEditableRow) + appendEditableRow(); + + m_hasEditableRow = hasEditableRow; +} + +bool QmlConsoleItemModel::hasEditableRow() const +{ + return m_hasEditableRow; +} + +void QmlConsoleItemModel::appendEditableRow() +{ + int position = m_rootItem->childCount(); + if (appendItem(new QmlConsoleItem(m_rootItem, QmlConsoleItem::InputType), position)) + emit selectEditableRow(index(position, 0), QItemSelectionModel::ClearAndSelect); +} + +void QmlConsoleItemModel::removeEditableRow() +{ + if (m_rootItem->child(m_rootItem->childCount() - 1)->itemType == QmlConsoleItem::InputType) + removeRow(m_rootItem->childCount() - 1); +} + +int QmlConsoleItemModel::sizeOfFile(const QFont &font) +{ + int lastReadOnlyRow = m_rootItem->childCount(); + if (m_hasEditableRow) + lastReadOnlyRow -= 2; + else + lastReadOnlyRow -= 1; + if (lastReadOnlyRow < 0) + return 0; + QString filename = m_rootItem->child(lastReadOnlyRow)->file; + const int pos = filename.lastIndexOf(QLatin1Char('/')); + if (pos != -1) + filename = filename.mid(pos + 1); + + QFontMetrics fm(font); + m_maxSizeOfFileName = qMax(m_maxSizeOfFileName, fm.width(filename)); + + return m_maxSizeOfFileName; +} + +int QmlConsoleItemModel::sizeOfLineNumber(const QFont &font) +{ + QFontMetrics fm(font); + return fm.width(QLatin1String("88888")); +} + +QVariant QmlConsoleItemModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + QmlConsoleItem *item = getItem(index); + + if (role == Qt::DisplayRole ) + return item->text(); + else if (role == QmlConsoleItemModel::TypeRole) + return int(item->itemType); + else if (role == QmlConsoleItemModel::FileRole) + return item->file; + else if (role == QmlConsoleItemModel::LineRole) + return item->line; + else + return QVariant(); +} + +QModelIndex QmlConsoleItemModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) + return QModelIndex(); + + if (column > 0) + return QModelIndex(); + + QmlConsoleItem *parentItem = getItem(parent); + + QmlConsoleItem *childItem = parentItem->child(row); + if (childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} + +QModelIndex QmlConsoleItemModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + QmlConsoleItem *childItem = getItem(index); + QmlConsoleItem *parentItem = childItem->parent(); + + if (parentItem == m_rootItem) + return QModelIndex(); + + if (!parentItem) + return QModelIndex(); + return createIndex(parentItem->childNumber(), 0, parentItem); +} + +int QmlConsoleItemModel::rowCount(const QModelIndex &parent) const +{ + QmlConsoleItem *parentItem = getItem(parent); + + return parentItem->childCount(); +} + +int QmlConsoleItemModel::columnCount(const QModelIndex & /* parent */) const +{ + return 1; +} + +Qt::ItemFlags QmlConsoleItemModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + QmlConsoleItem *item = getItem(index); + if (m_hasEditableRow && item->parent() == m_rootItem + && index.row() == m_rootItem->childCount() - 1) + return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +bool QmlConsoleItemModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + QmlConsoleItem *item = getItem(index); + bool result = false; + if (role == Qt::DisplayRole) { + item->setText(value.toString()); + result = true; + } else if (role == QmlConsoleItemModel::TypeRole) { + item->itemType = (QmlConsoleItem::ItemType)value.toInt(); + result = true; + } else if (role == QmlConsoleItemModel::FileRole) { + item->file = value.toString(); + result = true; + } else if (role == QmlConsoleItemModel::LineRole) { + item->line = value.toInt(); + result = true; + } + + if (result) + emit dataChanged(index, index); + + return result; +} + +bool QmlConsoleItemModel::insertRows(int position, int rows, const QModelIndex &parent) +{ + QmlConsoleItem *parentItem = getItem(parent); + bool success; + + beginInsertRows(parent, position, position + rows - 1); + success = parentItem->insertChildren(position, rows); + endInsertRows(); + + return success; +} + +bool QmlConsoleItemModel::removeRows(int position, int rows, const QModelIndex &parent) +{ + QmlConsoleItem *parentItem = getItem(parent); + bool success = true; + + beginRemoveRows(parent, position, position + rows - 1); + success = parentItem->removeChildren(position, rows); + endRemoveRows(); + + return success; +} + +QmlConsoleItem *QmlConsoleItemModel::getItem(const QModelIndex &index) const +{ + if (index.isValid()) { + QmlConsoleItem *item = static_cast<QmlConsoleItem*>(index.internalPointer()); + if (item) + return item; + } + return m_rootItem; +} + +} // Internal +} // QmlJSTools diff --git a/src/plugins/qmljstools/qmlconsoleitemmodel.h b/src/plugins/qmljstools/qmlconsoleitemmodel.h new file mode 100644 index 0000000000..a66ec58888 --- /dev/null +++ b/src/plugins/qmljstools/qmlconsoleitemmodel.h @@ -0,0 +1,103 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ + +#ifndef QMLCONSOLEITEMMODEL_H +#define QMLCONSOLEITEMMODEL_H + +#include "qmlconsoleitem.h" + +#include <QAbstractItemModel> +#include <QItemSelectionModel> +#include <QFont> + +namespace QmlJSTools { +namespace Internal { + +class QmlConsoleItemModel : public QAbstractItemModel +{ + Q_OBJECT +public: + enum Roles { TypeRole = Qt::UserRole, FileRole, LineRole }; + + explicit QmlConsoleItemModel(QObject *parent = 0); + ~QmlConsoleItemModel(); + + void setHasEditableRow(bool hasEditableRow); + bool hasEditableRow() const; + void appendEditableRow(); + void removeEditableRow(); + + bool appendItem(QmlConsoleItem *item, int position = -1); + bool appendMessage(QmlConsoleItem::ItemType itemType, const QString &message, + int position = -1); + + QAbstractItemModel *model() { return this; } + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + + int sizeOfFile(const QFont &font); + int sizeOfLineNumber(const QFont &font); + + QmlConsoleItem *root() const { return m_rootItem; } + +public slots: + void clear(); + +signals: + void selectEditableRow(const QModelIndex &index, QItemSelectionModel::SelectionFlags flags); + void rowInserted(const QModelIndex &index); + +protected: + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + + + int columnCount(const QModelIndex &parent = QModelIndex()) const; + + Qt::ItemFlags flags(const QModelIndex &index) const; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + bool insertRows(int position, int rows, const QModelIndex &parent = QModelIndex()); + bool removeRows(int position, int rows, const QModelIndex &parent = QModelIndex()); + + QmlConsoleItem *getItem(const QModelIndex &index) const; + +private: + bool m_hasEditableRow; + QmlConsoleItem *m_rootItem; + int m_maxSizeOfFileName; +}; + +} // Internal +} // QmlJSTools + +#endif // QMLCONSOLEITEMMODEL_H diff --git a/src/plugins/qmljstools/qmlconsolemanager.cpp b/src/plugins/qmljstools/qmlconsolemanager.cpp new file mode 100644 index 0000000000..963ed68dd3 --- /dev/null +++ b/src/plugins/qmljstools/qmlconsolemanager.cpp @@ -0,0 +1,194 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ + +#include "qmlconsolemanager.h" +#include "qmlconsolepane.h" +#include "qmlconsoleitemmodel.h" + +#include <extensionsystem/pluginmanager.h> + +#include <debugger/debuggerengine.h> + +#include <QScriptEngine> +#include <QVariant> + +namespace QmlJSTools { + +QmlConsoleManager *QmlConsoleManager::m_instance = 0; + +class QmlConsoleManagerPrivate +{ +public: + QScriptEngine *scriptEngine; + Internal::QmlConsoleItemModel *qmlConsoleItemModel; + Internal::QmlConsolePane *qmlConsolePane; + Debugger::DebuggerEngine *debuggerEngine; +}; + +QmlConsoleManager::QmlConsoleManager(QObject *parent) + : QObject(parent), + d(new QmlConsoleManagerPrivate) +{ + m_instance = this; + d->scriptEngine = new QScriptEngine(this); + d->qmlConsoleItemModel = new Internal::QmlConsoleItemModel(this); + d->qmlConsoleItemModel->setHasEditableRow(true); + d->qmlConsolePane = new Internal::QmlConsolePane(this); + ExtensionSystem::PluginManager::addObject(d->qmlConsolePane); + d->debuggerEngine = 0; +} + +QmlConsoleManager::~QmlConsoleManager() +{ + if (d->qmlConsolePane) { + ExtensionSystem::PluginManager::removeObject(d->qmlConsolePane); + } + delete d; + m_instance = 0; +} + +void QmlConsoleManager::showConsolePane() +{ + if (d->qmlConsolePane) + d->qmlConsolePane->popup(Core::IOutputPane::ModeSwitch); +} + +QmlConsoleItem *QmlConsoleManager::rootItem() const +{ + return d->qmlConsoleItemModel->root(); +} + +void QmlConsoleManager::setDebuggerEngine(Debugger::DebuggerEngine *debuggerEngine) +{ + d->debuggerEngine = debuggerEngine; + if (!debuggerEngine) + setContext(QString()); +} + +void QmlConsoleManager::setContext(const QString &context) +{ + d->qmlConsolePane->setContext(context); +} + +void QmlConsoleManager::printToConsolePane(QmlConsoleItem::ItemType itemType, + const QString &text, bool bringToForeground) +{ + if (!d->qmlConsolePane) + return; + if (itemType == QmlConsoleItem::ErrorType) + bringToForeground = true; + if (bringToForeground) + d->qmlConsolePane->popup(Core::IOutputPane::ModeSwitch); + d->qmlConsoleItemModel->appendMessage(itemType, text); +} + +void QmlConsoleManager::printToConsolePane(QmlConsoleItem *item, bool bringToForeground) +{ + if (!d->qmlConsolePane) + return; + if (item->itemType == QmlConsoleItem::ErrorType) + bringToForeground = true; + if (bringToForeground) + d->qmlConsolePane->popup(Core::IOutputPane::ModeSwitch); + d->qmlConsoleItemModel->appendItem(item); +} + +namespace Internal { + +QmlConsoleItem *constructLogItemTree(QmlConsoleItem *parent, const QVariant &result, + const QString &key = QString()) +{ + if (!result.isValid()) + return 0; + + QmlConsoleItem *item = new QmlConsoleItem(parent); + if (result.type() == QVariant::Map) { + if (key.isEmpty()) + item->setText(QLatin1String("Object")); + else + item->setText(key + QLatin1String(" : Object")); + + QMapIterator<QString, QVariant> i(result.toMap()); + while (i.hasNext()) { + i.next(); + QmlConsoleItem *child = constructLogItemTree(item, i.value(), i.key()); + if (child) + item->insertChild(child, true); + } + } else if (result.type() == QVariant::List) { + if (key.isEmpty()) + item->setText(QLatin1String("List")); + else + item->setText(QString(QLatin1String("[%1] : List")).arg(key)); + QVariantList resultList = result.toList(); + for (int i = 0; i < resultList.count(); i++) { + QmlConsoleItem *child = constructLogItemTree(item, resultList.at(i), + QString::number(i)); + if (child) + item->insertChild(child, true); + } + } else if (result.canConvert(QVariant::String)) { + item->setText(result.toString()); + } else { + item->setText(QLatin1String("Unknown Value")); + } + + return item; +} + +QmlConsoleItemModel *QmlConsoleModel::qmlConsoleItemModel() +{ + QmlConsoleManager *manager = QmlConsoleManager::instance(); + if (manager) + return manager->d->qmlConsoleItemModel; + return 0; +} + +void QmlConsoleModel::evaluate(const QString &expression) +{ + QmlConsoleManager *manager = QmlConsoleManager::instance(); + if (manager) { + if (manager->d->debuggerEngine) { + QmlConsoleModel::qmlConsoleItemModel()->appendEditableRow(); + manager->d->debuggerEngine->evaluateScriptExpression(expression); + } else { + QVariant result = manager->d->scriptEngine->evaluate(expression).toVariant(); + QmlConsoleItem *root = manager->rootItem(); + QmlConsoleItem *item = constructLogItemTree(root, result); + if (item) { + QmlConsoleModel::qmlConsoleItemModel()->appendEditableRow(); + manager->printToConsolePane(item); + } + } + } +} + +} // Internal +} // QmlJSTools diff --git a/src/plugins/qmljstools/qmlconsolemanager.h b/src/plugins/qmljstools/qmlconsolemanager.h new file mode 100644 index 0000000000..0a537be326 --- /dev/null +++ b/src/plugins/qmljstools/qmlconsolemanager.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef QMLCONSOLEMANAGER_H +#define QMLCONSOLEMANAGER_H + +#include "qmljstools_global.h" +#include "qmlconsoleitem.h" + +#include <QObject> + +namespace Debugger { +class DebuggerEngine; +} +namespace QmlJSTools { + +namespace Internal { +class QmlConsoleItemModel; +class QmlConsoleModel; +} + +class QmlConsoleManagerPrivate; +class QMLJSTOOLS_EXPORT QmlConsoleManager : public QObject +{ + Q_OBJECT +public: + QmlConsoleManager(QObject *parent); + ~QmlConsoleManager(); + + static QmlConsoleManager *instance() { return m_instance; } + + void showConsolePane(); + + QmlConsoleItem *rootItem() const; + + void setDebuggerEngine(Debugger::DebuggerEngine *debuggerEngine); + void setContext(const QString &context); + + void printToConsolePane(QmlConsoleItem::ItemType itemType, const QString &text, + bool bringToForeground = false); + void printToConsolePane(QmlConsoleItem *item, bool bringToForeground = false); + +private: + QmlConsoleManagerPrivate *d; + static QmlConsoleManager *m_instance; + friend class Internal::QmlConsoleModel; +}; + +namespace Internal { + +class QmlConsoleModel +{ +public: + static QmlConsoleItemModel *qmlConsoleItemModel(); + static void evaluate(const QString &expression); +}; + +} + +} // namespace QmlJSTools + +#endif // QMLCONSOLEMANAGER_H diff --git a/src/plugins/qmljstools/qmlconsolepane.cpp b/src/plugins/qmljstools/qmlconsolepane.cpp new file mode 100644 index 0000000000..56c1d69d3e --- /dev/null +++ b/src/plugins/qmljstools/qmlconsolepane.cpp @@ -0,0 +1,245 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ + +#include "qmlconsolepane.h" +#include "qmlconsoleview.h" +#include "qmlconsoleproxymodel.h" +#include "qmlconsoleitemmodel.h" +#include "qmlconsolemanager.h" +#include "qmlconsoleitemdelegate.h" + +#include <coreplugin/icore.h> +#include <coreplugin/icontext.h> +#include <coreplugin/findplaceholder.h> +#include <utils/savedaction.h> +#include <aggregation/aggregate.h> +#include <find/treeviewfind.h> + +#include <QToolButton> +#include <QLabel> +#include <QVBoxLayout> + +static const char CONSOLE[] = "Console"; +static const char SHOW_LOG[] = "showLog"; +static const char SHOW_WARNING[] = "showWarning"; +static const char SHOW_ERROR[] = "showError"; + +namespace QmlJSTools { +namespace Internal { + +///////////////////////////////////////////////////////////////////// +// +// QmlConsolePane +// +///////////////////////////////////////////////////////////////////// + +QmlConsolePane::QmlConsolePane(QObject *parent) + : Core::IOutputPane(parent) +{ + m_consoleWidget = new QWidget; + m_consoleWidget->setWindowTitle(displayName()); + m_consoleWidget->setEnabled(true); + + QVBoxLayout *vbox = new QVBoxLayout(m_consoleWidget); + vbox->setMargin(0); + vbox->setSpacing(0); + + m_consoleView = new QmlConsoleView(m_consoleWidget); + m_proxyModel = new QmlConsoleProxyModel(this); + m_proxyModel->setSourceModel(QmlConsoleModel::qmlConsoleItemModel()); + connect(QmlConsoleModel::qmlConsoleItemModel(), + SIGNAL(selectEditableRow(QModelIndex, QItemSelectionModel::SelectionFlags)), + m_proxyModel, + SLOT(selectEditableRow(QModelIndex,QItemSelectionModel::SelectionFlags))); + + //Scroll to bottom when rows matching current filter settings are inserted + //Not connecting rowsRemoved as the only way to remove rows is to clear the + //model which will automatically reset the view. + connect(QmlConsoleModel::qmlConsoleItemModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), + m_proxyModel, SLOT(onRowsInserted(QModelIndex,int,int))); + m_consoleView->setModel(m_proxyModel); + + connect(m_proxyModel, + SIGNAL(setCurrentIndex(QModelIndex,QItemSelectionModel::SelectionFlags)), + m_consoleView->selectionModel(), + SLOT(setCurrentIndex(QModelIndex,QItemSelectionModel::SelectionFlags))); + connect(m_proxyModel, SIGNAL(scrollToBottom()), m_consoleView, SLOT(onScrollToBottom())); + + m_itemDelegate = new QmlConsoleItemDelegate(this); + connect(m_consoleView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), + m_itemDelegate, SLOT(currentChanged(QModelIndex,QModelIndex))); + m_consoleView->setItemDelegate(m_itemDelegate); + + Aggregation::Aggregate *aggregate = new Aggregation::Aggregate(); + aggregate->add(m_consoleView); + aggregate->add(new Find::TreeViewFind(m_consoleView)); + + vbox->addWidget(m_consoleView); + vbox->addWidget(new Core::FindToolBarPlaceHolder(m_consoleWidget)); + + m_showDebugButton = new QToolButton(m_consoleWidget); + m_showDebugButton->setAutoRaise(true); + + m_showDebugButtonAction = new Utils::SavedAction(this); + m_showDebugButtonAction->setDefaultValue(true); + m_showDebugButtonAction->setSettingsKey(QLatin1String(CONSOLE), QLatin1String(SHOW_LOG)); + m_showDebugButtonAction->setToolTip(tr("Show debug, log, and info messages.")); + m_showDebugButtonAction->setCheckable(true); + m_showDebugButtonAction->setIcon(QIcon(QLatin1String(":/qmljstools/images/log.png"))); + connect(m_showDebugButtonAction, SIGNAL(toggled(bool)), m_proxyModel, SLOT(setShowLogs(bool))); + m_showDebugButton->setDefaultAction(m_showDebugButtonAction); + + m_showWarningButton = new QToolButton(m_consoleWidget); + m_showWarningButton->setAutoRaise(true); + + m_showWarningButtonAction = new Utils::SavedAction(this); + m_showWarningButtonAction->setDefaultValue(true); + m_showWarningButtonAction->setSettingsKey(QLatin1String(CONSOLE), QLatin1String(SHOW_WARNING)); + m_showWarningButtonAction->setToolTip(tr("Show debug, log, and info messages.")); + m_showWarningButtonAction->setCheckable(true); + m_showWarningButtonAction->setIcon(QIcon(QLatin1String(":/qmljstools/images/warning.png"))); + connect(m_showWarningButtonAction, SIGNAL(toggled(bool)), m_proxyModel, + SLOT(setShowWarnings(bool))); + m_showWarningButton->setDefaultAction(m_showWarningButtonAction); + + m_showErrorButton = new QToolButton(m_consoleWidget); + m_showErrorButton->setAutoRaise(true); + + m_showErrorButtonAction = new Utils::SavedAction(this); + m_showErrorButtonAction->setDefaultValue(true); + m_showErrorButtonAction->setSettingsKey(QLatin1String(CONSOLE), QLatin1String(SHOW_ERROR)); + m_showErrorButtonAction->setToolTip(tr("Show debug, log, and info messages.")); + m_showErrorButtonAction->setCheckable(true); + m_showErrorButtonAction->setIcon(QIcon(QLatin1String(":/qmljstools/images/error.png"))); + connect(m_showErrorButtonAction, SIGNAL(toggled(bool)), m_proxyModel, + SLOT(setShowErrors(bool))); + m_showErrorButton->setDefaultAction(m_showErrorButtonAction); + + m_spacer = new QWidget(m_consoleWidget); + m_spacer->setMinimumWidth(30); + + m_statusLabel = new QLabel(m_consoleWidget); + + readSettings(); + connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), SLOT(writeSettings())); +} + +QmlConsolePane::~QmlConsolePane() +{ + writeSettings(); + delete m_consoleWidget; +} + +QWidget *QmlConsolePane::outputWidget(QWidget *) +{ + return m_consoleWidget; +} + +QList<QWidget *> QmlConsolePane::toolBarWidgets() const +{ + return QList<QWidget *>() << m_showDebugButton << m_showWarningButton << m_showErrorButton + << m_spacer << m_statusLabel; +} + +int QmlConsolePane::priorityInStatusBar() const +{ + return 20; +} + +void QmlConsolePane::clearContents() +{ + QmlConsoleModel::qmlConsoleItemModel()->clear(); +} + +void QmlConsolePane::visibilityChanged(bool /*visible*/) +{ +} + +bool QmlConsolePane::canFocus() const +{ + return true; +} + +bool QmlConsolePane::hasFocus() const +{ + return m_consoleWidget->hasFocus(); +} + +void QmlConsolePane::setFocus() +{ + m_consoleWidget->setFocus(); +} + +bool QmlConsolePane::canNext() const +{ + return false; +} + +bool QmlConsolePane::canPrevious() const +{ + return false; +} + +void QmlConsolePane::goToNext() +{ +} + +void QmlConsolePane::goToPrev() +{ +} + +bool QmlConsolePane::canNavigate() const +{ + return false; +} + +void QmlConsolePane::readSettings() +{ + QSettings *settings = Core::ICore::settings(); + m_showDebugButtonAction->readSettings(settings); + m_showWarningButtonAction->readSettings(settings); + m_showErrorButtonAction->readSettings(settings); +} + +void QmlConsolePane::setContext(const QString &context) +{ + m_statusLabel->setText(context); +} + +void QmlConsolePane::writeSettings() const +{ + QSettings *settings = Core::ICore::settings(); + m_showDebugButtonAction->writeSettings(settings); + m_showWarningButtonAction->writeSettings(settings); + m_showErrorButtonAction->writeSettings(settings); +} + +} // Internal +} // QmlJSTools diff --git a/src/plugins/qmljstools/qmlconsolepane.h b/src/plugins/qmljstools/qmlconsolepane.h new file mode 100644 index 0000000000..2606485df2 --- /dev/null +++ b/src/plugins/qmljstools/qmlconsolepane.h @@ -0,0 +1,101 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ + +#ifndef QMLCONSOLEPANE_H +#define QMLCONSOLEPANE_H + +#include <coreplugin/ioutputpane.h> + +QT_BEGIN_NAMESPACE +class QToolButton; +class QLabel; +QT_END_NAMESPACE + +namespace Utils { +class SavedAction; +} + +namespace QmlJSTools { + +namespace Internal { + +class QmlConsoleView; +class QmlConsoleItemDelegate; +class QmlConsoleProxyModel; +class QmlConsoleItemModel; + +class QmlConsolePane : public Core::IOutputPane +{ + Q_OBJECT +public: + QmlConsolePane(QObject *parent); + ~QmlConsolePane(); + + QWidget *outputWidget(QWidget *); + QList<QWidget *> toolBarWidgets() const; + QString displayName() const { return tr("Console"); } + int priorityInStatusBar() const; + void clearContents(); + void visibilityChanged(bool visible); + bool canFocus() const; + bool hasFocus() const; + void setFocus(); + + bool canNext() const; + bool canPrevious() const; + void goToNext(); + void goToPrev(); + bool canNavigate() const; + + void readSettings(); + void setContext(const QString &context); + +public slots: + void writeSettings() const; + +private: + QToolButton *m_showDebugButton; + QToolButton *m_showWarningButton; + QToolButton *m_showErrorButton; + Utils::SavedAction *m_showDebugButtonAction; + Utils::SavedAction *m_showWarningButtonAction; + Utils::SavedAction *m_showErrorButtonAction; + QWidget *m_spacer; + QLabel *m_statusLabel; + QmlConsoleView *m_consoleView; + QmlConsoleItemDelegate *m_itemDelegate; + QmlConsoleProxyModel *m_proxyModel; + QWidget *m_consoleWidget; +}; + +} // namespace Internal +} // namespace QmlJSTools + +#endif // QMLCONSOLEPANE_H diff --git a/src/plugins/qmljstools/qmlconsoleproxymodel.cpp b/src/plugins/qmljstools/qmlconsoleproxymodel.cpp new file mode 100644 index 0000000000..cc1b4f5d4d --- /dev/null +++ b/src/plugins/qmljstools/qmlconsoleproxymodel.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "qmlconsoleproxymodel.h" +#include "qmlconsoleitemmodel.h" + +namespace QmlJSTools { +namespace Internal { + +QmlConsoleProxyModel::QmlConsoleProxyModel(QObject *parent) : + QSortFilterProxyModel(parent), + m_filter(QmlConsoleItem::DefaultTypes) +{ +} + +void QmlConsoleProxyModel::setShowLogs(bool show) +{ + m_filter = show ? m_filter | QmlConsoleItem::DebugType : m_filter & ~QmlConsoleItem::DebugType; + setFilterRegExp(QString()); +} + +void QmlConsoleProxyModel::setShowWarnings(bool show) +{ + m_filter = show ? m_filter | QmlConsoleItem::WarningType + : m_filter & ~QmlConsoleItem::WarningType; + setFilterRegExp(QString()); +} + +void QmlConsoleProxyModel::setShowErrors(bool show) +{ + m_filter = show ? m_filter | QmlConsoleItem::ErrorType : m_filter & ~QmlConsoleItem::ErrorType; + setFilterRegExp(QString()); +} + +void QmlConsoleProxyModel::selectEditableRow(const QModelIndex &index, + QItemSelectionModel::SelectionFlags command) +{ + emit setCurrentIndex(mapFromSource(index), command); +} + +bool QmlConsoleProxyModel::filterAcceptsRow(int sourceRow, + const QModelIndex &sourceParent) const + { + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + return m_filter.testFlag((QmlConsoleItem::ItemType)sourceModel()->data( + index, QmlConsoleItemModel::TypeRole).toInt()); + } + +void QmlConsoleProxyModel::onRowsInserted(const QModelIndex &index, int start, int end) +{ + int rowIndex = end; + do { + if (filterAcceptsRow(rowIndex, index)) { + emit scrollToBottom(); + break; + } + } while (--rowIndex >= start); +} + +} // Internal +} // QmlJSTools diff --git a/src/plugins/qmljstools/qmlconsoleproxymodel.h b/src/plugins/qmljstools/qmlconsoleproxymodel.h new file mode 100644 index 0000000000..ac7fd72bcb --- /dev/null +++ b/src/plugins/qmljstools/qmlconsoleproxymodel.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef QMLCONSOLEPROXYMODEL_H +#define QMLCONSOLEPROXYMODEL_H + +#include "qmlconsoleitem.h" + +#include <QSortFilterProxyModel> +#include <QItemSelectionModel> + +namespace QmlJSTools { +namespace Internal { + +class QmlConsoleProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + explicit QmlConsoleProxyModel(QObject *parent); + +public slots: + void setShowLogs(bool show); + void setShowWarnings(bool show); + void setShowErrors(bool show); + void selectEditableRow(const QModelIndex &index, + QItemSelectionModel::SelectionFlags command); + void onRowsInserted(const QModelIndex &index, int start, int end); + +signals: + void scrollToBottom(); + void setCurrentIndex(const QModelIndex &index, + QItemSelectionModel::SelectionFlags command); + +protected: + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; + +private: + QFlags<QmlConsoleItem::ItemType> m_filter; +}; + +} // Internal +} // QmlJSTools + +#endif // QMLCONSOLEPROXYMODEL_H diff --git a/src/plugins/qmljstools/qmlconsoleview.cpp b/src/plugins/qmljstools/qmlconsoleview.cpp new file mode 100644 index 0000000000..e0eebae43d --- /dev/null +++ b/src/plugins/qmljstools/qmlconsoleview.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "qmlconsoleview.h" +#include "qmlconsoleitemdelegate.h" +#include "qmlconsoleitemmodel.h" + +#include <texteditor/basetexteditor.h> + +#include <QMouseEvent> +#include <QProxyStyle> +#include <QPainter> +#include <QApplication> +#include <QClipboard> +#include <QAbstractProxyModel> +#include <QFileInfo> +#include <QUrl> +#include <QScrollBar> + +namespace QmlJSTools { +namespace Internal { + +class QmlConsoleViewStyle : public QProxyStyle +{ +public: + void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, + const QWidget *widget = 0) const + { + if (element != QStyle::PE_PanelItemViewRow) + QProxyStyle::drawPrimitive(element, option, painter, widget); + } + + int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, + QStyleHintReturn *returnData = 0) const { + if (hint == SH_ItemView_ShowDecorationSelected) + return 0; + else + return QProxyStyle::styleHint(hint, option, widget, returnData); + } +}; + +/////////////////////////////////////////////////////////////////////// +// +// QmlConsoleView +// +/////////////////////////////////////////////////////////////////////// + +QmlConsoleView::QmlConsoleView(QWidget *parent) : + QTreeView(parent) +{ + setFrameStyle(QFrame::NoFrame); + setHeaderHidden(true); + setRootIsDecorated(false); + setEditTriggers(QAbstractItemView::AllEditTriggers); + setStyleSheet(QLatin1String("QTreeView::branch:has-siblings:!adjoins-item {" + "border-image: none;" + "image: none; }" + "QTreeView::branch:has-siblings:adjoins-item {" + "border-image: none;" + "image: none; }" + "QTreeView::branch:!has-children:!has-siblings:adjoins-item {" + "border-image: none;" + "image: none; }" + "QTreeView::branch:has-children:!has-siblings:closed," + "QTreeView::branch:closed:has-children:has-siblings {" + "border-image: none;" + "image: none; }" + "QTreeView::branch:open:has-children:!has-siblings," + "QTreeView::branch:open:has-children:has-siblings {" + "border-image: none;" + "image: none; }")); + QmlConsoleViewStyle *style = new QmlConsoleViewStyle; + setStyle(style); + style->setParent(this); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + + connect(this, SIGNAL(activated(QModelIndex)), SLOT(onRowActivated(QModelIndex))); +} + +void QmlConsoleView::onScrollToBottom() +{ + // Keep scrolling to bottom if scroll bar is at maximum() + if (verticalScrollBar()->value() == verticalScrollBar()->maximum()) + scrollToBottom(); +} + +void QmlConsoleView::mousePressEvent(QMouseEvent *event) +{ + QPoint pos = event->pos(); + QModelIndex index = indexAt(pos); + if (index.isValid()) { + QmlConsoleItem::ItemType type = (QmlConsoleItem::ItemType)index.data( + QmlConsoleItemModel::TypeRole).toInt(); + bool handled = false; + if (type == QmlConsoleItem::UndefinedType) { + bool showTypeIcon = index.parent() == QModelIndex(); + ConsoleItemPositions positions(visualRect(index), viewOptions().font, showTypeIcon, + true); + + if (positions.expandCollapseIcon().contains(pos)) { + if (isExpanded(index)) + setExpanded(index, false); + else + setExpanded(index, true); + handled = true; + } + } + if (!handled) + QTreeView::mousePressEvent(event); + } else { + selectionModel()->setCurrentIndex(model()->index(model()->rowCount() - 1, 0), + QItemSelectionModel::ClearAndSelect); + } +} + +void QmlConsoleView::keyPressEvent(QKeyEvent *e) +{ + if (!e->modifiers() && e->key() == Qt::Key_Return) { + emit activated(currentIndex()); + e->accept(); + return; + } + QTreeView::keyPressEvent(e); +} + +void QmlConsoleView::resizeEvent(QResizeEvent *e) +{ + static_cast<QmlConsoleItemDelegate *>(itemDelegate())->emitSizeHintChanged( + selectionModel()->currentIndex()); + QTreeView::resizeEvent(e); +} + +void QmlConsoleView::drawBranches(QPainter *painter, const QRect &rect, + const QModelIndex &index) const +{ + static_cast<QmlConsoleItemDelegate *>(itemDelegate())->drawBackground(painter, rect, index, + false); + QTreeView::drawBranches(painter, rect, index); +} + +void QmlConsoleView::contextMenuEvent(QContextMenuEvent *event) +{ + QModelIndex itemIndex = indexAt(event->pos()); + QMenu menu; + + QAction *copy = new QAction(tr("&Copy"), this); + copy->setEnabled(itemIndex.isValid()); + menu.addAction(copy); + QAction *show = new QAction(tr("&Show in Editor"), this); + show->setEnabled(canShowItemInTextEditor(itemIndex)); + menu.addAction(show); + menu.addSeparator(); + QAction *clear = new QAction(tr("C&lear"), this); + menu.addAction(clear); + + QAction *a = menu.exec(event->globalPos()); + if (a == 0) + return; + + if (a == copy) { + copyToClipboard(itemIndex); + } else if (a == show) { + onRowActivated(itemIndex); + } else if (a == clear) { + QAbstractProxyModel *proxyModel = qobject_cast<QAbstractProxyModel *>(model()); + QmlConsoleItemModel *handler = qobject_cast<QmlConsoleItemModel *>( + proxyModel->sourceModel()); + handler->clear(); + } +} + +void QmlConsoleView::onRowActivated(const QModelIndex &index) +{ + if (!index.isValid()) + return; + + // See if we have file and line Info + QString filePath = model()->data(index, + QmlConsoleItemModel::FileRole).toString(); + if (!filePath.isEmpty()) { + QFileInfo fi(filePath); + if (fi.exists() && fi.isFile() && fi.isReadable()) { + int line = model()->data(index, QmlConsoleItemModel::LineRole).toInt(); + TextEditor::BaseTextEditorWidget::openEditorAt(fi.canonicalFilePath(), line); + } + } +} + +void QmlConsoleView::copyToClipboard(const QModelIndex &index) +{ + if (!index.isValid()) + return; + + QString contents = model()->data(index).toString(); + // See if we have file and line Info + QString filePath = model()->data(index, QmlConsoleItemModel::FileRole).toString(); + if (!filePath.isEmpty()) { + contents = QString(QLatin1String("%1 %2: %3")).arg(contents).arg(filePath).arg( + model()->data(index, QmlConsoleItemModel::LineRole).toString()); + } + QClipboard *cb = QApplication::clipboard(); + cb->setText(contents); +} + +bool QmlConsoleView::canShowItemInTextEditor(const QModelIndex &index) +{ + if (!index.isValid()) + return false; + + // See if we have file and line Info + QString filePath = model()->data(index, QmlConsoleItemModel::FileRole).toString(); + if (!filePath.isEmpty()) { + QFileInfo fi(filePath); + if (fi.exists() && fi.isFile() && fi.isReadable()) { + return true; + } + } + return false; +} + +} // Internal +} // QmlJSTools diff --git a/src/plugins/qmljstools/qmlconsoleview.h b/src/plugins/qmljstools/qmlconsoleview.h new file mode 100644 index 0000000000..d37fb5b853 --- /dev/null +++ b/src/plugins/qmljstools/qmlconsoleview.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef QMLCONSOLEVIEW_H +#define QMLCONSOLEVIEW_H + +#include <QTreeView> + +namespace QmlJSTools { +namespace Internal { + +class QmlConsoleView : public QTreeView +{ + Q_OBJECT +public: + QmlConsoleView(QWidget *parent); + +public slots: + void onScrollToBottom(); + +protected: + void mousePressEvent(QMouseEvent *event); + void keyPressEvent(QKeyEvent *e); + void resizeEvent(QResizeEvent *e); + void drawBranches(QPainter *painter, const QRect &rect, + const QModelIndex &index) const; + void contextMenuEvent(QContextMenuEvent *event); + +private slots: + void onRowActivated(const QModelIndex &index); + +private: + void copyToClipboard(const QModelIndex &index); + bool canShowItemInTextEditor(const QModelIndex &index); +}; + +} // Internal +} // QmlJSTools + +#endif // QMLCONSOLEVIEW_H diff --git a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp index 6ec0d5b7e0..b546ed5699 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp @@ -176,7 +176,7 @@ QmlJSCodeStyleSettingsPage::QmlJSCodeStyleSettingsPage(/*QSharedPointer<CppFileS QWidget *QmlJSCodeStyleSettingsPage::createPage(QWidget *parent) { TextEditor::SimpleCodeStylePreferences *originalTabPreferences - = QmlJSToolsSettings::instance()->qmlJSCodeStyle(); + = QmlJSToolsSettings::globalCodeStyle(); m_pageTabPreferences = new TextEditor::SimpleCodeStylePreferences(m_widget); m_pageTabPreferences->setDelegatingPool(originalTabPreferences->delegatingPool()); m_pageTabPreferences->setTabSettings(originalTabPreferences->tabSettings()); @@ -194,7 +194,7 @@ void QmlJSCodeStyleSettingsPage::apply() if (m_widget) { QSettings *s = Core::ICore::settings(); - TextEditor::SimpleCodeStylePreferences *originalTabPreferences = QmlJSToolsSettings::instance()->qmlJSCodeStyle(); + TextEditor::SimpleCodeStylePreferences *originalTabPreferences = QmlJSToolsSettings::globalCodeStyle(); if (originalTabPreferences->tabSettings() != m_pageTabPreferences->tabSettings()) { originalTabPreferences->setTabSettings(m_pageTabPreferences->tabSettings()); if (s) diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.h b/src/plugins/qmljstools/qmljsfunctionfilter.h index df3d59f300..55c9bb3a2c 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.h +++ b/src/plugins/qmljstools/qmljsfunctionfilter.h @@ -44,7 +44,7 @@ public: explicit FunctionFilter(LocatorData *data, QObject *parent = 0); ~FunctionFilter(); - QString displayName() const { return tr("Methods and Functions"); } + QString displayName() const { return tr("QML Methods and Functions"); } QString id() const { return QLatin1String("Functions"); } Priority priority() const { return Medium; } QList<Locator::FilterEntry> matchesFor(QFutureInterface<Locator::FilterEntry> &future, const QString &entry); diff --git a/src/plugins/qmljstools/qmljsinterpreter.cpp b/src/plugins/qmljstools/qmljsinterpreter.cpp new file mode 100644 index 0000000000..691f65d160 --- /dev/null +++ b/src/plugins/qmljstools/qmljsinterpreter.cpp @@ -0,0 +1,88 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ + +#include "qmljsinterpreter.h" + +namespace QmlJSTools { +namespace Internal { + +bool QmlJSInterpreter::canEvaluate() +{ + int yyaction = 0; + int yytoken = -1; + int yytos = -1; + + setCode(m_code, 1); + m_tokens.append(T_FEED_JS_PROGRAM); + + do { + if (++yytos == m_stateStack.size()) + m_stateStack.resize(m_stateStack.size() * 2); + + m_stateStack[yytos] = yyaction; + +again: + if (yytoken == -1 && action_index[yyaction] != -TERMINAL_COUNT) { + if (m_tokens.isEmpty()) + yytoken = lex(); + else + yytoken = m_tokens.takeFirst(); + } + + yyaction = t_action(yyaction, yytoken); + if (yyaction > 0) { + if (yyaction == ACCEPT_STATE) { + --yytos; + return true; + } + yytoken = -1; + } else if (yyaction < 0) { + const int ruleno = -yyaction - 1; + yytos -= rhs[ruleno]; + yyaction = nt_action(m_stateStack[yytos], lhs[ruleno] - TERMINAL_COUNT); + } + } while (yyaction); + + const int errorState = m_stateStack[yytos]; + if (t_action(errorState, T_AUTOMATIC_SEMICOLON) && canInsertAutomaticSemicolon(yytoken)) { + yyaction = errorState; + m_tokens.prepend(yytoken); + yytoken = T_SEMICOLON; + goto again; + } + + if (yytoken != EOF_SYMBOL) + return true; + + return false; +} + +} // namespace Internal +} // namespace QmlJSTools diff --git a/src/plugins/qmljstools/qmljsinterpreter.h b/src/plugins/qmljstools/qmljsinterpreter.h new file mode 100644 index 0000000000..7c4f86f688 --- /dev/null +++ b/src/plugins/qmljstools/qmljsinterpreter.h @@ -0,0 +1,70 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ + +#ifndef QMLJSINTERPRETER_H +#define QMLJSINTERPRETER_H + +#include <qmljs/parser/qmljslexer_p.h> +#include <qmljs/parser/qmljsengine_p.h> + +#include <QVector> +#include <QString> +#include <QList> + +namespace QmlJSTools { +namespace Internal { + +class QmlJSInterpreter: QmlJS::Lexer +{ +public: + QmlJSInterpreter() + : Lexer(&m_engine), + m_stateStack(128) + { + + } + + void clearText() { m_code.clear(); } + void appendText(const QString &text) { m_code += text; } + + QString code() const { return m_code; } + bool canEvaluate(); + +private: + QmlJS::Engine m_engine; + QVector<int> m_stateStack; + QList<int> m_tokens; + QString m_code; +}; + +} // namespace Internal +} // namespace QmlJSTools + +#endif // QMLJSINTERPRETER_H diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index a2d59c61a7..94bfb7a93a 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -50,6 +50,7 @@ #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/session.h> #include <qtsupport/baseqtversion.h> +#include <utils/hostosinfo.h> #include <QDir> #include <QFile> @@ -464,9 +465,9 @@ static bool findNewQmlLibraryInPath(const QString &path, return false; } -#ifdef Q_OS_WIN - // QTCREATORBUG-3402 - be case sensitive even here? -#endif + if (Utils::HostOsInfo::isWindowsHost()) { + // QTCREATORBUG-3402 - be case sensitive even here? + } // found a new library! qmldirFile.open(QFile::ReadOnly); @@ -653,12 +654,8 @@ static QStringList environmentImportPaths() QByteArray envImportPath = qgetenv("QML_IMPORT_PATH"); -#if defined(Q_OS_WIN) - QLatin1Char pathSep(';'); -#else - QLatin1Char pathSep(':'); -#endif - foreach (const QString &path, QString::fromLatin1(envImportPath).split(pathSep, QString::SkipEmptyParts)) { + foreach (const QString &path, QString::fromLatin1(envImportPath) + .split(Utils::HostOsInfo::pathListSeparator(), QString::SkipEmptyParts)) { QString canonicalPath = QDir(path).canonicalPath(); if (!canonicalPath.isEmpty() && !paths.contains(canonicalPath)) paths.append(canonicalPath); diff --git a/src/plugins/qmljstools/qmljstools-lib.pri b/src/plugins/qmljstools/qmljstools-lib.pri deleted file mode 100644 index e618816549..0000000000 --- a/src/plugins/qmljstools/qmljstools-lib.pri +++ /dev/null @@ -1,45 +0,0 @@ -!dll { - DEFINES += QMLJSTOOLS_STATIC -} - -INCLUDEPATH += $$PWD/.. - -HEADERS += \ - $$PWD/qmljstools_global.h \ - $$PWD/qmljstoolsplugin.h \ - $$PWD/qmljstoolsconstants.h \ - $$PWD/qmljstoolssettings.h \ - $$PWD/qmljscodestylepreferencesfactory.h \ - $$PWD/qmljsmodelmanager.h \ - $$PWD/qmljsqtstylecodeformatter.h \ - $$PWD/qmljsrefactoringchanges.h \ - $$PWD/qmljsplugindumper.h \ - $$PWD/qmljsfunctionfilter.h \ - $$PWD/qmljslocatordata.h \ - $$PWD/qmljsindenter.h \ - $$PWD/qmljscodestylesettingspage.h \ - $$PWD/qmljsfindexportedcpptypes.h \ - $$PWD/qmljssemanticinfo.h - -SOURCES += \ - $$PWD/qmljstoolsplugin.cpp \ - $$PWD/qmljstoolssettings.cpp \ - $$PWD/qmljscodestylepreferencesfactory.cpp \ - $$PWD/qmljsmodelmanager.cpp \ - $$PWD/qmljsqtstylecodeformatter.cpp \ - $$PWD/qmljsrefactoringchanges.cpp \ - $$PWD/qmljsplugindumper.cpp \ - $$PWD/qmljsfunctionfilter.cpp \ - $$PWD/qmljslocatordata.cpp \ - $$PWD/qmljsindenter.cpp \ - $$PWD/qmljscodestylesettingspage.cpp \ - $$PWD/qmljsfindexportedcpptypes.cpp \ - $$PWD/qmljssemanticinfo.cpp - -FORMS += \ - $$PWD/qmljscodestylesettingspage.ui - -equals(TEST, 1) { - SOURCES += \ - $$PWD/qmljstools_test.cpp -} diff --git a/src/plugins/qmljstools/qmljstools.pri b/src/plugins/qmljstools/qmljstools.pri index 75415d0c1f..1d36f5e406 100644 --- a/src/plugins/qmljstools/qmljstools.pri +++ b/src/plugins/qmljstools/qmljstools.pri @@ -1,5 +1,3 @@ include(qmljstools_dependencies.pri) -INCLUDEPATH *= $$PWD/.. - LIBS *= -l$$qtLibraryName(QmlJSTools) diff --git a/src/plugins/qmljstools/qmljstools.pro b/src/plugins/qmljstools/qmljstools.pro index 86426bb3b7..9313110d88 100644 --- a/src/plugins/qmljstools/qmljstools.pro +++ b/src/plugins/qmljstools/qmljstools.pro @@ -7,4 +7,69 @@ include(qmljstools_dependencies.pri) DEFINES += QT_NO_CAST_TO_ASCII DEFINES += QMLJSTOOLS_LIBRARY -include(qmljstools-lib.pri) +!dll { + DEFINES += QMLJSTOOLS_STATIC +} + +QT += script + +HEADERS += \ + $$PWD/qmljstoolsplugin.h \ + $$PWD/qmljstoolsconstants.h \ + $$PWD/qmljstoolssettings.h \ + $$PWD/qmljscodestylepreferencesfactory.h \ + $$PWD/qmljsmodelmanager.h \ + $$PWD/qmljsqtstylecodeformatter.h \ + $$PWD/qmljsrefactoringchanges.h \ + $$PWD/qmljsplugindumper.h \ + $$PWD/qmljsfunctionfilter.h \ + $$PWD/qmljslocatordata.h \ + $$PWD/qmljsindenter.h \ + $$PWD/qmljscodestylesettingspage.h \ + $$PWD/qmljsfindexportedcpptypes.h \ + $$PWD/qmljssemanticinfo.h \ + $$PWD/qmljstools_global.h \ + $$PWD/qmlconsolemanager.h \ + $$PWD/qmlconsoleitem.h \ + $$PWD/qmlconsoleitemmodel.h \ + $$PWD/qmlconsolepane.h \ + $$PWD/qmlconsoleview.h \ + $$PWD/qmlconsoleitemdelegate.h \ + $$PWD/qmlconsoleedit.h \ + $$PWD/qmljsinterpreter.h \ + $$PWD/qmlconsoleproxymodel.h + +SOURCES += \ + $$PWD/qmljstoolsplugin.cpp \ + $$PWD/qmljstoolssettings.cpp \ + $$PWD/qmljscodestylepreferencesfactory.cpp \ + $$PWD/qmljsmodelmanager.cpp \ + $$PWD/qmljsqtstylecodeformatter.cpp \ + $$PWD/qmljsrefactoringchanges.cpp \ + $$PWD/qmljsplugindumper.cpp \ + $$PWD/qmljsfunctionfilter.cpp \ + $$PWD/qmljslocatordata.cpp \ + $$PWD/qmljsindenter.cpp \ + $$PWD/qmljscodestylesettingspage.cpp \ + $$PWD/qmljsfindexportedcpptypes.cpp \ + $$PWD/qmljssemanticinfo.cpp \ + $$PWD/qmlconsolemanager.cpp \ + $$PWD/qmlconsoleitem.cpp \ + $$PWD/qmlconsoleitemmodel.cpp \ + $$PWD/qmlconsolepane.cpp \ + $$PWD/qmlconsoleview.cpp \ + $$PWD/qmlconsoleitemdelegate.cpp \ + $$PWD/qmlconsoleedit.cpp \ + $$PWD/qmljsinterpreter.cpp \ + $$PWD/qmlconsoleproxymodel.cpp + +RESOURCES += \ + qmljstools.qrc + +FORMS += \ + $$PWD/qmljscodestylesettingspage.ui + +equals(TEST, 1) { + SOURCES += \ + $$PWD/qmljstools_test.cpp +} diff --git a/src/plugins/qmljstools/qmljstools.qbs b/src/plugins/qmljstools/qmljstools.qbs index 2d5d58c64f..e1567641d1 100644 --- a/src/plugins/qmljstools/qmljstools.qbs +++ b/src/plugins/qmljstools/qmljstools.qbs @@ -1,6 +1,7 @@ import qbs.base 1.0 import "../QtcPlugin.qbs" as QtcPlugin +import "../../../qbs/defaults.js" as Defaults QtcPlugin { name: "QmlJSTools" @@ -18,16 +19,11 @@ QtcPlugin { Depends { name: "cpp" } cpp.defines: base.concat(["QT_NO_CAST_TO_ASCII"]) - cpp.includePaths: [ - "..", - "../../libs", - "../../libs/3rdparty", - buildDirectory - ] + cpp.includePaths: base.concat("../../libs/3rdparty") files: [ - "qmljsmodelmanager.cpp", - "qmljsmodelmanager.h", + "qmljscodestylepreferencesfactory.cpp", + "qmljscodestylepreferencesfactory.h", "qmljscodestylesettingspage.cpp", "qmljscodestylesettingspage.h", "qmljscodestylesettingspage.ui", @@ -40,6 +36,8 @@ QtcPlugin { "qmljslocatordata.cpp", "qmljslocatordata.h", "qmljsmodelmanager.cpp", + "qmljsmodelmanager.cpp", + "qmljsmodelmanager.h", "qmljsmodelmanager.h", "qmljsplugindumper.cpp", "qmljsplugindumper.h", @@ -47,21 +45,42 @@ QtcPlugin { "qmljsqtstylecodeformatter.h", "qmljsrefactoringchanges.cpp", "qmljsrefactoringchanges.h", + "qmljssemanticinfo.cpp", + "qmljssemanticinfo.h", "qmljstools_global.h", "qmljstoolsconstants.h", "qmljstoolsplugin.cpp", "qmljstoolsplugin.h", "qmljstoolssettings.cpp", "qmljstoolssettings.h", - "qmljscodestylepreferencesfactory.cpp", - "qmljscodestylepreferencesfactory.h", - "qmljssemanticinfo.cpp", - "qmljssemanticinfo.h" + "qmlconsolemanager.cpp", + "qmlconsolemanager.h", + "qmlconsoleitem.cpp", + "qmlconsoleitem.h", + "qmlcomsoleitemmodel.cpp", + "qmlconsoleitemmodel.h", + "qmlconsolepane.cpp", + "qmlconsolepane.h", + "qmlconsoleview.cpp", + "qmlconsoleview.h", + "qmlconsoleitemdelegate.cpp", + "qmlconsoleitemdelegate.h", + "qmlconsoleedit.cpp", + "qmlconsoleedit.h", + "qmljsinterpreter.cpp", + "qmljsinterpreter.h", + "qmljsconsoleproxymodel.cpp", + "qmljsconsoleproxymodel.h", + "qmljstools.qrc" ] + Group { + condition: Defaults.testsEnabled(qbs) + files: ["qmljstools_test.cpp"] + } + ProductModule { Depends { name: "CppTools" } Depends { name: "QmlDebug" } } } - diff --git a/src/plugins/qmljstools/qmljstools.qrc b/src/plugins/qmljstools/qmljstools.qrc new file mode 100644 index 0000000000..9e396a3995 --- /dev/null +++ b/src/plugins/qmljstools/qmljstools.qrc @@ -0,0 +1,10 @@ +<RCC> + <qresource prefix="/qmljstools"> + <file>images/prompt.png</file> + <file>images/collapse.png</file> + <file>images/warning.png</file> + <file>images/log.png</file> + <file>images/expand.png</file> + <file>images/error.png</file> + </qresource> +</RCC> diff --git a/src/plugins/qmljstools/qmljstoolsplugin.cpp b/src/plugins/qmljstools/qmljstoolsplugin.cpp index 69bf5eef8d..fb27af25ad 100644 --- a/src/plugins/qmljstools/qmljstoolsplugin.cpp +++ b/src/plugins/qmljstools/qmljstoolsplugin.cpp @@ -34,6 +34,7 @@ #include "qmljscodestylesettingspage.h" #include "qmljstoolsconstants.h" #include "qmljstoolssettings.h" +#include "qmlconsolemanager.h" #include <extensionsystem/pluginmanager.h> @@ -51,6 +52,7 @@ #include <QSettings> #include <QMenu> +using namespace QmlJSTools; using namespace QmlJSTools::Internal; enum { debug = 0 }; @@ -67,6 +69,7 @@ QmlJSToolsPlugin::~QmlJSToolsPlugin() { m_instance = 0; m_modelManager = 0; // deleted automatically + m_consoleManager = 0; // deleted automatically } bool QmlJSToolsPlugin::initialize(const QStringList &arguments, QString *error) @@ -78,6 +81,8 @@ bool QmlJSToolsPlugin::initialize(const QStringList &arguments, QString *error) // Objects m_modelManager = new ModelManager(this); + m_consoleManager = new QmlConsoleManager(this); + // Core::VCSManager *vcsManager = core->vcsManager(); // Core::DocumentManager *fileManager = core->fileManager(); // connect(vcsManager, SIGNAL(repositoryChanged(QString)), diff --git a/src/plugins/qmljstools/qmljstoolsplugin.h b/src/plugins/qmljstools/qmljstoolsplugin.h index df6297e628..e1ca0036a7 100644 --- a/src/plugins/qmljstools/qmljstoolsplugin.h +++ b/src/plugins/qmljstools/qmljstoolsplugin.h @@ -45,6 +45,7 @@ QT_END_NAMESPACE namespace QmlJSTools { class QmlJSToolsSettings; +class QmlConsoleManager; namespace Internal { @@ -76,6 +77,7 @@ private slots: private: ModelManager *m_modelManager; + QmlConsoleManager *m_consoleManager; QmlJSToolsSettings *m_settings; QAction *m_resetCodeModelAction; diff --git a/src/plugins/qmljstools/qmljstoolssettings.cpp b/src/plugins/qmljstools/qmljstoolssettings.cpp index b602db0544..24be181d7c 100644 --- a/src/plugins/qmljstools/qmljstoolssettings.cpp +++ b/src/plugins/qmljstools/qmljstoolssettings.cpp @@ -42,53 +42,40 @@ #include <QSettings> -static const char *idKey = "QmlJSGlobal"; - -using namespace QmlJSTools; -using TextEditor::TabSettings; +using namespace TextEditor; namespace QmlJSTools { -namespace Internal { -class QmlJSToolsSettingsPrivate -{ -public: - TextEditor::SimpleCodeStylePreferences *m_globalCodeStyle; -}; +const char idKey[] = "QmlJSGlobal"; -} // namespace Internal -} // namespace QmlJSTools - -QmlJSToolsSettings *QmlJSToolsSettings::m_instance = 0; +static TextEditor::SimpleCodeStylePreferences *m_globalCodeStyle = 0; QmlJSToolsSettings::QmlJSToolsSettings(QObject *parent) : QObject(parent) - , d(new Internal::QmlJSToolsSettingsPrivate) { - QTC_ASSERT(!m_instance, return); - m_instance = this; + QTC_ASSERT(!m_globalCodeStyle, return); - TextEditor::TextEditorSettings *textEditorSettings = TextEditor::TextEditorSettings::instance(); + TextEditorSettings *textEditorSettings = TextEditorSettings::instance(); // code style factory - TextEditor::ICodeStylePreferencesFactory *factory = new QmlJSTools::QmlJSCodeStylePreferencesFactory(); + ICodeStylePreferencesFactory *factory = new QmlJSCodeStylePreferencesFactory(); textEditorSettings->registerCodeStyleFactory(factory); // code style pool - TextEditor::CodeStylePool *pool = new TextEditor::CodeStylePool(factory, this); + CodeStylePool *pool = new CodeStylePool(factory, this); textEditorSettings->registerCodeStylePool(Constants::QML_JS_SETTINGS_ID, pool); // global code style settings - d->m_globalCodeStyle = new TextEditor::SimpleCodeStylePreferences(this); - d->m_globalCodeStyle->setDelegatingPool(pool); - d->m_globalCodeStyle->setDisplayName(tr("Global", "Settings")); - d->m_globalCodeStyle->setId(idKey); - pool->addCodeStyle(d->m_globalCodeStyle); - textEditorSettings->registerCodeStyle(QmlJSTools::Constants::QML_JS_SETTINGS_ID, d->m_globalCodeStyle); + m_globalCodeStyle = new SimpleCodeStylePreferences(this); + m_globalCodeStyle->setDelegatingPool(pool); + m_globalCodeStyle->setDisplayName(tr("Global", "Settings")); + m_globalCodeStyle->setId(idKey); + pool->addCodeStyle(m_globalCodeStyle); + textEditorSettings->registerCodeStyle(QmlJSTools::Constants::QML_JS_SETTINGS_ID, m_globalCodeStyle); // built-in settings // Qt style - TextEditor::SimpleCodeStylePreferences *qtCodeStyle = new TextEditor::SimpleCodeStylePreferences(); + SimpleCodeStylePreferences *qtCodeStyle = new SimpleCodeStylePreferences(); qtCodeStyle->setId(QLatin1String("qt")); qtCodeStyle->setDisplayName(tr("Qt")); qtCodeStyle->setReadOnly(true); @@ -101,13 +88,13 @@ QmlJSToolsSettings::QmlJSToolsSettings(QObject *parent) pool->addCodeStyle(qtCodeStyle); // default delegate for global preferences - d->m_globalCodeStyle->setCurrentDelegate(qtCodeStyle); + m_globalCodeStyle->setCurrentDelegate(qtCodeStyle); pool->loadCustomCodeStyles(); // load global settings (after built-in settings are added to the pool) QSettings *s = Core::ICore::settings(); - d->m_globalCodeStyle->fromSettings(QmlJSTools::Constants::QML_JS_SETTINGS_ID, s); + m_globalCodeStyle->fromSettings(QmlJSTools::Constants::QML_JS_SETTINGS_ID, s); // legacy handling start (Qt Creator Version < 2.4) const bool legacyTransformed = @@ -136,13 +123,13 @@ QmlJSToolsSettings::QmlJSToolsSettings(QObject *parent) } // create custom code style out of old settings - TextEditor::ICodeStylePreferences *oldCreator = pool->createCodeStyle( + ICodeStylePreferences *oldCreator = pool->createCodeStyle( QLatin1String("legacy"), legacyTabSettings, QVariant(), tr("Old Creator")); // change the current delegate and save - d->m_globalCodeStyle->setCurrentDelegate(oldCreator); - d->m_globalCodeStyle->toSettings(QmlJSTools::Constants::QML_JS_SETTINGS_ID, s); + m_globalCodeStyle->setCurrentDelegate(oldCreator); + m_globalCodeStyle->toSettings(QmlJSTools::Constants::QML_JS_SETTINGS_ID, s); } // mark old settings as transformed s->setValue(QLatin1String("QmlJSTabPreferences/LegacyTransformed"), true); @@ -163,19 +150,13 @@ QmlJSToolsSettings::QmlJSToolsSettings(QObject *parent) QmlJSToolsSettings::~QmlJSToolsSettings() { - delete d; - - m_instance = 0; -} - -QmlJSToolsSettings *QmlJSToolsSettings::instance() -{ - return m_instance; + delete m_globalCodeStyle; + m_globalCodeStyle = 0; } -TextEditor::SimpleCodeStylePreferences *QmlJSToolsSettings::qmlJSCodeStyle() const +SimpleCodeStylePreferences *QmlJSToolsSettings::globalCodeStyle() { - return d->m_globalCodeStyle; + return m_globalCodeStyle; } - +} // namespace QmlJSTools diff --git a/src/plugins/qmljstools/qmljstoolssettings.h b/src/plugins/qmljstools/qmljstoolssettings.h index ffd1589887..4118b8df85 100644 --- a/src/plugins/qmljstools/qmljstoolssettings.h +++ b/src/plugins/qmljstools/qmljstoolssettings.h @@ -34,18 +34,9 @@ #include <QObject> -namespace TextEditor -{ -class SimpleCodeStylePreferences; -} - -namespace QmlJSTools -{ +namespace TextEditor { class SimpleCodeStylePreferences; } -namespace Internal -{ -class QmlJSToolsSettingsPrivate; -} +namespace QmlJSTools { /** * This class provides a central place for cpp tools settings. @@ -58,14 +49,7 @@ public: explicit QmlJSToolsSettings(QObject *parent); ~QmlJSToolsSettings(); - static QmlJSToolsSettings *instance(); - - TextEditor::SimpleCodeStylePreferences *qmlJSCodeStyle() const; - -private: - Internal::QmlJSToolsSettingsPrivate *d; - - static QmlJSToolsSettings *m_instance; + static TextEditor::SimpleCodeStylePreferences *globalCodeStyle(); }; } // namespace QmlJSTools |