forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/3.4'
Conflicts: src/plugins/coreplugin/coreplugin.cpp Change-Id: I9aa6c61412e2ef4a91efe028296bcc2d075856d7
This commit is contained in:
+55
-53
@@ -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.
|
||||
|
||||
Vendored
+7
-1
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -47,7 +47,7 @@ FancyTabWidgetEnabledUnselectedTextColor=text
|
||||
FancyToolButtonHoverColor=hoverBackground
|
||||
FancyToolButtonSelectedColor=selectedBackground
|
||||
FutureProgressBackgroundColor=shadowBackground
|
||||
InfoBarBackground=shadowBackground
|
||||
InfoBarBackground=ff505000
|
||||
InfoBarText=text
|
||||
MenuBarEmptyAreaBackgroundColor=shadowBackground
|
||||
MenuBarItemBackgroundColor=shadowBackground
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 ¤tCommand = 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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,9 @@ private:
|
||||
|
||||
void setupEngine();
|
||||
void startLldb();
|
||||
void startLldbStage2();
|
||||
void setupInferior();
|
||||
void setupInferiorStage2();
|
||||
void runEngine();
|
||||
void shutdownInferior();
|
||||
void shutdownEngine();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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());
|
||||
|
||||
@@ -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,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
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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><i>jom</i> is a drop-in replacement for <i>nmake</i> which distributes the compilation process to multiple CPU cores. The latest binary is available at <a href="http://download.qt-project.org/official_releases/jom/">http://download.qt-project.org/official_releases/jom/</a>. Disable it if you experience problems with your builds.</string>
|
||||
<string><i>jom</i> is a drop-in replacement for <i>nmake</i> which distributes the compilation process to multiple CPU cores. The latest binary is available at <a href="http://download.qt.io/official_releases/jom/">http://download.qt.io/official_releases/jom/</a>. Disable it if you experience problems with your builds.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user