Merge remote-tracking branch 'origin/4.2'

Change-Id: Ied7c5b01ade2a71e92541fcced2935adcf143421
This commit is contained in:
Eike Ziller
2016-10-24 13:17:22 +02:00
144 changed files with 2892 additions and 1581 deletions

142
dist/changes-4.2.0.md vendored Normal file
View 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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -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/}

View File

@@ -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
*/ */

View File

@@ -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

View File

@@ -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)

View File

@@ -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" \

View File

@@ -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);
}
highp vec3 HSLtoRGB(highp vec3 color) { for (var row = 0; row < hubeBox.height; row++){
highp float h = color.x; var gradient = ctx.createLinearGradient(0, 0, hubeBox.width,0);
highp float l = color.z; var l = Math.abs(row - hubeBox.height) / hubeBox.height
highp float s = color.y;
if (s < 1.0 / 256.0) gradient.addColorStop(0, Qt.hsla(hubeBox.hue, 0, l, 1));
return vec3(l, l, l); gradient.addColorStop(1, Qt.hsla(hubeBox.hue, 1, l, 1));
highp float v1; ctx.fillStyle = gradient;
highp float v2; ctx.fillRect(0, row, hubeBox.width, 1);
if (l < 0.5) }
v2 = l * (1.0 + s);
else
v2 = (l + s) - (s * l);
v1 = 2.0 * l - v2; ctx.restore()
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)

View File

@@ -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
} }

View File

@@ -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,7 +167,8 @@ RowLayout {
onClicked: { onClicked: {
darkPanel.opacity = 1 darkPanel.opacity = 1
fileModel.openFileDialog() fileModel.openFileDialog()
backendValue.value = fileModel.fileName if (fileModel.fileName != "")
backendValue.value = fileModel.fileName
darkPanel.opacity = 0 darkPanel.opacity = 0
} }
} }

View File

@@ -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()

View File

@@ -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,

View File

@@ -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;

View File

@@ -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_;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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();
} }

View File

@@ -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

View File

@@ -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[0] = 0;
}
} }
typeName = new char[1];
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 */
}; };

View File

@@ -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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

View File

@@ -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:

View File

@@ -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,

View File

@@ -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 \

View File

@@ -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",

View File

@@ -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>

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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:

View File

@@ -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);
} }

View File

@@ -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;

View File

@@ -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());
} }

View File

@@ -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()

View File

@@ -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 \

View File

@@ -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,181 +62,293 @@ 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 QString filePrefix = fileNamePrefix(mainFilePath, location); const ClangBackEnd::SourceLocationContainer location = diagnostic.location();
const QString lineColumn = locationToString(location);
const QString linkText = filePrefix + lineColumn;
return wrapInLink(linkText, QLatin1String(LINK_ACTION_GOTO_LOCATION));
}
QString clickableFixIt(const QString &text, bool hasFixIt)
{
if (!hasFixIt)
return text;
QString clickableText = text;
QString nonClickableCategory;
const int colonPosition = text.indexOf(QStringLiteral(": "));
if (colonPosition != -1) {
nonClickableCategory = text.mid(0, colonPosition + 2);
clickableText = text.mid(colonPosition + 2);
}
return nonClickableCategory + wrapInLink(clickableText, QLatin1String(LINK_ACTION_APPLY_FIX));
}
void openEditorAt(const ClangBackEnd::SourceLocationContainer &location)
{
Core::EditorManager::openEditorAt(location.filePath().toString(), Core::EditorManager::openEditorAt(location.filePath().toString(),
int(location.line()), int(location.line()),
int(location.column() - 1)); int(location.column() - 1));
} }
void applyFixit(const QVector<ClangBackEnd::FixItContainer> &fixits) void applyFixit(const ClangBackEnd::DiagnosticContainer &diagnostic)
{ {
ClangCodeModel::ClangFixItOperation operation(Utf8String(), fixits); ClangCodeModel::ClangFixItOperation operation(Utf8String(), diagnostic.fixIts());
operation.perform(); operation.perform();
} }
template <typename LayoutType> class WidgetFromDiagnostics
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: public:
MainDiagnosticWidget(const ClangBackEnd::DiagnosticContainer &diagnostic, struct DisplayHints {
const ClangCodeModel::Internal::DisplayHints &displayHints) bool showCategoryAndEnableOption;
bool showFileNameInMainDiagnostic;
bool enableClickableFixits;
bool limitWidth;
bool hideTooltipAfterLinkActivation;
};
static QWidget *create(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
const DisplayHints &displayHints)
{ {
setContentsMargins(0, 0, 0, 0); WidgetFromDiagnostics converter(displayHints);
auto *mainLayout = createLayout<QVBoxLayout>(); return converter.createWidget(diagnostics);
}
const ClangBackEnd::SourceLocationContainer location = diagnostic.location(); private:
enum class IndentMode { Indent, DoNotIndent };
// Set up header row: category + responsible option WidgetFromDiagnostics(const DisplayHints &displayHints)
if (displayHints.showMainDiagnosticHeader) { : m_displayHints(displayHints)
const QString category = diagnostic.category(); {
const QString responsibleOption = diagnostic.enableOption(); }
auto *headerLayout = createLayout<QHBoxLayout>(); QWidget *createWidget(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics)
headerLayout->addWidget(new QLabel(wrapInBoldTags(category)), 1); {
const QString text = htmlText(diagnostics);
auto *responsibleOptionLabel = new QLabel(wrapInColor(responsibleOption, "gray")); auto *label = new QLabel;
headerLayout->addWidget(responsibleOptionLabel, 0); label->setTextFormat(Qt::RichText);
mainLayout->addLayout(headerLayout); 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);
} }
// Set up main row: diagnostic text const TargetIdToDiagnosticTable table = m_targetIdsToDiagnostics;
const Utf8String mainFilePath = displayHints.showFileNameInMainDiagnostic 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() ? Utf8String()
: location.filePath(); : diagnostic.location().filePath();
mainLayout->addWidget(createDiagnosticLabel(diagnostic,
mainFilePath,
DoNotIndentDiagnostic,
displayHints.enableClickableFixits));
setLayout(mainLayout); 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 lineColumn = locationToString(location);
const QString linkText = filePrefix + lineColumn;
const QString targetId = generateTargetId(LINK_ACTION_GOTO_LOCATION, diagnostic);
return wrapInLink(linkText, targetId);
}
QString clickableFixIt(const ClangBackEnd::DiagnosticContainer &diagnostic,
const QString &text,
bool hasFixIt)
{
if (!hasFixIt)
return text;
QString clickableText = text;
QString nonClickableCategory;
const int colonPosition = text.indexOf(QStringLiteral(": "));
if (colonPosition != -1) {
nonClickableCategory = text.mid(0, colonPosition + 2);
clickableText = text.mid(colonPosition + 2);
}
const QString targetId = generateTargetId(LINK_ACTION_APPLY_FIX, diagnostic);
return nonClickableCategory + wrapInLink(clickableText, targetId);
}
QString generateTargetId(const QString &targetPrefix,
const ClangBackEnd::DiagnosticContainer &diagnostic)
{
const QString idAsString = QString::number(++m_targetIdCounter);
const QString targetId = targetPrefix + idAsString;
m_targetIdsToDiagnostics.insert(targetId, diagnostic);
return targetId;
}
static QString wrapInLink(const QString &text, const QString &target)
{
return QStringLiteral("<a href='%1' style='text-decoration:none'>%2</a>").arg(target, text);
}
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"

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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();

View File

@@ -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();

View File

@@ -197,17 +197,19 @@ 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);
m_sessionManager.setActiveTarget(project, target, ProjectExplorer::SetActive::NoCascade);
const bool waitResult = waitUntilProjectUpdated.wait(30000); if (target != project->activeTarget()) {
if (!waitResult) { QSignalSpy waitUntilProjectUpdated(CppModelManager::instance(),
qWarning() << "waitUntilProjectUpdated() failed"; &CppModelManager::projectPartsUpdated);
return false; m_sessionManager.setActiveTarget(project, target, ProjectExplorer::SetActive::NoCascade);
const bool waitResult = waitUntilProjectUpdated.wait(30000);
if (!waitResult) {
qWarning() << "waitUntilProjectUpdated() failed";
return false;
}
} }
return true; return true;

View File

@@ -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);

View 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;

View File

@@ -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;

View File

@@ -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 \

View File

@@ -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",

View File

@@ -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);

View File

@@ -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

View 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

View File

@@ -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,7 +1085,8 @@ 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(),
ICore::dialogParent()); ExtensionSystem::PluginManager::getObject<DiffService>(),
ICore::dialogParent());
switch (previousReloadAnswer) { switch (previousReloadAnswer) {
case ReloadAll: case ReloadAll:
case ReloadCurrent: case ReloadCurrent:
@@ -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')));

View File

@@ -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))

View File

@@ -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);

View File

@@ -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

View File

@@ -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();

View File

@@ -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;
} }

View File

@@ -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 &macroName, languageFeatureMacros()) foreach (const QString &macroName, 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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;

View File

@@ -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();
} }

View File

@@ -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();
} }

View File

@@ -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;
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; return true;
}
if (type == TypePermissions) { if (type == TypePermissions) {
emit changed(); emit changed();
} else { } else {

View File

@@ -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

View File

@@ -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());

View File

@@ -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;
}; };

View File

@@ -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,9 +104,10 @@ 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()
? fileData.rightFileInfo.fileName ? overriddenFileName : revert
: fileData.leftFileInfo.fileName; ? fileData.rightFileInfo.fileName
: fileData.leftFileInfo.fileName;
QString leftPrefix, rightPrefix; QString leftPrefix, rightPrefix;
if (addPrefix) { if (addPrefix) {

View File

@@ -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());

View File

@@ -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();
} }

View File

@@ -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

View File

@@ -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();
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, revert); if (patchBehaviour == DiffFileInfo::PatchFile) {
const int strip = m_document->baseDirectory().isEmpty() ? -1 : 0;
if (patch.isEmpty()) const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, revert);
return;
const QString absFileName = QFileInfo(workingDirectory + '/' + fileName).absoluteFilePath(); if (patch.isEmpty())
FileChangeBlocker fileChangeBlocker(absFileName); return;
if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch),
workingDirectory, strip, revert)) FileChangeBlocker fileChangeBlocker(absFileName);
m_document->reload(); if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch),
workingDirectory, strip, revert))
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,

View File

@@ -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 {

View File

@@ -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;
} }
} }

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -263,8 +263,10 @@ 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 {
data.insert(QLatin1String(CPP_COMPILERNAME), cCompilerName); if (!cCompilerName.isEmpty())
data.insert(QLatin1String(CPP_CXXCOMPILERNAME), cxxCompilerName); data.insert(QLatin1String(CPP_COMPILERNAME), cCompilerName);
if (!cxxCompilerName.isEmpty())
data.insert(QLatin1String(CPP_CXXCOMPILERNAME), cxxCompilerName);
} }
if (tcC && tcCxx && cFileInfo.absolutePath() != cxxFileInfo.absolutePath()) { if (tcC && tcCxx && cFileInfo.absolutePath() != cxxFileInfo.absolutePath()) {

View File

@@ -710,10 +710,12 @@ void QbsProductNode::setQbsProductData(const qbs::Project &project, const qbs::P
} }
} }
const QStringList generatedFiles if (prd.isEnabled()) {
= Utils::transform(prd.generatedArtifacts(), &qbs::ArtifactData::filePath); const QStringList generatedFiles
QbsGroupNode::setupFiles(m_generatedFilesNode, qbs::GroupData(), generatedFiles, = Utils::transform(prd.generatedArtifacts(), &qbs::ArtifactData::filePath);
prd.buildDirectory(), true, true); QbsGroupNode::setupFiles(m_generatedFilesNode, qbs::GroupData(), generatedFiles,
prd.buildDirectory(), true, true);
}
addProjectNodes(toAdd); addProjectNodes(toAdd);
removeProjectNodes(toRemove); removeProjectNodes(toRemove);

View File

@@ -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()));

View File

@@ -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)

View File

@@ -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);
} }

View File

@@ -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");

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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; }
}; };

View File

@@ -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;

View File

@@ -43,41 +43,41 @@ BaseTextEditModifier::BaseTextEditModifier(TextEditor::TextEditorWidget *textEdi
{ {
} }
void BaseTextEditModifier::indentLines(int startLine, int endLine)
{
if (startLine < 0)
return;
TextEditor::TextEditorWidget *baseTextEditorWidget = qobject_cast<TextEditor::TextEditorWidget*>(plainTextEdit());
if (!baseTextEditorWidget)
return;
QTextDocument *textDocument = plainTextEdit()->document();
TextEditor::TextDocument *baseTextEditorDocument = baseTextEditorWidget->textDocument();
TextEditor::TabSettings tabSettings = baseTextEditorDocument->tabSettings();
QTextCursor tc(textDocument);
tc.beginEditBlock();
for (int i = startLine; i <= endLine; i++) {
QTextBlock start = textDocument->findBlockByNumber(i);
if (start.isValid()) {
QmlJSEditor::Internal::Indenter indenter;
indenter.indentBlock(textDocument, start, QChar::Null, tabSettings);
}
}
tc.endEditBlock();
}
void BaseTextEditModifier::indent(int offset, int length) void BaseTextEditModifier::indent(int offset, int length)
{ {
if (length == 0 || offset < 0 || offset + length >= text().length()) if (length == 0 || offset < 0 || offset + length >= text().length())
return; return;
if (TextEditor::TextEditorWidget *baseTextEditorWidget = qobject_cast<TextEditor::TextEditorWidget*>(plainTextEdit())) { int startLine = getLineInDocument(textDocument(), offset);
int endLine = getLineInDocument(textDocument(), offset + length);
TextEditor::TextDocument *baseTextEditorDocument = baseTextEditorWidget->textDocument(); if (startLine > -1 && endLine > -1)
QTextDocument *textDocument = baseTextEditorWidget->document(); indentLines(startLine, endLine);
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();
for (int i = startLine; i <= endLine; i++) {
QTextBlock start = textDocument->findBlockByNumber(i);
if (start.isValid()) {
QmlJSEditor::Internal::Indenter indenter;
indenter.indentBlock(textDocument, start, QChar::Null, tabSettings);
}
}
}
tc.endEditBlock();
}
} }
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;

View File

@@ -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();

View File

@@ -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();

View File

@@ -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);
} }
} }

View File

@@ -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);

View File

@@ -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;
}; };

View File

@@ -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>

Some files were not shown because too many files have changed in this diff Show More