Merge remote-tracking branch 'origin/6.0'
Conflicts: cmake/QtCreatorIDEBranding.cmake qbs/modules/qtc/qtc.qbs qtcreator_ide_branding.pri Change-Id: I366a1a0e378811dfc9b4e6f42ec96426dbb15356
2
.github/workflows/build_cmake.yml
vendored
@@ -9,7 +9,7 @@ env:
|
||||
CMAKE_VERSION: 3.21.1
|
||||
NINJA_VERSION: 1.10.2
|
||||
BUILD_TYPE: Release
|
||||
CCACHE_VERSION: 4.4
|
||||
CCACHE_VERSION: 4.5
|
||||
QT_MIRRORS: download.qt.io;mirrors.ocf.berkeley.edu/qt;ftp.fau.de/qtproject;mirror.bit.edu.cn/qtproject
|
||||
|
||||
jobs:
|
||||
|
BIN
doc/qtcreator/images/qtcreator-autotests-options-ctest.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 8.2 KiB |
@@ -38,13 +38,20 @@
|
||||
build system and uses it or even the build system as such to execute the
|
||||
respective tests.
|
||||
|
||||
\QC integrates the \l{Qt Test} framework,
|
||||
\l{https://github.com/google/googletest}{Google C++ Testing Framework},
|
||||
\l{https://www.boost.org/doc/libs/1_70_0/libs/test/doc/html/index.html}
|
||||
{Boost.Test}, and \l{https://github.com/catchorg/Catch2}
|
||||
{Catch2 test framework} for unit testing applications and libraries.
|
||||
\QC integrates the following testing frameworks for unit testing
|
||||
applications and libraries:
|
||||
|
||||
\list
|
||||
\li \l{https://www.boost.org/doc/libs/1_70_0/libs/test/doc/html/index.html}
|
||||
{Boost.Test}
|
||||
\li \l{https://github.com/catchorg/Catch2}{Catch2 test framework}
|
||||
\li \l{https://github.com/google/googletest}{Google C++ Testing Framework}
|
||||
\li \l{Qt Test} framework
|
||||
\endlist
|
||||
|
||||
Additional build system based support is provided for
|
||||
\l{https://cmake.org/cmake/help/latest/manual/ctest.1.html}{CTest}.
|
||||
|
||||
You can use \QC to create, build, and run code based tests for your
|
||||
projects.
|
||||
|
||||
@@ -332,16 +339,23 @@
|
||||
in the file currently open in the code editor.
|
||||
\endlist
|
||||
|
||||
\note By default, \QC builds a project before deploying and running
|
||||
it.
|
||||
\endlist
|
||||
|
||||
By default, \QC builds a project before deploying and running it.
|
||||
To run all tests without building and deploying them again, select
|
||||
\uicontrol {Run All Tests Without Deployment} in the context menu.
|
||||
To run the selected tests without deployment, select
|
||||
\uicontrol {Run Selected Tests Without Deployment}.
|
||||
|
||||
The functions to run tests are also available in the context menu in the
|
||||
\uicontrol Tests view and in \uicontrol Tools > \uicontrol Tests.
|
||||
|
||||
\note If you have enabled build system based and code based tests,
|
||||
you may run tests twice when using \uicontrol {Run All Tests} or
|
||||
\uicontrol {Run Selected Tests}. This happens if the tests can be
|
||||
found by the code based test frameworks and are registered as test
|
||||
with the build system.
|
||||
|
||||
\endlist
|
||||
|
||||
If a test takes more than a minute to execute, the default timeout might
|
||||
stop the test execution. To increase the timeout, select \uicontrol Tools >
|
||||
\uicontrol Options > \uicontrol {Testing} > \uicontrol General.
|
||||
@@ -369,7 +383,8 @@
|
||||
|
||||
The test cases are listed in alphabetic, case insensitive order. To list
|
||||
them in the order in which they are defined in the source code,
|
||||
select \inlineimage leafsort.png (\uicontrol {Sort Naturally}).
|
||||
select \inlineimage leafsort.png
|
||||
(\uicontrol {Sort Naturally}).
|
||||
|
||||
\section2 Running and Debugging Tests from Code Editor
|
||||
|
||||
@@ -511,7 +526,7 @@
|
||||
\li To specify settings for running Catch2 tests, select
|
||||
\uicontrol Tools > \uicontrol Options > \uicontrol {Testing} >
|
||||
\uicontrol {Catch Test}.
|
||||
\image qtcreator-autotests-options-catch2.png
|
||||
\image qtcreator-autotests-options-catch2.png "Catch Test options"
|
||||
\li Select the \uicontrol {Show success} check box to show succeeding
|
||||
expressions as well. By default Catch2 will print only fails.
|
||||
\li Select the \uicontrol {Break on failure while debugging} check box
|
||||
@@ -543,7 +558,7 @@
|
||||
\li To specify settings for running CTest-based tests, select
|
||||
\uicontrol Tools > \uicontrol Options > \uicontrol {Testing} >
|
||||
\uicontrol {CTest}.
|
||||
//! insert image here
|
||||
\image qtcreator-autotests-options-ctest.png "CTest options"
|
||||
\li Select the \uicontrol {Output on failure} check box to show test
|
||||
specific output if a test fails. Contrary to the CTest default
|
||||
this is enabled by default.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
@@ -158,7 +158,7 @@
|
||||
|
||||
However, some configuration options are available and you can set them in
|
||||
\uicontrol Tools > \uicontrol Options > \uicontrol {Version Control} >
|
||||
\uicontrol Common.
|
||||
\uicontrol General.
|
||||
|
||||
For more information about the supported functions, see
|
||||
\l{Using Version Control Systems}.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
@@ -65,7 +65,7 @@
|
||||
\li \b {\l{Designing User Interfaces}}
|
||||
|
||||
To create intuitive, modern-looking, fluid user interfaces, you
|
||||
can use \l{Qt Quick} and \QDS.
|
||||
can use \l{Qt Quick} and \l{Qt Design Studio Manual}{\QDS}.
|
||||
If you need a traditional user interface that is clearly
|
||||
structured and enforces a platform look and feel, you can use
|
||||
the integrated \QD. For more information, see
|
||||
@@ -114,9 +114,10 @@
|
||||
execution. In addition, the QML Profiler enables you to profile
|
||||
Qt Quick applications.
|
||||
|
||||
\QC is integrated to the \l{Qt Test}, Google C++ Testing, and
|
||||
Boost.Test frameworks for unit testing applications and
|
||||
libraries. You can use \QC to create, build, and run autotests.
|
||||
\QC is integrated to the \l{Qt Test}, Boost.Test, Catch 2 test,
|
||||
and Google C++ Testing frameworks for unit testing applications
|
||||
and libraries. You can use \QC to create, build, and run
|
||||
autotests.
|
||||
|
||||
For more information, see \l{Testing}.
|
||||
\li \b {Publishing}
|
||||
|
@@ -51,7 +51,8 @@
|
||||
\l{http://doc.qt.io/QtForDeviceCreation/index.html}{Qt for Device Creation}
|
||||
documentation.
|
||||
|
||||
If you have \QDS installed, you can open \QDS examples from \QC in \QDS.
|
||||
If you have \l{Qt Design Studio Manual}{\QDS} installed, you can open
|
||||
\QDS examples from \QC in \QDS.
|
||||
|
||||
\list 1
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
@@ -29,8 +29,8 @@
|
||||
\section2 Creating Widget-Based Qt for Python Applications
|
||||
|
||||
\l {https://doc.qt.io/qtforpython/index.html}{Qt for Python} enables you
|
||||
to use Qt 5 API in Python applications. You can use the PySide2 module to
|
||||
gain access to individual Qt modules, such as \l {Qt Core}, \l {Qt GUI},
|
||||
to use Qt 6 API in Python applications. You can use the PySide6 modules
|
||||
to gain access to individual Qt modules, such as \l {Qt Core}, \l {Qt GUI},
|
||||
and \l {Qt Widgets}.
|
||||
|
||||
The Qt for Python Application wizards generate a \c {.pyproject} file that
|
||||
@@ -46,7 +46,8 @@
|
||||
|
||||
The \uicontrol {Qt for Python - Window (UI file)} wizard enables you to
|
||||
create a Python project that contains the source file for a class. Specify
|
||||
the class name, base class, and and source file for the class.
|
||||
the PySide version, class name, base class, and and source file for the
|
||||
class.
|
||||
|
||||
\image qtcreator-python-wizard-app-window.png "Qt for Python wizard for creating a widget-based UI"
|
||||
|
||||
@@ -55,21 +56,22 @@
|
||||
Widgets module, and Qt UI tools:
|
||||
|
||||
\badcode
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
from PySide2.QtWidgets import QApplication, QWidget
|
||||
from PySide2.QtCore import QFile
|
||||
from PySide2.QtUiTools import QUiLoader
|
||||
from PySide6.QtWidgets import QApplication, QWidget
|
||||
from PySide6.QtCore import QFile
|
||||
from PySide6.QtUiTools import QUiLoader
|
||||
\endcode
|
||||
|
||||
The wizard also adds a main class with the specified name that
|
||||
inherits from the specified base class:
|
||||
|
||||
\badcode
|
||||
class MyWidget(QWidget):
|
||||
class Widget(QWidget):
|
||||
def __init__(self):
|
||||
super(MyWidget, self).__init__()
|
||||
super(Widget, self).__init__()
|
||||
self.load_ui()
|
||||
...
|
||||
\endcode
|
||||
@@ -79,12 +81,12 @@
|
||||
|
||||
\badcode
|
||||
def load_ui(self):
|
||||
loader = QUiLoader()
|
||||
path = os.path.join(os.path.dirname(__file__), "form.ui")
|
||||
ui_file = QFile(path)
|
||||
ui_file.open(QFile.ReadOnly)
|
||||
loader.load(ui_file, self)
|
||||
ui_file.close()
|
||||
loader = QUiLoader()
|
||||
path = os.fspath(Path(__file__).resolve().parent / "form.ui")
|
||||
ui_file = QFile(path)
|
||||
ui_file.open(QFile.ReadOnly)
|
||||
loader.load(ui_file, self)
|
||||
ui_file.close()
|
||||
\endcode
|
||||
|
||||
Next, the wizard adds a main function, where it creates a
|
||||
@@ -100,8 +102,8 @@
|
||||
Next, the wizard instantiates the \c MainWindow class and shows it:
|
||||
|
||||
\badcode
|
||||
window = MyWidget()
|
||||
window.show()
|
||||
widget = Widget()
|
||||
widget.show()
|
||||
...
|
||||
\endcode
|
||||
|
||||
@@ -153,12 +155,12 @@
|
||||
to QGuiApplication and QQmlApplicationEngine:
|
||||
|
||||
\badcode
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
from PySide2.QtGui import QGuiApplication
|
||||
from PySide2.QtQml import QQmlApplicationEngine
|
||||
|
||||
from PySide6.QtGui import QGuiApplication
|
||||
from PySide6.QtQml import QQmlApplicationEngine
|
||||
\endcode
|
||||
|
||||
The wizard also adds a main function, where it creates a QGuiApplication
|
||||
@@ -175,7 +177,7 @@
|
||||
|
||||
\badcode
|
||||
engine = QQmlApplicationEngine()
|
||||
engine.load(os.path.join(os.path.dirname(__file__), "main.qml"))
|
||||
engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml"))
|
||||
\endcode
|
||||
|
||||
Finally, the wizard adds code that checks whether the file was successfully
|
||||
@@ -190,7 +192,7 @@
|
||||
\endcode
|
||||
|
||||
Open the .qml file in the \uicontrol Edit mode to design a Qt Quick UI, or
|
||||
use \QDS.
|
||||
use \l{Qt Design Studio Manual}{\QDS}.
|
||||
|
||||
//! [python qml project wizards]
|
||||
*/
|
||||
|
@@ -35,13 +35,8 @@
|
||||
\image qtcreator-open-documents-view.png "Open Documents view"
|
||||
|
||||
You can use the context menu to apply some of the functions also available
|
||||
in the \uicontrol File menu
|
||||
\if defined(qtcreator)
|
||||
.
|
||||
\else
|
||||
and in the \l {File System Context Menu} {File System} view to the file
|
||||
that is selected in the view.
|
||||
\endif
|
||||
in the \uicontrol File menu and in the \l {File System Context Menu}
|
||||
{File System} view to the file that is selected in the view.
|
||||
|
||||
In addition, you can:
|
||||
|
||||
|
@@ -293,6 +293,7 @@
|
||||
style.
|
||||
\endif
|
||||
|
||||
|
||||
You can use \QC in the following modes:
|
||||
|
||||
\list
|
||||
@@ -487,8 +488,8 @@
|
||||
|
||||
The pane filters out irrelevant output from the build tools and presents the
|
||||
issues in an organized way. To further filter the output by type, select
|
||||
\uicontrol {Filter Tree}
|
||||
and then select a filter.
|
||||
\inlineimage filtericon.png
|
||||
(\uicontrol {Filter Tree}) and then select a filter.
|
||||
|
||||
\image qtcreator-issues.png "Issues output pane"
|
||||
|
||||
@@ -550,9 +551,10 @@
|
||||
|
||||
To specify settings for displaying application output, select
|
||||
\uicontrol Tools > \uicontrol Options > \uicontrol {Build & Run} >
|
||||
\uicontrol {Application Output}, or click the \uicontrol {Open Settings Page}
|
||||
button. You can select whether to open the \uicontrol{Application Output} pane
|
||||
on output when running or debugging applications, to clear old output on a new run,
|
||||
\uicontrol {Application Output}, or click the \inlineimage settings.png
|
||||
(\uicontrol {Open Settings Page}) button. You can select whether to open
|
||||
the \uicontrol{Application Output} pane on output when running or debugging
|
||||
applications, to clear old output on a new run,
|
||||
to word-wrap output, and to limit output to the specified number of lines.
|
||||
|
||||
\section1 Compile Output
|
||||
@@ -575,8 +577,8 @@
|
||||
In the \uicontrol {Limit output to} field, you can specify the maximum
|
||||
amount of build output lines to display in the pane.
|
||||
|
||||
You can also reach the options page by clicking the \uicontrol {Open Settings Page}
|
||||
button.
|
||||
You can also reach the options page by clicking \inlineimage settings.png
|
||||
(\uicontrol {Open Settings Page}).
|
||||
|
||||
To copy the output from the pane to the clipboard, select
|
||||
\uicontrol {Select All} in the context menu, and then select
|
||||
|
@@ -97,12 +97,14 @@
|
||||
|
||||
\list
|
||||
\li To see a complete list of all bindings, select
|
||||
\uicontrol {Filter Tree} > \uicontrol {Show All Bindings}.
|
||||
\inlineimage filtericon.png
|
||||
(\uicontrol {Filter Tree}) > \uicontrol {Show All Bindings}.
|
||||
\li To sort types or symbols alphabetically, select
|
||||
\inlineimage sort_alphabetically.png
|
||||
(\uicontrol {Sort Alphabetically}).
|
||||
\li To stop the synchronization with the type or symbol selected in the
|
||||
editor, deselect \uicontrol {Synchronize with Editor}.
|
||||
editor, deselect \inlineimage linkicon.png
|
||||
(\uicontrol {Synchronize with Editor}).
|
||||
\endlist
|
||||
|
||||
\section1 Viewing the Class Hierarchy
|
||||
@@ -144,5 +146,6 @@
|
||||
\image qtcreator-include-hierarchy-view.png "Include Hierarchy view"
|
||||
|
||||
To keep the view synchronized with the file currently opened in the editor,
|
||||
select \uicontrol {Synchronize with Editor}.
|
||||
select \inlineimage linkicon.png
|
||||
(\uicontrol {Synchronize with Editor}).
|
||||
*/
|
||||
|
@@ -25,10 +25,11 @@
|
||||
|
||||
#include "qmlstatenodeinstance.h"
|
||||
|
||||
#include <qmlprivategate.h>
|
||||
|
||||
#include "qmlpropertychangesnodeinstance.h"
|
||||
|
||||
#include <qmlprivategate.h>
|
||||
#include <designersupportdelegate.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
namespace Internal {
|
||||
|
||||
@@ -53,12 +54,28 @@ QmlStateNodeInstance::Pointer
|
||||
return instance;
|
||||
}
|
||||
|
||||
void setAllNodesDirtyRecursive(QQuickItem *parentItem)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
Q_UNUSED(parentItem)
|
||||
#else
|
||||
if (!parentItem)
|
||||
return;
|
||||
const QList<QQuickItem *> children = parentItem->childItems();
|
||||
for (QQuickItem *childItem : children)
|
||||
setAllNodesDirtyRecursive(childItem);
|
||||
DesignerSupport::addDirty(parentItem, QQuickDesignerSupport::Content);
|
||||
#endif
|
||||
}
|
||||
|
||||
void QmlStateNodeInstance::activateState()
|
||||
{
|
||||
if (!QmlPrivateGate::States::isStateActive(object(), context())
|
||||
&& nodeInstanceServer()->hasInstanceForObject(object())) {
|
||||
nodeInstanceServer()->setStateInstance(nodeInstanceServer()->instanceForObject(object()));
|
||||
QmlPrivateGate::States::activateState(object(), context());
|
||||
|
||||
setAllNodesDirtyRecursive(nodeInstanceServer()->rootItem());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1858,7 +1858,11 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
|
||||
#ifdef QUICK3D_MODULE
|
||||
if (qobject_cast<QQuick3DModel *>(object)
|
||||
|| qobject_cast<QQuick3DCamera *>(object)
|
||||
|| qobject_cast<QQuick3DAbstractLight *>(object)) {
|
||||
|| qobject_cast<QQuick3DAbstractLight *>(object)
|
||||
#ifdef QUICK3D_PARTICLES_MODULE
|
||||
|| qobject_cast<QQuick3DParticleSystem *>(object)
|
||||
#endif
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
// Node is a component if it has node children that have no instances
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 892 B |
After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 8.3 KiB |
@@ -202,8 +202,8 @@ Item {
|
||||
dialogBox.setScreenSizeIndex(index);
|
||||
|
||||
var r = screenSizeModel.screenSizes(index);
|
||||
widthTextField.text = r.width;
|
||||
heightTextField.text = r.height;
|
||||
widthField.realValue = r.width;
|
||||
heightField.realValue = r.height;
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -252,19 +252,20 @@ Item {
|
||||
}
|
||||
|
||||
// content items
|
||||
SC.TextField {
|
||||
id: widthTextField
|
||||
SC.RealSpinBox {
|
||||
id: widthField
|
||||
actionIndicatorVisible: false
|
||||
translationIndicatorVisible: false
|
||||
implicitWidth: 50
|
||||
color: DialogValues.textColor
|
||||
selectByMouse: true
|
||||
validator: IntValidator { bottom: 1; top: 100000; }
|
||||
implicitWidth: 70
|
||||
labelColor: DialogValues.textColor
|
||||
realFrom: 100
|
||||
realTo: 100000
|
||||
realValue: 100
|
||||
realStepSize: 10
|
||||
font.pixelSize: DialogValues.defaultPixelSize
|
||||
|
||||
onTextChanged: {
|
||||
var height = heightTextField.text ? parseInt(heightTextField.text) : 0
|
||||
var width = text ? parseInt(text) : 0
|
||||
onRealValueChanged: {
|
||||
var height = heightField.realValue
|
||||
var width = realValue
|
||||
|
||||
if (width >= height)
|
||||
orientationButton.setHorizontal()
|
||||
@@ -276,22 +277,23 @@ Item {
|
||||
Binding {
|
||||
target: dialogBox
|
||||
property: "customWidth"
|
||||
value: widthTextField.text
|
||||
value: widthField.realValue
|
||||
}
|
||||
|
||||
SC.TextField {
|
||||
id: heightTextField
|
||||
SC.RealSpinBox {
|
||||
id: heightField
|
||||
actionIndicatorVisible: false
|
||||
translationIndicatorVisible: false
|
||||
implicitWidth: 50
|
||||
color: DialogValues.textColor
|
||||
selectByMouse: true
|
||||
validator: IntValidator { bottom: 1; top: 100000; }
|
||||
implicitWidth: 70
|
||||
labelColor: DialogValues.textColor
|
||||
realFrom: 100
|
||||
realTo: 100000
|
||||
realValue: 100
|
||||
realStepSize: 10
|
||||
font.pixelSize: DialogValues.defaultPixelSize
|
||||
|
||||
onTextChanged: {
|
||||
var height = text ? parseInt(text) : 0
|
||||
var width = widthTextField.text ? parseInt(widthTextField.text) : 0
|
||||
onRealValueChanged: {
|
||||
var height = realValue
|
||||
var width = widthField.realValue
|
||||
|
||||
if (width >= height)
|
||||
orientationButton.setHorizontal()
|
||||
@@ -303,7 +305,7 @@ Item {
|
||||
Binding {
|
||||
target: dialogBox
|
||||
property: "customHeight"
|
||||
value: heightTextField.text
|
||||
value: heightField.realValue
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
@@ -348,9 +350,8 @@ Item {
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (widthTextField.text && heightTextField.text) {
|
||||
[widthTextField.text, heightTextField.text] = [heightTextField.text, widthTextField.text];
|
||||
|
||||
if (widthField.realValue && heightField.realValue) {
|
||||
[widthField.realValue, heightField.realValue] = [heightField.realValue, widthField.realValue];
|
||||
checked = !checked
|
||||
}
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ import QtQuick.Controls
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import newprojectdialog
|
||||
import NewProjectDialog
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
@@ -158,16 +158,15 @@ QtObject {
|
||||
readonly property string transparent: "\u0099"
|
||||
readonly property string triState: "\u009A"
|
||||
readonly property string triangleArcA: "\u009B"
|
||||
readonly property string triangleArcB: "\u009C"
|
||||
readonly property string triangleCornerA: "\u009D"
|
||||
readonly property string triangleCornerB: "\u009E"
|
||||
readonly property string unLinked: "\u009F"
|
||||
readonly property string undo: "\u00A0"
|
||||
readonly property string unpin: "\u00A1"
|
||||
readonly property string upDownIcon: "\u00A2"
|
||||
readonly property string upDownSquare2: "\u00A3"
|
||||
readonly property string visibilityOffBroken: "\u00A4" // visibilityOff
|
||||
readonly property string visibilityOff: "\u00A5" // visibilityOff2
|
||||
readonly property string triangleArcB: "\u009D"
|
||||
readonly property string triangleCornerA: "\u009E"
|
||||
readonly property string triangleCornerB: "\u009F"
|
||||
readonly property string unLinked: "\u00A0"
|
||||
readonly property string undo: "\u00A1"
|
||||
readonly property string unpin: "\u00A2"
|
||||
readonly property string upDownIcon: "\u00A3"
|
||||
readonly property string upDownSquare2: "\u00A4"
|
||||
readonly property string visibilityOff: "\u00A5"
|
||||
readonly property string visibilityOn: "\u00A6"
|
||||
readonly property string wildcard: "\u00A7"
|
||||
readonly property string wizardsAutomotive: "\u00A8"
|
||||
@@ -175,12 +174,12 @@ QtObject {
|
||||
readonly property string wizardsGeneric: "\u00AA"
|
||||
readonly property string wizardsMcuEmpty: "\u00AB"
|
||||
readonly property string wizardsMcuGraph: "\u00AC"
|
||||
readonly property string wizardsMobile: "\u00AD"
|
||||
readonly property string wizardsUnknown: "\u00AE"
|
||||
readonly property string zoomAll: "\u00AF"
|
||||
readonly property string zoomIn: "\u00B0"
|
||||
readonly property string zoomOut: "\u00B1"
|
||||
readonly property string zoomSelection: "\u00B2"
|
||||
readonly property string wizardsMobile: "\u00AE"
|
||||
readonly property string wizardsUnknown: "\u00AF"
|
||||
readonly property string zoomAll: "\u00B0"
|
||||
readonly property string zoomIn: "\u00B1"
|
||||
readonly property string zoomOut: "\u00B2"
|
||||
readonly property string zoomSelection: "\u00B3"
|
||||
|
||||
readonly property font iconFont: Qt.font({
|
||||
"family": controlIcons.name,
|
||||
|
@@ -794,8 +794,10 @@ bool Check::visit(UiObjectInitializer *)
|
||||
UiQualifiedId *qualifiedTypeId = qualifiedTypeNameId(parent());
|
||||
if (qualifiedTypeId) {
|
||||
typeName = qualifiedTypeId->name.toString();
|
||||
if (typeName == "Component")
|
||||
if (typeName == "Component") {
|
||||
m_idStack.push(StringSet());
|
||||
_componentChildCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_typeStack.push(typeName);
|
||||
@@ -806,10 +808,23 @@ bool Check::visit(UiObjectInitializer *)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Check::endVisit(UiObjectInitializer *)
|
||||
void Check::endVisit(UiObjectInitializer *uiObjectInitializer)
|
||||
{
|
||||
m_propertyStack.pop();
|
||||
m_typeStack.pop();
|
||||
|
||||
const QString type = m_typeStack.pop();
|
||||
|
||||
if (type == "Component" && _componentChildCount == 0) {
|
||||
SourceLocation loc;
|
||||
UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(parent());
|
||||
if (objectDefinition)
|
||||
loc = objectDefinition->qualifiedTypeNameId->identifierToken;
|
||||
UiObjectBinding *objectBinding = cast<UiObjectBinding *>(parent());
|
||||
if (objectBinding)
|
||||
loc = objectBinding->qualifiedTypeNameId->identifierToken;
|
||||
addMessage(WarnComponentRequiresChildren, loc);
|
||||
}
|
||||
|
||||
UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(parent());
|
||||
if (objectDefinition && objectDefinition->qualifiedTypeNameId->name == QLatin1String("Component"))
|
||||
m_idStack.pop();
|
||||
@@ -962,6 +977,12 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
|
||||
addMessage(ErrUnsupportedRootTypeInQmlUi,
|
||||
locationFromRange(ast->firstSourceLocation(), ast->lastSourceLocation()), typeName);
|
||||
|
||||
if (!m_typeStack.isEmpty() && m_typeStack.last() == "Component") {
|
||||
_componentChildCount++;
|
||||
if (_componentChildCount > 1)
|
||||
addMessage(ErrToManyComponentChildren, typeErrorLocation);
|
||||
}
|
||||
|
||||
bool typeError = false;
|
||||
if (_importsOk) {
|
||||
const ObjectValue *prototype = _context->lookupType(_doc.data(), typeId);
|
||||
|
@@ -158,6 +158,7 @@ private:
|
||||
|
||||
bool _importsOk;
|
||||
bool _inStatementBinding;
|
||||
int _componentChildCount = 0;
|
||||
const Imports *_imports;
|
||||
TranslationFunction lastTransLationfunction = noTranslationfunction;
|
||||
};
|
||||
|
@@ -251,6 +251,10 @@ StaticAnalysisMessages::StaticAnalysisMessages()
|
||||
tr("Type cannot be instantiated recursively (%1)."), 1);
|
||||
newMsg(WarnLogicalValueDoesNotDependOnValues, Warning,
|
||||
tr("Logical value does not depend on actual values"));
|
||||
newMsg(ErrToManyComponentChildren, Error,
|
||||
tr("Components are only allowed to have a single child element."));
|
||||
newMsg(WarnComponentRequiresChildren, Warning,
|
||||
tr("Components require a child element."));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
@@ -132,6 +132,8 @@ enum Type {
|
||||
ErrInvalidArrayValueLength = 323,
|
||||
ErrHitMaximumRecursion = 324,
|
||||
WarnLogicalValueDoesNotDependOnValues = 325,
|
||||
ErrToManyComponentChildren = 326,
|
||||
WarnComponentRequiresChildren = 327,
|
||||
WarnDuplicateImport = 400
|
||||
};
|
||||
|
||||
|
@@ -37,7 +37,10 @@
|
||||
|
||||
#include <projectexplorer/devicesupport/devicemanager.h>
|
||||
#include <projectexplorer/devicesupport/idevicewidget.h>
|
||||
#include <projectexplorer/kitinformation.h>
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
#include <projectexplorer/session.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <utils/qtcprocess.h>
|
||||
#include <utils/runextensions.h>
|
||||
@@ -418,11 +421,19 @@ QUrl AndroidDevice::toolControlChannel(const ControlChannelHint &) const
|
||||
|
||||
void AndroidDeviceManager::updateDevicesList()
|
||||
{
|
||||
connect(&m_devicesUpdaterTimer, &QTimer::timeout, this, [this]() {
|
||||
updateDevicesListOnce();
|
||||
});
|
||||
// If a non-Android Kit is currently active, skip the device list update
|
||||
const Target *startupTarget = SessionManager::startupTarget();
|
||||
if (!startupTarget)
|
||||
return;
|
||||
|
||||
const Kit *kit = startupTarget->kit();
|
||||
if (!kit)
|
||||
return;
|
||||
|
||||
if (DeviceTypeKitAspect::deviceTypeId(kit) != Constants::ANDROID_DEVICE_TYPE)
|
||||
return;
|
||||
|
||||
updateDevicesListOnce();
|
||||
m_devicesUpdaterTimer.start(deviceUpdaterMsInterval);
|
||||
}
|
||||
|
||||
void AndroidDeviceManager::updateDevicesListOnce()
|
||||
@@ -537,11 +548,17 @@ void AndroidDeviceManager::setEmulatorArguments(QWidget *parent)
|
||||
|
||||
void AndroidDeviceManager::setupDevicesWatcher()
|
||||
{
|
||||
// The call to avdmanager is always slower than the call to adb devices,
|
||||
// so connecting the slot to the slower call should be enough.
|
||||
connect(&m_avdsFutureWatcher, &QFutureWatcherBase::finished,
|
||||
this, &AndroidDeviceManager::devicesListUpdated);
|
||||
updateDevicesList();
|
||||
if (!m_devicesUpdaterTimer.isActive()) {
|
||||
// The call to avdmanager is always slower than the call to adb devices,
|
||||
// so connecting the slot to the slower call should be enough.
|
||||
connect(&m_avdsFutureWatcher, &QFutureWatcherBase::finished,
|
||||
this, &AndroidDeviceManager::devicesListUpdated);
|
||||
connect(&m_devicesUpdaterTimer, &QTimer::timeout, this, [this]() {
|
||||
updateDevicesList();
|
||||
});
|
||||
m_devicesUpdaterTimer.start(deviceUpdaterMsInterval);
|
||||
}
|
||||
updateDevicesListOnce();
|
||||
}
|
||||
|
||||
void AndroidDeviceManager::devicesListUpdated()
|
||||
|
@@ -83,21 +83,9 @@ FilePath ITestConfiguration::executableFilePath() const
|
||||
if (!hasExecutable())
|
||||
return {};
|
||||
|
||||
if (m_runnable.command.executable().isExecutableFile() && m_runnable.command.executable().path() != ".") {
|
||||
return m_runnable.command.executable().absoluteFilePath();
|
||||
} else if (m_runnable.command.executable().path() == "."){
|
||||
QString fullCommandFileName = m_runnable.command.executable().toString();
|
||||
// TODO: check if we can use searchInPath() from Utils::Environment
|
||||
const QStringList &pathList = m_runnable.environment.toProcessEnvironment().value("PATH")
|
||||
.split(HostOsInfo::pathListSeparator());
|
||||
|
||||
for (const QString &path : pathList) {
|
||||
QString filePath(path + QDir::separator() + fullCommandFileName);
|
||||
if (QFileInfo(filePath).isExecutable())
|
||||
return m_runnable.command.executable().absoluteFilePath();
|
||||
}
|
||||
}
|
||||
return {};
|
||||
const Environment env = m_runnable.environment.size() == 0 ? Environment::systemEnvironment()
|
||||
: m_runnable.environment;
|
||||
return env.searchInPath(m_runnable.command.executable().path());
|
||||
}
|
||||
|
||||
Environment ITestConfiguration::filteredEnvironment(const Environment &original) const
|
||||
|
@@ -338,7 +338,9 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper()
|
||||
return createProposal();
|
||||
break;
|
||||
case ClangCompletionContextAnalyzer::CompleteIncludePath:
|
||||
if (completeInclude(analyzer.positionEndOfExpression()))
|
||||
m_completions = completeInclude(analyzer.positionEndOfExpression(), m_completionOperator,
|
||||
m_interface.data(), m_interface->headerPaths());
|
||||
if (!m_completions.isEmpty())
|
||||
return createProposal();
|
||||
break;
|
||||
case ClangCompletionContextAnalyzer::CompletePreprocessorDirective:
|
||||
@@ -441,38 +443,46 @@ bool ClangCompletionAssistProcessor::accepts() const
|
||||
|
||||
/**
|
||||
* @brief Creates completion proposals for #include and given cursor
|
||||
* @param cursor - cursor placed after opening bracked or quote
|
||||
* @return false if completions list is empty
|
||||
* @param position - cursor placed after opening bracked or quote
|
||||
* @param completionOperator - the type of token
|
||||
* @param interface - relevant document data
|
||||
* @param headerPaths - the include paths
|
||||
* @return the list of completion items
|
||||
*/
|
||||
bool ClangCompletionAssistProcessor::completeInclude(const QTextCursor &cursor)
|
||||
QList<AssistProposalItemInterface *> ClangCompletionAssistProcessor::completeInclude(
|
||||
int position, unsigned completionOperator, const TextEditor::AssistInterface *interface,
|
||||
const ProjectExplorer::HeaderPaths &headerPaths)
|
||||
{
|
||||
QTextCursor cursor(interface->textDocument());
|
||||
cursor.setPosition(position);
|
||||
QString directoryPrefix;
|
||||
if (m_completionOperator == T_SLASH) {
|
||||
if (completionOperator == T_SLASH) {
|
||||
QTextCursor c = cursor;
|
||||
c.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
|
||||
QString sel = c.selectedText();
|
||||
int startCharPos = sel.indexOf(QLatin1Char('"'));
|
||||
if (startCharPos == -1) {
|
||||
startCharPos = sel.indexOf(QLatin1Char('<'));
|
||||
m_completionOperator = T_ANGLE_STRING_LITERAL;
|
||||
completionOperator = T_ANGLE_STRING_LITERAL;
|
||||
} else {
|
||||
m_completionOperator = T_STRING_LITERAL;
|
||||
completionOperator = T_STRING_LITERAL;
|
||||
}
|
||||
if (startCharPos != -1)
|
||||
directoryPrefix = sel.mid(startCharPos + 1, sel.length() - 1);
|
||||
}
|
||||
|
||||
// Make completion for all relevant includes
|
||||
ProjectExplorer::HeaderPaths headerPaths = m_interface->headerPaths();
|
||||
ProjectExplorer::HeaderPaths allHeaderPaths = headerPaths;
|
||||
const auto currentFilePath = ProjectExplorer::HeaderPath::makeUser(
|
||||
m_interface->filePath().toFileInfo().path());
|
||||
if (!headerPaths.contains(currentFilePath))
|
||||
headerPaths.append(currentFilePath);
|
||||
interface->filePath().toFileInfo().path());
|
||||
if (!allHeaderPaths.contains(currentFilePath))
|
||||
allHeaderPaths.append(currentFilePath);
|
||||
|
||||
const ::Utils::MimeType mimeType = ::Utils::mimeTypeForName("text/x-c++hdr");
|
||||
const QStringList suffixes = mimeType.suffixes();
|
||||
|
||||
foreach (const ProjectExplorer::HeaderPath &headerPath, headerPaths) {
|
||||
QList<AssistProposalItemInterface *> completions;
|
||||
foreach (const ProjectExplorer::HeaderPath &headerPath, allHeaderPaths) {
|
||||
QString realPath = headerPath.path;
|
||||
if (!directoryPrefix.isEmpty()) {
|
||||
realPath += QLatin1Char('/');
|
||||
@@ -480,11 +490,11 @@ bool ClangCompletionAssistProcessor::completeInclude(const QTextCursor &cursor)
|
||||
if (headerPath.type == ProjectExplorer::HeaderPathType::Framework)
|
||||
realPath += QLatin1String(".framework/Headers");
|
||||
}
|
||||
completeIncludePath(realPath, suffixes);
|
||||
completions << completeIncludePath(realPath, suffixes, completionOperator);
|
||||
}
|
||||
|
||||
QList<QPair<AssistProposalItemInterface *, QString>> completionsForSorting;
|
||||
for (AssistProposalItemInterface * const item : qAsConst(m_completions)) {
|
||||
for (AssistProposalItemInterface * const item : qAsConst(completions)) {
|
||||
QString s = item->text();
|
||||
s.replace('/', QChar(0)); // The dir separator should compare less than anything else.
|
||||
completionsForSorting << qMakePair(item, s);
|
||||
@@ -493,26 +503,21 @@ bool ClangCompletionAssistProcessor::completeInclude(const QTextCursor &cursor)
|
||||
return left.second < right.second;
|
||||
});
|
||||
for (int i = 0; i < completionsForSorting.count(); ++i)
|
||||
m_completions[i] = completionsForSorting[i].first;
|
||||
completions[i] = completionsForSorting[i].first;
|
||||
|
||||
return !m_completions.isEmpty();
|
||||
}
|
||||
|
||||
bool ClangCompletionAssistProcessor::completeInclude(int position)
|
||||
{
|
||||
QTextCursor textCursor(m_interface->textDocument()); // TODO: Simplify, move into function
|
||||
textCursor.setPosition(position);
|
||||
return completeInclude(textCursor);
|
||||
return completions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds #include completion proposals using given include path
|
||||
* @brief Finds #include completion proposals using given include path
|
||||
* @param realPath - one of directories where compiler searches includes
|
||||
* @param suffixes - file suffixes for C/C++ header files
|
||||
* @return a list of matching completion items
|
||||
*/
|
||||
void ClangCompletionAssistProcessor::completeIncludePath(const QString &realPath,
|
||||
const QStringList &suffixes)
|
||||
QList<AssistProposalItemInterface *> ClangCompletionAssistProcessor::completeIncludePath(
|
||||
const QString &realPath, const QStringList &suffixes, unsigned completionOperator)
|
||||
{
|
||||
QList<AssistProposalItemInterface *> completions;
|
||||
QDirIterator i(realPath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
//: Parent folder for proposed #include completion
|
||||
const QString hint = tr("Location: %1").arg(QDir::toNativeSeparators(QDir::cleanPath(realPath)));
|
||||
@@ -529,10 +534,11 @@ void ClangCompletionAssistProcessor::completeIncludePath(const QString &realPath
|
||||
item->setText(text);
|
||||
item->setDetail(hint);
|
||||
item->setIcon(CPlusPlus::Icons::keywordIcon());
|
||||
item->setCompletionOperator(m_completionOperator);
|
||||
m_completions.append(item);
|
||||
item->setCompletionOperator(completionOperator);
|
||||
completions.append(item);
|
||||
}
|
||||
}
|
||||
return completions;
|
||||
}
|
||||
|
||||
bool ClangCompletionAssistProcessor::completePreprocessorDirectives()
|
||||
|
@@ -34,6 +34,11 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QTextCursor>
|
||||
|
||||
namespace TextEditor {
|
||||
class AssistInterface;
|
||||
class AssistProposalItemInterface;
|
||||
}
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
@@ -48,6 +53,11 @@ public:
|
||||
ClangCompletionAssistProcessor();
|
||||
~ClangCompletionAssistProcessor() override;
|
||||
|
||||
static QList<TextEditor::AssistProposalItemInterface *> completeInclude(
|
||||
int position, unsigned completionOperator,
|
||||
const TextEditor::AssistInterface *interface,
|
||||
const ProjectExplorer::HeaderPaths &headerPaths);
|
||||
|
||||
TextEditor::IAssistProposal *perform(const TextEditor::AssistInterface *interface) override;
|
||||
|
||||
void handleAvailableCompletions(const CodeCompletions &completions);
|
||||
@@ -65,12 +75,10 @@ private:
|
||||
TextEditor::IAssistProposal *createProposal();
|
||||
TextEditor::IAssistProposal *createFunctionHintProposal(
|
||||
const CodeCompletions &completions);
|
||||
|
||||
QList<TextEditor::AssistProposalItemInterface *> toAssistProposalItems(
|
||||
const CodeCompletions &completions) const;
|
||||
bool completeInclude(const QTextCursor &cursor);
|
||||
bool completeInclude(int position);
|
||||
void completeIncludePath(const QString &realPath, const QStringList &suffixes);
|
||||
static QList<TextEditor::AssistProposalItemInterface *> completeIncludePath(
|
||||
const QString &realPath, const QStringList &suffixes, unsigned completionOperator);
|
||||
bool completePreprocessorDirectives();
|
||||
bool completeDoxygenKeywords();
|
||||
void addCompletionItem(const QString &text,
|
||||
|
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "clangdclient.h"
|
||||
|
||||
#include "clangcompletionassistprocessor.h"
|
||||
#include "clangcompletioncontextanalyzer.h"
|
||||
#include "clangdiagnosticmanager.h"
|
||||
#include "clangmodelmanagersupport.h"
|
||||
@@ -66,6 +67,7 @@
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/runextensions.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDateTime>
|
||||
@@ -810,14 +812,15 @@ public:
|
||||
};
|
||||
|
||||
|
||||
enum class CustomAssistMode { Doxygen, Preprocessor };
|
||||
enum class CustomAssistMode { Doxygen, Preprocessor, IncludePath };
|
||||
class CustomAssistProcessor : public IAssistProcessor
|
||||
{
|
||||
public:
|
||||
CustomAssistProcessor(ClangdClient *client, int position, unsigned completionOperator,
|
||||
CustomAssistMode mode)
|
||||
CustomAssistProcessor(ClangdClient *client, int position, int endPos,
|
||||
unsigned completionOperator, CustomAssistMode mode)
|
||||
: m_client(client)
|
||||
, m_position(position)
|
||||
, m_endPos(endPos)
|
||||
, m_completionOperator(completionOperator)
|
||||
, m_mode(mode)
|
||||
{}
|
||||
@@ -833,7 +836,7 @@ private:
|
||||
CPlusPlus::Icons::keywordIcon());
|
||||
}
|
||||
break;
|
||||
case CustomAssistMode::Preprocessor:
|
||||
case CustomAssistMode::Preprocessor: {
|
||||
static QIcon macroIcon = Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::Macro);
|
||||
for (const QString &completion
|
||||
: CppEditor::CppCompletionAssistProcessor::preprocessorCompletions()) {
|
||||
@@ -843,6 +846,17 @@ private:
|
||||
completions << createItem("import", macroIcon);
|
||||
break;
|
||||
}
|
||||
case ClangCodeModel::Internal::CustomAssistMode::IncludePath: {
|
||||
HeaderPaths headerPaths;
|
||||
const CppEditor::ProjectPart::ConstPtr projectPart
|
||||
= projectPartForFile(interface->filePath().toString());
|
||||
if (projectPart)
|
||||
headerPaths = projectPart->headerPaths;
|
||||
completions = ClangCompletionAssistProcessor::completeInclude(
|
||||
m_endPos, m_completionOperator, interface, headerPaths);
|
||||
break;
|
||||
}
|
||||
}
|
||||
GenericProposalModelPtr model(new GenericProposalModel);
|
||||
model->loadContent(completions);
|
||||
const auto proposal = new GenericProposal(m_position, model);
|
||||
@@ -864,6 +878,7 @@ private:
|
||||
|
||||
ClangdClient * const m_client;
|
||||
const int m_position;
|
||||
const int m_endPos;
|
||||
const unsigned m_completionOperator;
|
||||
const CustomAssistMode m_mode;
|
||||
};
|
||||
@@ -1110,6 +1125,12 @@ public:
|
||||
using LanguageClientCompletionItem::LanguageClientCompletionItem;
|
||||
void apply(TextDocumentManipulatorInterface &manipulator,
|
||||
int basePosition) const override;
|
||||
|
||||
enum class SpecialQtType { Signal, Slot, None };
|
||||
static SpecialQtType getQtType(const CompletionItem &item);
|
||||
|
||||
private:
|
||||
QIcon icon() const override;
|
||||
};
|
||||
|
||||
class ClangdClient::ClangdCompletionAssistProcessor : public LanguageClientCompletionAssistProcessor
|
||||
@@ -1155,15 +1176,7 @@ ClangdClient::ClangdCompletionAssistProcessor::generateCompletionItems(
|
||||
// whether the cursor was on the second argument of a (dis)connect() call.
|
||||
// If so, we offer only signals, as nothing else makes sense in that context.
|
||||
static const auto criterion = [](const CompletionItem &ci) {
|
||||
const Utils::optional<MarkupOrString> doc = ci.documentation();
|
||||
if (!doc)
|
||||
return false;
|
||||
QString docText;
|
||||
if (Utils::holds_alternative<QString>(*doc))
|
||||
docText = Utils::get<QString>(*doc);
|
||||
else if (Utils::holds_alternative<MarkupContent>(*doc))
|
||||
docText = Utils::get<MarkupContent>(*doc).content();
|
||||
return docText.contains("Annotation: qt_signal");
|
||||
return ClangdCompletionItem::getQtType(ci) == ClangdCompletionItem::SpecialQtType::Signal;
|
||||
};
|
||||
const QTextDocument *doc = document();
|
||||
const int pos = basePos();
|
||||
@@ -1526,6 +1539,30 @@ QString ClangdClient::displayNameFromDocumentSymbol(SymbolKind kind, const QStri
|
||||
}
|
||||
}
|
||||
|
||||
// Force re-parse of all open files that include the changed ui header.
|
||||
// Otherwise, we potentially have stale diagnostics.
|
||||
void ClangdClient::handleUiHeaderChange(const QString &fileName)
|
||||
{
|
||||
const QRegularExpression includeRex("#include.*" + fileName + R"([>"])");
|
||||
const QVector<Client *> &allClients = LanguageClientManager::clients();
|
||||
for (Client * const client : allClients) {
|
||||
if (!client->reachable() || !qobject_cast<ClangdClient *>(client))
|
||||
continue;
|
||||
for (IDocument * const doc : DocumentModel::openedDocuments()) {
|
||||
const auto textDoc = qobject_cast<TextDocument *>(doc);
|
||||
if (!textDoc || !client->documentOpen(textDoc))
|
||||
continue;
|
||||
const QTextCursor includePos = textDoc->document()->find(includeRex);
|
||||
if (includePos.isNull())
|
||||
continue;
|
||||
qCDebug(clangdLog) << "updating" << textDoc->filePath() << "due to change in UI header"
|
||||
<< fileName;
|
||||
client->documentContentsChanged(textDoc, 0, 0, 0);
|
||||
break; // No sane project includes the same UI header twice.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Location> &locations)
|
||||
{
|
||||
const auto refData = runningFindUsages.find(key);
|
||||
@@ -2817,14 +2854,26 @@ IAssistProcessor *ClangdClient::ClangdCompletionAssistProvider::createProcessor(
|
||||
qCDebug(clangdLogCompletion) << "creating doxygen processor";
|
||||
return new CustomAssistProcessor(m_client,
|
||||
contextAnalyzer.positionForProposal(),
|
||||
contextAnalyzer.positionEndOfExpression(),
|
||||
contextAnalyzer.completionOperator(),
|
||||
CustomAssistMode::Doxygen);
|
||||
case ClangCompletionContextAnalyzer::CompletePreprocessorDirective:
|
||||
qCDebug(clangdLogCompletion) << "creating macro processor";
|
||||
return new CustomAssistProcessor(m_client,
|
||||
contextAnalyzer.positionForProposal(),
|
||||
contextAnalyzer.positionEndOfExpression(),
|
||||
contextAnalyzer.completionOperator(),
|
||||
CustomAssistMode::Preprocessor);
|
||||
case ClangCompletionContextAnalyzer::CompleteIncludePath:
|
||||
if (m_client->versionNumber() < QVersionNumber(14)) { // https://reviews.llvm.org/D112996
|
||||
qCDebug(clangdLogCompletion) << "creating include processor";
|
||||
return new CustomAssistProcessor(m_client,
|
||||
contextAnalyzer.positionForProposal(),
|
||||
contextAnalyzer.positionEndOfExpression(),
|
||||
contextAnalyzer.completionOperator(),
|
||||
CustomAssistMode::IncludePath);
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -3009,6 +3058,38 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator,
|
||||
}
|
||||
}
|
||||
|
||||
ClangdCompletionItem::SpecialQtType ClangdCompletionItem::getQtType(const CompletionItem &item)
|
||||
{
|
||||
const Utils::optional<MarkupOrString> doc = item.documentation();
|
||||
if (!doc)
|
||||
return SpecialQtType::None;
|
||||
QString docText;
|
||||
if (Utils::holds_alternative<QString>(*doc))
|
||||
docText = Utils::get<QString>(*doc);
|
||||
else if (Utils::holds_alternative<MarkupContent>(*doc))
|
||||
docText = Utils::get<MarkupContent>(*doc).content();
|
||||
if (docText.contains("Annotation: qt_signal"))
|
||||
return SpecialQtType::Signal;
|
||||
if (docText.contains("Annotation: qt_slot"))
|
||||
return SpecialQtType::Slot;
|
||||
return SpecialQtType::None;
|
||||
}
|
||||
|
||||
QIcon ClangdCompletionItem::icon() const
|
||||
{
|
||||
const SpecialQtType qtType = getQtType(item());
|
||||
switch (qtType) {
|
||||
case SpecialQtType::Signal:
|
||||
return Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::Signal);
|
||||
case SpecialQtType::Slot:
|
||||
// FIXME: Add visibility info to completion item tags in clangd?
|
||||
return Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::SlotPublic);
|
||||
case SpecialQtType::None:
|
||||
break;
|
||||
}
|
||||
return LanguageClientCompletionItem::icon();
|
||||
}
|
||||
|
||||
MessageId ClangdClient::Private::getAndHandleAst(const TextDocOrFile &doc,
|
||||
const AstHandler &astHandler,
|
||||
AstCallbackMode callbackMode, const Range &range)
|
||||
|
@@ -86,6 +86,8 @@ public:
|
||||
static QString displayNameFromDocumentSymbol(LanguageServerProtocol::SymbolKind kind,
|
||||
const QString &name, const QString &detail);
|
||||
|
||||
static void handleUiHeaderChange(const QString &fileName);
|
||||
|
||||
signals:
|
||||
void indexingFinished();
|
||||
void foundReferences(const QList<Core::SearchResultItem> &items);
|
||||
|
@@ -155,9 +155,10 @@ static ::Utils::ProcessLinkCallback extendedCallback(::Utils::ProcessLinkCallbac
|
||||
// If globalFollowSymbol finds nothing follow to the declaration.
|
||||
return [original_callback = std::move(callback), result](const ::Utils::Link &link) {
|
||||
if (link.linkTextStart < 0 && result.isResultOnlyForFallBack) {
|
||||
return original_callback(::Utils::Link(::Utils::FilePath::fromString(result.fileName),
|
||||
result.startLine,
|
||||
result.startColumn - 1));
|
||||
return original_callback(Utils::Link(
|
||||
Utils::FilePath::fromString(result.fileName).cleanPath(),
|
||||
result.startLine,
|
||||
result.startColumn - 1));
|
||||
}
|
||||
return original_callback(link);
|
||||
};
|
||||
@@ -242,7 +243,7 @@ void ClangFollowSymbol::findLink(const CppEditor::CursorInEditor &data,
|
||||
symbolFinder,
|
||||
inNextSplit);
|
||||
} else {
|
||||
callback(Link(Utils::FilePath::fromString(result.fileName),
|
||||
callback(Link(Utils::FilePath::fromString(result.fileName).cleanPath(),
|
||||
result.startLine,
|
||||
result.startColumn - 1));
|
||||
}
|
||||
|
@@ -608,6 +608,7 @@ void ClangModelManagerSupport::onAbstractEditorSupportContentsUpdated(const QStr
|
||||
|
||||
const QString mappedPath = m_uiHeaderOnDiskManager.write(filePath, content);
|
||||
m_communicator.unsavedFilesUpdated(mappedPath, content, 0);
|
||||
ClangdClient::handleUiHeaderChange(Utils::FilePath::fromString(filePath).fileName());
|
||||
}
|
||||
|
||||
void ClangModelManagerSupport::onAbstractEditorSupportRemoved(const QString &filePath)
|
||||
@@ -618,6 +619,7 @@ void ClangModelManagerSupport::onAbstractEditorSupportRemoved(const QString &fil
|
||||
const QString mappedPath = m_uiHeaderOnDiskManager.remove(filePath);
|
||||
const QString projectPartId = projectPartIdForFile(filePath);
|
||||
m_communicator.unsavedFilesRemoved({{mappedPath, projectPartId}});
|
||||
ClangdClient::handleUiHeaderChange(Utils::FilePath::fromString(filePath).fileName());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1488,9 +1488,15 @@ void ClangdTestCompletion::testCompleteIncludeDirective()
|
||||
getProposal("includeDirectiveCompletion.cpp", proposal);
|
||||
|
||||
QVERIFY(proposal);
|
||||
QVERIFY(hasItem(proposal, " file.h>"));
|
||||
QVERIFY(hasItem(proposal, " otherFile.h>"));
|
||||
QVERIFY(hasItem(proposal, " mylib/"));
|
||||
if (client()->versionNumber() < QVersionNumber(14)) {
|
||||
QVERIFY(hasItem(proposal, "file.h"));
|
||||
QVERIFY(hasItem(proposal, "otherFile.h"));
|
||||
QVERIFY(hasItem(proposal, "mylib/"));
|
||||
} else {
|
||||
QVERIFY(hasItem(proposal, " file.h>"));
|
||||
QVERIFY(hasItem(proposal, " otherFile.h>"));
|
||||
QVERIFY(hasItem(proposal, " mylib/"));
|
||||
}
|
||||
QVERIFY(!hasSnippet(proposal, "class "));
|
||||
}
|
||||
|
||||
|
@@ -64,7 +64,7 @@ public:
|
||||
Utils::Id id() const { return m_id; }
|
||||
WizardKind kind() const { return m_supportedProjectTypes.isEmpty() ? FileWizard : ProjectWizard; }
|
||||
QIcon icon() const { return m_icon; }
|
||||
QString fontIcondCode() const { return m_fontIconCode; }
|
||||
QString fontIconName() const { return m_fontIconName; }
|
||||
QString description() const { return m_description; }
|
||||
QString displayName() const { return m_displayName; }
|
||||
QString category() const { return m_category; }
|
||||
@@ -79,7 +79,7 @@ public:
|
||||
void setId(const Utils::Id id) { m_id = id; }
|
||||
void setSupportedProjectTypes(const QSet<Utils::Id> &projectTypes) { m_supportedProjectTypes = projectTypes; }
|
||||
void setIcon(const QIcon &icon, const QString &iconText = {});
|
||||
void setFontIconCode(const QString &code) { m_fontIconCode = code; }
|
||||
void setFontIconName(const QString &code) { m_fontIconName = code; }
|
||||
void setDescription(const QString &description) { m_description = description; }
|
||||
void setDisplayName(const QString &displayName) { m_displayName = displayName; }
|
||||
void setCategory(const QString &category) { m_category = category; }
|
||||
@@ -137,7 +137,7 @@ private:
|
||||
|
||||
QAction *m_action = nullptr;
|
||||
QIcon m_icon;
|
||||
QString m_fontIconCode;
|
||||
QString m_fontIconName;
|
||||
QString m_description;
|
||||
QString m_displayName;
|
||||
QString m_category;
|
||||
|
@@ -57,7 +57,7 @@ QString ProjectPart::projectFileLocation() const
|
||||
|
||||
bool ProjectPart::belongsToProject(const ProjectExplorer::Project *project) const
|
||||
{
|
||||
return project && topLevelProject == project->projectFilePath();
|
||||
return project ? topLevelProject == project->projectFilePath() : !hasProject();
|
||||
}
|
||||
|
||||
QByteArray ProjectPart::readProjectConfigFile(const QString &projectConfigFile)
|
||||
|
@@ -258,7 +258,7 @@ void McuPackage::setRelativePathModifier(const QString &path)
|
||||
m_relativePathModifier = path;
|
||||
}
|
||||
|
||||
void McuPackage::setVersions(const QVector<QString> &versions)
|
||||
void McuPackage::setVersions(const QStringList &versions)
|
||||
{
|
||||
m_versions = versions;
|
||||
}
|
||||
@@ -312,13 +312,14 @@ void McuPackage::updateStatusUi()
|
||||
QString McuPackage::statusText() const
|
||||
{
|
||||
const QString displayPackagePath = m_path.toUserOutput();
|
||||
const QString displayVersions = QStringList(m_versions.toList()).join(" or ");
|
||||
const QString displayRequiredPath = QString("%1 %2").arg(
|
||||
FilePath::fromString(m_detectionPath).toUserOutput(),
|
||||
displayVersions);
|
||||
const QString displayDetectedPath = QString("%1 %2").arg(
|
||||
FilePath::fromString(m_detectionPath).toUserOutput(),
|
||||
m_detectedVersion);
|
||||
const QString displayVersions = m_versions.join(" or ");
|
||||
const QString outDetectionPath = FilePath::fromString(m_detectionPath).toUserOutput();
|
||||
const QString displayRequiredPath = m_versions.empty() ?
|
||||
outDetectionPath :
|
||||
QString("%1 %2").arg(outDetectionPath, displayVersions);
|
||||
const QString displayDetectedPath = m_versions.empty() ?
|
||||
outDetectionPath :
|
||||
QString("%1 %2").arg(outDetectionPath, m_detectedVersion);
|
||||
|
||||
QString response;
|
||||
switch (m_status) {
|
||||
|
@@ -88,7 +88,7 @@ public:
|
||||
void writeGeneralSettings() const;
|
||||
bool writeToSettings() const;
|
||||
void setRelativePathModifier(const QString &path);
|
||||
void setVersions(const QVector<QString> &versions);
|
||||
void setVersions(const QStringList &versions);
|
||||
|
||||
bool automaticKitCreationEnabled() const;
|
||||
void setAutomaticKitCreationEnabled(const bool enabled);
|
||||
@@ -118,7 +118,7 @@ private:
|
||||
Utils::FilePath m_path;
|
||||
QString m_relativePathModifier; // relative path to m_path to be returned by path()
|
||||
QString m_detectedVersion;
|
||||
QVector<QString> m_versions;
|
||||
QStringList m_versions;
|
||||
QString m_downloadUrl;
|
||||
QString m_environmentVariableName;
|
||||
bool m_addToPath = false;
|
||||
|
@@ -341,13 +341,13 @@ struct McuTargetDescription
|
||||
} platform;
|
||||
struct {
|
||||
QString id;
|
||||
QVector<QString> versions;
|
||||
QStringList versions;
|
||||
} toolchain;
|
||||
struct {
|
||||
QString name;
|
||||
QString defaultPath;
|
||||
QString envVar;
|
||||
QVector<QString> versions;
|
||||
QStringList versions;
|
||||
} boardSdk;
|
||||
struct {
|
||||
QString envVar;
|
||||
@@ -658,10 +658,10 @@ static McuTargetDescription parseDescriptionJsonCommon(const QString &qulVersion
|
||||
const QJsonObject freeRTOS = target.value("freeRTOS").toObject();
|
||||
|
||||
const QVariantList toolchainVersions = toolchain.value("versions").toArray().toVariantList();
|
||||
const auto toolchainVersionsVector = Utils::transform<QVector<QString> >(
|
||||
const auto toolchainVersionsList = Utils::transform<QStringList>(
|
||||
toolchainVersions, [&](const QVariant &version) { return version.toString(); });
|
||||
const QVariantList boardSdkVersions = boardSdk.value("versions").toArray().toVariantList();
|
||||
const auto boardSdkVersionsVector = Utils::transform<QVector<QString> >(
|
||||
const auto boardSdkVersionsList = Utils::transform<QStringList>(
|
||||
boardSdkVersions, [&](const QVariant &version) { return version.toString(); });
|
||||
|
||||
return {
|
||||
@@ -670,13 +670,13 @@ static McuTargetDescription parseDescriptionJsonCommon(const QString &qulVersion
|
||||
{},
|
||||
{
|
||||
toolchain.value("id").toString(),
|
||||
toolchainVersionsVector,
|
||||
toolchainVersionsList,
|
||||
},
|
||||
{
|
||||
boardSdk.value("name").toString(),
|
||||
boardSdk.value("defaultPath").toString(),
|
||||
boardSdk.value("envVar").toString(),
|
||||
boardSdkVersionsVector,
|
||||
boardSdkVersionsList,
|
||||
},
|
||||
{
|
||||
freeRTOS.value("envVar").toString(),
|
||||
|
@@ -72,7 +72,7 @@ const char CATEGORY_NAME_KEY[] = "trDisplayCategory";
|
||||
const char DISPLAY_NAME_KEY[] = "trDisplayName";
|
||||
const char ICON_KEY[] = "icon";
|
||||
const char ICON_TEXT_KEY[] = "iconText";
|
||||
const char FONT_ICON_CODE_KEY[] = "fontIconCode";
|
||||
const char FONT_ICON_NAME_KEY[] = "fontIconName";
|
||||
const char IMAGE_KEY[] = "image";
|
||||
const char ICON_KIND_KEY[] = "iconKind";
|
||||
const char DESCRIPTION_KEY[] = "trDescription";
|
||||
@@ -743,8 +743,8 @@ bool JsonWizardFactory::initialize(const QVariantMap &data, const FilePath &base
|
||||
: QIcon(iconPath.toString()),
|
||||
iconText);
|
||||
|
||||
const QString fontIconCode = data.value(QLatin1String(FONT_ICON_CODE_KEY)).toString();
|
||||
setFontIconCode(fontIconCode);
|
||||
const QString fontIconName = data.value(QLatin1String(FONT_ICON_NAME_KEY)).toString();
|
||||
setFontIconName(fontIconName);
|
||||
|
||||
strVal = data.value(QLatin1String(IMAGE_KEY)).toString();
|
||||
if (!strVal.isEmpty()) {
|
||||
|
@@ -1,5 +1,10 @@
|
||||
<RCC>
|
||||
<qresource prefix="/boilerplatetemplates">
|
||||
<file>qmlprojectmaincpp.tpl</file>
|
||||
<file>qmlprojectmaincppheader.tpl</file>
|
||||
<file>qmlprojectmodules.tpl</file>
|
||||
<file>qmlprojectmaincmakelists.tpl</file>
|
||||
<file>qmlprojectmodulecmakelists.tpl</file>
|
||||
<file>qmlprojectmainqml.tpl</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -186,6 +186,11 @@ QString Theme::getIconUnicode(Theme::Icon i)
|
||||
return instance()->m_constants->property(e.valueToKey(i)).toString();
|
||||
}
|
||||
|
||||
QString Theme::getIconUnicode(const QString &name)
|
||||
{
|
||||
return instance()->m_constants->property(name.toStdString().data()).toString();
|
||||
}
|
||||
|
||||
QColor Theme::qmlDesignerBackgroundColorDarker() const
|
||||
{
|
||||
return getColor(QmlDesigner_BackgroundColorDarker);
|
||||
|
@@ -174,8 +174,7 @@ public:
|
||||
unpin,
|
||||
upDownIcon,
|
||||
upDownSquare2,
|
||||
visibilityOffBroken, // visibilityOff
|
||||
visibilityOff, // visibilityOff2
|
||||
visibilityOff,
|
||||
visibilityOn,
|
||||
wildcard,
|
||||
wizardsAutomotive,
|
||||
@@ -198,6 +197,7 @@ public:
|
||||
static QColor getColor(Color role);
|
||||
static QPixmap getPixmap(const QString &id);
|
||||
static QString getIconUnicode(Theme::Icon i);
|
||||
static QString getIconUnicode(const QString &name);
|
||||
|
||||
Q_INVOKABLE QColor qmlDesignerBackgroundColorDarker() const;
|
||||
Q_INVOKABLE QColor qmlDesignerBackgroundColorDarkAlternate() const;
|
||||
|
@@ -279,6 +279,7 @@ bool DesignDocument::isDocumentLoaded() const
|
||||
|
||||
void DesignDocument::resetToDocumentModel()
|
||||
{
|
||||
plainTextEdit()->document()->clearUndoRedoStacks();
|
||||
m_inFileComponentModel.reset();
|
||||
}
|
||||
|
||||
@@ -310,6 +311,8 @@ void DesignDocument::changeToDocumentModel()
|
||||
viewManager().detachRewriterView();
|
||||
viewManager().detachViewsExceptRewriterAndComponetView();
|
||||
|
||||
plainTextEdit()->document()->clearUndoRedoStacks();
|
||||
|
||||
m_inFileComponentModel.reset();
|
||||
m_inFileComponentTextModifier.reset();
|
||||
|
||||
@@ -345,6 +348,8 @@ void DesignDocument::changeToInFileComponentModel(ComponentTextModifier *textMod
|
||||
viewManager().detachRewriterView();
|
||||
viewManager().detachViewsExceptRewriterAndComponetView();
|
||||
|
||||
plainTextEdit()->document()->clearUndoRedoStacks();
|
||||
|
||||
m_inFileComponentModel.reset(createInFileComponentModel());
|
||||
m_inFileComponentModel->setTextModifier(m_inFileComponentTextModifier.data());
|
||||
|
||||
|
@@ -160,40 +160,65 @@ void ComponentTextModifier::handleOriginalTextChanged()
|
||||
|
||||
const QString currentText = m_originalModifier->text();
|
||||
|
||||
// Adjust for removal/addition of whitespace in the document
|
||||
// Check that non-whitespace portion of the text is the same and count the whitespace diff
|
||||
const int oldLen = m_originalText.size();
|
||||
const int newLen = currentText.size();
|
||||
int newSpace = 0;
|
||||
int oldSpace = 0;
|
||||
int newIdx = 0;
|
||||
for (int oldIdx = 0; oldIdx < oldLen; ++oldIdx) {
|
||||
const QChar oldChar = m_originalText[oldIdx];
|
||||
if (oldIdx == m_componentStartOffset)
|
||||
m_componentStartOffset += newSpace - oldSpace;
|
||||
if (oldIdx == m_componentEndOffset) {
|
||||
m_componentEndOffset += newSpace - oldSpace;
|
||||
break;
|
||||
|
||||
if (oldLen != newLen) {
|
||||
int newSpace = 0;
|
||||
int oldSpace = 0;
|
||||
int newIdx = 0;
|
||||
int nonWhiteSpaceChangeIdx = -1;
|
||||
int newStartOffset = m_componentStartOffset;
|
||||
|
||||
// Adjust for removal/addition of whitespace in the document.
|
||||
// Whitespace changes that happen when document is saved can be spread around throughout
|
||||
// the entire document in multiple places.
|
||||
// Check that non-whitespace portion of the text is the same and count the whitespace diff
|
||||
for (int oldIdx = 0; oldIdx < oldLen; ++oldIdx) {
|
||||
const QChar oldChar = m_originalText[oldIdx];
|
||||
if (oldIdx == m_componentStartOffset)
|
||||
newStartOffset += newSpace - oldSpace;
|
||||
if (oldIdx == m_componentEndOffset) {
|
||||
m_componentEndOffset += newSpace - oldSpace;
|
||||
m_componentStartOffset = newStartOffset;
|
||||
m_originalText = currentText;
|
||||
break;
|
||||
}
|
||||
|
||||
while (newIdx < newLen && currentText[newIdx].isSpace()) {
|
||||
++newSpace;
|
||||
++newIdx;
|
||||
}
|
||||
|
||||
if (oldChar.isSpace()) {
|
||||
++oldSpace;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentText[newIdx] != oldChar) {
|
||||
nonWhiteSpaceChangeIdx = oldIdx;
|
||||
// A non-whitespace change is a result of manual text edit or undo/redo operation.
|
||||
// Assumption is that separate whitespace changes and a non-whitespace change can't
|
||||
// both happen simultaneously, so break out of whitespace check loop.
|
||||
break;
|
||||
} else {
|
||||
++newIdx;
|
||||
}
|
||||
}
|
||||
|
||||
while (newIdx < newLen && currentText[newIdx].isSpace()) {
|
||||
++newSpace;
|
||||
++newIdx;
|
||||
if (nonWhiteSpaceChangeIdx >= 0) {
|
||||
// For non-whitespace change, we assume the whole change is either before the component
|
||||
// or inside the component. If the change spans both, it's likely the change is
|
||||
// invalid anyway, and we don't care about trying to keep offsets up to date.
|
||||
int diff = newLen - oldLen;
|
||||
if (nonWhiteSpaceChangeIdx < m_componentEndOffset)
|
||||
m_componentEndOffset += diff;
|
||||
if (nonWhiteSpaceChangeIdx < m_componentStartOffset)
|
||||
m_componentStartOffset += diff;
|
||||
m_originalText = currentText;
|
||||
}
|
||||
|
||||
if (oldChar.isSpace()) {
|
||||
++oldSpace;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentText[newIdx] != oldChar) {
|
||||
// Non-whitespace difference, we can't determine a valid offset in this case
|
||||
// TODO: Needs proper handling to deal with undo/redo/arbitrary edits somehow (QDS-5392)
|
||||
break;
|
||||
} else {
|
||||
++newIdx;
|
||||
}
|
||||
}
|
||||
m_originalText = currentText;
|
||||
|
||||
emit textChanged();
|
||||
}
|
||||
|
@@ -66,6 +66,7 @@ const char NAVIGATOR_REVERSE_ITEM_ORDER[] = "NavigatorReverseItemOrder";
|
||||
const char REFORMAT_UI_QML_FILES[] = "ReformatUiQmlFiles"; /* These settings are not exposed in ui. */
|
||||
const char IGNORE_DEVICE_PIXEL_RATIO[] = "IgnoreDevicePixelRaio"; /* The settings can be used to turn off the feature, if there are serious issues */
|
||||
const char STANDALONE_MODE[] = "StandAloneMode";
|
||||
const char SHOW_DEBUG_SETTINGS[] = "ShowDebugSettings";
|
||||
const char ENABLE_TIMELINEVIEW[] = "EnableTimelineView";
|
||||
const char COLOR_PALETTE_RECENT[] = "ColorPaletteRecent";
|
||||
const char COLOR_PALETTE_FAVORITE[] = "ColorPaletteFavorite";
|
||||
|
@@ -78,7 +78,7 @@ void onGenerateCmakeLists()
|
||||
{
|
||||
queuedFiles.clear();
|
||||
FilePath rootDir = ProjectExplorer::SessionManager::startupProject()->projectDirectory();
|
||||
GenerateCmakeLists::generateMainCmake(rootDir);
|
||||
GenerateCmakeLists::generateCmakes(rootDir);
|
||||
GenerateEntryPoints::generateMainCpp(rootDir);
|
||||
GenerateEntryPoints::generateMainQml(rootDir);
|
||||
if (showConfirmationDialog(rootDir))
|
||||
@@ -139,138 +139,125 @@ bool writeFile(const GeneratableFile &file)
|
||||
return true;
|
||||
}
|
||||
|
||||
QString readTemplate(const QString &templatePath)
|
||||
{
|
||||
QFile templatefile(templatePath);
|
||||
templatefile.open(QIODevice::ReadOnly);
|
||||
QTextStream stream(&templatefile);
|
||||
QString content = stream.readAll();
|
||||
templatefile.close();
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace GenerateCmakeLists {
|
||||
|
||||
QStringList moduleNames;
|
||||
|
||||
const QDir::Filters FILES_ONLY = QDir::Files;
|
||||
const QDir::Filters DIRS_ONLY = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot;
|
||||
|
||||
const char CMAKEFILENAME[] = "CMakeLists.txt";
|
||||
const char QMLDIRFILENAME[] = "qmldir";
|
||||
const char MODULEFILENAME[] = "qmlmodules";
|
||||
|
||||
QStringList processDirectory(const FilePath &dir)
|
||||
bool generateCmakes(const FilePath &rootDir)
|
||||
{
|
||||
QStringList moduleNames;
|
||||
moduleNames.clear();
|
||||
|
||||
FilePaths files = dir.dirEntries(FILES_ONLY);
|
||||
for (FilePath &file : files) {
|
||||
if (!file.fileName().compare(CMAKEFILENAME))
|
||||
files.removeAll(file);
|
||||
}
|
||||
FilePath contentDir = rootDir.pathAppended("content");
|
||||
FilePath importDir = rootDir.pathAppended("imports");
|
||||
|
||||
if (files.isEmpty()) {
|
||||
generateSubdirCmake(dir);
|
||||
FilePaths subDirs = dir.dirEntries(DIRS_ONLY);
|
||||
for (FilePath &subDir : subDirs) {
|
||||
QStringList subDirModules = processDirectory(subDir);
|
||||
moduleNames.append(subDirModules);
|
||||
}
|
||||
}
|
||||
else {
|
||||
QString moduleName = generateModuleCmake(dir);
|
||||
if (!moduleName.isEmpty()) {
|
||||
moduleNames.append(moduleName);
|
||||
}
|
||||
}
|
||||
generateModuleCmake(contentDir);
|
||||
generateImportCmake(importDir);
|
||||
generateMainCmake(rootDir);
|
||||
|
||||
return moduleNames;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char MAINFILE_REQUIRED_VERSION[] = "cmake_minimum_required(VERSION 3.18)\n\n";
|
||||
const char MAINFILE_PROJECT[] = "project(%1 LANGUAGES CXX)\n\n";
|
||||
const char MAINFILE_CMAKE_OPTIONS[] = "set(CMAKE_INCLUDE_CURRENT_DIR ON)\nset(CMAKE_AUTOMOC ON)\n\n";
|
||||
const char MAINFILE_PACKAGES[] = "find_package(Qt6 COMPONENTS Gui Qml Quick)\n";
|
||||
const char MAINFILE_LIBRARIES[] = "set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)\n\n";
|
||||
const char MAINFILE_CPP[] = "add_executable(%1 main.cpp)\n\n";
|
||||
const char MAINFILE_MAINMODULE[] = "qt6_add_qml_module(%1\n\tURI \"Main\"\n\tVERSION 1.0\n\tNO_PLUGIN\n\tQML_FILES main.qml\n)\n\n";
|
||||
const char MAINFILE_LINK_LIBRARIES[] = "target_link_libraries(%1 PRIVATE\n\tQt${QT_VERSION_MAJOR}::Core\n\tQt${QT_VERSION_MAJOR}::Gui\n\tQt${QT_VERSION_MAJOR}::Quick\n\tQt${QT_VERSION_MAJOR}::Qml\n)\n\n";
|
||||
|
||||
const char ADD_SUBDIR[] = "add_subdirectory(%1)\n";
|
||||
const char MAIN_CMAKEFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincmakelists.tpl";
|
||||
const char QMLMODULES_FILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmodules.tpl";
|
||||
|
||||
void generateMainCmake(const FilePath &rootDir)
|
||||
{
|
||||
//TODO startupProject() may be a terrible way to try to get "current project". It's not necessarily the same thing at all.
|
||||
QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName();
|
||||
QString appName = projectName + "App";
|
||||
|
||||
FilePaths subDirs = rootDir.dirEntries(DIRS_ONLY);
|
||||
QString cmakeFileContent = GenerateCmake::readTemplate(MAIN_CMAKEFILE_TEMPLATE_PATH).arg(appName);
|
||||
queueCmakeFile(rootDir, cmakeFileContent);
|
||||
|
||||
QString modulesAsPlugins;
|
||||
for (const QString &moduleName : moduleNames)
|
||||
modulesAsPlugins.append(" " + moduleName + "plugin\n");
|
||||
|
||||
QString moduleFileContent = GenerateCmake::readTemplate(QMLMODULES_FILE_TEMPLATE_PATH).arg(appName).arg(modulesAsPlugins);
|
||||
GenerateCmake::queueFile(rootDir.pathAppended(MODULEFILENAME), moduleFileContent);
|
||||
}
|
||||
|
||||
const char DO_NOT_EDIT_FILE_COMMENT[] = "### This file is automatically generated by Qt Design Studio.\n### Do not change\n\n";
|
||||
const char ADD_SUBDIR[] = "add_subdirectory(%1)\n";
|
||||
|
||||
void generateImportCmake(const FilePath &dir)
|
||||
{
|
||||
QString fileContent;
|
||||
fileContent.append(MAINFILE_REQUIRED_VERSION);
|
||||
fileContent.append(QString(MAINFILE_PROJECT).arg(projectName));
|
||||
fileContent.append(MAINFILE_CMAKE_OPTIONS);
|
||||
fileContent.append(MAINFILE_PACKAGES);
|
||||
fileContent.append(QString(MAINFILE_CPP).arg(projectName));
|
||||
fileContent.append(QString(MAINFILE_MAINMODULE).arg(projectName));
|
||||
fileContent.append(MAINFILE_LIBRARIES);
|
||||
|
||||
fileContent.append(DO_NOT_EDIT_FILE_COMMENT);
|
||||
|
||||
FilePaths subDirs = dir.dirEntries(DIRS_ONLY);
|
||||
for (FilePath &subDir : subDirs) {
|
||||
QStringList subDirModules = processDirectory(subDir);
|
||||
if (!subDirModules.isEmpty())
|
||||
fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName()));
|
||||
fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName()));
|
||||
generateModuleCmake(subDir);
|
||||
}
|
||||
fileContent.append("\n");
|
||||
|
||||
fileContent.append(QString(MAINFILE_LINK_LIBRARIES).arg(projectName));
|
||||
|
||||
createCmakeFile(rootDir, fileContent);
|
||||
queueCmakeFile(dir, fileContent);
|
||||
}
|
||||
|
||||
const char MODULEFILE_PROPERTY_SINGLETON[] = "QT_QML_SINGLETON_TYPE";
|
||||
const char MODULEFILE_PROPERTY_SET[] = "set_source_files_properties(%1\n\tPROPERTIES\n\t\t%2 %3\n)\n\n";
|
||||
const char MODULEFILE_CREATE_MODULE[] = "qt6_add_qml_module(%1\n\tURI \"%1\"\n\tVERSION 1.0\n%2)\n\n";
|
||||
const char MODULEFILE_PROPERTY_SET[] = "set_source_files_properties(%1\n PROPERTIES\n %2 %3\n)\n\n";
|
||||
const char MODULEFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmodulecmakelists.tpl";
|
||||
|
||||
|
||||
QString generateModuleCmake(const FilePath &dir)
|
||||
void generateModuleCmake(const FilePath &dir)
|
||||
{
|
||||
QString fileContent;
|
||||
QString fileTemplate = GenerateCmake::readTemplate(MODULEFILE_TEMPLATE_PATH);
|
||||
const QStringList qmldirFilesOnly(QMLDIRFILENAME);
|
||||
|
||||
QString singletonContent;
|
||||
FilePaths qmldirFileList = dir.dirEntries(qmldirFilesOnly, FILES_ONLY);
|
||||
if (!qmldirFileList.isEmpty()) {
|
||||
QStringList singletons = getSingletonsFromQmldirFile(qmldirFileList.first());
|
||||
for (QString &singleton : singletons) {
|
||||
fileContent.append(QString(MODULEFILE_PROPERTY_SET).arg(singleton).arg(MODULEFILE_PROPERTY_SINGLETON).arg("true"));
|
||||
singletonContent.append(QString(MODULEFILE_PROPERTY_SET).arg(singleton).arg(MODULEFILE_PROPERTY_SINGLETON).arg("true"));
|
||||
}
|
||||
}
|
||||
|
||||
QStringList qmlFileList = getDirectoryTreeQmls(dir);
|
||||
QString qmlFiles;
|
||||
for (QString &qmlFile : qmlFileList)
|
||||
qmlFiles.append(QString("\t\t%1\n").arg(qmlFile));
|
||||
qmlFiles.append(QString(" %1\n").arg(qmlFile));
|
||||
|
||||
QStringList resourceFileList = getDirectoryTreeResources(dir);
|
||||
QString resourceFiles;
|
||||
for (QString &resourceFile : resourceFileList)
|
||||
resourceFiles.append(QString("\t\t%1\n").arg(resourceFile));
|
||||
resourceFiles.append(QString(" %1\n").arg(resourceFile));
|
||||
|
||||
QString moduleContent;
|
||||
if (!qmlFiles.isEmpty()) {
|
||||
moduleContent.append(QString("\tQML_FILES\n%1").arg(qmlFiles));
|
||||
moduleContent.append(QString(" QML_FILES\n%1").arg(qmlFiles));
|
||||
}
|
||||
if (!resourceFiles.isEmpty()) {
|
||||
moduleContent.append(QString("\tRESOURCES\n%1").arg(resourceFiles));
|
||||
moduleContent.append(QString(" RESOURCES\n%1").arg(resourceFiles));
|
||||
}
|
||||
|
||||
QString moduleName = dir.fileName();
|
||||
|
||||
fileContent.append(QString(MODULEFILE_CREATE_MODULE).arg(moduleName).arg(moduleContent));
|
||||
moduleNames.append(moduleName);
|
||||
|
||||
createCmakeFile(dir, fileContent);
|
||||
|
||||
return moduleName;
|
||||
}
|
||||
|
||||
void generateSubdirCmake(const FilePath &dir)
|
||||
{
|
||||
QString fileContent;
|
||||
FilePaths subDirs = dir.dirEntries(DIRS_ONLY);
|
||||
|
||||
for (FilePath &subDir : subDirs) {
|
||||
fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName()));
|
||||
}
|
||||
|
||||
createCmakeFile(dir, fileContent);
|
||||
fileContent.append(fileTemplate.arg(singletonContent).arg(moduleName).arg(moduleContent));
|
||||
queueCmakeFile(dir, fileContent);
|
||||
}
|
||||
|
||||
QStringList getSingletonsFromQmldirFile(const FilePath &filePath)
|
||||
@@ -347,7 +334,7 @@ QStringList getDirectoryTreeResources(const FilePath &dir)
|
||||
return resourceFileList;
|
||||
}
|
||||
|
||||
void createCmakeFile(const FilePath &dir, const QString &content)
|
||||
void queueCmakeFile(const FilePath &dir, const QString &content)
|
||||
{
|
||||
FilePath filePath = dir.pathAppended(CMAKEFILENAME);
|
||||
GenerateCmake::queueFile(filePath, content);
|
||||
@@ -370,35 +357,42 @@ bool generateEntryPointFiles(const FilePath &dir)
|
||||
return cppOk && qmlOk;
|
||||
}
|
||||
|
||||
const char MAIN_CPPFILE_CONTENT[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl";
|
||||
const char MAIN_CPPFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl";
|
||||
const char MAIN_CPPFILE_DIR[] = "src";
|
||||
const char MAIN_CPPFILE_NAME[] = "main.cpp";
|
||||
const char MAIN_CPPFILE_HEADER_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincppheader.tpl";
|
||||
const char MAIN_CPPFILE_HEADER_NAME[] = "import_qml_plugins.h";
|
||||
const char MAIN_CPPFILE_HEADER_PLUGIN_LINE[] = "Q_IMPORT_QML_PLUGIN(%1)\n";
|
||||
|
||||
bool generateMainCpp(const FilePath &dir)
|
||||
{
|
||||
QFile templatefile(MAIN_CPPFILE_CONTENT);
|
||||
templatefile.open(QIODevice::ReadOnly);
|
||||
QTextStream stream(&templatefile);
|
||||
QString content = stream.readAll();
|
||||
templatefile.close();
|
||||
FilePath srcDir = dir.pathAppended(MAIN_CPPFILE_DIR);
|
||||
|
||||
FilePath filePath = dir.pathAppended(MAIN_CPPFILE_NAME);
|
||||
return GenerateCmake::queueFile(filePath, content);
|
||||
QString cppContent = GenerateCmake::readTemplate(MAIN_CPPFILE_TEMPLATE_PATH);
|
||||
FilePath cppFilePath = srcDir.pathAppended(MAIN_CPPFILE_NAME);
|
||||
bool cppOk = GenerateCmake::queueFile(cppFilePath, cppContent);
|
||||
|
||||
QString modulesAsPlugins;
|
||||
for (const QString &moduleName : GenerateCmakeLists::moduleNames)
|
||||
modulesAsPlugins.append(
|
||||
QString(MAIN_CPPFILE_HEADER_PLUGIN_LINE).arg(moduleName + "plugin"));
|
||||
|
||||
QString headerContent = GenerateCmake::readTemplate(MAIN_CPPFILE_HEADER_TEMPLATE_PATH)
|
||||
.arg(modulesAsPlugins);
|
||||
FilePath headerFilePath = srcDir.pathAppended(MAIN_CPPFILE_HEADER_NAME);
|
||||
bool headerOk = GenerateCmake::queueFile(headerFilePath, headerContent);
|
||||
|
||||
return cppOk && headerOk;
|
||||
}
|
||||
|
||||
const char MAIN_QMLFILE_CONTENT[] = "import %1Qml\n\n%2 {\n}\n";
|
||||
const char MAIN_QMLFILE_PATH[] = ":/boilerplatetemplates/qmlprojectmainqml.tpl";
|
||||
const char MAIN_QMLFILE_NAME[] = "main.qml";
|
||||
|
||||
bool generateMainQml(const FilePath &dir)
|
||||
{
|
||||
QString content = GenerateCmake::readTemplate(MAIN_QMLFILE_PATH);
|
||||
FilePath filePath = dir.pathAppended(MAIN_QMLFILE_NAME);
|
||||
QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName();
|
||||
ProjectExplorer::RunConfiguration *runConfiguration = ProjectExplorer::SessionManager::startupRunConfiguration();
|
||||
QString mainClass;
|
||||
|
||||
if (const auto aspect = runConfiguration->aspect<QmlProjectManager::QmlMainFileAspect>())
|
||||
mainClass = FilePath::fromString(aspect->mainScript()).baseName();
|
||||
|
||||
return GenerateCmake::queueFile(filePath, QString(MAIN_QMLFILE_CONTENT).arg(projectName).arg(mainClass));
|
||||
return GenerateCmake::queueFile(filePath, content);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -45,16 +45,17 @@ bool showConfirmationDialog(const Utils::FilePath &rootDir);
|
||||
bool queueFile(const Utils::FilePath &filePath, const QString &fileContent);
|
||||
bool writeFile(const GeneratableFile &file);
|
||||
bool writeQueuedFiles();
|
||||
QString readTemplate(const QString &templatePath);
|
||||
}
|
||||
namespace GenerateCmakeLists {
|
||||
bool generateCmakes(const Utils::FilePath &rootDir);
|
||||
void generateMainCmake(const Utils::FilePath &rootDir);
|
||||
void generateSubdirCmake(const Utils::FilePath &dir);
|
||||
QString generateModuleCmake(const Utils::FilePath &dir);
|
||||
QStringList processDirectory(const Utils::FilePath &dir);
|
||||
void generateImportCmake(const Utils::FilePath &dir);
|
||||
void generateModuleCmake(const Utils::FilePath &dir);
|
||||
QStringList getSingletonsFromQmldirFile(const Utils::FilePath &filePath);
|
||||
QStringList getDirectoryTreeQmls(const Utils::FilePath &dir);
|
||||
QStringList getDirectoryTreeResources(const Utils::FilePath &dir);
|
||||
void createCmakeFile(const Utils::FilePath &filePath, const QString &content);
|
||||
void queueCmakeFile(const Utils::FilePath &filePath, const QString &content);
|
||||
bool isFileBlacklisted(const QString &fileName);
|
||||
}
|
||||
namespace GenerateEntryPoints {
|
||||
|
19
src/plugins/qmldesigner/qmlprojectmaincmakelists.tpl
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
project(%1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
find_package(Qt6 COMPONENTS Gui Qml Quick)
|
||||
add_executable(%1 src/main.cpp)
|
||||
|
||||
target_link_libraries(%1 PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Core
|
||||
Qt${QT_VERSION_MAJOR}::Gui
|
||||
Qt${QT_VERSION_MAJOR}::Quick
|
||||
Qt${QT_VERSION_MAJOR}::Qml
|
||||
)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules)
|
||||
|
8
src/plugins/qmldesigner/qmlprojectmaincppheader.tpl
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* This file is automatically generated by Qt Design Studio.
|
||||
* Do not change.
|
||||
*/
|
||||
|
||||
#include <QtQml/qqmlextensionplugin.h>
|
||||
|
||||
%1
|
6
src/plugins/qmldesigner/qmlprojectmainqml.tpl
Normal file
@@ -0,0 +1,6 @@
|
||||
import QtQuick
|
||||
import content
|
||||
|
||||
App {
|
||||
}
|
||||
|
11
src/plugins/qmldesigner/qmlprojectmodulecmakelists.tpl
Normal file
@@ -0,0 +1,11 @@
|
||||
### This file is automatically generated by Qt Design Studio.
|
||||
### Do not change
|
||||
|
||||
%1
|
||||
|
||||
qt_add_library(%2 STATIC)
|
||||
qt6_add_qml_module(%2
|
||||
URI "%2"
|
||||
VERSION 1.0
|
||||
%3
|
||||
)
|
16
src/plugins/qmldesigner/qmlprojectmodules.tpl
Normal file
@@ -0,0 +1,16 @@
|
||||
### This file is automatically generated by Qt Design Studio.
|
||||
### Do not change
|
||||
|
||||
qt6_add_qml_module(%1
|
||||
URI "Main"
|
||||
VERSION 1.0
|
||||
NO_PLUGIN
|
||||
QML_FILES main.qml
|
||||
)
|
||||
|
||||
add_subdirectory(content)
|
||||
add_subdirectory(imports)
|
||||
|
||||
target_link_libraries(%1 PRIVATE
|
||||
%2
|
||||
)
|
@@ -252,10 +252,14 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings)
|
||||
m_ui.askBeforeDeletingAssetCheckBox->setChecked(settings.value(
|
||||
DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET).toBool());
|
||||
|
||||
if (settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool()) {
|
||||
m_ui.debugGroupBox->hide();
|
||||
m_ui.featureTimelineEditorCheckBox->hide();
|
||||
}
|
||||
const auto standaloneMode = settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool();
|
||||
#ifdef QT_DEBUG
|
||||
const auto showDebugSettings = true;
|
||||
#else
|
||||
const auto showDebugSettings = settings.value(DesignerSettingsKey::SHOW_DEBUG_SETTINGS).toBool();
|
||||
#endif
|
||||
m_ui.debugGroupBox->setVisible(!standaloneMode || showDebugSettings);
|
||||
m_ui.featureTimelineEditorCheckBox->setVisible(standaloneMode);
|
||||
}
|
||||
|
||||
void SettingsPageWidget::apply()
|
||||
|
@@ -199,7 +199,7 @@ bool QmlProjectPlugin::initialize(const QStringList &, QString *errorMessage)
|
||||
info(openInQDSAppSetting,
|
||||
description + tr(" Learn more about Qt Design Studio here: ")
|
||||
+ "<a href='https://www.qt.io/product/ui-design-tools'>Qt Design Studio</a>",
|
||||
Utils::InfoBarEntry::GlobalSuppression::Enabled);
|
||||
Utils::InfoBarEntry::GlobalSuppression::Disabled);
|
||||
Core::ICore::infoBar()->addInfo(info);
|
||||
}
|
||||
return;
|
||||
@@ -209,7 +209,7 @@ bool QmlProjectPlugin::initialize(const QStringList &, QString *errorMessage)
|
||||
Utils::InfoBarEntry
|
||||
info(openInQDSAppSetting,
|
||||
description + "\n" + tr("Do you want to open this file in Qt Design Studio?"),
|
||||
Utils::InfoBarEntry::GlobalSuppression::Enabled);
|
||||
Utils::InfoBarEntry::GlobalSuppression::Disabled);
|
||||
info.setCustomButtonInfo(tr("Open in Qt Design Studio"), [filePath] {
|
||||
Core::ICore::infoBar()->removeInfo(openInQDSAppSetting);
|
||||
|
||||
|
@@ -353,6 +353,10 @@ bool StudioWelcomePlugin::initialize(const QStringList &arguments, QString *erro
|
||||
void StudioWelcomePlugin::extensionsInitialized()
|
||||
{
|
||||
Core::ModeManager::activateMode(m_welcomeMode->id());
|
||||
|
||||
// Enable QDS new project dialog
|
||||
Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); });
|
||||
|
||||
if (Utils::CheckableMessageBox::shouldAskAgain(Core::ICore::settings(),
|
||||
DO_NOT_SHOW_SPLASHSCREEN_AGAIN_KEY)) {
|
||||
connect(Core::ICore::instance(), &Core::ICore::coreOpened, this, [this] {
|
||||
@@ -370,8 +374,6 @@ void StudioWelcomePlugin::extensionsInitialized()
|
||||
s_view->setSource(QUrl("qrc:/qml/splashscreen/main.qml"));
|
||||
#endif
|
||||
|
||||
// disabled by default
|
||||
Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); });
|
||||
|
||||
QTC_ASSERT(s_view->rootObject(),
|
||||
qWarning() << "The StudioWelcomePlugin has a runtime depdendency on "
|
||||
|
@@ -28,11 +28,7 @@
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include "wizardfactories.h"
|
||||
|
||||
namespace {
|
||||
// TODO: should be extern, check coreplugin/dialogs/newdialogwidget.cpp
|
||||
const char BLACKLISTED_CATEGORIES_KEY[] = "Core/NewDialog/BlacklistedCategories";
|
||||
}
|
||||
#include <qmldesigner/components/componentcore/theme.h>
|
||||
|
||||
using namespace StudioWelcome;
|
||||
|
||||
@@ -41,9 +37,6 @@ WizardFactories::WizardFactories(QList<Core::IWizardFactory *> &factories, QWidg
|
||||
, m_platform{platform}
|
||||
, m_factories{factories}
|
||||
{
|
||||
QVariant value = Core::ICore::settings()->value(BLACKLISTED_CATEGORIES_KEY);
|
||||
m_blacklist = Utils::Id::fromStringList(value.toStringList());
|
||||
|
||||
sortByCategoryAndId();
|
||||
filter();
|
||||
m_projectItems = makeProjectItemsGroupedByCategory();
|
||||
@@ -65,10 +58,10 @@ void WizardFactories::filter()
|
||||
// TODO: perhaps I could use Utils::filtered here.
|
||||
std::copy_if(std::begin(m_factories), std::end(m_factories), std::back_inserter(acceptedFactories),
|
||||
[&](auto *wizard) {
|
||||
return wizard->isAvailable(m_platform)
|
||||
&& wizard->kind() == Core::IWizardFactory::ProjectWizard
|
||||
&& !m_blacklist.contains(Utils::Id::fromString(wizard->category()));
|
||||
});
|
||||
return wizard->isAvailable(m_platform)
|
||||
&& wizard->kind() == Core::IWizardFactory::ProjectWizard
|
||||
&& wizard->requiredFeatures().contains("QtStudio");
|
||||
});
|
||||
|
||||
m_factories = acceptedFactories;
|
||||
}
|
||||
@@ -83,7 +76,7 @@ ProjectItem WizardFactories::makeProjectItem(Core::IWizardFactory *f, QWidget *p
|
||||
/*.categoryId =*/f->category(),
|
||||
/*. description =*/f->description(),
|
||||
/*.qmlPath =*/f->detailsPageQmlPath(),
|
||||
/*.fontIconCode =*/f->fontIcondCode(),
|
||||
/*.fontIconCode =*/QmlDesigner::Theme::getIconUnicode(f->fontIconName()),
|
||||
/*.create =*/ std::bind(&Core::IWizardFactory::runWizard, f, _1, parent, platform,
|
||||
QVariantMap(), false),
|
||||
};
|
||||
|
@@ -55,7 +55,6 @@ private:
|
||||
std::map<QString, ProjectCategory> makeProjectItemsGroupedByCategory();
|
||||
|
||||
private:
|
||||
QSet<Utils::Id> m_blacklist;
|
||||
QWidget *m_wizardParent;
|
||||
Utils::Id m_platform;
|
||||
|
||||
|
@@ -651,7 +651,7 @@ void TextDocument::setFilePath(const Utils::FilePath &newName)
|
||||
{
|
||||
if (newName == filePath())
|
||||
return;
|
||||
IDocument::setFilePath(newName.absoluteFilePath());
|
||||
IDocument::setFilePath(newName.absoluteFilePath().cleanPath());
|
||||
}
|
||||
|
||||
IDocument::ReloadBehavior TextDocument::reloadBehavior(ChangeTrigger state, ChangeType type) const
|
||||
|
@@ -189,14 +189,14 @@ public:
|
||||
// Navigation
|
||||
QAction *m_goBack = nullptr;
|
||||
QAction *m_goNext = nullptr;
|
||||
QLineEdit *m_searchFilter = nullptr;
|
||||
QPointer<QLineEdit> m_searchFilter = nullptr;
|
||||
|
||||
// Cost formatting
|
||||
QAction *m_filterProjectCosts = nullptr;
|
||||
QAction *m_costAbsolute = nullptr;
|
||||
QAction *m_costRelative = nullptr;
|
||||
QAction *m_costRelativeToParent = nullptr;
|
||||
QComboBox *m_eventCombo = nullptr;
|
||||
QPointer<QComboBox> m_eventCombo;
|
||||
|
||||
QTimer m_updateTimer;
|
||||
|
||||
@@ -546,8 +546,10 @@ void CallgrindToolPrivate::setBusyCursor(bool busy)
|
||||
void CallgrindToolPrivate::selectFunction(const Function *func)
|
||||
{
|
||||
if (!func) {
|
||||
m_flatView->clearSelection();
|
||||
m_visualization->setFunction(nullptr);
|
||||
if (m_flatView)
|
||||
m_flatView->clearSelection();
|
||||
if (m_visualization)
|
||||
m_visualization->setFunction(nullptr);
|
||||
m_callersModel.clear();
|
||||
m_calleesModel.clear();
|
||||
return;
|
||||
@@ -555,15 +557,18 @@ void CallgrindToolPrivate::selectFunction(const Function *func)
|
||||
|
||||
const QModelIndex index = m_dataModel.indexForObject(func);
|
||||
const QModelIndex proxyIndex = m_proxyModel.mapFromSource(index);
|
||||
m_flatView->selectionModel()->clearSelection();
|
||||
m_flatView->selectionModel()->setCurrentIndex(proxyIndex,
|
||||
QItemSelectionModel::ClearAndSelect |
|
||||
QItemSelectionModel::Rows);
|
||||
m_flatView->scrollTo(proxyIndex);
|
||||
if (m_flatView) {
|
||||
m_flatView->selectionModel()->clearSelection();
|
||||
m_flatView->selectionModel()->setCurrentIndex(proxyIndex,
|
||||
QItemSelectionModel::ClearAndSelect |
|
||||
QItemSelectionModel::Rows);
|
||||
m_flatView->scrollTo(proxyIndex);
|
||||
}
|
||||
|
||||
m_callersModel.setCalls(func->incomingCalls(), func);
|
||||
m_calleesModel.setCalls(func->outgoingCalls(), func);
|
||||
m_visualization->setFunction(func);
|
||||
if (m_visualization)
|
||||
m_visualization->setFunction(func);
|
||||
|
||||
const Function *item = m_stackBrowser.current();
|
||||
if (!item || item != func)
|
||||
@@ -689,7 +694,8 @@ void CallgrindToolPrivate::visualisationFunctionSelected(const Function *functio
|
||||
void CallgrindToolPrivate::setParseData(ParseData *data)
|
||||
{
|
||||
// we have new parse data, invalidate filters in the proxy model
|
||||
m_visualization->setFunction(nullptr);
|
||||
if (m_visualization)
|
||||
m_visualization->setFunction(nullptr);
|
||||
|
||||
// invalidate parse data in the data model
|
||||
delete m_dataModel.parseData();
|
||||
@@ -705,7 +711,8 @@ void CallgrindToolPrivate::setParseData(ParseData *data)
|
||||
m_calleesModel.setParseData(data);
|
||||
m_callersModel.setParseData(data);
|
||||
|
||||
updateEventCombo();
|
||||
if (m_eventCombo)
|
||||
updateEventCombo();
|
||||
|
||||
// clear history for new data
|
||||
m_stackBrowser.clear();
|
||||
|