Merge remote-tracking branch 'origin/4.2'
Change-Id: Ied7c5b01ade2a71e92541fcced2935adcf143421
142
dist/changes-4.2.0.md
vendored
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
Qt Creator version 4.2 contains bug fixes and new features.
|
||||||
|
|
||||||
|
The most important changes are listed in this document. For a complete
|
||||||
|
list of changes, see the Git log for the Qt Creator sources that
|
||||||
|
you can check out from the public Git repository. For example:
|
||||||
|
|
||||||
|
git clone git://code.qt.io/qt-creator/qt-creator.git
|
||||||
|
git log --cherry-pick --pretty=oneline origin/4.1..v4.2.0
|
||||||
|
|
||||||
|
General
|
||||||
|
|
||||||
|
* Added experimental editor for Qt SCXML
|
||||||
|
* Added pattern substitution for variable expansion
|
||||||
|
`%{variable/pattern/replacement}` (and `%{variable//pattern/replacement}`
|
||||||
|
for replacing multiple matches)
|
||||||
|
* Added default values for variable expansion (`%{variable:-default}`)
|
||||||
|
* Added Help > System Information for bug reporting purposes
|
||||||
|
(QTCREATORBUG-16135)
|
||||||
|
* Added option to hide the central widget in Debug mode
|
||||||
|
|
||||||
|
Welcome
|
||||||
|
|
||||||
|
* Added keyboard shortcuts for opening recent sessions and projects
|
||||||
|
* Improved performance when many sessions are shown
|
||||||
|
|
||||||
|
Editing
|
||||||
|
|
||||||
|
* Added action for selecting word under cursor (QTCREATORBUG-641)
|
||||||
|
* Fixed highlighting of Markdown files
|
||||||
|
(QTCREATORBUG-16304)
|
||||||
|
|
||||||
|
Help
|
||||||
|
|
||||||
|
* Added option to open link and current page in window (QTCREATORBUG-16842)
|
||||||
|
|
||||||
|
All Projects
|
||||||
|
|
||||||
|
* Reworked Projects mode UI
|
||||||
|
* Grouped all device options into one options category
|
||||||
|
* Added support for toolchains for different languages (currently C and C++)
|
||||||
|
|
||||||
|
QMake Projects
|
||||||
|
|
||||||
|
* Removed Qt Labs Controls wizard which is superseded by Qt Quick Controls 2
|
||||||
|
* Fixed `Open with Designer` and `Open with Linguist` for mobile and embedded Qt
|
||||||
|
(QTCREATORBUG-16558)
|
||||||
|
* Fixed Add Library wizard when selecting library from absolute path or
|
||||||
|
different drive (QTCREATORBUG-8413, QTCREATORBUG-15732, QTCREATORBUG-16688)
|
||||||
|
|
||||||
|
CMake Projects
|
||||||
|
|
||||||
|
* Added support for CMake specific snippets
|
||||||
|
* Added support for platforms and toolsets
|
||||||
|
* Added warning for unsupported CMake versions
|
||||||
|
* Added drop down for selecting predefined values for properties
|
||||||
|
* Improved performance of opening project (QTCREATORBUG-16930)
|
||||||
|
* Made it possible to select CMake application on macOS
|
||||||
|
* Fixed that all unknown build target types were mapped to `ExecutableType`
|
||||||
|
|
||||||
|
Qbs Projects
|
||||||
|
|
||||||
|
* Made generated files available in project tree (QTCREATORBUG-15978)
|
||||||
|
|
||||||
|
C++ Support
|
||||||
|
|
||||||
|
* Added preview of images to tool tip on Qt resource URLs
|
||||||
|
* Added option to skip big files when indexing (QTCREATORBUG-16712)
|
||||||
|
* Added notification for parsing errors in headers
|
||||||
|
* Fixed `Move Definition to Class` for functions in template class and
|
||||||
|
template member functions (QTCREATORBUG-14354)
|
||||||
|
* Fixed issues with `Add Declaration`, `Add Definition`, and
|
||||||
|
`Move Definition Outside Class` for template functions
|
||||||
|
* Clang Code Model
|
||||||
|
* Improved responsiveness of completion and highlighting
|
||||||
|
|
||||||
|
Debugging
|
||||||
|
|
||||||
|
* Added pretty printing of `QRegExp` captures
|
||||||
|
* Added pretty printing of `QStaticStringData`
|
||||||
|
* Improved pretty printing of QV4 types
|
||||||
|
* Made display of maps more compact
|
||||||
|
* Fixed pretty printing of `QFixed`
|
||||||
|
* LLDB
|
||||||
|
* Added support for Qt Creator variables `%{...}` in startup commands
|
||||||
|
|
||||||
|
QML Profiler
|
||||||
|
|
||||||
|
* Added option to show memory usage and allocations as flame graph
|
||||||
|
* Added option to show vertical orientation lines in timeline
|
||||||
|
(click the time ruler)
|
||||||
|
|
||||||
|
Qt Quick Designer
|
||||||
|
|
||||||
|
* Added completion expression editor
|
||||||
|
* Added menu for editing `when` condition of states
|
||||||
|
* Added editor for managing C++ backend objects
|
||||||
|
* Added reformatting of `.ui.qml` files on save
|
||||||
|
* Added support for exporting single properties
|
||||||
|
* Added support for padding (Qt Quick 2.6)
|
||||||
|
* Added support for elide and various font properties to text items
|
||||||
|
* Fixed that it was not possible to give extracted components
|
||||||
|
the file extension `.ui.qml`
|
||||||
|
* Fixed that switching from Qt Quick Designer failed to commit pending changes
|
||||||
|
(QTCREATORBUG-14830)
|
||||||
|
* Fixed issues with pressing escape
|
||||||
|
|
||||||
|
Diff Viewer
|
||||||
|
|
||||||
|
* Added local diff for modified files in Qt Creator (`Diff` >
|
||||||
|
`Diff Current File`, `Diff` > `Diff All Modified Files`)
|
||||||
|
(QTCREATORBUG-9732)
|
||||||
|
* Fixed that reload prompt was shown when reverting change
|
||||||
|
|
||||||
|
Version Control Systems
|
||||||
|
|
||||||
|
* Gerrit
|
||||||
|
* Fixed pushing to Gerrit when remote repository is empty
|
||||||
|
(QTCREATORBUG-16780)
|
||||||
|
|
||||||
|
Test Integration
|
||||||
|
|
||||||
|
* Added option to disable crash handler when debugging
|
||||||
|
* Fixed that results were not shown when debugging (QTCREATORBUG-16693)
|
||||||
|
* Fixed that progress indicator sometimes did not stop
|
||||||
|
|
||||||
|
Model Editor
|
||||||
|
|
||||||
|
* Added zooming
|
||||||
|
* Added synchronization of selected diagram in diagram browser
|
||||||
|
|
||||||
|
Platform Specific
|
||||||
|
|
||||||
|
Android
|
||||||
|
|
||||||
|
* Improved stability of determination if application is running
|
||||||
|
* Fixed that running without deployment did not start emulator
|
||||||
|
(QTCREATORBUG-10237)
|
||||||
|
* Fixed that permission model downgrade was not detected as error
|
||||||
|
(QTCREATORBUG-16630)
|
||||||
|
* Fixed handling of minimum required API level (QTCREATORBUG-16740)
|
||||||
|
|
||||||
|
Credits for these changes go to:
|
||||||
BIN
doc/images/qmldesigner-backends.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 3.3 KiB |
@@ -124,6 +124,9 @@
|
|||||||
\row
|
\row
|
||||||
\li {4,1} \note To report bugs and suggestions to the Qt Bug
|
\li {4,1} \note To report bugs and suggestions to the Qt Bug
|
||||||
Tracker, select \uicontrol {Help > Report Bug}.
|
Tracker, select \uicontrol {Help > Report Bug}.
|
||||||
|
To copy and paste detailed information about your system to the
|
||||||
|
bug report, select \uicontrol Help >
|
||||||
|
\uicontrol {System Information}.
|
||||||
|
|
||||||
You can also join the \QC mailing list at:
|
You can also join the \QC mailing list at:
|
||||||
\l{http://lists.qt-project.org/mailman/listinfo/}
|
\l{http://lists.qt-project.org/mailman/listinfo/}
|
||||||
|
|||||||
@@ -41,6 +41,8 @@
|
|||||||
|
|
||||||
\li Create bindings between the properties of two objects.
|
\li Create bindings between the properties of two objects.
|
||||||
|
|
||||||
|
\li Manage backend QObjects.
|
||||||
|
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
For examples of adding connections, see
|
For examples of adding connections, see
|
||||||
@@ -58,6 +60,9 @@
|
|||||||
|
|
||||||
\li Select the \uicontrol {Connections} tab.
|
\li Select the \uicontrol {Connections} tab.
|
||||||
|
|
||||||
|
\li Select the \inlineimage plus.png
|
||||||
|
(\uicontrol Add) button to add a connection.
|
||||||
|
|
||||||
\li Select \uicontrol Target to add the object to connect to a signal.
|
\li Select \uicontrol Target to add the object to connect to a signal.
|
||||||
|
|
||||||
\li Select \uicontrol {Signal Handler} to select the signal that the connection
|
\li Select \uicontrol {Signal Handler} to select the signal that the connection
|
||||||
@@ -105,6 +110,9 @@
|
|||||||
|
|
||||||
\li Select the \uicontrol {Bindings} tab.
|
\li Select the \uicontrol {Bindings} tab.
|
||||||
|
|
||||||
|
\li Select the \inlineimage plus.png
|
||||||
|
(\uicontrol Add) button to add a binding.
|
||||||
|
|
||||||
\li Select \uicontrol Item to select the target object whose property you want
|
\li Select \uicontrol Item to select the target object whose property you want
|
||||||
to change dynamically.
|
to change dynamically.
|
||||||
|
|
||||||
@@ -119,4 +127,53 @@
|
|||||||
|
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
|
\section1 Managing C++ Backend Objects
|
||||||
|
|
||||||
|
Many applications provide QObject objects implemented in C++ that work as a
|
||||||
|
bridge between QML and C++. Such objects are typically registered with
|
||||||
|
qmlRegisterType or qmlRegisterSingletonType and then used by QML to
|
||||||
|
communicate with the C++ backend. Another example of such objects are the
|
||||||
|
state machines created by the \l {Using the Qt SCXML Compiler (qscxmlc)}
|
||||||
|
{Qt SCXML Compiler}.
|
||||||
|
|
||||||
|
Backend objects in a QML file are accessible if the QML file contains the
|
||||||
|
required imports. In addition, for a non-singleton QObject, a dynamic
|
||||||
|
property that contains the QObject must be specified.
|
||||||
|
|
||||||
|
A \e local QObject is instantiated in the current \e .qml file, as follows:
|
||||||
|
|
||||||
|
\badcode
|
||||||
|
property MyType myType: MyType {}.
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Otherwise the property is just defined, as follows:
|
||||||
|
|
||||||
|
\badcode
|
||||||
|
property MyType myType
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
To manage backend objects:
|
||||||
|
|
||||||
|
\list 1
|
||||||
|
|
||||||
|
\li Select the \uicontrol Backends tab to view accessible backend
|
||||||
|
objects.
|
||||||
|
|
||||||
|
\image qmldesigner-backends.png
|
||||||
|
|
||||||
|
\li Select the \inlineimage plus.png
|
||||||
|
(\uicontrol Add) button to add a backend object in the
|
||||||
|
\uicontrol {Add New C++ Backend} dialog.
|
||||||
|
|
||||||
|
\li In the \uicontrol Type field, select the type of the backend QObject
|
||||||
|
to add.
|
||||||
|
|
||||||
|
\li Select the \uicontrol {Define object locally} check box if the
|
||||||
|
QObject is not registered as a singleton.
|
||||||
|
|
||||||
|
\li Select \uicontrol OK to add the required import and to create the
|
||||||
|
property for a non-singleton object.
|
||||||
|
|
||||||
|
\endlist
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -43,8 +43,7 @@
|
|||||||
information for code completion and the semantic checks to work correctly.
|
information for code completion and the semantic checks to work correctly.
|
||||||
|
|
||||||
When you write a QML module or use QML from a C++ application you typically
|
When you write a QML module or use QML from a C++ application you typically
|
||||||
register new types with the \l{QQmlEngine} class \c qmlRegisterType()
|
register new types with the qmlRegisterType() function or expose some
|
||||||
function or expose some
|
|
||||||
class instances with \l{QQmlContext::setContextProperty()}. The \QC C++
|
class instances with \l{QQmlContext::setContextProperty()}. The \QC C++
|
||||||
code model now scans for these calls and
|
code model now scans for these calls and
|
||||||
tells the QML code model about them. This means that properties are
|
tells the QML code model about them. This means that properties are
|
||||||
@@ -53,6 +52,9 @@
|
|||||||
is available, and therefore, you must explicitly generate type information
|
is available, and therefore, you must explicitly generate type information
|
||||||
for QML modules with plugins before distributing them.
|
for QML modules with plugins before distributing them.
|
||||||
|
|
||||||
|
Classes registered with \c qmlRegisterType() can be used as backend objects
|
||||||
|
in the \QMLD. For more information, see \l {Adding Connections}.
|
||||||
|
|
||||||
Ideally, QML modules have a \c{plugins.qmltypes} file in the same directory
|
Ideally, QML modules have a \c{plugins.qmltypes} file in the same directory
|
||||||
as the \c qmldir file. The \c qmltypes file contains a description of the
|
as the \c qmldir file. The \c qmltypes file contains a description of the
|
||||||
types exported by the module's plugins and is loaded by \QC when the
|
types exported by the module's plugins and is loaded by \QC when the
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
var Environment = loadExtension("qbs.Environment")
|
var Environment = loadExtension("qbs.Environment")
|
||||||
var File = loadExtension("qbs.File")
|
var File = loadExtension("qbs.File")
|
||||||
|
var FileInfo = loadExtension("qbs.FileInfo")
|
||||||
var MinimumLLVMVersion = "3.8.0"
|
var MinimumLLVMVersion = "3.8.0"
|
||||||
var Process = loadExtension("qbs.Process")
|
var Process = loadExtension("qbs.Process")
|
||||||
|
|
||||||
@@ -57,12 +58,12 @@ function llvmConfig(qbs, qtcFunctions)
|
|||||||
|
|
||||||
function includeDir(llvmConfig)
|
function includeDir(llvmConfig)
|
||||||
{
|
{
|
||||||
return readOutput(llvmConfig, ["--includedir"])
|
return FileInfo.fromNativeSeparators(readOutput(llvmConfig, ["--includedir"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
function libDir(llvmConfig)
|
function libDir(llvmConfig)
|
||||||
{
|
{
|
||||||
return readOutput(llvmConfig, ["--libdir"])
|
return FileInfo.fromNativeSeparators(readOutput(llvmConfig, ["--libdir"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
function version(llvmConfig)
|
function version(llvmConfig)
|
||||||
|
|||||||
@@ -144,8 +144,6 @@ if [ ! -d "$app_path/Contents/Frameworks/QtCore.framework" ]; then
|
|||||||
"-executable=$app_path/Contents/Resources/qtpromaker" \
|
"-executable=$app_path/Contents/Resources/qtpromaker" \
|
||||||
"-executable=$app_path/Contents/Resources/sdktool" \
|
"-executable=$app_path/Contents/Resources/sdktool" \
|
||||||
"-executable=$app_path/Contents/Resources/ios/iostool" \
|
"-executable=$app_path/Contents/Resources/ios/iostool" \
|
||||||
"-executable=$app_path/Contents/Resources/ios/iossim" \
|
|
||||||
"-executable=$app_path/Contents/Resources/ios/iossim_1_8_2" \
|
|
||||||
"-executable=$app_path/Contents/Resources/buildoutputparser" \
|
"-executable=$app_path/Contents/Resources/buildoutputparser" \
|
||||||
"-executable=$app_path/Contents/Resources/cpaster" \
|
"-executable=$app_path/Contents/Resources/cpaster" \
|
||||||
"-executable=$app_path/Contents/MacOS/qtdiag" \
|
"-executable=$app_path/Contents/MacOS/qtdiag" \
|
||||||
|
|||||||
@@ -133,62 +133,35 @@ Item {
|
|||||||
fillMode: Image.Tile
|
fillMode: Image.Tile
|
||||||
|
|
||||||
// note we smoothscale the shader from a smaller version to improve performance
|
// note we smoothscale the shader from a smaller version to improve performance
|
||||||
ShaderEffect {
|
Canvas {
|
||||||
id: map
|
id: hubeBox
|
||||||
opacity: colorButton.alpha
|
opacity: colorButton.alpha
|
||||||
scale: surround.width / width;
|
|
||||||
layer.enabled: true
|
|
||||||
layer.smooth: true
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
property real hue: colorButton.hue
|
property real hue: colorButton.hue
|
||||||
|
onHueChanged: requestPaint()
|
||||||
|
|
||||||
fragmentShader: "
|
onPaint: {
|
||||||
varying mediump vec2 qt_TexCoord0;
|
var ctx = hubeBox.getContext('2d')
|
||||||
uniform highp float qt_Opacity;
|
|
||||||
uniform highp float hue;
|
|
||||||
|
|
||||||
highp float hueToIntensity(highp float v1, highp float v2, highp float h) {
|
ctx.save()
|
||||||
h = fract(h);
|
|
||||||
if (h < 1.0 / 6.0)
|
|
||||||
return v1 + (v2 - v1) * 6.0 * h;
|
|
||||||
else if (h < 1.0 / 2.0)
|
|
||||||
return v2;
|
|
||||||
else if (h < 2.0 / 3.0)
|
|
||||||
return v1 + (v2 - v1) * 6.0 * (2.0 / 3.0 - h);
|
|
||||||
|
|
||||||
return v1;
|
ctx.clearRect(0, 0, hubeBox.width, hubeBox.height);
|
||||||
|
|
||||||
|
for (var row = 0; row < hubeBox.height; row++){
|
||||||
|
var gradient = ctx.createLinearGradient(0, 0, hubeBox.width,0);
|
||||||
|
var l = Math.abs(row - hubeBox.height) / hubeBox.height
|
||||||
|
|
||||||
|
gradient.addColorStop(0, Qt.hsla(hubeBox.hue, 0, l, 1));
|
||||||
|
gradient.addColorStop(1, Qt.hsla(hubeBox.hue, 1, l, 1));
|
||||||
|
|
||||||
|
ctx.fillStyle = gradient;
|
||||||
|
ctx.fillRect(0, row, hubeBox.width, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
highp vec3 HSLtoRGB(highp vec3 color) {
|
ctx.restore()
|
||||||
highp float h = color.x;
|
|
||||||
highp float l = color.z;
|
|
||||||
highp float s = color.y;
|
|
||||||
|
|
||||||
if (s < 1.0 / 256.0)
|
|
||||||
return vec3(l, l, l);
|
|
||||||
|
|
||||||
highp float v1;
|
|
||||||
highp float v2;
|
|
||||||
if (l < 0.5)
|
|
||||||
v2 = l * (1.0 + s);
|
|
||||||
else
|
|
||||||
v2 = (l + s) - (s * l);
|
|
||||||
|
|
||||||
v1 = 2.0 * l - v2;
|
|
||||||
|
|
||||||
highp float d = 1.0 / 3.0;
|
|
||||||
highp float r = hueToIntensity(v1, v2, h + d);
|
|
||||||
highp float g = hueToIntensity(v1, v2, h);
|
|
||||||
highp float b = hueToIntensity(v1, v2, h - d);
|
|
||||||
return vec3(r, g, b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
|
||||||
lowp vec4 c = vec4(1.0);
|
|
||||||
c.rgb = HSLtoRGB(vec3(hue, 1.0 - qt_TexCoord0.t, qt_TexCoord0.s));
|
|
||||||
gl_FragColor = c * qt_Opacity;
|
|
||||||
}
|
|
||||||
"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Canvas {
|
Canvas {
|
||||||
@@ -215,9 +188,8 @@ Item {
|
|||||||
|
|
||||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
var yy = canvas.height - colorButton.saturation * canvas.height
|
var yy = canvas.height -colorButton.lightness * canvas.height
|
||||||
|
var xx = colorButton.saturation * canvas.width
|
||||||
var xx = colorButton.lightness * canvas.width
|
|
||||||
|
|
||||||
ctx.strokeStyle = canvas.strokeStyle
|
ctx.strokeStyle = canvas.strokeStyle
|
||||||
ctx.lineWidth = 1
|
ctx.lineWidth = 1
|
||||||
@@ -245,13 +217,9 @@ Item {
|
|||||||
if (pressed) {
|
if (pressed) {
|
||||||
var xx = Math.max(0, Math.min(mouse.x, parent.width))
|
var xx = Math.max(0, Math.min(mouse.x, parent.width))
|
||||||
var yy = Math.max(0, Math.min(mouse.y, parent.height))
|
var yy = Math.max(0, Math.min(mouse.y, parent.height))
|
||||||
//saturationSlider.value = 1.0 - yy / parent.height
|
|
||||||
//lightnessSlider.value = xx / parent.width
|
colorButton.lightness = 1.0 - yy / parent.height;
|
||||||
//var myHue = colorButton.hue
|
colorButton.saturation = xx / parent.width;
|
||||||
colorButton.saturation = 1.0 - yy / parent.height;
|
|
||||||
colorButton.lightness = xx / parent.width;
|
|
||||||
//colorButton.hue = myHue
|
|
||||||
//colorButton.color = Qt.hsla(colorButton.hue, 1.0 - yy / parent.height, xx / parent.width, colorButton.alpha)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onPressed: positionChanged(mouse)
|
onPressed: positionChanged(mouse)
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ Column {
|
|||||||
if (supportGradient && gradientLine.hasGradient) {
|
if (supportGradient && gradientLine.hasGradient) {
|
||||||
colorEditor.color = gradientLine.currentColor
|
colorEditor.color = gradientLine.currentColor
|
||||||
gradientLine.currentColor = color
|
gradientLine.currentColor = color
|
||||||
|
textField.text = colorEditor.color
|
||||||
}
|
}
|
||||||
gradientLine.isInValidState = true
|
gradientLine.isInValidState = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ RowLayout {
|
|||||||
x: 2
|
x: 2
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
backendValue: urlChooser.backendValue
|
backendValue: urlChooser.backendValue
|
||||||
visible: comboBox.enabled
|
visible: urlChooser.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
property bool isComplete: false
|
property bool isComplete: false
|
||||||
@@ -92,16 +92,25 @@ RowLayout {
|
|||||||
|
|
||||||
setCurrentText(textValue)
|
setCurrentText(textValue)
|
||||||
}
|
}
|
||||||
|
onAccepted: {
|
||||||
|
if (!comboBox.isComplete)
|
||||||
|
return;
|
||||||
|
|
||||||
onCurrentTextChanged: {
|
if (backendValue.value !== currentText)
|
||||||
|
backendValue.value = currentText;
|
||||||
|
}
|
||||||
|
|
||||||
|
onActivated: {
|
||||||
|
var cText = textAt(index)
|
||||||
|
print(cText)
|
||||||
if (backendValue === undefined)
|
if (backendValue === undefined)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!comboBox.isComplete)
|
if (!comboBox.isComplete)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (backendValue.value !== currentText)
|
if (backendValue.value !== cText)
|
||||||
backendValue.value = currentText;
|
backendValue.value = cText;
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
@@ -158,6 +167,7 @@ RowLayout {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
darkPanel.opacity = 1
|
darkPanel.opacity = 1
|
||||||
fileModel.openFileDialog()
|
fileModel.openFileDialog()
|
||||||
|
if (fileModel.fileName != "")
|
||||||
backendValue.value = fileModel.fileName
|
backendValue.value = fileModel.fileName
|
||||||
darkPanel.opacity = 0
|
darkPanel.opacity = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ ClangCodeModelConnectionClient::ClangCodeModelConnectionClient(
|
|||||||
ClangCodeModelClientInterface *client)
|
ClangCodeModelClientInterface *client)
|
||||||
: serverProxy_(client, ioDevice())
|
: serverProxy_(client, ioDevice())
|
||||||
{
|
{
|
||||||
stdErrPrefixer().setPrefix("ClangCodeModelConnectionClient.stderr: ");
|
stdErrPrefixer().setPrefix("clangbackend.stderr: ");
|
||||||
stdOutPrefixer().setPrefix("ClangCodeModelConnectionClient.stdout: ");
|
stdOutPrefixer().setPrefix("clangbackend.stdout: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
ClangCodeModelConnectionClient::~ClangCodeModelConnectionClient()
|
ClangCodeModelConnectionClient::~ClangCodeModelConnectionClient()
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ namespace ClangBackEnd {
|
|||||||
ConnectionClient::ConnectionClient()
|
ConnectionClient::ConnectionClient()
|
||||||
{
|
{
|
||||||
processAliveTimer.setInterval(10000);
|
processAliveTimer.setInterval(10000);
|
||||||
|
resetTemporaryDir();
|
||||||
|
|
||||||
static const bool startAliveTimer = !qEnvironmentVariableIntValue("QTC_CLANG_NO_ALIVE_TIMER");
|
static const bool startAliveTimer = !qEnvironmentVariableIntValue("QTC_CLANG_NO_ALIVE_TIMER");
|
||||||
|
|
||||||
@@ -113,9 +114,7 @@ QProcessEnvironment ConnectionClient::processEnvironment() const
|
|||||||
|
|
||||||
const QTemporaryDir &ConnectionClient::temporaryDirectory() const
|
const QTemporaryDir &ConnectionClient::temporaryDirectory() const
|
||||||
{
|
{
|
||||||
static QTemporaryDir temporaryDirectory(QDir::tempPath() + QStringLiteral("/qtc-clang-XXXXXX"));
|
return *temporaryDirectory_.data();
|
||||||
|
|
||||||
return temporaryDirectory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LinePrefixer &ConnectionClient::stdErrPrefixer()
|
LinePrefixer &ConnectionClient::stdErrPrefixer()
|
||||||
@@ -147,6 +146,7 @@ void ConnectionClient::restartProcessAsynchronously()
|
|||||||
{
|
{
|
||||||
if (!processIsStarting) {
|
if (!processIsStarting) {
|
||||||
finishProcess(std::move(process_));
|
finishProcess(std::move(process_));
|
||||||
|
resetTemporaryDir(); // clear left-over preambles
|
||||||
|
|
||||||
startProcessAndConnectToServerAsynchronously();
|
startProcessAndConnectToServerAsynchronously();
|
||||||
}
|
}
|
||||||
@@ -218,6 +218,12 @@ void ConnectionClient::printStandardError()
|
|||||||
qDebug("%s", stdErrPrefixer_.prefix(process_->readAllStandardError()).constData());
|
qDebug("%s", stdErrPrefixer_.prefix(process_->readAllStandardError()).constData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConnectionClient::resetTemporaryDir()
|
||||||
|
{
|
||||||
|
const QString templatePath = QDir::tempPath() + QStringLiteral("/qtc-clang-XXXXXX");
|
||||||
|
temporaryDirectory_.reset(new QTemporaryDir(templatePath));
|
||||||
|
}
|
||||||
|
|
||||||
void ConnectionClient::connectLocalSocketConnected()
|
void ConnectionClient::connectLocalSocketConnected()
|
||||||
{
|
{
|
||||||
connect(&localSocket,
|
connect(&localSocket,
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include <QLocalSocket>
|
#include <QLocalSocket>
|
||||||
#include <QProcessEnvironment>
|
#include <QProcessEnvironment>
|
||||||
|
#include <QScopedPointer>
|
||||||
|
#include <QTemporaryDir>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -102,6 +104,8 @@ private:
|
|||||||
void printStandardOutput();
|
void printStandardOutput();
|
||||||
void printStandardError();
|
void printStandardError();
|
||||||
|
|
||||||
|
void resetTemporaryDir();
|
||||||
|
|
||||||
void connectLocalSocketConnected();
|
void connectLocalSocketConnected();
|
||||||
void connectLocalSocketDisconnected();
|
void connectLocalSocketDisconnected();
|
||||||
void connectProcessFinished(QProcess *process) const;
|
void connectProcessFinished(QProcess *process) const;
|
||||||
@@ -121,6 +125,7 @@ private:
|
|||||||
|
|
||||||
mutable std::unique_ptr<QProcess> process_;
|
mutable std::unique_ptr<QProcess> process_;
|
||||||
QLocalSocket localSocket;
|
QLocalSocket localSocket;
|
||||||
|
QScopedPointer<QTemporaryDir> temporaryDirectory_;
|
||||||
QTimer processAliveTimer;
|
QTimer processAliveTimer;
|
||||||
QString processPath_;
|
QString processPath_;
|
||||||
bool isAliveTimerResetted = false;
|
bool isAliveTimerResetted = false;
|
||||||
|
|||||||
@@ -144,6 +144,11 @@ public:
|
|||||||
&& first.location_ == second.location_;
|
&& first.location_ == second.location_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const DiagnosticContainer &first, const DiagnosticContainer &second)
|
||||||
|
{
|
||||||
|
return !(first == second);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SourceLocationContainer location_;
|
SourceLocationContainer location_;
|
||||||
QVector<SourceRangeContainer> ranges_;
|
QVector<SourceRangeContainer> ranges_;
|
||||||
|
|||||||
@@ -76,20 +76,17 @@ DocumentController::DocumentController(QObject *parent) :
|
|||||||
{
|
{
|
||||||
// project controller
|
// project controller
|
||||||
connect(m_projectController, &ProjectController::changed, this, &DocumentController::changed);
|
connect(m_projectController, &ProjectController::changed, this, &DocumentController::changed);
|
||||||
connect(m_projectController, &ProjectController::modificationChanged, this, &DocumentController::modificationChanged);
|
|
||||||
|
|
||||||
// model controller
|
// model controller
|
||||||
m_modelController->setUndoController(m_undoController);
|
m_modelController->setUndoController(m_undoController);
|
||||||
connect(m_modelController, &ModelController::modified, [this](){
|
connect(m_modelController, &ModelController::modified,
|
||||||
m_projectController->setModified(true);
|
m_projectController, &ProjectController::setModified);
|
||||||
});
|
|
||||||
|
|
||||||
// diagram controller
|
// diagram controller
|
||||||
m_diagramController->setModelController(m_modelController);
|
m_diagramController->setModelController(m_modelController);
|
||||||
m_diagramController->setUndoController(m_undoController);
|
m_diagramController->setUndoController(m_undoController);
|
||||||
connect(m_diagramController, &DiagramController::modified, [this](){
|
connect(m_diagramController, &DiagramController::modified,
|
||||||
m_projectController->setModified(true);
|
m_projectController, &ProjectController::setModified);
|
||||||
});
|
|
||||||
|
|
||||||
// diagram scene controller
|
// diagram scene controller
|
||||||
m_diagramSceneController->setModelController(m_modelController);
|
m_diagramSceneController->setModelController(m_modelController);
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void changed();
|
void changed();
|
||||||
void modificationChanged(bool modified);
|
|
||||||
void modelClipboardChanged(bool isEmpty);
|
void modelClipboardChanged(bool isEmpty);
|
||||||
void diagramClipboardChanged(bool isEmpty);
|
void diagramClipboardChanged(bool isEmpty);
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ ProjectIsModifiedException::ProjectIsModifiedException()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProjectController::ProjectController(QObject *parent)
|
ProjectController::ProjectController(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent),
|
||||||
|
m_isModified(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ void ProjectController::newProject(const QString &fileName)
|
|||||||
rootPackage->setName(tr("Model"));
|
rootPackage->setName(tr("Model"));
|
||||||
m_project->setRootPackage(rootPackage);
|
m_project->setRootPackage(rootPackage);
|
||||||
m_project->setFileName(fileName);
|
m_project->setFileName(fileName);
|
||||||
setModified(false);
|
m_isModified = false;
|
||||||
emit fileNameChanged(m_project->fileName());
|
emit fileNameChanged(m_project->fileName());
|
||||||
emit changed();
|
emit changed();
|
||||||
}
|
}
|
||||||
@@ -67,18 +68,17 @@ void ProjectController::setFileName(const QString &fileName)
|
|||||||
{
|
{
|
||||||
if (fileName != m_project->fileName()) {
|
if (fileName != m_project->fileName()) {
|
||||||
m_project->setFileName(fileName);
|
m_project->setFileName(fileName);
|
||||||
setModified(true);
|
setModified();
|
||||||
emit fileNameChanged(m_project->fileName());
|
emit fileNameChanged(m_project->fileName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectController::setModified(bool modified)
|
void ProjectController::setModified()
|
||||||
{
|
{
|
||||||
if (m_isModified == modified)
|
if (!m_isModified) {
|
||||||
return;
|
m_isModified = true;
|
||||||
|
emit changed();
|
||||||
m_isModified = modified;
|
}
|
||||||
emit modificationChanged(modified);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectController::load()
|
void ProjectController::load()
|
||||||
@@ -89,7 +89,7 @@ void ProjectController::load()
|
|||||||
throw NoFileNameException();
|
throw NoFileNameException();
|
||||||
ProjectSerializer serializer;
|
ProjectSerializer serializer;
|
||||||
serializer.load(m_project->fileName(), m_project.data());
|
serializer.load(m_project->fileName(), m_project.data());
|
||||||
setModified(false);
|
m_isModified = false;
|
||||||
emit changed();
|
emit changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ void ProjectController::save()
|
|||||||
throw NoFileNameException();
|
throw NoFileNameException();
|
||||||
ProjectSerializer serializer;
|
ProjectSerializer serializer;
|
||||||
serializer.save(m_project->fileName(), m_project.data());
|
serializer.save(m_project->fileName(), m_project.data());
|
||||||
setModified(false);
|
m_isModified = false;
|
||||||
emit changed();
|
emit changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void changed();
|
void changed();
|
||||||
void fileNameChanged(const QString &fileName);
|
void fileNameChanged(const QString &fileName);
|
||||||
void modificationChanged(bool modified);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Project *project() const { return m_project.data(); }
|
Project *project() const { return m_project.data(); }
|
||||||
@@ -66,7 +65,7 @@ public:
|
|||||||
|
|
||||||
void newProject(const QString &fileName);
|
void newProject(const QString &fileName);
|
||||||
void setFileName(const QString &fileName);
|
void setFileName(const QString &fileName);
|
||||||
void setModified(bool modified);
|
void setModified();
|
||||||
|
|
||||||
void load();
|
void load();
|
||||||
void save();
|
void save();
|
||||||
@@ -74,7 +73,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QScopedPointer<Project> m_project;
|
QScopedPointer<Project> m_project;
|
||||||
bool m_isModified = false;
|
bool m_isModified;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace qmt
|
} // namespace qmt
|
||||||
|
|||||||
@@ -87,12 +87,14 @@ char *getTypeName(ULONG64 module, ULONG typeId)
|
|||||||
symbols->GetTypeName(module, typeId, NULL, 0, &size);
|
symbols->GetTypeName(module, typeId, NULL, 0, &size);
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
typeName = new char[size];
|
typeName = new char[size];
|
||||||
if (FAILED(symbols->GetTypeName(module, typeId, typeName, size, &size))) {
|
if (SUCCEEDED(symbols->GetTypeName(module, typeId, typeName, size, &size)))
|
||||||
|
return typeName;
|
||||||
|
else
|
||||||
delete[] typeName;
|
delete[] typeName;
|
||||||
|
}
|
||||||
typeName = new char[1];
|
typeName = new char[1];
|
||||||
typeName[0] = 0;
|
typeName[0] = 0;
|
||||||
}
|
|
||||||
}
|
|
||||||
return typeName;
|
return typeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,6 +272,24 @@ PyObject *type_TemplateArgument(Type *self, PyObject *args)
|
|||||||
return lookupType(innerType);
|
return lookupType(innerType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *type_TemplateArguments(Type *self)
|
||||||
|
{
|
||||||
|
std::vector<std::string> innerTypes = innerTypesOf(getTypeName(self));
|
||||||
|
auto templateArguments = PyList_New(0);
|
||||||
|
for (const std::string &innerType : innerTypes) {
|
||||||
|
PyObject* childValue;
|
||||||
|
try {
|
||||||
|
int integer = std::stoi(innerType);
|
||||||
|
childValue = Py_BuildValue("i", integer);
|
||||||
|
}
|
||||||
|
catch (std::invalid_argument) {
|
||||||
|
childValue = lookupType(innerType);
|
||||||
|
}
|
||||||
|
PyList_Append(templateArguments, childValue);
|
||||||
|
}
|
||||||
|
return templateArguments;
|
||||||
|
}
|
||||||
|
|
||||||
PyObject *type_New(PyTypeObject *type, PyObject *, PyObject *)
|
PyObject *type_New(PyTypeObject *type, PyObject *, PyObject *)
|
||||||
{
|
{
|
||||||
Type *self = reinterpret_cast<Type *>(type->tp_alloc(type, 0));
|
Type *self = reinterpret_cast<Type *>(type->tp_alloc(type, 0));
|
||||||
@@ -313,6 +333,8 @@ static PyMethodDef typeMethods[] = {
|
|||||||
|
|
||||||
{"templateArgument", PyCFunction(type_TemplateArgument), METH_VARARGS,
|
{"templateArgument", PyCFunction(type_TemplateArgument), METH_VARARGS,
|
||||||
"Returns template argument at position"},
|
"Returns template argument at position"},
|
||||||
|
{"templateArguments", PyCFunction(type_TemplateArguments), METH_NOARGS,
|
||||||
|
"Returns all template arguments."},
|
||||||
|
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ extern "C" HRESULT CALLBACK pid(CIDebugClient *client, PCSTR args)
|
|||||||
|
|
||||||
int token;
|
int token;
|
||||||
commandTokens<StringList>(args, &token);
|
commandTokens<StringList>(args, &token);
|
||||||
dprintf("Qt Creator CDB extension version 4.0 %d bit.\n",
|
dprintf("Qt Creator CDB extension version 4.2 %d bit.\n",
|
||||||
sizeof(void *) * 8);
|
sizeof(void *) * 8);
|
||||||
if (const ULONG pid = currentProcessId(client))
|
if (const ULONG pid = currentProcessId(client))
|
||||||
ExtensionContext::instance().report('R', token, 0, "pid", "%u", pid);
|
ExtensionContext::instance().report('R', token, 0, "pid", "%u", pid);
|
||||||
|
|||||||
113
src/libs/utils/guard.cpp
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "guard.h"
|
||||||
|
#include "qtcassert.h"
|
||||||
|
|
||||||
|
/*! \class Utils::Guard
|
||||||
|
|
||||||
|
\brief The Guard class implements a recursive guard with locking mechanism.
|
||||||
|
|
||||||
|
It may be used as an alternative to QSignalBlocker.
|
||||||
|
QSignalBlocker blocks all signals of the object
|
||||||
|
which is usually not desirable. It may also block signals
|
||||||
|
which are needed internally by the object itself.
|
||||||
|
The Guard and GuardLocker classes don't block signals at all.
|
||||||
|
|
||||||
|
When calling a object's method which may in turn emit a signal
|
||||||
|
which you are connected to, and you want to ignore
|
||||||
|
this notification, you should keep the Guard object
|
||||||
|
as your class member and declare the GuardLocker object
|
||||||
|
just before calling the mentioned method, like:
|
||||||
|
|
||||||
|
\code
|
||||||
|
class MyClass : public QObject
|
||||||
|
{
|
||||||
|
\dots
|
||||||
|
private:
|
||||||
|
Guard updateGuard; // member of your class
|
||||||
|
};
|
||||||
|
|
||||||
|
\dots
|
||||||
|
|
||||||
|
void MyClass::updateOtherObject()
|
||||||
|
{
|
||||||
|
GuardLocker updatelocker(updateGuard);
|
||||||
|
otherObject->update(); // this may trigger a signal
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Inside a slot which is connected to the other's object signal
|
||||||
|
you may check if the guard is locked and ignore the further
|
||||||
|
operations in this case:
|
||||||
|
|
||||||
|
\code
|
||||||
|
void MyClass::otherObjectUpdated()
|
||||||
|
{
|
||||||
|
if (updateGuard.isLocked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// we didn't trigger the update
|
||||||
|
// so do update now
|
||||||
|
\dots
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
The GuardLock unlocks the Guard in it's destructor.
|
||||||
|
|
||||||
|
The Guard object is recursive, you may declare many GuardLocker
|
||||||
|
objects for the same Guard instance and the Guard will be locked
|
||||||
|
as long as at least one GuardLocker object created for the Guard
|
||||||
|
is in scope.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Utils {
|
||||||
|
|
||||||
|
Guard::Guard()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Guard::~Guard()
|
||||||
|
{
|
||||||
|
QTC_CHECK(m_lockCount == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Guard::isLocked() const
|
||||||
|
{
|
||||||
|
return m_lockCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
GuardLocker::GuardLocker(Guard &guard)
|
||||||
|
: m_guard(guard)
|
||||||
|
{
|
||||||
|
++m_guard.m_lockCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
GuardLocker::~GuardLocker()
|
||||||
|
{
|
||||||
|
--m_guard.m_lockCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Utils
|
||||||
56
src/libs/utils/guard.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils_global.h"
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
namespace Utils {
|
||||||
|
|
||||||
|
class QTCREATOR_UTILS_EXPORT Guard
|
||||||
|
{
|
||||||
|
Q_DISABLE_COPY(Guard)
|
||||||
|
public:
|
||||||
|
Guard();
|
||||||
|
~Guard();
|
||||||
|
bool isLocked() const;
|
||||||
|
private:
|
||||||
|
int m_lockCount = 0;
|
||||||
|
friend class GuardLocker;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QTCREATOR_UTILS_EXPORT GuardLocker
|
||||||
|
{
|
||||||
|
Q_DISABLE_COPY(GuardLocker)
|
||||||
|
public:
|
||||||
|
GuardLocker(Guard &guard);
|
||||||
|
~GuardLocker();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Guard &m_guard;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Utils
|
||||||
BIN
src/libs/utils/images/snapshot.png
Normal file
|
After Width: | Height: | Size: 148 B |
BIN
src/libs/utils/images/snapshot@2x.png
Normal file
|
After Width: | Height: | Size: 250 B |
@@ -35,6 +35,7 @@ namespace Utils {
|
|||||||
|
|
||||||
QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const FileName &fileName,
|
QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const FileName &fileName,
|
||||||
bool modified,
|
bool modified,
|
||||||
|
bool enableDiffOption,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -50,12 +51,13 @@ QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const FileName &fileName,
|
|||||||
"The file <i>%1</i> has changed outside Qt Creator. Do you want to reload it?");
|
"The file <i>%1</i> has changed outside Qt Creator. Do you want to reload it?");
|
||||||
}
|
}
|
||||||
msg = msg.arg(fileName.fileName());
|
msg = msg.arg(fileName.fileName());
|
||||||
return reloadPrompt(title, msg, fileName.toUserOutput(), parent);
|
return reloadPrompt(title, msg, fileName.toUserOutput(), enableDiffOption, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title,
|
QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title,
|
||||||
const QString &prompt,
|
const QString &prompt,
|
||||||
const QString &details,
|
const QString &details,
|
||||||
|
bool enableDiffOption,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
{
|
{
|
||||||
QMessageBox msg(parent);
|
QMessageBox msg(parent);
|
||||||
@@ -69,7 +71,19 @@ QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title,
|
|||||||
msg.button(QMessageBox::Close)->setText(QCoreApplication::translate("Utils::reloadPrompt",
|
msg.button(QMessageBox::Close)->setText(QCoreApplication::translate("Utils::reloadPrompt",
|
||||||
"&Close"));
|
"&Close"));
|
||||||
|
|
||||||
switch (msg.exec()) {
|
QPushButton *diffButton = nullptr;
|
||||||
|
if (enableDiffOption) {
|
||||||
|
diffButton = msg.addButton(QCoreApplication::translate(
|
||||||
|
"Utils::reloadPrompt", "No to All && &Diff"),
|
||||||
|
QMessageBox::NoRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int result = msg.exec();
|
||||||
|
|
||||||
|
if (msg.clickedButton() == diffButton)
|
||||||
|
return ReloadNoneAndDiff;
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
case QMessageBox::Yes:
|
case QMessageBox::Yes:
|
||||||
return ReloadCurrent;
|
return ReloadCurrent;
|
||||||
case QMessageBox::YesToAll:
|
case QMessageBox::YesToAll:
|
||||||
|
|||||||
@@ -40,15 +40,19 @@ enum ReloadPromptAnswer {
|
|||||||
ReloadAll,
|
ReloadAll,
|
||||||
ReloadSkipCurrent,
|
ReloadSkipCurrent,
|
||||||
ReloadNone,
|
ReloadNone,
|
||||||
|
ReloadNoneAndDiff,
|
||||||
CloseCurrent
|
CloseCurrent
|
||||||
};
|
};
|
||||||
|
|
||||||
QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const FileName &fileName,
|
QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const FileName &fileName,
|
||||||
bool modified,
|
bool modified,
|
||||||
|
bool enableDiffOption,
|
||||||
QWidget *parent);
|
QWidget *parent);
|
||||||
QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title,
|
QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title,
|
||||||
const QString &prompt,
|
const QString &prompt,
|
||||||
const QString &details, QWidget *parent);
|
const QString &details,
|
||||||
|
bool enableDiffOption,
|
||||||
|
QWidget *parent);
|
||||||
|
|
||||||
enum FileDeletedPromptAnswer {
|
enum FileDeletedPromptAnswer {
|
||||||
FileDeletedClose,
|
FileDeletedClose,
|
||||||
|
|||||||
@@ -100,7 +100,8 @@ SOURCES += $$PWD/environment.cpp \
|
|||||||
$$PWD/icon.cpp \
|
$$PWD/icon.cpp \
|
||||||
$$PWD/port.cpp \
|
$$PWD/port.cpp \
|
||||||
$$PWD/runextensions.cpp \
|
$$PWD/runextensions.cpp \
|
||||||
$$PWD/utilsicons.cpp
|
$$PWD/utilsicons.cpp \
|
||||||
|
$$PWD/guard.cpp
|
||||||
|
|
||||||
win32:SOURCES += $$PWD/consoleprocess_win.cpp
|
win32:SOURCES += $$PWD/consoleprocess_win.cpp
|
||||||
else:SOURCES += $$PWD/consoleprocess_unix.cpp
|
else:SOURCES += $$PWD/consoleprocess_unix.cpp
|
||||||
@@ -217,7 +218,8 @@ HEADERS += \
|
|||||||
$$PWD/smallstringvector.h \
|
$$PWD/smallstringvector.h \
|
||||||
$$PWD/smallstringlayout.h \
|
$$PWD/smallstringlayout.h \
|
||||||
$$PWD/sizedarray.h \
|
$$PWD/sizedarray.h \
|
||||||
$$PWD/smallstringio.h
|
$$PWD/smallstringio.h \
|
||||||
|
$$PWD/guard.h
|
||||||
|
|
||||||
FORMS += $$PWD/filewizardpage.ui \
|
FORMS += $$PWD/filewizardpage.ui \
|
||||||
$$PWD/projectintropage.ui \
|
$$PWD/projectintropage.ui \
|
||||||
|
|||||||
@@ -114,6 +114,8 @@ Project {
|
|||||||
"flowlayout.cpp",
|
"flowlayout.cpp",
|
||||||
"flowlayout.h",
|
"flowlayout.h",
|
||||||
"functiontraits.h",
|
"functiontraits.h",
|
||||||
|
"guard.cpp",
|
||||||
|
"guard.h",
|
||||||
"historycompleter.cpp",
|
"historycompleter.cpp",
|
||||||
"historycompleter.h",
|
"historycompleter.h",
|
||||||
"hostosinfo.h",
|
"hostosinfo.h",
|
||||||
|
|||||||
@@ -159,5 +159,7 @@
|
|||||||
<file>images/iconoverlay_warning_background@2x.png</file>
|
<file>images/iconoverlay_warning_background@2x.png</file>
|
||||||
<file>images/bookmark.png</file>
|
<file>images/bookmark.png</file>
|
||||||
<file>images/bookmark@2x.png</file>
|
<file>images/bookmark@2x.png</file>
|
||||||
|
<file>images/snapshot.png</file>
|
||||||
|
<file>images/snapshot@2x.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ const Icon BOOKMARK_TOOLBAR({
|
|||||||
{QLatin1String(":/utils/images/bookmark.png"), Theme::IconsBaseColor}});
|
{QLatin1String(":/utils/images/bookmark.png"), Theme::IconsBaseColor}});
|
||||||
const Icon BOOKMARK_TEXTEDITOR({
|
const Icon BOOKMARK_TEXTEDITOR({
|
||||||
{QLatin1String(":/utils/images/bookmark.png"), Theme::Bookmarks_TextMarkColor}}, Icon::Tint);
|
{QLatin1String(":/utils/images/bookmark.png"), Theme::Bookmarks_TextMarkColor}}, Icon::Tint);
|
||||||
|
const Icon SNAPSHOT_TOOLBAR({
|
||||||
|
{QLatin1String(":/utils/images/snapshot.png"), Theme::IconsBaseColor}});
|
||||||
|
|
||||||
const Icon NEWFILE({
|
const Icon NEWFILE({
|
||||||
{QLatin1String(":/utils/images/filenew.png"), Theme::PanelTextColorMid}}, Icon::Tint);
|
{QLatin1String(":/utils/images/filenew.png"), Theme::PanelTextColorMid}}, Icon::Tint);
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ QTCREATOR_UTILS_EXPORT extern const Icon ERROR;
|
|||||||
QTCREATOR_UTILS_EXPORT extern const Icon BOOKMARK;
|
QTCREATOR_UTILS_EXPORT extern const Icon BOOKMARK;
|
||||||
QTCREATOR_UTILS_EXPORT extern const Icon BOOKMARK_TOOLBAR;
|
QTCREATOR_UTILS_EXPORT extern const Icon BOOKMARK_TOOLBAR;
|
||||||
QTCREATOR_UTILS_EXPORT extern const Icon BOOKMARK_TEXTEDITOR;
|
QTCREATOR_UTILS_EXPORT extern const Icon BOOKMARK_TEXTEDITOR;
|
||||||
|
QTCREATOR_UTILS_EXPORT extern const Icon SNAPSHOT_TOOLBAR;
|
||||||
|
|
||||||
QTCREATOR_UTILS_EXPORT extern const Icon NEWFILE;
|
QTCREATOR_UTILS_EXPORT extern const Icon NEWFILE;
|
||||||
QTCREATOR_UTILS_EXPORT extern const Icon OPENFILE;
|
QTCREATOR_UTILS_EXPORT extern const Icon OPENFILE;
|
||||||
|
|||||||
@@ -43,12 +43,8 @@ AndroidManifestDocument::AndroidManifestDocument(AndroidManifestEditorWidget *ed
|
|||||||
setId(Constants::ANDROID_MANIFEST_EDITOR_ID);
|
setId(Constants::ANDROID_MANIFEST_EDITOR_ID);
|
||||||
setMimeType(QLatin1String(Constants::ANDROID_MANIFEST_MIME_TYPE));
|
setMimeType(QLatin1String(Constants::ANDROID_MANIFEST_MIME_TYPE));
|
||||||
setSuspendAllowed(false);
|
setSuspendAllowed(false);
|
||||||
connect(editorWidget, &AndroidManifestEditorWidget::modificationChanged,
|
connect(editorWidget, &AndroidManifestEditorWidget::guiChanged,
|
||||||
this, &Core::IDocument::setModified);
|
this, &Core::IDocument::changed);
|
||||||
connect(this, &Core::IDocument::modificationChanged,
|
|
||||||
editorWidget, &AndroidManifestEditorWidget::setModified);
|
|
||||||
|
|
||||||
setModified(editorWidget->isModified());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidManifestDocument::save(QString *errorString, const QString &fileName, bool autoSave)
|
bool AndroidManifestDocument::save(QString *errorString, const QString &fileName, bool autoSave)
|
||||||
@@ -59,6 +55,11 @@ bool AndroidManifestDocument::save(QString *errorString, const QString &fileName
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AndroidManifestDocument::isModified() const
|
||||||
|
{
|
||||||
|
return TextDocument::isModified() || m_editorWidget->isModified();
|
||||||
|
}
|
||||||
|
|
||||||
bool AndroidManifestDocument::isSaveAsAllowed() const
|
bool AndroidManifestDocument::isSaveAsAllowed() const
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public:
|
|||||||
bool save(QString *errorString, const QString &fileName = QString(),
|
bool save(QString *errorString, const QString &fileName = QString(),
|
||||||
bool autoSave = false) override;
|
bool autoSave = false) override;
|
||||||
|
|
||||||
|
bool isModified() const override;
|
||||||
bool isSaveAsAllowed() const override;
|
bool isSaveAsAllowed() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ Project *androidProject(const Utils::FileName &fileName)
|
|||||||
|
|
||||||
AndroidManifestEditorWidget::AndroidManifestEditorWidget()
|
AndroidManifestEditorWidget::AndroidManifestEditorWidget()
|
||||||
: QStackedWidget(),
|
: QStackedWidget(),
|
||||||
m_modified(false),
|
m_dirty(false),
|
||||||
m_stayClean(false)
|
m_stayClean(false)
|
||||||
{
|
{
|
||||||
m_textEditorWidget = new AndroidManifestTextEditorWidget(this);
|
m_textEditorWidget = new AndroidManifestTextEditorWidget(this);
|
||||||
@@ -138,7 +138,7 @@ void AndroidManifestEditorWidget::initializePage()
|
|||||||
QGroupBox *packageGroupBox = new QGroupBox(mainWidget);
|
QGroupBox *packageGroupBox = new QGroupBox(mainWidget);
|
||||||
topLayout->addWidget(packageGroupBox);
|
topLayout->addWidget(packageGroupBox);
|
||||||
|
|
||||||
auto setDirtyFunc = [this] { setModified(); };
|
auto setDirtyFunc = [this] { setDirty(); };
|
||||||
packageGroupBox->setTitle(tr("Package"));
|
packageGroupBox->setTitle(tr("Package"));
|
||||||
{
|
{
|
||||||
QFormLayout *formLayout = new QFormLayout();
|
QFormLayout *formLayout = new QFormLayout();
|
||||||
@@ -206,7 +206,7 @@ void AndroidManifestEditorWidget::initializePage()
|
|||||||
connect(m_packageNameLineEdit, &QLineEdit::textEdited,
|
connect(m_packageNameLineEdit, &QLineEdit::textEdited,
|
||||||
this, &AndroidManifestEditorWidget::setPackageName);
|
this, &AndroidManifestEditorWidget::setPackageName);
|
||||||
connect(m_versionCode, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
|
connect(m_versionCode, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
|
||||||
this, &AndroidManifestEditorWidget::setModified);
|
this, &AndroidManifestEditorWidget::setDirty);
|
||||||
connect(m_versionNameLinedit, &QLineEdit::textEdited,
|
connect(m_versionNameLinedit, &QLineEdit::textEdited,
|
||||||
this, setDirtyFunc);
|
this, setDirtyFunc);
|
||||||
connect(m_androidMinSdkVersion,
|
connect(m_androidMinSdkVersion,
|
||||||
@@ -524,17 +524,17 @@ void AndroidManifestEditorWidget::updateAfterFileLoad()
|
|||||||
setActivePage(Source);
|
setActivePage(Source);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidManifestEditorWidget::setModified(bool modified)
|
void AndroidManifestEditorWidget::setDirty(bool dirty)
|
||||||
{
|
{
|
||||||
if (m_stayClean || modified == m_modified)
|
if (m_stayClean || dirty == m_dirty)
|
||||||
return;
|
return;
|
||||||
m_modified = modified;
|
m_dirty = dirty;
|
||||||
emit modificationChanged(modified);
|
emit guiChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidManifestEditorWidget::isModified() const
|
bool AndroidManifestEditorWidget::isModified() const
|
||||||
{
|
{
|
||||||
return m_modified
|
return m_dirty
|
||||||
|| !m_hIconPath.isEmpty()
|
|| !m_hIconPath.isEmpty()
|
||||||
|| !m_mIconPath.isEmpty()
|
|| !m_mIconPath.isEmpty()
|
||||||
|| !m_lIconPath.isEmpty();
|
|| !m_lIconPath.isEmpty();
|
||||||
@@ -819,7 +819,7 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
|
|||||||
updateAddRemovePermissionButtons();
|
updateAddRemovePermissionButtons();
|
||||||
|
|
||||||
m_stayClean = false;
|
m_stayClean = false;
|
||||||
m_modified = false;
|
m_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int extractVersion(const QString &string)
|
int extractVersion(const QString &string)
|
||||||
@@ -862,7 +862,7 @@ void AndroidManifestEditorWidget::syncToEditor()
|
|||||||
m_textEditorWidget->setPlainText(result);
|
m_textEditorWidget->setPlainText(result);
|
||||||
m_textEditorWidget->document()->setModified(true);
|
m_textEditorWidget->document()->setModified(true);
|
||||||
|
|
||||||
m_modified = false;
|
m_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -1253,7 +1253,7 @@ void AndroidManifestEditorWidget::setLDPIIcon()
|
|||||||
return;
|
return;
|
||||||
m_lIconPath = file;
|
m_lIconPath = file;
|
||||||
m_lIconButton->setIcon(QIcon(file));
|
m_lIconButton->setIcon(QIcon(file));
|
||||||
setModified(true);
|
setDirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidManifestEditorWidget::setMDPIIcon()
|
void AndroidManifestEditorWidget::setMDPIIcon()
|
||||||
@@ -1263,7 +1263,7 @@ void AndroidManifestEditorWidget::setMDPIIcon()
|
|||||||
return;
|
return;
|
||||||
m_mIconPath = file;
|
m_mIconPath = file;
|
||||||
m_mIconButton->setIcon(QIcon(file));
|
m_mIconButton->setIcon(QIcon(file));
|
||||||
setModified(true);
|
setDirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidManifestEditorWidget::setHDPIIcon()
|
void AndroidManifestEditorWidget::setHDPIIcon()
|
||||||
@@ -1273,12 +1273,12 @@ void AndroidManifestEditorWidget::setHDPIIcon()
|
|||||||
return;
|
return;
|
||||||
m_hIconPath = file;
|
m_hIconPath = file;
|
||||||
m_hIconButton->setIcon(QIcon(file));
|
m_hIconButton->setIcon(QIcon(file));
|
||||||
setModified(true);
|
setDirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidManifestEditorWidget::defaultPermissionOrFeatureCheckBoxClicked()
|
void AndroidManifestEditorWidget::defaultPermissionOrFeatureCheckBoxClicked()
|
||||||
{
|
{
|
||||||
setModified(true);
|
setDirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidManifestEditorWidget::updateAddRemovePermissionButtons()
|
void AndroidManifestEditorWidget::updateAddRemovePermissionButtons()
|
||||||
@@ -1293,7 +1293,7 @@ void AndroidManifestEditorWidget::addPermission()
|
|||||||
{
|
{
|
||||||
m_permissionsModel->addPermission(m_permissionsComboBox->currentText());
|
m_permissionsModel->addPermission(m_permissionsComboBox->currentText());
|
||||||
updateAddRemovePermissionButtons();
|
updateAddRemovePermissionButtons();
|
||||||
setModified(true);
|
setDirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidManifestEditorWidget::removePermission()
|
void AndroidManifestEditorWidget::removePermission()
|
||||||
@@ -1302,7 +1302,7 @@ void AndroidManifestEditorWidget::removePermission()
|
|||||||
if (idx.isValid())
|
if (idx.isValid())
|
||||||
m_permissionsModel->removePermission(idx.row());
|
m_permissionsModel->removePermission(idx.row());
|
||||||
updateAddRemovePermissionButtons();
|
updateAddRemovePermissionButtons();
|
||||||
setModified(true);
|
setDirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidManifestEditorWidget::setPackageName()
|
void AndroidManifestEditorWidget::setPackageName()
|
||||||
@@ -1312,7 +1312,7 @@ void AndroidManifestEditorWidget::setPackageName()
|
|||||||
bool valid = checkPackageName(packageName);
|
bool valid = checkPackageName(packageName);
|
||||||
m_packageNameWarning->setVisible(!valid);
|
m_packageNameWarning->setVisible(!valid);
|
||||||
m_packageNameWarningIcon->setVisible(!valid);
|
m_packageNameWarningIcon->setVisible(!valid);
|
||||||
setModified(true);
|
setDirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -101,10 +101,10 @@ public:
|
|||||||
Core::IEditor *editor() const;
|
Core::IEditor *editor() const;
|
||||||
TextEditor::TextEditorWidget *textEditorWidget() const;
|
TextEditor::TextEditorWidget *textEditorWidget() const;
|
||||||
|
|
||||||
void setModified(bool modified = true);
|
void setDirty(bool dirty = true);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void modificationChanged(bool modified);
|
void guiChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool eventFilter(QObject *obj, QEvent *event);
|
bool eventFilter(QObject *obj, QEvent *event);
|
||||||
@@ -150,7 +150,7 @@ private:
|
|||||||
QString parseComment(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
QString parseComment(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||||
void parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
void parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer);
|
||||||
|
|
||||||
bool m_modified; // indicates that we need to call syncToEditor()
|
bool m_dirty; // indicates that we need to call syncToEditor()
|
||||||
bool m_stayClean;
|
bool m_stayClean;
|
||||||
int m_errorLine;
|
int m_errorLine;
|
||||||
int m_errorColumn;
|
int m_errorColumn;
|
||||||
|
|||||||
@@ -320,6 +320,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
bool isModified() const override
|
||||||
|
{
|
||||||
|
return isTemporary()/*e.g. memory view*/ ? false
|
||||||
|
: m_widget->isModified();
|
||||||
|
}
|
||||||
|
|
||||||
bool isFileReadOnly() const override {
|
bool isFileReadOnly() const override {
|
||||||
const FileName fn = filePath();
|
const FileName fn = filePath();
|
||||||
if (fn.isEmpty())
|
if (fn.isEmpty())
|
||||||
@@ -385,12 +391,7 @@ public:
|
|||||||
connect(m_addressEdit, &QLineEdit::editingFinished,
|
connect(m_addressEdit, &QLineEdit::editingFinished,
|
||||||
this, &BinEditor::jumpToAddress);
|
this, &BinEditor::jumpToAddress);
|
||||||
connect(widget, &BinEditorWidget::modificationChanged,
|
connect(widget, &BinEditorWidget::modificationChanged,
|
||||||
m_file, &IDocument::setModified);
|
m_file, &IDocument::changed);
|
||||||
connect(m_file, &IDocument::modificationChanged,
|
|
||||||
widget, &BinEditorWidget::setModified);
|
|
||||||
|
|
||||||
m_file->setModified(widget->isModified());
|
|
||||||
|
|
||||||
updateCursorPosition(widget->cursorPosition());
|
updateCursorPosition(widget->cursorPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,7 @@
|
|||||||
|
|
||||||
#include <cplusplus/Icons.h>
|
#include <cplusplus/Icons.h>
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
@@ -691,8 +692,10 @@ void IpcCommunicator::logRestartedDueToUnexpectedFinish()
|
|||||||
|
|
||||||
void IpcCommunicator::logError(const QString &text)
|
void IpcCommunicator::logError(const QString &text)
|
||||||
{
|
{
|
||||||
Core::MessageManager::write(text, Core::MessageManager::Flash);
|
const QString textWithTimestamp = QDateTime::currentDateTime().toString(Qt::ISODate)
|
||||||
qWarning("%s", qPrintable(text));
|
+ ' ' + text;
|
||||||
|
Core::MessageManager::write(textWithTimestamp, Core::MessageManager::Flash);
|
||||||
|
qWarning("%s", qPrintable(textWithTimestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IpcCommunicator::initializeBackendWithCurrentData()
|
void IpcCommunicator::initializeBackendWithCurrentData()
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ include(../../shared/clang/clang_installation.pri)
|
|||||||
|
|
||||||
# The following defines are used to determine the clang include path for intrinsics.
|
# The following defines are used to determine the clang include path for intrinsics.
|
||||||
DEFINES += CLANG_VERSION=\\\"$${LLVM_VERSION}\\\"
|
DEFINES += CLANG_VERSION=\\\"$${LLVM_VERSION}\\\"
|
||||||
DEFINES += "\"CLANG_RESOURCE_DIR=\\\"$${LLVM_LIBDIR}/clang/$${LLVM_VERSION}/include\\\"\""
|
CLANG_RESOURCE_DIR=$$clean_path($${LLVM_LIBDIR}/clang/$${LLVM_VERSION}/include)
|
||||||
|
DEFINES += "\"CLANG_RESOURCE_DIR=\\\"$${CLANG_RESOURCE_DIR}\\\"\""
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
clangactivationsequencecontextprocessor.cpp \
|
clangactivationsequencecontextprocessor.cpp \
|
||||||
|
|||||||
@@ -28,34 +28,22 @@
|
|||||||
|
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/tooltip/tooltip.h>
|
#include <utils/tooltip/tooltip.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDesktopWidget>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QHBoxLayout>
|
#include <QHash>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QPushButton>
|
|
||||||
#include <QVBoxLayout>
|
using namespace ClangCodeModel;
|
||||||
|
using Internal::ClangDiagnosticWidget;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char LINK_ACTION_GOTO_LOCATION[] = "#gotoLocation";
|
const char LINK_ACTION_GOTO_LOCATION[] = "#gotoLocation";
|
||||||
const char LINK_ACTION_APPLY_FIX[] = "#applyFix";
|
const char LINK_ACTION_APPLY_FIX[] = "#applyFix";
|
||||||
const int childIndentationOnTheLeftInPixel = 10;
|
|
||||||
|
|
||||||
QString wrapInBoldTags(const QString &text)
|
|
||||||
{
|
|
||||||
return QStringLiteral("<b>") + text + QStringLiteral("</b>");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString wrapInLink(const QString &text, const QString &target)
|
|
||||||
{
|
|
||||||
return QStringLiteral("<a href='%1' style='text-decoration:none'>%2</a>").arg(target, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString wrapInColor(const QString &text, const QByteArray &color)
|
|
||||||
{
|
|
||||||
return QStringLiteral("<font color='%2'>%1</font>").arg(text, QString::fromUtf8(color));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString fileNamePrefix(const QString &mainFilePath,
|
QString fileNamePrefix(const QString &mainFilePath,
|
||||||
const ClangBackEnd::SourceLocationContainer &location)
|
const ClangBackEnd::SourceLocationContainer &location)
|
||||||
@@ -74,18 +62,202 @@ QString locationToString(const ClangBackEnd::SourceLocationContainer &location)
|
|||||||
+ QString::number(location.column());
|
+ QString::number(location.column());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString clickableLocation(const QString &mainFilePath,
|
void openEditorAt(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||||
const ClangBackEnd::SourceLocationContainer &location)
|
|
||||||
{
|
{
|
||||||
|
const ClangBackEnd::SourceLocationContainer location = diagnostic.location();
|
||||||
|
|
||||||
|
Core::EditorManager::openEditorAt(location.filePath().toString(),
|
||||||
|
int(location.line()),
|
||||||
|
int(location.column() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyFixit(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||||
|
{
|
||||||
|
ClangCodeModel::ClangFixItOperation operation(Utf8String(), diagnostic.fixIts());
|
||||||
|
|
||||||
|
operation.perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
class WidgetFromDiagnostics
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct DisplayHints {
|
||||||
|
bool showCategoryAndEnableOption;
|
||||||
|
bool showFileNameInMainDiagnostic;
|
||||||
|
bool enableClickableFixits;
|
||||||
|
bool limitWidth;
|
||||||
|
bool hideTooltipAfterLinkActivation;
|
||||||
|
};
|
||||||
|
|
||||||
|
static QWidget *create(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||||
|
const DisplayHints &displayHints)
|
||||||
|
{
|
||||||
|
WidgetFromDiagnostics converter(displayHints);
|
||||||
|
return converter.createWidget(diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class IndentMode { Indent, DoNotIndent };
|
||||||
|
|
||||||
|
WidgetFromDiagnostics(const DisplayHints &displayHints)
|
||||||
|
: m_displayHints(displayHints)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *createWidget(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics)
|
||||||
|
{
|
||||||
|
const QString text = htmlText(diagnostics);
|
||||||
|
|
||||||
|
auto *label = new QLabel;
|
||||||
|
label->setTextFormat(Qt::RichText);
|
||||||
|
label->setText(text);
|
||||||
|
label->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||||
|
// Using "setWordWrap(true)" alone will wrap the text already for small
|
||||||
|
// widths, so do not require word wrapping until we hit limits.
|
||||||
|
if (m_displayHints.limitWidth && label->sizeHint().width() > widthLimit()) {
|
||||||
|
label->setMaximumWidth(widthLimit());
|
||||||
|
label->setWordWrap(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TargetIdToDiagnosticTable table = m_targetIdsToDiagnostics;
|
||||||
|
const bool hideToolTipAfterLinkActivation = m_displayHints.hideTooltipAfterLinkActivation;
|
||||||
|
QObject::connect(label, &QLabel::linkActivated, [table, hideToolTipAfterLinkActivation]
|
||||||
|
(const QString &action) {
|
||||||
|
const ClangBackEnd::DiagnosticContainer diagnostic = table.value(action);
|
||||||
|
QTC_ASSERT(diagnostic != ClangBackEnd::DiagnosticContainer(), return);
|
||||||
|
|
||||||
|
if (action.startsWith(LINK_ACTION_APPLY_FIX))
|
||||||
|
applyFixit(diagnostic);
|
||||||
|
else
|
||||||
|
openEditorAt(diagnostic);
|
||||||
|
|
||||||
|
if (hideToolTipAfterLinkActivation)
|
||||||
|
Utils::ToolTip::hideImmediately();
|
||||||
|
});
|
||||||
|
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString htmlText(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics)
|
||||||
|
{
|
||||||
|
// For debugging, add: style='border-width:1px;border-color:black'
|
||||||
|
QString text = "<table cellspacing='0' cellpadding='0'>";
|
||||||
|
|
||||||
|
foreach (const ClangBackEnd::DiagnosticContainer &diagnostic, diagnostics)
|
||||||
|
text.append(tableRows(diagnostic));
|
||||||
|
|
||||||
|
text.append("</table>");
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString tableRows(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||||
|
{
|
||||||
|
m_mainFilePath = m_displayHints.showFileNameInMainDiagnostic
|
||||||
|
? Utf8String()
|
||||||
|
: diagnostic.location().filePath();
|
||||||
|
|
||||||
|
QString text;
|
||||||
|
|
||||||
|
if (m_displayHints.showCategoryAndEnableOption)
|
||||||
|
text.append(diagnosticCategoryAndEnableOptionRow(diagnostic));
|
||||||
|
text.append(diagnosticRow(diagnostic, IndentMode::DoNotIndent));
|
||||||
|
text.append(diagnosticRowsForChildren(diagnostic));
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString diagnosticCategoryAndEnableOptionRow(
|
||||||
|
const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||||
|
{
|
||||||
|
const QString text = QString::fromLatin1(
|
||||||
|
" <tr>"
|
||||||
|
" <td align='left'><b>%1</b></td>"
|
||||||
|
" <td align='right'><font color='gray'>%2</font></td>"
|
||||||
|
" </tr>")
|
||||||
|
.arg(diagnostic.category(), diagnostic.enableOption());
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString diagnosticText(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||||
|
{
|
||||||
|
const bool hasFixit = m_displayHints.enableClickableFixits
|
||||||
|
&& !diagnostic.fixIts().isEmpty();
|
||||||
|
const QString diagnosticText = diagnostic.text().toString().toHtmlEscaped();
|
||||||
|
|
||||||
|
// For debugging, add to <table>: style='border-width:1px;border-color:red'
|
||||||
|
const QString text = QString::fromLatin1(
|
||||||
|
"<table cellspacing='0' cellpadding='0'>"
|
||||||
|
" <tr>"
|
||||||
|
" <td>%1: </td>"
|
||||||
|
" <td width='100%'>%2</td>"
|
||||||
|
" </tr>"
|
||||||
|
"</table>")
|
||||||
|
.arg(clickableLocation(diagnostic, m_mainFilePath),
|
||||||
|
clickableFixIt(diagnostic, diagnosticText, hasFixit));
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString diagnosticRow(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||||
|
IndentMode indentMode)
|
||||||
|
{
|
||||||
|
const QString text = QString::fromLatin1(
|
||||||
|
" <tr>"
|
||||||
|
" <td colspan='2' align='left' style='%1'>%2</td>"
|
||||||
|
" </tr>")
|
||||||
|
.arg(indentModeToHtmlStyle(indentMode),
|
||||||
|
diagnosticText(diagnostic));
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString diagnosticRowsForChildren(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||||
|
{
|
||||||
|
const QVector<ClangBackEnd::DiagnosticContainer> children = diagnostic.children();
|
||||||
|
QString text;
|
||||||
|
|
||||||
|
if (children.size() <= 10) {
|
||||||
|
text += diagnosticRowsForChildren(children.begin(), children.end());
|
||||||
|
} else {
|
||||||
|
text += diagnosticRowsForChildren(children.begin(), children.begin() + 7);
|
||||||
|
text += ellipsisRow();
|
||||||
|
text += diagnosticRowsForChildren(children.end() - 3, children.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString diagnosticRowsForChildren(
|
||||||
|
const QVector<ClangBackEnd::DiagnosticContainer>::const_iterator first,
|
||||||
|
const QVector<ClangBackEnd::DiagnosticContainer>::const_iterator last)
|
||||||
|
{
|
||||||
|
QString text;
|
||||||
|
|
||||||
|
for (auto it = first; it != last; ++it)
|
||||||
|
text.append(diagnosticRow(*it, IndentMode::Indent));
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString clickableLocation(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||||
|
const QString &mainFilePath)
|
||||||
|
{
|
||||||
|
const ClangBackEnd::SourceLocationContainer location = diagnostic.location();
|
||||||
|
|
||||||
const QString filePrefix = fileNamePrefix(mainFilePath, location);
|
const QString filePrefix = fileNamePrefix(mainFilePath, location);
|
||||||
const QString lineColumn = locationToString(location);
|
const QString lineColumn = locationToString(location);
|
||||||
const QString linkText = filePrefix + lineColumn;
|
const QString linkText = filePrefix + lineColumn;
|
||||||
|
const QString targetId = generateTargetId(LINK_ACTION_GOTO_LOCATION, diagnostic);
|
||||||
|
|
||||||
return wrapInLink(linkText, QLatin1String(LINK_ACTION_GOTO_LOCATION));
|
return wrapInLink(linkText, targetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString clickableFixIt(const QString &text, bool hasFixIt)
|
QString clickableFixIt(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||||
{
|
const QString &text,
|
||||||
|
bool hasFixIt)
|
||||||
|
{
|
||||||
if (!hasFixIt)
|
if (!hasFixIt)
|
||||||
return text;
|
return text;
|
||||||
|
|
||||||
@@ -98,157 +270,85 @@ QString clickableFixIt(const QString &text, bool hasFixIt)
|
|||||||
clickableText = text.mid(colonPosition + 2);
|
clickableText = text.mid(colonPosition + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nonClickableCategory + wrapInLink(clickableText, QLatin1String(LINK_ACTION_APPLY_FIX));
|
const QString targetId = generateTargetId(LINK_ACTION_APPLY_FIX, diagnostic);
|
||||||
}
|
|
||||||
|
|
||||||
void openEditorAt(const ClangBackEnd::SourceLocationContainer &location)
|
return nonClickableCategory + wrapInLink(clickableText, targetId);
|
||||||
{
|
}
|
||||||
Core::EditorManager::openEditorAt(location.filePath().toString(),
|
|
||||||
int(location.line()),
|
|
||||||
int(location.column() - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void applyFixit(const QVector<ClangBackEnd::FixItContainer> &fixits)
|
QString generateTargetId(const QString &targetPrefix,
|
||||||
{
|
const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||||
ClangCodeModel::ClangFixItOperation operation(Utf8String(), fixits);
|
|
||||||
|
|
||||||
operation.perform();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename LayoutType>
|
|
||||||
LayoutType *createLayout()
|
|
||||||
{
|
|
||||||
auto *layout = new LayoutType;
|
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
layout->setSpacing(2);
|
|
||||||
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum IndentType { IndentDiagnostic, DoNotIndentDiagnostic };
|
|
||||||
|
|
||||||
QWidget *createDiagnosticLabel(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
|
||||||
const QString &mainFilePath,
|
|
||||||
IndentType indentType = DoNotIndentDiagnostic,
|
|
||||||
bool enableClickableFixits = true)
|
|
||||||
{
|
|
||||||
const bool hasFixit = enableClickableFixits ? !diagnostic.fixIts().isEmpty() : false;
|
|
||||||
const QString diagnosticText = diagnostic.text().toString().toHtmlEscaped();
|
|
||||||
const QString text = clickableLocation(mainFilePath, diagnostic.location())
|
|
||||||
+ QStringLiteral(": ")
|
|
||||||
+ clickableFixIt(diagnosticText, hasFixit);
|
|
||||||
const ClangBackEnd::SourceLocationContainer location = diagnostic.location();
|
|
||||||
const QVector<ClangBackEnd::FixItContainer> fixits = diagnostic.fixIts();
|
|
||||||
|
|
||||||
auto *label = new QLabel(text);
|
|
||||||
if (indentType == IndentDiagnostic)
|
|
||||||
label->setContentsMargins(childIndentationOnTheLeftInPixel, 0, 0, 0);
|
|
||||||
label->setTextFormat(Qt::RichText);
|
|
||||||
QObject::connect(label, &QLabel::linkActivated, [location, fixits](const QString &action) {
|
|
||||||
if (action == QLatin1String(LINK_ACTION_APPLY_FIX))
|
|
||||||
applyFixit(fixits);
|
|
||||||
else
|
|
||||||
openEditorAt(location);
|
|
||||||
|
|
||||||
Utils::ToolTip::hideImmediately();
|
|
||||||
});
|
|
||||||
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MainDiagnosticWidget : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
MainDiagnosticWidget(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
|
||||||
const ClangCodeModel::Internal::DisplayHints &displayHints)
|
|
||||||
{
|
{
|
||||||
setContentsMargins(0, 0, 0, 0);
|
const QString idAsString = QString::number(++m_targetIdCounter);
|
||||||
auto *mainLayout = createLayout<QVBoxLayout>();
|
const QString targetId = targetPrefix + idAsString;
|
||||||
|
m_targetIdsToDiagnostics.insert(targetId, diagnostic);
|
||||||
|
|
||||||
const ClangBackEnd::SourceLocationContainer location = diagnostic.location();
|
return targetId;
|
||||||
|
|
||||||
// Set up header row: category + responsible option
|
|
||||||
if (displayHints.showMainDiagnosticHeader) {
|
|
||||||
const QString category = diagnostic.category();
|
|
||||||
const QString responsibleOption = diagnostic.enableOption();
|
|
||||||
|
|
||||||
auto *headerLayout = createLayout<QHBoxLayout>();
|
|
||||||
headerLayout->addWidget(new QLabel(wrapInBoldTags(category)), 1);
|
|
||||||
|
|
||||||
auto *responsibleOptionLabel = new QLabel(wrapInColor(responsibleOption, "gray"));
|
|
||||||
headerLayout->addWidget(responsibleOptionLabel, 0);
|
|
||||||
mainLayout->addLayout(headerLayout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up main row: diagnostic text
|
static QString wrapInLink(const QString &text, const QString &target)
|
||||||
const Utf8String mainFilePath = displayHints.showFileNameInMainDiagnostic
|
{
|
||||||
? Utf8String()
|
return QStringLiteral("<a href='%1' style='text-decoration:none'>%2</a>").arg(target, text);
|
||||||
: location.filePath();
|
|
||||||
mainLayout->addWidget(createDiagnosticLabel(diagnostic,
|
|
||||||
mainFilePath,
|
|
||||||
DoNotIndentDiagnostic,
|
|
||||||
displayHints.enableClickableFixits));
|
|
||||||
|
|
||||||
setLayout(mainLayout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString ellipsisRow()
|
||||||
|
{
|
||||||
|
return QString::fromLatin1(
|
||||||
|
" <tr>"
|
||||||
|
" <td colspan='2' align='left' style='%1'>...</td>"
|
||||||
|
" </tr>")
|
||||||
|
.arg(indentModeToHtmlStyle(IndentMode::Indent));
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString indentModeToHtmlStyle(IndentMode indentMode)
|
||||||
|
{
|
||||||
|
return indentMode == IndentMode::Indent
|
||||||
|
? QString("padding-left:10px")
|
||||||
|
: QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int widthLimit()
|
||||||
|
{
|
||||||
|
return QApplication::desktop()->availableGeometry(QCursor::pos()).width() / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const DisplayHints m_displayHints;
|
||||||
|
|
||||||
|
using TargetIdToDiagnosticTable = QHash<QString, ClangBackEnd::DiagnosticContainer>;
|
||||||
|
TargetIdToDiagnosticTable m_targetIdsToDiagnostics;
|
||||||
|
unsigned m_targetIdCounter = 0;
|
||||||
|
|
||||||
|
QString m_mainFilePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
void addChildrenToLayout(const QString &mainFilePath,
|
|
||||||
const QVector<ClangBackEnd::DiagnosticContainer>::const_iterator first,
|
|
||||||
const QVector<ClangBackEnd::DiagnosticContainer>::const_iterator last,
|
|
||||||
bool enableClickableFixits,
|
|
||||||
QLayout &boxLayout)
|
|
||||||
{
|
|
||||||
for (auto it = first; it != last; ++it) {
|
|
||||||
boxLayout.addWidget(createDiagnosticLabel(*it,
|
|
||||||
mainFilePath,
|
|
||||||
IndentDiagnostic,
|
|
||||||
enableClickableFixits));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupChildDiagnostics(const QString &mainFilePath,
|
|
||||||
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
|
||||||
bool enableClickableFixits,
|
|
||||||
QLayout &boxLayout)
|
|
||||||
{
|
|
||||||
if (diagnostics.size() <= 10) {
|
|
||||||
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.end(),
|
|
||||||
enableClickableFixits, boxLayout);
|
|
||||||
} else {
|
|
||||||
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.begin() + 7,
|
|
||||||
enableClickableFixits, boxLayout);
|
|
||||||
|
|
||||||
auto ellipsisLabel = new QLabel(QStringLiteral("..."));
|
|
||||||
ellipsisLabel->setContentsMargins(childIndentationOnTheLeftInPixel, 0, 0, 0);
|
|
||||||
boxLayout.addWidget(ellipsisLabel);
|
|
||||||
|
|
||||||
addChildrenToLayout(mainFilePath, diagnostics.end() - 3, diagnostics.end(),
|
|
||||||
enableClickableFixits, boxLayout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
void addToolTipToLayout(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
QWidget *ClangDiagnosticWidget::create(
|
||||||
QLayout *target,
|
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||||
const DisplayHints &displayHints)
|
const Destination &destination)
|
||||||
{
|
{
|
||||||
// Set up header and text row for main diagnostic
|
WidgetFromDiagnostics::DisplayHints hints;
|
||||||
target->addWidget(new MainDiagnosticWidget(diagnostic, displayHints));
|
|
||||||
|
|
||||||
// Set up child rows for notes
|
if (destination == ToolTip) {
|
||||||
setupChildDiagnostics(diagnostic.location().filePath(),
|
hints.showCategoryAndEnableOption = true;
|
||||||
diagnostic.children(),
|
hints.showFileNameInMainDiagnostic = false;
|
||||||
displayHints.enableClickableFixits,
|
hints.enableClickableFixits = true;
|
||||||
*target);
|
hints.limitWidth = true;
|
||||||
|
hints.hideTooltipAfterLinkActivation = true;
|
||||||
|
} else { // Info Bar
|
||||||
|
hints.showCategoryAndEnableOption = false;
|
||||||
|
hints.showFileNameInMainDiagnostic = true;
|
||||||
|
// Clickable fixits might change toolchain headers, so disable.
|
||||||
|
hints.enableClickableFixits = false;
|
||||||
|
hints.limitWidth = false;
|
||||||
|
hints.hideTooltipAfterLinkActivation = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WidgetFromDiagnostics::create(diagnostics, hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
|
||||||
#include "clangdiagnostictooltipwidget.moc"
|
|
||||||
|
|||||||
@@ -34,15 +34,13 @@ QT_END_NAMESPACE
|
|||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
struct DisplayHints {
|
class ClangDiagnosticWidget {
|
||||||
bool showMainDiagnosticHeader = true;
|
public:
|
||||||
bool showFileNameInMainDiagnostic = false;
|
enum Destination { ToolTip, InfoBar };
|
||||||
bool enableClickableFixits = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
void addToolTipToLayout(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
static QWidget *create(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||||
QLayout *target,
|
const Destination &destination);
|
||||||
const DisplayHints &displayHints = DisplayHints());
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
|||||||
@@ -263,8 +263,12 @@ void ClangEditorDocumentProcessor::addDiagnosticToolTipToLayout(uint line,
|
|||||||
uint column,
|
uint column,
|
||||||
QLayout *target) const
|
QLayout *target) const
|
||||||
{
|
{
|
||||||
foreach (const auto &diagnostic, m_diagnosticManager.diagnosticsAt(line, column))
|
using Internal::ClangDiagnosticWidget;
|
||||||
addToolTipToLayout(diagnostic, target);
|
|
||||||
|
const QVector<ClangBackEnd::DiagnosticContainer> diagnostics
|
||||||
|
= m_diagnosticManager.diagnosticsAt(line, column);
|
||||||
|
|
||||||
|
target->addWidget(ClangDiagnosticWidget::create(diagnostics, ClangDiagnosticWidget::ToolTip));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangEditorDocumentProcessor::editorDocumentTimerRestarted()
|
void ClangEditorDocumentProcessor::editorDocumentTimerRestarted()
|
||||||
@@ -342,16 +346,6 @@ void ClangEditorDocumentProcessor::requestDocumentAnnotations(const QString &pro
|
|||||||
m_ipcCommunicator.requestDocumentAnnotations(fileContainer);
|
m_ipcCommunicator.requestDocumentAnnotations(fileContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Internal::DisplayHints displayHintsForInfoBar()
|
|
||||||
{
|
|
||||||
Internal::DisplayHints displayHints;
|
|
||||||
displayHints.showMainDiagnosticHeader = false;
|
|
||||||
displayHints.showFileNameInMainDiagnostic = true;
|
|
||||||
displayHints.enableClickableFixits = false; // Tool chain headers might be changed, so disable.
|
|
||||||
|
|
||||||
return displayHints;
|
|
||||||
}
|
|
||||||
|
|
||||||
CppTools::BaseEditorDocumentProcessor::HeaderErrorDiagnosticWidgetCreator
|
CppTools::BaseEditorDocumentProcessor::HeaderErrorDiagnosticWidgetCreator
|
||||||
ClangEditorDocumentProcessor::creatorForHeaderErrorDiagnosticWidget(
|
ClangEditorDocumentProcessor::creatorForHeaderErrorDiagnosticWidget(
|
||||||
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic)
|
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic)
|
||||||
@@ -365,7 +359,8 @@ ClangEditorDocumentProcessor::creatorForHeaderErrorDiagnosticWidget(
|
|||||||
vbox->setContentsMargins(10, 0, 0, 2);
|
vbox->setContentsMargins(10, 0, 0, 2);
|
||||||
vbox->setSpacing(2);
|
vbox->setSpacing(2);
|
||||||
|
|
||||||
addToolTipToLayout(firstHeaderErrorDiagnostic, vbox, displayHintsForInfoBar());
|
vbox->addWidget(ClangDiagnosticWidget::create({firstHeaderErrorDiagnostic},
|
||||||
|
ClangDiagnosticWidget::InfoBar));
|
||||||
|
|
||||||
auto widget = new QWidget;
|
auto widget = new QWidget;
|
||||||
widget->setLayout(vbox);
|
widget->setLayout(vbox);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <utils/icon.h>
|
#include <utils/icon.h>
|
||||||
#include <utils/theme/theme.h>
|
#include <utils/theme/theme.h>
|
||||||
|
|
||||||
|
#include <QLayout>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
@@ -84,7 +85,11 @@ void ClangTextMark::setIcon(ClangBackEnd::DiagnosticSeverity severity)
|
|||||||
|
|
||||||
bool ClangTextMark::addToolTipContent(QLayout *target)
|
bool ClangTextMark::addToolTipContent(QLayout *target)
|
||||||
{
|
{
|
||||||
Internal::addToolTipToLayout(m_diagnostic, target, Internal::DisplayHints());
|
using Internal::ClangDiagnosticWidget;
|
||||||
|
|
||||||
|
QWidget *widget = ClangDiagnosticWidget::create({m_diagnostic}, ClangDiagnosticWidget::ToolTip);
|
||||||
|
target->addWidget(widget);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,11 +89,14 @@ public:
|
|||||||
|
|
||||||
LibClangOptionsBuilder optionsBuilder(*projectPart.data());
|
LibClangOptionsBuilder optionsBuilder(*projectPart.data());
|
||||||
|
|
||||||
|
optionsBuilder.addWordWidth();
|
||||||
optionsBuilder.addTargetTriple();
|
optionsBuilder.addTargetTriple();
|
||||||
optionsBuilder.addLanguageOption(fileKind);
|
optionsBuilder.addLanguageOption(fileKind);
|
||||||
optionsBuilder.addOptionsForLanguage(/*checkForBorlandExtensions*/ true);
|
optionsBuilder.addOptionsForLanguage(/*checkForBorlandExtensions*/ true);
|
||||||
optionsBuilder.enableExceptions();
|
optionsBuilder.enableExceptions();
|
||||||
|
|
||||||
|
optionsBuilder.addDefineToAvoidIncludingGccOrMinGwIntrinsics();
|
||||||
|
optionsBuilder.addDefineFloat128ForMingw();
|
||||||
optionsBuilder.addToolchainAndProjectDefines();
|
optionsBuilder.addToolchainAndProjectDefines();
|
||||||
optionsBuilder.undefineCppLanguageFeatureMacrosForMsvc2015();
|
optionsBuilder.undefineCppLanguageFeatureMacrosForMsvc2015();
|
||||||
|
|
||||||
|
|||||||
@@ -124,11 +124,14 @@ Utils::SmallStringVector RefactoringCompilerOptionsBuilder::build(CppTools::Proj
|
|||||||
|
|
||||||
RefactoringCompilerOptionsBuilder optionsBuilder(projectPart);
|
RefactoringCompilerOptionsBuilder optionsBuilder(projectPart);
|
||||||
|
|
||||||
|
optionsBuilder.addWordWidth();
|
||||||
optionsBuilder.addTargetTriple();
|
optionsBuilder.addTargetTriple();
|
||||||
optionsBuilder.addLanguageOption(fileKind);
|
optionsBuilder.addLanguageOption(fileKind);
|
||||||
optionsBuilder.addOptionsForLanguage(/*checkForBorlandExtensions*/ true);
|
optionsBuilder.addOptionsForLanguage(/*checkForBorlandExtensions*/ true);
|
||||||
optionsBuilder.enableExceptions();
|
optionsBuilder.enableExceptions();
|
||||||
|
|
||||||
|
optionsBuilder.addDefineFloat128ForMingw();
|
||||||
|
optionsBuilder.addDefineToAvoidIncludingGccOrMinGwIntrinsics();
|
||||||
optionsBuilder.addToolchainAndProjectDefines();
|
optionsBuilder.addToolchainAndProjectDefines();
|
||||||
optionsBuilder.undefineCppLanguageFeatureMacrosForMsvc2015();
|
optionsBuilder.undefineCppLanguageFeatureMacrosForMsvc2015();
|
||||||
|
|
||||||
|
|||||||
@@ -197,11 +197,12 @@ bool ClangStaticAnalyzerPreconfiguredSessionTests::switchToProjectAndTarget(Proj
|
|||||||
if (project == activeProject && target == activeProject->activeTarget())
|
if (project == activeProject && target == activeProject->activeTarget())
|
||||||
return true; // OK, desired project/target already active.
|
return true; // OK, desired project/target already active.
|
||||||
|
|
||||||
QSignalSpy waitUntilProjectUpdated(CppModelManager::instance(),
|
|
||||||
&CppModelManager::projectPartsUpdated);
|
|
||||||
|
|
||||||
if (project != activeProject)
|
if (project != activeProject)
|
||||||
m_sessionManager.setStartupProject(project);
|
m_sessionManager.setStartupProject(project);
|
||||||
|
|
||||||
|
if (target != project->activeTarget()) {
|
||||||
|
QSignalSpy waitUntilProjectUpdated(CppModelManager::instance(),
|
||||||
|
&CppModelManager::projectPartsUpdated);
|
||||||
m_sessionManager.setActiveTarget(project, target, ProjectExplorer::SetActive::NoCascade);
|
m_sessionManager.setActiveTarget(project, target, ProjectExplorer::SetActive::NoCascade);
|
||||||
|
|
||||||
const bool waitResult = waitUntilProjectUpdated.wait(30000);
|
const bool waitResult = waitUntilProjectUpdated.wait(30000);
|
||||||
@@ -209,6 +210,7 @@ bool ClangStaticAnalyzerPreconfiguredSessionTests::switchToProjectAndTarget(Proj
|
|||||||
qWarning() << "waitUntilProjectUpdated() failed";
|
qWarning() << "waitUntilProjectUpdated() failed";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,18 +86,18 @@ ClangStaticAnalyzerRunControl::ClangStaticAnalyzerRunControl(
|
|||||||
|
|
||||||
ToolChain *toolChain = ToolChainKitInformation::toolChain(target->kit(), ToolChain::Language::Cxx);
|
ToolChain *toolChain = ToolChainKitInformation::toolChain(target->kit(), ToolChain::Language::Cxx);
|
||||||
QTC_ASSERT(toolChain, return);
|
QTC_ASSERT(toolChain, return);
|
||||||
m_extraToolChainInfo.wordWidth = toolChain->targetAbi().wordWidth();
|
m_targetTriple = toolChain->originalTargetTriple();
|
||||||
m_extraToolChainInfo.targetTriple = toolChain->originalTargetTriple();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prependWordWidthArgumentIfNotIncluded(QStringList *arguments, unsigned char wordWidth)
|
static void prependWordWidthArgumentIfNotIncluded(QStringList *arguments,
|
||||||
|
ProjectPart::ToolChainWordWidth wordWidth)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(arguments, return);
|
QTC_ASSERT(arguments, return);
|
||||||
|
|
||||||
const QString m64Argument = QLatin1String("-m64");
|
const QString m64Argument = QLatin1String("-m64");
|
||||||
const QString m32Argument = QLatin1String("-m32");
|
const QString m32Argument = QLatin1String("-m32");
|
||||||
|
|
||||||
const QString argument = wordWidth == 64 ? m64Argument : m32Argument;
|
const QString argument = wordWidth == ProjectPart::WordWidth64Bit ? m64Argument : m32Argument;
|
||||||
if (!arguments->contains(argument))
|
if (!arguments->contains(argument))
|
||||||
arguments->prepend(argument);
|
arguments->prepend(argument);
|
||||||
|
|
||||||
@@ -165,25 +165,19 @@ class ClangStaticAnalyzerOptionsBuilder : public CompilerOptionsBuilder
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static QStringList build(const CppTools::ProjectPart &projectPart,
|
static QStringList build(const CppTools::ProjectPart &projectPart,
|
||||||
CppTools::ProjectFile::Kind fileKind,
|
CppTools::ProjectFile::Kind fileKind)
|
||||||
const ExtraToolChainInfo &extraParams)
|
|
||||||
{
|
{
|
||||||
ClangStaticAnalyzerOptionsBuilder optionsBuilder(projectPart);
|
ClangStaticAnalyzerOptionsBuilder optionsBuilder(projectPart);
|
||||||
|
|
||||||
|
optionsBuilder.addWordWidth();
|
||||||
optionsBuilder.addTargetTriple();
|
optionsBuilder.addTargetTriple();
|
||||||
optionsBuilder.addLanguageOption(fileKind);
|
optionsBuilder.addLanguageOption(fileKind);
|
||||||
optionsBuilder.addOptionsForLanguage(false);
|
optionsBuilder.addOptionsForLanguage(false);
|
||||||
optionsBuilder.enableExceptions();
|
optionsBuilder.enableExceptions();
|
||||||
|
|
||||||
// In gcc headers, lots of built-ins are referenced that clang does not understand.
|
optionsBuilder.addDefineFloat128ForMingw();
|
||||||
// Therefore, prevent the inclusion of the header that references them. Of course, this
|
optionsBuilder.addDefineToAvoidIncludingGccOrMinGwIntrinsics();
|
||||||
// will break if code actually requires stuff from there, but that should be the less common
|
|
||||||
// case.
|
|
||||||
const Core::Id type = projectPart.toolchainType;
|
const Core::Id type = projectPart.toolchainType;
|
||||||
if (type == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID
|
|
||||||
|| type == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID)
|
|
||||||
optionsBuilder.addDefine("#define _X86INTRIN_H_INCLUDED");
|
|
||||||
|
|
||||||
if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
||||||
optionsBuilder.addDefines(projectPart.toolchainDefines);
|
optionsBuilder.addDefines(projectPart.toolchainDefines);
|
||||||
optionsBuilder.addDefines(projectPart.projectDefines);
|
optionsBuilder.addDefines(projectPart.projectDefines);
|
||||||
@@ -195,10 +189,7 @@ public:
|
|||||||
if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
||||||
optionsBuilder.add(QLatin1String("-fPIC")); // TODO: Remove?
|
optionsBuilder.add(QLatin1String("-fPIC")); // TODO: Remove?
|
||||||
|
|
||||||
QStringList options = optionsBuilder.options();
|
return optionsBuilder.options();
|
||||||
prependWordWidthArgumentIfNotIncluded(&options, extraParams.wordWidth);
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClangStaticAnalyzerOptionsBuilder(const CppTools::ProjectPart &projectPart)
|
ClangStaticAnalyzerOptionsBuilder(const CppTools::ProjectPart &projectPart)
|
||||||
@@ -263,6 +254,13 @@ private:
|
|||||||
return CompilerOptionsBuilder::defineOption();
|
return CompilerOptionsBuilder::defineOption();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString undefineOption() const override
|
||||||
|
{
|
||||||
|
if (m_isMsvcToolchain)
|
||||||
|
return QLatin1String("/U");
|
||||||
|
return CompilerOptionsBuilder::undefineOption();
|
||||||
|
}
|
||||||
|
|
||||||
void enableExceptions() override
|
void enableExceptions() override
|
||||||
{
|
{
|
||||||
if (m_isMsvcToolchain)
|
if (m_isMsvcToolchain)
|
||||||
@@ -318,11 +316,11 @@ static QStringList createHeaderPathsOptionsForClangOnMac(const ProjectPart &proj
|
|||||||
static QStringList tweakedArguments(const ProjectPart &projectPart,
|
static QStringList tweakedArguments(const ProjectPart &projectPart,
|
||||||
const QString &filePath,
|
const QString &filePath,
|
||||||
const QStringList &arguments,
|
const QStringList &arguments,
|
||||||
const ExtraToolChainInfo &extraParams)
|
const QString &targetTriple)
|
||||||
{
|
{
|
||||||
QStringList newArguments = inputAndOutputArgumentsRemoved(filePath, arguments);
|
QStringList newArguments = inputAndOutputArgumentsRemoved(filePath, arguments);
|
||||||
prependWordWidthArgumentIfNotIncluded(&newArguments, extraParams.wordWidth);
|
prependWordWidthArgumentIfNotIncluded(&newArguments, projectPart.toolChainWordWidth);
|
||||||
prependTargetTripleIfNotIncludedAndNotEmpty(&newArguments, extraParams.targetTriple);
|
prependTargetTripleIfNotIncludedAndNotEmpty(&newArguments, targetTriple);
|
||||||
newArguments.append(createHeaderPathsOptionsForClangOnMac(projectPart));
|
newArguments.append(createHeaderPathsOptionsForClangOnMac(projectPart));
|
||||||
newArguments.append(createMsCompatibilityVersionOption(projectPart));
|
newArguments.append(createMsCompatibilityVersionOption(projectPart));
|
||||||
newArguments.append(createOptionsToUndefineClangVersionMacrosForMsvc(projectPart));
|
newArguments.append(createOptionsToUndefineClangVersionMacrosForMsvc(projectPart));
|
||||||
@@ -334,7 +332,7 @@ static QStringList tweakedArguments(const ProjectPart &projectPart,
|
|||||||
static AnalyzeUnits unitsToAnalyzeFromCompilerCallData(
|
static AnalyzeUnits unitsToAnalyzeFromCompilerCallData(
|
||||||
const QHash<QString, ProjectPart::Ptr> &projectFileToProjectPart,
|
const QHash<QString, ProjectPart::Ptr> &projectFileToProjectPart,
|
||||||
const ProjectInfo::CompilerCallData &compilerCallData,
|
const ProjectInfo::CompilerCallData &compilerCallData,
|
||||||
const ExtraToolChainInfo &extraParams)
|
const QString &targetTriple)
|
||||||
{
|
{
|
||||||
qCDebug(LOG) << "Taking arguments for analyzing from CompilerCallData.";
|
qCDebug(LOG) << "Taking arguments for analyzing from CompilerCallData.";
|
||||||
|
|
||||||
@@ -354,7 +352,7 @@ static AnalyzeUnits unitsToAnalyzeFromCompilerCallData(
|
|||||||
const QStringList arguments = tweakedArguments(*projectPart,
|
const QStringList arguments = tweakedArguments(*projectPart,
|
||||||
file,
|
file,
|
||||||
options,
|
options,
|
||||||
extraParams);
|
targetTriple);
|
||||||
unitsToAnalyze << AnalyzeUnit(file, arguments);
|
unitsToAnalyze << AnalyzeUnit(file, arguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,8 +361,7 @@ static AnalyzeUnits unitsToAnalyzeFromCompilerCallData(
|
|||||||
return unitsToAnalyze;
|
return unitsToAnalyze;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AnalyzeUnits unitsToAnalyzeFromProjectParts(const QList<ProjectPart::Ptr> projectParts,
|
static AnalyzeUnits unitsToAnalyzeFromProjectParts(const QList<ProjectPart::Ptr> projectParts)
|
||||||
const ExtraToolChainInfo &extraParams)
|
|
||||||
{
|
{
|
||||||
qCDebug(LOG) << "Taking arguments for analyzing from ProjectParts.";
|
qCDebug(LOG) << "Taking arguments for analyzing from ProjectParts.";
|
||||||
|
|
||||||
@@ -380,9 +377,7 @@ static AnalyzeUnits unitsToAnalyzeFromProjectParts(const QList<ProjectPart::Ptr>
|
|||||||
QTC_CHECK(file.kind != ProjectFile::Unclassified);
|
QTC_CHECK(file.kind != ProjectFile::Unclassified);
|
||||||
if (ProjectFile::isSource(file.kind)) {
|
if (ProjectFile::isSource(file.kind)) {
|
||||||
const QStringList arguments
|
const QStringList arguments
|
||||||
= ClangStaticAnalyzerOptionsBuilder::build(*projectPart.data(),
|
= ClangStaticAnalyzerOptionsBuilder::build(*projectPart.data(), file.kind);
|
||||||
file.kind,
|
|
||||||
extraParams);
|
|
||||||
unitsToAnalyze << AnalyzeUnit(file.path, arguments);
|
unitsToAnalyze << AnalyzeUnit(file.path, arguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -411,13 +406,13 @@ AnalyzeUnits ClangStaticAnalyzerRunControl::sortedUnitsToAnalyze()
|
|||||||
AnalyzeUnits units;
|
AnalyzeUnits units;
|
||||||
const ProjectInfo::CompilerCallData compilerCallData = m_projectInfo.compilerCallData();
|
const ProjectInfo::CompilerCallData compilerCallData = m_projectInfo.compilerCallData();
|
||||||
if (compilerCallData.isEmpty()) {
|
if (compilerCallData.isEmpty()) {
|
||||||
units = unitsToAnalyzeFromProjectParts(m_projectInfo.projectParts(), m_extraToolChainInfo);
|
units = unitsToAnalyzeFromProjectParts(m_projectInfo.projectParts());
|
||||||
} else {
|
} else {
|
||||||
const QHash<QString, ProjectPart::Ptr> projectFileToProjectPart
|
const QHash<QString, ProjectPart::Ptr> projectFileToProjectPart
|
||||||
= generateProjectFileToProjectPartMapping(m_projectInfo.projectParts());
|
= generateProjectFileToProjectPartMapping(m_projectInfo.projectParts());
|
||||||
units = unitsToAnalyzeFromCompilerCallData(projectFileToProjectPart,
|
units = unitsToAnalyzeFromCompilerCallData(projectFileToProjectPart,
|
||||||
compilerCallData,
|
compilerCallData,
|
||||||
m_extraToolChainInfo);
|
m_targetTriple);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::sort(units, &AnalyzeUnit::file);
|
Utils::sort(units, &AnalyzeUnit::file);
|
||||||
|
|||||||
@@ -47,11 +47,6 @@ struct AnalyzeUnit {
|
|||||||
};
|
};
|
||||||
typedef QList<AnalyzeUnit> AnalyzeUnits;
|
typedef QList<AnalyzeUnit> AnalyzeUnits;
|
||||||
|
|
||||||
struct ExtraToolChainInfo {
|
|
||||||
unsigned char wordWidth = 0;
|
|
||||||
QString targetTriple;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ClangStaticAnalyzerRunControl : public ProjectExplorer::RunControl
|
class ClangStaticAnalyzerRunControl : public ProjectExplorer::RunControl
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -88,7 +83,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const CppTools::ProjectInfo m_projectInfo;
|
const CppTools::ProjectInfo m_projectInfo;
|
||||||
ExtraToolChainInfo m_extraToolChainInfo;
|
QString m_targetTriple;
|
||||||
|
|
||||||
Utils::Environment m_environment;
|
Utils::Environment m_environment;
|
||||||
QString m_clangExecutable;
|
QString m_clangExecutable;
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
|
class QDialog;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QPlainTextEdit;
|
class QPlainTextEdit;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
|||||||
@@ -218,7 +218,8 @@ HEADERS += corejsextensions.h \
|
|||||||
iwelcomepage.h \
|
iwelcomepage.h \
|
||||||
systemsettings.h \
|
systemsettings.h \
|
||||||
coreicons.h \
|
coreicons.h \
|
||||||
editormanager/documentmodel_p.h
|
editormanager/documentmodel_p.h \
|
||||||
|
diffservice.h
|
||||||
|
|
||||||
FORMS += dialogs/newdialog.ui \
|
FORMS += dialogs/newdialog.ui \
|
||||||
dialogs/saveitemsdialog.ui \
|
dialogs/saveitemsdialog.ui \
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ Project {
|
|||||||
"corejsextensions.cpp", "corejsextensions.h",
|
"corejsextensions.cpp", "corejsextensions.h",
|
||||||
"coreplugin.cpp", "coreplugin.h",
|
"coreplugin.cpp", "coreplugin.h",
|
||||||
"designmode.cpp", "designmode.h",
|
"designmode.cpp", "designmode.h",
|
||||||
|
"diffservice.h",
|
||||||
"documentmanager.cpp", "documentmanager.h",
|
"documentmanager.cpp", "documentmanager.h",
|
||||||
"editmode.cpp", "editmode.h",
|
"editmode.cpp", "editmode.h",
|
||||||
"editortoolbar.cpp", "editortoolbar.h",
|
"editortoolbar.cpp", "editortoolbar.h",
|
||||||
|
|||||||
@@ -25,12 +25,15 @@
|
|||||||
|
|
||||||
#include "saveitemsdialog.h"
|
#include "saveitemsdialog.h"
|
||||||
|
|
||||||
|
#include <coreplugin/diffservice.h>
|
||||||
#include <coreplugin/fileiconprovider.h>
|
#include <coreplugin/fileiconprovider.h>
|
||||||
#include <coreplugin/idocument.h>
|
#include <coreplugin/idocument.h>
|
||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
|
|
||||||
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
@@ -51,6 +54,12 @@ SaveItemsDialog::SaveItemsDialog(QWidget *parent,
|
|||||||
// QDialogButtonBox's behavior for "destructive" is wrong, the "do not save" should be left-aligned
|
// QDialogButtonBox's behavior for "destructive" is wrong, the "do not save" should be left-aligned
|
||||||
const QDialogButtonBox::ButtonRole discardButtonRole = Utils::HostOsInfo::isMacHost()
|
const QDialogButtonBox::ButtonRole discardButtonRole = Utils::HostOsInfo::isMacHost()
|
||||||
? QDialogButtonBox::ResetRole : QDialogButtonBox::DestructiveRole;
|
? QDialogButtonBox::ResetRole : QDialogButtonBox::DestructiveRole;
|
||||||
|
|
||||||
|
if (ExtensionSystem::PluginManager::getObject<Core::DiffService>()) {
|
||||||
|
m_diffButton = m_ui.buttonBox->addButton(tr("&Diff"), discardButtonRole);
|
||||||
|
connect(m_diffButton, &QAbstractButton::clicked, this, &SaveItemsDialog::collectFilesToDiff);
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton *discardButton = m_ui.buttonBox->addButton(tr("Do not Save"), discardButtonRole);
|
QPushButton *discardButton = m_ui.buttonBox->addButton(tr("Do not Save"), discardButtonRole);
|
||||||
m_ui.buttonBox->button(QDialogButtonBox::Save)->setDefault(true);
|
m_ui.buttonBox->button(QDialogButtonBox::Save)->setDefault(true);
|
||||||
m_ui.treeWidget->setFocus();
|
m_ui.treeWidget->setFocus();
|
||||||
@@ -80,13 +89,13 @@ SaveItemsDialog::SaveItemsDialog(QWidget *parent,
|
|||||||
if (Utils::HostOsInfo::isMacHost())
|
if (Utils::HostOsInfo::isMacHost())
|
||||||
m_ui.treeWidget->setAlternatingRowColors(true);
|
m_ui.treeWidget->setAlternatingRowColors(true);
|
||||||
adjustButtonWidths();
|
adjustButtonWidths();
|
||||||
updateSaveButton();
|
updateButtons();
|
||||||
|
|
||||||
connect(m_ui.buttonBox->button(QDialogButtonBox::Save), &QAbstractButton::clicked,
|
connect(m_ui.buttonBox->button(QDialogButtonBox::Save), &QAbstractButton::clicked,
|
||||||
this, &SaveItemsDialog::collectItemsToSave);
|
this, &SaveItemsDialog::collectItemsToSave);
|
||||||
connect(discardButton, &QAbstractButton::clicked, this, &SaveItemsDialog::discardAll);
|
connect(discardButton, &QAbstractButton::clicked, this, &SaveItemsDialog::discardAll);
|
||||||
connect(m_ui.treeWidget, &QTreeWidget::itemSelectionChanged,
|
connect(m_ui.treeWidget, &QTreeWidget::itemSelectionChanged,
|
||||||
this, &SaveItemsDialog::updateSaveButton);
|
this, &SaveItemsDialog::updateButtons);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveItemsDialog::setMessage(const QString &msg)
|
void SaveItemsDialog::setMessage(const QString &msg)
|
||||||
@@ -94,19 +103,27 @@ void SaveItemsDialog::setMessage(const QString &msg)
|
|||||||
m_ui.msgLabel->setText(msg);
|
m_ui.msgLabel->setText(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveItemsDialog::updateSaveButton()
|
void SaveItemsDialog::updateButtons()
|
||||||
{
|
{
|
||||||
int count = m_ui.treeWidget->selectedItems().count();
|
int count = m_ui.treeWidget->selectedItems().count();
|
||||||
QPushButton *button = m_ui.buttonBox->button(QDialogButtonBox::Save);
|
QPushButton *saveButton = m_ui.buttonBox->button(QDialogButtonBox::Save);
|
||||||
|
bool buttonsEnabled = true;
|
||||||
|
QString saveText = tr("Save");
|
||||||
|
QString diffText = tr("&Diff && Cancel");
|
||||||
if (count == m_ui.treeWidget->topLevelItemCount()) {
|
if (count == m_ui.treeWidget->topLevelItemCount()) {
|
||||||
button->setEnabled(true);
|
saveText = tr("Save All");
|
||||||
button->setText(tr("Save All"));
|
diffText = tr("&Diff All && Cancel");
|
||||||
} else if (count == 0) {
|
} else if (count == 0) {
|
||||||
button->setEnabled(false);
|
buttonsEnabled = false;
|
||||||
button->setText(tr("Save"));
|
|
||||||
} else {
|
} else {
|
||||||
button->setEnabled(true);
|
saveText = tr("Save Selected");
|
||||||
button->setText(tr("Save Selected"));
|
diffText = tr("&Diff Selected && Cancel");
|
||||||
|
}
|
||||||
|
saveButton->setEnabled(buttonsEnabled);
|
||||||
|
saveButton->setText(saveText);
|
||||||
|
if (m_diffButton) {
|
||||||
|
m_diffButton->setEnabled(buttonsEnabled);
|
||||||
|
m_diffButton->setText(diffText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +162,16 @@ void SaveItemsDialog::collectItemsToSave()
|
|||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SaveItemsDialog::collectFilesToDiff()
|
||||||
|
{
|
||||||
|
m_filesToDiff.clear();
|
||||||
|
foreach (QTreeWidgetItem *item, m_ui.treeWidget->selectedItems()) {
|
||||||
|
if (IDocument *doc = item->data(0, Qt::UserRole).value<IDocument*>())
|
||||||
|
m_filesToDiff.append(doc->filePath().toString());
|
||||||
|
}
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
|
||||||
void SaveItemsDialog::discardAll()
|
void SaveItemsDialog::discardAll()
|
||||||
{
|
{
|
||||||
m_ui.treeWidget->clearSelection();
|
m_ui.treeWidget->clearSelection();
|
||||||
@@ -156,6 +183,11 @@ QList<IDocument*> SaveItemsDialog::itemsToSave() const
|
|||||||
return m_itemsToSave;
|
return m_itemsToSave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList SaveItemsDialog::filesToDiff() const
|
||||||
|
{
|
||||||
|
return m_filesToDiff;
|
||||||
|
}
|
||||||
|
|
||||||
void SaveItemsDialog::setAlwaysSaveMessage(const QString &msg)
|
void SaveItemsDialog::setAlwaysSaveMessage(const QString &msg)
|
||||||
{
|
{
|
||||||
m_ui.saveBeforeBuildCheckBox->setText(msg);
|
m_ui.saveBeforeBuildCheckBox->setText(msg);
|
||||||
|
|||||||
@@ -54,15 +54,19 @@ public:
|
|||||||
void setAlwaysSaveMessage(const QString &msg);
|
void setAlwaysSaveMessage(const QString &msg);
|
||||||
bool alwaysSaveChecked();
|
bool alwaysSaveChecked();
|
||||||
QList<IDocument *> itemsToSave() const;
|
QList<IDocument *> itemsToSave() const;
|
||||||
|
QStringList filesToDiff() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void collectItemsToSave();
|
void collectItemsToSave();
|
||||||
|
void collectFilesToDiff();
|
||||||
void discardAll();
|
void discardAll();
|
||||||
void updateSaveButton();
|
void updateButtons();
|
||||||
void adjustButtonWidths();
|
void adjustButtonWidths();
|
||||||
|
|
||||||
Ui::SaveItemsDialog m_ui;
|
Ui::SaveItemsDialog m_ui;
|
||||||
QList<IDocument*> m_itemsToSave;
|
QList<IDocument*> m_itemsToSave;
|
||||||
|
QStringList m_filesToDiff;
|
||||||
|
QPushButton *m_diffButton = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
47
src/plugins/coreplugin/diffservice.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core_global.h"
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QStringList)
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
class CORE_EXPORT DiffService
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~DiffService() {}
|
||||||
|
|
||||||
|
virtual void diffModifiedFiles(const QStringList &fileNames) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
Q_DECLARE_INTERFACE(Core::DiffService, "Core::DiffService")
|
||||||
|
QT_END_NAMESPACE
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "idocument.h"
|
#include "idocument.h"
|
||||||
#include "coreconstants.h"
|
#include "coreconstants.h"
|
||||||
|
|
||||||
|
#include <coreplugin/diffservice.h>
|
||||||
#include <coreplugin/dialogs/readonlyfilesdialog.h>
|
#include <coreplugin/dialogs/readonlyfilesdialog.h>
|
||||||
#include <coreplugin/dialogs/saveitemsdialog.h>
|
#include <coreplugin/dialogs/saveitemsdialog.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
@@ -38,6 +39,8 @@
|
|||||||
#include <coreplugin/editormanager/ieditorfactory.h>
|
#include <coreplugin/editormanager/ieditorfactory.h>
|
||||||
#include <coreplugin/editormanager/iexternaleditor.h>
|
#include <coreplugin/editormanager/iexternaleditor.h>
|
||||||
|
|
||||||
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/mimetypes/mimedatabase.h>
|
#include <utils/mimetypes/mimedatabase.h>
|
||||||
@@ -606,6 +609,11 @@ static bool saveModifiedFilesHelper(const QList<IDocument *> &documents,
|
|||||||
(*alwaysSave) = dia.alwaysSaveChecked();
|
(*alwaysSave) = dia.alwaysSaveChecked();
|
||||||
if (failedToSave)
|
if (failedToSave)
|
||||||
(*failedToSave) = modifiedDocuments;
|
(*failedToSave) = modifiedDocuments;
|
||||||
|
const QStringList filesToDiff = dia.filesToDiff();
|
||||||
|
if (!filesToDiff.isEmpty()) {
|
||||||
|
if (auto diffService = ExtensionSystem::PluginManager::getObject<DiffService>())
|
||||||
|
diffService->diffModifiedFiles(filesToDiff);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (alwaysSave)
|
if (alwaysSave)
|
||||||
@@ -978,6 +986,7 @@ void DocumentManager::checkForReload()
|
|||||||
|
|
||||||
// handle the IDocuments
|
// handle the IDocuments
|
||||||
QStringList errorStrings;
|
QStringList errorStrings;
|
||||||
|
QStringList filesToDiff;
|
||||||
foreach (IDocument *document, changedIDocuments) {
|
foreach (IDocument *document, changedIDocuments) {
|
||||||
IDocument::ChangeTrigger trigger = IDocument::TriggerInternal;
|
IDocument::ChangeTrigger trigger = IDocument::TriggerInternal;
|
||||||
IDocument::ChangeType type = IDocument::TypePermissions;
|
IDocument::ChangeType type = IDocument::TypePermissions;
|
||||||
@@ -1052,7 +1061,6 @@ void DocumentManager::checkForReload()
|
|||||||
documentsToClose << document;
|
documentsToClose << document;
|
||||||
} else if (defaultBehavior == IDocument::IgnoreAll) {
|
} else if (defaultBehavior == IDocument::IgnoreAll) {
|
||||||
// content change or removed, but settings say ignore
|
// content change or removed, but settings say ignore
|
||||||
document->setModified(true);
|
|
||||||
success = document->reload(&errorString, IDocument::FlagIgnore, type);
|
success = document->reload(&errorString, IDocument::FlagIgnore, type);
|
||||||
// either the default behavior is to always ask,
|
// either the default behavior is to always ask,
|
||||||
// or the ReloadUnmodified default behavior didn't kick in,
|
// or the ReloadUnmodified default behavior didn't kick in,
|
||||||
@@ -1068,9 +1076,8 @@ void DocumentManager::checkForReload()
|
|||||||
// IDocument wants us to ask
|
// IDocument wants us to ask
|
||||||
} else if (type == IDocument::TypeContents) {
|
} else if (type == IDocument::TypeContents) {
|
||||||
// content change, IDocument wants to ask user
|
// content change, IDocument wants to ask user
|
||||||
if (previousReloadAnswer == ReloadNone) {
|
if (previousReloadAnswer == ReloadNone || previousReloadAnswer == ReloadNoneAndDiff) {
|
||||||
// answer already given, ignore
|
// answer already given, ignore
|
||||||
document->setModified(true);
|
|
||||||
success = document->reload(&errorString, IDocument::FlagIgnore, IDocument::TypeContents);
|
success = document->reload(&errorString, IDocument::FlagIgnore, IDocument::TypeContents);
|
||||||
} else if (previousReloadAnswer == ReloadAll) {
|
} else if (previousReloadAnswer == ReloadAll) {
|
||||||
// answer already given, reload
|
// answer already given, reload
|
||||||
@@ -1078,6 +1085,7 @@ void DocumentManager::checkForReload()
|
|||||||
} else {
|
} else {
|
||||||
// Ask about content change
|
// Ask about content change
|
||||||
previousReloadAnswer = reloadPrompt(document->filePath(), document->isModified(),
|
previousReloadAnswer = reloadPrompt(document->filePath(), document->isModified(),
|
||||||
|
ExtensionSystem::PluginManager::getObject<DiffService>(),
|
||||||
ICore::dialogParent());
|
ICore::dialogParent());
|
||||||
switch (previousReloadAnswer) {
|
switch (previousReloadAnswer) {
|
||||||
case ReloadAll:
|
case ReloadAll:
|
||||||
@@ -1086,7 +1094,7 @@ void DocumentManager::checkForReload()
|
|||||||
break;
|
break;
|
||||||
case ReloadSkipCurrent:
|
case ReloadSkipCurrent:
|
||||||
case ReloadNone:
|
case ReloadNone:
|
||||||
document->setModified(true);
|
case ReloadNoneAndDiff:
|
||||||
success = document->reload(&errorString, IDocument::FlagIgnore, IDocument::TypeContents);
|
success = document->reload(&errorString, IDocument::FlagIgnore, IDocument::TypeContents);
|
||||||
break;
|
break;
|
||||||
case CloseCurrent:
|
case CloseCurrent:
|
||||||
@@ -1094,6 +1102,9 @@ void DocumentManager::checkForReload()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (previousReloadAnswer == ReloadNoneAndDiff)
|
||||||
|
filesToDiff.append(document->filePath().toString());
|
||||||
|
|
||||||
// IDocument wants us to ask, and it's the TypeRemoved case
|
// IDocument wants us to ask, and it's the TypeRemoved case
|
||||||
} else {
|
} else {
|
||||||
// Ask about removed file
|
// Ask about removed file
|
||||||
@@ -1137,6 +1148,12 @@ void DocumentManager::checkForReload()
|
|||||||
|
|
||||||
d->m_blockedIDocument = 0;
|
d->m_blockedIDocument = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!filesToDiff.isEmpty()) {
|
||||||
|
if (auto diffService = ExtensionSystem::PluginManager::getObject<DiffService>())
|
||||||
|
diffService->diffModifiedFiles(filesToDiff);
|
||||||
|
}
|
||||||
|
|
||||||
if (!errorStrings.isEmpty())
|
if (!errorStrings.isEmpty())
|
||||||
QMessageBox::critical(ICore::dialogParent(), tr("File Error"),
|
QMessageBox::critical(ICore::dialogParent(), tr("File Error"),
|
||||||
errorStrings.join(QLatin1Char('\n')));
|
errorStrings.join(QLatin1Char('\n')));
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <coreplugin/actionmanager/command.h>
|
#include <coreplugin/actionmanager/command.h>
|
||||||
#include <coreplugin/dialogs/openwithdialog.h>
|
#include <coreplugin/dialogs/openwithdialog.h>
|
||||||
#include <coreplugin/dialogs/readonlyfilesdialog.h>
|
#include <coreplugin/dialogs/readonlyfilesdialog.h>
|
||||||
|
#include <coreplugin/diffservice.h>
|
||||||
#include <coreplugin/documentmanager.h>
|
#include <coreplugin/documentmanager.h>
|
||||||
#include <coreplugin/editormanager/ieditorfactory.h>
|
#include <coreplugin/editormanager/ieditorfactory.h>
|
||||||
#include <coreplugin/editormanager/iexternaleditor.h>
|
#include <coreplugin/editormanager/iexternaleditor.h>
|
||||||
@@ -1905,9 +1906,9 @@ void EditorManagerPrivate::handleDocumentStateChange()
|
|||||||
IDocument *document = qobject_cast<IDocument *>(sender());
|
IDocument *document = qobject_cast<IDocument *>(sender());
|
||||||
if (!document->isModified())
|
if (!document->isModified())
|
||||||
document->removeAutoSaveFile();
|
document->removeAutoSaveFile();
|
||||||
if (EditorManager::currentDocument() == document) {
|
if (EditorManager::currentDocument() == document)
|
||||||
emit m_instance->currentDocumentStateChanged();
|
emit m_instance->currentDocumentStateChanged();
|
||||||
}
|
emit m_instance->documentStateChanged(document);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorManagerPrivate::editorAreaDestroyed(QObject *area)
|
void EditorManagerPrivate::editorAreaDestroyed(QObject *area)
|
||||||
@@ -2168,11 +2169,21 @@ void EditorManagerPrivate::revertToSaved(IDocument *document)
|
|||||||
QMessageBox::Yes|QMessageBox::No, ICore::mainWindow());
|
QMessageBox::Yes|QMessageBox::No, ICore::mainWindow());
|
||||||
msgBox.button(QMessageBox::Yes)->setText(tr("Proceed"));
|
msgBox.button(QMessageBox::Yes)->setText(tr("Proceed"));
|
||||||
msgBox.button(QMessageBox::No)->setText(tr("Cancel"));
|
msgBox.button(QMessageBox::No)->setText(tr("Cancel"));
|
||||||
|
|
||||||
|
QPushButton *diffButton = nullptr;
|
||||||
|
auto diffService = ExtensionSystem::PluginManager::getObject<DiffService>();
|
||||||
|
if (diffService)
|
||||||
|
diffButton = msgBox.addButton(tr("Cancel && &Diff"), QMessageBox::RejectRole);
|
||||||
|
|
||||||
msgBox.setDefaultButton(QMessageBox::No);
|
msgBox.setDefaultButton(QMessageBox::No);
|
||||||
msgBox.setEscapeButton(QMessageBox::No);
|
msgBox.setEscapeButton(QMessageBox::No);
|
||||||
if (msgBox.exec() == QMessageBox::No)
|
if (msgBox.exec() == QMessageBox::No)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (diffService && msgBox.clickedButton() == diffButton) {
|
||||||
|
diffService->diffModifiedFiles(QStringList() << fileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
QString errorString;
|
QString errorString;
|
||||||
if (!document->reload(&errorString, IDocument::FlagReload, IDocument::TypeContents))
|
if (!document->reload(&errorString, IDocument::FlagReload, IDocument::TypeContents))
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ public: // for tests
|
|||||||
signals:
|
signals:
|
||||||
void currentEditorChanged(Core::IEditor *editor);
|
void currentEditorChanged(Core::IEditor *editor);
|
||||||
void currentDocumentStateChanged();
|
void currentDocumentStateChanged();
|
||||||
|
void documentStateChanged(Core::IDocument *document);
|
||||||
void editorCreated(Core::IEditor *editor, const QString &fileName);
|
void editorCreated(Core::IEditor *editor, const QString &fileName);
|
||||||
void editorOpened(Core::IEditor *editor);
|
void editorOpened(Core::IEditor *editor);
|
||||||
void editorAboutToClose(Core::IEditor *editor);
|
void editorAboutToClose(Core::IEditor *editor);
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ public:
|
|||||||
bool hasWriteWarning = false;
|
bool hasWriteWarning = false;
|
||||||
bool restored = false;
|
bool restored = false;
|
||||||
bool isSuspendAllowed = false;
|
bool isSuspendAllowed = false;
|
||||||
bool isModified = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
@@ -201,17 +200,7 @@ bool IDocument::shouldAutoSave() const
|
|||||||
|
|
||||||
bool IDocument::isModified() const
|
bool IDocument::isModified() const
|
||||||
{
|
{
|
||||||
return d->isModified;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
void IDocument::setModified(bool modified)
|
|
||||||
{
|
|
||||||
if (d->isModified == modified)
|
|
||||||
return;
|
|
||||||
|
|
||||||
d->isModified = modified;
|
|
||||||
emit modificationChanged(modified);
|
|
||||||
emit changed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IDocument::isSaveAsAllowed() const
|
bool IDocument::isSaveAsAllowed() const
|
||||||
|
|||||||
@@ -106,9 +106,6 @@ public:
|
|||||||
bool isTemporary() const;
|
bool isTemporary() const;
|
||||||
void setTemporary(bool temporary);
|
void setTemporary(bool temporary);
|
||||||
|
|
||||||
bool isModified() const;
|
|
||||||
void setModified(bool modified);
|
|
||||||
|
|
||||||
virtual QString fallbackSaveAsPath() const;
|
virtual QString fallbackSaveAsPath() const;
|
||||||
virtual QString fallbackSaveAsFileName() const;
|
virtual QString fallbackSaveAsFileName() const;
|
||||||
|
|
||||||
@@ -116,6 +113,7 @@ public:
|
|||||||
void setMimeType(const QString &mimeType);
|
void setMimeType(const QString &mimeType);
|
||||||
|
|
||||||
virtual bool shouldAutoSave() const;
|
virtual bool shouldAutoSave() const;
|
||||||
|
virtual bool isModified() const;
|
||||||
virtual bool isSaveAsAllowed() const;
|
virtual bool isSaveAsAllowed() const;
|
||||||
bool isSuspendAllowed() const;
|
bool isSuspendAllowed() const;
|
||||||
void setSuspendAllowed(bool value);
|
void setSuspendAllowed(bool value);
|
||||||
@@ -138,8 +136,6 @@ signals:
|
|||||||
// For meta data changes: file name, modified state, ...
|
// For meta data changes: file name, modified state, ...
|
||||||
void changed();
|
void changed();
|
||||||
|
|
||||||
void modificationChanged(bool modified);
|
|
||||||
|
|
||||||
// For changes in the contents of the document
|
// For changes in the contents of the document
|
||||||
void contentsChanged();
|
void contentsChanged();
|
||||||
|
|
||||||
|
|||||||
@@ -200,7 +200,9 @@ QString ResourcePreviewHoverHandler::makeTooltip() const
|
|||||||
if (mimeType.name().startsWith("image", Qt::CaseInsensitive))
|
if (mimeType.name().startsWith("image", Qt::CaseInsensitive))
|
||||||
ret += QString("<img src=\"file:///%1\" /><br/>").arg(m_resPath);
|
ret += QString("<img src=\"file:///%1\" /><br/>").arg(m_resPath);
|
||||||
|
|
||||||
ret += QString("<a href=\"file:///%1\">%2</a>").arg(m_resPath).arg(m_resPath);
|
ret += QString("<a href=\"file:///%1\">%2</a>")
|
||||||
|
.arg(m_resPath)
|
||||||
|
.arg(QDir::toNativeSeparators(m_resPath));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,14 @@ void CompilerOptionsBuilder::addDefine(const QByteArray &defineDirective)
|
|||||||
m_options.append(defineDirectiveToDefineOption(defineDirective));
|
m_options.append(defineDirectiveToDefineOption(defineDirective));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompilerOptionsBuilder::addWordWidth()
|
||||||
|
{
|
||||||
|
const QString argument = m_projectPart.toolChainWordWidth == ProjectPart::WordWidth64Bit
|
||||||
|
? QLatin1String("-m64")
|
||||||
|
: QLatin1String("-m32");
|
||||||
|
add(argument);
|
||||||
|
}
|
||||||
|
|
||||||
void CompilerOptionsBuilder::addTargetTriple()
|
void CompilerOptionsBuilder::addTargetTriple()
|
||||||
{
|
{
|
||||||
if (!m_projectPart.targetTriple.isEmpty()) {
|
if (!m_projectPart.targetTriple.isEmpty()) {
|
||||||
@@ -262,6 +270,20 @@ void CompilerOptionsBuilder::addOptionsForLanguage(bool checkForBorlandExtension
|
|||||||
m_options.append(opts);
|
m_options.append(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompilerOptionsBuilder::addDefineToAvoidIncludingGccOrMinGwIntrinsics()
|
||||||
|
{
|
||||||
|
// In gcc headers, lots of built-ins are referenced that clang does not understand.
|
||||||
|
// Therefore, prevent the inclusion of the header that references them. Of course, this
|
||||||
|
// will break if code actually requires stuff from there, but that should be the less common
|
||||||
|
// case.
|
||||||
|
|
||||||
|
const Core::Id type = m_projectPart.toolchainType;
|
||||||
|
if (type == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID
|
||||||
|
|| type == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID) {
|
||||||
|
addDefine("#define _X86INTRIN_H_INCLUDED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static QByteArray toMsCompatibilityVersionFormat(const QByteArray &mscFullVer)
|
static QByteArray toMsCompatibilityVersionFormat(const QByteArray &mscFullVer)
|
||||||
{
|
{
|
||||||
return mscFullVer.left(2)
|
return mscFullVer.left(2)
|
||||||
@@ -342,10 +364,18 @@ void CompilerOptionsBuilder::undefineCppLanguageFeatureMacrosForMsvc2015()
|
|||||||
// Undefine the language feature macros that are pre-defined in clang-cl 3.8.0,
|
// Undefine the language feature macros that are pre-defined in clang-cl 3.8.0,
|
||||||
// but not in MSVC2015's cl.exe.
|
// but not in MSVC2015's cl.exe.
|
||||||
foreach (const QString ¯oName, languageFeatureMacros())
|
foreach (const QString ¯oName, languageFeatureMacros())
|
||||||
m_options.append(QLatin1String("/U") + macroName);
|
m_options.append(undefineOption() + macroName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompilerOptionsBuilder::addDefineFloat128ForMingw()
|
||||||
|
{
|
||||||
|
// TODO: Remove once this is fixed in clang >= 3.9.
|
||||||
|
// https://llvm.org/bugs/show_bug.cgi?id=30685
|
||||||
|
if (m_projectPart.toolchainType == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID)
|
||||||
|
addDefine("#define __float128 void");
|
||||||
|
}
|
||||||
|
|
||||||
QString CompilerOptionsBuilder::includeOption() const
|
QString CompilerOptionsBuilder::includeOption() const
|
||||||
{
|
{
|
||||||
return QLatin1String("-I");
|
return QLatin1String("-I");
|
||||||
@@ -364,6 +394,11 @@ QString CompilerOptionsBuilder::defineOption() const
|
|||||||
return QLatin1String("-D");
|
return QLatin1String("-D");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString CompilerOptionsBuilder::undefineOption() const
|
||||||
|
{
|
||||||
|
return QLatin1String("-U");
|
||||||
|
}
|
||||||
|
|
||||||
static bool isGccOrMinGwToolchain(const Core::Id &toolchainType)
|
static bool isGccOrMinGwToolchain(const Core::Id &toolchainType)
|
||||||
{
|
{
|
||||||
return toolchainType == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID
|
return toolchainType == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public:
|
|||||||
void addDefine(const QByteArray &defineDirective);
|
void addDefine(const QByteArray &defineDirective);
|
||||||
|
|
||||||
// Add options based on project part
|
// Add options based on project part
|
||||||
|
void addWordWidth();
|
||||||
virtual void addTargetTriple();
|
virtual void addTargetTriple();
|
||||||
virtual void enableExceptions();
|
virtual void enableExceptions();
|
||||||
void addHeaderPathOptions();
|
void addHeaderPathOptions();
|
||||||
@@ -52,14 +53,19 @@ public:
|
|||||||
virtual void addLanguageOption(ProjectFile::Kind fileKind);
|
virtual void addLanguageOption(ProjectFile::Kind fileKind);
|
||||||
virtual void addOptionsForLanguage(bool checkForBorlandExtensions = true);
|
virtual void addOptionsForLanguage(bool checkForBorlandExtensions = true);
|
||||||
|
|
||||||
|
void addDefineToAvoidIncludingGccOrMinGwIntrinsics();
|
||||||
|
|
||||||
void addMsvcCompatibilityVersion();
|
void addMsvcCompatibilityVersion();
|
||||||
void undefineCppLanguageFeatureMacrosForMsvc2015();
|
void undefineCppLanguageFeatureMacrosForMsvc2015();
|
||||||
|
|
||||||
|
void addDefineFloat128ForMingw();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool excludeDefineDirective(const QByteArray &defineDirective) const;
|
virtual bool excludeDefineDirective(const QByteArray &defineDirective) const;
|
||||||
virtual bool excludeHeaderPath(const QString &headerPath) const;
|
virtual bool excludeHeaderPath(const QString &headerPath) const;
|
||||||
|
|
||||||
virtual QString defineOption() const;
|
virtual QString defineOption() const;
|
||||||
|
virtual QString undefineOption() const;
|
||||||
virtual QString includeOption() const;
|
virtual QString includeOption() const;
|
||||||
|
|
||||||
const ProjectPart m_projectPart;
|
const ProjectPart m_projectPart;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ namespace CppTools {
|
|||||||
|
|
||||||
ProjectPart::ProjectPart()
|
ProjectPart::ProjectPart()
|
||||||
: project(0)
|
: project(0)
|
||||||
|
, toolChainWordWidth(WordWidth32Bit)
|
||||||
, isMsvc2015Toolchain(false)
|
, isMsvc2015Toolchain(false)
|
||||||
, languageVersion(CXX14)
|
, languageVersion(CXX14)
|
||||||
, languageExtensions(NoExtensions)
|
, languageExtensions(NoExtensions)
|
||||||
|
|||||||
@@ -81,6 +81,11 @@ public: // Types
|
|||||||
Qt5 = 2
|
Qt5 = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ToolChainWordWidth {
|
||||||
|
WordWidth32Bit,
|
||||||
|
WordWidth64Bit,
|
||||||
|
};
|
||||||
|
|
||||||
using Ptr = QSharedPointer<ProjectPart>;
|
using Ptr = QSharedPointer<ProjectPart>;
|
||||||
|
|
||||||
|
|
||||||
@@ -103,6 +108,7 @@ public: // fields
|
|||||||
QByteArray projectDefines;
|
QByteArray projectDefines;
|
||||||
QByteArray toolchainDefines;
|
QByteArray toolchainDefines;
|
||||||
Core::Id toolchainType;
|
Core::Id toolchainType;
|
||||||
|
ToolChainWordWidth toolChainWordWidth;
|
||||||
bool isMsvc2015Toolchain;
|
bool isMsvc2015Toolchain;
|
||||||
QString targetTriple;
|
QString targetTriple;
|
||||||
ProjectPartHeaderPaths headerPaths;
|
ProjectPartHeaderPaths headerPaths;
|
||||||
|
|||||||
@@ -343,6 +343,9 @@ void ProjectPartBuilder::evaluateProjectPartToolchain(
|
|||||||
projectPart->toolchainType = toolChain->typeId();
|
projectPart->toolchainType = toolChain->typeId();
|
||||||
projectPart->isMsvc2015Toolchain
|
projectPart->isMsvc2015Toolchain
|
||||||
= toolChain->targetAbi().osFlavor() == ProjectExplorer::Abi::WindowsMsvc2015Flavor;
|
= toolChain->targetAbi().osFlavor() == ProjectExplorer::Abi::WindowsMsvc2015Flavor;
|
||||||
|
projectPart->toolChainWordWidth = toolChain->targetAbi().wordWidth() == 64
|
||||||
|
? ProjectPart::WordWidth64Bit
|
||||||
|
: ProjectPart::WordWidth32Bit;
|
||||||
projectPart->targetTriple = targetTriple(projectPart->project, toolChain->typeId());
|
projectPart->targetTriple = targetTriple(projectPart->project, toolChain->typeId());
|
||||||
projectPart->updateLanguageFeatures();
|
projectPart->updateLanguageFeatures();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1209,6 +1209,8 @@ void CdbEngine::activateFrame(int index)
|
|||||||
qPrintable(frame.file), frame.line);
|
qPrintable(frame.file), frame.line);
|
||||||
stackHandler()->setCurrentIndex(index);
|
stackHandler()->setCurrentIndex(index);
|
||||||
gotoLocation(frame);
|
gotoLocation(frame);
|
||||||
|
if (m_pythonVersion > 0x030000)
|
||||||
|
runCommand({".frame " + QString::number(index), NoFlags});
|
||||||
updateLocals();
|
updateLocals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,9 +59,6 @@ FormWindowFile::FormWindowFile(QDesignerFormWindowInterface *form, QObject *pare
|
|||||||
connect(m_formWindow->commandHistory(), &QUndoStack::indexChanged,
|
connect(m_formWindow->commandHistory(), &QUndoStack::indexChanged,
|
||||||
this, &FormWindowFile::setShouldAutoSave);
|
this, &FormWindowFile::setShouldAutoSave);
|
||||||
connect(m_formWindow.data(), &QDesignerFormWindowInterface::changed, this, &FormWindowFile::updateIsModified);
|
connect(m_formWindow.data(), &QDesignerFormWindowInterface::changed, this, &FormWindowFile::updateIsModified);
|
||||||
connect(this, &IDocument::modificationChanged, m_formWindow.data(), &QDesignerFormWindowInterface::setDirty);
|
|
||||||
|
|
||||||
setModified(m_formWindow->isDirty());
|
|
||||||
|
|
||||||
m_resourceHandler = new ResourceHandler(form);
|
m_resourceHandler = new ResourceHandler(form);
|
||||||
connect(this, &FormWindowFile::filePathChanged,
|
connect(this, &FormWindowFile::filePathChanged,
|
||||||
@@ -186,10 +183,16 @@ void FormWindowFile::setFilePath(const FileName &newName)
|
|||||||
|
|
||||||
void FormWindowFile::updateIsModified()
|
void FormWindowFile::updateIsModified()
|
||||||
{
|
{
|
||||||
|
if (m_modificationChangedGuard.isLocked())
|
||||||
|
return;
|
||||||
|
|
||||||
bool value = m_formWindow && m_formWindow->isDirty();
|
bool value = m_formWindow && m_formWindow->isDirty();
|
||||||
if (value)
|
if (value)
|
||||||
emit contentsChanged();
|
emit contentsChanged();
|
||||||
setModified(value);
|
if (value == m_isModified)
|
||||||
|
return;
|
||||||
|
m_isModified = value;
|
||||||
|
emit changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FormWindowFile::shouldAutoSave() const
|
bool FormWindowFile::shouldAutoSave() const
|
||||||
@@ -197,6 +200,11 @@ bool FormWindowFile::shouldAutoSave() const
|
|||||||
return m_shouldAutoSave;
|
return m_shouldAutoSave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FormWindowFile::isModified() const
|
||||||
|
{
|
||||||
|
return m_formWindow && m_formWindow->isDirty();
|
||||||
|
}
|
||||||
|
|
||||||
bool FormWindowFile::isSaveAsAllowed() const
|
bool FormWindowFile::isSaveAsAllowed() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -204,8 +212,20 @@ bool FormWindowFile::isSaveAsAllowed() const
|
|||||||
|
|
||||||
bool FormWindowFile::reload(QString *errorString, ReloadFlag flag, ChangeType type)
|
bool FormWindowFile::reload(QString *errorString, ReloadFlag flag, ChangeType type)
|
||||||
{
|
{
|
||||||
if (flag == FlagIgnore)
|
if (flag == FlagIgnore) {
|
||||||
|
if (!m_formWindow || type != TypeContents)
|
||||||
return true;
|
return true;
|
||||||
|
const bool wasModified = m_formWindow->isDirty();
|
||||||
|
{
|
||||||
|
Utils::GuardLocker locker(m_modificationChangedGuard);
|
||||||
|
// hack to ensure we clean the clear state in form window
|
||||||
|
m_formWindow->setDirty(false);
|
||||||
|
m_formWindow->setDirty(true);
|
||||||
|
}
|
||||||
|
if (!wasModified)
|
||||||
|
updateIsModified();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (type == TypePermissions) {
|
if (type == TypePermissions) {
|
||||||
emit changed();
|
emit changed();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <texteditor/textdocument.h>
|
#include <texteditor/textdocument.h>
|
||||||
|
#include <utils/guard.h>
|
||||||
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ public:
|
|||||||
QByteArray contents() const override;
|
QByteArray contents() const override;
|
||||||
bool setContents(const QByteArray &contents) override;
|
bool setContents(const QByteArray &contents) override;
|
||||||
bool shouldAutoSave() const override;
|
bool shouldAutoSave() const override;
|
||||||
|
bool isModified() const override;
|
||||||
bool isSaveAsAllowed() const override;
|
bool isSaveAsAllowed() const override;
|
||||||
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
|
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
|
||||||
QString fallbackSaveAsFileName() const override;
|
QString fallbackSaveAsFileName() const override;
|
||||||
@@ -81,7 +83,9 @@ private:
|
|||||||
// Might actually go out of scope before the IEditor due
|
// Might actually go out of scope before the IEditor due
|
||||||
// to deleting the WidgetHost which owns it.
|
// to deleting the WidgetHost which owns it.
|
||||||
QPointer<QDesignerFormWindowInterface> m_formWindow;
|
QPointer<QDesignerFormWindowInterface> m_formWindow;
|
||||||
|
bool m_isModified = false;
|
||||||
ResourceHandler *m_resourceHandler = nullptr;
|
ResourceHandler *m_resourceHandler = nullptr;
|
||||||
|
Utils::Guard m_modificationChangedGuard;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -69,19 +69,6 @@ static const char useDiffEditorKeyC[] = "UseDiffEditor";
|
|||||||
|
|
||||||
using namespace TextEditor;
|
using namespace TextEditor;
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class Guard
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Guard(int *state) : m_state(state) { ++(*state); }
|
|
||||||
~Guard() { --(*m_state); QTC_ASSERT(*m_state >= 0, return); }
|
|
||||||
private:
|
|
||||||
int *m_state;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace DiffEditor {
|
namespace DiffEditor {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -226,7 +213,6 @@ DiffEditor::DiffEditor()
|
|||||||
, m_viewSwitcherAction(0)
|
, m_viewSwitcherAction(0)
|
||||||
, m_currentViewIndex(-1)
|
, m_currentViewIndex(-1)
|
||||||
, m_currentDiffFileIndex(-1)
|
, m_currentDiffFileIndex(-1)
|
||||||
, m_ignoreChanges(0)
|
|
||||||
, m_sync(false)
|
, m_sync(false)
|
||||||
, m_showDescription(true)
|
, m_showDescription(true)
|
||||||
{
|
{
|
||||||
@@ -329,7 +315,7 @@ void DiffEditor::setDocument(QSharedPointer<DiffEditorDocument>(doc))
|
|||||||
|
|
||||||
DiffEditor::DiffEditor(DiffEditorDocument *doc) : DiffEditor()
|
DiffEditor::DiffEditor(DiffEditorDocument *doc) : DiffEditor()
|
||||||
{
|
{
|
||||||
Guard guard(&m_ignoreChanges);
|
Utils::GuardLocker guard(m_ignoreChanges);
|
||||||
setDocument(QSharedPointer<DiffEditorDocument>(doc));
|
setDocument(QSharedPointer<DiffEditorDocument>(doc));
|
||||||
setupView(loadSettings());
|
setupView(loadSettings());
|
||||||
}
|
}
|
||||||
@@ -343,7 +329,7 @@ DiffEditor::~DiffEditor()
|
|||||||
Core::IEditor *DiffEditor::duplicate()
|
Core::IEditor *DiffEditor::duplicate()
|
||||||
{
|
{
|
||||||
DiffEditor *editor = new DiffEditor();
|
DiffEditor *editor = new DiffEditor();
|
||||||
Guard guard(&editor->m_ignoreChanges);
|
Utils::GuardLocker guard(editor->m_ignoreChanges);
|
||||||
|
|
||||||
editor->setDocument(m_document);
|
editor->setDocument(m_document);
|
||||||
editor->m_sync = m_sync;
|
editor->m_sync = m_sync;
|
||||||
@@ -371,7 +357,7 @@ QWidget *DiffEditor::toolBar()
|
|||||||
|
|
||||||
void DiffEditor::documentHasChanged()
|
void DiffEditor::documentHasChanged()
|
||||||
{
|
{
|
||||||
Guard guard(&m_ignoreChanges);
|
Utils::GuardLocker guard(m_ignoreChanges);
|
||||||
const QList<FileData> diffFileList = m_document->diffFiles();
|
const QList<FileData> diffFileList = m_document->diffFiles();
|
||||||
|
|
||||||
updateDescription();
|
updateDescription();
|
||||||
@@ -430,7 +416,7 @@ void DiffEditor::documentHasChanged()
|
|||||||
|
|
||||||
void DiffEditor::toggleDescription()
|
void DiffEditor::toggleDescription()
|
||||||
{
|
{
|
||||||
if (m_ignoreChanges > 0)
|
if (m_ignoreChanges.isLocked())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_showDescription = !m_showDescription;
|
m_showDescription = !m_showDescription;
|
||||||
@@ -446,7 +432,7 @@ void DiffEditor::updateDescription()
|
|||||||
m_descriptionWidget->setPlainText(description);
|
m_descriptionWidget->setPlainText(description);
|
||||||
m_descriptionWidget->setVisible(m_showDescription && !description.isEmpty());
|
m_descriptionWidget->setVisible(m_showDescription && !description.isEmpty());
|
||||||
|
|
||||||
Guard guard(&m_ignoreChanges);
|
Utils::GuardLocker guard(m_ignoreChanges);
|
||||||
m_toggleDescriptionAction->setChecked(m_showDescription);
|
m_toggleDescriptionAction->setChecked(m_showDescription);
|
||||||
m_toggleDescriptionAction->setToolTip(m_showDescription ? tr("Hide Change Description")
|
m_toggleDescriptionAction->setToolTip(m_showDescription ? tr("Hide Change Description")
|
||||||
: tr("Show Change Description"));
|
: tr("Show Change Description"));
|
||||||
@@ -458,7 +444,7 @@ void DiffEditor::updateDescription()
|
|||||||
void DiffEditor::contextLineCountHasChanged(int lines)
|
void DiffEditor::contextLineCountHasChanged(int lines)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!m_document->isContextLineCountForced(), return);
|
QTC_ASSERT(!m_document->isContextLineCountForced(), return);
|
||||||
if (m_ignoreChanges > 0 || lines == m_document->contextLineCount())
|
if (m_ignoreChanges.isLocked() || lines == m_document->contextLineCount())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_document->setContextLineCount(lines);
|
m_document->setContextLineCount(lines);
|
||||||
@@ -471,7 +457,7 @@ void DiffEditor::ignoreWhitespaceHasChanged()
|
|||||||
{
|
{
|
||||||
const bool ignore = m_whitespaceButtonAction->isChecked();
|
const bool ignore = m_whitespaceButtonAction->isChecked();
|
||||||
|
|
||||||
if (m_ignoreChanges > 0 || ignore == m_document->ignoreWhitespace())
|
if (m_ignoreChanges.isLocked() || ignore == m_document->ignoreWhitespace())
|
||||||
return;
|
return;
|
||||||
m_document->setIgnoreWhitespace(ignore);
|
m_document->setIgnoreWhitespace(ignore);
|
||||||
saveSetting(QLatin1String(ignoreWhitespaceKeyC), ignore);
|
saveSetting(QLatin1String(ignoreWhitespaceKeyC), ignore);
|
||||||
@@ -494,7 +480,7 @@ void DiffEditor::prepareForReload()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Guard guard(&m_ignoreChanges);
|
Utils::GuardLocker guard(m_ignoreChanges);
|
||||||
m_contextSpinBox->setValue(m_document->contextLineCount());
|
m_contextSpinBox->setValue(m_document->contextLineCount());
|
||||||
m_whitespaceButtonAction->setChecked(m_document->ignoreWhitespace());
|
m_whitespaceButtonAction->setChecked(m_document->ignoreWhitespace());
|
||||||
}
|
}
|
||||||
@@ -539,12 +525,12 @@ void DiffEditor::updateEntryToolTip()
|
|||||||
|
|
||||||
void DiffEditor::setCurrentDiffFileIndex(int index)
|
void DiffEditor::setCurrentDiffFileIndex(int index)
|
||||||
{
|
{
|
||||||
if (m_ignoreChanges > 0)
|
if (m_ignoreChanges.isLocked())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QTC_ASSERT((index < 0) != (m_entriesComboBox->count() > 0), return);
|
QTC_ASSERT((index < 0) != (m_entriesComboBox->count() > 0), return);
|
||||||
|
|
||||||
Guard guard(&m_ignoreChanges);
|
Utils::GuardLocker guard(m_ignoreChanges);
|
||||||
m_currentDiffFileIndex = index;
|
m_currentDiffFileIndex = index;
|
||||||
currentView()->setCurrentDiffFileIndex(index);
|
currentView()->setCurrentDiffFileIndex(index);
|
||||||
|
|
||||||
@@ -575,7 +561,7 @@ void DiffEditor::updateDiffEditorSwitcher()
|
|||||||
|
|
||||||
void DiffEditor::toggleSync()
|
void DiffEditor::toggleSync()
|
||||||
{
|
{
|
||||||
if (m_ignoreChanges > 0)
|
if (m_ignoreChanges.isLocked())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QTC_ASSERT(currentView(), return);
|
QTC_ASSERT(currentView(), return);
|
||||||
@@ -669,7 +655,7 @@ void DiffEditor::setupView(IDiffView *view)
|
|||||||
saveSetting(QLatin1String(diffViewKeyC), currentView()->id().toSetting());
|
saveSetting(QLatin1String(diffViewKeyC), currentView()->id().toSetting());
|
||||||
|
|
||||||
{
|
{
|
||||||
Guard guard(&m_ignoreChanges);
|
Utils::GuardLocker guard(m_ignoreChanges);
|
||||||
m_toggleSyncAction->setVisible(currentView()->supportsSync());
|
m_toggleSyncAction->setVisible(currentView()->supportsSync());
|
||||||
m_toggleSyncAction->setToolTip(currentView()->syncToolTip());
|
m_toggleSyncAction->setToolTip(currentView()->syncToolTip());
|
||||||
m_toggleSyncAction->setText(currentView()->syncToolTip());
|
m_toggleSyncAction->setText(currentView()->syncToolTip());
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include <coreplugin/editormanager/ieditor.h>
|
#include <coreplugin/editormanager/ieditor.h>
|
||||||
#include <coreplugin/idocument.h>
|
#include <coreplugin/idocument.h>
|
||||||
|
#include <utils/guard.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
@@ -103,7 +104,7 @@ private:
|
|||||||
QPair<QString, QString> m_currentFileChunk;
|
QPair<QString, QString> m_currentFileChunk;
|
||||||
int m_currentViewIndex;
|
int m_currentViewIndex;
|
||||||
int m_currentDiffFileIndex;
|
int m_currentDiffFileIndex;
|
||||||
int m_ignoreChanges;
|
Utils::Guard m_ignoreChanges;
|
||||||
bool m_sync;
|
bool m_sync;
|
||||||
bool m_showDescription;
|
bool m_showDescription;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -87,7 +87,9 @@ DiffEditorController *DiffEditorDocument::controller() const
|
|||||||
return m_controller;
|
return m_controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DiffEditorDocument::makePatch(int fileIndex, int chunkIndex, bool revert, bool addPrefix) const
|
QString DiffEditorDocument::makePatch(int fileIndex, int chunkIndex,
|
||||||
|
bool revert, bool addPrefix,
|
||||||
|
const QString &overriddenFileName) const
|
||||||
{
|
{
|
||||||
if (fileIndex < 0 || chunkIndex < 0)
|
if (fileIndex < 0 || chunkIndex < 0)
|
||||||
return QString();
|
return QString();
|
||||||
@@ -102,7 +104,8 @@ QString DiffEditorDocument::makePatch(int fileIndex, int chunkIndex, bool revert
|
|||||||
const ChunkData &chunkData = fileData.chunks.at(chunkIndex);
|
const ChunkData &chunkData = fileData.chunks.at(chunkIndex);
|
||||||
const bool lastChunk = (chunkIndex == fileData.chunks.count() - 1);
|
const bool lastChunk = (chunkIndex == fileData.chunks.count() - 1);
|
||||||
|
|
||||||
const QString fileName = revert
|
const QString fileName = !overriddenFileName.isEmpty()
|
||||||
|
? overriddenFileName : revert
|
||||||
? fileData.rightFileInfo.fileName
|
? fileData.rightFileInfo.fileName
|
||||||
: fileData.leftFileInfo.fileName;
|
: fileData.leftFileInfo.fileName;
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ public:
|
|||||||
|
|
||||||
DiffEditorController *controller() const;
|
DiffEditorController *controller() const;
|
||||||
|
|
||||||
QString makePatch(int fileIndex, int chunkIndex, bool revert, bool addPrefix = false) const;
|
QString makePatch(int fileIndex, int chunkIndex,
|
||||||
|
bool revert, bool addPrefix = false,
|
||||||
|
const QString &overriddenFileName = QString()) const;
|
||||||
|
|
||||||
void setDiffFiles(const QList<FileData> &data, const QString &directory,
|
void setDiffFiles(const QList<FileData> &data, const QString &directory,
|
||||||
const QString &startupFile = QString());
|
const QString &startupFile = QString());
|
||||||
|
|||||||
@@ -44,10 +44,14 @@
|
|||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
|
#include <texteditor/textdocument.h>
|
||||||
#include <texteditor/texteditor.h>
|
#include <texteditor/texteditor.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
using namespace Core;
|
||||||
|
|
||||||
namespace DiffEditor {
|
namespace DiffEditor {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -55,20 +59,20 @@ class DiffFilesController : public DiffEditorController
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
DiffFilesController(Core::IDocument *document);
|
DiffFilesController(IDocument *document);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FileData diffFiles(const QString &leftContents, const QString &rightContents);
|
FileData diffFiles(const QString &leftContents, const QString &rightContents);
|
||||||
};
|
};
|
||||||
|
|
||||||
DiffFilesController::DiffFilesController(Core::IDocument *document)
|
DiffFilesController::DiffFilesController(IDocument *document)
|
||||||
: DiffEditorController(document)
|
: DiffEditorController(document)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
FileData DiffFilesController::diffFiles(const QString &leftContents, const QString &rightContents)
|
FileData DiffFilesController::diffFiles(const QString &leftContents, const QString &rightContents)
|
||||||
{
|
{
|
||||||
Differ differ;
|
Differ differ;
|
||||||
QList<Diff> diffList = differ.cleanupSemantics(differ.diff(leftContents, rightContents));
|
const QList<Diff> diffList = differ.cleanupSemantics(differ.diff(leftContents, rightContents));
|
||||||
|
|
||||||
QList<Diff> leftDiffList;
|
QList<Diff> leftDiffList;
|
||||||
QList<Diff> rightDiffList;
|
QList<Diff> rightDiffList;
|
||||||
@@ -90,7 +94,7 @@ FileData DiffFilesController::diffFiles(const QString &leftContents, const QStri
|
|||||||
|
|
||||||
const ChunkData chunkData = DiffUtils::calculateOriginalData(
|
const ChunkData chunkData = DiffUtils::calculateOriginalData(
|
||||||
outputLeftDiffList, outputRightDiffList);
|
outputLeftDiffList, outputRightDiffList);
|
||||||
FileData fileData = DiffUtils::calculateContextData(chunkData, contextLineCount(), 0);
|
const FileData fileData = DiffUtils::calculateContextData(chunkData, contextLineCount(), 0);
|
||||||
|
|
||||||
return fileData;
|
return fileData;
|
||||||
}
|
}
|
||||||
@@ -99,7 +103,7 @@ class DiffCurrentFileController : public DiffFilesController
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
DiffCurrentFileController(Core::IDocument *document, const QString &fileName);
|
DiffCurrentFileController(IDocument *document, const QString &fileName);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void reload();
|
void reload();
|
||||||
@@ -108,7 +112,7 @@ private:
|
|||||||
QString m_fileName;
|
QString m_fileName;
|
||||||
};
|
};
|
||||||
|
|
||||||
DiffCurrentFileController::DiffCurrentFileController(Core::IDocument *document, const QString &fileName) :
|
DiffCurrentFileController::DiffCurrentFileController(IDocument *document, const QString &fileName) :
|
||||||
DiffFilesController(document), m_fileName(fileName)
|
DiffFilesController(document), m_fileName(fileName)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@@ -117,7 +121,7 @@ void DiffCurrentFileController::reload()
|
|||||||
QList<FileData> fileDataList;
|
QList<FileData> fileDataList;
|
||||||
|
|
||||||
TextEditor::TextDocument *textDocument = qobject_cast<TextEditor::TextDocument *>(
|
TextEditor::TextDocument *textDocument = qobject_cast<TextEditor::TextDocument *>(
|
||||||
Core::DocumentModel::documentForFilePath(m_fileName));
|
DocumentModel::documentForFilePath(m_fileName));
|
||||||
|
|
||||||
if (textDocument && textDocument->isModified()) {
|
if (textDocument && textDocument->isModified()) {
|
||||||
QString errorString;
|
QString errorString;
|
||||||
@@ -139,6 +143,7 @@ void DiffCurrentFileController::reload()
|
|||||||
fileData.rightFileInfo.fileName = m_fileName;
|
fileData.rightFileInfo.fileName = m_fileName;
|
||||||
fileData.leftFileInfo.typeInfo = tr("Saved");
|
fileData.leftFileInfo.typeInfo = tr("Saved");
|
||||||
fileData.rightFileInfo.typeInfo = tr("Modified");
|
fileData.rightFileInfo.typeInfo = tr("Modified");
|
||||||
|
fileData.rightFileInfo.patchBehaviour = DiffFileInfo::PatchEditor;
|
||||||
|
|
||||||
if (!leftFileExists)
|
if (!leftFileExists)
|
||||||
fileData.fileOperation = FileData::NewFile;
|
fileData.fileOperation = FileData::NewFile;
|
||||||
@@ -152,28 +157,28 @@ void DiffCurrentFileController::reload()
|
|||||||
|
|
||||||
/////////////////
|
/////////////////
|
||||||
|
|
||||||
class DiffAllModifiedFilesController : public DiffFilesController
|
class DiffOpenFilesController : public DiffFilesController
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
DiffAllModifiedFilesController(Core::IDocument *document);
|
DiffOpenFilesController(IDocument *document);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void reload();
|
void reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
DiffAllModifiedFilesController::DiffAllModifiedFilesController(Core::IDocument *document) :
|
DiffOpenFilesController::DiffOpenFilesController(IDocument *document) :
|
||||||
DiffFilesController(document)
|
DiffFilesController(document)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void DiffAllModifiedFilesController::reload()
|
void DiffOpenFilesController::reload()
|
||||||
{
|
{
|
||||||
QList<Core::IDocument *> openedDocuments =
|
const QList<IDocument *> openedDocuments =
|
||||||
Core::DocumentModel::openedDocuments();
|
DocumentModel::openedDocuments();
|
||||||
|
|
||||||
QList<FileData> fileDataList;
|
QList<FileData> fileDataList;
|
||||||
|
|
||||||
foreach (Core::IDocument *doc, openedDocuments) {
|
foreach (IDocument *doc, openedDocuments) {
|
||||||
TextEditor::TextDocument *textDocument = qobject_cast<TextEditor::TextDocument *>(doc);
|
TextEditor::TextDocument *textDocument = qobject_cast<TextEditor::TextDocument *>(doc);
|
||||||
|
|
||||||
if (textDocument && textDocument->isModified()) {
|
if (textDocument && textDocument->isModified()) {
|
||||||
@@ -197,6 +202,68 @@ void DiffAllModifiedFilesController::reload()
|
|||||||
fileData.rightFileInfo.fileName = fileName;
|
fileData.rightFileInfo.fileName = fileName;
|
||||||
fileData.leftFileInfo.typeInfo = tr("Saved");
|
fileData.leftFileInfo.typeInfo = tr("Saved");
|
||||||
fileData.rightFileInfo.typeInfo = tr("Modified");
|
fileData.rightFileInfo.typeInfo = tr("Modified");
|
||||||
|
fileData.rightFileInfo.patchBehaviour = DiffFileInfo::PatchEditor;
|
||||||
|
|
||||||
|
if (!leftFileExists)
|
||||||
|
fileData.fileOperation = FileData::NewFile;
|
||||||
|
|
||||||
|
fileDataList << fileData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setDiffFiles(fileDataList);
|
||||||
|
reloadFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
|
||||||
|
class DiffModifiedFilesController : public DiffFilesController
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
DiffModifiedFilesController(IDocument *document, const QStringList &fileNames);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void reload();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList m_fileNames;
|
||||||
|
};
|
||||||
|
|
||||||
|
DiffModifiedFilesController::DiffModifiedFilesController(IDocument *document, const QStringList &fileNames) :
|
||||||
|
DiffFilesController(document), m_fileNames(fileNames)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void DiffModifiedFilesController::reload()
|
||||||
|
{
|
||||||
|
QList<FileData> fileDataList;
|
||||||
|
|
||||||
|
foreach (const QString fileName, m_fileNames) {
|
||||||
|
TextEditor::TextDocument *textDocument = qobject_cast<TextEditor::TextDocument *>(
|
||||||
|
DocumentModel::documentForFilePath(fileName));
|
||||||
|
|
||||||
|
if (textDocument && textDocument->isModified()) {
|
||||||
|
QString errorString;
|
||||||
|
Utils::TextFileFormat format = textDocument->format();
|
||||||
|
|
||||||
|
QString leftText;
|
||||||
|
bool leftFileExists = true;
|
||||||
|
const QString fileName = textDocument->filePath().toString();
|
||||||
|
if (Utils::TextFileFormat::readFile(fileName,
|
||||||
|
format.codec,
|
||||||
|
&leftText, &format, &errorString)
|
||||||
|
!= Utils::TextFileFormat::ReadSuccess) {
|
||||||
|
leftFileExists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString rightText = textDocument->plainText();
|
||||||
|
|
||||||
|
FileData fileData = diffFiles(leftText, rightText);
|
||||||
|
fileData.leftFileInfo.fileName = fileName;
|
||||||
|
fileData.rightFileInfo.fileName = fileName;
|
||||||
|
fileData.leftFileInfo.typeInfo = tr("Saved");
|
||||||
|
fileData.rightFileInfo.typeInfo = tr("Modified");
|
||||||
|
fileData.rightFileInfo.patchBehaviour = DiffFileInfo::PatchEditor;
|
||||||
|
|
||||||
if (!leftFileExists)
|
if (!leftFileExists)
|
||||||
fileData.fileOperation = FileData::NewFile;
|
fileData.fileOperation = FileData::NewFile;
|
||||||
@@ -215,7 +282,7 @@ class DiffExternalFilesController : public DiffFilesController
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
DiffExternalFilesController(Core::IDocument *document, const QString &leftFileName,
|
DiffExternalFilesController(IDocument *document, const QString &leftFileName,
|
||||||
const QString &rightFileName);
|
const QString &rightFileName);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -226,7 +293,7 @@ private:
|
|||||||
QString m_rightFileName;
|
QString m_rightFileName;
|
||||||
};
|
};
|
||||||
|
|
||||||
DiffExternalFilesController::DiffExternalFilesController(Core::IDocument *document, const QString &leftFileName,
|
DiffExternalFilesController::DiffExternalFilesController(IDocument *document, const QString &leftFileName,
|
||||||
const QString &rightFileName) :
|
const QString &rightFileName) :
|
||||||
DiffFilesController(document), m_leftFileName(leftFileName), m_rightFileName(rightFileName)
|
DiffFilesController(document), m_leftFileName(leftFileName), m_rightFileName(rightFileName)
|
||||||
{ }
|
{ }
|
||||||
@@ -235,7 +302,7 @@ void DiffExternalFilesController::reload()
|
|||||||
{
|
{
|
||||||
QString errorString;
|
QString errorString;
|
||||||
Utils::TextFileFormat format;
|
Utils::TextFileFormat format;
|
||||||
format.codec = Core::EditorManager::defaultTextCodec();
|
format.codec = EditorManager::defaultTextCodec();
|
||||||
|
|
||||||
QString leftText;
|
QString leftText;
|
||||||
bool leftFileExists = true;
|
bool leftFileExists = true;
|
||||||
@@ -273,42 +340,79 @@ void DiffExternalFilesController::reload()
|
|||||||
|
|
||||||
/////////////////
|
/////////////////
|
||||||
|
|
||||||
|
|
||||||
|
static TextEditor::TextDocument *currentTextDocument()
|
||||||
|
{
|
||||||
|
return qobject_cast<TextEditor::TextDocument *>(
|
||||||
|
EditorManager::currentDocument());
|
||||||
|
}
|
||||||
|
|
||||||
|
DiffEditorServiceImpl::DiffEditorServiceImpl(QObject *parent) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiffEditorServiceImpl::diffModifiedFiles(const QStringList &fileNames)
|
||||||
|
{
|
||||||
|
const QString documentId = QLatin1String("Diff Modified Files");
|
||||||
|
const QString title = tr("Diff Modified Files");
|
||||||
|
auto const document = qobject_cast<DiffEditorDocument *>(
|
||||||
|
DiffEditorController::findOrCreateDocument(documentId, title));
|
||||||
|
if (!document)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!DiffEditorController::controller(document))
|
||||||
|
new DiffModifiedFilesController(document, fileNames);
|
||||||
|
EditorManager::activateEditorForDocument(document);
|
||||||
|
document->reload();
|
||||||
|
}
|
||||||
|
|
||||||
bool DiffEditorPlugin::initialize(const QStringList &arguments, QString *errorMessage)
|
bool DiffEditorPlugin::initialize(const QStringList &arguments, QString *errorMessage)
|
||||||
{
|
{
|
||||||
Q_UNUSED(arguments)
|
Q_UNUSED(arguments)
|
||||||
Q_UNUSED(errorMessage)
|
Q_UNUSED(errorMessage)
|
||||||
|
|
||||||
//register actions
|
//register actions
|
||||||
Core::ActionContainer *toolsContainer
|
ActionContainer *toolsContainer
|
||||||
= Core::ActionManager::actionContainer(Core::Constants::M_TOOLS);
|
= ActionManager::actionContainer(Core::Constants::M_TOOLS);
|
||||||
toolsContainer->insertGroup(Core::Constants::G_TOOLS_OPTIONS, Constants::G_TOOLS_DIFF);
|
toolsContainer->insertGroup(Core::Constants::G_TOOLS_OPTIONS, Constants::G_TOOLS_DIFF);
|
||||||
Core::ActionContainer *diffContainer = Core::ActionManager::createMenu("Diff");
|
ActionContainer *diffContainer = ActionManager::createMenu("Diff");
|
||||||
diffContainer->menu()->setTitle(tr("&Diff"));
|
diffContainer->menu()->setTitle(tr("&Diff"));
|
||||||
toolsContainer->addMenu(diffContainer, Constants::G_TOOLS_DIFF);
|
toolsContainer->addMenu(diffContainer, Constants::G_TOOLS_DIFF);
|
||||||
|
|
||||||
m_diffCurrentFileAction = new QAction(tr("Diff Current File"), this);
|
m_diffCurrentFileAction = new QAction(tr("Diff Current File"), this);
|
||||||
Core::Command *diffCurrentFileCommand = Core::ActionManager::registerAction(m_diffCurrentFileAction, "DiffEditor.DiffCurrentFile");
|
Command *diffCurrentFileCommand = ActionManager::registerAction(m_diffCurrentFileAction, "DiffEditor.DiffCurrentFile");
|
||||||
diffCurrentFileCommand->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+H") : tr("Ctrl+H")));
|
diffCurrentFileCommand->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+H") : tr("Ctrl+H")));
|
||||||
connect(m_diffCurrentFileAction, &QAction::triggered, this, &DiffEditorPlugin::diffCurrentFile);
|
connect(m_diffCurrentFileAction, &QAction::triggered, this, &DiffEditorPlugin::diffCurrentFile);
|
||||||
diffContainer->addAction(diffCurrentFileCommand);
|
diffContainer->addAction(diffCurrentFileCommand);
|
||||||
|
|
||||||
QAction *diffAllModifiedFilesAction = new QAction(tr("Diff All Modified Files"), this);
|
m_diffOpenFilesAction = new QAction(tr("Diff Open Files"), this);
|
||||||
Core::Command *diffAllModifiedFilesCommand = Core::ActionManager::registerAction(diffAllModifiedFilesAction, "DiffEditor.DiffAllModifiedFiles");
|
Command *diffOpenFilesCommand = ActionManager::registerAction(m_diffOpenFilesAction, "DiffEditor.DiffOpenFiles");
|
||||||
diffAllModifiedFilesCommand->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+Shift+H") : tr("Ctrl+Shift+H")));
|
diffOpenFilesCommand->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+Shift+H") : tr("Ctrl+Shift+H")));
|
||||||
connect(diffAllModifiedFilesAction, &QAction::triggered, this, &DiffEditorPlugin::diffAllModifiedFiles);
|
connect(m_diffOpenFilesAction, &QAction::triggered, this, &DiffEditorPlugin::diffOpenFiles);
|
||||||
diffContainer->addAction(diffAllModifiedFilesCommand);
|
diffContainer->addAction(diffOpenFilesCommand);
|
||||||
|
|
||||||
QAction *diffExternalFilesAction = new QAction(tr("Diff External Files..."), this);
|
QAction *diffExternalFilesAction = new QAction(tr("Diff External Files..."), this);
|
||||||
Core::Command *diffExternalFilesCommand = Core::ActionManager::registerAction(diffExternalFilesAction, "DiffEditor.DiffExternalFiles");
|
Command *diffExternalFilesCommand = ActionManager::registerAction(diffExternalFilesAction, "DiffEditor.DiffExternalFiles");
|
||||||
connect(diffExternalFilesAction, &QAction::triggered, this, &DiffEditorPlugin::diffExternalFiles);
|
connect(diffExternalFilesAction, &QAction::triggered, this, &DiffEditorPlugin::diffExternalFiles);
|
||||||
diffContainer->addAction(diffExternalFilesCommand);
|
diffContainer->addAction(diffExternalFilesCommand);
|
||||||
|
|
||||||
connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
|
connect(EditorManager::instance(), &EditorManager::currentEditorChanged,
|
||||||
this, &DiffEditorPlugin::updateCurrentEditor);
|
this, &DiffEditorPlugin::updateDiffCurrentFileAction);
|
||||||
|
connect(EditorManager::instance(), &EditorManager::currentDocumentStateChanged,
|
||||||
|
this, &DiffEditorPlugin::updateDiffCurrentFileAction);
|
||||||
|
connect(EditorManager::instance(), &EditorManager::editorOpened,
|
||||||
|
this, &DiffEditorPlugin::updateDiffOpenFilesAction);
|
||||||
|
connect(EditorManager::instance(), &EditorManager::editorsClosed,
|
||||||
|
this, &DiffEditorPlugin::updateDiffOpenFilesAction);
|
||||||
|
connect(EditorManager::instance(), &EditorManager::documentStateChanged,
|
||||||
|
this, &DiffEditorPlugin::updateDiffOpenFilesAction);
|
||||||
|
|
||||||
updateActions();
|
updateDiffCurrentFileAction();
|
||||||
|
updateDiffOpenFilesAction();
|
||||||
|
|
||||||
addAutoReleasedObject(new DiffEditorFactory(this));
|
addAutoReleasedObject(new DiffEditorFactory(this));
|
||||||
|
addAutoReleasedObject(new DiffEditorServiceImpl(this));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -316,36 +420,28 @@ bool DiffEditorPlugin::initialize(const QStringList &arguments, QString *errorMe
|
|||||||
void DiffEditorPlugin::extensionsInitialized()
|
void DiffEditorPlugin::extensionsInitialized()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void DiffEditorPlugin::updateCurrentEditor(Core::IEditor *editor)
|
void DiffEditorPlugin::updateDiffCurrentFileAction()
|
||||||
{
|
{
|
||||||
if (m_currentTextDocument)
|
auto textDocument = currentTextDocument();
|
||||||
m_currentTextDocument->disconnect(this);
|
const bool enabled = textDocument && textDocument->isModified();
|
||||||
m_currentTextDocument = 0;
|
m_diffCurrentFileAction->setEnabled(enabled);
|
||||||
|
|
||||||
if (editor) {
|
|
||||||
TextEditor::TextEditorWidget *editorWidget = qobject_cast<TextEditor::TextEditorWidget *>(editor->widget());
|
|
||||||
if (editorWidget) {
|
|
||||||
m_currentTextDocument = editorWidget->textDocument();
|
|
||||||
connect(m_currentTextDocument.data(), &Core::IDocument::changed,
|
|
||||||
this, &DiffEditorPlugin::updateActions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateActions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiffEditorPlugin::updateActions()
|
void DiffEditorPlugin::updateDiffOpenFilesAction()
|
||||||
{
|
{
|
||||||
const bool diffCurrentFileEnabled = m_currentTextDocument && m_currentTextDocument->isModified();
|
const bool enabled = Utils::anyOf(DocumentModel::openedDocuments(), [](IDocument *doc) {
|
||||||
m_diffCurrentFileAction->setEnabled(diffCurrentFileEnabled);
|
return doc->isModified() && qobject_cast<TextEditor::TextDocument *>(doc);
|
||||||
|
});
|
||||||
|
m_diffOpenFilesAction->setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiffEditorPlugin::diffCurrentFile()
|
void DiffEditorPlugin::diffCurrentFile()
|
||||||
{
|
{
|
||||||
if (!m_currentTextDocument)
|
auto textDocument = currentTextDocument();
|
||||||
|
if (!textDocument)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QString fileName = m_currentTextDocument->filePath().toString();
|
const QString fileName = textDocument->filePath().toString();
|
||||||
|
|
||||||
if (fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
return;
|
return;
|
||||||
@@ -359,34 +455,34 @@ void DiffEditorPlugin::diffCurrentFile()
|
|||||||
|
|
||||||
if (!DiffEditorController::controller(document))
|
if (!DiffEditorController::controller(document))
|
||||||
new DiffCurrentFileController(document, fileName);
|
new DiffCurrentFileController(document, fileName);
|
||||||
Core::EditorManager::activateEditorForDocument(document);
|
EditorManager::activateEditorForDocument(document);
|
||||||
document->reload();
|
document->reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiffEditorPlugin::diffAllModifiedFiles()
|
void DiffEditorPlugin::diffOpenFiles()
|
||||||
{
|
{
|
||||||
const QString documentId = QLatin1String("Diff All Modified Files");
|
const QString documentId = QLatin1String("Diff Open Files");
|
||||||
const QString title = tr("Diff All Modified Files");
|
const QString title = tr("Diff Open Files");
|
||||||
auto const document = qobject_cast<DiffEditorDocument *>(
|
auto const document = qobject_cast<DiffEditorDocument *>(
|
||||||
DiffEditorController::findOrCreateDocument(documentId, title));
|
DiffEditorController::findOrCreateDocument(documentId, title));
|
||||||
if (!document)
|
if (!document)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!DiffEditorController::controller(document))
|
if (!DiffEditorController::controller(document))
|
||||||
new DiffAllModifiedFilesController(document);
|
new DiffOpenFilesController(document);
|
||||||
Core::EditorManager::activateEditorForDocument(document);
|
EditorManager::activateEditorForDocument(document);
|
||||||
document->reload();
|
document->reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiffEditorPlugin::diffExternalFiles()
|
void DiffEditorPlugin::diffExternalFiles()
|
||||||
{
|
{
|
||||||
const QString fileName1 = QFileDialog::getOpenFileName(Core::ICore::dialogParent(),
|
const QString fileName1 = QFileDialog::getOpenFileName(ICore::dialogParent(),
|
||||||
tr("Select First File for Diff"),
|
tr("Select First File for Diff"),
|
||||||
QString());
|
QString());
|
||||||
if (fileName1.isNull())
|
if (fileName1.isNull())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QString fileName2 = QFileDialog::getOpenFileName(Core::ICore::dialogParent(),
|
const QString fileName2 = QFileDialog::getOpenFileName(ICore::dialogParent(),
|
||||||
tr("Select Second File for Diff"),
|
tr("Select Second File for Diff"),
|
||||||
QString());
|
QString());
|
||||||
if (fileName2.isNull())
|
if (fileName2.isNull())
|
||||||
@@ -402,7 +498,7 @@ void DiffEditorPlugin::diffExternalFiles()
|
|||||||
|
|
||||||
if (!DiffEditorController::controller(document))
|
if (!DiffEditorController::controller(document))
|
||||||
new DiffExternalFilesController(document, fileName1, fileName2);
|
new DiffExternalFilesController(document, fileName1, fileName2);
|
||||||
Core::EditorManager::activateEditorForDocument(document);
|
EditorManager::activateEditorForDocument(document);
|
||||||
document->reload();
|
document->reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
#include "diffeditor_global.h"
|
#include "diffeditor_global.h"
|
||||||
|
|
||||||
#include <texteditor/textdocument.h>
|
#include <coreplugin/diffservice.h>
|
||||||
#include <extensionsystem/iplugin.h>
|
#include <extensionsystem/iplugin.h>
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QAction)
|
QT_FORWARD_DECLARE_CLASS(QAction)
|
||||||
@@ -37,6 +37,16 @@ namespace Core { class IEditor; }
|
|||||||
namespace DiffEditor {
|
namespace DiffEditor {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class DiffEditorServiceImpl : public QObject, public Core::DiffService
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(Core::DiffService)
|
||||||
|
public:
|
||||||
|
explicit DiffEditorServiceImpl(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
void diffModifiedFiles(const QStringList &fileNames) override;
|
||||||
|
};
|
||||||
|
|
||||||
class DiffEditorPlugin : public ExtensionSystem::IPlugin
|
class DiffEditorPlugin : public ExtensionSystem::IPlugin
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -47,10 +57,10 @@ public:
|
|||||||
void extensionsInitialized();
|
void extensionsInitialized();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateCurrentEditor(Core::IEditor *editor);
|
void updateDiffCurrentFileAction();
|
||||||
void updateActions();
|
void updateDiffOpenFilesAction();
|
||||||
void diffCurrentFile();
|
void diffCurrentFile();
|
||||||
void diffAllModifiedFiles();
|
void diffOpenFiles();
|
||||||
void diffExternalFiles();
|
void diffExternalFiles();
|
||||||
|
|
||||||
#ifdef WITH_TESTS
|
#ifdef WITH_TESTS
|
||||||
@@ -61,7 +71,7 @@ private slots:
|
|||||||
#endif // WITH_TESTS
|
#endif // WITH_TESTS
|
||||||
private:
|
private:
|
||||||
QAction *m_diffCurrentFileAction;
|
QAction *m_diffCurrentFileAction;
|
||||||
QPointer<TextEditor::TextDocument> m_currentTextDocument;
|
QAction *m_diffOpenFilesAction;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include <coreplugin/patchtool.h>
|
#include <coreplugin/patchtool.h>
|
||||||
|
|
||||||
#include <texteditor/fontsettings.h>
|
#include <texteditor/fontsettings.h>
|
||||||
|
#include <texteditor/textdocument.h>
|
||||||
|
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QTemporaryFile>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
|
|
||||||
using namespace Core;
|
using namespace Core;
|
||||||
@@ -77,27 +79,60 @@ void DiffEditorWidgetController::patch(bool revert)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int strip = m_document->baseDirectory().isEmpty() ? -1 : 0;
|
|
||||||
|
|
||||||
const FileData fileData = m_contextFileData.at(m_contextMenuFileIndex);
|
const FileData fileData = m_contextFileData.at(m_contextMenuFileIndex);
|
||||||
const QString fileName = revert
|
const QString fileName = revert
|
||||||
? fileData.rightFileInfo.fileName
|
? fileData.rightFileInfo.fileName
|
||||||
: fileData.leftFileInfo.fileName;
|
: fileData.leftFileInfo.fileName;
|
||||||
|
const DiffFileInfo::PatchBehaviour patchBehaviour = revert
|
||||||
|
? fileData.rightFileInfo.patchBehaviour
|
||||||
|
: fileData.leftFileInfo.patchBehaviour;
|
||||||
|
|
||||||
const QString workingDirectory = m_document->baseDirectory().isEmpty()
|
const QString workingDirectory = m_document->baseDirectory().isEmpty()
|
||||||
? QFileInfo(fileName).absolutePath()
|
? QFileInfo(fileName).absolutePath()
|
||||||
: m_document->baseDirectory();
|
: m_document->baseDirectory();
|
||||||
|
const QString absFileName = QFileInfo(workingDirectory + '/' + QFileInfo(fileName).fileName()).absoluteFilePath();
|
||||||
|
|
||||||
|
if (patchBehaviour == DiffFileInfo::PatchFile) {
|
||||||
|
const int strip = m_document->baseDirectory().isEmpty() ? -1 : 0;
|
||||||
|
|
||||||
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, revert);
|
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, revert);
|
||||||
|
|
||||||
if (patch.isEmpty())
|
if (patch.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QString absFileName = QFileInfo(workingDirectory + '/' + fileName).absoluteFilePath();
|
|
||||||
FileChangeBlocker fileChangeBlocker(absFileName);
|
FileChangeBlocker fileChangeBlocker(absFileName);
|
||||||
if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch),
|
if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch),
|
||||||
workingDirectory, strip, revert))
|
workingDirectory, strip, revert))
|
||||||
m_document->reload();
|
m_document->reload();
|
||||||
|
} else { // PatchEditor
|
||||||
|
TextEditor::TextDocument *textDocument = qobject_cast<TextEditor::TextDocument *>(
|
||||||
|
DocumentModel::documentForFilePath(absFileName));
|
||||||
|
if (!textDocument)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QTemporaryFile contentsCopy;
|
||||||
|
if (!contentsCopy.open())
|
||||||
|
return;
|
||||||
|
|
||||||
|
contentsCopy.write(textDocument->contents());
|
||||||
|
contentsCopy.close();
|
||||||
|
|
||||||
|
const QString contentsCopyFileName = contentsCopy.fileName();
|
||||||
|
const QString contentsCopyDir = QFileInfo(contentsCopyFileName).absolutePath();
|
||||||
|
|
||||||
|
const QString patch = m_document->makePatch(m_contextMenuFileIndex,
|
||||||
|
m_contextMenuChunkIndex, revert, false, QFileInfo(contentsCopyFileName).fileName());
|
||||||
|
|
||||||
|
if (patch.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch),
|
||||||
|
contentsCopyDir, 0, revert)) {
|
||||||
|
QString errorString;
|
||||||
|
if (textDocument->reload(&errorString, contentsCopyFileName))
|
||||||
|
m_document->reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiffEditorWidgetController::jumpToOriginalFile(const QString &fileName,
|
void DiffEditorWidgetController::jumpToOriginalFile(const QString &fileName,
|
||||||
|
|||||||
@@ -38,12 +38,18 @@ class Diff;
|
|||||||
|
|
||||||
class DIFFEDITOR_EXPORT DiffFileInfo {
|
class DIFFEDITOR_EXPORT DiffFileInfo {
|
||||||
public:
|
public:
|
||||||
|
enum PatchBehaviour {
|
||||||
|
PatchFile,
|
||||||
|
PatchEditor
|
||||||
|
};
|
||||||
|
|
||||||
DiffFileInfo() {}
|
DiffFileInfo() {}
|
||||||
DiffFileInfo(const QString &file) : fileName(file) {}
|
DiffFileInfo(const QString &file) : fileName(file) {}
|
||||||
DiffFileInfo(const QString &file, const QString &type)
|
DiffFileInfo(const QString &file, const QString &type)
|
||||||
: fileName(file), typeInfo(type) {}
|
: fileName(file), typeInfo(type) {}
|
||||||
QString fileName;
|
QString fileName;
|
||||||
QString typeInfo;
|
QString typeInfo;
|
||||||
|
PatchBehaviour patchBehaviour = PatchFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DIFFEDITOR_EXPORT TextLineData {
|
class DIFFEDITOR_EXPORT TextLineData {
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ void ExtPropertiesMView::onConfigPathChanged(const QString &path)
|
|||||||
if (path.isEmpty()) {
|
if (path.isEmpty()) {
|
||||||
if (!project->configPath().isEmpty()) {
|
if (!project->configPath().isEmpty()) {
|
||||||
project->setConfigPath(QString());
|
project->setConfigPath(QString());
|
||||||
m_projectController->setModified(true);
|
m_projectController->setModified();
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -103,7 +103,7 @@ void ExtPropertiesMView::onConfigPathChanged(const QString &path)
|
|||||||
QString configPath = projectDir.relativeFilePath(absConfigPath.filePath());
|
QString configPath = projectDir.relativeFilePath(absConfigPath.filePath());
|
||||||
if (configPath != project->configPath()) {
|
if (configPath != project->configPath()) {
|
||||||
project->setConfigPath(configPath);
|
project->setConfigPath(configPath);
|
||||||
m_projectController->setModified(true);
|
m_projectController->setModified();
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ bool ModelDocument::save(QString *errorString, const QString &name, bool autoSav
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (autoSave) {
|
if (autoSave) {
|
||||||
d->documentController->projectController()->setModified(true);
|
d->documentController->projectController()->setModified();
|
||||||
} else {
|
} else {
|
||||||
setFilePath(Utils::FileName::fromString(d->documentController->projectController()->project()->fileName()));
|
setFilePath(Utils::FileName::fromString(d->documentController->projectController()->project()->fileName()));
|
||||||
emit changed();
|
emit changed();
|
||||||
@@ -108,6 +108,11 @@ bool ModelDocument::shouldAutoSave() const
|
|||||||
return isModified();
|
return isModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ModelDocument::isModified() const
|
||||||
|
{
|
||||||
|
return d->documentController ? d->documentController->projectController()->isModified() : false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ModelDocument::isSaveAsAllowed() const
|
bool ModelDocument::isSaveAsAllowed() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -135,10 +140,6 @@ Core::IDocument::OpenResult ModelDocument::load(QString *errorString, const QStr
|
|||||||
{
|
{
|
||||||
d->documentController = ModelEditorPlugin::modelsManager()->createModel(this);
|
d->documentController = ModelEditorPlugin::modelsManager()->createModel(this);
|
||||||
connect(d->documentController, &qmt::DocumentController::changed, this, &IDocument::changed);
|
connect(d->documentController, &qmt::DocumentController::changed, this, &IDocument::changed);
|
||||||
connect(d->documentController, &qmt::DocumentController::modificationChanged, this, &IDocument::setModified);
|
|
||||||
connect(this, &IDocument::modificationChanged,
|
|
||||||
d->documentController->projectController(), &qmt::ProjectController::setModified);
|
|
||||||
setModified(d->documentController->projectController()->isModified());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
d->documentController->loadProject(fileName);
|
d->documentController->loadProject(fileName);
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ public:
|
|||||||
const QString &realFileName) override;
|
const QString &realFileName) override;
|
||||||
bool save(QString *errorString, const QString &fileName, bool autoSave) override;
|
bool save(QString *errorString, const QString &fileName, bool autoSave) override;
|
||||||
bool shouldAutoSave() const override;
|
bool shouldAutoSave() const override;
|
||||||
|
bool isModified() const override;
|
||||||
bool isSaveAsAllowed() const override;
|
bool isSaveAsAllowed() const override;
|
||||||
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
|
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "panelswidget.h"
|
#include "panelswidget.h"
|
||||||
#include "project.h"
|
#include "project.h"
|
||||||
#include "projectexplorer.h"
|
#include "projectexplorer.h"
|
||||||
|
#include "projectexplorericons.h"
|
||||||
#include "projectwindow.h"
|
#include "projectwindow.h"
|
||||||
#include "runsettingspropertiespage.h"
|
#include "runsettingspropertiespage.h"
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
@@ -563,8 +564,19 @@ public:
|
|||||||
case KitIdRole:
|
case KitIdRole:
|
||||||
return m_kitId.toSetting();
|
return m_kitId.toSetting();
|
||||||
|
|
||||||
case Qt::DecorationRole:
|
case Qt::DecorationRole: {
|
||||||
return Utils::Icons::EMPTY14.icon();
|
switch (m_subIndex) {
|
||||||
|
case BuildPage: {
|
||||||
|
static const QIcon buildIcon = ProjectExplorer::Icons::BUILD_SMALL.icon();
|
||||||
|
return buildIcon;
|
||||||
|
}
|
||||||
|
case RunPage: {
|
||||||
|
static const QIcon runIcon = Utils::Icons::RUN_SMALL.icon();
|
||||||
|
return runIcon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -263,7 +263,9 @@ QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplor
|
|||||||
if (toolchain.contains(QLatin1String("msvc"))) {
|
if (toolchain.contains(QLatin1String("msvc"))) {
|
||||||
data.insert(QLatin1String(CPP_COMPILERNAME), mainCompilerName);
|
data.insert(QLatin1String(CPP_COMPILERNAME), mainCompilerName);
|
||||||
} else {
|
} else {
|
||||||
|
if (!cCompilerName.isEmpty())
|
||||||
data.insert(QLatin1String(CPP_COMPILERNAME), cCompilerName);
|
data.insert(QLatin1String(CPP_COMPILERNAME), cCompilerName);
|
||||||
|
if (!cxxCompilerName.isEmpty())
|
||||||
data.insert(QLatin1String(CPP_CXXCOMPILERNAME), cxxCompilerName);
|
data.insert(QLatin1String(CPP_CXXCOMPILERNAME), cxxCompilerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -710,10 +710,12 @@ void QbsProductNode::setQbsProductData(const qbs::Project &project, const qbs::P
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prd.isEnabled()) {
|
||||||
const QStringList generatedFiles
|
const QStringList generatedFiles
|
||||||
= Utils::transform(prd.generatedArtifacts(), &qbs::ArtifactData::filePath);
|
= Utils::transform(prd.generatedArtifacts(), &qbs::ArtifactData::filePath);
|
||||||
QbsGroupNode::setupFiles(m_generatedFilesNode, qbs::GroupData(), generatedFiles,
|
QbsGroupNode::setupFiles(m_generatedFilesNode, qbs::GroupData(), generatedFiles,
|
||||||
prd.buildDirectory(), true, true);
|
prd.buildDirectory(), true, true);
|
||||||
|
}
|
||||||
|
|
||||||
addProjectNodes(toAdd);
|
addProjectNodes(toAdd);
|
||||||
removeProjectNodes(toRemove);
|
removeProjectNodes(toRemove);
|
||||||
|
|||||||
@@ -670,8 +670,9 @@ void addSignalHandlerOrGotoImplementation(const SelectionContext &selectionState
|
|||||||
|
|
||||||
QString itemId = modelNode.id();
|
QString itemId = modelNode.id();
|
||||||
|
|
||||||
const QString fileName = QmlDesignerPlugin::instance()->documentManager().currentDesignDocument()->fileName().toString();
|
const Utils::FileName currentDesignDocument = QmlDesignerPlugin::instance()->documentManager().currentDesignDocument()->fileName();
|
||||||
const QString typeName = QmlDesignerPlugin::instance()->documentManager().currentDesignDocument()->fileName().toFileInfo().baseName();
|
const QString fileName = currentDesignDocument.toString();
|
||||||
|
const QString typeName = currentDesignDocument.toFileInfo().baseName();
|
||||||
|
|
||||||
QStringList signalNames = cleanSignalNames(getSortedSignalNameList(selectionState.selectedModelNodes().first()));
|
QStringList signalNames = cleanSignalNames(getSortedSignalNameList(selectionState.selectedModelNodes().first()));
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ static ComponentTextModifier *createComponentTextModifier(TextModifier *original
|
|||||||
componentEndOffset = componentStartOffset + rewriterView->nodeLength(componentNode);
|
componentEndOffset = componentStartOffset + rewriterView->nodeLength(componentNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ComponentTextModifier (originalModifier, componentStartOffset, componentEndOffset, rootStartOffset);
|
return new ComponentTextModifier(originalModifier, componentStartOffset, componentEndOffset, rootStartOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesignDocument::loadInFileComponent(const ModelNode &componentNode)
|
bool DesignDocument::loadInFileComponent(const ModelNode &componentNode)
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ WidgetInfo ItemLibraryView::widgetInfo()
|
|||||||
void ItemLibraryView::modelAttached(Model *model)
|
void ItemLibraryView::modelAttached(Model *model)
|
||||||
{
|
{
|
||||||
AbstractView::modelAttached(model);
|
AbstractView::modelAttached(model);
|
||||||
|
m_widget->clearSearchFilter();
|
||||||
m_widget->setModel(model);
|
m_widget->setModel(model);
|
||||||
updateImports();
|
updateImports();
|
||||||
model->attachView(m_importManagerView);
|
model->attachView(m_importManagerView);
|
||||||
@@ -75,6 +76,7 @@ void ItemLibraryView::modelAboutToBeDetached(Model *model)
|
|||||||
model->detachView(m_importManagerView);
|
model->detachView(m_importManagerView);
|
||||||
|
|
||||||
AbstractView::modelAboutToBeDetached(model);
|
AbstractView::modelAboutToBeDetached(model);
|
||||||
|
|
||||||
m_widget->setModel(0);
|
m_widget->setModel(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -247,6 +247,11 @@ QString ItemLibraryWidget::qmlSourcesPath()
|
|||||||
return Core::ICore::resourcePath() + QStringLiteral("/qmldesigner/itemLibraryQmlSources");
|
return Core::ICore::resourcePath() + QStringLiteral("/qmldesigner/itemLibraryQmlSources");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItemLibraryWidget::clearSearchFilter()
|
||||||
|
{
|
||||||
|
m_filterLineEdit->clear();
|
||||||
|
}
|
||||||
|
|
||||||
void ItemLibraryWidget::reloadQmlSource()
|
void ItemLibraryWidget::reloadQmlSource()
|
||||||
{
|
{
|
||||||
QString itemLibraryQmlFilePath = qmlSourcesPath() + QStringLiteral("/ItemsView.qml");
|
QString itemLibraryQmlFilePath = qmlSourcesPath() + QStringLiteral("/ItemsView.qml");
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ public:
|
|||||||
void setImportsWidget(QWidget *importsWidget);
|
void setImportsWidget(QWidget *importsWidget);
|
||||||
|
|
||||||
static QString qmlSourcesPath();
|
static QString qmlSourcesPath();
|
||||||
|
void clearSearchFilter();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setSearchFilter(const QString &searchFilter);
|
void setSearchFilter(const QString &searchFilter);
|
||||||
void delayedUpdateModel();
|
void delayedUpdateModel();
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class QMLDESIGNERCORE_EXPORT BaseTextEditModifier: public PlainTextEditModifier
|
|||||||
public:
|
public:
|
||||||
BaseTextEditModifier(TextEditor::TextEditorWidget *textEdit);
|
BaseTextEditModifier(TextEditor::TextEditorWidget *textEdit);
|
||||||
|
|
||||||
|
void indentLines(int startLine, int endLine) override;
|
||||||
void indent(int offset, int length) override;
|
void indent(int offset, int length) override;
|
||||||
|
|
||||||
int indentDepth() const override;
|
int indentDepth() const override;
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public:
|
|||||||
void replace(int offset, int length, const QString& replacement) override;
|
void replace(int offset, int length, const QString& replacement) override;
|
||||||
void move(const MoveInfo &moveInfo) override;
|
void move(const MoveInfo &moveInfo) override;
|
||||||
void indent(int offset, int length) override;
|
void indent(int offset, int length) override;
|
||||||
|
void indentLines(int startLine, int endLine) override;
|
||||||
|
|
||||||
int indentDepth() const override;
|
int indentDepth() const override;
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ public:
|
|||||||
void replace(int offset, int length, const QString &replacement) override;
|
void replace(int offset, int length, const QString &replacement) override;
|
||||||
void move(const MoveInfo &moveInfo) override;
|
void move(const MoveInfo &moveInfo) override;
|
||||||
void indent(int offset, int length) override = 0;
|
void indent(int offset, int length) override = 0;
|
||||||
|
void indentLines(int startLine, int endLine) override = 0;
|
||||||
|
|
||||||
int indentDepth() const override = 0;
|
int indentDepth() const override = 0;
|
||||||
|
|
||||||
@@ -102,10 +103,12 @@ public:
|
|||||||
: PlainTextEditModifier(textEdit)
|
: PlainTextEditModifier(textEdit)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual void indent(int /*offset*/, int /*length*/)
|
void indent(int /*offset*/, int /*length*/) override
|
||||||
|
{}
|
||||||
|
void indentLines(int /*offset*/, int /*length*/) override
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual int indentDepth() const
|
int indentDepth() const override
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ public:
|
|||||||
virtual void replace(int offset, int length, const QString& replacement) = 0;
|
virtual void replace(int offset, int length, const QString& replacement) = 0;
|
||||||
virtual void move(const MoveInfo &moveInfo) = 0;
|
virtual void move(const MoveInfo &moveInfo) = 0;
|
||||||
virtual void indent(int offset, int length) = 0;
|
virtual void indent(int offset, int length) = 0;
|
||||||
|
virtual void indentLines(int startLine, int endLine) = 0;
|
||||||
|
|
||||||
virtual int indentDepth() const = 0;
|
virtual int indentDepth() const = 0;
|
||||||
|
|
||||||
@@ -74,6 +75,7 @@ public:
|
|||||||
virtual QTextDocument *textDocument() const = 0;
|
virtual QTextDocument *textDocument() const = 0;
|
||||||
virtual QString text() const = 0;
|
virtual QString text() const = 0;
|
||||||
virtual QTextCursor textCursor() const = 0;
|
virtual QTextCursor textCursor() const = 0;
|
||||||
|
static int getLineInDocument(QTextDocument* document, int offset);
|
||||||
|
|
||||||
virtual void deactivateChangeSignals() = 0;
|
virtual void deactivateChangeSignals() = 0;
|
||||||
virtual void reactivateChangeSignals() = 0;
|
virtual void reactivateChangeSignals() = 0;
|
||||||
|
|||||||
@@ -43,29 +43,20 @@ BaseTextEditModifier::BaseTextEditModifier(TextEditor::TextEditorWidget *textEdi
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseTextEditModifier::indent(int offset, int length)
|
void BaseTextEditModifier::indentLines(int startLine, int endLine)
|
||||||
{
|
{
|
||||||
if (length == 0 || offset < 0 || offset + length >= text().length())
|
if (startLine < 0)
|
||||||
|
return;
|
||||||
|
TextEditor::TextEditorWidget *baseTextEditorWidget = qobject_cast<TextEditor::TextEditorWidget*>(plainTextEdit());
|
||||||
|
if (!baseTextEditorWidget)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (TextEditor::TextEditorWidget *baseTextEditorWidget = qobject_cast<TextEditor::TextEditorWidget*>(plainTextEdit())) {
|
QTextDocument *textDocument = plainTextEdit()->document();
|
||||||
|
|
||||||
TextEditor::TextDocument *baseTextEditorDocument = baseTextEditorWidget->textDocument();
|
TextEditor::TextDocument *baseTextEditorDocument = baseTextEditorWidget->textDocument();
|
||||||
QTextDocument *textDocument = baseTextEditorWidget->document();
|
|
||||||
|
|
||||||
int startLine = -1;
|
|
||||||
int endLine = -1;
|
|
||||||
int column;
|
|
||||||
|
|
||||||
baseTextEditorWidget->convertPosition(offset, &startLine, &column); //get line
|
|
||||||
baseTextEditorWidget->convertPosition(offset + length, &endLine, &column); //get line
|
|
||||||
|
|
||||||
QTextDocument *doc = baseTextEditorDocument->document();
|
|
||||||
QTextCursor tc(doc);
|
|
||||||
tc.beginEditBlock();
|
|
||||||
|
|
||||||
if (startLine > 0) {
|
|
||||||
TextEditor::TabSettings tabSettings = baseTextEditorDocument->tabSettings();
|
TextEditor::TabSettings tabSettings = baseTextEditorDocument->tabSettings();
|
||||||
|
QTextCursor tc(textDocument);
|
||||||
|
|
||||||
|
tc.beginEditBlock();
|
||||||
for (int i = startLine; i <= endLine; i++) {
|
for (int i = startLine; i <= endLine; i++) {
|
||||||
QTextBlock start = textDocument->findBlockByNumber(i);
|
QTextBlock start = textDocument->findBlockByNumber(i);
|
||||||
|
|
||||||
@@ -74,10 +65,19 @@ void BaseTextEditModifier::indent(int offset, int length)
|
|||||||
indenter.indentBlock(textDocument, start, QChar::Null, tabSettings);
|
indenter.indentBlock(textDocument, start, QChar::Null, tabSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tc.endEditBlock();
|
tc.endEditBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseTextEditModifier::indent(int offset, int length)
|
||||||
|
{
|
||||||
|
if (length == 0 || offset < 0 || offset + length >= text().length())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int startLine = getLineInDocument(textDocument(), offset);
|
||||||
|
int endLine = getLineInDocument(textDocument(), offset + length);
|
||||||
|
|
||||||
|
if (startLine > -1 && endLine > -1)
|
||||||
|
indentLines(startLine, endLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
int BaseTextEditModifier::indentDepth() const
|
int BaseTextEditModifier::indentDepth() const
|
||||||
@@ -134,7 +134,6 @@ bool BaseTextEditModifier::moveToComponent(int nodeOffset)
|
|||||||
|
|
||||||
QmlJSEditor::ComponentFromObjectDef::perform(document->filePath().toString(), object);
|
QmlJSEditor::ComponentFromObjectDef::perform(document->filePath().toString(), object);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "componenttextmodifier.h"
|
#include "componenttextmodifier.h"
|
||||||
|
|
||||||
using namespace QmlDesigner;
|
using namespace QmlDesigner;
|
||||||
|
|
||||||
ComponentTextModifier::ComponentTextModifier(TextModifier *originalModifier, int componentStartOffset, int componentEndOffset, int rootStartOffset) :
|
ComponentTextModifier::ComponentTextModifier(TextModifier *originalModifier, int componentStartOffset, int componentEndOffset, int rootStartOffset) :
|
||||||
m_originalModifier(originalModifier),
|
m_originalModifier(originalModifier),
|
||||||
m_componentStartOffset(componentStartOffset),
|
m_componentStartOffset(componentStartOffset),
|
||||||
@@ -57,6 +58,11 @@ void ComponentTextModifier::indent(int offset, int length)
|
|||||||
m_originalModifier->indent(offset, length);
|
m_originalModifier->indent(offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ComponentTextModifier::indentLines(int startLine, int endLine)
|
||||||
|
{
|
||||||
|
m_originalModifier->indentLines(startLine, endLine);
|
||||||
|
}
|
||||||
|
|
||||||
int ComponentTextModifier::indentDepth() const
|
int ComponentTextModifier::indentDepth() const
|
||||||
{
|
{
|
||||||
return m_originalModifier->indentDepth();
|
return m_originalModifier->indentDepth();
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "textmodifier.h"
|
#include "textmodifier.h"
|
||||||
|
|
||||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||||
|
#include <texteditor/convenience.h>
|
||||||
|
|
||||||
using namespace QmlDesigner;
|
using namespace QmlDesigner;
|
||||||
|
|
||||||
@@ -33,6 +34,14 @@ TextModifier::~TextModifier()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TextModifier::getLineInDocument(QTextDocument *document, int offset)
|
||||||
|
{
|
||||||
|
int line = -1;
|
||||||
|
int column = -1;
|
||||||
|
TextEditor::Convenience::convertPosition(document, offset, &line, &column);
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
QmlJS::Snapshot TextModifier::qmljsSnapshot()
|
QmlJS::Snapshot TextModifier::qmljsSnapshot()
|
||||||
{
|
{
|
||||||
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
|
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
|
||||||
|
|||||||
@@ -53,13 +53,14 @@ namespace QmlDesigner {
|
|||||||
|
|
||||||
Q_LOGGING_CATEGORY(documentManagerLog, "qtc.qtquickdesigner.documentmanager")
|
Q_LOGGING_CATEGORY(documentManagerLog, "qtc.qtquickdesigner.documentmanager")
|
||||||
|
|
||||||
static inline DesignDocument* currentDesignDocument()
|
static inline QmlDesigner::DesignDocument* designDocument()
|
||||||
{
|
{
|
||||||
return QmlDesignerPlugin::instance()->documentManager().currentDesignDocument();
|
return QmlDesigner::QmlDesignerPlugin::instance()->documentManager().currentDesignDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void getProperties(const ModelNode &node, QHash<PropertyName, QVariant> &propertyHash)
|
static inline QHash<PropertyName, QVariant> getProperties(const ModelNode &node)
|
||||||
{
|
{
|
||||||
|
QHash<PropertyName, QVariant> propertyHash;
|
||||||
if (QmlObjectNode::isValidQmlObjectNode(node)) {
|
if (QmlObjectNode::isValidQmlObjectNode(node)) {
|
||||||
foreach (const AbstractProperty &abstractProperty, node.properties()) {
|
foreach (const AbstractProperty &abstractProperty, node.properties()) {
|
||||||
if (abstractProperty.isVariantProperty()
|
if (abstractProperty.isVariantProperty()
|
||||||
@@ -79,6 +80,7 @@ static inline void getProperties(const ModelNode &node, QHash<PropertyName, QVar
|
|||||||
propertyHash.remove("opacity");
|
propertyHash.remove("opacity");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return propertyHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void applyProperties(ModelNode &node, const QHash<PropertyName, QVariant> &propertyHash)
|
static inline void applyProperties(ModelNode &node, const QHash<PropertyName, QVariant> &propertyHash)
|
||||||
@@ -111,14 +113,8 @@ static inline void applyProperties(ModelNode &node, const QHash<PropertyName, QV
|
|||||||
static void openFileComponent(const ModelNode &modelNode)
|
static void openFileComponent(const ModelNode &modelNode)
|
||||||
{
|
{
|
||||||
QmlDesignerPlugin::instance()->viewManager().nextFileIsCalledInternally();
|
QmlDesignerPlugin::instance()->viewManager().nextFileIsCalledInternally();
|
||||||
|
Core::EditorManager::openEditor(modelNode.metaInfo().componentFileName(),
|
||||||
QHash<PropertyName, QVariant> propertyHash;
|
Core::Id(), Core::EditorManager::DoNotMakeVisible);
|
||||||
|
|
||||||
getProperties(modelNode, propertyHash);
|
|
||||||
Core::EditorManager::openEditor(modelNode.metaInfo().componentFileName(), Core::Id(), Core::EditorManager::DoNotMakeVisible);
|
|
||||||
|
|
||||||
ModelNode rootModelNode = currentDesignDocument()->rewriterView()->rootModelNode();
|
|
||||||
applyProperties(rootModelNode, propertyHash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void openFileComponentForDelegate(const ModelNode &modelNode)
|
static void openFileComponentForDelegate(const ModelNode &modelNode)
|
||||||
@@ -130,10 +126,6 @@ static void openComponentSourcePropertyOfLoader(const ModelNode &modelNode)
|
|||||||
{
|
{
|
||||||
QmlDesignerPlugin::instance()->viewManager().nextFileIsCalledInternally();
|
QmlDesignerPlugin::instance()->viewManager().nextFileIsCalledInternally();
|
||||||
|
|
||||||
QHash<PropertyName, QVariant> propertyHash;
|
|
||||||
|
|
||||||
getProperties(modelNode, propertyHash);
|
|
||||||
|
|
||||||
ModelNode componentModelNode;
|
ModelNode componentModelNode;
|
||||||
|
|
||||||
if (modelNode.hasNodeProperty("sourceComponent")) {
|
if (modelNode.hasNodeProperty("sourceComponent")) {
|
||||||
@@ -149,32 +141,23 @@ static void openComponentSourcePropertyOfLoader(const ModelNode &modelNode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Core::EditorManager::openEditor(componentModelNode.metaInfo().componentFileName(), Core::Id(), Core::EditorManager::DoNotMakeVisible);
|
Core::EditorManager::openEditor(componentModelNode.metaInfo().componentFileName(), Core::Id(), Core::EditorManager::DoNotMakeVisible);
|
||||||
|
|
||||||
ModelNode rootModelNode = currentDesignDocument()->rewriterView()->rootModelNode();
|
|
||||||
applyProperties(rootModelNode, propertyHash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void openSourcePropertyOfLoader(const ModelNode &modelNode)
|
static void openSourcePropertyOfLoader(const ModelNode &modelNode)
|
||||||
{
|
{
|
||||||
QmlDesignerPlugin::instance()->viewManager().nextFileIsCalledInternally();
|
QmlDesignerPlugin::instance()->viewManager().nextFileIsCalledInternally();
|
||||||
|
|
||||||
QHash<PropertyName, QVariant> propertyHash;
|
|
||||||
|
|
||||||
QString componentFileName = modelNode.variantProperty("source").value().toString();
|
QString componentFileName = modelNode.variantProperty("source").value().toString();
|
||||||
QString componentFilePath = modelNode.model()->fileUrl().resolved(QUrl::fromLocalFile(componentFileName)).toLocalFile();
|
QString componentFilePath = modelNode.model()->fileUrl().resolved(QUrl::fromLocalFile(componentFileName)).toLocalFile();
|
||||||
|
|
||||||
getProperties(modelNode, propertyHash);
|
|
||||||
Core::EditorManager::openEditor(componentFilePath, Core::Id(), Core::EditorManager::DoNotMakeVisible);
|
Core::EditorManager::openEditor(componentFilePath, Core::Id(), Core::EditorManager::DoNotMakeVisible);
|
||||||
|
|
||||||
ModelNode rootModelNode = currentDesignDocument()->rewriterView()->rootModelNode();
|
|
||||||
applyProperties(rootModelNode, propertyHash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void handleComponent(const ModelNode &modelNode)
|
static void handleComponent(const ModelNode &modelNode)
|
||||||
{
|
{
|
||||||
if (modelNode.nodeSourceType() == ModelNode::NodeWithComponentSource)
|
if (modelNode.nodeSourceType() == ModelNode::NodeWithComponentSource)
|
||||||
currentDesignDocument()->changeToSubComponent(modelNode);
|
designDocument()->changeToSubComponent(modelNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleDelegate(const ModelNode &modelNode)
|
static void handleDelegate(const ModelNode &modelNode)
|
||||||
@@ -182,36 +165,25 @@ static void handleDelegate(const ModelNode &modelNode)
|
|||||||
if (modelNode.metaInfo().isView()
|
if (modelNode.metaInfo().isView()
|
||||||
&& modelNode.hasNodeProperty("delegate")
|
&& modelNode.hasNodeProperty("delegate")
|
||||||
&& modelNode.nodeProperty("delegate").modelNode().nodeSourceType() == ModelNode::NodeWithComponentSource)
|
&& modelNode.nodeProperty("delegate").modelNode().nodeSourceType() == ModelNode::NodeWithComponentSource)
|
||||||
currentDesignDocument()->changeToSubComponent(modelNode.nodeProperty("delegate").modelNode());
|
designDocument()->changeToSubComponent(modelNode.nodeProperty("delegate").modelNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleTabComponent(const ModelNode &modelNode)
|
static void handleTabComponent(const ModelNode &modelNode)
|
||||||
{
|
{
|
||||||
if (modelNode.hasNodeProperty("component")
|
if (modelNode.hasNodeProperty("component")
|
||||||
&& modelNode.nodeProperty("component").modelNode().nodeSourceType() == ModelNode::NodeWithComponentSource) {
|
&& modelNode.nodeProperty("component").modelNode().nodeSourceType() == ModelNode::NodeWithComponentSource) {
|
||||||
currentDesignDocument()->changeToSubComponent(modelNode.nodeProperty("component").modelNode());
|
designDocument()->changeToSubComponent(modelNode.nodeProperty("component").modelNode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void openInlineComponent(const ModelNode &modelNode)
|
static inline void openInlineComponent(const ModelNode &modelNode)
|
||||||
{
|
{
|
||||||
|
if (!modelNode.metaInfo().isValid())
|
||||||
if (!modelNode.isValid() || !modelNode.metaInfo().isValid())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!currentDesignDocument())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QHash<PropertyName, QVariant> propertyHash;
|
|
||||||
|
|
||||||
getProperties(modelNode, propertyHash);
|
|
||||||
|
|
||||||
handleComponent(modelNode);
|
handleComponent(modelNode);
|
||||||
handleDelegate(modelNode);
|
handleDelegate(modelNode);
|
||||||
handleTabComponent(modelNode);
|
handleTabComponent(modelNode);
|
||||||
|
|
||||||
ModelNode rootModelNode = currentDesignDocument()->rewriterView()->rootModelNode();
|
|
||||||
applyProperties(rootModelNode, propertyHash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isFileComponent(const ModelNode &node)
|
static bool isFileComponent(const ModelNode &node)
|
||||||
@@ -249,7 +221,6 @@ static bool isLoaderWithSourceComponent(const ModelNode &modelNode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hasSourceWithFileComponent(const ModelNode &modelNode)
|
static bool hasSourceWithFileComponent(const ModelNode &modelNode)
|
||||||
@@ -295,7 +266,7 @@ DesignDocument *DocumentManager::currentDesignDocument() const
|
|||||||
|
|
||||||
bool DocumentManager::hasCurrentDesignDocument() const
|
bool DocumentManager::hasCurrentDesignDocument() const
|
||||||
{
|
{
|
||||||
return m_currentDesignDocument.data();
|
return !m_currentDesignDocument.isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentManager::removeEditors(const QList<Core::IEditor *> &editors)
|
void DocumentManager::removeEditors(const QList<Core::IEditor *> &editors)
|
||||||
@@ -306,8 +277,9 @@ void DocumentManager::removeEditors(const QList<Core::IEditor *> &editors)
|
|||||||
|
|
||||||
void DocumentManager::goIntoComponent(const ModelNode &modelNode)
|
void DocumentManager::goIntoComponent(const ModelNode &modelNode)
|
||||||
{
|
{
|
||||||
if (modelNode.isValid() && modelNode.isComponent()) {
|
if (modelNode.isValid() && modelNode.isComponent() && designDocument()) {
|
||||||
QmlDesignerPlugin::instance()->viewManager().setComponentNode(modelNode);
|
QmlDesignerPlugin::instance()->viewManager().setComponentNode(modelNode);
|
||||||
|
QHash<PropertyName, QVariant> oldProperties = getProperties(modelNode);
|
||||||
if (isFileComponent(modelNode))
|
if (isFileComponent(modelNode))
|
||||||
openFileComponent(modelNode);
|
openFileComponent(modelNode);
|
||||||
else if (hasDelegateWithFileComponent(modelNode))
|
else if (hasDelegateWithFileComponent(modelNode))
|
||||||
@@ -318,6 +290,8 @@ void DocumentManager::goIntoComponent(const ModelNode &modelNode)
|
|||||||
openComponentSourcePropertyOfLoader(modelNode);
|
openComponentSourcePropertyOfLoader(modelNode);
|
||||||
else
|
else
|
||||||
openInlineComponent(modelNode);
|
openInlineComponent(modelNode);
|
||||||
|
ModelNode rootModelNode = designDocument()->rewriterView()->rootModelNode();
|
||||||
|
applyProperties(rootModelNode, oldProperties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,14 +63,10 @@ ResourceEditorDocument::ResourceEditorDocument(QObject *parent) :
|
|||||||
setId(ResourceEditor::Constants::RESOURCEEDITOR_ID);
|
setId(ResourceEditor::Constants::RESOURCEEDITOR_ID);
|
||||||
setMimeType(QLatin1String(ResourceEditor::Constants::C_RESOURCE_MIMETYPE));
|
setMimeType(QLatin1String(ResourceEditor::Constants::C_RESOURCE_MIMETYPE));
|
||||||
connect(m_model, &RelativeResourceModel::dirtyChanged,
|
connect(m_model, &RelativeResourceModel::dirtyChanged,
|
||||||
this, &ResourceEditorDocument::setModified);
|
this, &ResourceEditorDocument::dirtyChanged);
|
||||||
connect(this, &IDocument::modificationChanged,
|
|
||||||
m_model, &RelativeResourceModel::setDirty);
|
|
||||||
connect(m_model, &ResourceModel::contentsChanged,
|
connect(m_model, &ResourceModel::contentsChanged,
|
||||||
this, &IDocument::contentsChanged);
|
this, &IDocument::contentsChanged);
|
||||||
|
|
||||||
setModified(m_model->dirty());
|
|
||||||
|
|
||||||
if (debugResourceEditorW)
|
if (debugResourceEditorW)
|
||||||
qDebug() << "ResourceEditorFile::ResourceEditorFile()";
|
qDebug() << "ResourceEditorFile::ResourceEditorFile()";
|
||||||
}
|
}
|
||||||
@@ -128,16 +124,20 @@ Core::IDocument::OpenResult ResourceEditorDocument::open(QString *errorString,
|
|||||||
if (debugResourceEditorW)
|
if (debugResourceEditorW)
|
||||||
qDebug() << "ResourceEditorW::open: " << fileName;
|
qDebug() << "ResourceEditorW::open: " << fileName;
|
||||||
|
|
||||||
|
setBlockDirtyChanged(true);
|
||||||
|
|
||||||
m_model->setFileName(realFileName);
|
m_model->setFileName(realFileName);
|
||||||
|
|
||||||
OpenResult openResult = m_model->reload();
|
OpenResult openResult = m_model->reload();
|
||||||
if (openResult != OpenResult::Success) {
|
if (openResult != OpenResult::Success) {
|
||||||
*errorString = m_model->errorMessage();
|
*errorString = m_model->errorMessage();
|
||||||
|
setBlockDirtyChanged(false);
|
||||||
emit loaded(false);
|
emit loaded(false);
|
||||||
return openResult;
|
return openResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
setFilePath(FileName::fromString(fileName));
|
setFilePath(FileName::fromString(fileName));
|
||||||
|
setBlockDirtyChanged(false);
|
||||||
m_model->setDirty(fileName != realFileName);
|
m_model->setDirty(fileName != realFileName);
|
||||||
m_shouldAutoSave = false;
|
m_shouldAutoSave = false;
|
||||||
|
|
||||||
@@ -155,10 +155,12 @@ bool ResourceEditorDocument::save(QString *errorString, const QString &name, boo
|
|||||||
if (actualName.isEmpty())
|
if (actualName.isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
m_blockDirtyChanged = true;
|
||||||
m_model->setFileName(actualName.toString());
|
m_model->setFileName(actualName.toString());
|
||||||
if (!m_model->save()) {
|
if (!m_model->save()) {
|
||||||
*errorString = m_model->errorMessage();
|
*errorString = m_model->errorMessage();
|
||||||
m_model->setFileName(oldFileName.toString());
|
m_model->setFileName(oldFileName.toString());
|
||||||
|
m_blockDirtyChanged = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,10 +168,12 @@ bool ResourceEditorDocument::save(QString *errorString, const QString &name, boo
|
|||||||
if (autoSave) {
|
if (autoSave) {
|
||||||
m_model->setFileName(oldFileName.toString());
|
m_model->setFileName(oldFileName.toString());
|
||||||
m_model->setDirty(true);
|
m_model->setDirty(true);
|
||||||
|
m_blockDirtyChanged = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
setFilePath(actualName);
|
setFilePath(actualName);
|
||||||
|
m_blockDirtyChanged = false;
|
||||||
|
|
||||||
emit changed();
|
emit changed();
|
||||||
return true;
|
return true;
|
||||||
@@ -209,6 +213,11 @@ void ResourceEditorDocument::setFilePath(const FileName &newName)
|
|||||||
IDocument::setFilePath(newName);
|
IDocument::setFilePath(newName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResourceEditorDocument::setBlockDirtyChanged(bool value)
|
||||||
|
{
|
||||||
|
m_blockDirtyChanged = value;
|
||||||
|
}
|
||||||
|
|
||||||
RelativeResourceModel *ResourceEditorDocument::model() const
|
RelativeResourceModel *ResourceEditorDocument::model() const
|
||||||
{
|
{
|
||||||
return m_model;
|
return m_model;
|
||||||
@@ -229,6 +238,11 @@ bool ResourceEditorDocument::shouldAutoSave() const
|
|||||||
return m_shouldAutoSave;
|
return m_shouldAutoSave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ResourceEditorDocument::isModified() const
|
||||||
|
{
|
||||||
|
return m_model->dirty();
|
||||||
|
}
|
||||||
|
|
||||||
bool ResourceEditorDocument::isSaveAsAllowed() const
|
bool ResourceEditorDocument::isSaveAsAllowed() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -250,6 +264,16 @@ bool ResourceEditorDocument::reload(QString *errorString, ReloadFlag flag, Chang
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResourceEditorDocument::dirtyChanged(bool dirty)
|
||||||
|
{
|
||||||
|
if (m_blockDirtyChanged)
|
||||||
|
return; // We emit changed() afterwards, unless it was an autosave
|
||||||
|
|
||||||
|
if (debugResourceEditorW)
|
||||||
|
qDebug() << " ResourceEditorW::dirtyChanged" << dirty;
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
|
||||||
void ResourceEditorW::onUndoStackChanged(bool canUndo, bool canRedo)
|
void ResourceEditorW::onUndoStackChanged(bool canUndo, bool canRedo)
|
||||||
{
|
{
|
||||||
m_plugin->onUndoStackChanged(this, canUndo, canRedo);
|
m_plugin->onUndoStackChanged(this, canUndo, canRedo);
|
||||||
|
|||||||
@@ -58,9 +58,11 @@ public:
|
|||||||
QByteArray contents() const override;
|
QByteArray contents() const override;
|
||||||
bool setContents(const QByteArray &contents) override;
|
bool setContents(const QByteArray &contents) override;
|
||||||
bool shouldAutoSave() const override;
|
bool shouldAutoSave() const override;
|
||||||
|
bool isModified() const override;
|
||||||
bool isSaveAsAllowed() const override;
|
bool isSaveAsAllowed() const override;
|
||||||
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
|
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
|
||||||
void setFilePath(const Utils::FileName &newName) override;
|
void setFilePath(const Utils::FileName &newName) override;
|
||||||
|
void setBlockDirtyChanged(bool value);
|
||||||
|
|
||||||
RelativeResourceModel *model() const;
|
RelativeResourceModel *model() const;
|
||||||
void setShouldAutoSave(bool save);
|
void setShouldAutoSave(bool save);
|
||||||
@@ -69,8 +71,10 @@ signals:
|
|||||||
void loaded(bool success);
|
void loaded(bool success);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void dirtyChanged(bool);
|
||||||
|
|
||||||
RelativeResourceModel *m_model;
|
RelativeResourceModel *m_model;
|
||||||
|
bool m_blockDirtyChanged = false;
|
||||||
bool m_shouldAutoSave = false;
|
bool m_shouldAutoSave = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
<file>images/fullnamespace.png</file>
|
<file>images/fullnamespace.png</file>
|
||||||
<file>images/history.png</file>
|
<file>images/history.png</file>
|
||||||
<file>images/icon-export-canvas.png</file>
|
<file>images/icon-export-canvas.png</file>
|
||||||
|
<file>images/icon-export-canvas@2x.png</file>
|
||||||
<file>images/icon-fit-screen.png</file>
|
<file>images/icon-fit-screen.png</file>
|
||||||
<file>images/icon-pan.png</file>
|
<file>images/icon-pan.png</file>
|
||||||
<file>images/icon-zoom-in.png</file>
|
<file>images/icon-zoom-in.png</file>
|
||||||
@@ -24,7 +25,6 @@
|
|||||||
<file>images/navigator.png</file>
|
<file>images/navigator.png</file>
|
||||||
<file>images/parallel.png</file>
|
<file>images/parallel.png</file>
|
||||||
<file>images/parallel_icon.png</file>
|
<file>images/parallel_icon.png</file>
|
||||||
<file>images/screenshot.png</file>
|
|
||||||
<file>images/state.png</file>
|
<file>images/state.png</file>
|
||||||
<file>images/state_color.png</file>
|
<file>images/state_color.png</file>
|
||||||
<file>images/statistics.png</file>
|
<file>images/statistics.png</file>
|
||||||
|
|||||||