Merge remote-tracking branch 'origin/3.4'

Conflicts:
	src/plugins/coreplugin/coreplugin.cpp

Change-Id: I9aa6c61412e2ef4a91efe028296bcc2d075856d7
This commit is contained in:
Eike Ziller
2015-03-11 10:35:49 +01:00
118 changed files with 2364 additions and 2597 deletions
+55 -53
View File
@@ -1,9 +1,9 @@
Qt Creator
==========
# Qt Creator
Qt Creator is a cross-platform IDE for development with the Qt framework.
Supported Platforms
===================
## Supported Platforms
The standalone binary packages support the following platforms:
Windows XP SP3 or later
@@ -12,16 +12,17 @@ Mac OS X 10.7 or later
Building the sources requires Qt 5.3.1 or later.
Compiling Qt Creator
====================
## Compiling Qt Creator
Prerequisites:
* Qt 5.3.1 or later
* On Windows:
- ActiveState Active Perl
- MinGW with g++ 4.5 or Visual Studio 2010 or later
- jom
* On Mac OS X: latest Xcode
* On Linux: g++ 4.5 or later
* Qt 5.3.1 or later
* On Windows:
* ActiveState Active Perl
* MinGW with g++ 4.5 or Visual Studio 2010 or later
* jom
* On Mac OS X: latest Xcode
* On Linux: g++ 4.5 or later
The installed toolchains have to match the one Qt was compiled with.
@@ -35,72 +36,70 @@ Installation ("make install") is not needed. It is however possible, using
make install INSTALL_ROOT=$INSTALL_DIRECTORY
Compiling Qt and Qt Creator on Windows
--------------------------------------
## Compiling Qt and Qt Creator on Windows
This section provides step by step instructions for compiling the latest
versions of Qt and Qt Creator on Windows. Alternatively, to avoid having to
compile Qt yourself, you can use one of the versions of Qt shipped with the Qt
SDK (release builds of Qt using MinGW and Visual C++ 2010 or later).
For detailed information on the supported compilers, see
http://wiki.qt.io/Building_Qt_5_from_Git .
<https://wiki.qt.io/Building_Qt_5_from_Git> .
1. Decide which compiler to use: MinGW or Microsoft Visual Studio. If you
plan to contribute to Qt Creator, you should compile your changes with
both compilers.
2. Install msysGit from https://msysgit.github.io/. If you plan to
2. Install msysGit from <https://msysgit.github.io/>. If you plan to
use the MinGW compiler suite, do not choose to put git in the
default path of Windows command prompts. For more information, see
step 9.
3. Create a working directory under which to check out Qt and Qt Creator,
for example, c:\work. If you plan to use MinGW and Microsoft Visual
for example, `c:\work`. If you plan to use MinGW and Microsoft Visual
Studio simultaneously or mix different Qt versions, we recommend
creating a directory structure which reflects that. For example:
C:\work\qt5.2.1-vs10, C:\work\qt5.2.1-mingw.
`C:\work\qt5.2.1-vs10, C:\work\qt5.2.1-mingw`.
4. Download and install Perl from http://www.activestate.com/activeperl
and check that perl.exe is added to the path. Run perl -v to verify
4. Download and install Perl from <https://www.activestate.com/activeperl>
and check that perl.exe is added to the path. Run `perl -v` to verify
that the version displayed is 5.10 or later. Note that git ships
an outdated version 5.8 which cannot be used for Qt.
5. In the working directory, check out the respective branch of Qt
(we recommend the latest released version from the release branch,
5.2.1; see https://qt.gitorious.org/qt).
5. In the working directory, check out the respective branch of Qt from
<https://code.qt.io/cgit/qt/qt5.git> (we recommend the latest released version).
6. Check out Qt Creator (master branch or latest version, see
https://qt.gitorious.org/qt-creator).
<https://code.qt.io/cgit/qt-creator/qt-creator.git>).
You should now have the directories qt and creator under your working
directory.
7. Install a compiler:
- For a MinGW toolchain for Qt, see http://wiki.qt.io/MinGW .
- For a MinGW toolchain for Qt, see <https://wiki.qt.io/MinGW> .
- For Microsoft Visual C++, install the Windows SDK and the "Debugging
Tools for Windows" from the SDK image. We strongly recommend using the
64-bit version and 64-bit compilers on 64-bit systems.
When using Visual C++ 2010, you must apply a hotfix that is available
from http://support.microsoft.com/kb/2280741
(See https://bugreports.qt.io/browse/QTBUG-11445).
from `https://support.microsoft.com/kb/2280741`
(see [QTBUG-11445](https://bugreports.qt.io/browse/QTBUG-11445)).
For the Visual C++ compilers, it is recommended to use the tool 'jom'.
It is a replacement for nmake that utilizes all CPU cores and thus
speeds up compilation significantly. Download it from
http://download.qt-project.org/official_releases/jom
<https://download.qt.io/official_releases/jom>
and add the executable to the path.
8. For convenience, we recommend creating shell prompts with the correct
environment. This can be done by creating a .bat-file
(such as, <working_directory>\qtvars.bat) that contains the environment
(such as, `<working_directory>\qtvars.bat`) that contains the environment
variable settings.
A .bat-file for MinGW looks like:
A `.bat`-file for MinGW looks like:
set PATH=<path_to_qt>\[qtbase\]bin;<path_to_mingw>\bin;<working_directory>\creator\bin;%PATH%
set QMAKESPEC=win32-g++
For the Visual C++ compilers, call the .bat file that sets up the
For the Visual C++ compilers, call the `.bat` file that sets up the
environment for the compiler (provided by the Windows SDK or the
compiler):
@@ -108,21 +107,21 @@ http://wiki.qt.io/Building_Qt_5_from_Git .
set PATH=<path_to_qt>\[qtbase\]bin;<working_directory>\creator\bin;%PATH%
set QMAKESPEC=win32-msvc2010
You can create desktop links to the bat files using the working
You can create desktop links to the `.bat` files using the working
directory and specifying
%SystemRoot%\system32\cmd.exe /E:ON /V:ON /k <working_directory>\qtvars.bat
%SystemRoot%\system32\cmd.exe /E:ON /V:ON /k <working_directory>\qtvars.bat
9. When using MinGW, open the shell prompt and enter:
sh.exe
sh.exe
That should result in a 'sh is not recognized as internal or external
command...' error. If a sh.exe is found, the compile process will fail.
That should result in a `sh is not recognized as internal or external
command...` error. If a `sh.exe` is found, the compile process will fail.
You have to remove it from the path.
10. You are now ready to configure and build Qt and Qt Creator.
Please see http://wiki.qt.io/Building_Qt_5_from_Git for
Please see <https://wiki.qt.io/Building_Qt_5_from_Git> for
recommended configure-options for Qt 5.
To use MinGW, open the the shell prompt and enter:
@@ -142,35 +141,38 @@ http://wiki.qt.io/Building_Qt_5_from_Git .
qtcreator
12. When using Visual C++ with the "Debugging Tools for Windows" installed,
the extension library qtcreatorcdbext.dll to be loaded into the
Windows console debugger (cdb.exe) should have been built under
lib\qtcreatorcdbext32 or lib\qtcreatorcdbext64.
the extension library `qtcreatorcdbext.dll` to be loaded into the
Windows console debugger (`cdb.exe`) should have been built under
`lib\qtcreatorcdbext32` or `lib\qtcreatorcdbext64`.
When using a 32 bit-build of Qt Creator with the 64 bit version of the
"Debugging Tools for Windows" the library should also be built with
a 64 bit compiler (rebuild src\libs\qtcreatorcdbext using a 64 bit
a 64 bit compiler (rebuild `src\libs\qtcreatorcdbext` using a 64 bit
compiler).
If you are building 32 bit and running on a 64 bit
Windows, you can obtain the 64 bit versions of the extension library
and the binary win64interrupt.exe, which is required for
and the binary `win64interrupt.exe`, which is required for
debugging from the repository
https://qt.gitorious.org/qt-creator/binary-artifacts/source/ .
<https://code.qt.io/cgit/qt-creator/binary-artifacts.git/tree> .
13. Qt Creator can be registered as a post-mortem debugger. This
can be done in the options page or by running the tool qtcdebugger
with administrative privileges passing the command line options
-register/unregister, respectively. Alternatively,
the required registry entries
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug and
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug
can be modified using the registry editor regedt32 to contain
<path>\qt-creator\bin\qtcdebugger %ld %ld
<path>\qt-creator\bin\qtcdebugger %ld %ld
When using a self-built version of Qt Creator as post-mortem debugger, it needs to be
able to find all dependent Qt-libraries and plugins when being launched by the
system. The easiest way to provide them for Qt 5 is to run the tool windeployqt:
windeployqt -qmldir share\qtcreator -qmldir src\plugins\qmlprofiler bin\qtcreator.exe lib\qtcreator lib\qtcreator\plugins
windeployqt -qmldir share\qtcreator -qmldir src\plugins\qmlprofiler bin\qtcreator.exe lib\qtcreator lib\qtcreator\plugins
Note that unlike on Unix, you cannot overwrite executables that are running.
Thus, if you want to work on Qt Creator using Qt Creator, you need a
@@ -178,12 +180,12 @@ separate build of it. We recommend using a separate, release-built version
of Qt and Qt Creator to work on a debug-built version of Qt and Qt Creator
or using shadow builds.
Third-party Components
======================
## Third-party Components
Qt Creator includes the following third-party components,
we thank the authors who made this possible:
* Open Source front-end for C++ (license MIT), enhanced for use in Qt Creator
### Open Source front-end for C++ (license MIT), enhanced for use in Qt Creator
Roberto Raggi <roberto.raggi@gmail.com>
@@ -208,7 +210,7 @@ we thank the authors who made this possible:
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* Botan, a C++ crypto library. Version 1.10.2
### Botan, a C++ crypto library. Version 1.10.2
Botan (http://botan.randombit.net/) is distributed under these terms::
@@ -257,7 +259,7 @@ we thank the authors who made this possible:
QtCreator/src/libs/3rdparty
* ClassView and ImageViewer plugins
### ClassView and ImageViewer plugins
Copyright (C) 2015 The Qt Company Ltd.
+7 -1
View File
@@ -4,7 +4,7 @@ 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://gitorious.org/qt-creator/qt-creator.git
git clone git://code.qt.io/qt-creator/qt-creator.git
git log --cherry-pick --pretty=oneline origin/3.3..origin/3.4
General
@@ -97,6 +97,12 @@ Windows
OS X
Linux
* Added support to retrieve application output from journald.
Journald support needs to be explicitly enabled by passing CONFIG+=journald to
qmake when configuring Qt Creator.
Android
* Added support for 64bit tool chains
* Fixed that active run configuration setting was ignored for deploying application
+1 -1
View File
@@ -36,7 +36,7 @@ checkunzip:
${source}/python.zip: | makesourcedir checkwget
cd ${source} && \
echo "Downloading python..." && \
wget -q http://download.qt-project.org/development_releases/prebuilt/gdb/build-prerequisites/python.zip && \
wget -q http://download.qt.io/development_releases/prebuilt/gdb/build-prerequisites/python.zip && \
touch python.zip
${broot}/python/python.exe: ${source}/python.zip | checkunzip
+3 -3
View File
@@ -35,7 +35,7 @@
Prebuilt \QC packages usually use the latest stable release of Qt.
You can see the exact minimum requirement at the top of \QC's qtcreator.pro.
(You can find the current version in our source repository here:
\l{http://qt.gitorious.org/qt-creator/qt-creator/blobs/master/qtcreator.pro}.)
\l{https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/qtcreator.pro#n4}.)
You can get prebuilt Qt packages from \l{https://download.qt.io}{Qt Downloads}.
If you want to use Qt as provided by your Linux distribution, you need to make sure that all
@@ -44,8 +44,8 @@
\section1 Getting and Building \QC
You can get the \QC sources for a specific version either by using one of the
released source bundles, or from the Gitorious repository
\l{http://qt.gitorious.org/qt-creator}. If you intend to contribute to \QC
released source bundles, or from the Git repository
\l{https://code.qt.io/cgit/qt-creator/qt-creator.git}. If you intend to contribute to \QC
itself, you should use the repository from our Gerrit review tool as described
in: \l{https://wiki.qt.io/Setting_up_Gerrit}{Setting up Gerrit}.
+1 -1
View File
@@ -101,7 +101,7 @@ macx {
deployqt.depends = install
win32 {
deployartifacts.depends = install
deployartifacts.commands = git clone "git://gitorious.org/qt-creator/binary-artifacts.git" -b $$BINARY_ARTIFACTS_BRANCH&& xcopy /s /q /y /i "binary-artifacts\\win32" \"$(INSTALL_ROOT)$$QTC_PREFIX\"&& rmdir /s /q binary-artifacts
deployartifacts.commands = git clone "git://code.qt.io/qt-creator/binary-artifacts.git" -b $$BINARY_ARTIFACTS_BRANCH&& xcopy /s /q /y /i "binary-artifacts\\win32" \"$(INSTALL_ROOT)$$QTC_PREFIX\"&& rmdir /s /q binary-artifacts
QMAKE_EXTRA_TARGETS += deployartifacts
}
}
+99 -83
View File
@@ -906,48 +906,41 @@ class DumperBase:
self.putFields(value)
def putCStyleArray(self, value):
type = value.type.unqualified()
arrayType = value.type.unqualified()
innerType = value[0].type
ts = innerType.sizeof
#self.putAddress(value.address)
self.putType(type)
self.putType(arrayType)
self.putNumChild(1)
format = self.currentItemFormat()
isDefault1 = format == None and str(innerType.unqualified()) == "char"
isDefault2 = format == None and str(innerType.unqualified()) == "wchar_t"
if isDefault1 or isDefault2 or format == 0 or format == 1 or format == 2:
blob = self.readMemory(self.addressOf(value), type.sizeof)
if isDefault1:
# Use Latin1 as default for char [].
self.putValue(blob, Hex2EncodedLatin1)
elif isDefault2:
if type.sizeof == 2:
self.putValue(blob, Hex4EncodedLittleEndian)
else:
self.putValue(blob, Hex8EncodedLittleEndian)
elif format == 0:
# Explicitly requested Latin1 formatting.
self.putValue(blob, Hex2EncodedLatin1)
elif format == 1:
# Explicitly requested UTF-8 formatting.
self.putValue(blob, Hex2EncodedUtf8)
elif format == 2:
# Explicitly requested Local 8-bit formatting.
self.putValue(blob, Hex2EncodedLocal8Bit)
else:
try:
self.putValue("@0x%x" % self.pointerValue(value.cast(innerType.pointer())))
except:
self.putEmptyValue()
try:
p = self.addressOf(value)
except:
p = None
itemFormat = self.currentItemFormat()
n = int(arrayType.sizeof / ts)
if p and self.tryPutSimpleFormattedPointer(p, str(arrayType), itemFormat, arrayType.sizeof):
self.putNumChild(n)
pass
elif itemFormat is None:
innerTypeName = str(innerType.unqualified())
blob = self.readMemory(self.addressOf(value), arrayType.sizeof)
if innerTypeName == "char":
# Use Latin1 as default for char [].
self.putValue(blob, Hex2EncodedLatin1)
elif innerTypeName == "wchar_t":
if innerType.sizeof == 2:
self.putValue(blob, Hex4EncodedLittleEndian)
else:
self.putValue(blob, Hex8EncodedLittleEndian)
if self.currentIName in self.expandedINames:
try:
# May fail on artificial items like xmm register data.
p = self.addressOf(value)
ts = innerType.sizeof
if not self.tryPutArrayContents(p, int(type.sizeof / ts), innerType):
with Children(self, childType=innerType,
addrBase=p, addrStep=ts):
if not self.tryPutArrayContents(p, n, innerType):
with Children(self, childType=innerType, addrBase=p, addrStep=ts):
self.putFields(value)
except:
with Children(self, childType=innerType):
@@ -1004,6 +997,74 @@ class DumperBase:
else:
self.put('editvalue="%s|%s",' % (cmd, value))
# This is shared by pointer and array formatting.
def tryPutSimpleFormattedPointer(self, value, typeName, itemFormat, limit):
if itemFormat == None and typeName == "char":
# Use Latin1 as default for char *.
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 1, limit)
self.putValue(data, Hex2EncodedLatin1, elided=elided)
self.putDisplay(StopDisplay)
return True
if itemFormat == Latin1StringFormat:
# Explicitly requested Latin1 formatting.
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 1, limit)
self.putValue(data, Hex2EncodedLatin1, elided=elided)
self.putDisplay(StopDisplay)
return True
if itemFormat == SeparateLatin1StringFormat:
# Explicitly requested Latin1 formatting in separate window.
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 1, limit)
self.putValue(data, Hex2EncodedLatin1, elided=elided)
self.putDisplay(DisplayLatin1String, data)
return True
if itemFormat == Utf8StringFormat:
# Explicitly requested UTF-8 formatting.
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 1, limit)
self.putValue(data, Hex2EncodedUtf8, elided=elided)
self.putDisplay(StopDisplay)
return True
if itemFormat == SeparateUtf8StringFormat:
# Explicitly requested UTF-8 formatting in separate window.
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 1, limit)
self.putValue(data, Hex2EncodedUtf8, elided=elided)
self.putDisplay(DisplayUtf8String, data)
return True
if itemFormat == Local8BitStringFormat:
# Explicitly requested local 8 bit formatting.
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 1, limit)
self.putValue(data, Hex2EncodedLocal8Bit, elided=elided)
self.putDisplay(StopDisplay)
return True
if itemFormat == Utf16StringFormat:
# Explicitly requested UTF-16 formatting.
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 2, limit)
self.putValue(data, Hex4EncodedLittleEndian, elided=elided)
self.putDisplay(StopDisplay)
return True
if itemFormat == Ucs4StringFormat:
# Explicitly requested UCS-4 formatting.
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 4, limit)
self.putValue(data, Hex8EncodedLittleEndian, elided=elided)
self.putDisplay(StopDisplay)
return True
return False
def putFormattedPointer(self, value):
#warn("POINTER: %s" % value)
if self.isNull(value):
@@ -1037,14 +1098,6 @@ class DumperBase:
self.putNumChild(0)
return
if format == None and innerTypeName == "char":
# Use Latin1 as default for char *.
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 1, self.displayStringLimit)
self.putValue(data, Hex2EncodedLatin1, elided=elided)
self.putNumChild(0)
return
if format == 0:
# Explicitly requested bald pointer.
self.putType(typeName)
@@ -1056,47 +1109,10 @@ class DumperBase:
self.putItem(value.dereference())
return
if format == Latin1StringFormat or format == SeparateLatin1StringFormat:
# Explicitly requested Latin1 formatting.
limit = self.displayStringLimit if format == Latin1StringFormat else 1000000
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 1, limit)
self.putValue(data, Hex2EncodedLatin1, elided=elided)
self.putNumChild(0)
self.putDisplay((StopDisplay if format == Latin1StringFormat else DisplayLatin1String), data)
return
if format == Utf8StringFormat or format == SeparateUtf8StringFormat:
# Explicitly requested UTF-8 formatting.
limit = self.displayStringLimit if format == Utf8StringFormat else 1000000
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 1, limit)
self.putValue(data, Hex2EncodedUtf8, elided=elided)
self.putNumChild(0)
self.putDisplay((StopDisplay if format == Utf8StringFormat else DisplayUtf8String), data)
return
if format == Local8BitStringFormat:
# Explicitly requested local 8 bit formatting.
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 1, self.displayStringLimit)
self.putValue(data, Hex2EncodedLocal8Bit, elided=elided)
self.putNumChild(0)
return
if format == Utf16StringFormat:
# Explicitly requested UTF-16 formatting.
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 2, self.displayStringLimit)
self.putValue(data, Hex4EncodedLittleEndian, elided=elided)
self.putNumChild(0)
return
if format == Ucs4StringFormat:
# Explicitly requested UCS-4 formatting.
self.putType(typeName)
(elided, data) = self.encodeCArray(value, 4, self.displayStringLimit)
self.putValue(data, Hex8EncodedLittleEndian, elided=elided)
limit = self.displayStringLimit
if format == DisplayLatin1String or format == DisplayUtf8String:
limit = 1000000
if self.tryPutSimpleFormattedPointer(value, typeName, format, limit):
self.putNumChild(0)
return
+1 -1
View File
@@ -1721,7 +1721,7 @@ class Tester(Dumper):
self.expandedINames = set(expandedINames)
self.passExceptions = True
self.loadDumperFiles()
self.loadDumperFiles({})
error = lldb.SBError()
self.target = self.debugger.CreateTarget(binary, None, None, True, error)
@@ -369,7 +369,7 @@ void NodeInstanceServer::removeSharedMemory(const RemoveSharedMemoryCommand &/*c
{
}
void NodeInstanceServer::setupImports(const QVector<AddImportContainer> &containerVector, const QVector<IdContainer> &idContainerVector)
void NodeInstanceServer::setupImports(const QVector<AddImportContainer> &containerVector)
{
Q_ASSERT(quickView());
QSet<QString> importStatementSet;
@@ -420,11 +420,8 @@ void NodeInstanceServer::setupImports(const QVector<AddImportContainer> &contain
workingImportStatementList.prepend(firstWorkingImportStatement);
}
QVector<qint32> instanceIds;
foreach (const IdContainer &idContainer, idContainerVector)
instanceIds.append(idContainer.instanceId());
if (!errorMessage.isEmpty())
sendDebugOutput(DebugOutputCommand::WarningType, errorMessage, instanceIds);
sendDebugOutput(DebugOutputCommand::WarningType, errorMessage);
setupOnlyWorkingImports(workingImportStatementList);
}
@@ -438,6 +435,15 @@ void NodeInstanceServer::setupOnlyWorkingImports(const QStringList &workingImpor
m_importComponent->setData(componentCode.append("\nItem {}\n"), fileUrl());
m_importComponentObject = m_importComponent->create();
if (!m_importComponentObject) {
delete m_importComponent;
m_importComponent = new QQmlComponent(engine(), quickView());
m_importComponent->setData("import QtQuick 2.0\n\nItem {}\n", fileUrl());
sendDebugOutput(DebugOutputCommand::WarningType, tr("No working QtQuick import"));
m_importComponentObject = m_importComponent->create();
}
Q_ASSERT(m_importComponent && m_importComponentObject);
Q_ASSERT_X(m_importComponent->errors().isEmpty(), __FUNCTION__, m_importComponent->errorString().toLatin1());
}
@@ -128,7 +128,7 @@ public:
virtual QQmlView *declarativeView() const = 0;
virtual QQuickView *quickView() const = 0;
void sendDebugOutput(DebugOutputCommand::Type type, const QString &message, qint32 instanceId);
void sendDebugOutput(DebugOutputCommand::Type type, const QString &message, qint32 instanceId = 0);
void sendDebugOutput(DebugOutputCommand::Type type, const QString &message, const QVector<qint32> &instanceIds);
void removeInstanceRelationsipForDeletedObject(QObject *object);
@@ -195,7 +195,7 @@ protected:
void setupDummysForContext(QQmlContext *context);
void setupFileUrl(const QUrl &fileUrl);
void setupImports(const QVector<AddImportContainer> &container, const QVector<IdContainer> &idContainerVector);
void setupImports(const QVector<AddImportContainer> &container);
void setupDummyData(const QUrl &fileUrl);
void setupDefaultDummyData();
QList<ServerNodeInstance> setupInstances(const CreateSceneCommand &command);
@@ -91,7 +91,7 @@ void Qt5NodeInstanceServer::resetAllItems()
void Qt5NodeInstanceServer::setupScene(const CreateSceneCommand &command)
{
setupFileUrl(command.fileUrl());
setupImports(command.imports(), command.ids());
setupImports(command.imports());
setupDummyData(command.fileUrl());
setupInstances(command);
+1 -1
View File
@@ -47,7 +47,7 @@ FancyTabWidgetEnabledUnselectedTextColor=text
FancyToolButtonHoverColor=hoverBackground
FancyToolButtonSelectedColor=selectedBackground
FutureProgressBackgroundColor=shadowBackground
InfoBarBackground=shadowBackground
InfoBarBackground=ff505000
InfoBarText=text
MenuBarEmptyAreaBackgroundColor=shadowBackground
MenuBarItemBackgroundColor=shadowBackground
+2 -2
View File
@@ -3,7 +3,7 @@ How To add translations to Qt Creator
- Coordinate over the mailing list to avoid duplicate work.
- Read the instructions at http://wiki.qt-project.org/Qt_Localization
- Read the instructions at http://wiki.qt.io/Qt_Localization
- Add your language to the LANGUAGES line in translations.pro.
Don't qualify it with a country unless it is reasonable to expect
@@ -29,7 +29,7 @@ How To add translations to Qt Creator
- Run "make commit-ts" to create a commit with a cleaned .ts file
- If needed, amend the commit with the modified .pro file
- Follow http://wiki.qt-project.org/Qt_Contribution_Guidelines to post the
- Follow http://wiki.qt.io/Qt_Contribution_Guidelines to post the
change for review.
- .qm files are generated as part of the regular build.
@@ -180,12 +180,12 @@ ColumnLayout {
IconAndLink {
iconSource: "images/icons/onlineCommunity.png"
title: qsTr("Online Community")
openUrl: "http://qt-project.org/forums"
openUrl: "http://forum.qt.io"
}
IconAndLink {
iconSource: "images/icons/blogs.png"
title: qsTr("Blogs")
openUrl: "http://planet.qt-project.org"
openUrl: "http://planet.qt.io"
}
IconAndLink {
iconSource: "images/icons/userGuide.png"
+3 -1
View File
@@ -63,7 +63,9 @@ public:
virtual void extensionsInitialized() = 0;
virtual bool delayedInitialize() { return false; }
virtual ShutdownFlag aboutToShutdown() { return SynchronousShutdown; }
virtual QObject *remoteCommand(const QStringList & /* options */, const QStringList & /* arguments */) { return 0; }
virtual QObject *remoteCommand(const QStringList & /* options */,
const QString & /* workingDirectory */,
const QStringList & /* arguments */) { return 0; }
virtual QList<QObject *> createTestObjects() const;
PluginSpec *pluginSpec() const;
+10 -11
View File
@@ -505,6 +505,7 @@ QHash<QString, PluginCollection *> PluginManager::pluginCollections()
}
static const char argumentKeywordC[] = ":arguments";
static const char pwdKeywordC[] = ":pwd";
/*!
Serializes plugin options and arguments for sending in a single string
@@ -528,20 +529,15 @@ QString PluginManager::serializedArguments()
rc += ps->arguments().join(separator);
}
}
if (!rc.isEmpty())
rc += separator;
rc += QLatin1String(pwdKeywordC) + separator + QDir::currentPath();
if (!d->arguments.isEmpty()) {
if (!rc.isEmpty())
rc += separator;
rc += QLatin1String(argumentKeywordC);
// If the argument appears to be a file, make it absolute
// when sending to another instance.
foreach (const QString &argument, d->arguments) {
rc += separator;
const QFileInfo fi(argument);
if (fi.exists() && fi.isRelative())
rc += fi.absoluteFilePath();
else
rc += argument;
}
foreach (const QString &argument, d->arguments)
rc += separator + argument;
}
return rc;
}
@@ -577,11 +573,14 @@ void PluginManager::remoteArguments(const QString &serializedArgument, QObject *
if (serializedArgument.isEmpty())
return;
QStringList serializedArguments = serializedArgument.split(QLatin1Char('|'));
const QStringList pwdValue = subList(serializedArguments, QLatin1String(pwdKeywordC));
const QString workingDirectory = pwdValue.isEmpty() ? QString() : pwdValue.first();
const QStringList arguments = subList(serializedArguments, QLatin1String(argumentKeywordC));
foreach (const PluginSpec *ps, plugins()) {
if (ps->state() == PluginSpec::Running) {
const QStringList pluginOptions = subList(serializedArguments, QLatin1Char(':') + ps->name());
QObject *socketParent = ps->plugin()->remoteCommand(pluginOptions, arguments);
QObject *socketParent = ps->plugin()->remoteCommand(pluginOptions, workingDirectory,
arguments);
if (socketParent && socket) {
socket->setParent(socketParent);
socket = 0;
@@ -279,7 +279,7 @@ extern "C" HRESULT CALLBACK pid(CIDebugClient *client, PCSTR args)
int token;
commandTokens<StringList>(args, &token);
dprintf("Qt Creator CDB extension version 3.3 %d bit.\n",
dprintf("Qt Creator CDB extension version 3.4 %d bit.\n",
sizeof(void *) * 8);
if (const ULONG pid = currentProcessId(client))
ExtensionContext::instance().report('R', token, 0, "pid", "%u", pid);
+6 -2
View File
@@ -190,9 +190,13 @@ MimeType MimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileName
// Disambiguate conflicting extensions (if magic matching found something)
if (candidateByData.isValid() && magicAccuracy > 0) {
// "for glob_match in glob_matches:"
// "if glob_match is subclass or equal to sniffed_type, use glob_match"
const QString sniffedMime = candidateByData.name();
// If the sniffedMime matches a glob match, use it
if (candidatesByName.contains(sniffedMime)) {
*accuracyPtr = 100;
return candidateByData;
}
// If there is a glob match that is a sub class of sniffedMime, use it
foreach (const QString &m, candidatesByName) {
if (inherits(m, sniffedMime)) {
// We have magic + pattern pointing to this, so it's a pretty good match
+3 -1
View File
@@ -188,8 +188,10 @@ static bool createMagicMatchRule(const QXmlStreamAttributes &atts,
MimeMagicRule *tempRule = new MimeMagicRule(magicType, value.toUtf8(), startPos, endPos,
mask.toLatin1(), errorMessage);
if (!tempRule->isValid())
if (!tempRule->isValid()) {
delete tempRule;
return false;
}
rule = tempRule;
return true;
+1
View File
@@ -1436,6 +1436,7 @@ bool QtcProcess::ArgIterator::next()
state.current = MxParen;
m_simple = false;
hadWord = true;
continue;
#if 0 // Should match only at the beginning of a command, which we never have currently.
} else if (cc == '{') {
sstack.push(state);
@@ -636,8 +636,8 @@ void AndroidSettingsWidget::showGdbWarningDialog()
tr("Unsupported GDB"),
tr("The GDB inside this NDK seems to not support Python. "
"The Qt Project offers fixed GDB builds at: "
"<a href=\"http://download.qt-project.org/official_releases/gdb/\">"
"http://download.qt-project.org/official_releases/gdb/</a>"));
"<a href=\"http://download.qt.io/official_releases/gdb/\">"
"http://download.qt.io/official_releases/gdb/</a>"));
}
void AndroidSettingsWidget::manageAVD()
@@ -182,7 +182,6 @@ BuildInfo *AutotoolsBuildConfigurationFactory::createBuildInfo(const Kit *k,
info->typeName = tr("Build");
info->buildDirectory = buildDir;
info->kitId = k->id();
info->supportsShadowBuild = true; // Works sometimes...
return info;
}
+2 -2
View File
@@ -46,8 +46,8 @@ BazaarEditorWidget::BazaarEditorWidget() :
m_changesetId(QLatin1String(Constants::CHANGESET_ID)),
m_exactChangesetId(QLatin1String(Constants::CHANGESET_ID_EXACT))
{
setAnnotateRevisionTextFormat(tr("Annotate %1"));
setAnnotatePreviousRevisionTextFormat(tr("Annotate parent revision %1"));
setAnnotateRevisionTextFormat(tr("&Annotate %1"));
setAnnotatePreviousRevisionTextFormat(tr("Annotate &parent revision %1"));
// Diff format:
// === <change> <file|dir> 'mainwindow.cpp'
setDiffFilePattern(QRegExp(QLatin1String("^=== [a-z]+ [a-z]+ '(.+)'\\s*")));
@@ -278,6 +278,14 @@ public:
QMessageBox::critical(ICore::mainWindow(), tr("File Error"), msg);
return false;
}
if (size > INT_MAX) {
QString msg = tr("The file is too big for the Binary Editor (max. 2GB).");
if (errorString)
*errorString = msg;
else
QMessageBox::critical(ICore::mainWindow(), tr("File Error"), msg);
return false;
}
if (offset >= size)
return false;
setFilePath(FileName::fromString(fileName));
@@ -279,7 +279,6 @@ CMakeBuildInfo *CMakeBuildConfigurationFactory::createBuildInfo(const ProjectExp
k->addToEnvironment(info->environment);
info->useNinja = false;
info->sourceDirectory = sourceDir;
info->supportsShadowBuild = true;
return info;
}
+6 -3
View File
@@ -226,17 +226,20 @@ bool CorePlugin::delayedInitialize()
return true;
}
QObject *CorePlugin::remoteCommand(const QStringList & /* options */, const QStringList &args)
QObject *CorePlugin::remoteCommand(const QStringList & /* options */,
const QString &workingDirectory,
const QStringList &args)
{
IDocument *res = m_mainWindow->openFiles(
args, ICore::OpenFilesFlags(ICore::SwitchMode | ICore::CanContainLineAndColumnNumbers));
args, ICore::OpenFilesFlags(ICore::SwitchMode | ICore::CanContainLineAndColumnNumbers),
workingDirectory);
m_mainWindow->raiseWindow();
return res;
}
void CorePlugin::fileOpenRequest(const QString &f)
{
remoteCommand(QStringList(), QStringList(f));
remoteCommand(QStringList(), QString(), QStringList(f));
}
ExtensionSystem::IPlugin::ShutdownFlag CorePlugin::aboutToShutdown()
+3 -1
View File
@@ -59,7 +59,9 @@ public:
void extensionsInitialized();
bool delayedInitialize();
ShutdownFlag aboutToShutdown();
QObject *remoteCommand(const QStringList & /* options */, const QStringList &args);
QObject *remoteCommand(const QStringList & /* options */,
const QString &workingDirectory,
const QStringList &args);
public slots:
void fileOpenRequest(const QString&);
@@ -113,6 +113,17 @@ private:
QHash<QString, DocumentModel::Entry *> m_entryByFixedPath;
};
class RestoredDocument : public IDocument
{
public:
bool save(QString *, const QString &, bool) { return false; }
QString defaultPath() const { return filePath().toFileInfo().absolutePath(); }
QString suggestedFileName() const { return filePath().fileName(); }
bool isModified() const { return false; }
bool isSaveAsAllowed() const { return false; }
bool reload(QString *, ReloadFlag, ChangeType) { return true; }
};
DocumentModelPrivate::DocumentModelPrivate() :
m_lockedIcon(QLatin1String(":/core/images/locked.png")),
m_unlockedIcon(QLatin1String(":/core/images/unlocked.png"))
@@ -127,10 +138,17 @@ DocumentModelPrivate::~DocumentModelPrivate()
static DocumentModelPrivate *d;
DocumentModel::Entry::Entry() :
document(0)
document(0),
isRestored(false)
{
}
DocumentModel::Entry::~Entry()
{
if (isRestored)
delete document;
}
DocumentModel::DocumentModel()
{
}
@@ -162,22 +180,22 @@ QAbstractItemModel *DocumentModel::model()
Utils::FileName DocumentModel::Entry::fileName() const
{
return document ? document->filePath() : m_fileName;
return document->filePath();
}
QString DocumentModel::Entry::displayName() const
{
return document ? document->displayName() : m_displayName;
return document->displayName();
}
QString DocumentModel::Entry::plainDisplayName() const
{
return document ? document->plainDisplayName() : m_displayName;
return document->plainDisplayName();
}
Id DocumentModel::Entry::id() const
{
return document ? document->id() : m_id;
return document->id();
}
int DocumentModelPrivate::columnCount(const QModelIndex &parent) const
@@ -214,15 +232,17 @@ void DocumentModel::addEditor(IEditor *editor, bool *isNewDocument)
void DocumentModel::addRestoredDocument(const QString &fileName, const QString &displayName, Id id)
{
Entry *entry = new Entry;
entry->m_fileName = Utils::FileName::fromString(fileName);
entry->m_displayName = displayName;
entry->m_id = id;
entry->document = new RestoredDocument;
entry->document->setFilePath(Utils::FileName::fromString(fileName));
entry->document->setPreferredDisplayName(displayName);
entry->document->setId(id);
entry->isRestored = true;
d->addEntry(entry);
}
DocumentModel::Entry *DocumentModel::firstRestoredEntry()
{
return Utils::findOrDefault(d->m_entries, [](Entry *entry) { return !entry->document; });
return Utils::findOrDefault(d->m_entries, [](Entry *entry) { return entry->isRestored; });
}
void DocumentModelPrivate::addEntry(DocumentModel::Entry *entry)
@@ -236,7 +256,7 @@ void DocumentModelPrivate::addEntry(DocumentModel::Entry *entry)
int previousIndex = indexOfFilePath(fileName);
if (previousIndex >= 0) {
DocumentModel::Entry *previousEntry = m_entries.at(previousIndex);
const bool replace = entry->document && !previousEntry->document;
const bool replace = !entry->isRestored && previousEntry->isRestored;
if (replace) {
delete previousEntry;
m_entries[previousIndex] = entry;
@@ -268,8 +288,7 @@ void DocumentModelPrivate::addEntry(DocumentModel::Entry *entry)
disambiguateDisplayNames(entry);
if (!fixedPath.isEmpty())
m_entryByFixedPath[fixedPath] = entry;
if (entry->document)
connect(entry->document, SIGNAL(changed()), this, SLOT(itemChanged()));
connect(entry->document, SIGNAL(changed()), this, SLOT(itemChanged()));
endInsertRows();
}
@@ -282,8 +301,6 @@ bool DocumentModelPrivate::disambiguateDisplayNames(DocumentModel::Entry *entry)
for (int i = 0, total = m_entries.count(); i < total; ++i) {
DocumentModel::Entry *e = m_entries.at(i);
if (!e->document)
continue;
if (e == entry || e->plainDisplayName() == displayName) {
e->document->setUniqueDisplayName(QString());
dups += DynamicEntry(e);
@@ -349,7 +366,8 @@ int DocumentModelPrivate::indexOfFilePath(const Utils::FileName &filePath) const
void DocumentModel::removeEntry(DocumentModel::Entry *entry)
{
QTC_ASSERT(!entry->document, return); // we wouldn't know what to do with the associated editors
// For non restored entries, we wouldn't know what to do with the associated editors
QTC_ASSERT(entry->isRestored, return);
int index = d->m_entries.indexOf(entry);
d->removeDocument(index);
}
@@ -373,7 +391,8 @@ void DocumentModel::removeEditor(IEditor *editor, bool *lastOneForDocument)
void DocumentModel::removeDocument(const QString &fileName)
{
int index = d->indexOfFilePath(Utils::FileName::fromString(fileName));
QTC_ASSERT(!d->m_entries.at(index)->document, return); // we wouldn't know what to do with the associated editors
// For non restored entries, we wouldn't know what to do with the associated editors
QTC_ASSERT(d->m_entries.at(index)->isRestored, return);
d->removeDocument(index);
}
@@ -393,8 +412,7 @@ void DocumentModelPrivate::removeDocument(int idx)
DocumentManager::ResolveLinks);
m_entryByFixedPath.remove(fixedPath);
}
if (IDocument *document = entry->document)
disconnect(document, SIGNAL(changed()), this, SLOT(itemChanged()));
disconnect(entry->document, SIGNAL(changed()), this, SLOT(itemChanged()));
disambiguateDisplayNames(entry);
delete entry;
}
@@ -402,7 +420,7 @@ void DocumentModelPrivate::removeDocument(int idx)
void DocumentModel::removeAllRestoredEntries()
{
for (int i = d->m_entries.count()-1; i >= 0; --i) {
if (!d->m_entries.at(i)->document) {
if (d->m_entries.at(i)->isRestored) {
int row = i + 1/*<no document>*/;
d->beginRemoveRows(QModelIndex(), row, row);
delete d->m_entries.takeAt(i);
@@ -527,19 +545,12 @@ QVariant DocumentModelPrivate::data(const QModelIndex &index, int role) const
switch (role) {
case Qt::DisplayRole: {
QString name = e->displayName();
if (e->document && e->document->isModified())
if (e->document->isModified())
name += QLatin1Char('*');
return name;
}
case Qt::DecorationRole:
{
bool showLock = false;
if (e->document)
showLock = e->document->filePath().isEmpty() ? false : e->document->isFileReadOnly();
else
showLock = !e->m_fileName.toFileInfo().isWritable();
return showLock ? m_lockedIcon : QIcon();
}
return e->document->isFileReadOnly() ? m_lockedIcon : QIcon();
case Qt::ToolTipRole:
return e->fileName().isEmpty() ? e->displayName() : e->fileName().toUserOutput();
default:
@@ -59,15 +59,15 @@ public:
struct CORE_EXPORT Entry {
Entry();
IDocument *document;
~Entry();
Utils::FileName fileName() const;
QString displayName() const;
QString plainDisplayName() const;
QString uniqueDisplayName() const;
Id id() const;
Utils::FileName m_fileName;
QString m_displayName;
Id m_id;
IDocument *document;
bool isRestored;
};
static Entry *entryAtRow(int row);
@@ -1067,7 +1067,7 @@ void EditorManagerPrivate::activateEditorForEntry(EditorView *view, DocumentMode
return;
}
IDocument *document = entry->document;
if (document) {
if (!entry->isRestored) {
activateEditorForDocument(view, document, flags);
return;
}
@@ -2048,10 +2048,10 @@ void EditorManager::closeDocument(DocumentModel::Entry *entry)
{
if (!entry)
return;
if (entry->document)
closeDocuments(QList<IDocument *>() << entry->document);
else
if (entry->isRestored)
DocumentModel::removeEntry(entry);
else
closeDocuments(QList<IDocument *>() << entry->document);
}
bool EditorManager::closeEditors(const QList<IEditor*> &editorsToClose, bool askAboutModifiedEditors)
@@ -2537,15 +2537,15 @@ QByteArray EditorManager::saveState()
int entriesCount = 0;
foreach (DocumentModel::Entry *entry, entries) {
// The editor may be 0 if it was not loaded yet: In that case it is not temporary
if (!entry->document || !entry->document->isTemporary())
if (!entry->document->isTemporary())
++entriesCount;
}
stream << entriesCount;
foreach (DocumentModel::Entry *entry, entries) {
if (!entry->document || !entry->document->isTemporary())
stream << entry->fileName().toString() << entry->displayName() << entry->id();
if (!entry->document->isTemporary())
stream << entry->fileName().toString() << entry->plainDisplayName() << entry->id();
}
stream << d->m_editorAreas.first()->saveState(); // TODO
@@ -249,7 +249,7 @@ void OpenEditorsWindow::addHistoryItems(const QList<EditLocation> &history, Edit
void OpenEditorsWindow::addRestoredItems()
{
foreach (DocumentModel::Entry *entry, DocumentModel::entries()) {
if (entry->document)
if (!entry->isRestored)
continue;
QTreeWidgetItem *item = new QTreeWidgetItem();
QString title = entry->displayName();
@@ -73,13 +73,13 @@ QList<LocatorFilterEntry> OpenDocumentsFilter::matchesFor(QFutureInterface<Locat
if (!regexp.isValid())
return goodEntries;
const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry);
foreach (const DocumentModel::Entry &editorEntry, editors()) {
foreach (const Entry &editorEntry, editors()) {
if (future.isCanceled())
break;
QString fileName = editorEntry.fileName().toString();
QString fileName = editorEntry.fileName.toString();
if (fileName.isEmpty())
continue;
QString displayName = editorEntry.displayName();
QString displayName = editorEntry.displayName;
if (regexp.exactMatch(displayName)) {
LocatorFilterEntry fiEntry(this, displayName, QString(fileName + lineNoSuffix));
fiEntry.extraInfo = FileUtils::shortNativePath(FileName::fromString(fileName));
@@ -98,16 +98,16 @@ void OpenDocumentsFilter::refreshInternally()
QMutexLocker lock(&m_mutex); Q_UNUSED(lock)
m_editors.clear();
foreach (DocumentModel::Entry *e, DocumentModel::entries()) {
DocumentModel::Entry entry;
Entry entry;
// create copy with only the information relevant to use
// to avoid model deleting entries behind our back
entry.m_displayName = e->displayName();
entry.m_fileName = e->fileName();
entry.displayName = e->displayName();
entry.fileName = e->fileName();
m_editors.append(entry);
}
}
QList<DocumentModel::Entry> OpenDocumentsFilter::editors() const
QList<OpenDocumentsFilter::Entry> OpenDocumentsFilter::editors() const
{
QMutexLocker lock(&m_mutex); Q_UNUSED(lock)
return m_editors;
@@ -57,10 +57,17 @@ public slots:
void refreshInternally();
private:
QList<DocumentModel::Entry> editors() const;
class Entry
{
public:
Utils::FileName fileName;
QString displayName;
};
QList<Entry> editors() const;
mutable QMutex m_mutex;
QList<DocumentModel::Entry> m_editors;
QList<Entry> m_editors;
};
} // namespace Internal
+8 -2
View File
@@ -761,18 +761,24 @@ static IDocumentFactory *findDocumentFactory(const QList<IDocumentFactory*> &fil
* \a flags can be used to stop on first failure, indicate that a file name
* might include line numbers and/or switch mode to edit mode.
*
* \a workingDirectory is used when files are opened by a remote client, since
* the file names are relative to the client working directory.
*
* \returns the first opened document. Required to support the -block flag
* for client mode.
*
* \sa IPlugin::remoteArguments()
*/
IDocument *MainWindow::openFiles(const QStringList &fileNames, ICore::OpenFilesFlags flags)
IDocument *MainWindow::openFiles(const QStringList &fileNames,
ICore::OpenFilesFlags flags,
const QString &workingDirectory)
{
QList<IDocumentFactory*> documentFactories = PluginManager::getObjects<IDocumentFactory>();
IDocument *res = 0;
foreach (const QString &fileName, fileNames) {
const QFileInfo fi(fileName);
const QDir workingDir(workingDirectory.isEmpty() ? QDir::currentPath() : workingDirectory);
const QFileInfo fi(workingDir, fileName);
const QString absoluteFilePath = fi.absoluteFilePath();
if (IDocumentFactory *documentFactory = findDocumentFactory(documentFactories, fi)) {
IDocument *document = documentFactory->open(absoluteFilePath);
+3 -1
View File
@@ -94,7 +94,9 @@ public:
void addContextObject(IContext *context);
void removeContextObject(IContext *context);
IDocument *openFiles(const QStringList &fileNames, ICore::OpenFilesFlags flags);
IDocument *openFiles(const QStringList &fileNames,
ICore::OpenFilesFlags flags,
const QString &workingDirectory = QString());
inline SettingsDatabase *settingsDatabase() const { return m_settingsDatabase; }
virtual QPrinter *printer() const;
@@ -4537,6 +4537,18 @@ void CppEditorPlugin::test_quickfix_ConvertQt4Connect_connectWithinClass_data()
QTest::newRow("three-args-connect")
<< QByteArray("conne@ct(this, SIGNAL(sigFoo(int)), SLOT(setProp(int)));")
<< QByteArray("connect(this, &TestClass::sigFoo, this, &TestClass::setProp);");
QTest::newRow("template-value")
<< QByteArray("Pointer<TestClass> p;\n"
"conne@ct(p.t, SIGNAL(sigFoo(int)), p.t, SLOT(setProp(int)));")
<< QByteArray("Pointer<TestClass> p;\n"
"connect(p.t, &TestClass::sigFoo, p.t, &TestClass::setProp);");
QTest::newRow("implicit-pointer")
<< QByteArray("Pointer<TestClass> p;\n"
"conne@ct(p, SIGNAL(sigFoo(int)), p, SLOT(setProp(int)));")
<< QByteArray("Pointer<TestClass> p;\n"
"connect(p.data(), &TestClass::sigFoo, p.data(), &TestClass::setProp);");
}
void CppEditorPlugin::test_quickfix_ConvertQt4Connect_connectWithinClass()
@@ -4545,6 +4557,13 @@ void CppEditorPlugin::test_quickfix_ConvertQt4Connect_connectWithinClass()
QFETCH(QByteArray, expected);
QByteArray prefix =
"template<class T>\n"
"struct Pointer\n"
"{\n"
" T *t;\n"
" operator T*() const { return t; }\n"
" T *data() const { return t; }\n"
"};\n"
"class QObject {};\n"
"class TestClass : public QObject\n"
"{\n"
+82 -5
View File
@@ -5578,10 +5578,75 @@ Symbol *skipForwardDeclarations(const QList<Symbol *> &symbols)
return 0;
}
bool findRawAccessFunction(Class *klass, PointerType *pointerType, QString *objAccessFunction)
{
QList<Function *> candidates;
for (auto it = klass->memberBegin(), end = klass->memberEnd(); it != end; ++it) {
if (Function *func = (*it)->asFunction()) {
const Name *funcName = func->name();
if (!funcName->isOperatorNameId()
&& !funcName->isConversionNameId()
&& func->returnType().type() == pointerType
&& func->isConst()
&& func->argumentCount() == 0) {
candidates << func;
}
}
}
const Name *funcName = 0;
switch (candidates.size()) {
case 0:
return false;
case 1:
funcName = candidates.first()->name();
break;
default:
// Multiple candidates - prefer a function named data
foreach (Function *func, candidates) {
if (!strcmp(func->name()->identifier()->chars(), "data")) {
funcName = func->name();
break;
}
}
if (!funcName)
funcName = candidates.first()->name();
}
const Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview();
*objAccessFunction = QLatin1Char('.') + oo.prettyName(funcName) + QLatin1String("()");
return true;
}
PointerType *determineConvertedType(NamedType *namedType, const LookupContext &context,
Scope *scope, QString *objAccessFunction)
{
if (!namedType)
return 0;
if (ClassOrNamespace *binding = context.lookupType(namedType->name(), scope)) {
if (Symbol *objectClassSymbol = skipForwardDeclarations(binding->symbols())) {
if (Class *klass = objectClassSymbol->asClass()) {
for (auto it = klass->memberBegin(), end = klass->memberEnd(); it != end; ++it) {
if (Function *func = (*it)->asFunction()) {
if (const ConversionNameId *conversionName =
func->name()->asConversionNameId()) {
if (PointerType *type = conversionName->type()->asPointerType()) {
if (findRawAccessFunction(klass, type, objAccessFunction))
return type;
}
}
}
}
}
}
}
return 0;
}
Class *senderOrReceiverClass(const CppQuickFixInterface &interface,
const CppRefactoringFilePtr &file,
const ExpressionAST *objectPointerAST,
Scope *objectPointerScope)
Scope *objectPointerScope,
QString *objAccessFunction)
{
const LookupContext &context = interface.context();
@@ -5592,6 +5657,7 @@ Class *senderOrReceiverClass(const CppQuickFixInterface &interface,
objectPointerExpression = "this";
TypeOfExpression toe;
toe.setExpandTemplates(true);
toe.init(interface.semanticInfo().doc, interface.snapshot(), context.bindings());
const QList<LookupItem> objectPointerExpressions = toe(objectPointerExpression,
objectPointerScope, TypeOfExpression::Preprocess);
@@ -5601,6 +5667,10 @@ Class *senderOrReceiverClass(const CppQuickFixInterface &interface,
QTC_ASSERT(objectPointerTypeBase, return 0);
PointerType *objectPointerType = objectPointerTypeBase->asPointerType();
if (!objectPointerType) {
objectPointerType = determineConvertedType(objectPointerTypeBase->asNamedType(), context,
objectPointerScope, objAccessFunction);
}
QTC_ASSERT(objectPointerType, return 0);
Type *objectTypeBase = objectPointerType->elementType().type(); // Dereference
@@ -5623,7 +5693,8 @@ bool findConnectReplacement(const CppQuickFixInterface &interface,
const ExpressionAST *objectPointerAST,
const QtMethodAST *methodAST,
const CppRefactoringFilePtr &file,
QString *replacement)
QString *replacement,
QString *objAccessFunction)
{
// Get name of method
if (!methodAST->declarator || !methodAST->declarator->core_declarator)
@@ -5639,7 +5710,8 @@ bool findConnectReplacement(const CppQuickFixInterface &interface,
// Lookup object pointer type
Scope *scope = file->scopeAt(methodAST->firstToken());
Class *objectClass = senderOrReceiverClass(interface, file, objectPointerAST, scope);
Class *objectClass = senderOrReceiverClass(interface, file, objectPointerAST, scope,
objAccessFunction);
QTC_ASSERT(objectClass, return false);
// Look up member function in call, including base class members.
@@ -5761,17 +5833,22 @@ void ConvertQt4Connect::match(const CppQuickFixInterface &interface, QuickFixOpe
const CppRefactoringFilePtr file = interface.currentFile();
QString newSignal;
if (!findConnectReplacement(interface, arg1, arg2, file, &newSignal))
QString senderAccessFunc;
if (!findConnectReplacement(interface, arg1, arg2, file, &newSignal, &senderAccessFunc))
continue;
QString newMethod;
if (!findConnectReplacement(interface, arg3, arg4, file, &newMethod))
QString receiverAccessFunc;
if (!findConnectReplacement(interface, arg3, arg4, file, &newMethod, &receiverAccessFunc))
continue;
ChangeSet changes;
changes.replace(file->endOf(arg1), file->endOf(arg1), senderAccessFunc);
changes.replace(file->startOf(arg2), file->endOf(arg2), newSignal);
if (!arg3)
newMethod.prepend(QLatin1String("this, "));
else
changes.replace(file->endOf(arg3), file->endOf(arg3), receiverAccessFunc);
changes.replace(file->startOf(arg4), file->endOf(arg4), newMethod);
result.append(new ConvertQt4ConnectOperation(interface, changes));
+152 -145
View File
@@ -85,9 +85,7 @@ enum { debugSourceMapping = 0 };
enum { debugWatches = 0 };
enum { debugBreakpoints = 0 };
enum { LocalsUpdateForNewFrame = 0x1 };
#define CB(callback) [this](const CdbCommandPtr &r) { callback(r); }
#define CB(callback) [this](const CdbResponse &r) { callback(r); }
#if 0
# define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line);
@@ -126,7 +124,7 @@ enum { LocalsUpdateForNewFrame = 0x1 };
\list
\li postCommand(): Does not expect a reply
\li postCommand(): Does not expect a response
\li postBuiltinCommand(): Run a builtin-command producing free-format, multiline output
that is captured by enclosing it in special tokens using the 'echo' command and
then invokes a callback with a CdbBuiltinCommand structure.
@@ -180,19 +178,11 @@ struct MemoryChangeCookie
QByteArray data;
};
struct ConditionalBreakPointCookie
{
ConditionalBreakPointCookie(BreakpointModelId i = BreakpointModelId()) : id(i) {}
BreakpointModelId id;
GdbMi stopReason;
};
} // namespace Internal
} // namespace Debugger
Q_DECLARE_METATYPE(Debugger::Internal::MemoryViewCookie)
Q_DECLARE_METATYPE(Debugger::Internal::MemoryChangeCookie)
Q_DECLARE_METATYPE(Debugger::Internal::ConditionalBreakPointCookie)
namespace Debugger {
namespace Internal {
@@ -203,37 +193,52 @@ static inline bool isCreatorConsole(const DebuggerStartParameters &sp)
&& (sp.startMode == StartInternal || sp.startMode == StartExternal);
}
// Base data structure for command queue entries with callback
struct CdbCommand
class CdbResponse
{
CdbCommand()
: token(0), flags(0), commandSequence(0), isBuiltin(true), success(false)
{}
CdbCommand(bool builtin, const QByteArray &cmd, int token, unsigned flags,
CdbEngine::CommandHandler h, unsigned nc)
: token(token), flags(flags), command(cmd), commandSequence(nc),
isBuiltin(builtin), handler(h), success(false)
public:
CdbResponse()
: commandSequence(0), success(false)
{}
QByteArray joinedReply() const;
int token;
unsigned flags;
QByteArray command;
// Continue with other commands as specified in CommandSequenceFlags
unsigned commandSequence;
bool isBuiltin;
CdbEngine::CommandHandler handler;
QList<QByteArray> builtinReply;
QByteArray extensionReply;
QByteArray errorMessage;
bool success;
};
QByteArray CdbCommand::joinedReply() const
// Base data structure for command queue entries with callback
class CdbCommand
{
public:
CdbCommand()
: token(0), flags(0), isBuiltin(true)
{}
CdbCommand(bool builtin, const QByteArray &cmd, int token, unsigned flags,
CdbEngine::CommandHandler h, unsigned nc)
: token(token), flags(flags), isBuiltin(builtin), handler(h)
{
response.command = cmd;
response.commandSequence = nc;
}
int token;
unsigned flags;
bool isBuiltin;
CdbEngine::CommandHandler handler;
CdbResponse response; // FIXME: remove.
};
QByteArray CdbResponse::joinedReply() const
{
if (builtinReply.isEmpty())
return QByteArray();
@@ -536,9 +541,9 @@ void CdbEngine::createFullBacktrace()
postBuiltinCommand("~*kp", 0, CB(handleCreateFullBackTrace));
}
void CdbEngine::handleCreateFullBackTrace(const CdbEngine::CdbCommandPtr &cmd)
void CdbEngine::handleCreateFullBackTrace(const CdbResponse &response)
{
Internal::openTextEditor(QLatin1String("Backtrace $"), QLatin1String(cmd->joinedReply()));
Internal::openTextEditor(QLatin1String("Backtrace $"), QLatin1String(response.joinedReply()));
}
void CdbEngine::setupEngine()
@@ -609,7 +614,7 @@ bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessa
if (!extensionFi.isFile()) {
*errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found.\n"
"If you build Qt Creator from sources, check out "
"https://qt.gitorious.org/qt-creator/binary-artifacts/").
"https://code.qt.io/cgit/qt-creator/binary-artifacts.git/.").
arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
return false;
}
@@ -990,7 +995,7 @@ void CdbEngine::updateWatchData(const WatchData &dataIn)
if (!dataIn.name.isEmpty() && dataIn.name != QLatin1String(dataIn.exp))
m_watchInameToName.insert(dataIn.iname, dataIn.name);
postExtensionCommand("addwatch", args, 0,
[this, dataIn](const CdbCommandPtr &r) { handleAddWatch(r, dataIn); });
[this, dataIn](const CdbResponse &r) { handleAddWatch(r, dataIn); });
return;
}
@@ -1003,18 +1008,18 @@ void CdbEngine::updateWatchData(const WatchData &dataIn)
updateLocalVariable(dataIn.iname);
}
void CdbEngine::handleAddWatch(const CdbCommandPtr &reply, WatchData item)
void CdbEngine::handleAddWatch(const CdbResponse &response, WatchData item)
{
if (debugWatches)
qDebug() << "handleAddWatch ok=" << reply->success << item.iname;
if (reply->success) {
qDebug() << "handleAddWatch ok=" << response.success << item.iname;
if (response.success) {
updateLocalVariable(item.iname);
} else {
item.setError(tr("Unable to add expression"));
watchHandler()->insertData(item);
showMessage(QString::fromLatin1("Unable to add watch item \"%1\"/\"%2\": %3").
arg(QString::fromLatin1(item.iname), QString::fromLatin1(item.exp),
QString::fromLocal8Bit(reply->errorMessage)), LogError);
QString::fromLocal8Bit(response.errorMessage)), LogError);
}
}
@@ -1050,7 +1055,7 @@ void CdbEngine::updateLocalVariable(const QByteArray &iname)
}
str << blankSeparator << iname;
postExtensionCommand(isWatch ? "watches" : "locals", localsArguments, 0,
[this](const CdbCommandPtr &r) { handleLocals(r, 0); });
[this](const CdbResponse &r) { handleLocals(r, false); });
}
bool CdbEngine::hasCapability(unsigned cap) const
@@ -1221,7 +1226,7 @@ void CdbEngine::executeJumpToLine(const ContextData &data)
QByteArray cmd;
ByteArrayInputStream str(cmd);
str << "? `" << QDir::toNativeSeparators(data.fileName) << ':' << data.lineNumber << '`';
postBuiltinCommand(cmd, 0, [this, data](const CdbCommandPtr &r) { handleJumpToLineAddressResolution(r, data); });
postBuiltinCommand(cmd, 0, [this, data](const CdbResponse &r) { handleJumpToLineAddressResolution(r, data); });
}
}
@@ -1238,13 +1243,13 @@ void CdbEngine::jumpToAddress(quint64 address)
postCommand(registerCmd, 0);
}
void CdbEngine::handleJumpToLineAddressResolution(const CdbCommandPtr &cmd, const ContextData &context)
void CdbEngine::handleJumpToLineAddressResolution(const CdbResponse &response, const ContextData &context)
{
if (cmd->builtinReply.isEmpty())
if (response.builtinReply.isEmpty())
return;
// Evaluate expression: 5365511549 = 00000001`3fcf357d
// Set register 'rip' to hex address and goto lcoation
QByteArray answer = cmd->builtinReply.front().trimmed();
QByteArray answer = response.builtinReply.front().trimmed();
const int equalPos = answer.indexOf(" = ");
if (equalPos == -1)
return;
@@ -1303,21 +1308,21 @@ void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, c
postCommand(cmd, 0);
// Update all locals in case we change a union or something pointed to
// that affects other variables, too.
updateLocals();
updateLocals(false);
}
void CdbEngine::handleThreads(const CdbCommandPtr &reply)
void CdbEngine::handleThreads(const CdbResponse &response)
{
if (debug)
qDebug("CdbEngine::handleThreads success=%d", reply->success);
if (reply->success) {
qDebug("CdbEngine::handleThreads success=%d", response.success);
if (response.success) {
GdbMi data;
data.fromString(reply->extensionReply);
data.fromString(response.extensionReply);
threadsHandler()->updateThreads(data);
// Continue sequence
postCommandSequence(reply->commandSequence);
postCommandSequence(response.commandSequence);
} else {
showMessage(QString::fromLatin1(reply->errorMessage), LogError);
showMessage(QString::fromLatin1(response.errorMessage), LogError);
}
}
@@ -1436,7 +1441,7 @@ void CdbEngine::activateFrame(int index)
updateLocals(true);
}
void CdbEngine::updateLocals(bool forNewStackFrame)
void CdbEngine::updateLocals(bool newFrame)
{
typedef QHash<QByteArray, int> WatcherHash;
@@ -1450,7 +1455,7 @@ void CdbEngine::updateLocals(bool forNewStackFrame)
watchHandler()->removeAllData();
return;
}
if (forNewStackFrame)
if (newFrame)
watchHandler()->resetValueCache();
/* Watchers: Forcibly discard old symbol group as switching from
* thread 0/frame 0 -> thread 1/assembly -> thread 0/frame 0 will otherwise re-use it
@@ -1499,10 +1504,9 @@ void CdbEngine::updateLocals(bool forNewStackFrame)
}
// Required arguments: frame
const int flags = forNewStackFrame ? LocalsUpdateForNewFrame : 0;
str << blankSeparator << frameIndex;
postExtensionCommand("locals", arguments, 0,
[this, flags](const CdbCommandPtr &r) { handleLocals(r, flags); });
[this, newFrame](const CdbResponse &r) { handleLocals(r, newFrame); });
}
void CdbEngine::selectThread(ThreadId threadId)
@@ -1560,7 +1564,7 @@ void CdbEngine::postDisassemblerCommand(quint64 address, quint64 endAddress,
ByteArrayInputStream str(cmd);
str << "u " << hex <<hexPrefixOn << address << ' ' << endAddress;
postBuiltinCommand(cmd, 0,
[this, agent](const CdbCommandPtr &r) { handleDisassembler(r, agent); });
[this, agent](const CdbResponse &r) { handleDisassembler(r, agent); });
}
void CdbEngine::postResolveSymbol(const QString &module, const QString &function,
@@ -1573,7 +1577,7 @@ void CdbEngine::postResolveSymbol(const QString &module, const QString &function
if (addresses.isEmpty()) {
showMessage(QLatin1String("Resolving symbol: ") + symbol + QLatin1String("..."), LogMisc);
postBuiltinCommand(QByteArray("x ") + symbol.toLatin1(), 0,
[this, symbol, agent](const CdbCommandPtr &r) { handleResolveSymbol(r, symbol, agent); });
[this, symbol, agent](const CdbResponse &r) { handleResolveSymbol(r, symbol, agent); });
} else {
showMessage(QString::fromLatin1("Using cached addresses for %1.").
arg(symbol), LogMisc);
@@ -1598,13 +1602,13 @@ static inline quint64 resolvedAddress(const QByteArray &line)
return 0;
}
void CdbEngine::handleResolveSymbol(const CdbCommandPtr &command, const QString &symbol,
void CdbEngine::handleResolveSymbol(const CdbResponse &response, const QString &symbol,
DisassemblerAgent *agent)
{
// Insert all matches of (potentially) ambiguous symbols
if (const int size = command->builtinReply.size()) {
if (const int size = response.builtinReply.size()) {
for (int i = 0; i < size; i++) {
if (const quint64 address = resolvedAddress(command->builtinReply.at(i))) {
if (const quint64 address = resolvedAddress(response.builtinReply.at(i))) {
m_symbolAddressCache.insert(symbol, address);
showMessage(QString::fromLatin1("Obtained 0x%1 for %2 (#%3)").
arg(address, 0, 16).arg(symbol).arg(i + 1), LogMisc);
@@ -1612,7 +1616,7 @@ void CdbEngine::handleResolveSymbol(const CdbCommandPtr &command, const QString
}
} else {
showMessage(QLatin1String("Symbol resolution failed: ")
+ QString::fromLatin1(command->joinedReply()),
+ QString::fromLatin1(response.joinedReply()),
LogError);
}
handleResolveSymbolHelper(m_symbolAddressCache.values(symbol), agent);
@@ -1700,9 +1704,9 @@ void CdbEngine::handleResolveSymbolHelper(const QList<quint64> &addresses, Disas
}
// Parse: "00000000`77606060 cc int 3"
void CdbEngine::handleDisassembler(const CdbCommandPtr &command, DisassemblerAgent *agent)
void CdbEngine::handleDisassembler(const CdbResponse &response, DisassemblerAgent *agent)
{
agent->setContents(parseCdbDisassembler(command->builtinReply));
agent->setContents(parseCdbDisassembler(response.builtinReply));
}
void CdbEngine::fetchMemory(MemoryAgent *agent, QObject *editor, quint64 addr, quint64 length)
@@ -1722,7 +1726,7 @@ void CdbEngine::postFetchMemory(const MemoryViewCookie &cookie)
ByteArrayInputStream str(args);
str << cookie.address << ' ' << cookie.length;
postExtensionCommand("memory", args, 0,
[this, cookie](const CdbCommandPtr &r) { handleMemory(r, cookie); });
[this, cookie](const CdbResponse &r) { handleMemory(r, cookie); });
}
void CdbEngine::changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data)
@@ -1736,15 +1740,15 @@ void CdbEngine::changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, c
}
}
void CdbEngine::handleMemory(const CdbCommandPtr &command, const MemoryViewCookie &memViewCookie)
void CdbEngine::handleMemory(const CdbResponse &response, const MemoryViewCookie &memViewCookie)
{
if (command->success && memViewCookie.agent) {
const QByteArray data = QByteArray::fromBase64(command->extensionReply);
if (response.success && memViewCookie.agent) {
const QByteArray data = QByteArray::fromBase64(response.extensionReply);
if (unsigned(data.size()) == memViewCookie.length)
memViewCookie.agent->addLazyData(memViewCookie.editorToken,
memViewCookie.address, data);
} else {
showMessage(QString::fromLocal8Bit(command->errorMessage), LogWarning);
showMessage(QString::fromLocal8Bit(response.errorMessage), LogWarning);
}
}
@@ -1782,27 +1786,27 @@ void CdbEngine::reloadFullStack()
postCommandSequence(CommandListStack);
}
void CdbEngine::handlePid(const CdbCommandPtr &reply)
void CdbEngine::handlePid(const CdbResponse &response)
{
// Fails for core dumps.
if (reply->success)
notifyInferiorPid(reply->extensionReply.toULongLong());
if (reply->success || startParameters().startMode == AttachCore) {
if (response.success)
notifyInferiorPid(response.extensionReply.toULongLong());
if (response.success || startParameters().startMode == AttachCore) {
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupOk")
notifyInferiorSetupOk();
} else {
showMessage(QString::fromLatin1("Failed to determine inferior pid: %1").
arg(QLatin1String(reply->errorMessage)), LogError);
arg(QLatin1String(response.errorMessage)), LogError);
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupFailed")
notifyInferiorSetupFailed();
}
}
void CdbEngine::handleModules(const CdbCommandPtr &reply)
void CdbEngine::handleModules(const CdbResponse &response)
{
if (reply->success) {
if (response.success) {
GdbMi value;
value.fromString(reply->extensionReply);
value.fromString(response.extensionReply);
if (value.type() == GdbMi::List) {
ModulesHandler *handler = modulesHandler();
handler->beginUpdateAll();
@@ -1819,21 +1823,21 @@ void CdbEngine::handleModules(const CdbCommandPtr &reply)
handler->endUpdateAll();
} else {
showMessage(QString::fromLatin1("Parse error in modules response."), LogError);
qWarning("Parse error in modules response:\n%s", reply->extensionReply.constData());
qWarning("Parse error in modules response:\n%s", response.extensionReply.constData());
}
} else {
showMessage(QString::fromLatin1("Failed to determine modules: %1").
arg(QLatin1String(reply->errorMessage)), LogError);
arg(QLatin1String(response.errorMessage)), LogError);
}
postCommandSequence(reply->commandSequence);
postCommandSequence(response.commandSequence);
}
void CdbEngine::handleRegistersExt(const CdbCommandPtr &reply)
void CdbEngine::handleRegistersExt(const CdbResponse &response)
{
if (reply->success) {
if (response.success) {
GdbMi value;
value.fromString(reply->extensionReply);
value.fromString(response.extensionReply);
if (value.type() == GdbMi::List) {
RegisterHandler *handler = registerHandler();
foreach (const GdbMi &item, value.children()) {
@@ -1848,28 +1852,28 @@ void CdbEngine::handleRegistersExt(const CdbCommandPtr &reply)
handler->commitUpdates();
} else {
showMessage(QString::fromLatin1("Parse error in registers response."), LogError);
qWarning("Parse error in registers response:\n%s", reply->extensionReply.constData());
qWarning("Parse error in registers response:\n%s", response.extensionReply.constData());
}
} else {
showMessage(QString::fromLatin1("Failed to determine registers: %1").
arg(QLatin1String(reply->errorMessage)), LogError);
arg(QLatin1String(response.errorMessage)), LogError);
}
postCommandSequence(reply->commandSequence);
postCommandSequence(response.commandSequence);
}
void CdbEngine::handleLocals(const CdbCommandPtr &reply, int flags)
void CdbEngine::handleLocals(const CdbResponse &response, bool newFrame)
{
if (reply->success) {
if (response.success) {
if (boolSetting(VerboseLog))
showMessage(QLatin1String("Locals: ") + QString::fromLatin1(reply->extensionReply), LogDebug);
showMessage(QLatin1String("Locals: ") + QString::fromLatin1(response.extensionReply), LogDebug);
QList<WatchData> watchData;
WatchHandler *handler = watchHandler();
if (flags & LocalsUpdateForNewFrame) {
if (newFrame) {
watchData.append(*handler->findData("local"));
watchData.append(*handler->findData("watch"));
}
GdbMi root;
root.fromString(reply->extensionReply);
root.fromString(response.extensionReply);
QTC_ASSERT(root.type() == GdbMi::List, return);
if (debugLocals)
qDebug() << root.toString(true, 4);
@@ -1896,19 +1900,19 @@ void CdbEngine::handleLocals(const CdbCommandPtr &reply, int flags)
foreach (const WatchData &wd, watchData)
nsp << wd.toString() <<'\n';
}
if (flags & LocalsUpdateForNewFrame) {
if (newFrame) {
emit stackFrameCompleted();
DebuggerToolTipManager::updateEngine(this);
}
} else {
showMessage(QString::fromLatin1(reply->errorMessage), LogWarning);
showMessage(QString::fromLatin1(response.errorMessage), LogWarning);
}
}
void CdbEngine::handleExpandLocals(const CdbCommandPtr &reply)
void CdbEngine::handleExpandLocals(const CdbResponse &response)
{
if (!reply->success)
showMessage(QString::fromLatin1(reply->errorMessage), LogError);
if (!response.success)
showMessage(QString::fromLatin1(response.errorMessage), LogError);
}
enum CdbExecutionStatus {
@@ -2043,7 +2047,7 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
exp.append('"');
}
postExtensionCommand("expression", exp, 0,
[this, id, stopReason](const CdbCommandPtr &r) { handleExpression(r, id, stopReason); });
[this, id, stopReason](const CdbResponse &r) { handleExpression(r, id, stopReason); });
return StopReportLog;
}
@@ -2207,7 +2211,7 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT
return;
case ParseStackWow64:
postBuiltinCommand("lm m wow64", 0,
[this, stack](const CdbCommandPtr &r) { handleCheckWow64(r, stack); });
[this, stack](const CdbResponse &r) { handleCheckWow64(r, stack); });
break;
}
} else {
@@ -2236,9 +2240,9 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT
showStoppedByExceptionMessageBox(exceptionBoxMessage);
}
void CdbEngine::handleBreakInsert(const CdbCommandPtr &cmd)
void CdbEngine::handleBreakInsert(const CdbResponse &response)
{
const QList<QByteArray> &reply = cmd->builtinReply;
const QList<QByteArray> &reply = response.builtinReply;
if (reply.isEmpty())
return;
foreach (const QByteArray &line, reply)
@@ -2260,12 +2264,12 @@ void CdbEngine::handleBreakInsert(const CdbCommandPtr &cmd)
// extract break point model id from command
QRegExp numberRegEx(QLatin1String("\\d"));
const int numberStart = numberRegEx.indexIn(QLatin1String(cmd->command));
const int numberStart = numberRegEx.indexIn(QLatin1String(response.command));
if (numberStart == -1)
return;
const int numberEnd = cmd->command.indexOf(' ', numberStart);
const int numberEnd = response.command.indexOf(' ', numberStart);
bool ok = true;
const int cdbBreakPointId = cmd->command.mid(numberStart, numberEnd - numberStart).toInt(&ok);
const int cdbBreakPointId = response.command.mid(numberStart, numberEnd - numberStart).toInt(&ok);
if (!ok)
return;
const BreakpointModelId &originalId = cdbIdToBreakpointModelId(cdbBreakPointId);
@@ -2300,26 +2304,26 @@ void CdbEngine::handleBreakInsert(const CdbCommandPtr &cmd)
attemptBreakpointSynchronization();
}
void CdbEngine::handleCheckWow64(const CdbCommandPtr &cmd, const GdbMi &stack)
void CdbEngine::handleCheckWow64(const CdbResponse &response, const GdbMi &stack)
{
// Using the lm (list modules) command to check if there is a 32 bit subsystem in this debuggee.
// expected reply if there is a 32 bit stack:
// start end module name
// 00000000`77490000 00000000`774d5000 wow64 (deferred)
if (cmd->builtinReply.value(1).contains("wow64")) {
if (response.builtinReply.value(1).contains("wow64")) {
postBuiltinCommand("k", 0,
[this, stack](const CdbCommandPtr &r) { ensureUsing32BitStackInWow64(r, stack); });
[this, stack](const CdbResponse &r) { ensureUsing32BitStackInWow64(r, stack); });
return;
}
m_wow64State = noWow64Stack;
parseStackTrace(stack, false);
}
void CdbEngine::ensureUsing32BitStackInWow64(const CdbEngine::CdbCommandPtr &cmd, const GdbMi &stack)
void CdbEngine::ensureUsing32BitStackInWow64(const CdbResponse &response, const GdbMi &stack)
{
// Parsing the header of the stack output to check which bitness
// the cdb is currently using.
foreach (const QByteArray &line, cmd->builtinReply) {
foreach (const QByteArray &line, response.builtinReply) {
if (!line.startsWith("Child"))
continue;
if (line.startsWith("ChildEBP")) {
@@ -2336,11 +2340,11 @@ void CdbEngine::ensureUsing32BitStackInWow64(const CdbEngine::CdbCommandPtr &cmd
parseStackTrace(stack, false);
}
void CdbEngine::handleSwitchWow64Stack(const CdbEngine::CdbCommandPtr &cmd)
void CdbEngine::handleSwitchWow64Stack(const CdbResponse &response)
{
if (cmd->builtinReply.first() == "Switched to 32bit mode")
if (response.builtinReply.first() == "Switched to 32bit mode")
m_wow64State = wow64Stack32Bit;
else if (cmd->builtinReply.first() == "Switched to 64bit mode")
else if (response.builtinReply.first() == "Switched to 64bit mode")
m_wow64State = wow64Stack64Bit;
else
m_wow64State = noWow64Stack;
@@ -2434,17 +2438,18 @@ void CdbEngine::handleExtensionMessage(char t, int token, const QByteArray &what
// Did the command finish? Take off queue and complete, invoke CB
const CdbCommandPtr command = m_extensionCommandQueue.takeAt(index);
if (t == 'R') {
command->success = true;
command->extensionReply = message;
command->response.success = true;
command->response.extensionReply = message;
} else {
command->success = false;
command->errorMessage = message;
command->response.success = false;
command->response.errorMessage = message;
}
if (debug)
qDebug("### Completed extension command '%s', token=%d, pending=%d",
command->command.constData(), command->token, m_extensionCommandQueue.size());
if (command->handler)
command->handler(command);
command->response.command.constData(), command->token, m_extensionCommandQueue.size());
if (command->handler) {
command->handler(command->response);
}
return;
}
}
@@ -2599,16 +2604,17 @@ void CdbEngine::parseOutputLine(QByteArray line)
// Did the command finish? Invoke callback and remove from queue.
if (debug)
qDebug("### Completed builtin command '%s', token=%d, %d lines, pending=%d",
currentCommand->command.constData(), currentCommand->token,
currentCommand->builtinReply.size(), m_builtinCommandQueue.size() - 1);
currentCommand->response.command.constData(), currentCommand->token,
currentCommand->response.builtinReply.size(), m_builtinCommandQueue.size() - 1);
QTC_ASSERT(token == currentCommand->token, return; );
if (currentCommand->handler)
currentCommand->handler(currentCommand);
if (currentCommand->handler) {
currentCommand->handler(currentCommand->response);
}
m_builtinCommandQueue.removeAt(m_currentBuiltinCommandIndex);
m_currentBuiltinCommandIndex = -1;
} else {
// Record output of current command
currentCommand->builtinReply.push_back(line);
currentCommand->response.builtinReply.push_back(line);
}
return;
} // m_currentCommandIndex
@@ -2619,7 +2625,8 @@ void CdbEngine::parseOutputLine(QByteArray line)
m_currentBuiltinCommandIndex = index;
const CdbCommandPtr &currentCommand = m_builtinCommandQueue.at(m_currentBuiltinCommandIndex);
if (debug)
qDebug("### Gathering output for '%s' token %d", currentCommand->command.constData(), currentCommand->token);
qDebug("### Gathering output for '%s' token %d",
currentCommand->response.command.constData(), currentCommand->token);
return;
}
const char versionString[] = "Microsoft (R) Windows Debugger Version";
@@ -3029,16 +3036,16 @@ void CdbEngine::loadAdditionalQmlStack()
postExtensionCommand("qmlstack", QByteArray(), 0, CB(handleAdditionalQmlStack));
}
void CdbEngine::handleAdditionalQmlStack(const CdbCommandPtr &reply)
void CdbEngine::handleAdditionalQmlStack(const CdbResponse &response)
{
QString errorMessage;
do {
if (!reply->success) {
errorMessage = QLatin1String(reply->errorMessage);
if (!response.success) {
errorMessage = QLatin1String(response.errorMessage);
break;
}
GdbMi stackGdbMi;
stackGdbMi.fromString(reply->extensionReply);
stackGdbMi.fromString(response.extensionReply);
if (!stackGdbMi.isValid()) {
errorMessage = QLatin1String("GDBMI parser error");
break;
@@ -3068,28 +3075,28 @@ void CdbEngine::mergeStartParametersSourcePathMap()
}
}
void CdbEngine::handleStackTrace(const CdbCommandPtr &command)
void CdbEngine::handleStackTrace(const CdbResponse &response)
{
if (command->success) {
if (response.success) {
GdbMi stack;
stack.fromString(command->extensionReply);
stack.fromString(response.extensionReply);
if (parseStackTrace(stack, false) == ParseStackWow64) {
postBuiltinCommand("lm m wow64", 0,
[this, stack](const CdbCommandPtr &r) { handleCheckWow64(r, stack); });
[this, stack](const CdbResponse &r) { handleCheckWow64(r, stack); });
}
postCommandSequence(command->commandSequence);
postCommandSequence(response.commandSequence);
} else {
showMessage(QString::fromLocal8Bit(command->errorMessage), LogError);
showMessage(QString::fromLocal8Bit(response.errorMessage), LogError);
}
}
void CdbEngine::handleExpression(const CdbCommandPtr &command, BreakpointModelId id, const GdbMi &stopReason)
void CdbEngine::handleExpression(const CdbResponse &response, BreakpointModelId id, const GdbMi &stopReason)
{
int value = 0;
if (command->success)
value = command->extensionReply.toInt();
if (response.success)
value = response.extensionReply.toInt();
else
showMessage(QString::fromLocal8Bit(command->errorMessage), LogError);
showMessage(QString::fromLocal8Bit(response.errorMessage), LogError);
// Is this a conditional breakpoint?
const QString message = value ?
tr("Value %1 obtained from evaluating the condition of breakpoint %2, stopping.").
@@ -3104,9 +3111,9 @@ void CdbEngine::handleExpression(const CdbCommandPtr &command, BreakpointModelId
doContinueInferior();
}
void CdbEngine::dummyHandler(const CdbCommandPtr &command)
void CdbEngine::dummyHandler(const CdbResponse &command)
{
postCommandSequence(command->commandSequence);
postCommandSequence(command.commandSequence);
}
// Post a sequence of standard commands: Trigger next once one completes successfully
@@ -3141,17 +3148,17 @@ void CdbEngine::postCommandSequence(unsigned mask)
}
}
void CdbEngine::handleWidgetAt(const CdbCommandPtr &reply)
void CdbEngine::handleWidgetAt(const CdbResponse &response)
{
bool success = false;
QString message;
do {
if (!reply->success) {
message = QString::fromLatin1(reply->errorMessage);
if (!response.success) {
message = QString::fromLatin1(response.errorMessage);
break;
}
// Should be "namespace::QWidget:0x555"
QString watchExp = QString::fromLatin1(reply->extensionReply);
QString watchExp = QString::fromLatin1(response.extensionReply);
const int sepPos = watchExp.lastIndexOf(QLatin1Char(':'));
if (sepPos == -1) {
message = QString::fromLatin1("Invalid output: %1").arg(watchExp);
@@ -3191,16 +3198,16 @@ static inline void formatCdbBreakPointResponse(BreakpointModelId id, const Break
str << '\n';
}
void CdbEngine::handleBreakPoints(const CdbCommandPtr &reply)
void CdbEngine::handleBreakPoints(const CdbResponse &response)
{
if (debugBreakpoints)
qDebug("CdbEngine::handleBreakPoints: success=%d: %s", reply->success, reply->extensionReply.constData());
if (!reply->success) {
showMessage(QString::fromLatin1(reply->errorMessage), LogError);
qDebug("CdbEngine::handleBreakPoints: success=%d: %s", response.success, response.extensionReply.constData());
if (!response.success) {
showMessage(QString::fromLatin1(response.errorMessage), LogError);
return;
}
GdbMi value;
value.fromString(reply->extensionReply);
value.fromString(response.extensionReply);
if (value.type() != GdbMi::List) {
showMessage(QString::fromLatin1("Unabled to parse breakpoints reply"), LogError);
return;
+27 -26
View File
@@ -49,7 +49,8 @@ namespace Debugger {
namespace Internal {
class DisassemblerAgent;
struct CdbCommand;
class CdbCommand;
class CdbResponse;
struct MemoryViewCookie;
class ByteArrayInputStream;
class GdbMi;
@@ -70,7 +71,7 @@ public:
};
typedef QSharedPointer<CdbCommand> CdbCommandPtr;
typedef std::function<void(const CdbCommandPtr &)> CommandHandler;
typedef std::function<void(const CdbResponse &)> CommandHandler;
CdbEngine(const DebuggerStartParameters &sp);
~CdbEngine();
@@ -216,37 +217,37 @@ private:
void postResolveSymbol(const QString &module, const QString &function,
DisassemblerAgent *agent);
// Builtin commands
void dummyHandler(const CdbCommandPtr &);
void handleStackTrace(const CdbCommandPtr &);
void handleRegisters(const CdbCommandPtr &);
void handleDisassembler(const CdbCommandPtr &, DisassemblerAgent *agent);
void handleJumpToLineAddressResolution(const CdbCommandPtr &, const ContextData &context);
void handleExpression(const CdbCommandPtr &command, BreakpointModelId id, const GdbMi &stopReason);
void handleResolveSymbol(const CdbCommandPtr &command, const QString &symbol, DisassemblerAgent *agent);
void dummyHandler(const CdbResponse &);
void handleStackTrace(const CdbResponse &);
void handleRegisters(const CdbResponse &);
void handleDisassembler(const CdbResponse &, DisassemblerAgent *agent);
void handleJumpToLineAddressResolution(const CdbResponse &response, const ContextData &context);
void handleExpression(const CdbResponse &command, BreakpointModelId id, const GdbMi &stopReason);
void handleResolveSymbol(const CdbResponse &command, const QString &symbol, DisassemblerAgent *agent);
void handleResolveSymbolHelper(const QList<quint64> &addresses, DisassemblerAgent *agent);
void handleBreakInsert(const CdbCommandPtr &cmd);
void handleCheckWow64(const CdbCommandPtr &cmd, const GdbMi &stack);
void ensureUsing32BitStackInWow64(const CdbCommandPtr &cmd, const GdbMi &stack);
void handleSwitchWow64Stack(const CdbCommandPtr &cmd);
void handleBreakInsert(const CdbResponse &response);
void handleCheckWow64(const CdbResponse &response, const GdbMi &stack);
void ensureUsing32BitStackInWow64(const CdbResponse &response, const GdbMi &stack);
void handleSwitchWow64Stack(const CdbResponse &response);
void jumpToAddress(quint64 address);
void handleCreateFullBackTrace(const CdbCommandPtr &cmd);
void handleCreateFullBackTrace(const CdbResponse &response);
// Extension commands
void handleThreads(const CdbCommandPtr &);
void handlePid(const CdbCommandPtr &reply);
void handleLocals(const CdbCommandPtr &reply, int flags);
void handleAddWatch(const CdbCommandPtr &reply, WatchData item);
void handleExpandLocals(const CdbCommandPtr &reply);
void handleRegistersExt(const CdbCommandPtr &reply);
void handleModules(const CdbCommandPtr &reply);
void handleMemory(const CdbCommandPtr &, const MemoryViewCookie &memViewCookie);
void handleWidgetAt(const CdbCommandPtr &);
void handleBreakPoints(const CdbCommandPtr &);
void handleThreads(const CdbResponse &response);
void handlePid(const CdbResponse &response);
void handleLocals(const CdbResponse &response, bool newFrame);
void handleAddWatch(const CdbResponse &response, WatchData item);
void handleExpandLocals(const CdbResponse &response);
void handleRegistersExt(const CdbResponse &response);
void handleModules(const CdbResponse &response);
void handleMemory(const CdbResponse &response, const MemoryViewCookie &memViewCookie);
void handleWidgetAt(const CdbResponse &response);
void handleBreakPoints(const CdbResponse &response);
void handleBreakPoints(const GdbMi &value);
void handleAdditionalQmlStack(const CdbCommandPtr &);
void handleAdditionalQmlStack(const CdbResponse &response);
NormalizedSourceFileName sourceMapNormalizeFileNameFromDebugger(const QString &f);
void updateLocalVariable(const QByteArray &iname);
void updateLocals(bool forNewStackFrame = false);
void updateLocals(bool forNewStackFrame);
int elapsedLogTime() const;
void addLocalsOptions(ByteArrayInputStream &s) const;
unsigned parseStackTrace(const GdbMi &data, bool sourceStepInto);
+7 -5
View File
@@ -737,7 +737,7 @@ public:
void runControlStarted(DebuggerEngine *engine);
void runControlFinished(DebuggerEngine *engine);
void remoteCommand(const QStringList &options, const QStringList &);
void remoteCommand(const QStringList &options);
void displayDebugger(DebuggerEngine *engine, bool updateEngine = true);
@@ -2370,8 +2370,7 @@ void DebuggerPluginPrivate::runControlFinished(DebuggerEngine *engine)
m_logWindow->clearUndoRedoStacks();
}
void DebuggerPluginPrivate::remoteCommand(const QStringList &options,
const QStringList &)
void DebuggerPluginPrivate::remoteCommand(const QStringList &options)
{
if (options.isEmpty())
return;
@@ -3295,9 +3294,12 @@ IPlugin::ShutdownFlag DebuggerPlugin::aboutToShutdown()
}
QObject *DebuggerPlugin::remoteCommand(const QStringList &options,
const QStringList &list)
const QString &workingDirectory,
const QStringList &list)
{
dd->remoteCommand(options, list);
Q_UNUSED(workingDirectory);
Q_UNUSED(list);
dd->remoteCommand(options);
return 0;
}
+3 -1
View File
@@ -51,7 +51,9 @@ public:
private:
// IPlugin implementation.
bool initialize(const QStringList &arguments, QString *errorMessage);
QObject *remoteCommand(const QStringList &options, const QStringList &arguments);
QObject *remoteCommand(const QStringList &options,
const QString &workingDirectory,
const QStringList &arguments);
ShutdownFlag aboutToShutdown();
void extensionsInitialized();
+20 -5
View File
@@ -266,8 +266,15 @@ void LldbEngine::startLldb()
showMessage(_("ADAPTER START FAILED"));
if (!msg.isEmpty())
ICore::showWarningWithOptions(tr("Adapter start failed."), msg);
return;
}
m_lldbProc.waitForReadyRead(1000);
m_lldbProc.write("sc print('@\\nlldbstartupok@\\n')\n");
}
// FIXME: splitting of startLldb() necessary to support LLDB <= 310 - revert asap
void LldbEngine::startLldbStage2()
{
showMessage(_("ADAPTER STARTED"));
showStatusMessage(tr("Setting up inferior..."));
@@ -282,8 +289,6 @@ void LldbEngine::startLldb()
void LldbEngine::setupInferior()
{
const DebuggerStartParameters &sp = startParameters();
const QString path = stringSetting(ExtraDumperFile);
if (!path.isEmpty()) {
DebuggerCommand cmd("addDumperModule");
@@ -300,6 +305,12 @@ void LldbEngine::setupInferior()
DebuggerCommand cmd1("loadDumperFiles");
runCommand(cmd1);
}
// FIXME: splitting of setupInferior() necessary to support LLDB <= 310 - revert asap
void LldbEngine::setupInferiorStage2()
{
const DebuggerStartParameters &sp = startParameters();
QString executable;
QtcProcess::Arguments args;
@@ -436,9 +447,10 @@ void LldbEngine::handleResponse(const QByteArray &response)
const QByteArray name = item.name();
if (name == "data")
refreshLocals(item);
else if (name == "dumpers")
else if (name == "dumpers") {
watchHandler()->addDumpers(item);
else if (name == "stack")
setupInferiorStage2();
} else if (name == "stack")
refreshStack(item);
else if (name == "registers")
refreshRegisters(item);
@@ -973,7 +985,10 @@ void LldbEngine::readLldbStandardOutput()
break;
QByteArray response = m_inbuffer.left(pos).trimmed();
m_inbuffer = m_inbuffer.mid(pos + 2);
emit outputReady(response);
if (response == "lldbstartupok")
startLldbStage2();
else
emit outputReady(response);
}
}
+2
View File
@@ -78,7 +78,9 @@ private:
void setupEngine();
void startLldb();
void startLldbStage2();
void setupInferior();
void setupInferiorStage2();
void runEngine();
void shutdownInferior();
void shutdownEngine();
+1 -1
View File
@@ -154,7 +154,7 @@ GDB 32bit | Api | Api | NA | Win32
if (!QFile::exists(executable)) {
*errorMessage = QString::fromLatin1("%1 does not exist. If you have built QtCreator "
"on your own ,checkout "
"http://qt.gitorious.org/qt-creator/binary-artifacts.").
"https://code.qt.io/cgit/qt-creator/binary-artifacts.git/.").
arg(QDir::toNativeSeparators(executable));
break;
}
@@ -775,7 +775,7 @@ QList<WatchData> QmlInspectorAgent::buildWatchData(const ObjectReference &obj,
// hence we can insert the data in the correct position
const QByteArray oldIname = m_debugIdToIname.value(objDebugId);
if (oldIname != objIname)
m_debuggerEngine->watchHandler()->removeData(oldIname);
m_debuggerEngine->watchHandler()->removeItemByIName(oldIname);
}
m_debugIdToIname.insert(objDebugId, objIname);
}
+6 -9
View File
@@ -1017,8 +1017,13 @@ TypeFormatList WatchModel::typeFormatList(const WatchData &data) const
formats.append(Array1000Format);
formats.append(Array10000Format);
} else if (data.type.contains("char[") || data.type.contains("char [")) {
formats.append(RawFormat);
formats.append(Latin1StringFormat);
formats.append(SeparateLatin1StringFormat);
formats.append(Utf8StringFormat);
formats.append(SeparateUtf8StringFormat);
formats.append(Local8BitStringFormat);
formats.append(Utf16StringFormat);
formats.append(Ucs4StringFormat);
}
@@ -1279,7 +1284,7 @@ void WatchHandler::purgeOutdatedItems(const QSet<QByteArray> &inames)
updateWatchersWindow();
}
void WatchHandler::removeData(const QByteArray &iname)
void WatchHandler::removeItemByIName(const QByteArray &iname)
{
WatchItem *item = m_model->findItem(iname);
if (!item)
@@ -1293,14 +1298,6 @@ void WatchHandler::removeData(const QByteArray &iname)
updateWatchersWindow();
}
void WatchHandler::removeChildren(const QByteArray &iname)
{
WatchItem *item = m_model->findItem(iname);
if (item)
item->removeChildren();
updateWatchersWindow();
}
QByteArray WatchHandler::watcherName(const QByteArray &exp)
{
return "watch." + QByteArray::number(theWatcherNames[exp]);
+1 -2
View File
@@ -239,8 +239,7 @@ public:
void insertData(const WatchData &data); // DEPRECATED
void insertDataList(const QList<WatchData> &list); // DEPRECATED
void insertItem(WatchItem *item); // Takes ownership.
void removeData(const QByteArray &iname);
void removeChildren(const QByteArray &iname);
void removeItemByIName(const QByteArray &iname);
void removeAllData(bool includeInspectData = false);
void resetValueCache();
void purgeOutdatedItems(const QSet<QByteArray> &inames);
+2 -2
View File
@@ -460,7 +460,7 @@ void WatchTreeView::keyPressEvent(QKeyEvent *ev)
if (ev->key() == Qt::Key_Delete && m_type == WatchersType) {
WatchHandler *handler = currentEngine()->watchHandler();
foreach (const QModelIndex &idx, activeRows())
handler->removeData(idx.data(LocalsINameRole).toByteArray());
handler->removeItemByIName(idx.data(LocalsINameRole).toByteArray());
} else if (ev->key() == Qt::Key_Return
&& ev->modifiers() == Qt::ControlModifier
&& m_type == LocalsType) {
@@ -886,7 +886,7 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev)
} else if (act == &actWatchExpression) {
watchExpression(exp, name);
} else if (act == &actRemoveWatchExpression) {
handler->removeData(p.data(LocalsINameRole).toByteArray());
handler->removeItemByIName(p.data(LocalsINameRole).toByteArray());
} else if (act == &actRemoveAllWatchExpression) {
handler->clearWatches();
} else if (act == &actCopy) {
+260 -184
View File
@@ -31,7 +31,6 @@
#include "diffeditor.h"
#include "diffeditorconstants.h"
#include "diffeditordocument.h"
#include "diffeditorguicontroller.h"
#include "diffview.h"
#include <coreplugin/icore.h>
@@ -62,7 +61,13 @@
#include <QTextBlock>
static const char settingsGroupC[] = "DiffEditor";
static const char diffEditorTypeKeyC[] = "DiffEditorType";
static const char descriptionVisibleKeyC[] = "DescriptionVisible";
static const char horizontalScrollBarSynchronizationKeyC[] =
"HorizontalScrollBarSynchronization";
static const char contextLineCountKeyC[] = "ContextLineNumbers";
static const char ignoreWhitespaceKeyC[] = "IgnoreWhitespace";
static const char diffViewKeyC[] = "DiffEditorType";
static const char legacySettingsGroupC[] = "Git";
static const char useDiffEditorKeyC[] = "UseDiffEditor";
@@ -187,7 +192,6 @@ void DescriptionEditorWidget::highlightCurrentContents()
sel.format.setFontUnderline(true);
setExtraSelections(TextEditorWidget::OtherSelection,
QList<QTextEdit::ExtraSelection>() << sel);
}
void DescriptionEditorWidget::handleCurrentContents()
@@ -204,15 +208,23 @@ DiffEditor::DiffEditor(const QSharedPointer<DiffEditorDocument> &doc)
: m_document(doc)
, m_descriptionWidget(0)
, m_stackedWidget(0)
, m_currentViewIndex(-1)
, m_guiController(0)
, m_toolBar(0)
, m_entriesComboBox(0)
, m_toggleSyncAction(0)
, m_whitespaceButtonAction(0)
, m_contextLabelAction(0)
, m_contextSpinBoxAction(0)
, m_toggleDescriptionAction(0)
, m_reloadAction(0)
, m_diffEditorSwitcher(0)
, m_currentViewIndex(-1)
, m_currentDiffFileIndex(-1)
, m_sync(false)
, m_showDescription(true)
, m_ignoreChanges(true)
{
QTC_ASSERT(m_document, return);
setDuplicateSupported(true);
QSplitter *splitter = new Core::MiniSplitter(Qt::Vertical);
@@ -228,29 +240,23 @@ DiffEditor::DiffEditor(const QSharedPointer<DiffEditorDocument> &doc)
setWidget(splitter);
DiffEditorController *control = controller();
m_guiController = new DiffEditorGuiController(control, this);
connect(m_descriptionWidget, &DescriptionEditorWidget::requestBranchList,
control, &DiffEditorController::expandBranchesRequested);
connect(control, &DiffEditorController::cleared, this, &DiffEditor::slotCleared);
connect(control, &DiffEditorController::diffFilesChanged,
this, &DiffEditor::slotDiffFilesChanged);
connect(control, &DiffEditorController::descriptionChanged,
this, &DiffEditor::slotDescriptionChanged);
connect(control, &DiffEditorController::descriptionEnablementChanged,
this, &DiffEditor::slotDescriptionVisibilityChanged);
connect(m_guiController, &DiffEditorGuiController::descriptionVisibilityChanged,
this, &DiffEditor::slotDescriptionVisibilityChanged);
connect(m_guiController, &DiffEditorGuiController::currentDiffFileIndexChanged,
this, &DiffEditor::activateEntry);
slotDescriptionChanged(control->description());
slotDescriptionVisibilityChanged();
showDiffView(readCurrentDiffEditorSetting());
m_document.data(), &DiffEditorDocument::requestMoreInformation);
connect(m_document.data(), &DiffEditorDocument::documentChanged,
this, &DiffEditor::documentHasChanged);
connect(m_document.data(), &DiffEditorDocument::descriptionChanged,
this, &DiffEditor::updateDescription);
connect(m_document.data(), &DiffEditorDocument::aboutToReload,
this, &DiffEditor::prepareForReload);
connect(m_document.data(), &DiffEditorDocument::reloadFinished,
this, &DiffEditor::reloadHasFinished);
toolBar();
loadSettings();
updateDescription();
m_ignoreChanges = false;
}
DiffEditor::~DiffEditor()
@@ -295,8 +301,6 @@ QWidget *DiffEditor::toolBar()
if (m_toolBar)
return m_toolBar;
DiffEditorController *control = controller();
// Create
m_toolBar = createToolBar(m_views.at(0));
@@ -306,109 +310,77 @@ QWidget *DiffEditor::toolBar()
QSizePolicy policy = m_entriesComboBox->sizePolicy();
policy.setHorizontalPolicy(QSizePolicy::Expanding);
m_entriesComboBox->setSizePolicy(policy);
connect(m_entriesComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
this, &DiffEditor::entryActivated);
connect(m_entriesComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &DiffEditor::setCurrentDiffFileIndex);
m_toolBar->addWidget(m_entriesComboBox);
QToolButton *whitespaceButton = new QToolButton(m_toolBar);
whitespaceButton->setText(tr("Ignore Whitespace"));
whitespaceButton->setCheckable(true);
whitespaceButton->setChecked(control->isIgnoreWhitespace());
m_whitespaceButtonAction = m_toolBar->addWidget(whitespaceButton);
m_whitespaceButton = new QToolButton(m_toolBar);
m_whitespaceButton->setText(tr("Ignore Whitespace"));
m_whitespaceButton->setCheckable(true);
m_whitespaceButton->setChecked(m_document->ignoreWhitespace());
m_whitespaceButtonAction = m_toolBar->addWidget(m_whitespaceButton);
QLabel *contextLabel = new QLabel(m_toolBar);
contextLabel->setText(tr("Context Lines:"));
contextLabel->setContentsMargins(6, 0, 6, 0);
m_contextLabelAction = m_toolBar->addWidget(contextLabel);
QSpinBox *contextSpinBox = new QSpinBox(m_toolBar);
contextSpinBox->setRange(1, 100);
contextSpinBox->setValue(control->contextLinesNumber());
contextSpinBox->setFrame(false);
contextSpinBox->setSizePolicy(QSizePolicy::Minimum,
QSizePolicy::Expanding); // Mac Qt5
m_contextSpinBoxAction = m_toolBar->addWidget(contextSpinBox);
m_contextSpinBox = new QSpinBox(m_toolBar);
m_contextSpinBox->setRange(1, 100);
m_contextSpinBox->setValue(m_document->contextLineCount());
m_contextSpinBox->setFrame(false);
m_contextSpinBox->setSizePolicy(QSizePolicy::Minimum,
QSizePolicy::Expanding); // Mac Qt5
m_contextSpinBoxAction = m_toolBar->addWidget(m_contextSpinBox);
QToolButton *toggleDescription = new QToolButton(m_toolBar);
toggleDescription->setIcon(QIcon(QLatin1String(Constants::ICON_TOP_BAR)));
toggleDescription->setCheckable(true);
toggleDescription->setChecked(m_guiController->isDescriptionVisible());
toggleDescription->setChecked(m_showDescription);
m_toggleDescriptionAction = m_toolBar->addWidget(toggleDescription);
slotDescriptionVisibilityChanged();
updateDescription();
QToolButton *reloadButton = new QToolButton(m_toolBar);
reloadButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_RELOAD_GRAY)));
reloadButton->setToolTip(tr("Reload Editor"));
m_reloadAction = m_toolBar->addWidget(reloadButton);
slotReloaderChanged();
documentStateChanged();
QToolButton *toggleSync = new QToolButton(m_toolBar);
toggleSync->setIcon(QIcon(QLatin1String(Core::Constants::ICON_LINK)));
toggleSync->setCheckable(true);
toggleSync->setChecked(m_guiController->horizontalScrollBarSynchronization());
toggleSync->setToolTip(tr("Synchronize Horizontal Scroll Bars"));
m_toolBar->addWidget(toggleSync);
m_toggleSyncAction = m_toolBar->addWidget(toggleSync);
m_diffEditorSwitcher = new QToolButton(m_toolBar);
m_toolBar->addWidget(m_diffEditorSwitcher);
updateDiffEditorSwitcher();
connect(whitespaceButton, &QToolButton::clicked,
control, &DiffEditorController::setIgnoreWhitespace);
connect(control, &DiffEditorController::ignoreWhitespaceChanged,
whitespaceButton, &QToolButton::setChecked);
connect(contextSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
control, &DiffEditorController::setContextLinesNumber);
connect(control, &DiffEditorController::contextLinesNumberChanged,
contextSpinBox, &QSpinBox::setValue);
connect(toggleSync, &QAbstractButton::clicked,
m_guiController, &DiffEditorGuiController::setHorizontalScrollBarSynchronization);
connect(m_whitespaceButton, &QToolButton::clicked,
this, &DiffEditor::ignoreWhitespaceHasChanged);
connect(m_contextSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
this, &DiffEditor::contextLineCountHasChanged);
connect(toggleSync, &QAbstractButton::clicked, this, &DiffEditor::toggleSync);
connect(toggleDescription, &QAbstractButton::clicked,
m_guiController, &DiffEditorGuiController::setDescriptionVisible);
this, &DiffEditor::toggleDescription);
connect(m_diffEditorSwitcher, &QAbstractButton::clicked,
this, [this]() { showDiffView(nextView()); });
connect(reloadButton, &QAbstractButton::clicked,
control, &DiffEditorController::requestReload);
connect(control, &DiffEditorController::reloaderChanged,
this, &DiffEditor::slotReloaderChanged);
connect(control, &DiffEditorController::contextLinesNumberEnablementChanged,
this, &DiffEditor::slotReloaderChanged);
connect(reloadButton, &QAbstractButton::clicked, this, [this]() { m_document->reload(); });
connect(m_document.data(), &DiffEditorDocument::temporaryStateChanged,
this, &DiffEditor::documentStateChanged);
return m_toolBar;
}
DiffEditorController *DiffEditor::controller() const
void DiffEditor::documentHasChanged()
{
return m_document->controller();
}
m_ignoreChanges = true;
const QList<FileData> diffFileList = m_document->diffFiles();
void DiffEditor::updateEntryToolTip()
{
const QString &toolTip = m_entriesComboBox->itemData(
m_entriesComboBox->currentIndex(), Qt::ToolTipRole).toString();
m_entriesComboBox->setToolTip(toolTip);
}
void DiffEditor::entryActivated(int index)
{
updateEntryToolTip();
m_guiController->setCurrentDiffFileIndex(index);
}
void DiffEditor::slotCleared(const QString &message)
{
Q_UNUSED(message)
m_entriesComboBox->clear();
updateEntryToolTip();
}
void DiffEditor::slotDiffFilesChanged(const QList<FileData> &diffFileList,
const QString &workingDirectory)
{
Q_UNUSED(workingDirectory)
currentView()->setDiff(diffFileList, m_document->baseDirectory());
m_entriesComboBox->clear();
int index = 0;
const int count = diffFileList.count();
for (int i = 0; i < count; i++) {
const DiffFileInfo leftEntry = diffFileList.at(i).leftFileInfo;
@@ -449,64 +421,193 @@ void DiffEditor::slotDiffFilesChanged(const QList<FileData> &diffFileList,
rightEntry.fileName);
}
}
if (m_currentFileChunk.first == leftEntry.fileName
&& m_currentFileChunk.second == rightEntry.fileName)
index = i;
m_entriesComboBox->addItem(itemText);
m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1,
leftEntry.fileName, Qt::UserRole);
m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1,
rightEntry.fileName, Qt::UserRole + 1);
m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1,
itemToolTip, Qt::ToolTipRole);
}
updateEntryToolTip();
m_ignoreChanges = false;
setCurrentDiffFileIndex(m_entriesComboBox->count() > 0 ? index : -1);
}
void DiffEditor::activateEntry(int index)
void DiffEditor::toggleDescription()
{
m_entriesComboBox->blockSignals(true);
m_entriesComboBox->setCurrentIndex(index);
m_entriesComboBox->blockSignals(false);
updateEntryToolTip();
m_showDescription = !m_showDescription;
saveSetting(QLatin1String(descriptionVisibleKeyC), m_showDescription);
updateDescription();
}
void DiffEditor::slotDescriptionChanged(const QString &description)
void DiffEditor::updateDescription()
{
QString description = m_document->description();
m_descriptionWidget->setPlainText(description);
}
m_descriptionWidget->setVisible(m_showDescription && !description.isEmpty());
void DiffEditor::slotDescriptionVisibilityChanged()
{
const bool enabled = controller()->isDescriptionEnabled();
const bool visible = m_guiController->isDescriptionVisible();
m_descriptionWidget->setVisible(visible && enabled);
if (!m_toggleDescriptionAction)
return;
QTC_ASSERT(m_toolBar, return);
QTC_ASSERT(m_toggleDescriptionAction, return);
QWidget *toggle = m_toolBar->widgetForAction(m_toggleDescriptionAction);
if (visible)
toggle->setToolTip(tr("Hide Change Description"));
else
toggle->setToolTip(tr("Show Change Description"));
m_toggleDescriptionAction->setVisible(enabled);
toggle->setToolTip(m_showDescription ? tr("Hide Change Description")
: tr("Show Change Description"));
m_toggleDescriptionAction->setVisible(!description.isEmpty());
}
void DiffEditor::slotReloaderChanged()
void DiffEditor::contextLineCountHasChanged(int lines)
{
DiffEditorController *control = controller();
const DiffEditorReloader *reloader = control->reloader();
const bool contextVisible = control->isContextLinesNumberEnabled();
QTC_ASSERT(!m_document->isContextLineCountForced(), return);
if (m_ignoreChanges || lines == m_document->contextLineCount())
return;
m_whitespaceButtonAction->setVisible(reloader);
m_contextLabelAction->setVisible(reloader && contextVisible);
m_contextSpinBoxAction->setVisible(reloader && contextVisible);
m_reloadAction->setVisible(reloader);
m_document->setContextLineCount(lines);
saveSetting(QLatin1String(contextLineCountKeyC), lines);
m_document->reload();
}
void DiffEditor::ignoreWhitespaceHasChanged(bool ignore)
{
if (m_ignoreChanges || ignore == m_document->ignoreWhitespace())
return;
m_document->setIgnoreWhitespace(ignore);
saveSetting(QLatin1String(ignoreWhitespaceKeyC), ignore);
m_document->reload();
}
void DiffEditor::prepareForReload()
{
documentStateChanged(); // To update actions...
QTC_ASSERT(currentView(), return);
if (m_entriesComboBox->count() > 0) {
m_currentFileChunk
= qMakePair(m_entriesComboBox->itemData(m_currentDiffFileIndex, Qt::UserRole).toString(),
m_entriesComboBox->itemData(m_currentDiffFileIndex, Qt::UserRole + 1).toString());
} else {
m_currentFileChunk = qMakePair(QString(), QString());
}
m_ignoreChanges = true;
m_contextSpinBox->setValue(m_document->contextLineCount());
m_whitespaceButton->setChecked(m_document->ignoreWhitespace());
m_ignoreChanges = false;
currentView()->beginOperation();
}
void DiffEditor::reloadHasFinished(bool success)
{
if (!currentView())
return;
m_currentFileChunk = qMakePair(QString(), QString());
currentView()->endOperation(success);
}
void DiffEditor::updateEntryToolTip()
{
const QString &toolTip = m_entriesComboBox->itemData(
m_entriesComboBox->currentIndex(), Qt::ToolTipRole).toString();
m_entriesComboBox->setToolTip(toolTip);
}
void DiffEditor::setCurrentDiffFileIndex(int index)
{
if (m_ignoreChanges)
return;
QTC_ASSERT((index < 0) != (m_entriesComboBox->count() > 0), return);
m_ignoreChanges = true;
m_currentDiffFileIndex = index;
currentView()->setCurrentDiffFileIndex(index);
m_entriesComboBox->setCurrentIndex(m_entriesComboBox->count() > 0 ? qMax(0, index) : -1);
updateEntryToolTip();
m_ignoreChanges = false;
}
void DiffEditor::documentStateChanged()
{
const bool canReload = m_document->isTemporary();
const bool contextVisible = !m_document->isContextLineCountForced();
m_whitespaceButtonAction->setVisible(canReload);
m_contextLabelAction->setVisible(canReload && contextVisible);
m_contextSpinBoxAction->setVisible(canReload && contextVisible);
m_reloadAction->setVisible(canReload);
}
void DiffEditor::updateDiffEditorSwitcher()
{
if (!m_diffEditorSwitcher)
return;
IDiffView *next = nextView();
m_diffEditorSwitcher->setIcon(next->icon());
m_diffEditorSwitcher->setToolTip(next->toolTip());
}
m_diffEditorSwitcher->setIcon(currentView()->icon());
m_diffEditorSwitcher->setToolTip(currentView()->toolTip());
void DiffEditor::toggleSync()
{
QTC_ASSERT(currentView(), return);
m_sync = !m_sync;
saveSetting(QLatin1String(horizontalScrollBarSynchronizationKeyC), m_sync);
currentView()->setSync(m_sync);
}
void DiffEditor::loadSettings()
{
QTC_ASSERT(currentView(), return);
QSettings *s = Core::ICore::settings();
// TODO: Remove in 3.6: Read legacy settings first:
s->beginGroup(QLatin1String(legacySettingsGroupC));
const bool legacyExists = s->contains(QLatin1String(useDiffEditorKeyC));
const bool legacyEditor = s->value(
QLatin1String(useDiffEditorKeyC), true).toBool();
s->remove(QLatin1String(useDiffEditorKeyC));
s->endGroup();
// Save legacy settings to current settings:
if (legacyExists) {
saveSetting(QLatin1String(diffViewKeyC), legacyEditor ? m_views.at(0)->id().toSetting() :
m_views.at(1)->id().toSetting());
}
// Read current settings:
s->beginGroup(QLatin1String(settingsGroupC));
m_showDescription = s->value(QLatin1String(descriptionVisibleKeyC),
true).toBool();
m_sync = s->value(QLatin1String(horizontalScrollBarSynchronizationKeyC),
true).toBool();
m_document->setIgnoreWhitespace(s->value(QLatin1String(ignoreWhitespaceKeyC), false).toBool());
m_document->setContextLineCount(s->value(QLatin1String(contextLineCountKeyC), 3).toInt());
Core::Id id = Core::Id::fromSetting(s->value(QLatin1String(diffViewKeyC)));
s->endGroup();
IDiffView *view = Utils::findOr(m_views, m_views.at(0), [id](IDiffView *v) { return v->id() == id; });
QTC_ASSERT(view, return);
setupView(view);
}
void DiffEditor::saveSetting(const QString &key, const QVariant &value) const
{
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(key, value);
s->endGroup();
}
void DiffEditor::addView(IDiffView *view)
@@ -514,6 +615,10 @@ void DiffEditor::addView(IDiffView *view)
QTC_ASSERT(!m_views.contains(view), return);
m_views.append(view);
m_stackedWidget->addWidget(view->widget());
if (m_views.count() == 1)
setCurrentView(view);
connect(view, &IDiffView::currentDiffFileIndexChanged, this, &DiffEditor::setCurrentDiffFileIndex);
}
IDiffView *DiffEditor::currentView() const
@@ -539,71 +644,42 @@ IDiffView *DiffEditor::nextView()
return m_views.at(pos);
}
void DiffEditor::showDiffView(IDiffView *newView)
void DiffEditor::setupView(IDiffView *view)
{
QTC_ASSERT(newView, return);
QTC_ASSERT(view, return);
setCurrentView(view);
if (currentView() == newView)
saveSetting(QLatin1String(diffViewKeyC), currentView()->id().toSetting());
m_toggleSyncAction->setVisible(currentView()->supportsSync());
m_toggleSyncAction->setToolTip(currentView()->syncToolTip());
m_toggleSyncAction->setChecked(m_sync);
view->setDocument(m_document.data());
view->setSync(m_sync);
view->beginOperation();
view->setDiff(m_document->diffFiles(), m_document->baseDirectory());
view->endOperation(true);
view->setCurrentDiffFileIndex(m_currentDiffFileIndex);
m_stackedWidget->setCurrentWidget(view->widget());
updateDiffEditorSwitcher();
if (widget())
widget()->setFocusProxy(view->widget());
}
void DiffEditor::showDiffView(IDiffView *view)
{
if (currentView() == view)
return;
if (currentView()) // during initialization
currentView()->setDiffEditorGuiController(0);
setCurrentView(newView);
currentView()->setDiffEditorGuiController(m_guiController);
currentView()->setDocument(0);
m_stackedWidget->setCurrentWidget(currentView()->widget());
writeCurrentDiffEditorSetting(currentView());
updateDiffEditorSwitcher();
widget()->setFocusProxy(currentView()->widget());
}
// TODO: Remove in 3.6:
IDiffView *DiffEditor::readLegacyCurrentDiffEditorSetting()
{
QTC_ASSERT(!m_views.isEmpty(), return 0);
QTC_ASSERT(m_views.count() == 2, return m_views.at(0));
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(legacySettingsGroupC));
const bool legacyExists = s->contains(QLatin1String(useDiffEditorKeyC));
const bool legacyEditor = s->value(
QLatin1String(useDiffEditorKeyC), true).toBool();
if (legacyExists)
s->remove(QLatin1String(useDiffEditorKeyC));
s->endGroup();
IDiffView *currentEditor = m_views.at(0);
if (!legacyEditor)
currentEditor = m_views.at(1);
if (legacyExists)
writeCurrentDiffEditorSetting(currentEditor);
return currentEditor;
}
IDiffView *DiffEditor::readCurrentDiffEditorSetting()
{
// replace it with m_sideBySideEditor when dropping legacy stuff
IDiffView *view = readLegacyCurrentDiffEditorSetting();
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
const Core::Id id = Core::Id::fromSetting(s->value(QLatin1String(diffEditorTypeKeyC)));
s->endGroup();
return Utils::findOr(m_views, view, [id](IDiffView *v) { return v->id() == id; });
}
void DiffEditor::writeCurrentDiffEditorSetting(IDiffView *currentEditor)
{
QTC_ASSERT(currentEditor, return);
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(diffEditorTypeKeyC), currentEditor->id().toSetting());
s->endGroup();
QTC_ASSERT(view, return);
setupView(view);
}
} // namespace Internal
+25 -19
View File
@@ -38,6 +38,7 @@
QT_BEGIN_NAMESPACE
class QComboBox;
class QSpinBox;
class QToolBar;
class QToolButton;
class QStackedWidget;
@@ -50,7 +51,6 @@ namespace DiffEditor {
namespace Internal {
class DescriptionEditorWidget;
class DiffEditorDocument;
class DiffEditorGuiController;
class IDiffView;
class DiffEditor : public Core::IEditor
@@ -62,8 +62,6 @@ public:
~DiffEditor();
public:
DiffEditorController *controller() const;
Core::IEditor *duplicate();
bool open(QString *errorString,
@@ -73,44 +71,52 @@ public:
QWidget *toolBar();
public slots:
void activateEntry(int index);
private slots:
void slotCleared(const QString &message);
void slotDiffFilesChanged(const QList<FileData> &diffFileList,
const QString &workingDirectory);
void entryActivated(int index);
void slotDescriptionChanged(const QString &description);
void slotDescriptionVisibilityChanged();
void slotReloaderChanged();
void documentHasChanged();
void toggleDescription();
void updateDescription();
void contextLineCountHasChanged(int lines);
void ignoreWhitespaceHasChanged(bool ignore);
void prepareForReload();
void reloadHasFinished(bool success);
void setCurrentDiffFileIndex(int index);
void documentStateChanged();
void toggleSync();
private:
void loadSettings();
void saveSetting(const QString &key, const QVariant &value) const;
void updateEntryToolTip();
void showDiffView(IDiffView *newEditor);
void showDiffView(IDiffView *view);
void updateDiffEditorSwitcher();
void addView(IDiffView *view);
IDiffView *currentView() const;
void setCurrentView(IDiffView *view);
IDiffView *nextView();
IDiffView *readLegacyCurrentDiffEditorSetting();
IDiffView *readCurrentDiffEditorSetting();
void writeCurrentDiffEditorSetting(IDiffView *currentEditor);
void setupView(IDiffView *view);
QSharedPointer<DiffEditorDocument> m_document;
DescriptionEditorWidget *m_descriptionWidget;
QStackedWidget *m_stackedWidget;
QVector<IDiffView *> m_views;
int m_currentViewIndex;
DiffEditorGuiController *m_guiController;
QToolBar *m_toolBar;
QComboBox *m_entriesComboBox;
QToolButton *m_whitespaceButton;
QSpinBox *m_contextSpinBox;
QAction *m_toggleSyncAction;
QAction *m_whitespaceButtonAction;
QAction *m_contextLabelAction;
QAction *m_contextSpinBoxAction;
QAction *m_toggleDescriptionAction;
QAction *m_reloadAction;
QToolButton *m_diffEditorSwitcher;
QPair<QString, QString> m_currentFileChunk;
int m_currentViewIndex;
int m_currentDiffFileIndex;
bool m_sync;
bool m_showDescription;
bool m_ignoreChanges;
};
} // namespace Internal
-4
View File
@@ -7,10 +7,8 @@ HEADERS += diffeditor_global.h \
diffeditorcontroller.h \
diffeditordocument.h \
diffeditorfactory.h \
diffeditorguicontroller.h \
diffeditormanager.h \
diffeditorplugin.h \
diffeditorreloader.h \
differ.h \
diffutils.h \
diffview.h \
@@ -22,10 +20,8 @@ SOURCES += diffeditor.cpp \
diffeditorcontroller.cpp \
diffeditordocument.cpp \
diffeditorfactory.cpp \
diffeditorguicontroller.cpp \
diffeditormanager.cpp \
diffeditorplugin.cpp \
diffeditorreloader.cpp \
differ.cpp \
diffutils.cpp \
diffview.cpp \
-4
View File
@@ -21,14 +21,10 @@ QtcPlugin {
"diffeditordocument.h",
"diffeditorfactory.cpp",
"diffeditorfactory.h",
"diffeditorguicontroller.cpp",
"diffeditorguicontroller.h",
"diffeditormanager.cpp",
"diffeditormanager.h",
"diffeditorplugin.cpp",
"diffeditorplugin.h",
"diffeditorreloader.cpp",
"diffeditorreloader.h",
"differ.cpp",
"differ.h",
"diffutils.cpp",
+59 -225
View File
@@ -30,227 +30,90 @@
#include "diffeditorconstants.h"
#include "diffeditorcontroller.h"
#include "diffeditorreloader.h"
#include "diffeditordocument.h"
#include <coreplugin/icore.h>
#include <QStringList>
#include <utils/qtcassert.h>
static const char settingsGroupC[] = "DiffEditor";
static const char contextLineNumbersKeyC[] = "ContextLineNumbers";
static const char ignoreWhitespaceKeyC[] = "IgnoreWhitespace";
#include <QStringList>
namespace DiffEditor {
DiffEditorController::DiffEditorController(QObject *parent)
: QObject(parent),
m_reloader(0),
m_contextLinesNumber(3),
m_diffFileIndex(-1),
m_chunkIndex(-1),
m_descriptionEnabled(false),
m_contextLinesNumberEnabled(true),
m_ignoreWhitespace(true)
DiffEditorController::DiffEditorController(Core::IDocument *document) :
QObject(document),
m_document(qobject_cast<Internal::DiffEditorDocument *>(document)),
m_isReloading(false),
m_diffFileIndex(-1),
m_chunkIndex(-1)
{
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
m_contextLinesNumber = s->value(QLatin1String(contextLineNumbersKeyC),
m_contextLinesNumber).toInt();
m_ignoreWhitespace = s->value(QLatin1String(ignoreWhitespaceKeyC),
m_ignoreWhitespace).toBool();
s->endGroup();
clear();
QTC_ASSERT(m_document, return);
QTC_CHECK(!m_document->controller());
m_document->setController(this);
}
DiffEditorController::~DiffEditorController()
bool DiffEditorController::isReloading() const
{
delete m_reloader;
return m_isReloading;
}
QString DiffEditorController::clearMessage() const
QString DiffEditorController::baseDirectory() const
{
return m_clearMessage;
return m_document->baseDirectory();
}
QList<FileData> DiffEditorController::diffFiles() const
int DiffEditorController::contextLineCount() const
{
return m_diffFiles;
return m_document->contextLineCount();
}
QString DiffEditorController::workingDirectory() const
bool DiffEditorController::ignoreWhitespace() const
{
return m_workingDirectory;
return m_document->ignoreWhitespace();
}
QString DiffEditorController::description() const
QString DiffEditorController::revisionFromDescription() const
{
return m_description;
}
bool DiffEditorController::isDescriptionEnabled() const
{
return m_descriptionEnabled;
}
int DiffEditorController::contextLinesNumber() const
{
return m_contextLinesNumber;
}
bool DiffEditorController::isContextLinesNumberEnabled() const
{
return m_contextLinesNumberEnabled;
}
bool DiffEditorController::isIgnoreWhitespace() const
{
return m_ignoreWhitespace;
}
// ### fixme: git-specific handling should be done in the git plugin:
// Remove unexpanded branches and follows-tag, clear indentation
// and create E-mail
static void formatGitDescription(QString *description)
{
QString result;
result.reserve(description->size());
foreach (QString line, description->split(QLatin1Char('\n'))) {
if (line.startsWith(QLatin1String("commit "))
|| line.startsWith(QLatin1String("Branches: <Expand>"))) {
continue;
}
if (line.startsWith(QLatin1String("Author: ")))
line.replace(0, 8, QStringLiteral("From: "));
else if (line.startsWith(QLatin1String(" ")))
line.remove(0, 4);
result.append(line);
result.append(QLatin1Char('\n'));
}
*description = result;
}
QString DiffEditorController::contents() const
{
QString result = m_description;
const int formattingOptions = DiffUtils::GitFormat;
if (formattingOptions & DiffUtils::GitFormat)
formatGitDescription(&result);
const QString diff = DiffUtils::makePatch(diffFiles(), formattingOptions);
if (!diff.isEmpty()) {
if (!result.isEmpty())
result += QLatin1Char('\n');
result += diff;
}
return result;
// TODO: This is specific for git and does not belong here at all!
return m_document->description().mid(7, 12);
}
QString DiffEditorController::makePatch(bool revert, bool addPrefix) const
{
if (m_diffFileIndex < 0 || m_chunkIndex < 0)
return QString();
if (m_diffFileIndex >= m_diffFiles.count())
return QString();
const FileData fileData = m_diffFiles.at(m_diffFileIndex);
if (m_chunkIndex >= fileData.chunks.count())
return QString();
const ChunkData chunkData = fileData.chunks.at(m_chunkIndex);
const bool lastChunk = (m_chunkIndex == fileData.chunks.count() - 1);
const QString fileName = revert
? fileData.rightFileInfo.fileName
: fileData.leftFileInfo.fileName;
QString leftPrefix, rightPrefix;
if (addPrefix) {
leftPrefix = QLatin1String("a/");
rightPrefix = QLatin1String("b/");
}
return DiffUtils::makePatch(chunkData,
leftPrefix + fileName,
rightPrefix + fileName,
lastChunk && fileData.lastChunkAtTheEndOfFile);
}
DiffEditorReloader *DiffEditorController::reloader() const
{
return m_reloader;
}
// The ownership of reloader is passed to the controller
void DiffEditorController::setReloader(DiffEditorReloader *reloader)
{
if (m_reloader == reloader)
return; // nothing changes
delete m_reloader;
m_reloader = reloader;
if (m_reloader)
m_reloader->setController(this);
emit reloaderChanged();
}
void DiffEditorController::clear()
{
clear(tr("No difference"));
}
void DiffEditorController::clear(const QString &message)
{
setDescription(QString());
setDiffFiles(QList<FileData>());
m_clearMessage = message;
emit cleared(message);
return m_document->makePatch(m_diffFileIndex, m_chunkIndex, revert, addPrefix);
}
void DiffEditorController::setDiffFiles(const QList<FileData> &diffFileList,
const QString &workingDirectory)
{
m_diffFiles = diffFileList;
m_workingDirectory = workingDirectory;
emit diffFilesChanged(diffFileList, workingDirectory);
m_document->setDiffFiles(diffFileList, workingDirectory);
}
void DiffEditorController::setDescription(const QString &description)
{
if (m_description == description)
return;
m_description = description;
emit descriptionChanged(m_description);
m_document->setDescription(description);
}
void DiffEditorController::setDescriptionEnabled(bool on)
{
if (m_descriptionEnabled == on)
return;
m_descriptionEnabled = on;
emit descriptionEnablementChanged(on);
}
void DiffEditorController::branchesForCommitReceived(const QString &output)
void DiffEditorController::informationForCommitReceived(const QString &output)
{
// TODO: Git specific code...
const QString branches = prepareBranchesForCommit(output);
m_description.replace(QLatin1String(Constants::EXPAND_BRANCHES), branches);
emit descriptionChanged(m_description);
QString tmp = m_document->description();
tmp.replace(QLatin1String(Constants::EXPAND_BRANCHES), branches);
m_document->setDescription(tmp);
}
void DiffEditorController::expandBranchesRequested()
void DiffEditorController::requestMoreInformation()
{
emit requestBranchList(m_description.mid(7, 8));
const QString rev = revisionFromDescription();
if (!rev.isEmpty())
emit requestInformationForCommit(rev);
}
QString DiffEditorController::prepareBranchesForCommit(const QString &output)
{
// TODO: More git-specific code...
QString moreBranches;
QString branches;
QStringList res;
@@ -274,69 +137,40 @@ QString DiffEditorController::prepareBranchesForCommit(const QString &output)
return branches;
}
void DiffEditorController::setContextLinesNumber(int lines)
/**
* @brief Force the lines of context to the given number.
*
* The user will not be able to change the context lines anymore. This needs to be set before
* starting any operation or the flag will be ignored by the UI.
*
* @param lines Lines of context to display.
*/
void DiffEditorController::forceContextLineCount(int lines)
{
const int l = qMax(lines, 1);
if (m_contextLinesNumber == l)
return;
m_contextLinesNumber = l;
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(contextLineNumbersKeyC), m_contextLinesNumber);
s->endGroup();
emit contextLinesNumberChanged(l);
}
void DiffEditorController::setContextLinesNumberEnabled(bool on)
{
if (m_contextLinesNumberEnabled == on)
return;
m_contextLinesNumberEnabled = on;
emit contextLinesNumberEnablementChanged(on);
}
void DiffEditorController::setIgnoreWhitespace(bool ignore)
{
if (m_ignoreWhitespace == ignore)
return;
m_ignoreWhitespace = ignore;
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(ignoreWhitespaceKeyC), m_ignoreWhitespace);
s->endGroup();
emit ignoreWhitespaceChanged(ignore);
m_document->forceContextLineCount(lines);
}
/**
* @brief Request the diff data to be re-read.
*/
void DiffEditorController::requestReload()
{
if (m_reloader)
m_reloader->requestReload();
m_isReloading = true;
m_document->beginReload();
reload();
}
void DiffEditorController::requestChunkActions(QMenu *menu,
int diffFileIndex,
int chunkIndex)
void DiffEditorController::reloadFinished(bool success)
{
m_document->endReload(success);
m_isReloading = false;
}
void DiffEditorController::requestChunkActions(QMenu *menu, int diffFileIndex, int chunkIndex)
{
m_diffFileIndex = diffFileIndex;
m_chunkIndex = chunkIndex;
emit chunkActionsRequested(menu, diffFileIndex >= 0 && chunkIndex >= 0);
}
void DiffEditorController::requestSaveState()
{
emit saveStateRequested();
}
void DiffEditorController::requestRestoreState()
{
emit restoreStateRequested();
}
} // namespace DiffEditor
+36 -54
View File
@@ -36,81 +36,63 @@
#include <QObject>
QT_FORWARD_DECLARE_CLASS(QMenu)
namespace Core { class IDocument; }
namespace DiffEditor {
class DiffEditorReloader;
namespace Internal { class DiffEditorDocument; }
class DIFFEDITOR_EXPORT DiffEditorController : public QObject
{
Q_OBJECT
public:
DiffEditorController(QObject *parent = 0);
~DiffEditorController();
explicit DiffEditorController(Core::IDocument *document);
QString clearMessage() const;
void requestReload();
bool isReloading() const;
QList<FileData> diffFiles() const;
QString workingDirectory() const;
QString description() const;
bool isDescriptionEnabled() const;
int contextLinesNumber() const;
bool isContextLinesNumberEnabled() const;
bool isIgnoreWhitespace() const;
QString baseDirectory() const;
int contextLineCount() const;
bool ignoreWhitespace() const;
QString revisionFromDescription() const;
QString makePatch(bool revert, bool addPrefix = false) const;
QString contents() const;
DiffEditorReloader *reloader() const;
void setReloader(DiffEditorReloader *reloader);
public slots:
void clear();
void clear(const QString &message);
void setDiffFiles(const QList<FileData> &diffFileList,
const QString &workingDirectory = QString());
void setDescription(const QString &description);
void setDescriptionEnabled(bool on);
void setContextLinesNumber(int lines);
void setContextLinesNumberEnabled(bool on);
void setIgnoreWhitespace(bool ignore);
void requestReload();
void requestChunkActions(QMenu *menu,
int diffFileIndex,
int chunkIndex);
void requestSaveState();
void requestRestoreState();
void branchesForCommitReceived(const QString &output);
void expandBranchesRequested();
void informationForCommitReceived(const QString &output);
signals:
void cleared(const QString &message);
void diffFilesChanged(const QList<FileData> &diffFileList,
const QString &workingDirectory);
void descriptionChanged(const QString &description);
void descriptionEnablementChanged(bool on);
void contextLinesNumberChanged(int lines);
void contextLinesNumberEnablementChanged(bool on);
void ignoreWhitespaceChanged(bool ignore);
void chunkActionsRequested(QMenu *menu, bool isValid);
void saveStateRequested();
void restoreStateRequested();
void requestBranchList(const QString &revision);
void reloaderChanged();
void requestInformationForCommit(const QString &revision);
protected:
// reloadFinished() should be called
// inside reload() (for synchronous reload)
// or later (for asynchronous reload)
virtual void reload() = 0;
void reloadFinished(bool success);
void setDiffFiles(const QList<FileData> &diffFileList,
const QString &baseDirectory = QString());
void setDescription(const QString &description);
void forceContextLineCount(int lines);
private:
QString prepareBranchesForCommit(const QString &output);
QString m_clearMessage;
void requestMoreInformation();
void requestChunkActions(QMenu *menu, int diffFileIndex, int chunkIndex);
QList<FileData> m_diffFiles;
QString m_workingDirectory;
QString m_description;
DiffEditorReloader *m_reloader;
int m_contextLinesNumber;
QString prepareBranchesForCommit(const QString &output);
Internal::DiffEditorDocument *const m_document;
bool m_isReloading;
int m_diffFileIndex;
int m_chunkIndex;
bool m_descriptionEnabled;
bool m_contextLinesNumberEnabled;
bool m_ignoreWhitespace;
friend class Internal::DiffEditorDocument;
};
} // namespace DiffEditor
+224 -43
View File
@@ -32,33 +32,165 @@
#include "diffeditorconstants.h"
#include "diffeditorcontroller.h"
#include "diffeditormanager.h"
#include "diffeditorreloader.h"
#include "diffutils.h"
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <coreplugin/editormanager/editormanager.h>
#include <QCoreApplication>
#include <QFile>
#include <QDir>
#include <QMenu>
#include <QTextCodec>
#include <QUuid>
using namespace Utils;
namespace DiffEditor {
namespace Internal {
DiffEditorDocument::DiffEditorDocument() :
Core::BaseTextDocument(),
m_controller(new DiffEditorController(this))
m_controller(0),
m_contextLineCount(3),
m_isContextLineCountForced(false),
m_ignoreWhitespace(false)
{
setId(Constants::DIFF_EDITOR_ID);
setMimeType(QLatin1String(Constants::DIFF_EDITOR_MIMETYPE));
setTemporary(true);
}
DiffEditorDocument::~DiffEditorDocument()
{
DiffEditorManager::removeDocument(this);
}
/**
* @brief Set a controller for a document
* @param controller The controller to set.
*
* This method takes ownership of the controller and will delete it after it is done with it.
*/
void DiffEditorDocument::setController(DiffEditorController *controller)
{
QTC_ASSERT(isTemporary(), return);
if (m_controller == controller)
return;
if (m_controller)
m_controller->deleteLater();
m_controller = controller;
if (m_controller) {
connect(this, &DiffEditorDocument::chunkActionsRequested,
m_controller, &DiffEditorController::requestChunkActions);
connect(this, &DiffEditorDocument::requestMoreInformation,
m_controller, &DiffEditorController::requestMoreInformation);
}
}
DiffEditorController *DiffEditorDocument::controller() const
{
return m_controller;
}
QString DiffEditorDocument::makePatch(int fileIndex, int chunkIndex, bool revert, bool addPrefix) const
{
if (fileIndex < 0 || chunkIndex < 0)
return QString();
if (fileIndex >= m_diffFiles.count())
return QString();
const FileData &fileData = m_diffFiles.at(fileIndex);
if (chunkIndex >= fileData.chunks.count())
return QString();
const ChunkData &chunkData = fileData.chunks.at(chunkIndex);
const bool lastChunk = (chunkIndex == fileData.chunks.count() - 1);
const QString fileName = revert
? fileData.rightFileInfo.fileName
: fileData.leftFileInfo.fileName;
QString leftPrefix, rightPrefix;
if (addPrefix) {
leftPrefix = QLatin1String("a/");
rightPrefix = QLatin1String("b/");
}
return DiffUtils::makePatch(chunkData,
leftPrefix + fileName,
rightPrefix + fileName,
lastChunk && fileData.lastChunkAtTheEndOfFile);
}
void DiffEditorDocument::setDiffFiles(const QList<FileData> &data, const QString &directory)
{
m_diffFiles = data;
m_baseDirectory = directory;
emit documentChanged();
}
QList<FileData> DiffEditorDocument::diffFiles() const
{
return m_diffFiles;
}
QString DiffEditorDocument::baseDirectory() const
{
return m_baseDirectory;
}
void DiffEditorDocument::setDescription(const QString &description)
{
if (m_description == description)
return;
m_description = description;
emit descriptionChanged();
}
QString DiffEditorDocument::description() const
{
return m_description;
}
void DiffEditorDocument::setContextLineCount(int lines)
{
m_contextLineCount = lines;
}
int DiffEditorDocument::contextLineCount() const
{
return m_contextLineCount;
}
void DiffEditorDocument::forceContextLineCount(int lines)
{
m_contextLineCount = lines;
m_isContextLineCountForced = true;
}
bool DiffEditorDocument::isContextLineCountForced() const
{
return m_isContextLineCountForced;
}
void DiffEditorDocument::setIgnoreWhitespace(bool ignore)
{
if (m_isContextLineCountForced)
return;
m_ignoreWhitespace = ignore;
}
bool DiffEditorDocument::ignoreWhitespace() const
{
return m_ignoreWhitespace;
}
bool DiffEditorDocument::setContents(const QByteArray &contents)
{
Q_UNUSED(contents);
@@ -67,7 +199,9 @@ bool DiffEditorDocument::setContents(const QByteArray &contents)
QString DiffEditorDocument::defaultPath() const
{
return m_controller->workingDirectory();
if (!m_baseDirectory.isEmpty())
return m_baseDirectory;
return QDir::homePath();
}
bool DiffEditorDocument::save(QString *errorString, const QString &fileName, bool autoSave)
@@ -75,23 +209,35 @@ bool DiffEditorDocument::save(QString *errorString, const QString &fileName, boo
Q_UNUSED(errorString)
Q_UNUSED(autoSave)
const bool ok = write(fileName, format(), m_controller->contents(), errorString);
const bool ok = write(fileName, format(), plainText(), errorString);
if (!ok)
return false;
m_controller->setReloader(0);
m_controller->setDescription(QString());
m_controller->setDescriptionEnabled(false);
DiffEditorManager::removeDocument(this);
setController(0);
setDescription(QString());
const QFileInfo fi(fileName);
setTemporary(false);
setFilePath(Utils::FileName::fromString(fi.absoluteFilePath()));
setFilePath(FileName::fromString(fi.absoluteFilePath()));
setPreferredDisplayName(QString());
emit temporaryStateChanged();
return true;
}
void DiffEditorDocument::reload()
{
if (m_controller) {
m_controller->requestReload();
} else {
QString errorMessage;
reload(&errorMessage, Core::IDocument::FlagReload, Core::IDocument::TypeContents);
}
}
bool DiffEditorDocument::reload(QString *errorString, ReloadFlag flag, ChangeType type)
{
Q_UNUSED(type)
@@ -102,8 +248,10 @@ bool DiffEditorDocument::reload(QString *errorString, ReloadFlag flag, ChangeTyp
bool DiffEditorDocument::open(QString *errorString, const QString &fileName)
{
QTC_ASSERT(errorString, return false);
beginReload();
QString patch;
if (read(fileName, &patch, errorString) != Utils::TextFileFormat::ReadSuccess)
if (read(fileName, &patch, errorString) != TextFileFormat::ReadSuccess)
return false;
bool ok = false;
@@ -112,49 +260,82 @@ bool DiffEditorDocument::open(QString *errorString, const QString &fileName)
*errorString = tr("Could not parse patch file \"%1\". "
"The content is not of unified diff format.")
.arg(fileName);
return false;
} else {
const QFileInfo fi(fileName);
setTemporary(false);
emit temporaryStateChanged();
setFilePath(FileName::fromString(fi.absoluteFilePath()));
setDiffFiles(fileDataList, fi.absolutePath());
}
const QFileInfo fi(fileName);
setTemporary(false);
setFilePath(Utils::FileName::fromString(fi.absoluteFilePath()));
m_controller->setDiffFiles(fileDataList, fi.absolutePath());
return true;
endReload(ok);
return ok;
}
QString DiffEditorDocument::suggestedFileName() const
{
enum { maxSubjectLength = 50 };
QString result = QStringLiteral("0001");
const QString description = m_controller->description();
if (!description.isEmpty()) {
// Derive "git format-patch-type" file name from subject.
const int pos = description.indexOf(QLatin1String("\n\n "));
const int endPos = pos >= 0 ? description.indexOf(QLatin1Char('\n'), pos + 6) : -1;
if (endPos > pos) {
const QChar space(QLatin1Char(' '));
const QChar dash(QLatin1Char('-'));
QString subject = description.mid(pos, endPos - pos);
for (int i = 0; i < subject.size(); ++i) {
if (!subject.at(i).isLetterOrNumber())
subject[i] = space;
}
subject = subject.simplified();
if (subject.size() > maxSubjectLength) {
const int lastSpace = subject.lastIndexOf(space, maxSubjectLength);
subject.truncate(lastSpace > 0 ? lastSpace : maxSubjectLength);
}
subject.replace(space, dash);
result += dash;
result += subject;
}
const int maxSubjectLength = 50;
const QString desc = description();
if (!desc.isEmpty()) {
QString name = QString::fromLatin1("0001-%1").arg(desc.left(desc.indexOf(QLatin1Char('\n'))));
name = FileUtils::fileSystemFriendlyName(name);
name.truncate(maxSubjectLength);
name.append(QLatin1String(".patch"));
return name;
}
return result + QStringLiteral(".patch");
return QStringLiteral("0001.patch");
}
// ### fixme: git-specific handling should be done in the git plugin:
// Remove unexpanded branches and follows-tag, clear indentation
// and create E-mail
static void formatGitDescription(QString *description)
{
QString result;
result.reserve(description->size());
foreach (QString line, description->split(QLatin1Char('\n'))) {
if (line.startsWith(QLatin1String("commit "))
|| line.startsWith(QLatin1String("Branches: <Expand>"))) {
continue;
}
if (line.startsWith(QLatin1String("Author: ")))
line.replace(0, 8, QStringLiteral("From: "));
else if (line.startsWith(QLatin1String(" ")))
line.remove(0, 4);
result.append(line);
result.append(QLatin1Char('\n'));
}
*description = result;
}
QString DiffEditorDocument::plainText() const
{
return m_controller->contents();
QString result = description();
const int formattingOptions = DiffUtils::GitFormat;
if (formattingOptions & DiffUtils::GitFormat)
formatGitDescription(&result);
const QString diff = DiffUtils::makePatch(diffFiles(), formattingOptions);
if (!diff.isEmpty()) {
if (!result.isEmpty())
result += QLatin1Char('\n');
result += diff;
}
return result;
}
void DiffEditorDocument::beginReload()
{
emit aboutToReload();
const bool blocked = blockSignals(true);
setDiffFiles(QList<FileData>(), QString());
setDescription(QString());
blockSignals(blocked);
}
void DiffEditorDocument::endReload(bool success)
{
emit reloadFinished(success);
}
} // namespace Internal
+44 -1
View File
@@ -31,8 +31,12 @@
#ifndef DIFFEDITORDOCUMENT_H
#define DIFFEDITORDOCUMENT_H
#include "diffutils.h"
#include <coreplugin/textdocument.h>
QT_FORWARD_DECLARE_CLASS(QMenu)
namespace DiffEditor {
class DiffEditorController;
@@ -45,9 +49,26 @@ class DiffEditorDocument : public Core::BaseTextDocument
Q_PROPERTY(QString plainText READ plainText STORED false) // For access by code pasters
public:
DiffEditorDocument();
~DiffEditorDocument();
DiffEditorController *controller() const;
QString makePatch(int fileIndex, int chunkIndex, bool revert, bool addPrefix = false) const;
void setDiffFiles(const QList<FileData> &data, const QString &directory);
QList<FileData> diffFiles() const;
QString baseDirectory() const;
void setDescription(const QString &description);
QString description() const;
void setContextLineCount(int lines);
int contextLineCount() const;
void forceContextLineCount(int lines);
bool isContextLineCountForced() const;
void setIgnoreWhitespace(bool ignore);
bool ignoreWhitespace() const;
bool setContents(const QByteArray &contents);
QString defaultPath() const;
QString suggestedFileName() const Q_DECL_OVERRIDE;
@@ -55,13 +76,35 @@ public:
bool isModified() const { return false; }
bool isSaveAsAllowed() const { return true; }
bool save(QString *errorString, const QString &fileName, bool autoSave);
void reload();
bool reload(QString *errorString, ReloadFlag flag, ChangeType type);
bool open(QString *errorString, const QString &fileName);
QString plainText() const;
signals:
void temporaryStateChanged();
void documentChanged();
void descriptionChanged();
void chunkActionsRequested(QMenu *menu, int diffFileIndex, int chunkIndex);
void requestMoreInformation();
public slots:
void beginReload();
void endReload(bool success);
private:
DiffEditorController *const m_controller;
void setController(DiffEditorController *controller);
DiffEditorController *m_controller;
QList<FileData> m_diffFiles;
QString m_baseDirectory;
QString m_description;
int m_contextLineCount;
bool m_isContextLineCountForced;
bool m_ignoreWhitespace;
friend class ::DiffEditor::DiffEditorController;
};
} // namespace Internal
@@ -33,8 +33,6 @@
#include "diffeditor_global.h"
#include <QStringList>
#include <coreplugin/editormanager/ieditorfactory.h>
namespace DiffEditor {
@@ -1,143 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "diffeditorguicontroller.h"
#include "diffeditorcontroller.h"
#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
static const char settingsGroupC[] = "DiffEditor";
static const char descriptionVisibleKeyC[] = "DescriptionVisible";
static const char horizontalScrollBarSynchronizationKeyC[] =
"HorizontalScrollBarSynchronization";
namespace DiffEditor {
namespace Internal {
DiffEditorGuiController::DiffEditorGuiController(
DiffEditorController *controller,
QObject *parent)
: QObject(parent),
m_controller(controller),
m_descriptionVisible(true),
m_syncScrollBars(true),
m_currentDiffFileIndex(-1)
{
QTC_ASSERT(m_controller, return);
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
m_descriptionVisible = s->value(QLatin1String(descriptionVisibleKeyC),
m_descriptionVisible).toBool();
m_syncScrollBars = s->value(QLatin1String(horizontalScrollBarSynchronizationKeyC),
m_syncScrollBars).toBool();
s->endGroup();
connect(m_controller, &DiffEditorController::cleared, this,
&DiffEditorGuiController::slotUpdateDiffFileIndex);
connect(m_controller, &DiffEditorController::diffFilesChanged, this,
&DiffEditorGuiController::slotUpdateDiffFileIndex);
slotUpdateDiffFileIndex();
}
DiffEditorController *DiffEditorGuiController::controller() const
{
return m_controller;
}
bool DiffEditorGuiController::isDescriptionVisible() const
{
return m_descriptionVisible;
}
bool DiffEditorGuiController::horizontalScrollBarSynchronization() const
{
return m_syncScrollBars;
}
int DiffEditorGuiController::currentDiffFileIndex() const
{
return m_currentDiffFileIndex;
}
void DiffEditorGuiController::slotUpdateDiffFileIndex()
{
m_currentDiffFileIndex = (m_controller->diffFiles().isEmpty() ? -1 : 0);
}
void DiffEditorGuiController::setDescriptionVisible(bool on)
{
if (m_descriptionVisible == on)
return;
m_descriptionVisible = on;
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(descriptionVisibleKeyC), m_descriptionVisible);
s->endGroup();
emit descriptionVisibilityChanged(on);
}
void DiffEditorGuiController::setHorizontalScrollBarSynchronization(bool on)
{
if (m_syncScrollBars == on)
return;
m_syncScrollBars = on;
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(horizontalScrollBarSynchronizationKeyC),
m_syncScrollBars);
s->endGroup();
emit horizontalScrollBarSynchronizationChanged(on);
}
void DiffEditorGuiController::setCurrentDiffFileIndex(int diffFileIndex)
{
if (m_controller->diffFiles().isEmpty())
return; // -1 is the only valid value in this case
const int newIndex = qBound(0, diffFileIndex,
m_controller->diffFiles().count() - 1);
if (m_currentDiffFileIndex == newIndex)
return;
m_currentDiffFileIndex = newIndex;
emit currentDiffFileIndexChanged(newIndex);
}
} // namespace Internal
} // namespace DiffEditor
@@ -1,78 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef DIFFEDITORGUICONTROLLER_H
#define DIFFEDITORGUICONTROLLER_H
#include <QObject>
namespace DiffEditor {
class DiffEditorController;
namespace Internal {
class DiffEditorGuiController : public QObject
{
Q_OBJECT
public:
DiffEditorGuiController(DiffEditorController *controller,
QObject *parent = 0);
DiffEditorController *controller() const;
bool isDescriptionVisible() const;
bool horizontalScrollBarSynchronization() const;
int currentDiffFileIndex() const;
public slots:
void setDescriptionVisible(bool on);
void setHorizontalScrollBarSynchronization(bool on);
void setCurrentDiffFileIndex(int diffFileIndex);
signals:
void descriptionVisibilityChanged(bool on);
void horizontalScrollBarSynchronizationChanged(bool on);
void currentDiffFileIndexChanged(int diffFileIndex);
private slots:
void slotUpdateDiffFileIndex();
private:
DiffEditorController *const m_controller;
bool m_descriptionVisible;
bool m_syncScrollBars;
int m_currentDiffFileIndex;
};
} // namespace Internal
} // namespace DiffEditor
#endif // DIFFEDITORGUICONTROLLER_H
+7 -26
View File
@@ -36,6 +36,9 @@
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/documentmodel.h>
#include <coreplugin/id.h>
#include <coreplugin/idocument.h>
#include <coreplugin/editormanager/ieditor.h>
#include <utils/qtcassert.h>
namespace DiffEditor {
@@ -49,10 +52,6 @@ DiffEditorManager::DiffEditorManager(QObject *parent)
{
QTC_ASSERT(!m_instance, return);
m_instance = this;
Core::EditorManager *editorManager = Core::EditorManager::instance();
connect(editorManager, &Core::EditorManager::editorsClosed,
this, &DiffEditorManager::slotEditorsClosed);
}
DiffEditorManager::~DiffEditorManager()
@@ -60,27 +59,11 @@ DiffEditorManager::~DiffEditorManager()
m_instance = 0;
}
void DiffEditorManager::slotEditorsClosed(const QList<Core::IEditor *> &editors)
{
QMap<Core::IDocument *, int> editorsForDocument;
for (int i = 0; i < editors.count(); i++) {
DiffEditor *diffEditor = qobject_cast<DiffEditor *>(editors.at(i));
if (diffEditor) {
Core::IDocument *document = diffEditor->document();
editorsForDocument[document]++;
}
}
QMapIterator<Core::IDocument *, int> it(editorsForDocument);
while (it.hasNext()) {
it.next();
if (Core::DocumentModel::editorsForDocument(it.key()).count() == 0) // no other editors use that document
removeDocument(it.key());
}
}
Core::IDocument *DiffEditorManager::find(const QString &vcsId)
{
return m_instance->m_idToDocument.value(vcsId);
Core::IDocument *document = m_instance->m_idToDocument.value(vcsId);
QTC_ASSERT(!document || document->isTemporary(), return 0);
return document;
}
Core::IDocument *DiffEditorManager::findOrCreate(const QString &vcsId, const QString &displayName)
@@ -89,10 +72,8 @@ Core::IDocument *DiffEditorManager::findOrCreate(const QString &vcsId, const QSt
if (document)
return document;
const QString msgWait = tr("Waiting for data...");
DiffEditor *diffEditor = qobject_cast<DiffEditor *>(
Core::EditorManager::openEditorWithContents(Constants::DIFF_EDITOR_ID,
0, msgWait.toUtf8()));
Core::EditorManager::openEditorWithContents(Constants::DIFF_EDITOR_ID, 0));
QTC_ASSERT(diffEditor, return 0);
document = qobject_cast<Internal::DiffEditorDocument *>(diffEditor->document());
+9 -9
View File
@@ -33,12 +33,13 @@
#include "diffeditor_global.h"
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/idocument.h>
#include <QMap>
#include <QObject>
namespace Core { class IDocument; }
namespace Core {
class IDocument;
class IEditor;
}
namespace DiffEditor {
@@ -53,17 +54,16 @@ public:
explicit DiffEditorManager(QObject *parent);
virtual ~DiffEditorManager();
static Core::IDocument *find(const QString &vcsId);
static Core::IDocument *findOrCreate(const QString &vcsId, const QString &displayName);
static DiffEditorController *controller(Core::IDocument *document);
private:
static Core::IDocument *find(const QString &vcsId);
static void removeDocument(Core::IDocument *document);
private slots:
void slotEditorsClosed(const QList<Core::IEditor *> &editors);
private:
QMap<QString, Internal::DiffEditorDocument *> m_idToDocument;
friend class Internal::DiffEditorDocument;
};
} // namespace DiffEditor
+31 -58
View File
@@ -31,10 +31,10 @@
#include "diffeditorplugin.h"
#include "diffeditor.h"
#include "diffeditorconstants.h"
#include "diffeditorcontroller.h"
#include "diffeditordocument.h"
#include "diffeditorfactory.h"
#include "diffeditormanager.h"
#include "diffeditorreloader.h"
#include "differ.h"
#include <QAction>
@@ -53,12 +53,12 @@
namespace DiffEditor {
namespace Internal {
class SimpleDiffEditorReloader : public DiffEditorReloader
class FileDiffController : public DiffEditorController
{
Q_OBJECT
public:
SimpleDiffEditorReloader(const QString &leftFileName,
const QString &rightFileName);
FileDiffController(Core::IDocument *document, const QString &leftFileName,
const QString &rightFileName);
protected:
void reload();
@@ -68,14 +68,12 @@ private:
QString m_rightFileName;
};
SimpleDiffEditorReloader::SimpleDiffEditorReloader(const QString &leftFileName,
const QString &rightFileName)
: m_leftFileName(leftFileName),
m_rightFileName(rightFileName)
{
}
FileDiffController::FileDiffController(Core::IDocument *document, const QString &leftFileName,
const QString &rightFileName) :
DiffEditorController(document), m_leftFileName(leftFileName), m_rightFileName(rightFileName)
{ }
void SimpleDiffEditorReloader::reload()
void FileDiffController::reload()
{
QString errorString;
Utils::TextFileFormat format;
@@ -86,7 +84,6 @@ void SimpleDiffEditorReloader::reload()
format.codec,
&leftText, &format, &errorString)
!= Utils::TextFileFormat::ReadSuccess) {
return;
}
@@ -95,13 +92,11 @@ void SimpleDiffEditorReloader::reload()
format.codec,
&rightText, &format, &errorString)
!= Utils::TextFileFormat::ReadSuccess) {
return;
}
Differ differ;
QList<Diff> diffList = differ.cleanupSemantics(
differ.diff(leftText, rightText));
QList<Diff> diffList = differ.cleanupSemantics(differ.diff(leftText, rightText));
QList<Diff> leftDiffList;
QList<Diff> rightDiffList;
@@ -109,15 +104,13 @@ void SimpleDiffEditorReloader::reload()
QList<Diff> outputLeftDiffList;
QList<Diff> outputRightDiffList;
if (controller()->isIgnoreWhitespace()) {
const QList<Diff> leftIntermediate =
Differ::moveWhitespaceIntoEqualities(leftDiffList);
const QList<Diff> rightIntermediate =
Differ::moveWhitespaceIntoEqualities(rightDiffList);
Differ::ignoreWhitespaceBetweenEqualities(leftIntermediate,
rightIntermediate,
&outputLeftDiffList,
&outputRightDiffList);
if (ignoreWhitespace()) {
const QList<Diff> leftIntermediate
= Differ::moveWhitespaceIntoEqualities(leftDiffList);
const QList<Diff> rightIntermediate
= Differ::moveWhitespaceIntoEqualities(rightDiffList);
Differ::ignoreWhitespaceBetweenEqualities(leftIntermediate, rightIntermediate,
&outputLeftDiffList, &outputRightDiffList);
} else {
outputLeftDiffList = leftDiffList;
outputRightDiffList = rightDiffList;
@@ -125,45 +118,31 @@ void SimpleDiffEditorReloader::reload()
const ChunkData chunkData = DiffUtils::calculateOriginalData(
outputLeftDiffList, outputRightDiffList);
FileData fileData = DiffUtils::calculateContextData(
chunkData, controller()->contextLinesNumber(), 0);
FileData fileData = DiffUtils::calculateContextData(chunkData, contextLineCount(), 0);
fileData.leftFileInfo.fileName = m_leftFileName;
fileData.rightFileInfo.fileName = m_rightFileName;
QList<FileData> fileDataList;
fileDataList << fileData;
controller()->requestSaveState();
controller()->setDiffFiles(fileDataList);
controller()->requestRestoreState();
reloadFinished();
setDiffFiles(fileDataList);
reloadFinished(true);
}
/////////////////
DiffEditorPlugin::DiffEditorPlugin()
{
}
DiffEditorPlugin::~DiffEditorPlugin()
{
}
bool DiffEditorPlugin::initialize(const QStringList &arguments, QString *errorMessage)
{
Q_UNUSED(arguments)
Q_UNUSED(errorMessage)
//register actions
Core::ActionContainer *toolsContainer =
Core::ActionManager::actionContainer(Core::Constants::M_TOOLS);
toolsContainer->insertGroup(Core::Constants::G_TOOLS_OPTIONS,
Constants::G_TOOLS_DIFF);
Core::ActionContainer *toolsContainer
= Core::ActionManager::actionContainer(Core::Constants::M_TOOLS);
toolsContainer->insertGroup(Core::Constants::G_TOOLS_OPTIONS, Constants::G_TOOLS_DIFF);
QAction *diffAction = new QAction(tr("Diff..."), this);
Core::Command *diffCommand = Core::ActionManager::registerAction(diffAction,
"DiffEditor.Diff");
Core::Command *diffCommand = Core::ActionManager::registerAction(diffAction, "DiffEditor.Diff");
connect(diffAction, &QAction::triggered, this, &DiffEditorPlugin::diff);
toolsContainer->addAction(diffCommand, Constants::G_TOOLS_DIFF);
@@ -175,8 +154,7 @@ bool DiffEditorPlugin::initialize(const QStringList &arguments, QString *errorMe
}
void DiffEditorPlugin::extensionsInitialized()
{
}
{ }
void DiffEditorPlugin::diff()
{
@@ -193,24 +171,19 @@ void DiffEditorPlugin::diff()
return;
const QString documentId = QLatin1String("Diff ") + fileName1
+ QLatin1String(", ") + fileName2;
const QString documentId = QLatin1String("Diff ") + fileName1 + QLatin1String(", ") + fileName2;
QString title = tr("Diff \"%1\", \"%2\"").arg(fileName1).arg(fileName2);
Core::IDocument *const document = DiffEditorManager::findOrCreate(documentId, title);
auto const document
= qobject_cast<DiffEditorDocument *>(DiffEditorManager::findOrCreate(documentId, title));
if (!document)
return;
DiffEditorController *controller = DiffEditorManager::controller(document);
if (!controller)
controller = new FileDiffController(document, fileName1, fileName2);
QTC_ASSERT(controller, return);
if (!controller->reloader()) {
SimpleDiffEditorReloader *reloader =
new SimpleDiffEditorReloader(fileName1, fileName2);
controller->setReloader(reloader);
}
Core::EditorManager::activateEditorForDocument(document);
controller->requestReload();
document->reload();
}
} // namespace Internal
@@ -44,9 +44,6 @@ class DiffEditorPlugin : public ExtensionSystem::IPlugin
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "DiffEditor.json")
public:
DiffEditorPlugin();
~DiffEditorPlugin();
bool initialize(const QStringList &arguments, QString *errorMessage = 0);
void extensionsInitialized();
@@ -1,97 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "diffeditorreloader.h"
#include "diffeditorcontroller.h"
namespace DiffEditor {
DiffEditorReloader::DiffEditorReloader()
: m_controller(0),
m_reloading(false)
{
}
DiffEditorReloader::~DiffEditorReloader()
{
}
DiffEditorController *DiffEditorReloader::controller() const
{
return m_controller;
}
void DiffEditorReloader::setController(DiffEditorController *controller)
{
if (m_controller == controller)
return; // nothing changes
if (m_controller) {
disconnect(m_controller, SIGNAL(ignoreWhitespaceChanged(bool)),
this, SLOT(requestReload()));
disconnect(m_controller, SIGNAL(contextLinesNumberChanged(int)),
this, SLOT(requestReload()));
}
m_controller = controller;
if (m_controller) {
connect(m_controller, &DiffEditorController::ignoreWhitespaceChanged,
this, &DiffEditorReloader::requestReload);
connect(m_controller, &DiffEditorController::contextLinesNumberChanged,
this, &DiffEditorReloader::requestReload);
}
}
void DiffEditorReloader::requestReload()
{
if (m_reloading)
return;
if (!m_controller)
return;
m_reloading = true;
reload();
}
bool DiffEditorReloader::isReloading() const
{
return m_reloading;
}
void DiffEditorReloader::reloadFinished()
{
m_reloading = false;
}
} // namespace DiffEditor
@@ -1,74 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef DIFFEDITORRELOADER_H
#define DIFFEDITORRELOADER_H
#include "diffeditor_global.h"
#include <QObject>
namespace DiffEditor {
class DiffEditorController;
class DIFFEDITOR_EXPORT DiffEditorReloader : public QObject
{
Q_OBJECT
public:
DiffEditorReloader();
~DiffEditorReloader();
bool isReloading() const;
DiffEditorController *controller() const;
public slots:
void requestReload();
protected:
// reloadFinished() should be called
// inside reload() (for synchronous reload)
// or later (for asynchronous reload)
virtual void reload() = 0;
void setController(DiffEditorController *controller);
protected slots:
void reloadFinished();
private:
DiffEditorController *m_controller;
bool m_reloading;
friend class DiffEditorController;
};
} // namespace DiffEditor
#endif // DIFFEDITORRELOADER_H
+4 -5
View File
@@ -263,11 +263,10 @@ ChunkData DiffUtils::calculateOriginalData(const QList<Diff> &leftDiffList,
return chunkData;
}
FileData DiffUtils::calculateContextData(const ChunkData &originalData,
int contextLinesNumber,
FileData DiffUtils::calculateContextData(const ChunkData &originalData, int contextLineCount,
int joinChunkThreshold)
{
if (contextLinesNumber < 0)
if (contextLineCount < 0)
return FileData(originalData);
FileData fileData;
@@ -292,9 +291,9 @@ FileData DiffUtils::calculateContextData(const ChunkData &originalData,
const bool last = i == originalData.rows.count(); // includes last line?
const int firstLine = first
? 0 : equalRowStart + contextLinesNumber;
? 0 : equalRowStart + contextLineCount;
const int lastLine = last
? originalData.rows.count() : i - contextLinesNumber;
? originalData.rows.count() : i - contextLineCount;
if (firstLine < lastLine - joinChunkThreshold) {
for (int j = firstLine; j < lastLine; j++) {
+1 -4
View File
@@ -35,9 +35,6 @@
#include <QString>
#include <QMap>
#include <QTextEdit>
#include "texteditor/texteditorconstants.h"
namespace TextEditor { class FontSettings; }
@@ -138,7 +135,7 @@ public:
static ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
const QList<Diff> &rightDiffList);
static FileData calculateContextData(const ChunkData &originalData,
int contextLinesNumber,
int contextLineCount,
int joinChunkThreshold = 1);
static QString makePatchLine(const QChar &startLineCharacter,
const QString &textLine,
+100 -6
View File
@@ -40,6 +40,9 @@
namespace DiffEditor {
namespace Internal {
IDiffView::IDiffView(QObject *parent) : QObject(parent), m_supportsSync(false)
{ }
QIcon IDiffView::icon() const
{
return m_icon;
@@ -50,6 +53,16 @@ QString IDiffView::toolTip() const
return m_toolTip;
}
bool IDiffView::supportsSync() const
{
return m_supportsSync;
}
QString IDiffView::syncToolTip() const
{
return m_syncToolTip;
}
Core::Id IDiffView::id() const
{
return m_id;
@@ -70,6 +83,16 @@ void IDiffView::setId(const Core::Id &id)
m_id = id;
}
void IDiffView::setSupportsSync(bool sync)
{
m_supportsSync = sync;
}
void IDiffView::setSyncToolTip(const QString &text)
{
m_syncToolTip = text;
}
UnifiedView::UnifiedView() : m_widget(0)
{
setId(UNIFIED_VIEW_ID);
@@ -79,15 +102,49 @@ UnifiedView::UnifiedView() : m_widget(0)
QWidget *UnifiedView::widget()
{
if (!m_widget)
if (!m_widget) {
m_widget = new UnifiedDiffEditorWidget;
connect(m_widget, &UnifiedDiffEditorWidget::currentDiffFileIndexChanged,
this, &UnifiedView::currentDiffFileIndexChanged);
}
return m_widget;
}
void UnifiedView::setDiffEditorGuiController(DiffEditorGuiController *controller)
void UnifiedView::setDocument(DiffEditorDocument *document)
{
QTC_ASSERT(m_widget, return);
m_widget->setDiffEditorGuiController(controller);
m_widget->setDocument(document);
}
void UnifiedView::beginOperation()
{
QTC_ASSERT(m_widget, return);
m_widget->saveState();
m_widget->clear(tr("Waiting for data..."));
}
void UnifiedView::setDiff(const QList<FileData> &diffFileList, const QString &workingDirectory)
{
QTC_ASSERT(m_widget, return);
m_widget->setDiff(diffFileList, workingDirectory);
}
void UnifiedView::endOperation(bool success)
{
Q_UNUSED(success);
QTC_ASSERT(m_widget, return);
m_widget->restoreState();
}
void UnifiedView::setCurrentDiffFileIndex(int index)
{
QTC_ASSERT(m_widget, return);
m_widget->setCurrentDiffFileIndex(index);
}
void UnifiedView::setSync(bool sync)
{
Q_UNUSED(sync);
}
SideBySideView::SideBySideView() : m_widget(0)
@@ -96,19 +153,56 @@ SideBySideView::SideBySideView() : m_widget(0)
setIcon(QIcon(QLatin1String(":/diffeditor/images/sidebysidediff.png")));
setToolTip(QCoreApplication::translate("DiffEditor::SideBySideView",
"Switch to Side By Side Diff Editor"));
setSupportsSync(true);
setSyncToolTip(tr("Synchronize Horizontal Scroll Bars"));
}
QWidget *SideBySideView::widget()
{
if (!m_widget)
if (!m_widget) {
m_widget = new SideBySideDiffEditorWidget;
connect(m_widget, &SideBySideDiffEditorWidget::currentDiffFileIndexChanged,
this, &SideBySideView::currentDiffFileIndexChanged);
}
return m_widget;
}
void SideBySideView::setDiffEditorGuiController(DiffEditorGuiController *controller)
void SideBySideView::setDocument(DiffEditorDocument *document)
{
QTC_ASSERT(m_widget, return);
m_widget->setDiffEditorGuiController(controller);
m_widget->setDocument(document);
}
void SideBySideView::beginOperation()
{
QTC_ASSERT(m_widget, return);
m_widget->saveState();
m_widget->clear(tr("Waiting for data..."));
}
void SideBySideView::setCurrentDiffFileIndex(int index)
{
QTC_ASSERT(m_widget, return);
m_widget->setCurrentDiffFileIndex(index);
}
void SideBySideView::setDiff(const QList<FileData> &diffFileList, const QString &workingDirectory)
{
QTC_ASSERT(m_widget, return);
m_widget->setDiff(diffFileList, workingDirectory);
}
void SideBySideView::endOperation(bool success)
{
Q_UNUSED(success);
QTC_ASSERT(m_widget, return);
m_widget->restoreState();
}
void SideBySideView::setSync(bool sync)
{
QTC_ASSERT(m_widget, return);
m_widget->setHorizontalSync(sync);
}
} // namespace Internal
+53 -10
View File
@@ -35,59 +35,102 @@
#include <QIcon>
#include <QString>
#include <QWidget>
#include <QObject>
QT_FORWARD_DECLARE_CLASS(QWidget)
namespace DiffEditor {
class DiffEditorController;
class FileData;
namespace Internal {
class DiffEditorGuiController;
class DiffEditorDocument;
class SideBySideDiffEditorWidget;
class UnifiedDiffEditorWidget;
const char SIDE_BY_SIDE_VIEW_ID[] = "SideBySide";
const char UNIFIED_VIEW_ID[] = "Unified";
class IDiffView
class IDiffView : public QObject
{
Q_OBJECT
public:
IDiffView() { }
virtual ~IDiffView() { }
explicit IDiffView(QObject *parent = 0);
QIcon icon() const;
QString toolTip() const;
bool supportsSync() const;
QString syncToolTip() const;
Core::Id id() const;
virtual QWidget *widget() = 0;
virtual void setDiffEditorGuiController(DiffEditorGuiController *controller) = 0;
virtual void setDocument(DiffEditorDocument *document) = 0;
virtual void beginOperation() = 0;
virtual void setCurrentDiffFileIndex(int index) = 0;
virtual void setDiff(const QList<FileData> &diffFileList, const QString &workingDirectory) = 0;
virtual void endOperation(bool success) = 0;
virtual void setSync(bool) = 0;
signals:
void currentDiffFileIndexChanged(int index);
protected:
void setIcon(const QIcon &icon);
void setToolTip(const QString &toolTip);
void setId(const Core::Id &id);
void setSupportsSync(bool sync);
void setSyncToolTip(const QString &text);
private:
QIcon m_icon;
QString m_toolTip;
Core::Id m_id;
bool m_supportsSync;
QString m_syncToolTip;
};
class UnifiedView : public IDiffView {
class UnifiedView : public IDiffView
{
Q_OBJECT
public:
UnifiedView();
QWidget *widget();
void setDiffEditorGuiController(DiffEditorGuiController *controller);
void setDocument(DiffEditorDocument *document);
void beginOperation();
void setCurrentDiffFileIndex(int index);
void setDiff(const QList<FileData> &diffFileList, const QString &workingDirectory);
void endOperation(bool success);
void setSync(bool sync);
private:
UnifiedDiffEditorWidget *m_widget;
};
class SideBySideView : public IDiffView {
class SideBySideView : public IDiffView
{
Q_OBJECT
public:
SideBySideView();
QWidget *widget();
void setDiffEditorGuiController(DiffEditorGuiController *controller);
void setDocument(DiffEditorDocument *document);
void beginOperation();
void setCurrentDiffFileIndex(int index);
void setDiff(const QList<FileData> &diffFileList, const QString &workingDirectory);
void endOperation(bool success);
void setSync(bool sync);
private:
SideBySideDiffEditorWidget *m_widget;
@@ -30,34 +30,29 @@
#include "sidebysidediffeditorwidget.h"
#include "selectabletexteditorwidget.h"
#include "diffeditorguicontroller.h"
#include "diffeditordocument.h"
#include "diffutils.h"
#include "diffeditorconstants.h"
#include <coreplugin/editormanager/editormanager.h>
#include <QPlainTextEdit>
#include <QVBoxLayout>
#include <QPlainTextDocumentLayout>
#include <QTextBlock>
#include <QTextCodec>
#include <QScrollBar>
#include <QPainter>
#include <QDir>
#include <QToolButton>
#include <QTextCodec>
#include <QMessageBox>
#include <QMenu>
#include <QVBoxLayout>
#include <texteditor/texteditor.h>
#include <texteditor/textdocumentlayout.h>
#include <texteditor/syntaxhighlighter.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/fontsettings.h>
#include <texteditor/displaysettings.h>
#include <texteditor/highlighterutils.h>
#include <coreplugin/icore.h>
#include <coreplugin/minisplitter.h>
#include <coreplugin/patchtool.h>
@@ -133,11 +128,11 @@ public:
return TextEditorWidget::firstVisibleBlock();
}
// void setDocuments(const QList<QPair<DiffFileInfo, QString> > &documents);
void saveState();
void restoreState();
public slots:
void setDisplaySettings(const DisplaySettings &ds);
void saveStateRequested();
void restoreStateRequested();
signals:
void jumpToOriginalFileRequested(int diffFileIndex,
@@ -311,20 +306,20 @@ SideDiffEditorWidget::SideDiffEditorWidget(QWidget *parent)
// baseTextDocument()->setSyntaxHighlighter(m_highlighter);
}
void SideDiffEditorWidget::saveStateRequested()
void SideDiffEditorWidget::saveState()
{
if (!m_state.isNull())
return;
m_state = saveState();
m_state = SelectableTextEditorWidget::saveState();
}
void SideDiffEditorWidget::restoreStateRequested()
void SideDiffEditorWidget::restoreState()
{
if (m_state.isNull())
return;
restoreState(m_state);
SelectableTextEditorWidget::restoreState(m_state);
m_state.clear();
}
@@ -443,10 +438,8 @@ int SideDiffEditorWidget::blockNumberForFileIndex(int fileIndex) const
int SideDiffEditorWidget::fileIndexForBlockNumber(int blockNumber) const
{
QMap<int, DiffFileInfo>::const_iterator it
= m_fileInfo.constBegin();
QMap<int, DiffFileInfo>::const_iterator itEnd
= m_fileInfo.constEnd();
QMap<int, DiffFileInfo>::const_iterator it = m_fileInfo.constBegin();
QMap<int, DiffFileInfo>::const_iterator itEnd = m_fileInfo.constEnd();
int i = -1;
while (it != itEnd) {
@@ -484,7 +477,6 @@ void SideDiffEditorWidget::clearAll(const QString &message)
setExtraSelections(TextEditorWidget::OtherSelection,
QList<QTextEdit::ExtraSelection>());
setPlainText(message);
// m_highlighter->setDocuments(QList<QPair<DiffFileInfo, QString> >());
}
void SideDiffEditorWidget::clearAllData()
@@ -497,12 +489,7 @@ void SideDiffEditorWidget::clearAllData()
m_separators.clear();
setSelections(QMap<int, QList<DiffSelection> >());
}
/*
void SideDiffEditorWidget::setDocuments(const QList<QPair<DiffFileInfo, QString> > &documents)
{
m_highlighter->setDocuments(documents);
}
*/
void SideDiffEditorWidget::scrollContentsBy(int dx, int dy)
{
SelectableTextEditorWidget::scrollContentsBy(dx, dy);
@@ -751,10 +738,10 @@ void SideDiffEditorWidget::drawCollapsedBlockPopup(QPainter &painter,
SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent)
: QWidget(parent)
, m_guiController(0)
, m_controller(0)
, m_document(0)
, m_ignoreCurrentIndexChange(false)
, m_foldingBlocker(false)
, m_horizontalSync(false)
, m_contextMenuFileIndex(-1)
, m_contextMenuChunkIndex(-1)
{
@@ -815,8 +802,6 @@ SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent)
connect(m_rightEditor, &QPlainTextEdit::cursorPositionChanged,
this, &SideBySideDiffEditorWidget::rightCursorPositionChanged);
// connect(m_rightEditor->document()->documentLayout(), SIGNAL(documentSizeChanged(QSizeF)),
// this, SLOT(rightDocumentSizeChanged()));
m_splitter = new MiniSplitter(this);
m_splitter->addWidget(m_leftEditor);
@@ -825,83 +810,42 @@ SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent)
l->setMargin(0);
l->addWidget(m_splitter);
setFocusProxy(m_rightEditor);
clear(tr("No controller"));
}
void SideBySideDiffEditorWidget::setDiffEditorGuiController(
DiffEditorGuiController *controller)
void SideBySideDiffEditorWidget::setDocument(DiffEditorDocument *document)
{
if (m_guiController == controller)
return;
if (m_guiController) {
disconnect(m_controller, &DiffEditorController::cleared,
this, &SideBySideDiffEditorWidget::clearAll);
disconnect(m_controller, &DiffEditorController::diffFilesChanged,
this, &SideBySideDiffEditorWidget::setDiff);
disconnect(m_controller, &DiffEditorController::saveStateRequested,
m_leftEditor, &SideDiffEditorWidget::saveStateRequested);
disconnect(m_controller, &DiffEditorController::saveStateRequested,
m_rightEditor, &SideDiffEditorWidget::saveStateRequested);
disconnect(m_controller, &DiffEditorController::restoreStateRequested,
m_leftEditor, &SideDiffEditorWidget::restoreStateRequested);
disconnect(m_controller, &DiffEditorController::restoreStateRequested,
m_rightEditor, &SideDiffEditorWidget::restoreStateRequested);
disconnect(m_guiController, &DiffEditorGuiController::currentDiffFileIndexChanged,
this, &SideBySideDiffEditorWidget::setCurrentDiffFileIndex);
clearAll(tr("No controller"));
}
m_guiController = controller;
m_controller = 0;
if (m_guiController) {
m_controller = m_guiController->controller();
connect(m_controller, &DiffEditorController::cleared,
this, &SideBySideDiffEditorWidget::clearAll);
connect(m_controller, &DiffEditorController::diffFilesChanged,
this, &SideBySideDiffEditorWidget::setDiff);
connect(m_controller, &DiffEditorController::saveStateRequested,
m_leftEditor, &SideDiffEditorWidget::saveStateRequested);
connect(m_controller, &DiffEditorController::saveStateRequested,
m_rightEditor, &SideDiffEditorWidget::saveStateRequested);
connect(m_controller, &DiffEditorController::restoreStateRequested,
m_leftEditor, &SideDiffEditorWidget::restoreStateRequested);
connect(m_controller, &DiffEditorController::restoreStateRequested,
m_rightEditor, &SideDiffEditorWidget::restoreStateRequested);
connect(m_guiController, &DiffEditorGuiController::currentDiffFileIndexChanged,
this, &SideBySideDiffEditorWidget::setCurrentDiffFileIndex);
setDiff(m_controller->diffFiles(), m_controller->workingDirectory());
setCurrentDiffFileIndex(m_guiController->currentDiffFileIndex());
}
m_document = document;
}
void SideBySideDiffEditorWidget::clear(const QString &message)
{
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
setDiff(QList<FileData>(), QString());
m_leftEditor->clearAll(message);
m_rightEditor->clearAll(message);
m_ignoreCurrentIndexChange = oldIgnore;
}
void SideBySideDiffEditorWidget::clearAll(const QString &message)
{
setDiff(QList<FileData>(), QString());
clear(message);
}
void SideBySideDiffEditorWidget::setDiff(const QList<FileData> &diffFileList,
const QString &workingDirectory)
{
Q_UNUSED(workingDirectory)
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
m_leftEditor->clear();
m_rightEditor->clear();
m_contextFileData = diffFileList;
showDiff();
if (m_contextFileData.isEmpty()) {
const QString msg = tr("No difference");
m_leftEditor->setPlainText(msg);
m_rightEditor->setPlainText(msg);
} else {
showDiff();
}
m_ignoreCurrentIndexChange = oldIgnore;
}
void SideBySideDiffEditorWidget::setCurrentDiffFileIndex(int diffFileIndex)
@@ -928,14 +872,29 @@ void SideBySideDiffEditorWidget::setCurrentDiffFileIndex(int diffFileIndex)
m_ignoreCurrentIndexChange = oldIgnore;
}
void SideBySideDiffEditorWidget::setHorizontalSync(bool sync)
{
m_horizontalSync = sync;
rightHSliderChanged();
}
void SideBySideDiffEditorWidget::saveState()
{
m_leftEditor->saveState();
m_rightEditor->saveState();
}
void SideBySideDiffEditorWidget::restoreState()
{
m_leftEditor->restoreState();
m_rightEditor->restoreState();
}
void SideBySideDiffEditorWidget::showDiff()
{
clear(tr("No difference"));
QMap<int, QList<DiffSelection> > leftFormats;
QMap<int, QList<DiffSelection> > rightFormats;
// QList<QPair<DiffFileInfo, QString> > leftDocs, rightDocs;
QString leftTexts, rightTexts;
int blockNumber = 0;
QChar separator = QLatin1Char('\n');
@@ -1065,16 +1024,11 @@ void SideBySideDiffEditorWidget::showDiff()
rightText.replace(QLatin1Char('\r'), QLatin1Char(' '));
leftTexts += leftText;
rightTexts += rightText;
// leftDocs.append(qMakePair(contextFileData.leftFileInfo, leftText));
// rightDocs.append(qMakePair(contextFileData.rightFileInfo, rightText));
}
if (leftTexts.isEmpty() && rightTexts.isEmpty())
return;
// m_leftEditor->setDocuments(leftDocs);
// m_rightEditor->setDocuments(rightDocs);
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
m_leftEditor->clear();
@@ -1085,63 +1039,6 @@ void SideBySideDiffEditorWidget::showDiff()
m_leftEditor->setSelections(leftFormats);
m_rightEditor->setSelections(rightFormats);
/*
QTextBlock leftBlock = m_leftEditor->document()->firstBlock();
QTextBlock rightBlock = m_rightEditor->document()->firstBlock();
for (int i = 0; i < m_contextFileData.count(); i++) {
const FileData &contextFileData = m_contextFileData.at(i);
leftBlock = leftBlock.next();
rightBlock = rightBlock.next();
for (int j = 0; j < contextFileData.chunks.count(); j++) {
ChunkData chunkData = contextFileData.chunks.at(j);
if (chunkData.contextChunk) {
BaseTextDocumentLayout::setFoldingIndent(leftBlock, FILE_LEVEL);
BaseTextDocumentLayout::setFoldingIndent(rightBlock, FILE_LEVEL);
leftBlock = leftBlock.next();
rightBlock = rightBlock.next();
}
const int indent = chunkData.contextChunk ? CHUNK_LEVEL : FILE_LEVEL;
for (int k = 0; k < chunkData.rows.count(); k++) {
BaseTextDocumentLayout::setFoldingIndent(leftBlock, indent);
BaseTextDocumentLayout::setFoldingIndent(rightBlock, indent);
leftBlock = leftBlock.next();
rightBlock = rightBlock.next();
}
}
}
blockNumber = 0;
for (int i = 0; i < m_contextFileData.count(); i++) {
const FileData &contextFileData = m_contextFileData.at(i);
blockNumber++;
for (int j = 0; j < contextFileData.chunks.count(); j++) {
ChunkData chunkData = contextFileData.chunks.at(j);
if (chunkData.contextChunk) {
QTextBlock leftBlock = m_leftEditor->document()->findBlockByNumber(blockNumber);
BaseTextDocumentLayout::doFoldOrUnfold(leftBlock, false);
QTextBlock rightBlock = m_rightEditor->document()->findBlockByNumber(blockNumber);
BaseTextDocumentLayout::doFoldOrUnfold(rightBlock, false);
blockNumber++;
}
blockNumber += chunkData.rows.count();
}
}
m_foldingBlocker = true;
BaseTextDocumentLayout *leftLayout = qobject_cast<BaseTextDocumentLayout *>(m_leftEditor->document()->documentLayout());
if (leftLayout) {
leftLayout->requestUpdate();
leftLayout->emitDocumentSizeChanged();
}
BaseTextDocumentLayout *rightLayout = qobject_cast<BaseTextDocumentLayout *>(m_rightEditor->document()->documentLayout());
if (rightLayout) {
rightLayout->requestUpdate();
rightLayout->emitDocumentSizeChanged();
}
m_foldingBlocker = false;
*/
// m_leftEditor->updateFoldingHighlight(QPoint(-1, -1));
// m_rightEditor->updateFoldingHighlight(QPoint(-1, -1));
}
void SideBySideDiffEditorWidget::setFontSettings(
@@ -1210,12 +1107,12 @@ void SideBySideDiffEditorWidget::slotRightJumpToOriginalFileRequested(
}
void SideBySideDiffEditorWidget::jumpToOriginalFile(const QString &fileName,
int lineNumber, int columnNumber)
int lineNumber, int columnNumber)
{
if (!m_controller)
if (!m_document)
return;
const QDir dir(m_controller->workingDirectory());
const QDir dir(m_document->baseDirectory());
const QString absoluteFileName = dir.absoluteFilePath(fileName);
QFileInfo fi(absoluteFileName);
if (fi.exists() && !fi.isDir())
@@ -1249,7 +1146,7 @@ void SideBySideDiffEditorWidget::slotLeftContextMenuRequested(QMenu *menu,
if (m_contextMenuChunkIndex >= fileData.chunks.count())
return;
m_controller->requestChunkActions(menu, diffFileIndex, chunkIndex);
m_document->chunkActionsRequested(menu, diffFileIndex, chunkIndex);
if (fileData.leftFileInfo.fileName == fileData.rightFileInfo.fileName)
return;
@@ -1284,33 +1181,22 @@ void SideBySideDiffEditorWidget::slotRightContextMenuRequested(QMenu *menu,
if (m_contextMenuChunkIndex >= fileData.chunks.count())
return;
m_controller->requestChunkActions(menu, diffFileIndex, chunkIndex);
m_document->chunkActionsRequested(menu, diffFileIndex, chunkIndex);
revertAction->setEnabled(true);
}
void SideBySideDiffEditorWidget::slotSendChunkToCodePaster()
{
if (!m_controller)
if (!m_document)
return;
if (m_contextMenuFileIndex < 0 || m_contextMenuChunkIndex < 0)
return;
if (m_contextMenuFileIndex >= m_contextFileData.count())
return;
const FileData fileData = m_contextFileData.at(m_contextMenuFileIndex);
if (m_contextMenuChunkIndex >= fileData.chunks.count())
return;
const QString patch = m_controller->makePatch(false);
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, false);
if (patch.isEmpty())
return;
// Retrieve service by soft dependency.
QObject *pasteService =
ExtensionSystem::PluginManager::getObjectByClassName(
QObject *pasteService= ExtensionSystem::PluginManager::getObjectByClassName(
QLatin1String("CodePaster::CodePasterService"));
if (pasteService) {
QMetaObject::invokeMethod(pasteService, "postText",
@@ -1334,18 +1220,10 @@ void SideBySideDiffEditorWidget::slotRevertChunk()
void SideBySideDiffEditorWidget::patch(bool revert)
{
if (!m_controller)
return;
if (m_contextMenuFileIndex < 0 || m_contextMenuChunkIndex < 0)
return;
if (m_contextMenuFileIndex >= m_contextFileData.count())
if (!m_document)
return;
const FileData fileData = m_contextFileData.at(m_contextMenuFileIndex);
if (m_contextMenuChunkIndex >= fileData.chunks.count())
return;
const QString title = revert ? tr("Revert Chunk") : tr("Apply Chunk");
const QString question = revert
@@ -1358,50 +1236,46 @@ void SideBySideDiffEditorWidget::patch(bool revert)
return;
}
const int strip = m_controller->workingDirectory().isEmpty() ? -1 : 0;
const int strip = m_document->baseDirectory().isEmpty() ? -1 : 0;
const QString fileName = revert
? fileData.rightFileInfo.fileName
: fileData.leftFileInfo.fileName;
const QString workingDirectory = m_controller->workingDirectory().isEmpty()
const QString workingDirectory = m_document->baseDirectory().isEmpty()
? QFileInfo(fileName).absolutePath()
: m_controller->workingDirectory();
: m_document->baseDirectory();
const QString patch = m_controller->makePatch(revert);
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, revert);
if (patch.isEmpty())
return;
if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch),
workingDirectory, strip, revert))
m_controller->requestReload();
workingDirectory, strip, revert))
m_document->reload();
}
void SideBySideDiffEditorWidget::leftVSliderChanged()
{
m_rightEditor->verticalScrollBar()->setValue(
m_leftEditor->verticalScrollBar()->value());
m_rightEditor->verticalScrollBar()->setValue(m_leftEditor->verticalScrollBar()->value());
}
void SideBySideDiffEditorWidget::rightVSliderChanged()
{
m_leftEditor->verticalScrollBar()->setValue(
m_rightEditor->verticalScrollBar()->value());
m_leftEditor->verticalScrollBar()->setValue(m_rightEditor->verticalScrollBar()->value());
}
void SideBySideDiffEditorWidget::leftHSliderChanged()
{
if (!m_guiController || m_guiController->horizontalScrollBarSynchronization())
m_rightEditor->horizontalScrollBar()->setValue(
m_leftEditor->horizontalScrollBar()->value());
if (m_horizontalSync)
m_rightEditor->horizontalScrollBar()->setValue(m_leftEditor->horizontalScrollBar()->value());
}
void SideBySideDiffEditorWidget::rightHSliderChanged()
{
if (!m_guiController || m_guiController->horizontalScrollBarSynchronization())
m_leftEditor->horizontalScrollBar()->setValue(
m_rightEditor->horizontalScrollBar()->value());
if (m_horizontalSync)
m_leftEditor->horizontalScrollBar()->setValue(m_rightEditor->horizontalScrollBar()->value());
}
void SideBySideDiffEditorWidget::leftCursorPositionChanged()
@@ -1409,17 +1283,13 @@ void SideBySideDiffEditorWidget::leftCursorPositionChanged()
leftVSliderChanged();
leftHSliderChanged();
if (!m_guiController)
return;
if (m_ignoreCurrentIndexChange)
return;
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
m_guiController->setCurrentDiffFileIndex(
m_leftEditor->fileIndexForBlockNumber(
m_leftEditor->textCursor().blockNumber()));
emit currentDiffFileIndexChanged(
m_leftEditor->fileIndexForBlockNumber(m_leftEditor->textCursor().blockNumber()));
m_ignoreCurrentIndexChange = oldIgnore;
}
@@ -1428,161 +1298,16 @@ void SideBySideDiffEditorWidget::rightCursorPositionChanged()
rightVSliderChanged();
rightHSliderChanged();
if (!m_guiController)
return;
if (m_ignoreCurrentIndexChange)
return;
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
m_guiController->setCurrentDiffFileIndex(
m_rightEditor->fileIndexForBlockNumber(
m_rightEditor->textCursor().blockNumber()));
emit currentDiffFileIndexChanged(
m_rightEditor->fileIndexForBlockNumber(m_rightEditor->textCursor().blockNumber()));
m_ignoreCurrentIndexChange = oldIgnore;
}
#if 0
void SideBySideDiffEditorWidget::leftDocumentSizeChanged()
{
synchronizeFoldings(m_leftEditor, m_rightEditor);
}
void SideBySideDiffEditorWidget::rightDocumentSizeChanged()
{
synchronizeFoldings(m_rightEditor, m_leftEditor);
}
/* Special version of that method (original: BaseTextDocumentLayout::doFoldOrUnfold())
The hack lies in fact, that when unfolding all direct sub-blocks are made visible,
while some of them need to stay invisible (i.e. unfolded chunk lines)
*/
static void doFoldOrUnfold(SideDiffEditorWidget *editor, const QTextBlock &block, bool unfold)
{
if (!BaseTextDocumentLayout::canFold(block))
return;
QTextBlock b = block.next();
int indent = BaseTextDocumentLayout::foldingIndent(block);
while (b.isValid() && BaseTextDocumentLayout::foldingIndent(b) > indent && (unfold || b.next().isValid())) {
if (unfold && editor->isChunkLine(b.blockNumber()) && !BaseTextDocumentLayout::isFolded(b)) {
b.setVisible(false);
b.setLineCount(0);
} else {
b.setVisible(unfold);
b.setLineCount(unfold ? qMax(1, b.layout()->lineCount()) : 0);
}
if (unfold) { // do not unfold folded sub-blocks
if (BaseTextDocumentLayout::isFolded(b) && b.next().isValid()) {
int jndent = BaseTextDocumentLayout::foldingIndent(b);
b = b.next();
while (b.isValid() && BaseTextDocumentLayout::foldingIndent(b) > jndent)
b = b.next();
continue;
}
}
b = b.next();
}
BaseTextDocumentLayout::setFolded(block, !unfold);
}
void SideBySideDiffEditorWidget::synchronizeFoldings(SideDiffEditorWidget *source, SideDiffEditorWidget *destination)
{
if (m_foldingBlocker)
return;
m_foldingBlocker = true;
QTextBlock sourceBlock = source->document()->firstBlock();
QTextBlock destinationBlock = destination->document()->firstBlock();
while (sourceBlock.isValid() && destinationBlock.isValid()) {
if (BaseTextDocumentLayout::canFold(sourceBlock)) {
const bool isSourceFolded = BaseTextDocumentLayout::isFolded(sourceBlock);
const bool isDestinationFolded = BaseTextDocumentLayout::isFolded(destinationBlock);
if (isSourceFolded != isDestinationFolded) {
if (source->isFileLine(sourceBlock.blockNumber())) {
doFoldOrUnfold(source, sourceBlock, !isSourceFolded);
doFoldOrUnfold(destination, destinationBlock, !isSourceFolded);
} else {
if (isSourceFolded) { // we fold the destination (shrinking)
QTextBlock previousSource = sourceBlock.previous(); // skippedLines
QTextBlock previousDestination = destinationBlock.previous(); // skippedLines
if (source->isChunkLine(previousSource.blockNumber())) {
QTextBlock firstVisibleDestinationBlock = destination->firstVisibleBlock();
QTextBlock firstDestinationBlock = destination->document()->firstBlock();
BaseTextDocumentLayout::doFoldOrUnfold(destinationBlock, !isSourceFolded);
BaseTextDocumentLayout::setFoldingIndent(sourceBlock, CHUNK_LEVEL);
BaseTextDocumentLayout::setFoldingIndent(destinationBlock, CHUNK_LEVEL);
previousSource.setVisible(true);
previousSource.setLineCount(1);
previousDestination.setVisible(true);
previousDestination.setLineCount(1);
sourceBlock.setVisible(false);
sourceBlock.setLineCount(0);
destinationBlock.setVisible(false);
destinationBlock.setLineCount(0);
BaseTextDocumentLayout::setFolded(previousSource, true);
BaseTextDocumentLayout::setFolded(previousDestination, true);
if (firstVisibleDestinationBlock == destinationBlock) {
/*
The following hack is completely crazy. That's the only way to scroll 1 line up
in case destinationBlock was the top visible block.
There is no need to scroll the source since this is in sync anyway
(leftSliderChanged(), rightSliderChanged())
*/
destination->verticalScrollBar()->setValue(destination->verticalScrollBar()->value() - 1);
destination->verticalScrollBar()->setValue(destination->verticalScrollBar()->value() + 1);
if (firstVisibleDestinationBlock.previous() == firstDestinationBlock) {
/*
Even more crazy case: the destinationBlock was the first top visible block.
*/
destination->verticalScrollBar()->setValue(0);
}
}
}
} else { // we unfold the destination (expanding)
if (source->isChunkLine(sourceBlock.blockNumber())) {
QTextBlock nextSource = sourceBlock.next();
QTextBlock nextDestination = destinationBlock.next();
BaseTextDocumentLayout::doFoldOrUnfold(destinationBlock, !isSourceFolded);
BaseTextDocumentLayout::setFoldingIndent(nextSource, FILE_LEVEL);
BaseTextDocumentLayout::setFoldingIndent(nextDestination, FILE_LEVEL);
sourceBlock.setVisible(false);
sourceBlock.setLineCount(0);
destinationBlock.setVisible(false);
destinationBlock.setLineCount(0);
BaseTextDocumentLayout::setFolded(nextSource, false);
BaseTextDocumentLayout::setFolded(nextDestination, false);
}
}
}
break; // only one should be synchronized
}
}
sourceBlock = sourceBlock.next();
destinationBlock = destinationBlock.next();
}
BaseTextDocumentLayout *sourceLayout = qobject_cast<BaseTextDocumentLayout *>(source->document()->documentLayout());
if (sourceLayout) {
sourceLayout->requestUpdate();
sourceLayout->emitDocumentSizeChanged();
}
QWidget *ea = source->extraArea();
if (ea->contentsRect().contains(ea->mapFromGlobal(QCursor::pos())))
source->updateFoldingHighlight(source->mapFromGlobal(QCursor::pos()));
BaseTextDocumentLayout *destinationLayout = qobject_cast<BaseTextDocumentLayout *>(destination->document()->documentLayout());
if (destinationLayout) {
destinationLayout->requestUpdate();
destinationLayout->emitDocumentSizeChanged();
}
m_foldingBlocker = false;
}
#endif
} // namespace Internal
} // namespace DiffEditor
@@ -31,28 +31,26 @@
#ifndef SIDEBYSIDEDIFFEDITORWIDGET_H
#define SIDEBYSIDEDIFFEDITORWIDGET_H
#include "differ.h"
#include "diffeditorcontroller.h"
#include "diffutils.h"
#include <QWidget>
#include <QTextCharFormat>
namespace TextEditor { class FontSettings; }
QT_BEGIN_NAMESPACE
class QSplitter;
class QMenu;
class QSplitter;
QT_END_NAMESPACE
namespace DiffEditor {
class ChunkData;
class FileData;
class DiffEditorController;
namespace Internal {
class DiffEditorDocument;
class SideDiffEditorWidget;
class DiffEditorGuiController;
class SideBySideDiffEditorWidget : public QWidget
{
@@ -60,16 +58,23 @@ class SideBySideDiffEditorWidget : public QWidget
public:
explicit SideBySideDiffEditorWidget(QWidget *parent = 0);
void setDiffEditorGuiController(Internal::DiffEditorGuiController *controller);
void setDocument(DiffEditorDocument *document);
private slots:
void clear(const QString &message = QString());
void clearAll(const QString &message = QString());
void setDiff(const QList<FileData> &diffFileList,
const QString &workingDirectory);
void setCurrentDiffFileIndex(int diffFileIndex);
void setHorizontalSync(bool sync);
void saveState();
void restoreState();
void clear(const QString &message = QString());
signals:
void currentDiffFileIndexChanged(int index);
private slots:
void setFontSettings(const TextEditor::FontSettings &fontSettings);
void slotLeftJumpToOriginalFileRequested(int diffFileIndex,
int lineNumber, int columnNumber);
@@ -98,16 +103,16 @@ private:
int lineNumber, int columnNumber);
void patch(bool revert);
DiffEditorGuiController *m_guiController;
DiffEditorController *m_controller;
DiffEditorDocument *m_document;
SideDiffEditorWidget *m_leftEditor;
SideDiffEditorWidget *m_rightEditor;
QSplitter *m_splitter;
QList<FileData> m_contextFileData; // ultimate data to be shown, contextLinesNumber taken into account
QList<FileData> m_contextFileData; // ultimate data to be shown, contextLineCount taken into account
bool m_ignoreCurrentIndexChange;
bool m_foldingBlocker;
bool m_horizontalSync;
int m_contextMenuFileIndex;
int m_contextMenuChunkIndex;
@@ -29,34 +29,28 @@
****************************************************************************/
#include "unifieddiffeditorwidget.h"
#include "diffeditorguicontroller.h"
#include "diffeditorcontroller.h"
#include "diffutils.h"
#include "diffeditorconstants.h"
#include "diffeditordocument.h"
#include <QPlainTextEdit>
#include <QVBoxLayout>
#include <QMenu>
#include <QPlainTextDocumentLayout>
#include <QTextBlock>
#include <QScrollBar>
#include <QTextCodec>
#include <QPainter>
#include <QDir>
#include <QToolButton>
#include <QTextCodec>
#include <QMessageBox>
#include <texteditor/texteditor.h>
#include <texteditor/textdocument.h>
#include <texteditor/textdocumentlayout.h>
#include <texteditor/syntaxhighlighter.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/fontsettings.h>
#include <texteditor/displaysettings.h>
#include <texteditor/highlighterutils.h>
#include <coreplugin/icore.h>
#include <coreplugin/minisplitter.h>
#include <coreplugin/patchtool.h>
#include <coreplugin/editormanager/editormanager.h>
@@ -75,8 +69,7 @@ namespace Internal {
UnifiedDiffEditorWidget::UnifiedDiffEditorWidget(QWidget *parent)
: SelectableTextEditorWidget("DiffEditor.UnifiedDiffEditor", parent)
, m_guiController(0)
, m_controller(0)
, m_document(0)
, m_ignoreCurrentIndexChange(false)
, m_contextMenuFileIndex(-1)
, m_contextMenuChunkIndex(-1)
@@ -102,70 +95,35 @@ UnifiedDiffEditorWidget::UnifiedDiffEditorWidget(QWidget *parent)
this, &UnifiedDiffEditorWidget::setFontSettings);
setFontSettings(TextEditorSettings::fontSettings());
clear(tr("No controller"));
clear(tr("No document"));
connect(this, &QPlainTextEdit::cursorPositionChanged,
this, &UnifiedDiffEditorWidget::slotCursorPositionChangedInEditor);
}
void UnifiedDiffEditorWidget::setDiffEditorGuiController(
DiffEditorGuiController *controller)
void UnifiedDiffEditorWidget::setDocument(DiffEditorDocument *document)
{
if (m_guiController == controller)
return;
if (m_guiController) {
disconnect(m_controller, &DiffEditorController::cleared,
this, &UnifiedDiffEditorWidget::clearAll);
disconnect(m_controller, &DiffEditorController::diffFilesChanged,
this, &UnifiedDiffEditorWidget::setDiff);
disconnect(m_controller, &DiffEditorController::saveStateRequested,
this, &UnifiedDiffEditorWidget::saveStateRequested);
disconnect(m_controller, &DiffEditorController::restoreStateRequested,
this, &UnifiedDiffEditorWidget::restoreStateRequested);
disconnect(m_guiController, &DiffEditorGuiController::currentDiffFileIndexChanged,
this, &UnifiedDiffEditorWidget::setCurrentDiffFileIndex);
clear(tr("No controller"));
}
m_guiController = controller;
m_controller = 0;
if (m_guiController) {
m_controller = m_guiController->controller();
connect(m_controller, &DiffEditorController::cleared,
this, &UnifiedDiffEditorWidget::clearAll);
connect(m_controller, &DiffEditorController::diffFilesChanged,
this, &UnifiedDiffEditorWidget::setDiff);
connect(m_controller, &DiffEditorController::saveStateRequested,
this, &UnifiedDiffEditorWidget::saveStateRequested);
connect(m_controller, &DiffEditorController::restoreStateRequested,
this, &UnifiedDiffEditorWidget::restoreStateRequested);
connect(m_guiController, &DiffEditorGuiController::currentDiffFileIndexChanged,
this, &UnifiedDiffEditorWidget::setCurrentDiffFileIndex);
setDiff(m_controller->diffFiles(), m_controller->workingDirectory());
setCurrentDiffFileIndex(m_guiController->currentDiffFileIndex());
}
m_document = document;
}
void UnifiedDiffEditorWidget::saveStateRequested()
void UnifiedDiffEditorWidget::saveState()
{
if (!m_state.isNull())
return;
m_state = saveState();
m_state = SelectableTextEditorWidget::saveState();
}
void UnifiedDiffEditorWidget::restoreStateRequested()
void UnifiedDiffEditorWidget::restoreState()
{
if (m_state.isNull())
return;
restoreState(m_state);
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
SelectableTextEditorWidget::restoreState(m_state);
m_state.clear();
m_ignoreCurrentIndexChange = oldIgnore;
}
void UnifiedDiffEditorWidget::setDisplaySettings(const DisplaySettings &ds)
@@ -187,16 +145,12 @@ void UnifiedDiffEditorWidget::setFontSettings(const FontSettings &fontSettings)
void UnifiedDiffEditorWidget::slotCursorPositionChangedInEditor()
{
if (!m_guiController)
return;
if (m_ignoreCurrentIndexChange)
return;
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
m_guiController->setCurrentDiffFileIndex(fileIndexForBlockNumber(
textCursor().blockNumber()));
emit currentDiffFileIndexChanged(fileIndexForBlockNumber(textCursor().blockNumber()));
m_ignoreCurrentIndexChange = oldIgnore;
}
@@ -230,7 +184,7 @@ void UnifiedDiffEditorWidget::addContextMenuActions(QMenu *menu,
int diffFileIndex,
int chunkIndex)
{
if (!m_controller)
if (!m_document || !m_document->controller())
return;
menu->addSeparator();
@@ -260,7 +214,7 @@ void UnifiedDiffEditorWidget::addContextMenuActions(QMenu *menu,
if (m_contextMenuChunkIndex >= fileData.chunks.count())
return;
m_controller->requestChunkActions(menu, diffFileIndex, chunkIndex);
m_document->chunkActionsRequested(menu, diffFileIndex, chunkIndex);
revertAction->setEnabled(true);
@@ -272,20 +226,10 @@ void UnifiedDiffEditorWidget::addContextMenuActions(QMenu *menu,
void UnifiedDiffEditorWidget::slotSendChunkToCodePaster()
{
if (!m_controller)
if (!m_document)
return;
if (m_contextMenuFileIndex < 0 || m_contextMenuChunkIndex < 0)
return;
if (m_contextMenuFileIndex >= m_contextFileData.count())
return;
const FileData fileData = m_contextFileData.at(m_contextMenuFileIndex);
if (m_contextMenuChunkIndex >= fileData.chunks.count())
return;
const QString patch = m_controller->makePatch(false);
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, false);
if (patch.isEmpty())
return;
@@ -316,17 +260,7 @@ void UnifiedDiffEditorWidget::slotRevertChunk()
void UnifiedDiffEditorWidget::patch(bool revert)
{
if (!m_controller)
return;
if (m_contextMenuFileIndex < 0 || m_contextMenuChunkIndex < 0)
return;
if (m_contextMenuFileIndex >= m_contextFileData.count())
return;
const FileData fileData = m_contextFileData.at(m_contextMenuFileIndex);
if (m_contextMenuChunkIndex >= fileData.chunks.count())
if (!m_document)
return;
const QString title = revert ? tr("Revert Chunk") : tr("Apply Chunk");
@@ -339,24 +273,24 @@ void UnifiedDiffEditorWidget::patch(bool revert)
return;
}
const int strip = m_controller->workingDirectory().isEmpty() ? -1 : 0;
const int strip = m_document->baseDirectory().isEmpty() ? -1 : 0;
const FileData fileData = m_contextFileData.at(m_contextMenuFileIndex);
const QString fileName = revert
? fileData.rightFileInfo.fileName
: fileData.leftFileInfo.fileName;
const QString workingDirectory = m_controller->workingDirectory().isEmpty()
const QString workingDirectory = m_document->baseDirectory().isEmpty()
? QFileInfo(fileName).absolutePath()
: m_controller->workingDirectory();
: m_document->baseDirectory();
const QString patch = m_controller->makePatch(revert);
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, revert);
if (patch.isEmpty())
return;
if (PatchTool::runPatch(
EditorManager::defaultTextCodec()->fromUnicode(patch),
workingDirectory, strip, revert))
m_controller->requestReload();
if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch),
workingDirectory, strip, revert))
m_document->reload();
}
void UnifiedDiffEditorWidget::clear(const QString &message)
@@ -372,16 +306,11 @@ void UnifiedDiffEditorWidget::clear(const QString &message)
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
SelectableTextEditorWidget::clear();
setDiff(QList<FileData>(), QString());
setPlainText(message);
m_ignoreCurrentIndexChange = oldIgnore;
}
void UnifiedDiffEditorWidget::clearAll(const QString &message)
{
setDiff(QList<FileData>(), QString());
clear(message);
}
QString UnifiedDiffEditorWidget::lineNumber(int blockNumber) const
{
QString lineNumberString;
@@ -618,8 +547,6 @@ QString UnifiedDiffEditorWidget::showChunk(const ChunkData &chunkData,
void UnifiedDiffEditorWidget::showDiff()
{
clear(tr("No difference"));
QString diffText;
int blockNumber = 0;
@@ -669,8 +596,10 @@ void UnifiedDiffEditorWidget::showDiff()
}
if (diffText.isEmpty())
if (diffText.isEmpty()) {
setPlainText(tr("No difference."));
return;
}
diffText.replace(QLatin1Char('\r'), QLatin1Char(' '));
const bool oldIgnore = m_ignoreCurrentIndexChange;
@@ -783,10 +712,10 @@ void UnifiedDiffEditorWidget::jumpToOriginalFile(const QString &fileName,
int lineNumber,
int columnNumber)
{
if (!m_controller)
if (!m_document)
return;
const QDir dir(m_controller->workingDirectory());
const QDir dir(m_document->baseDirectory());
const QString absoluteFileName = dir.absoluteFilePath(fileName);
QFileInfo fi(absoluteFileName);
if (fi.exists() && !fi.isDir())
@@ -31,8 +31,7 @@
#ifndef UNIFIEDDIFFEDITORWIDGET_H
#define UNIFIEDDIFFEDITORWIDGET_H
#include "differ.h"
#include "diffeditorcontroller.h"
#include "diffutils.h"
#include "selectabletexteditorwidget.h"
namespace TextEditor {
@@ -47,20 +46,32 @@ QT_END_NAMESPACE
namespace DiffEditor {
namespace Internal { class DiffEditorGuiController; }
class ChunkData;
class FileData;
namespace Internal {
class DiffEditorDocument;
class UnifiedDiffEditorWidget : public SelectableTextEditorWidget
{
Q_OBJECT
public:
UnifiedDiffEditorWidget(QWidget *parent = 0);
void setDiffEditorGuiController(Internal::DiffEditorGuiController *controller);
void setDocument(DiffEditorDocument *document);
void setDiff(const QList<FileData> &diffFileList,
const QString &workingDirectory);
void setCurrentDiffFileIndex(int diffFileIndex);
void saveState();
void restoreState();
void clear(const QString &message = QString());
signals:
void currentDiffFileIndexChanged(int index);
public slots:
void setDisplaySettings(const TextEditor::DisplaySettings &ds);
@@ -72,13 +83,6 @@ protected:
int lineNumberDigits() const;
private slots:
void clear(const QString &message = QString());
void clearAll(const QString &message = QString());
void setDiff(const QList<FileData> &diffFileList,
const QString &workingDirectory);
void setCurrentDiffFileIndex(int diffFileIndex);
void setFontSettings(const TextEditor::FontSettings &fontSettings);
void slotCursorPositionChangedInEditor();
@@ -86,8 +90,6 @@ private slots:
void slotSendChunkToCodePaster();
void slotApplyChunk();
void slotRevertChunk();
void saveStateRequested();
void restoreStateRequested();
private:
void setLeftLineNumber(int blockNumber, int lineNumber);
@@ -114,8 +116,7 @@ private:
int chunkIndex);
void patch(bool revert);
Internal::DiffEditorGuiController *m_guiController;
DiffEditorController *m_controller;
DiffEditorDocument *m_document;
// block number, visual line number.
QMap<int, int> m_leftLineNumbers;
@@ -132,7 +133,7 @@ private:
QMap<int, QPair<int, int> > m_chunkInfo;
QList<FileData> m_contextFileData; // ultimate data to be shown
// contextLinesNumber taken into account
// contextLineCount taken into account
QTextCharFormat m_fileLineFormat;
QTextCharFormat m_chunkLineFormat;
+295 -361
View File
@@ -45,6 +45,7 @@
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/idocument.h>
#include <coreplugin/vcsmanager.h>
#include <coreplugin/id.h>
#include <coreplugin/iversioncontrol.h>
@@ -64,7 +65,6 @@
#include <diffeditor/diffeditorconstants.h>
#include <diffeditor/diffeditorcontroller.h>
#include <diffeditor/diffeditormanager.h>
#include <diffeditor/diffeditorreloader.h>
#include <diffeditor/diffutils.h>
#include <QCoreApplication>
@@ -103,341 +103,288 @@ static unsigned diffExecutionFlags()
return HostOsInfo::isWindowsHost() ? unsigned(VcsBasePlugin::SuppressStdErrInLogWindow) : 0u;
}
class GitDiffHandler : public QObject
/////////////////////////////////////
class BaseController : public DiffEditorController
{
Q_OBJECT
public:
GitDiffHandler(DiffEditorController *controller, const QString &workingDirectory);
// index -> working tree
void diffFile(const QString &fileName);
// stagedFileNames: HEAD -> index
// unstagedFileNames: index -> working tree
void diffFiles(const QStringList &stagedFileNames,
const QStringList &unstagedFileNames);
// index -> working tree
void diffProjects(const QStringList &projectPaths);
// index -> working tree
void diffRepository();
// branch HEAD -> working tree
void diffBranch(const QString &branchName);
// id^ -> id
void show(const QString &id);
BaseController(IDocument *document, const QString &dir);
~BaseController();
void runCommand(const QList<QStringList> &args, QTextCodec *codec = 0);
private slots:
void slotShowDescriptionReceived(const QString &data);
void slotTextualDiffOutputReceived(const QString &contents);
virtual void processOutput(const QString &output);
protected:
void processDiff(const QString &output);
QStringList addConfigurationArguments(const QStringList &args) const;
GitClient *gitClient() const;
QStringList addHeadWhenCommandInProgress() const;
const QString m_directory;
private:
void postCollectShowDescription(const QString &id);
void postCollectTextualDiffOutputUsingDiffCommand(const QStringList &arguments);
void postCollectTextualDiffOutputUsingDiffCommand(const QList<QStringList> &argumentsList);
void postCollectTextualDiffOutputUsingShowCommand(const QStringList &arguments);
void postCollectTextualDiffOutput(const QString &gitCommand,
const QList<QStringList> &argumentsList);
void addJob(VcsCommand *command,
const QString &gitCommand,
const QStringList &arguments);
QStringList addHeadWhenCommandInProgress() const;
int timeout() const;
QProcessEnvironment processEnvironment() const;
FileName gitPath() const;
QPointer<DiffEditorController> m_controller;
const QString m_workingDirectory;
GitClient *m_gitClient;
const QString m_waitMessage;
QString m_id;
VcsCommand *m_command;
};
GitDiffHandler::GitDiffHandler(DiffEditorController *controller,
const QString &workingDirectory)
: m_controller(controller),
m_workingDirectory(workingDirectory),
m_gitClient(GitPlugin::instance()->gitClient()),
m_waitMessage(tr("Waiting for data..."))
BaseController::BaseController(IDocument *document, const QString &dir) :
DiffEditorController(document),
m_directory(dir),
m_command(0)
{ }
BaseController::~BaseController()
{
if (m_command)
m_command->cancel();
}
void GitDiffHandler::diffFile(const QString &fileName)
void BaseController::runCommand(const QList<QStringList> &args, QTextCodec *codec)
{
postCollectTextualDiffOutputUsingDiffCommand(addHeadWhenCommandInProgress()
<< QLatin1String("--")
<< fileName);
}
void GitDiffHandler::diffFiles(const QStringList &stagedFileNames,
const QStringList &unstagedFileNames)
{
QList<QStringList> arguments;
if (!stagedFileNames.isEmpty()) {
QStringList stagedArguments;
stagedArguments << QLatin1String("--cached");
stagedArguments << QLatin1String("--");
stagedArguments << stagedFileNames;
arguments << stagedArguments;
if (m_command) {
m_command->disconnect();
m_command->cancel();
}
if (!unstagedFileNames.isEmpty()) {
QStringList unstagedArguments = addHeadWhenCommandInProgress();
unstagedArguments << QLatin1String("--");
unstagedArguments << unstagedFileNames;
arguments << unstagedArguments;
m_command = new VcsCommand(gitClient()->gitExecutable(), m_directory, gitClient()->processEnvironment());
m_command->setCodec(codec ? codec : EditorManager::defaultTextCodec());
connect(m_command, &VcsCommand::output, this, &BaseController::processOutput);
connect(m_command, &VcsCommand::finished, this, &BaseController::reloadFinished);
m_command->addFlags(diffExecutionFlags());
foreach (const QStringList &arg, args) {
QTC_ASSERT(!arg.isEmpty(), continue);
m_command->addJob(arg, GitPlugin::instance()->settings().intValue(GitSettings::timeoutKey));
}
postCollectTextualDiffOutputUsingDiffCommand(arguments);
m_command->execute();
}
void GitDiffHandler::diffProjects(const QStringList &projectPaths)
void BaseController::processDiff(const QString &output)
{
postCollectTextualDiffOutputUsingDiffCommand(addHeadWhenCommandInProgress()
<< QLatin1String("--")
<< projectPaths);
m_command = 0;
bool ok;
QList<FileData> fileDataList = DiffUtils::readPatch(output, &ok);
setDiffFiles(fileDataList, m_directory);
}
void GitDiffHandler::diffRepository()
QStringList BaseController::addConfigurationArguments(const QStringList &args) const
{
postCollectTextualDiffOutputUsingDiffCommand(addHeadWhenCommandInProgress());
QTC_ASSERT(!args.isEmpty(), return args);
QStringList realArgs;
realArgs << args.at(0);
realArgs << QLatin1String("-m"); // show diff agains parents instead of merge commits
realArgs << QLatin1String("--first-parent"); // show only first parent
if (ignoreWhitespace())
realArgs << QLatin1String("--ignore-space-change");
realArgs << QLatin1String("--unified=") + QString::number(contextLineCount());
realArgs << QLatin1String("--src-prefix=a/") << QLatin1String("--dst-prefix=b/");
realArgs << args.mid(1);
return realArgs;
}
void GitDiffHandler::diffBranch(const QString &branchName)
void BaseController::processOutput(const QString &output)
{
postCollectTextualDiffOutputUsingDiffCommand(addHeadWhenCommandInProgress()
<< branchName);
processDiff(output);
}
void GitDiffHandler::show(const QString &id)
GitClient *BaseController::gitClient() const
{
m_id = id;
postCollectShowDescription(id);
return GitPlugin::instance()->gitClient();
}
void GitDiffHandler::postCollectShowDescription(const QString &id)
{
if (m_controller.isNull()) {
deleteLater();
return;
}
m_controller->requestSaveState();
m_controller->clear(m_waitMessage);
auto command = new VcsCommand(gitPath(), m_workingDirectory, processEnvironment());
command->setCodec(m_gitClient->encoding(m_workingDirectory,
"i18n.commitEncoding"));
connect(command, &VcsCommand::output, this, &GitDiffHandler::slotShowDescriptionReceived);
QStringList arguments;
arguments << QLatin1String("show")
<< QLatin1String("-s")
<< QLatin1String(noColorOption)
<< QLatin1String(decorateOption)
<< id;
command->addJob(arguments, timeout());
command->execute();
}
void GitDiffHandler::slotShowDescriptionReceived(const QString &description)
{
if (m_controller.isNull()) {
deleteLater();
return;
}
postCollectTextualDiffOutputUsingShowCommand(QStringList()
<< QLatin1String("--format=format:") // omit header, already generated
<< QLatin1String("-M")
<< QLatin1String("-C")
<< QLatin1String(noColorOption)
<< QLatin1String(decorateOption)
<< m_id);
// need to be called after postCollectDiffOutput(), since it clears the description
m_controller->setDescription(
m_gitClient->extendedShowDescription(m_workingDirectory,
description));
}
void GitDiffHandler::addJob(VcsCommand *command,
const QString &gitCommand,
const QStringList &arguments)
{
QStringList args;
args << gitCommand;
args << QLatin1String("-m"); // show diff agains parents instead of merge commits
args << QLatin1String("--first-parent"); // show only first parent
if (m_controller->isIgnoreWhitespace())
args << QLatin1String("--ignore-space-change");
args << QLatin1String("--unified=") + QString::number(
m_controller->contextLinesNumber());
args << QLatin1String("--src-prefix=a/") << QLatin1String("--dst-prefix=b/");
args << arguments;
command->addJob(args, timeout());
}
QStringList GitDiffHandler::addHeadWhenCommandInProgress() const
QStringList BaseController::addHeadWhenCommandInProgress() const
{
QStringList args;
// This is workaround for lack of support for merge commits and resolving conflicts,
// we compare the current state of working tree to the HEAD of current branch
// instead of showing unsupported combined diff format.
GitClient::CommandInProgress commandInProgress = m_gitClient->checkCommandInProgress(m_workingDirectory);
GitClient::CommandInProgress commandInProgress = gitClient()->checkCommandInProgress(m_directory);
if (commandInProgress != GitClient::NoCommand)
args << QLatin1String(HEAD);
return args;
}
void GitDiffHandler::postCollectTextualDiffOutputUsingDiffCommand(const QStringList &arguments)
{
postCollectTextualDiffOutputUsingDiffCommand(QList<QStringList>() << arguments);
}
void GitDiffHandler::postCollectTextualDiffOutputUsingDiffCommand(const QList<QStringList> &argumentsList)
{
postCollectTextualDiffOutput(QLatin1String("diff"), argumentsList);
}
void GitDiffHandler::postCollectTextualDiffOutputUsingShowCommand(const QStringList &arguments)
{
postCollectTextualDiffOutput(QLatin1String("show"), QList<QStringList>() << arguments);
}
void GitDiffHandler::postCollectTextualDiffOutput(const QString &gitCommand, const QList<QStringList> &argumentsList)
{
if (m_controller.isNull()) {
deleteLater();
return;
}
m_controller->requestSaveState();
m_controller->clear(m_waitMessage);
auto command = new VcsCommand(gitPath(), m_workingDirectory, processEnvironment());
command->setCodec(EditorManager::defaultTextCodec());
connect(command, &VcsCommand::output, this, &GitDiffHandler::slotTextualDiffOutputReceived);
command->addFlags(diffExecutionFlags());
for (int i = 0; i < argumentsList.count(); i++)
addJob(command, gitCommand, argumentsList.at(i));
command->execute();
}
void GitDiffHandler::slotTextualDiffOutputReceived(const QString &contents)
{
if (m_controller.isNull()) {
deleteLater();
return;
}
bool ok;
QList<FileData> fileDataList = DiffUtils::readPatch(contents, &ok);
m_controller->setDiffFiles(fileDataList, m_workingDirectory);
m_controller->requestRestoreState();
deleteLater();
}
int GitDiffHandler::timeout() const
{
return m_gitClient->settings()->intValue(GitSettings::timeoutKey);
}
QProcessEnvironment GitDiffHandler::processEnvironment() const
{
return m_gitClient->processEnvironment();
}
FileName GitDiffHandler::gitPath() const
{
return m_gitClient->gitExecutable();
}
/////////////////////////////////////
class GitDiffEditorReloader : public DiffEditorReloader
class RepositoryDiffController : public BaseController
{
Q_OBJECT
public:
enum DiffType {
DiffRepository,
DiffFile,
DiffFileList,
DiffProjectList,
DiffBranch,
DiffShow
};
RepositoryDiffController(IDocument *document, const QString &dir) :
BaseController(document, dir)
{ }
GitDiffEditorReloader();
void setWorkingDirectory(const QString &workingDir) {
m_workingDirectory = workingDir;
}
void setDiffType(DiffType type) { m_diffType = type; }
void setFileName(const QString &fileName) { m_fileName = fileName; }
void setFileList(const QStringList &stagedFiles,
const QStringList &unstagedFiles) {
m_stagedFiles = stagedFiles;
m_unstagedFiles = unstagedFiles;
}
void setProjectList(const QStringList &projectFiles) {
m_projectFiles = projectFiles;
}
void setBranchName(const QString &branchName) {
m_branchName = branchName;
}
void setId(const QString &id) { m_id = id; }
void setDisplayName(const QString &displayName) {
m_displayName = displayName;
}
void reload();
};
void RepositoryDiffController::reload()
{
QStringList args;
args << QLatin1String("diff");
args.append(addHeadWhenCommandInProgress());
runCommand(QList<QStringList>() << addConfigurationArguments(args));
}
class FileDiffController : public BaseController
{
Q_OBJECT
public:
FileDiffController(IDocument *document, const QString &dir, const QString &fileName) :
BaseController(document, dir),
m_fileName(fileName)
{ }
protected:
void reload();
private:
GitClient *m_gitClient;
QString m_workingDirectory;
DiffType m_diffType;
QString m_fileName;
QStringList m_stagedFiles;
QStringList m_unstagedFiles;
QStringList m_projectFiles;
QString m_branchName;
QString m_id;
QString m_displayName;
const QString m_fileName;
};
GitDiffEditorReloader::GitDiffEditorReloader()
: m_gitClient(GitPlugin::instance()->gitClient())
void FileDiffController::reload()
{
QStringList args;
args << QLatin1String("diff");
args.append(addHeadWhenCommandInProgress());
args << QLatin1String("--") << m_fileName;
runCommand(QList<QStringList>() << addConfigurationArguments(args));
}
void GitDiffEditorReloader::reload()
class FileListDiffController : public BaseController
{
auto handler = new GitDiffHandler(controller(), m_workingDirectory);
connect(handler, &GitDiffHandler::destroyed, this, &GitDiffEditorReloader::reloadFinished);
Q_OBJECT
public:
FileListDiffController(IDocument *document, const QString &dir,
const QStringList &stagedFiles, const QStringList &unstagedFiles) :
BaseController(document, dir),
m_stagedFiles(stagedFiles),
m_unstagedFiles(unstagedFiles)
{ }
switch (m_diffType) {
case DiffRepository:
handler->diffRepository();
break;
case DiffFile:
handler->diffFile(m_fileName);
break;
case DiffFileList:
handler->diffFiles(m_stagedFiles, m_unstagedFiles);
break;
case DiffProjectList:
handler->diffProjects(m_projectFiles);
break;
case DiffBranch:
handler->diffBranch(m_branchName);
break;
case DiffShow:
handler->show(m_id);
break;
default:
break;
void reload();
private:
const QStringList m_stagedFiles;
const QStringList m_unstagedFiles;
};
void FileListDiffController::reload()
{
QList<QStringList> argLists;
if (!m_stagedFiles.isEmpty()) {
QStringList stagedArgs;
stagedArgs << QLatin1String("diff") << QLatin1String("--cached") << QLatin1String("--")
<< m_stagedFiles;
argLists << addConfigurationArguments(stagedArgs);
}
if (!m_unstagedFiles.isEmpty()) {
QStringList unstagedArgs;
unstagedArgs << QLatin1String("diff") << addHeadWhenCommandInProgress()
<< QLatin1String("--") << m_unstagedFiles;
argLists << addConfigurationArguments(unstagedArgs);
}
if (!argLists.isEmpty())
runCommand(argLists);
}
class ProjectDiffController : public BaseController
{
Q_OBJECT
public:
ProjectDiffController(IDocument *document, const QString &dir,
const QStringList &projectPaths) :
BaseController(document, dir),
m_projectPaths(projectPaths)
{ }
void reload();
private:
const QStringList m_projectPaths;
};
void ProjectDiffController::reload()
{
QStringList args;
args << QLatin1String("diff") << addHeadWhenCommandInProgress()
<< QLatin1String("--") << m_projectPaths;
runCommand(QList<QStringList>() << addConfigurationArguments(args));
}
class BranchDiffController : public BaseController
{
Q_OBJECT
public:
BranchDiffController(IDocument *document, const QString &dir,
const QString &branch) :
BaseController(document, dir),
m_branch(branch)
{ }
void reload();
private:
const QString m_branch;
};
void BranchDiffController::reload()
{
QStringList args;
args << QLatin1String("diff") << addHeadWhenCommandInProgress() << m_branch;
runCommand(QList<QStringList>() << addConfigurationArguments(args));
}
class ShowController : public BaseController
{
Q_OBJECT
public:
ShowController(IDocument *document, const QString &dir, const QString &id) :
BaseController(document, dir),
m_id(id),
m_state(Idle)
{ }
void reload();
void processOutput(const QString &output);
private:
const QString m_id;
enum State { Idle, GettingDescription, GettingDiff };
State m_state;
};
void ShowController::reload()
{
QTC_ASSERT(m_state == Idle, return);
QStringList args;
args << QLatin1String("show") << QLatin1String("-s") << QLatin1String(noColorOption)
<< QLatin1String(decorateOption) << m_id;
m_state = GettingDescription;
runCommand(QList<QStringList>() << args, gitClient()->encoding(m_directory, "i18n.commitEncoding"));
}
void ShowController::processOutput(const QString &output)
{
QTC_ASSERT(m_state != Idle, return);
if (m_state == GettingDescription) {
setDescription(gitClient()->extendedShowDescription(m_directory, output));
QStringList args;
args << QLatin1String("show") << QLatin1String("--format=format:") // omit header, already generated
<< QLatin1String("-M") << QLatin1String("-C") << QLatin1String(noColorOption)
<< QLatin1String(decorateOption) << m_id;
m_state = GettingDiff;
runCommand(QList<QStringList>() << addConfigurationArguments(args));
} else if (m_state == GettingDiff) {
m_state = Idle;
processDiff(output);
}
}
@@ -589,8 +536,6 @@ private:
QRegExp m_progressExp;
};
IEditor *locateEditor(const char *property, const QString &entry)
{
foreach (IDocument *document, DocumentModel::openedDocuments())
@@ -735,39 +680,6 @@ VcsBaseEditorWidget *GitClient::findExistingVCSEditor(const char *registerDynami
return rc;
}
GitDiffEditorReloader *GitClient::findOrCreateDiffEditor(const QString &documentId,
const QString &source,
const QString &title,
const QString &workingDirectory) const
{
DiffEditorController *controller = 0;
GitDiffEditorReloader *reloader = 0;
Core::IDocument *document = DiffEditorManager::find(documentId);
if (document) {
controller = DiffEditorManager::controller(document);
reloader = static_cast<GitDiffEditorReloader *>(controller->reloader());
} else {
document = DiffEditorManager::findOrCreate(documentId, title);
QTC_ASSERT(document, return 0);
controller = DiffEditorManager::controller(document);
connect(controller, &DiffEditorController::chunkActionsRequested,
this, &GitClient::slotChunkActionsRequested, Qt::DirectConnection);
connect(controller, &DiffEditorController::requestBranchList,
this, &GitClient::branchesForCommit);
reloader = new GitDiffEditorReloader();
controller->setReloader(reloader);
reloader->setWorkingDirectory(workingDirectory);
}
QTC_ASSERT(reloader, return 0);
VcsBasePlugin::setSource(document, source);
EditorManager::activateEditorForDocument(document);
return reloader;
}
void GitClient::slotChunkActionsRequested(QMenu *menu, bool isValid)
{
menu->addSeparator();
@@ -814,7 +726,7 @@ void GitClient::stage(const QString &patch, bool revert)
if (!patchFile.open())
return;
const QString baseDir = m_contextController->workingDirectory();
const QString baseDir = m_contextController->baseDirectory();
QTextCodec *codec = EditorManager::defaultTextCodec();
const QByteArray patchData = codec
? codec->fromUnicode(patch) : patch.toLocal8Bit();
@@ -878,41 +790,60 @@ VcsBaseEditorWidget *GitClient::createVcsEditor(
return rc;
}
void GitClient::requestReload(const QString &documentId, const QString &source,
const QString &title,
std::function<DiffEditorController *(IDocument *)> factory) const
{
DiffEditorController *controller = 0;
IDocument *document = DiffEditorManager::findOrCreate(documentId, title);
QTC_ASSERT(document, return);
controller = DiffEditorManager::controller(document);
if (!controller) {
controller = factory(document);
QTC_ASSERT(controller, return);
connect(controller, &DiffEditorController::chunkActionsRequested,
this, &GitClient::slotChunkActionsRequested, Qt::DirectConnection);
connect(controller, &DiffEditorController::requestInformationForCommit,
this, &GitClient::branchesForCommit);
}
VcsBasePlugin::setSource(document, source);
EditorManager::activateEditorForDocument(document);
controller->requestReload();
}
void GitClient::diffFiles(const QString &workingDirectory,
const QStringList &unstagedFileNames,
const QStringList &stagedFileNames) const
{
GitDiffEditorReloader *reloader = findOrCreateDiffEditor(QLatin1String("Files:") + workingDirectory,
workingDirectory,
tr("Git Diff Files"),
workingDirectory);
QTC_ASSERT(reloader, return);
reloader->setDiffType(GitDiffEditorReloader::DiffFileList);
reloader->setFileList(stagedFileNames, unstagedFileNames);
reloader->requestReload();
requestReload(QLatin1String("Files:") + workingDirectory,
workingDirectory, tr("Git Diff Files"),
[this, workingDirectory, stagedFileNames, unstagedFileNames]
(IDocument *doc) -> DiffEditorController* {
return new FileListDiffController(doc, workingDirectory,
stagedFileNames, unstagedFileNames);
});
}
void GitClient::diffProject(const QString &workingDirectory, const QString &projectDirectory) const
{
GitDiffEditorReloader *reloader = findOrCreateDiffEditor(QLatin1String("Project:") + workingDirectory,
workingDirectory,
tr("Git Diff Project"),
workingDirectory);
QTC_ASSERT(reloader, return);
reloader->setDiffType(GitDiffEditorReloader::DiffProjectList);
reloader->setProjectList(QStringList(projectDirectory));
reloader->requestReload();
requestReload(QLatin1String("Project:") + workingDirectory,
workingDirectory, tr("Git Diff Project"),
[this, workingDirectory, projectDirectory]
(IDocument *doc) -> DiffEditorController* {
return new ProjectDiffController(doc, workingDirectory,
QStringList(projectDirectory));
});
}
void GitClient::diffRepository(const QString &workingDirectory) const
{
GitDiffEditorReloader *reloader = findOrCreateDiffEditor(QLatin1String("Repository:") + workingDirectory,
workingDirectory,
tr("Git Diff Repository"),
workingDirectory);
QTC_ASSERT(reloader, return);
reloader->setDiffType(GitDiffEditorReloader::DiffRepository);
reloader->requestReload();
requestReload(QLatin1String("Repository:") + workingDirectory,
workingDirectory, tr("Git Diff Repository"),
[this, workingDirectory](IDocument *doc) -> DiffEditorController* {
return new RepositoryDiffController(doc, workingDirectory);
});
}
void GitClient::diffFile(const QString &workingDirectory, const QString &fileName) const
@@ -920,12 +851,11 @@ void GitClient::diffFile(const QString &workingDirectory, const QString &fileNam
const QString title = tr("Git Diff \"%1\"").arg(fileName);
const QString sourceFile = VcsBaseEditor::getSource(workingDirectory, fileName);
const QString documentId = QLatin1String("File:") + sourceFile;
GitDiffEditorReloader *reloader = findOrCreateDiffEditor(documentId, sourceFile,
title, workingDirectory);
QTC_ASSERT(reloader, return);
reloader->setDiffType(GitDiffEditorReloader::DiffFile);
reloader->setFileName(fileName);
reloader->requestReload();
requestReload(documentId, sourceFile, title,
[this, workingDirectory, fileName]
(IDocument *doc) -> DiffEditorController* {
return new FileDiffController(doc, workingDirectory, fileName);
});
}
void GitClient::diffBranch(const QString &workingDirectory,
@@ -933,12 +863,11 @@ void GitClient::diffBranch(const QString &workingDirectory,
{
const QString title = tr("Git Diff Branch \"%1\"").arg(branchName);
const QString documentId = QLatin1String("Branch:") + branchName;
GitDiffEditorReloader *reloader = findOrCreateDiffEditor(documentId, workingDirectory,
title, workingDirectory);
QTC_ASSERT(reloader, return);
reloader->setDiffType(GitDiffEditorReloader::DiffBranch);
reloader->setBranchName(branchName);
reloader->requestReload();
requestReload(documentId, workingDirectory, title,
[this, workingDirectory, branchName]
(IDocument *doc) -> DiffEditorController* {
return new BranchDiffController(doc, workingDirectory, branchName);
});
}
void GitClient::merge(const QString &workingDirectory,
@@ -962,16 +891,22 @@ void GitClient::status(const QString &workingDirectory)
void GitClient::log(const QString &workingDirectory, const QString &fileName,
bool enableAnnotationContextMenu, const QStringList &args)
{
const QString msgArg = fileName.isEmpty() ? workingDirectory : fileName;
QString msgArg;
if (!fileName.isEmpty())
msgArg = fileName;
else if (!args.isEmpty())
msgArg = args.first();
else
msgArg = workingDirectory;
const QString title = tr("Git Log \"%1\"").arg(msgArg);
const Id editorId = Git::Constants::GIT_LOG_EDITOR_ID;
const QString sourceFile = VcsBaseEditor::getSource(workingDirectory, fileName);
VcsBaseEditorWidget *editor = findExistingVCSEditor("logFileName", sourceFile);
VcsBaseEditorWidget *editor = findExistingVCSEditor("logTitle", msgArg);
if (!editor) {
auto *argWidget = new GitLogArgumentsWidget(settings());
connect(argWidget, &VcsBaseEditorParameterWidget::commandExecutionRequested,
[=]() { this->log(workingDirectory, fileName, enableAnnotationContextMenu, args); });
editor = createVcsEditor(editorId, title, sourceFile, CodecLogOutput, "logFileName", sourceFile,
editor = createVcsEditor(editorId, title, sourceFile, CodecLogOutput, "logTitle", msgArg,
argWidget);
}
editor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);
@@ -1049,13 +984,11 @@ void GitClient::show(const QString &source, const QString &id, const QString &na
if (!repoDirectory.isEmpty())
workingDirectory = repoDirectory;
const QString documentId = QLatin1String("Show:") + id;
GitDiffEditorReloader *reloader = findOrCreateDiffEditor(documentId, source, title, workingDirectory);
QTC_ASSERT(reloader, return);
reloader->setDiffType(GitDiffEditorReloader::DiffShow);
reloader->setFileName(source);
reloader->setId(id);
reloader->controller()->setDescriptionEnabled(true);
reloader->requestReload();
requestReload(documentId, source, title,
[this, workingDirectory, id]
(IDocument *doc) -> DiffEditorController* {
return new ShowController(doc, workingDirectory, id);
});
}
void GitClient::saveSettings()
@@ -1650,12 +1583,12 @@ void GitClient::branchesForCommit(const QString &revision)
<< QLatin1String("-a") << QLatin1String("--contains") << revision;
auto controller = qobject_cast<DiffEditorController *>(sender());
QString workingDirectory = controller->workingDirectory();
QString workingDirectory = controller->baseDirectory();
auto command = new VcsCommand(gitExecutable(), workingDirectory, processEnvironment());
command->setCodec(getSourceCodec(currentDocumentPath()));
connect(command, &VcsCommand::output, controller,
&DiffEditorController::branchesForCommitReceived);
&DiffEditorController::informationForCommitReceived);
command->addJob(arguments, -1);
command->setCookie(workingDirectory);
@@ -3578,6 +3511,7 @@ void GitClient::StashInfo::end()
m_pushAction = NoPush;
m_stashResult = NotStashed;
}
} // namespace Internal
} // namespace Git
+2 -5
View File
@@ -72,7 +72,6 @@ namespace Git {
namespace Internal {
class CommitData;
class GitDiffEditorReloader;
struct GitSubmitEditorPanelData;
class Stash;
@@ -375,10 +374,8 @@ private:
const QString &dynamicPropertyValue,
VcsBase::VcsBaseEditorParameterWidget *configWidget) const;
GitDiffEditorReloader *findOrCreateDiffEditor(const QString &documentId,
const QString &source,
const QString &title,
const QString &workingDirectory) const;
void requestReload(const QString &documentId, const QString &source, const QString &title,
std::function<DiffEditor::DiffEditorController *(Core::IDocument *)> factory) const;
VcsBase::VcsCommand *createCommand(const QString &workingDirectory,
VcsBase::VcsBaseEditorWidget* editor = 0,
+24 -9
View File
@@ -75,8 +75,8 @@ GitEditorWidget::GitEditorWidget() :
*/
setDiffFilePattern(QRegExp(QLatin1String("^(?:diff --git a/|index |[+-]{3} (?:/dev/null|[ab]/(.+$)))")));
setLogEntryPattern(QRegExp(QLatin1String("^commit ([0-9a-f]{8})[0-9a-f]{32}")));
setAnnotateRevisionTextFormat(tr("Blame %1"));
setAnnotatePreviousRevisionTextFormat(tr("Blame Parent Revision %1"));
setAnnotateRevisionTextFormat(tr("&Blame %1"));
setAnnotatePreviousRevisionTextFormat(tr("Blame &Parent Revision %1"));
}
QSet<QString> GitEditorWidget::annotationChanges() const
@@ -212,12 +212,13 @@ void GitEditorWidget::checkoutChange()
sourceWorkingDirectory(), m_currentChange);
}
void GitEditorWidget::resetChange()
void GitEditorWidget::resetChange(const QByteArray &resetType)
{
const QString workingDir = sourceWorkingDirectory();
GitClient *client = GitPlugin::instance()->gitClient();
if (client->gitStatus(workingDir, StatusMode(NoUntracked | NoSubmodules))
if (resetType == "hard"
&& client->gitStatus(workingDir, StatusMode(NoUntracked | NoSubmodules))
!= GitClient::StatusUnchanged) {
if (QMessageBox::question(
Core::ICore::mainWindow(), tr("Reset"),
@@ -227,7 +228,7 @@ void GitEditorWidget::resetChange()
return;
}
}
client->reset(workingDir, QLatin1String("--hard"), m_currentChange);
client->reset(workingDir, QLatin1String("--" + resetType), m_currentChange);
}
void GitEditorWidget::cherryPickChange()
@@ -242,6 +243,12 @@ void GitEditorWidget::revertChange()
sourceWorkingDirectory(), m_currentChange);
}
void GitEditorWidget::logChange()
{
GitPlugin::instance()->gitClient()->log(
sourceWorkingDirectory(), QString(), false, QStringList(m_currentChange));
}
void GitEditorWidget::applyDiffChunk(const DiffChunk& chunk, bool revert)
{
QTemporaryFile patchFile;
@@ -345,10 +352,18 @@ void GitEditorWidget::addChangeActions(QMenu *menu, const QString &change)
{
m_currentChange = change;
if (contentType() != OtherContent) {
menu->addAction(tr("Cherry-Pick Change %1").arg(change), this, SLOT(cherryPickChange()));
menu->addAction(tr("Revert Change %1").arg(change), this, SLOT(revertChange()));
menu->addAction(tr("Checkout Change %1").arg(change), this, SLOT(checkoutChange()));
menu->addAction(tr("Hard Reset to Change %1").arg(change), this, SLOT(resetChange()));
menu->addAction(tr("Cherr&y-Pick Change %1").arg(change), this, SLOT(cherryPickChange()));
menu->addAction(tr("Re&vert Change %1").arg(change), this, SLOT(revertChange()));
menu->addAction(tr("C&heckout Change %1").arg(change), this, SLOT(checkoutChange()));
menu->addAction(tr("&Log for Change %1").arg(change), this, SLOT(logChange()));
QMenu *resetMenu = new QMenu(tr("&Reset to Change %1").arg(change), menu);
connect(resetMenu->addAction(tr("&Hard")), &QAction::triggered,
this, [this]() { resetChange("hard"); });
connect(resetMenu->addAction(tr("&Mixed")), &QAction::triggered,
this, [this]() { resetChange("mixed"); });
connect(resetMenu->addAction(tr("&Soft")), &QAction::triggered,
this, [this]() { resetChange("soft"); });
menu->addMenu(resetMenu);
}
}
+2 -1
View File
@@ -56,13 +56,14 @@ public slots:
private slots:
void checkoutChange();
void resetChange();
void cherryPickChange();
void revertChange();
void logChange();
void applyDiffChunk(const VcsBase::DiffChunk& chunk, bool revert);
private:
void init();
void resetChange(const QByteArray &resetType);
void addDiffActions(QMenu *menu, const VcsBase::DiffChunk &chunk);
bool open(QString *errorString, const QString &fileName, const QString &realFileName);
QSet<QString> annotationChanges() const;
+2 -2
View File
@@ -55,8 +55,8 @@ MercurialEditorWidget::MercurialEditorWidget() :
{
setDiffFilePattern(QRegExp(QLatin1String(Constants::DIFFIDENTIFIER)));
setLogEntryPattern(QRegExp(QLatin1String("^changeset:\\s+(\\S+)$")));
setAnnotateRevisionTextFormat(tr("Annotate %1"));
setAnnotatePreviousRevisionTextFormat(tr("Annotate parent revision %1"));
setAnnotateRevisionTextFormat(tr("&Annotate %1"));
setAnnotatePreviousRevisionTextFormat(tr("Annotate &parent revision %1"));
}
QSet<QString> MercurialEditorWidget::annotationChanges() const
+1 -2
View File
@@ -45,7 +45,7 @@ class IBuildConfigurationFactory;
class PROJECTEXPLORER_EXPORT BuildInfo
{
public:
BuildInfo(const IBuildConfigurationFactory *f) : supportsShadowBuild(false), m_factory(f) { }
BuildInfo(const IBuildConfigurationFactory *f) : m_factory(f) { }
virtual ~BuildInfo() { }
const IBuildConfigurationFactory *factory() const { return m_factory; }
@@ -54,7 +54,6 @@ public:
QString typeName;
Utils::FileName buildDirectory;
Core::Id kitId;
bool supportsShadowBuild;
virtual QList<Task> reportIssues(const QString &projectPath,
const QString &buildDir) const
@@ -185,8 +185,8 @@ GDB 32bit | Api | Api | N/A | Win32
: QLatin1String("/win64interrupt.exe");
if (!QFile::exists(executable)) {
appendMsgCannotInterrupt(pid, tr( "%1 does not exist. If you built Qt Creator "
"yourself, check out http://qt.gitorious.org/"
"qt-creator/binary-artifacts.").
"yourself, check out https://code.qt.io/cgit/"
"qt-creator/binary-artifacts.git/.").
arg(QDir::toNativeSeparators(executable)));
}
switch (QProcess::execute(executable, QStringList(QString::number(pid)))) {
@@ -200,7 +200,7 @@
<item>
<widget class="QLabel" name="jomLabel">
<property name="text">
<string>&lt;i&gt;jom&lt;/i&gt; is a drop-in replacement for &lt;i&gt;nmake&lt;/i&gt; which distributes the compilation process to multiple CPU cores. The latest binary is available at &lt;a href=&quot;http://download.qt-project.org/official_releases/jom/&quot;&gt;http://download.qt-project.org/official_releases/jom/&lt;/a&gt;. Disable it if you experience problems with your builds.</string>
<string>&lt;i&gt;jom&lt;/i&gt; is a drop-in replacement for &lt;i&gt;nmake&lt;/i&gt; which distributes the compilation process to multiple CPU cores. The latest binary is available at &lt;a href=&quot;http://download.qt.io/official_releases/jom/&quot;&gt;http://download.qt.io/official_releases/jom/&lt;/a&gt;. Disable it if you experience problems with your builds.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
+42 -5
View File
@@ -34,6 +34,7 @@
#include "project.h"
#include "projectnodes.h"
#include "projectexplorerconstants.h"
#include "nodesvisitor.h"
#include <utils/algorithm.h>
#include <coreplugin/icore.h>
@@ -187,11 +188,16 @@ void ProjectTree::updateFromDocumentManager(bool invalidCurrentNode)
else
currentNode = ProjectTreeWidget::nodeForFile(fileName);
Project *project = projectForNode(currentNode);
updateFromNode(currentNode);
}
update(currentNode, project);
void ProjectTree::updateFromNode(Node *node)
{
Project *project = projectForNode(node);
update(node, project);
foreach (ProjectTreeWidget *widget, m_projectTreeWidgets)
widget->sync(currentNode);
widget->sync(node);
}
void ProjectTree::update(Node *node, Project *project)
@@ -289,6 +295,8 @@ void ProjectTree::emitFoldersAboutToBeAdded(FolderNode *parentFolder, const QLis
if (!isInNodeHierarchy(parentFolder))
return;
m_foldersAdded = newFolders;
emit foldersAboutToBeAdded(parentFolder, newFolders);
}
@@ -302,7 +310,22 @@ void ProjectTree::emitFoldersAdded(FolderNode *folder)
if (Utils::anyOf(m_projectTreeWidgets, &ProjectTreeWidget::hasFocus))
return;
updateFromDocumentManager();
if (!m_currentNode) {
Core::IDocument *document = Core::EditorManager::currentDocument();
const FileName fileName = document ? document->filePath() : FileName();
FindNodesForFileVisitor findNodes(fileName);
foreach (FolderNode *fn, m_foldersAdded)
fn->accept(&findNodes);
Node *bestNode = ProjectTreeWidget::mostExpandedNode(findNodes.nodes());
if (!bestNode)
return;
updateFromNode(bestNode);
}
m_foldersAdded.clear();
}
void ProjectTree::emitFoldersAboutToBeRemoved(FolderNode *parentFolder, const QList<FolderNode *> &staleFolders)
@@ -344,6 +367,7 @@ void ProjectTree::emitFilesAboutToBeAdded(FolderNode *folder, const QList<FileNo
{
if (!isInNodeHierarchy(folder))
return;
m_filesAdded = newFiles;
emit filesAboutToBeAdded(folder, newFiles);
}
@@ -357,7 +381,20 @@ void ProjectTree::emitFilesAdded(FolderNode *folder)
if (Utils::anyOf(m_projectTreeWidgets, &ProjectTreeWidget::hasFocus))
return;
updateFromDocumentManager();
if (!m_currentNode) {
Core::IDocument *document = Core::EditorManager::currentDocument();
const FileName fileName = document ? document->filePath() : FileName();
int index = Utils::indexOf(m_filesAdded, [&fileName](FileNode *node) {
return node->path() == fileName;
});
if (index == -1)
return;
updateFromNode(m_filesAdded.at(index));
}
m_filesAdded.clear();
}
void ProjectTree::emitFilesAboutToBeRemoved(FolderNode *folder, const QList<FileNode *> &staleFiles)
@@ -135,6 +135,7 @@ private:
void updateFromProjectTreeWidget(Internal::ProjectTreeWidget *widget);
void documentManagerCurrentFileChanged();
void updateFromDocumentManager(bool invalidCurrentNode = false);
void updateFromNode(Node *node);
void update(Node *node, Project *project);
void updateContext();
@@ -150,6 +151,8 @@ private:
QList<Internal::ProjectTreeWidget *> m_projectTreeWidgets;
Node *m_currentNode;
Project *m_currentProject;
QList<FileNode *> m_filesAdded;
QList<FolderNode *> m_foldersAdded;
bool m_resetCurrentNodeFolder;
bool m_resetCurrentNodeFile;
bool m_resetCurrentNodeProject;
@@ -237,11 +237,16 @@ void ProjectTreeWidget::rowsInserted(const QModelIndex &parent, int start, int e
}
Node *ProjectTreeWidget::nodeForFile(const Utils::FileName &fileName)
{
return mostExpandedNode(SessionManager::nodesForFile(fileName));
}
Node *ProjectTreeWidget::mostExpandedNode(const QList<Node *> &nodes)
{
Node *bestNode = 0;
int bestNodeExpandCount = INT_MAX;
foreach (Node *node, SessionManager::nodesForFile(fileName)) {
foreach (Node *node, nodes) {
if (!bestNode) {
bestNode = node;
bestNodeExpandCount = ProjectTreeWidget::expandedCount(node);
@@ -256,7 +261,6 @@ Node *ProjectTreeWidget::nodeForFile(const Utils::FileName &fileName)
}
}
}
return bestNode;
}
@@ -68,6 +68,7 @@ public:
void sync(ProjectExplorer::Node *node);
static Node *nodeForFile(const Utils::FileName &fileName);
static Node *mostExpandedNode(const QList<Node*> &nodes);
public slots:
void toggleAutoSynchronization();
@@ -179,9 +179,8 @@ void TargetSetupWidget::addBuildInfo(BuildInfo *info, bool isImport)
Utils::PathChooser *pathChooser = new Utils::PathChooser();
pathChooser->setExpectedKind(Utils::PathChooser::Directory);
pathChooser->setFileName(info->buildDirectory);
pathChooser->setEnabled(info->supportsShadowBuild);
pathChooser->setHistoryCompleter(QLatin1String("TargetSetup.BuildDir.History"));
pathChooser->setReadOnly(!info->supportsShadowBuild || isImport);
pathChooser->setReadOnly(isImport);
m_newBuildsLayout->addWidget(pathChooser, pos * 2, 1);
QLabel *reportIssuesLabel = new QLabel;
@@ -376,7 +376,6 @@ BuildInfo *QbsBuildConfigurationFactory::createBuildInfo(const Kit *k,
info->typeName = tr("Build");
info->kitId = k->id();
info->type = type;
info->supportsShadowBuild = true;
return info;
}
@@ -186,7 +186,7 @@ bool QbsBuildStep::keepGoing() const
bool QbsBuildStep::showCommandLines() const
{
return m_qbsBuildOptions.showCommandLines();
return m_qbsBuildOptions.echoMode() == qbs::CommandEchoModeCommandLine;
}
bool QbsBuildStep::install() const
@@ -215,7 +215,9 @@ bool QbsBuildStep::fromMap(const QVariantMap &map)
m_qbsBuildOptions.setDryRun(map.value(QLatin1String(QBS_DRY_RUN)).toBool());
m_qbsBuildOptions.setKeepGoing(map.value(QLatin1String(QBS_KEEP_GOING)).toBool());
m_qbsBuildOptions.setMaxJobCount(map.value(QLatin1String(QBS_MAXJOBCOUNT)).toInt());
m_qbsBuildOptions.setShowCommandLines(map.value(QLatin1String(QBS_SHOWCOMMANDLINES)).toBool());
const bool showCommandLines = map.value(QLatin1String(QBS_SHOWCOMMANDLINES)).toBool();
m_qbsBuildOptions.setEchoMode(showCommandLines ? qbs::CommandEchoModeCommandLine
: qbs::CommandEchoModeSummary);
m_qbsBuildOptions.setInstall(map.value(QLatin1String(QBS_INSTALL), true).toBool());
m_qbsBuildOptions.setRemoveExistingInstallation(map.value(QLatin1String(QBS_CLEAN_INSTALL_ROOT))
.toBool());
@@ -229,7 +231,8 @@ QVariantMap QbsBuildStep::toMap() const
map.insert(QLatin1String(QBS_DRY_RUN), m_qbsBuildOptions.dryRun());
map.insert(QLatin1String(QBS_KEEP_GOING), m_qbsBuildOptions.keepGoing());
map.insert(QLatin1String(QBS_MAXJOBCOUNT), m_qbsBuildOptions.maxJobCount());
map.insert(QLatin1String(QBS_SHOWCOMMANDLINES), m_qbsBuildOptions.showCommandLines());
map.insert(QLatin1String(QBS_SHOWCOMMANDLINES),
m_qbsBuildOptions.echoMode() == qbs::CommandEchoModeCommandLine);
map.insert(QLatin1String(QBS_INSTALL), m_qbsBuildOptions.install());
map.insert(QLatin1String(QBS_CLEAN_INSTALL_ROOT),
m_qbsBuildOptions.removeExistingInstallation());
@@ -379,9 +382,10 @@ void QbsBuildStep::setMaxJobs(int jobcount)
void QbsBuildStep::setShowCommandLines(bool show)
{
if (m_qbsBuildOptions.showCommandLines() == show)
if (showCommandLines() == show)
return;
m_qbsBuildOptions.setShowCommandLines(show);
m_qbsBuildOptions.setEchoMode(show ? qbs::CommandEchoModeCommandLine
: qbs::CommandEchoModeSummary);
emit qbsBuildOptionsChanged();
}
@@ -77,11 +77,6 @@ QString QmakeBuildConfiguration::shadowBuildDirectory(const QString &proFilePath
{
if (proFilePath.isEmpty())
return QString();
QFileInfo info(proFilePath);
BaseQtVersion *version = QtKitInformation::qtVersion(k);
if (version && !version->supportsShadowBuilds())
return info.absolutePath();
const QString projectName = QFileInfo(proFilePath).completeBaseName();
ProjectMacroExpander expander(projectName, k, suffix);
@@ -90,14 +85,11 @@ QString QmakeBuildConfiguration::shadowBuildDirectory(const QString &proFilePath
return FileUtils::resolvePath(projectDir, buildPath);
}
static Utils::FileName defaultBuildDirectory(bool supportsShadowBuild,
const QString &projectPath,
static Utils::FileName defaultBuildDirectory(const QString &projectPath,
const ProjectExplorer::Kit *k,
const QString &suffix)
{
if (supportsShadowBuild)
return Utils::FileName::fromString(QmakeBuildConfiguration::shadowBuildDirectory(projectPath, k, suffix));
return ProjectExplorer::Project::projectDirectory(Utils::FileName::fromString(projectPath));
return Utils::FileName::fromString(QmakeBuildConfiguration::shadowBuildDirectory(projectPath, k, suffix));
}
const char QMAKE_BC_ID[] = "Qt4ProjectManager.Qt4BuildConfiguration";
@@ -160,8 +152,6 @@ bool QmakeBuildConfiguration::fromMap(const QVariantMap &map)
m_shadowBuild = map.value(QLatin1String(USE_SHADOW_BUILD_KEY), true).toBool();
m_qmakeBuildConfiguration = BaseQtVersion::QmakeBuildConfigs(map.value(QLatin1String(BUILD_CONFIGURATION_KEY)).toInt());
m_qtVersionSupportsShadowBuilds = supportsShadowBuilds();
m_lastKitState = LastKitState(target()->kit());
connect(ProjectExplorer::ToolChainManager::instance(), SIGNAL(toolChainUpdated(ProjectExplorer::ToolChain*)),
@@ -187,7 +177,6 @@ void QmakeBuildConfiguration::kitChanged()
// For that reason the QmakeBuildConfiguration is also connected
// to the toolchain and qtversion managers
emitProFileEvaluateNeeded();
updateShadowBuild();
m_lastKitState = newState;
}
}
@@ -204,17 +193,6 @@ void QmakeBuildConfiguration::qtVersionsChanged(const QList<int> &,const QList<i
emitProFileEvaluateNeeded();
}
void QmakeBuildConfiguration::updateShadowBuild()
{
// We also emit buildDirectoryChanged if the Qt version's supportShadowBuild changed
bool currentShadowBuild = supportsShadowBuilds();
if (currentShadowBuild != m_qtVersionSupportsShadowBuilds) {
if (!currentShadowBuild)
setBuildDirectory(target()->project()->projectDirectory());
m_qtVersionSupportsShadowBuilds = currentShadowBuild;
}
}
NamedWidget *QmakeBuildConfiguration::createConfigWidget()
{
return new QmakeProjectConfigWidget(this);
@@ -227,12 +205,6 @@ QString QmakeBuildConfiguration::defaultShadowBuildDirectory() const
target()->kit(), displayName());
}
bool QmakeBuildConfiguration::supportsShadowBuilds()
{
BaseQtVersion *version = QtKitInformation::qtVersion(target()->kit());
return !version || version->supportsShadowBuilds();
}
/// If only a sub tree should be build this function returns which sub node
/// should be build
/// \see QMakeBuildConfiguration::setSubNodeBuild
@@ -276,9 +248,6 @@ void QmakeBuildConfiguration::setBuildDirectory(const FileName &directory)
if (directory == buildDirectory())
return;
BuildConfiguration::setBuildDirectory(directory);
QTC_CHECK(supportsShadowBuilds()
|| (!supportsShadowBuilds()
&& buildDirectory() == target()->project()->projectDirectory()));
emitProFileEvaluateNeeded();
}
@@ -389,7 +358,7 @@ QmakeBuildConfiguration::MakefileState QmakeBuildConfiguration::compareToImportF
// This copies the settings from userArgs to actualArgs (minus some we
// are not interested in), splitting them up into individual strings:
extractSpecFromArguments(&userArgs, workingDirectory, version, &actualArgs);
actualArgs = qs->deducedArguments() + actualArgs + qs->deducedArgumentsAfter();
actualArgs = qs->deducedArguments() + actualArgs;
FileName actualSpec = qs->mkspec();
QString qmakeArgs = result.second;
@@ -647,7 +616,6 @@ QmakeBuildInfo *QmakeBuildConfigurationFactory::createBuildInfo(const Kit *k,
info->typeName = tr("Build");
// Leave info->buildDirectory unset;
info->kitId = k->id();
info->supportsShadowBuild = (version && version->supportsShadowBuilds());
// check if this project is in the source directory:
Utils::FileName projectFilePath = Utils::FileName::fromString(projectPath);
@@ -661,8 +629,7 @@ QmakeBuildInfo *QmakeBuildConfigurationFactory::createBuildInfo(const Kit *k,
info->buildDirectory = Utils::FileName::fromString(absoluteBuildPath);
} else {
info->buildDirectory
= defaultBuildDirectory(info->supportsShadowBuild, projectPath, k, suffix);
info->buildDirectory = defaultBuildDirectory(projectPath, k, suffix);
}
info->type = type;
return info;
@@ -696,6 +663,8 @@ int QmakeBuildConfigurationFactory::priority(const Kit *k, const QString &projec
QList<BuildInfo *> QmakeBuildConfigurationFactory::availableSetups(const Kit *k, const QString &projectPath) const
{
QList<ProjectExplorer::BuildInfo *> result;
if (!QtSupport::QtKitInformation::qtVersion(k))
return result;
result << createBuildInfo(k, projectPath, ProjectExplorer::BuildConfiguration::Debug);
result << createBuildInfo(k, projectPath, ProjectExplorer::BuildConfiguration::Release);
return result;
@@ -745,8 +714,7 @@ void QmakeBuildConfigurationFactory::configureBuildConfiguration(Target *parent,
Utils::FileName directory = qmakeInfo->buildDirectory;
if (directory.isEmpty()) {
directory = defaultBuildDirectory(qmakeInfo->supportsShadowBuild,
parent->project()->projectFilePath().toString(),
directory = defaultBuildDirectory(parent->project()->projectFilePath().toString(),
parent->kit(), qmakeInfo->displayName);
}
@@ -108,9 +108,6 @@ public:
BuildType buildType() const;
/// returns whether the Qt version in the profile supports shadow building (also true for no Qt version)
bool supportsShadowBuilds();
public slots:
void emitProFileEvaluateNeeded();
@@ -134,7 +131,6 @@ protected:
private:
void ctor();
QString defaultShadowBuildDirectory() const;
void updateShadowBuild();
class LastKitState
{
@@ -153,7 +149,6 @@ private:
bool m_shadowBuild;
bool m_isEnabled;
bool m_qtVersionSupportsShadowBuilds;
QtSupport::BaseQtVersion::QmakeBuildConfigs m_qmakeBuildConfiguration;
QmakeProjectManager::QmakeProFileNode *m_subNodeBuild;
ProjectExplorer::FileNode *m_fileNodeBuild;
@@ -54,7 +54,6 @@ public:
&& typeName == o.typeName
&& buildDirectory == o.buildDirectory
&& kitId == o.kitId
&& supportsShadowBuild == o.supportsShadowBuild
&& type == o.type
&& additionalArguments == o.additionalArguments;
}
@@ -237,13 +237,6 @@ void QmakeProjectConfigWidget::updateProblemLabel()
}
}
QString shadowBuildWarning;
if (!version->supportsShadowBuilds() && m_buildConfiguration->isShadowBuild()) {
shadowBuildWarning = tr("The Qt version %1 does not support shadow builds, building might fail.")
.arg(version->displayName())
+ QLatin1String("<br>");
}
if (allGood) {
QString buildDirectory = m_buildConfiguration->target()->project()->projectDirectory().toString();
if (m_buildConfiguration->isShadowBuild())
@@ -252,8 +245,8 @@ void QmakeProjectConfigWidget::updateProblemLabel()
issues = version->reportIssues(proFileName, buildDirectory);
Utils::sort(issues);
if (!issues.isEmpty() || !shadowBuildWarning.isEmpty()) {
QString text = QLatin1String("<nobr>") + shadowBuildWarning;
if (!issues.isEmpty()) {
QString text = QLatin1String("<nobr>");
foreach (const ProjectExplorer::Task &task, issues) {
QString type;
switch (task.type) {
@@ -277,18 +270,15 @@ void QmakeProjectConfigWidget::updateProblemLabel()
return;
}
} else if (targetMismatch) {
setProblemLabel(shadowBuildWarning + tr("A build for a different project exists in %1, which will be overwritten.",
"%1 build directory")
setProblemLabel(tr("A build for a different project exists in %1, which will be overwritten.",
"%1 build directory")
.arg(m_buildConfiguration->buildDirectory().toUserOutput()));
return;
} else if (incompatibleBuild) {
setProblemLabel(shadowBuildWarning +tr("An incompatible build exists in %1, which will be overwritten.",
"%1 build directory")
setProblemLabel(tr("An incompatible build exists in %1, which will be overwritten.",
"%1 build directory")
.arg(m_buildConfiguration->buildDirectory().toUserOutput()));
return;
} else if (!shadowBuildWarning.isEmpty()) {
setProblemLabel(shadowBuildWarning);
return;
}
setProblemLabel(QString());
@@ -196,8 +196,8 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
connect(m_buildSubProjectAction, SIGNAL(triggered()), m_qmakeProjectManager, SLOT(buildSubDirContextMenu()));
m_runQMakeAction = new QAction(tr("Run qmake"), this);
command = Core::ActionManager::registerAction(m_runQMakeAction, Constants::RUNQMAKE, projectContext);
command->setAttribute(Core::Command::CA_Hide);
const Core::Context globalcontext(Core::Constants::C_GLOBAL);
command = Core::ActionManager::registerAction(m_runQMakeAction, Constants::RUNQMAKE, globalcontext);
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
connect(m_runQMakeAction, SIGNAL(triggered()), m_qmakeProjectManager, SLOT(runQMake()));
@@ -231,8 +231,11 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
connect(BuildManager::instance(), SIGNAL(buildStateChanged(ProjectExplorer::Project*)),
this, SLOT(buildStateChanged(ProjectExplorer::Project*)));
connect(SessionManager::instance(), SIGNAL(startupProjectChanged(ProjectExplorer::Project*)),
this, SLOT(startupProjectChanged()));
connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
this, &QmakeProjectManagerPlugin::projectChanged);
connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged,
this, &QmakeProjectManagerPlugin::projectChanged);
connect(ProjectTree::instance(), &ProjectTree::currentNodeChanged,
this, &QmakeProjectManagerPlugin::updateContextActions);
@@ -272,13 +275,16 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
void QmakeProjectManagerPlugin::extensionsInitialized()
{ }
void QmakeProjectManagerPlugin::startupProjectChanged()
void QmakeProjectManagerPlugin::projectChanged()
{
if (m_previousStartupProject)
disconnect(m_previousStartupProject, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
this, SLOT(activeTargetChanged()));
m_previousStartupProject = qobject_cast<QmakeProject *>(SessionManager::startupProject());
if (ProjectTree::currentProject())
m_previousStartupProject = qobject_cast<QmakeProject *>(ProjectTree::currentProject());
else
m_previousStartupProject = qobject_cast<QmakeProject *>(SessionManager::startupProject());
if (m_previousStartupProject)
connect(m_previousStartupProject, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
@@ -305,11 +311,10 @@ void QmakeProjectManagerPlugin::activeTargetChanged()
void QmakeProjectManagerPlugin::updateRunQMakeAction()
{
bool enable = true;
if (BuildManager::isBuilding(ProjectTree::currentProject()))
if (BuildManager::isBuilding(m_previousStartupProject))
enable = false;
QmakeProject *pro = qobject_cast<QmakeProject *>(ProjectTree::currentProject());
if (!pro)
pro = qobject_cast<QmakeProject *>(SessionManager::startupProject());
QmakeProject *pro = qobject_cast<QmakeProject *>(m_previousStartupProject);
m_runQMakeAction->setVisible(pro);
if (!pro
|| !pro->activeTarget()
|| !pro->activeTarget()->activeBuildConfiguration())
@@ -65,7 +65,7 @@ public:
void extensionsInitialized();
private slots:
void startupProjectChanged();
void projectChanged();
void activeTargetChanged();
void updateRunQMakeAction();
void updateContextActions(ProjectExplorer::Node *node, ProjectExplorer::Project *project);
@@ -159,9 +159,6 @@ QString QMakeStep::allArguments(bool shorted)
QString args = QtcProcess::joinArgs(arguments);
// User arguments
QtcProcess::addArgs(&args, m_userArgs);
// moreArgumentsAfter
foreach (const QString &arg, deducedArgumentsAfter())
QtcProcess::addArg(&args, arg);
return args;
}
@@ -199,25 +196,6 @@ QStringList QMakeStep::deducedArguments()
return arguments;
}
/// -after OBJECTS_DIR, MOC_DIR, UI_DIR, RCC_DIR
QStringList QMakeStep::deducedArgumentsAfter()
{
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit());
if (version && !version->supportsShadowBuilds()) {
// We have a target which does not allow shadow building.
// But we really don't want to have the build artefacts in the source dir
// so we try to hack around it, to make the common cases work.
// This is a HACK, remove once all make generators support
// shadow building
return QStringList() << QLatin1String("-after")
<< QLatin1String("OBJECTS_DIR=obj")
<< QLatin1String("MOC_DIR=moc")
<< QLatin1String("UI_DIR=ui")
<< QLatin1String("RCC_DIR=rcc");
}
return QStringList();
}
bool QMakeStep::init()
{
QmakeBuildConfiguration *qt4bc = qmakeBuildConfiguration();
@@ -102,8 +102,6 @@ public:
QString allArguments(bool shorted = false);
// deduced arguments e.g. qmljs debugging
QStringList deducedArguments();
// deduced arguments with -after, e.g. OBJECTS_DIR for symbian
QStringList deducedArgumentsAfter();
// arguments passed to the pro file parser
QStringList parserArguments();
// arguments set by the user
@@ -0,0 +1,96 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "backgroundaction.h"
#include <QComboBox>
#include <QPainter>
namespace QmlDesigner {
BackgroundAction::BackgroundAction(QObject *parent) :
QWidgetAction(parent)
{
}
QIcon iconForColor(const QColor &color) {
const int size = 16;
QImage image(size, size, QImage::Format_ARGB32);
image.fill(0);
QPainter p(&image);
p.fillRect(2, 2, size - 4, size - 4, Qt::black);
if (color.alpha() == 0) {
const int miniSize = (size - 8) / 2;
p.fillRect(4, 4, miniSize, miniSize, Qt::white);
p.fillRect(miniSize + 4, miniSize + 4, miniSize, miniSize, Qt::white);
} else {
p.fillRect(4, 4, size - 8, size - 8, color);
}
return QPixmap::fromImage(image);
}
QWidget *BackgroundAction::createWidget(QWidget *parent)
{
QComboBox *comboBox = new QComboBox(parent);
comboBox->setFixedWidth(42);
for (int i = 0; i < colors().count(); ++i) {
comboBox->addItem(tr(""));
comboBox->setItemIcon(i, iconForColor((colors().at(i))));
}
comboBox->setCurrentIndex(0);
connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(emitBackgroundChanged(int)));
comboBox->setProperty("hideborder", true);
return comboBox;
}
void BackgroundAction::emitBackgroundChanged(int index)
{
if (index < colors().count())
emit backgroundChanged(colors().at(index));
}
QList<QColor> BackgroundAction::colors()
{
static QColor alphaZero(Qt::transparent);
static QList<QColor> colorList = QList<QColor>() << alphaZero
<< QColor(Qt::black)
<< QColor(Qt::darkGray)
<< QColor(Qt::lightGray)
<< QColor(Qt::white);
return colorList;
}
} // namespace QmlDesigner
@@ -0,0 +1,64 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef QMLDESIGNER_BACKGROUNDACTION_H
#define QMLDESIGNER_BACKGROUNDACTION_H
#include <QWidgetAction>
namespace QmlDesigner {
class BackgroundAction : public QWidgetAction
{
enum BackgroundType {
CheckboardBackground,
WhiteBackground,
BlackBackground
};
Q_OBJECT
public:
explicit BackgroundAction(QObject *parent);
signals:
void backgroundChanged(const QColor &color);
protected:
QWidget *createWidget(QWidget *parent);
private slots:
void emitBackgroundChanged(int index);
private:
static QList<QColor> colors();
};
} // namespace QmlDesigner
#endif // QMLDESIGNER_BACKGROUNDACTION_H
@@ -35,7 +35,8 @@ SOURCES += formeditoritem.cpp \
anchorindicatorgraphicsitem.cpp \
bindingindicator.cpp \
bindingindicatorgraphicsitem.cpp \
contentnoteditableindicator.cpp
contentnoteditableindicator.cpp \
backgroundaction.cpp
HEADERS += formeditorscene.h \
formeditorwidget.h \
formeditoritem.h \
@@ -72,5 +73,6 @@ HEADERS += formeditorscene.h \
anchorindicatorgraphicsitem.h \
bindingindicator.h \
bindingindicatorgraphicsitem.h \
contentnoteditableindicator.h
contentnoteditableindicator.h \
backgroundaction.h
RESOURCES += formeditor.qrc
@@ -54,16 +54,7 @@ FormEditorGraphicsView::FormEditorGraphicsView(QWidget *parent) :
setAutoFillBackground(true);
setBackgroundRole(QPalette::Window);
const int checkerbordSize= 20;
QPixmap tilePixmap(checkerbordSize * 2, checkerbordSize * 2);
tilePixmap.fill(Qt::white);
QPainter tilePainter(&tilePixmap);
QColor color(220, 220, 220);
tilePainter.fillRect(0, 0, checkerbordSize, checkerbordSize, color);
tilePainter.fillRect(checkerbordSize, checkerbordSize, checkerbordSize, checkerbordSize, color);
tilePainter.end();
setBackgroundBrush(tilePixmap);
activateCheckboardBackground();
viewport()->setMouseTracking(true);
}
@@ -126,6 +117,25 @@ QRectF FormEditorGraphicsView::rootItemRect() const
return m_rootItemRect;
}
void FormEditorGraphicsView::activateCheckboardBackground()
{
const int checkerbordSize= 20;
QPixmap tilePixmap(checkerbordSize * 2, checkerbordSize * 2);
tilePixmap.fill(Qt::white);
QPainter tilePainter(&tilePixmap);
QColor color(220, 220, 220);
tilePainter.fillRect(0, 0, checkerbordSize, checkerbordSize, color);
tilePainter.fillRect(checkerbordSize, checkerbordSize, checkerbordSize, checkerbordSize, color);
tilePainter.end();
setBackgroundBrush(tilePixmap);
}
void FormEditorGraphicsView::activateColoredBackground(const QColor &color)
{
setBackgroundBrush(color);
}
void FormEditorGraphicsView::drawBackground(QPainter *painter, const QRectF &rectangle)
{
painter->save();
@@ -44,6 +44,9 @@ public:
void setRootItemRect(const QRectF &rect);
QRectF rootItemRect() const;
void activateCheckboardBackground();
void activateColoredBackground(const QColor &color);
protected:
void drawBackground(QPainter *painter, const QRectF &rect);
void wheelEvent(QWheelEvent *event);

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