diff options
author | MohammadHossein Qanbari <[email protected]> | 2024-08-23 17:12:51 +0200 |
---|---|---|
committer | MohammadHossein Qanbari <[email protected]> | 2024-09-02 22:46:58 +0200 |
commit | 8330154be6401569450b97512b6718b0f31d6eaf (patch) | |
tree | fc7736297b321a2592dcaf59f7e7e1edc7cbe8fe /examples/quick | |
parent | 2f9e1e55766af3123189ccddbfa63139ecf53fec (diff) |
QML Previewer Example: Add Error List and Line Numbers
Implement LineNumberArea to display line numbers, based on the Code
Editor Example documentation. Introduce QListView with ErrorListModel
to show errors and warnings. Double-clicking an error in the list moves
the code editor's cursor to the corresponding position.
Update shortcut functionality to work only on platforms where the
feature is available. Related code has been modified accordingly.
Fixes: QTBUG-128227
Pick-to: 6.8
Change-Id: Icb66280a5360b015280afc756f8a827247a2ebaf
Reviewed-by: Jan Arve Sæther <[email protected]>
Diffstat (limited to 'examples/quick')
14 files changed, 453 insertions, 40 deletions
diff --git a/examples/quick/quickwidgets/qmlpreviewer/CMakeLists.txt b/examples/quick/quickwidgets/qmlpreviewer/CMakeLists.txt index 5361679456..f196019de6 100644 --- a/examples/quick/quickwidgets/qmlpreviewer/CMakeLists.txt +++ b/examples/quick/quickwidgets/qmlpreviewer/CMakeLists.txt @@ -12,11 +12,15 @@ qt_standard_project_setup(REQUIRES 6.8) qt_add_executable(${PROJECT_NAME} WIN32 MACOSX_BUNDLE main.cpp - widgets/mainwindow.h widgets/mainwindow.cpp - widgets/editorwidget.h widgets/editorwidget.cpp - widgets/patheditwidget.h widgets/patheditwidget.cpp + models/errorlistmodel.h models/errorlistmodel.cpp states/statecontroller.h states/statecontroller.cpp utility/syntaxhighlighter.h utility/syntaxhighlighter.cpp + widgets/codeeditor.h widgets/codeeditor.cpp + widgets/editorwidget.h widgets/editorwidget.cpp + widgets/linenumberarea.h widgets/linenumberarea.cpp + widgets/mainwindow.h widgets/mainwindow.cpp + widgets/patheditwidget.h widgets/patheditwidget.cpp + widgets/previewwidget.h widgets/previewwidget.cpp ) include(resources.cmake) diff --git a/examples/quick/quickwidgets/qmlpreviewer/models/errorlistmodel.cpp b/examples/quick/quickwidgets/qmlpreviewer/models/errorlistmodel.cpp new file mode 100644 index 0000000000..59b65585ce --- /dev/null +++ b/examples/quick/quickwidgets/qmlpreviewer/models/errorlistmodel.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "errorlistmodel.h" + +#include <QQmlError> + +ErrorListModel::ErrorListModel(QObject *parent) + : QAbstractListModel{parent} +{} + +bool ErrorListModel::isIndexValid(const QModelIndex &index) const +{ + return index.isValid() && (0 <= index.row()) && (index.row() < rowCount()); +} + +void ErrorListModel::setErrorList(const QList<QQmlError> &errorList) +{ + beginResetModel(); + m_errorList = errorList; + endResetModel(); +} + +void ErrorListModel::selectIndex(const QModelIndex &index) +{ + if (!isIndexValid(index)) + return; + const QQmlError &error = m_errorList.at(index.row()); + emit errorPositionSelected(error.line(), error.column()); +} + +int ErrorListModel::rowCount(const QModelIndex &parent) const +{ + return m_errorList.size(); +} + +QVariant ErrorListModel::data(const QModelIndex &index, int role) const +{ + if ((role != Qt::DisplayRole) && (role != Qt::EditRole)) + return QVariant{}; + + if (!isIndexValid(index)) + return QVariant{}; + + return m_errorList.at(index.row()).toString(); +} diff --git a/examples/quick/quickwidgets/qmlpreviewer/models/errorlistmodel.h b/examples/quick/quickwidgets/qmlpreviewer/models/errorlistmodel.h new file mode 100644 index 0000000000..b2970d5e96 --- /dev/null +++ b/examples/quick/quickwidgets/qmlpreviewer/models/errorlistmodel.h @@ -0,0 +1,37 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef ERRORLISTMODEL_H +#define ERRORLISTMODEL_H + +#include <QAbstractListModel> + +class QQmlError; + +class ErrorListModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit ErrorListModel(QObject *parent = nullptr); + + void setErrorList(const QList<QQmlError> &errorList); + +private: + bool isIndexValid(const QModelIndex &index) const; + + // QAbstractItemModel interface + int rowCount(const QModelIndex &parent = QModelIndex{}) const final; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const final; + +signals: + void errorPositionSelected(int line, int column); + +public slots: + void selectIndex(const QModelIndex &index); + +private: + QList<QQmlError> m_errorList; +}; + +#endif // ERRORLISTMODEL_H diff --git a/examples/quick/quickwidgets/qmlpreviewer/utility/syntaxhighlighter.cpp b/examples/quick/quickwidgets/qmlpreviewer/utility/syntaxhighlighter.cpp index 190a6c5889..248bf3f8be 100644 --- a/examples/quick/quickwidgets/qmlpreviewer/utility/syntaxhighlighter.cpp +++ b/examples/quick/quickwidgets/qmlpreviewer/utility/syntaxhighlighter.cpp @@ -15,7 +15,7 @@ void SyntaxHighlighter::highlightBlock(const QString &text) setFormat(0, text.length(), QColor{214, 207 , 154}); // import keyword - QRegularExpression regex{"^\\bimport\\b"}; + QRegularExpression regex{"^\\bimport\\b||^\\s*property\\b"}; QRegularExpressionMatchIterator it = regex.globalMatchView(text); while (it.hasNext()) { QRegularExpressionMatch match = it.next(); diff --git a/examples/quick/quickwidgets/qmlpreviewer/widgets/codeeditor.cpp b/examples/quick/quickwidgets/qmlpreviewer/widgets/codeeditor.cpp new file mode 100644 index 0000000000..fa505df115 --- /dev/null +++ b/examples/quick/quickwidgets/qmlpreviewer/widgets/codeeditor.cpp @@ -0,0 +1,105 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "codeeditor.h" +#include "linenumberarea.h" + +#include <QPainter> +#include <QTextBlock> + +CodeEditor::CodeEditor(QWidget *parent) + : QPlainTextEdit{parent} + , m_lineNumberArea{new LineNumberArea{this}} +{ + setupConnections(); + updateLineNumberAreaWidth(); + highlightCurrentLine(); +} + +void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event) +{ + const QRect eventRect = event->rect(); + + QPainter painter{m_lineNumberArea}; + painter.fillRect(eventRect, palette().color(QPalette::AlternateBase)); + + QTextBlock block = firstVisibleBlock(); + int blockNumber = block.blockNumber(); + qreal top = blockBoundingGeometry(block).translated(contentOffset()).top(); + qreal bottom = top + blockBoundingRect(block).height(); + + while (block.isVisible() && (top <= eventRect.bottom()) && (blockNumber < blockCount())) { + if (block.isVisible() && (bottom >= eventRect.top())) { + const QString number = QString::number(blockNumber + 1); + painter.setPen(palette().color(QPalette::Text)); + painter.drawText(0, qRound(top), m_lineNumberArea->width() - 5, fontMetrics().height(), + Qt::AlignRight, number); + } + + block = block.next(); + top = bottom; + bottom = top + blockBoundingRect(block).height(); + ++blockNumber; + } +} + +int CodeEditor::lineNumberAreaWidth() const +{ + int digits = 1; + int max = qMax(1, blockCount()); + while (max >= 10) { + max /= 10; + ++digits; + } + + const int space = 9 + fontMetrics().horizontalAdvance('9') * digits; + return space; +} + +void CodeEditor::setupConnections() +{ + connect(this, &CodeEditor::blockCountChanged, this, &CodeEditor::updateLineNumberAreaWidth); + connect(this, &CodeEditor::updateRequest, this, &CodeEditor::updateLineNumberArea); + connect(this, &CodeEditor::cursorPositionChanged, this, &CodeEditor::highlightCurrentLine); +} + +void CodeEditor::resizeEvent(QResizeEvent *event) +{ + QPlainTextEdit::resizeEvent(event); + + const QRect rect = contentsRect(); + m_lineNumberArea->setGeometry(rect.left(), rect.top(), lineNumberAreaWidth(), rect.height()); +} + +void CodeEditor::updateLineNumberArea(const QRect &rect, int dy) +{ + if (dy) + m_lineNumberArea->scroll(0, dy); + else + m_lineNumberArea->update(0, rect.y(), m_lineNumberArea->width(), rect.height()); + + if (rect.contains(viewport()->rect())) + updateLineNumberAreaWidth(); +} + +void CodeEditor::updateLineNumberAreaWidth() +{ + setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); +} + +void CodeEditor::highlightCurrentLine() +{ + QList<QTextEdit::ExtraSelection> extraSelections; + + if (!isReadOnly()) { + QTextEdit::ExtraSelection selection; + selection.format.setBackground(palette().color(QPalette::AlternateBase)); + selection.format.setProperty(QTextFormat::FullWidthSelection, true); + selection.cursor = textCursor(); + selection.cursor.clearSelection(); + + extraSelections.append(selection); + } + + setExtraSelections(extraSelections); +} diff --git a/examples/quick/quickwidgets/qmlpreviewer/widgets/codeeditor.h b/examples/quick/quickwidgets/qmlpreviewer/widgets/codeeditor.h new file mode 100644 index 0000000000..a952c29378 --- /dev/null +++ b/examples/quick/quickwidgets/qmlpreviewer/widgets/codeeditor.h @@ -0,0 +1,34 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef CODEEDITOR_H +#define CODEEDITOR_H + +#include <QPlainTextEdit> + +class LineNumberArea; + +class CodeEditor : public QPlainTextEdit +{ + Q_OBJECT + +public: + CodeEditor(QWidget *parent = nullptr); + + void lineNumberAreaPaintEvent(QPaintEvent *event); + int lineNumberAreaWidth() const; + +private: + void setupConnections(); + void resizeEvent(QResizeEvent *event) final; + +private slots: + void updateLineNumberArea(const QRect &rect, int dy); + void updateLineNumberAreaWidth(); + void highlightCurrentLine(); + +private: + LineNumberArea *m_lineNumberArea = nullptr; +}; + +#endif // CODEEDITOR_H diff --git a/examples/quick/quickwidgets/qmlpreviewer/widgets/editorwidget.cpp b/examples/quick/quickwidgets/qmlpreviewer/widgets/editorwidget.cpp index f35e6c0c2d..c77fd5fa70 100644 --- a/examples/quick/quickwidgets/qmlpreviewer/widgets/editorwidget.cpp +++ b/examples/quick/quickwidgets/qmlpreviewer/widgets/editorwidget.cpp @@ -2,13 +2,13 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause #include "editorwidget.h" +#include "codeeditor.h" #include "patheditwidget.h" #include "../states/statecontroller.h" #include "../utility/syntaxhighlighter.h" #include <QFile> #include <QMessageBox> -#include <QPlainTextEdit> #include <QPushButton> #include <QVBoxLayout> @@ -34,7 +34,7 @@ static inline QByteArray loadFromFile(const QString &filePath) EditorWidget::EditorWidget(QWidget *parent) : QWidget{parent} , m_pathEdit{new PathEditWidget} - , m_editor{new QPlainTextEdit} + , m_editor{new CodeEditor} , m_saveButton{new QPushButton} , m_reloadButton{new QPushButton} , m_closeButton{new QPushButton} @@ -146,6 +146,19 @@ void EditorWidget::reloadFile() m_mutex.unlock(); } +void EditorWidget::moveCursorTo(int line, int column) +{ + if (line < 1 || column < 1) + return; + + QTextCursor cursor = m_editor->textCursor(); + cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, line - 1); + cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, column - 1); + m_editor->setTextCursor(cursor); + m_editor->setFocus(); +} + void EditorWidget::initUI() { QHBoxLayout *actionsLayout = new QHBoxLayout; @@ -160,6 +173,7 @@ void EditorWidget::initUI() layout->setContentsMargins(0,0,0,0); setLayout(layout); + m_editor->setCursorWidth(2); m_editor->setPlaceholderText(tr("Write code or open a file")); m_saveButton->setText(tr("Save")); m_saveButton->setEnabled(false); diff --git a/examples/quick/quickwidgets/qmlpreviewer/widgets/editorwidget.h b/examples/quick/quickwidgets/qmlpreviewer/widgets/editorwidget.h index 46c5730b5c..939f008dec 100644 --- a/examples/quick/quickwidgets/qmlpreviewer/widgets/editorwidget.h +++ b/examples/quick/quickwidgets/qmlpreviewer/widgets/editorwidget.h @@ -24,6 +24,7 @@ public slots: void saveFile(); void closeFile(); void reloadFile(); + void moveCursorTo(int line, int column); private: void initUI(); diff --git a/examples/quick/quickwidgets/qmlpreviewer/widgets/linenumberarea.cpp b/examples/quick/quickwidgets/qmlpreviewer/widgets/linenumberarea.cpp new file mode 100644 index 0000000000..fba36d2b2e --- /dev/null +++ b/examples/quick/quickwidgets/qmlpreviewer/widgets/linenumberarea.cpp @@ -0,0 +1,20 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "linenumberarea.h" +#include "codeeditor.h" + +LineNumberArea::LineNumberArea(CodeEditor *editor) + : QWidget{editor} + , m_codeEditor{editor} +{} + +QSize LineNumberArea::sizeHint() const +{ + return QSize{m_codeEditor->lineNumberAreaWidth(), 0}; +} + +void LineNumberArea::paintEvent(QPaintEvent *event) +{ + m_codeEditor->lineNumberAreaPaintEvent(event); +} diff --git a/examples/quick/quickwidgets/qmlpreviewer/widgets/linenumberarea.h b/examples/quick/quickwidgets/qmlpreviewer/widgets/linenumberarea.h new file mode 100644 index 0000000000..2ba6fb9d58 --- /dev/null +++ b/examples/quick/quickwidgets/qmlpreviewer/widgets/linenumberarea.h @@ -0,0 +1,27 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef LINENUMBERAREA_H +#define LINENUMBERAREA_H + +#include <QWidget> + +class CodeEditor; + +class LineNumberArea : public QWidget +{ + Q_OBJECT + +public: + explicit LineNumberArea(CodeEditor *editor); + + QSize sizeHint() const final; + +private: + void paintEvent(QPaintEvent *event) final; + +private: + CodeEditor *m_codeEditor = nullptr; +}; + +#endif // LINENUMBERAREA_H diff --git a/examples/quick/quickwidgets/qmlpreviewer/widgets/mainwindow.cpp b/examples/quick/quickwidgets/qmlpreviewer/widgets/mainwindow.cpp index eb27720280..339379e127 100644 --- a/examples/quick/quickwidgets/qmlpreviewer/widgets/mainwindow.cpp +++ b/examples/quick/quickwidgets/qmlpreviewer/widgets/mainwindow.cpp @@ -3,27 +3,19 @@ #include "mainwindow.h" #include "editorwidget.h" +#include "previewwidget.h" #include "../states/statecontroller.h" +#include <QCloseEvent> #include <QFileSystemWatcher> #include <QLayout> #include <QMenuBar> #include <QMessageBox> -#include <QQmlEngine> -#include <QQuickWidget> - -namespace { -static constexpr auto QUIT_SHORTCUT = QKeySequence::Quit; -static constexpr auto OPEN_SHORTCUT = QKeySequence::Open; -static constexpr auto SAVE_SHORTCUT = QKeySequence::Save; -static constexpr auto CLOSE_SHORTCUT = QKeySequence::Close; -static constexpr auto RELOAD_SHORTCUT = Qt::CTRL | Qt::Key_R; -} MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , m_editorWidget{new EditorWidget} - , m_previewWidget{new QQuickWidget} + , m_previewWidget{new PreviewWidget} , m_fileWatcher{new QFileSystemWatcher} { setWindowIcon(QIcon(":/resources/logo.png")); @@ -51,8 +43,6 @@ void MainWindow::initUI() centralWidget->setLayout(horizontalLayout); horizontalLayout->addWidget(m_editorWidget, 1); - - m_previewWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); horizontalLayout->addWidget(m_previewWidget, 1); } @@ -61,21 +51,24 @@ void MainWindow::initMenuBar() QMenu *fileMenu = menuBar()->addMenu(tr("&File")); m_openAction = fileMenu->addAction(tr("&Open")); - m_openAction->setShortcut(OPEN_SHORTCUT); m_saveAction = fileMenu->addAction(tr("&Save")); - m_saveAction->setShortcut(SAVE_SHORTCUT); m_saveAction->setEnabled(false); m_closeAction = fileMenu->addAction(tr("&Close")); - m_closeAction->setShortcut(CLOSE_SHORTCUT); m_closeAction->setEnabled(false); m_reloadAction = fileMenu->addAction(tr("&Reload")); - m_reloadAction->setShortcut(::RELOAD_SHORTCUT); m_reloadAction->setEnabled(false); fileMenu->addSeparator(); - QAction *quitAction = fileMenu->addAction(tr("&Quit")); - quitAction->setShortcut(QUIT_SHORTCUT); + m_quitAction = fileMenu->addAction(tr("&Quit")); + +#if QT_CONFIG(shortcut) + m_openAction->setShortcut(QKeySequence::Open); + m_saveAction->setShortcut(QKeySequence::Save); + m_closeAction->setShortcut(QKeySequence::Close); + m_reloadAction->setShortcut(Qt::CTRL | Qt::Key_R); + m_quitAction->setShortcut(QKeySequence::Quit); +#endif } void MainWindow::setupConnections() @@ -84,6 +77,8 @@ void MainWindow::setupConnections() &MainWindow::onAppStateChanged); connect(m_fileWatcher, &QFileSystemWatcher::fileChanged, this, &MainWindow::onFileChanged); connect(menuBar(), &QMenuBar::triggered, this, &MainWindow::onMenuBarTriggered); + connect(m_previewWidget, &PreviewWidget::errorPositionSelected, m_editorWidget, + &EditorWidget::moveCursorTo); } void MainWindow::closeEvent(QCloseEvent *event) @@ -112,11 +107,10 @@ void MainWindow::onAppStateChanged(int oldState, int newState) { switch (newState) { case StateController::InitState: - if (!m_previewWidget->source().isEmpty()) { - m_previewWidget->engine()->clearComponentCache(); + if (!m_previewWidget->sourcePath().isEmpty()) { if (const QStringList files = m_fileWatcher->files(); !files.isEmpty()) m_fileWatcher->removePaths(files); - m_previewWidget->setSource(QUrl{}); + m_previewWidget->setSourcePath(QString{}); } m_saveAction->setEnabled(false); m_closeAction->setEnabled(false); @@ -124,11 +118,10 @@ void MainWindow::onAppStateChanged(int oldState, int newState) break; case StateController::OpenState: - m_previewWidget->engine()->clearComponentCache(); if (const QStringList files = m_fileWatcher->files(); !files.isEmpty()) m_fileWatcher->removePaths(files); m_fileWatcher->addPath(StateController::instance()->filePath()); - m_previewWidget->setSource(QUrl::fromLocalFile(StateController::instance()->filePath())); + m_previewWidget->setSourcePath(StateController::instance()->filePath()); m_saveAction->setEnabled(false); m_closeAction->setEnabled(true); m_reloadAction->setEnabled(false); @@ -169,22 +162,20 @@ void MainWindow::onFileChanged(const QString &path) } m_editorWidget->updateEditor(); - m_previewWidget->engine()->clearComponentCache(); - m_previewWidget->setSource(QUrl::fromLocalFile(path)); + m_previewWidget->setSourcePath(path); stateController->setDirty(false); } void MainWindow::onMenuBarTriggered(QAction *action) { - const QKeySequence shortcut = action->shortcut(); - if (shortcut == OPEN_SHORTCUT) + if (action == m_openAction) m_editorWidget->openFile(); - else if (shortcut == SAVE_SHORTCUT) + else if (action == m_saveAction) m_editorWidget->saveFile(); - else if (shortcut == CLOSE_SHORTCUT) + else if (action == m_closeAction) m_editorWidget->closeFile(); - else if (shortcut == RELOAD_SHORTCUT) + else if (action == m_reloadAction) m_editorWidget->reloadFile(); - else if (shortcut == QUIT_SHORTCUT) + else if (action == m_quitAction) QCoreApplication::quit(); } diff --git a/examples/quick/quickwidgets/qmlpreviewer/widgets/mainwindow.h b/examples/quick/quickwidgets/qmlpreviewer/widgets/mainwindow.h index 89cbb6c332..22ce63d34b 100644 --- a/examples/quick/quickwidgets/qmlpreviewer/widgets/mainwindow.h +++ b/examples/quick/quickwidgets/qmlpreviewer/widgets/mainwindow.h @@ -6,8 +6,8 @@ #include <QMainWindow> +class PreviewWidget; class EditorWidget; -class QQuickWidget; class QFileSystemWatcher; class MainWindow : public QMainWindow @@ -31,11 +31,12 @@ private slots: private: EditorWidget *m_editorWidget = nullptr; - QQuickWidget *m_previewWidget = nullptr; + PreviewWidget *m_previewWidget = nullptr; QFileSystemWatcher *m_fileWatcher = nullptr; QAction *m_openAction = nullptr; QAction *m_saveAction = nullptr; QAction *m_closeAction = nullptr; QAction *m_reloadAction = nullptr; + QAction *m_quitAction = nullptr; }; #endif // MAINWINDOW_H diff --git a/examples/quick/quickwidgets/qmlpreviewer/widgets/previewwidget.cpp b/examples/quick/quickwidgets/qmlpreviewer/widgets/previewwidget.cpp new file mode 100644 index 0000000000..c75b07b37a --- /dev/null +++ b/examples/quick/quickwidgets/qmlpreviewer/widgets/previewwidget.cpp @@ -0,0 +1,94 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "previewwidget.h" +#include "../states/statecontroller.h" + +#include <QListView> +#include <QQmlEngine> +#include <QQuickWidget> +#include <QSplitter> +#include <QVBoxLayout> + +PreviewWidget::PreviewWidget(QWidget *parent) + : QWidget{parent} + , m_errorListModel{this} + , m_errorListView{new QListView} + , m_quickWidget{new QQuickWidget} +{ + initUI(); + setupConnections(); +} + +QString PreviewWidget::sourcePath() const +{ + return m_quickWidget->source().toString(); +} + +void PreviewWidget::setSourcePath(const QString &path) +{ + m_quickWidget->engine()->clearComponentCache(); + m_quickWidget->setSource(QUrl::fromLocalFile(path)); +} + +void PreviewWidget::initUI() +{ + m_errorListView->setModel(&m_errorListModel); + m_errorListView->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_errorListView->setWordWrap(true); + m_errorListView->setSpacing(4); + + m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + + QSizePolicy sizePolicy = m_quickWidget->sizePolicy(); + sizePolicy.setVerticalStretch(1); + m_quickWidget->setSizePolicy(sizePolicy); + + QSplitter *splitter = new QSplitter{this}; + splitter->setOrientation(Qt::Vertical); + splitter->addWidget(m_quickWidget); + splitter->addWidget(m_errorListView); + + QVBoxLayout *layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(splitter); + setLayout(layout); +} + +void PreviewWidget::setupConnections() +{ + connect(StateController::instance(), &StateController::stateChanged, this, + &PreviewWidget::onAppStateChanged); + connect(m_quickWidget, &QQuickWidget::statusChanged, this, + &PreviewWidget::onQuickWidetStatusChanged); + connect(m_errorListView, &QAbstractItemView::doubleClicked, &m_errorListModel, + &ErrorListModel::selectIndex); + connect(&m_errorListModel, &ErrorListModel::errorPositionSelected, this, + &PreviewWidget::errorPositionSelected); +} + +void PreviewWidget::onAppStateChanged(int oldState, int newState) +{ + Q_UNUSED(oldState); + + switch (newState) { + case StateController::InitState: + m_errorListModel.setErrorList({}); + break; + + default: + break; + } +} + +void PreviewWidget::onQuickWidetStatusChanged(int status) +{ + switch (status) { + case QQuickWidget::Error: + m_errorListModel.setErrorList(m_quickWidget->errors()); + break; + default: + m_errorListModel.setErrorList({}); + break; + } +} diff --git a/examples/quick/quickwidgets/qmlpreviewer/widgets/previewwidget.h b/examples/quick/quickwidgets/qmlpreviewer/widgets/previewwidget.h new file mode 100644 index 0000000000..16b739a900 --- /dev/null +++ b/examples/quick/quickwidgets/qmlpreviewer/widgets/previewwidget.h @@ -0,0 +1,39 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef PREVIEWWIDGET_H +#define PREVIEWWIDGET_H + +#include "../models/errorlistmodel.h" +#include <QWidget> + +class QListView; +class QQuickWidget; + +class PreviewWidget : public QWidget +{ + Q_OBJECT +public: + explicit PreviewWidget(QWidget *parent = nullptr); + + QString sourcePath() const; + void setSourcePath(const QString &path); + +private: + void initUI(); + void setupConnections(); + +signals: + void errorPositionSelected(int line, int column); + +private slots: + void onAppStateChanged(int oldState, int newState); + void onQuickWidetStatusChanged(int status); + +private: + ErrorListModel m_errorListModel; + QListView *m_errorListView = nullptr; + QQuickWidget *m_quickWidget = nullptr; +}; + +#endif // PREVIEWWIDGET_H |