diff --git a/README b/README.md similarity index 78% rename from README rename to README.md index 74655f93c18..97cda94efd0 100644 --- a/README +++ b/README.md @@ -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 . + . 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 . 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 + 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 + (we recommend the latest released version). 6. Check out Qt Creator (master branch or latest version, see - https://qt.gitorious.org/qt-creator). + ). 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 . - 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 + 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, \qtvars.bat) that contains the environment + (such as, `\qtvars.bat`) that contains the environment variable settings. - A .bat-file for MinGW looks like: + A `.bat`-file for MinGW looks like: set PATH=\[qtbase\]bin;\bin;\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=\[qtbase\]bin;\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 \qtvars.bat + %SystemRoot%\system32\cmd.exe /E:ON /V:ON /k \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 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/ . + . 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 - \qt-creator\bin\qtcdebugger %ld %ld + + \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 @@ -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. diff --git a/dist/changes-3.4.0 b/dist/changes-3.4.0 index d69578639bc..9abb850a639 100644 --- a/dist/changes-3.4.0 +++ b/dist/changes-3.4.0 @@ -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 diff --git a/dist/gdb/Makefile.mingw b/dist/gdb/Makefile.mingw index 3d23a97173d..54e9feadde3 100644 --- a/dist/gdb/Makefile.mingw +++ b/dist/gdb/Makefile.mingw @@ -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 diff --git a/doc/api/getting-and-building.qdoc b/doc/api/getting-and-building.qdoc index 29002b03bb4..fe459c1240e 100644 --- a/doc/api/getting-and-building.qdoc +++ b/doc/api/getting-and-building.qdoc @@ -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}. diff --git a/qtcreator.pro b/qtcreator.pro index cbc959a00df..f43df3032db 100644 --- a/qtcreator.pro +++ b/qtcreator.pro @@ -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 } } diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 97c689b39b5..a7bca8fd297 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -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 diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 959d2008bbd..c9b8eb2d6ce 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -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) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index c691d0b328b..1e2225ddfbf 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -369,7 +369,7 @@ void NodeInstanceServer::removeSharedMemory(const RemoveSharedMemoryCommand &/*c { } -void NodeInstanceServer::setupImports(const QVector &containerVector, const QVector &idContainerVector) +void NodeInstanceServer::setupImports(const QVector &containerVector) { Q_ASSERT(quickView()); QSet importStatementSet; @@ -420,11 +420,8 @@ void NodeInstanceServer::setupImports(const QVector &contain workingImportStatementList.prepend(firstWorkingImportStatement); } - QVector 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()); } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index 6273ec1013c..c817449ee74 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -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 &instanceIds); void removeInstanceRelationsipForDeletedObject(QObject *object); @@ -195,7 +195,7 @@ protected: void setupDummysForContext(QQmlContext *context); void setupFileUrl(const QUrl &fileUrl); - void setupImports(const QVector &container, const QVector &idContainerVector); + void setupImports(const QVector &container); void setupDummyData(const QUrl &fileUrl); void setupDefaultDummyData(); QList setupInstances(const CreateSceneCommand &command); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 6fd9dfca600..20bc738a3d0 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -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); diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme index e90ae2ed2e5..21f057f88e2 100644 --- a/share/qtcreator/themes/dark.creatortheme +++ b/share/qtcreator/themes/dark.creatortheme @@ -47,7 +47,7 @@ FancyTabWidgetEnabledUnselectedTextColor=text FancyToolButtonHoverColor=hoverBackground FancyToolButtonSelectedColor=selectedBackground FutureProgressBackgroundColor=shadowBackground -InfoBarBackground=shadowBackground +InfoBarBackground=ff505000 InfoBarText=text MenuBarEmptyAreaBackgroundColor=shadowBackground MenuBarItemBackgroundColor=shadowBackground diff --git a/share/qtcreator/translations/README b/share/qtcreator/translations/README index 84d3ae04e72..2c38a2d07e4 100644 --- a/share/qtcreator/translations/README +++ b/share/qtcreator/translations/README @@ -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. diff --git a/share/qtcreator/welcomescreen/widgets/SideBar.qml b/share/qtcreator/welcomescreen/widgets/SideBar.qml index 613b92b2f19..5a552bfa99d 100644 --- a/share/qtcreator/welcomescreen/widgets/SideBar.qml +++ b/share/qtcreator/welcomescreen/widgets/SideBar.qml @@ -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" diff --git a/src/libs/extensionsystem/iplugin.h b/src/libs/extensionsystem/iplugin.h index 32440880538..9532e757792 100644 --- a/src/libs/extensionsystem/iplugin.h +++ b/src/libs/extensionsystem/iplugin.h @@ -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 createTestObjects() const; PluginSpec *pluginSpec() const; diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 20da164208b..5c2fd958d31 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -505,6 +505,7 @@ QHash 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; diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp index abe5c140438..47349168232 100644 --- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp +++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp @@ -279,7 +279,7 @@ extern "C" HRESULT CALLBACK pid(CIDebugClient *client, PCSTR args) int token; commandTokens(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); diff --git a/src/libs/utils/mimetypes/mimedatabase.cpp b/src/libs/utils/mimetypes/mimedatabase.cpp index 39f3cf7a2a9..be018edcc8e 100644 --- a/src/libs/utils/mimetypes/mimedatabase.cpp +++ b/src/libs/utils/mimetypes/mimedatabase.cpp @@ -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 diff --git a/src/libs/utils/mimetypes/mimetypeparser.cpp b/src/libs/utils/mimetypes/mimetypeparser.cpp index c1db64fb5c4..92e69f3bf5b 100644 --- a/src/libs/utils/mimetypes/mimetypeparser.cpp +++ b/src/libs/utils/mimetypes/mimetypeparser.cpp @@ -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; diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 0750d4a7396..2960028f936 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -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); diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 6b34cd9c677..9274f937825 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -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: " - "" - "http://download.qt-project.org/official_releases/gdb/")); + "" + "http://download.qt.io/official_releases/gdb/")); } void AndroidSettingsWidget::manageAVD() diff --git a/src/plugins/autotoolsprojectmanager/autotoolsbuildconfiguration.cpp b/src/plugins/autotoolsprojectmanager/autotoolsbuildconfiguration.cpp index 620a487db41..f17b1d7f6c1 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsbuildconfiguration.cpp +++ b/src/plugins/autotoolsprojectmanager/autotoolsbuildconfiguration.cpp @@ -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; } diff --git a/src/plugins/bazaar/bazaareditor.cpp b/src/plugins/bazaar/bazaareditor.cpp index 0c8ec34b6a4..32bb0c5023b 100644 --- a/src/plugins/bazaar/bazaareditor.cpp +++ b/src/plugins/bazaar/bazaareditor.cpp @@ -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: // === 'mainwindow.cpp' setDiffFilePattern(QRegExp(QLatin1String("^=== [a-z]+ [a-z]+ '(.+)'\\s*"))); diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp index 586bb58e52b..533b4b7cd67 100644 --- a/src/plugins/bineditor/bineditorplugin.cpp +++ b/src/plugins/bineditor/bineditorplugin.cpp @@ -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)); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index ea20cb580cd..36a9c9eb065 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -279,7 +279,6 @@ CMakeBuildInfo *CMakeBuildConfigurationFactory::createBuildInfo(const ProjectExp k->addToEnvironment(info->environment); info->useNinja = false; info->sourceDirectory = sourceDir; - info->supportsShadowBuild = true; return info; } diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index ac19491576d..05b9d617b04 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -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() diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h index b07d04d865b..fd82e709d61 100644 --- a/src/plugins/coreplugin/coreplugin.h +++ b/src/plugins/coreplugin/coreplugin.h @@ -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&); diff --git a/src/plugins/coreplugin/editormanager/documentmodel.cpp b/src/plugins/coreplugin/editormanager/documentmodel.cpp index 79652c1d380..ea3e53f492f 100644 --- a/src/plugins/coreplugin/editormanager/documentmodel.cpp +++ b/src/plugins/coreplugin/editormanager/documentmodel.cpp @@ -113,6 +113,17 @@ private: QHash 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/**/; 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: diff --git a/src/plugins/coreplugin/editormanager/documentmodel.h b/src/plugins/coreplugin/editormanager/documentmodel.h index 28d1f9348ea..b8c47a35b23 100644 --- a/src/plugins/coreplugin/editormanager/documentmodel.h +++ b/src/plugins/coreplugin/editormanager/documentmodel.h @@ -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); diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 93ce68805b0..8280f6fbcc3 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -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() << entry->document); - else + if (entry->isRestored) DocumentModel::removeEntry(entry); + else + closeDocuments(QList() << entry->document); } bool EditorManager::closeEditors(const QList &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 diff --git a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp index b039cedaaa1..30ff1d4c001 100644 --- a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp +++ b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp @@ -249,7 +249,7 @@ void OpenEditorsWindow::addHistoryItems(const QList &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(); diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index 76a4bc841bb..7dfa8d64115 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -73,13 +73,13 @@ QList OpenDocumentsFilter::matchesFor(QFutureInterfacedisplayName(); - entry.m_fileName = e->fileName(); + entry.displayName = e->displayName(); + entry.fileName = e->fileName(); m_editors.append(entry); } } -QList OpenDocumentsFilter::editors() const +QList OpenDocumentsFilter::editors() const { QMutexLocker lock(&m_mutex); Q_UNUSED(lock) return m_editors; diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.h b/src/plugins/coreplugin/locator/opendocumentsfilter.h index d77a77ef4d6..06008387e36 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.h +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.h @@ -57,10 +57,17 @@ public slots: void refreshInternally(); private: - QList editors() const; + class Entry + { + public: + Utils::FileName fileName; + QString displayName; + }; + + QList editors() const; mutable QMutex m_mutex; - QList m_editors; + QList m_editors; }; } // namespace Internal diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 1f1a38f36cd..5808b4e21cb 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -761,18 +761,24 @@ static IDocumentFactory *findDocumentFactory(const QList &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 documentFactories = PluginManager::getObjects(); 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); diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h index 17b8f88457c..6f047ca9041 100644 --- a/src/plugins/coreplugin/mainwindow.h +++ b/src/plugins/coreplugin/mainwindow.h @@ -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; diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index c964e438b2d..4a203153d36 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -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 p;\n" + "conne@ct(p.t, SIGNAL(sigFoo(int)), p.t, SLOT(setProp(int)));") + << QByteArray("Pointer p;\n" + "connect(p.t, &TestClass::sigFoo, p.t, &TestClass::setProp);"); + + QTest::newRow("implicit-pointer") + << QByteArray("Pointer p;\n" + "conne@ct(p, SIGNAL(sigFoo(int)), p, SLOT(setProp(int)));") + << QByteArray("Pointer 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\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" diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index d28b33be426..d71303eb25e 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -5578,10 +5578,75 @@ Symbol *skipForwardDeclarations(const QList &symbols) return 0; } +bool findRawAccessFunction(Class *klass, PointerType *pointerType, QString *objAccessFunction) +{ + QList 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 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)); diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 4b3d33af833..8726650cb6f 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -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 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 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 <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 &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; 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 &reply = cmd->builtinReply; + const QList &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; diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index b2708e98c8c..540bfd740bb 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -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 CdbCommandPtr; - typedef std::function CommandHandler; + typedef std::function 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 &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); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 6911f3df0e4..76c7a0add5d 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -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; } diff --git a/src/plugins/debugger/debuggerplugin.h b/src/plugins/debugger/debuggerplugin.h index ba8241cb03b..ba7ca8bdcef 100644 --- a/src/plugins/debugger/debuggerplugin.h +++ b/src/plugins/debugger/debuggerplugin.h @@ -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(); diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 9fb7726198f..4e0f538a382 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -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); } } diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index 9991db443ff..9e02351c732 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -78,7 +78,9 @@ private: void setupEngine(); void startLldb(); + void startLldbStage2(); void setupInferior(); + void setupInferiorStage2(); void runEngine(); void shutdownInferior(); void shutdownEngine(); diff --git a/src/plugins/debugger/procinterrupt.cpp b/src/plugins/debugger/procinterrupt.cpp index 83134ca9125..35d7dec2eb4 100644 --- a/src/plugins/debugger/procinterrupt.cpp +++ b/src/plugins/debugger/procinterrupt.cpp @@ -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; } diff --git a/src/plugins/debugger/qml/qmlinspectoragent.cpp b/src/plugins/debugger/qml/qmlinspectoragent.cpp index 4eaff580337..7e2aecc4697 100644 --- a/src/plugins/debugger/qml/qmlinspectoragent.cpp +++ b/src/plugins/debugger/qml/qmlinspectoragent.cpp @@ -775,7 +775,7 @@ QList 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); } diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 39b10a7acaf..1b6e7fc38ba 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -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 &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]); diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index b5e898b5648..338a443203e 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -239,8 +239,7 @@ public: void insertData(const WatchData &data); // DEPRECATED void insertDataList(const QList &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 &inames); diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index 4c359802695..12503058e55 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -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) { diff --git a/src/plugins/diffeditor/diffeditor.cpp b/src/plugins/diffeditor/diffeditor.cpp index 1b63b8f5a60..8e2a0739490 100644 --- a/src/plugins/diffeditor/diffeditor.cpp +++ b/src/plugins/diffeditor/diffeditor.cpp @@ -31,7 +31,6 @@ #include "diffeditor.h" #include "diffeditorconstants.h" #include "diffeditordocument.h" -#include "diffeditorguicontroller.h" #include "diffview.h" #include @@ -62,7 +61,13 @@ #include 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() << sel); - } void DescriptionEditorWidget::handleCurrentContents() @@ -204,15 +208,23 @@ DiffEditor::DiffEditor(const QSharedPointer &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 &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(&QComboBox::activated), - this, &DiffEditor::entryActivated); + connect(m_entriesComboBox, static_cast(&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(&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(&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 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 &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 &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 diff --git a/src/plugins/diffeditor/diffeditor.h b/src/plugins/diffeditor/diffeditor.h index 3a10abdbab3..78134cc24ce 100644 --- a/src/plugins/diffeditor/diffeditor.h +++ b/src/plugins/diffeditor/diffeditor.h @@ -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 &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 m_document; DescriptionEditorWidget *m_descriptionWidget; QStackedWidget *m_stackedWidget; QVector 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 m_currentFileChunk; + int m_currentViewIndex; + int m_currentDiffFileIndex; + bool m_sync; + bool m_showDescription; + bool m_ignoreChanges; }; } // namespace Internal diff --git a/src/plugins/diffeditor/diffeditor.pro b/src/plugins/diffeditor/diffeditor.pro index dd591992fc3..b93d6ae9366 100644 --- a/src/plugins/diffeditor/diffeditor.pro +++ b/src/plugins/diffeditor/diffeditor.pro @@ -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 \ diff --git a/src/plugins/diffeditor/diffeditor.qbs b/src/plugins/diffeditor/diffeditor.qbs index 3dc92a5b07e..58b73b0cba3 100644 --- a/src/plugins/diffeditor/diffeditor.qbs +++ b/src/plugins/diffeditor/diffeditor.qbs @@ -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", diff --git a/src/plugins/diffeditor/diffeditorcontroller.cpp b/src/plugins/diffeditor/diffeditorcontroller.cpp index e4bab7fc74a..6380dee25b2 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.cpp +++ b/src/plugins/diffeditor/diffeditorcontroller.cpp @@ -30,227 +30,90 @@ #include "diffeditorconstants.h" #include "diffeditorcontroller.h" -#include "diffeditorreloader.h" +#include "diffeditordocument.h" #include -#include +#include -static const char settingsGroupC[] = "DiffEditor"; -static const char contextLineNumbersKeyC[] = "ContextLineNumbers"; -static const char ignoreWhitespaceKeyC[] = "IgnoreWhitespace"; +#include 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(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 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: "))) { - 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()); - m_clearMessage = message; - emit cleared(message); + return m_document->makePatch(m_diffFileIndex, m_chunkIndex, revert, addPrefix); } void DiffEditorController::setDiffFiles(const QList &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 diff --git a/src/plugins/diffeditor/diffeditorcontroller.h b/src/plugins/diffeditor/diffeditorcontroller.h index 08d4036ab4e..b21946fff20 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.h +++ b/src/plugins/diffeditor/diffeditorcontroller.h @@ -36,81 +36,63 @@ #include +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 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 &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 &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 &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 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 diff --git a/src/plugins/diffeditor/diffeditordocument.cpp b/src/plugins/diffeditor/diffeditordocument.cpp index 262e2e9c09a..0937a230e0d 100644 --- a/src/plugins/diffeditor/diffeditordocument.cpp +++ b/src/plugins/diffeditor/diffeditordocument.cpp @@ -32,33 +32,165 @@ #include "diffeditorconstants.h" #include "diffeditorcontroller.h" #include "diffeditormanager.h" -#include "diffeditorreloader.h" #include "diffutils.h" +#include +#include + #include #include #include #include +#include #include +#include + +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 &data, const QString &directory) +{ + m_diffFiles = data; + m_baseDirectory = directory; + emit documentChanged(); +} + +QList 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: "))) { + 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(), QString()); + setDescription(QString()); + blockSignals(blocked); +} + +void DiffEditorDocument::endReload(bool success) +{ + emit reloadFinished(success); } } // namespace Internal diff --git a/src/plugins/diffeditor/diffeditordocument.h b/src/plugins/diffeditor/diffeditordocument.h index bba9f635cf8..911f4f49aca 100644 --- a/src/plugins/diffeditor/diffeditordocument.h +++ b/src/plugins/diffeditor/diffeditordocument.h @@ -31,8 +31,12 @@ #ifndef DIFFEDITORDOCUMENT_H #define DIFFEDITORDOCUMENT_H +#include "diffutils.h" + #include +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 &data, const QString &directory); + QList 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 m_diffFiles; + QString m_baseDirectory; + QString m_description; + int m_contextLineCount; + bool m_isContextLineCountForced; + bool m_ignoreWhitespace; + + friend class ::DiffEditor::DiffEditorController; }; } // namespace Internal diff --git a/src/plugins/diffeditor/diffeditorfactory.h b/src/plugins/diffeditor/diffeditorfactory.h index 45455e95eef..3af9ea001c2 100644 --- a/src/plugins/diffeditor/diffeditorfactory.h +++ b/src/plugins/diffeditor/diffeditorfactory.h @@ -33,8 +33,6 @@ #include "diffeditor_global.h" -#include - #include namespace DiffEditor { diff --git a/src/plugins/diffeditor/diffeditorguicontroller.cpp b/src/plugins/diffeditor/diffeditorguicontroller.cpp deleted file mode 100644 index c2885fb83ee..00000000000 --- a/src/plugins/diffeditor/diffeditorguicontroller.cpp +++ /dev/null @@ -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 - -#include - -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 diff --git a/src/plugins/diffeditor/diffeditorguicontroller.h b/src/plugins/diffeditor/diffeditorguicontroller.h deleted file mode 100644 index 5c2eee87c0c..00000000000 --- a/src/plugins/diffeditor/diffeditorguicontroller.h +++ /dev/null @@ -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 - -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 diff --git a/src/plugins/diffeditor/diffeditormanager.cpp b/src/plugins/diffeditor/diffeditormanager.cpp index 06ec139e99e..d5944418199 100644 --- a/src/plugins/diffeditor/diffeditormanager.cpp +++ b/src/plugins/diffeditor/diffeditormanager.cpp @@ -36,6 +36,9 @@ #include #include #include +#include +#include + #include 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 &editors) -{ - QMap editorsForDocument; - for (int i = 0; i < editors.count(); i++) { - DiffEditor *diffEditor = qobject_cast(editors.at(i)); - if (diffEditor) { - Core::IDocument *document = diffEditor->document(); - editorsForDocument[document]++; - } - } - QMapIterator 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( - 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(diffEditor->document()); diff --git a/src/plugins/diffeditor/diffeditormanager.h b/src/plugins/diffeditor/diffeditormanager.h index 2185da63033..80f50b4ec7c 100644 --- a/src/plugins/diffeditor/diffeditormanager.h +++ b/src/plugins/diffeditor/diffeditormanager.h @@ -33,12 +33,13 @@ #include "diffeditor_global.h" -#include -#include - #include +#include -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 &editors); - -private: QMap m_idToDocument; + + friend class Internal::DiffEditorDocument; }; } // namespace DiffEditor diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 4a980d99218..e87f8aaa900 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -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 @@ -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 diffList = differ.cleanupSemantics( - differ.diff(leftText, rightText)); + QList diffList = differ.cleanupSemantics(differ.diff(leftText, rightText)); QList leftDiffList; QList rightDiffList; @@ -109,15 +104,13 @@ void SimpleDiffEditorReloader::reload() QList outputLeftDiffList; QList outputRightDiffList; - if (controller()->isIgnoreWhitespace()) { - const QList leftIntermediate = - Differ::moveWhitespaceIntoEqualities(leftDiffList); - const QList rightIntermediate = - Differ::moveWhitespaceIntoEqualities(rightDiffList); - Differ::ignoreWhitespaceBetweenEqualities(leftIntermediate, - rightIntermediate, - &outputLeftDiffList, - &outputRightDiffList); + if (ignoreWhitespace()) { + const QList leftIntermediate + = Differ::moveWhitespaceIntoEqualities(leftDiffList); + const QList 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 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(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 diff --git a/src/plugins/diffeditor/diffeditorplugin.h b/src/plugins/diffeditor/diffeditorplugin.h index 6e2caa196ed..52a96e536d9 100644 --- a/src/plugins/diffeditor/diffeditorplugin.h +++ b/src/plugins/diffeditor/diffeditorplugin.h @@ -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(); diff --git a/src/plugins/diffeditor/diffeditorreloader.cpp b/src/plugins/diffeditor/diffeditorreloader.cpp deleted file mode 100644 index 9ae58051dda..00000000000 --- a/src/plugins/diffeditor/diffeditorreloader.cpp +++ /dev/null @@ -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 diff --git a/src/plugins/diffeditor/diffeditorreloader.h b/src/plugins/diffeditor/diffeditorreloader.h deleted file mode 100644 index 2858868f50d..00000000000 --- a/src/plugins/diffeditor/diffeditorreloader.h +++ /dev/null @@ -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 - -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 diff --git a/src/plugins/diffeditor/diffutils.cpp b/src/plugins/diffeditor/diffutils.cpp index d464e230b09..0e16becbdf6 100644 --- a/src/plugins/diffeditor/diffutils.cpp +++ b/src/plugins/diffeditor/diffutils.cpp @@ -263,11 +263,10 @@ ChunkData DiffUtils::calculateOriginalData(const QList &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++) { diff --git a/src/plugins/diffeditor/diffutils.h b/src/plugins/diffeditor/diffutils.h index f902ba484c0..02b2d8d1c30 100644 --- a/src/plugins/diffeditor/diffutils.h +++ b/src/plugins/diffeditor/diffutils.h @@ -35,9 +35,6 @@ #include #include -#include - -#include "texteditor/texteditorconstants.h" namespace TextEditor { class FontSettings; } @@ -138,7 +135,7 @@ public: static ChunkData calculateOriginalData(const QList &leftDiffList, const QList &rightDiffList); static FileData calculateContextData(const ChunkData &originalData, - int contextLinesNumber, + int contextLineCount, int joinChunkThreshold = 1); static QString makePatchLine(const QChar &startLineCharacter, const QString &textLine, diff --git a/src/plugins/diffeditor/diffview.cpp b/src/plugins/diffeditor/diffview.cpp index cc2478f9c1c..457fa5e2d12 100644 --- a/src/plugins/diffeditor/diffview.cpp +++ b/src/plugins/diffeditor/diffview.cpp @@ -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 &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 &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 diff --git a/src/plugins/diffeditor/diffview.h b/src/plugins/diffeditor/diffview.h index cf46b0f433f..4f5f58a3a27 100644 --- a/src/plugins/diffeditor/diffview.h +++ b/src/plugins/diffeditor/diffview.h @@ -35,59 +35,102 @@ #include #include -#include +#include + +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 &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 &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 &diffFileList, const QString &workingDirectory); + void endOperation(bool success); + + void setSync(bool sync); private: SideBySideDiffEditorWidget *m_widget; diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp index b1a3b4d0bf4..76a989c42cc 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp @@ -30,34 +30,29 @@ #include "sidebysidediffeditorwidget.h" #include "selectabletexteditorwidget.h" -#include "diffeditorguicontroller.h" +#include "diffeditordocument.h" #include "diffutils.h" #include "diffeditorconstants.h" #include -#include -#include -#include #include +#include #include #include #include -#include -#include #include #include +#include #include #include -#include #include #include #include #include #include -#include #include #include @@ -133,11 +128,11 @@ public: return TextEditorWidget::firstVisibleBlock(); } // void setDocuments(const QList > &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::const_iterator it - = m_fileInfo.constBegin(); - QMap::const_iterator itEnd - = m_fileInfo.constEnd(); + QMap::const_iterator it = m_fileInfo.constBegin(); + QMap::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()); setPlainText(message); -// m_highlighter->setDocuments(QList >()); } void SideDiffEditorWidget::clearAllData() @@ -497,12 +489,7 @@ void SideDiffEditorWidget::clearAllData() m_separators.clear(); setSelections(QMap >()); } -/* -void SideDiffEditorWidget::setDocuments(const QList > &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(), QString()); m_leftEditor->clearAll(message); m_rightEditor->clearAll(message); m_ignoreCurrentIndexChange = oldIgnore; } -void SideBySideDiffEditorWidget::clearAll(const QString &message) -{ - setDiff(QList(), QString()); - clear(message); -} - void SideBySideDiffEditorWidget::setDiff(const QList &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 > leftFormats; QMap > rightFormats; -// QList > 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(m_leftEditor->document()->documentLayout()); - if (leftLayout) { - leftLayout->requestUpdate(); - leftLayout->emitDocumentSizeChanged(); - } - BaseTextDocumentLayout *rightLayout = qobject_cast(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(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(destination->document()->documentLayout()); - if (destinationLayout) { - destinationLayout->requestUpdate(); - destinationLayout->emitDocumentSizeChanged(); - } - m_foldingBlocker = false; -} -#endif - } // namespace Internal } // namespace DiffEditor diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.h b/src/plugins/diffeditor/sidebysidediffeditorwidget.h index bbf47ed8354..54386f89705 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.h +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.h @@ -31,28 +31,26 @@ #ifndef SIDEBYSIDEDIFFEDITORWIDGET_H #define SIDEBYSIDEDIFFEDITORWIDGET_H -#include "differ.h" -#include "diffeditorcontroller.h" +#include "diffutils.h" + #include #include 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 &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 m_contextFileData; // ultimate data to be shown, contextLinesNumber taken into account + QList 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; diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp index 31bd0961f87..22ef037c3d1 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp @@ -29,34 +29,28 @@ ****************************************************************************/ #include "unifieddiffeditorwidget.h" -#include "diffeditorguicontroller.h" +#include "diffeditorcontroller.h" #include "diffutils.h" #include "diffeditorconstants.h" +#include "diffeditordocument.h" #include -#include #include #include #include -#include +#include #include #include -#include -#include #include -#include #include #include -#include #include #include #include #include #include -#include -#include #include #include @@ -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(), QString()); setPlainText(message); m_ignoreCurrentIndexChange = oldIgnore; } -void UnifiedDiffEditorWidget::clearAll(const QString &message) -{ - setDiff(QList(), 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()) diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.h b/src/plugins/diffeditor/unifieddiffeditorwidget.h index 6e50f354192..19582e72495 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.h +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.h @@ -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 &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 &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 m_leftLineNumbers; @@ -132,7 +133,7 @@ private: QMap > m_chunkInfo; QList m_contextFileData; // ultimate data to be shown - // contextLinesNumber taken into account + // contextLineCount taken into account QTextCharFormat m_fileLineFormat; QTextCharFormat m_chunkLineFormat; diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 42767f0d253..58a9ead1b0a 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -64,7 +65,6 @@ #include #include #include -#include #include #include @@ -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 &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 &argumentsList); - void postCollectTextualDiffOutputUsingShowCommand(const QStringList &arguments); - void postCollectTextualDiffOutput(const QString &gitCommand, - const QList &argumentsList); - void addJob(VcsCommand *command, - const QString &gitCommand, - const QStringList &arguments); - QStringList addHeadWhenCommandInProgress() const; - int timeout() const; - QProcessEnvironment processEnvironment() const; - FileName gitPath() const; - - QPointer 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 &args, QTextCodec *codec) { - postCollectTextualDiffOutputUsingDiffCommand(addHeadWhenCommandInProgress() - << QLatin1String("--") - << fileName); -} - -void GitDiffHandler::diffFiles(const QStringList &stagedFileNames, - const QStringList &unstagedFileNames) -{ - QList 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 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() << arguments); -} - -void GitDiffHandler::postCollectTextualDiffOutputUsingDiffCommand(const QList &argumentsList) -{ - postCollectTextualDiffOutput(QLatin1String("diff"), argumentsList); -} - -void GitDiffHandler::postCollectTextualDiffOutputUsingShowCommand(const QStringList &arguments) -{ - postCollectTextualDiffOutput(QLatin1String("show"), QList() << arguments); -} - -void GitDiffHandler::postCollectTextualDiffOutput(const QString &gitCommand, const QList &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 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() << 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() << 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 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() << 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() << 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() << 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() << 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(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 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(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 diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 6cb337fe61c..870e2e25903 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -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 factory) const; VcsBase::VcsCommand *createCommand(const QString &workingDirectory, VcsBase::VcsBaseEditorWidget* editor = 0, diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp index 024ecb4d949..d621573a31b 100644 --- a/src/plugins/git/giteditor.cpp +++ b/src/plugins/git/giteditor.cpp @@ -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 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); } } diff --git a/src/plugins/git/giteditor.h b/src/plugins/git/giteditor.h index 8de4d4ebf17..8d2803c1a46 100644 --- a/src/plugins/git/giteditor.h +++ b/src/plugins/git/giteditor.h @@ -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 annotationChanges() const; diff --git a/src/plugins/mercurial/mercurialeditor.cpp b/src/plugins/mercurial/mercurialeditor.cpp index 75cb3a8b326..6d8a2bc936e 100644 --- a/src/plugins/mercurial/mercurialeditor.cpp +++ b/src/plugins/mercurial/mercurialeditor.cpp @@ -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 MercurialEditorWidget::annotationChanges() const diff --git a/src/plugins/projectexplorer/buildinfo.h b/src/plugins/projectexplorer/buildinfo.h index d7ded538bb1..7a0accccca7 100644 --- a/src/plugins/projectexplorer/buildinfo.h +++ b/src/plugins/projectexplorer/buildinfo.h @@ -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 reportIssues(const QString &projectPath, const QString &buildDir) const diff --git a/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp b/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp index a0db4a49712..88fcfce5d5b 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp @@ -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)))) { diff --git a/src/plugins/projectexplorer/projectexplorersettingspage.ui b/src/plugins/projectexplorer/projectexplorersettingspage.ui index 2b1b0407502..0c3d4259d39 100644 --- a/src/plugins/projectexplorer/projectexplorersettingspage.ui +++ b/src/plugins/projectexplorer/projectexplorersettingspage.ui @@ -200,7 +200,7 @@ - <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. + <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. true diff --git a/src/plugins/projectexplorer/projecttree.cpp b/src/plugins/projectexplorer/projecttree.cpp index 66173a4856a..47bbca77c60 100644 --- a/src/plugins/projectexplorer/projecttree.cpp +++ b/src/plugins/projectexplorer/projecttree.cpp @@ -34,6 +34,7 @@ #include "project.h" #include "projectnodes.h" #include "projectexplorerconstants.h" +#include "nodesvisitor.h" #include #include @@ -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 &staleFolders) @@ -344,6 +367,7 @@ void ProjectTree::emitFilesAboutToBeAdded(FolderNode *folder, const QListfilePath() : 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 &staleFiles) diff --git a/src/plugins/projectexplorer/projecttree.h b/src/plugins/projectexplorer/projecttree.h index 642458221e3..3f28618a0fc 100644 --- a/src/plugins/projectexplorer/projecttree.h +++ b/src/plugins/projectexplorer/projecttree.h @@ -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 m_projectTreeWidgets; Node *m_currentNode; Project *m_currentProject; + QList m_filesAdded; + QList m_foldersAdded; bool m_resetCurrentNodeFolder; bool m_resetCurrentNodeFile; bool m_resetCurrentNodeProject; diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp index aba3e4c32ab..656fe9b5d88 100644 --- a/src/plugins/projectexplorer/projecttreewidget.cpp +++ b/src/plugins/projectexplorer/projecttreewidget.cpp @@ -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 &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; } diff --git a/src/plugins/projectexplorer/projecttreewidget.h b/src/plugins/projectexplorer/projecttreewidget.h index 4f1a385259c..8b2eba324b6 100644 --- a/src/plugins/projectexplorer/projecttreewidget.h +++ b/src/plugins/projectexplorer/projecttreewidget.h @@ -68,6 +68,7 @@ public: void sync(ProjectExplorer::Node *node); static Node *nodeForFile(const Utils::FileName &fileName); + static Node *mostExpandedNode(const QList &nodes); public slots: void toggleAutoSynchronization(); diff --git a/src/plugins/projectexplorer/targetsetupwidget.cpp b/src/plugins/projectexplorer/targetsetupwidget.cpp index bc2620c4c70..22fc0063d4e 100644 --- a/src/plugins/projectexplorer/targetsetupwidget.cpp +++ b/src/plugins/projectexplorer/targetsetupwidget.cpp @@ -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; diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp index f01eb4b09b1..28e8d1184ea 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp @@ -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; } diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index b08019dd4ed..5c88e2a70b9 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -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(); } diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp index f538926f2a1..fe638e69aee 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp @@ -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 &,const QListproject()->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 QmakeBuildConfigurationFactory::availableSetups(const Kit *k, const QString &projectPath) const { QList 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); } diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h index 2d2d5997e07..112e8f10db6 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h @@ -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; diff --git a/src/plugins/qmakeprojectmanager/qmakebuildinfo.h b/src/plugins/qmakeprojectmanager/qmakebuildinfo.h index ebfadf7cf72..5aa77d1ee76 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildinfo.h +++ b/src/plugins/qmakeprojectmanager/qmakebuildinfo.h @@ -54,7 +54,6 @@ public: && typeName == o.typeName && buildDirectory == o.buildDirectory && kitId == o.kitId - && supportsShadowBuild == o.supportsShadowBuild && type == o.type && additionalArguments == o.additionalArguments; } diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectconfigwidget.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectconfigwidget.cpp index a131ab0e972..5f01755cf76 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectconfigwidget.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectconfigwidget.cpp @@ -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("
"); - } - 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("") + shadowBuildWarning; + if (!issues.isEmpty()) { + QString text = QLatin1String(""); 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()); diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp index 8a495d4accb..c91a99b7aff 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp @@ -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(SessionManager::startupProject()); + if (ProjectTree::currentProject()) + m_previousStartupProject = qobject_cast(ProjectTree::currentProject()); + else + m_previousStartupProject = qobject_cast(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(ProjectTree::currentProject()); - if (!pro) - pro = qobject_cast(SessionManager::startupProject()); + QmakeProject *pro = qobject_cast(m_previousStartupProject); + m_runQMakeAction->setVisible(pro); if (!pro || !pro->activeTarget() || !pro->activeTarget()->activeBuildConfiguration()) diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h index 3c018989f56..a052e462855 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h @@ -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); diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 6e190e2992b..76ae18bca09 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -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(); diff --git a/src/plugins/qmakeprojectmanager/qmakestep.h b/src/plugins/qmakeprojectmanager/qmakestep.h index 25109a89a5f..6314533dbf1 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.h +++ b/src/plugins/qmakeprojectmanager/qmakestep.h @@ -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 diff --git a/src/plugins/qmldesigner/components/formeditor/backgroundaction.cpp b/src/plugins/qmldesigner/components/formeditor/backgroundaction.cpp new file mode 100644 index 00000000000..c1fe4e37e5e --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/backgroundaction.cpp @@ -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 +#include + +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 BackgroundAction::colors() +{ + static QColor alphaZero(Qt::transparent); + static QList colorList = QList() << alphaZero + << QColor(Qt::black) + << QColor(Qt::darkGray) + << QColor(Qt::lightGray) + << QColor(Qt::white); + + + return colorList; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/backgroundaction.h b/src/plugins/qmldesigner/components/formeditor/backgroundaction.h new file mode 100644 index 00000000000..65eb16bc64b --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/backgroundaction.h @@ -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 + +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 colors(); +}; + +} // namespace QmlDesigner + +#endif // QMLDESIGNER_BACKGROUNDACTION_H diff --git a/src/plugins/qmldesigner/components/formeditor/formeditor.pri b/src/plugins/qmldesigner/components/formeditor/formeditor.pri index 8968c2f597c..1bb4f11d5e1 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditor.pri +++ b/src/plugins/qmldesigner/components/formeditor/formeditor.pri @@ -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 diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp index daad8028bb0..569bb86f87f 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp @@ -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(); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h index be1e86273af..37c28ec2aa8 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h @@ -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); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp index 21d4c187934..c44938111d5 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -128,6 +129,11 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) fillLayout->addWidget(m_toolBox.data()); m_toolBox->setLeftSideActions(upperActions); + m_backgroundAction = new BackgroundAction(m_toolActionGroup.data()); + connect(m_backgroundAction.data(), &BackgroundAction::backgroundChanged, this, &FormEditorWidget::changeBackgound); + addAction(m_backgroundAction.data()); + upperActions.append(m_backgroundAction.data()); + m_toolBox->addRightSideAction(m_backgroundAction.data()); m_zoomAction = new ZoomAction(m_toolActionGroup.data()); connect(m_zoomAction.data(), SIGNAL(zoomLevelChanged(double)), SLOT(setZoomLevel(double))); @@ -177,6 +183,14 @@ void FormEditorWidget::changeRootItemHeight(const QString &heighText) m_formEditorView->rootModelNode().setAuxiliaryData("height", QVariant()); } +void FormEditorWidget::changeBackgound(const QColor &color) +{ + if (color.alpha() == 0) + m_graphicsView->activateCheckboardBackground(); + else + m_graphicsView->activateColoredBackground(color); +} + void FormEditorWidget::resetNodeInstanceView() { m_formEditorView->setCurrentStateNode(m_formEditorView->rootModelNode()); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h index a44cd4daf22..2265145dfb5 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h @@ -42,6 +42,7 @@ namespace QmlDesigner { class ZoomAction; class LineEditAction; +class BackgroundAction; class FormEditorView; class FormEditorScene; class FormEditorGraphicsView; @@ -88,6 +89,7 @@ private slots: void setZoomLevel(double zoomLevel); void changeRootItemWidth(const QString &widthText); void changeRootItemHeight(const QString &heightText); + void changeBackgound(const QColor &color); void resetNodeInstanceView(); private: @@ -104,6 +106,7 @@ private: QPointer m_selectOnlyContentItemsAction; QPointer m_rootWidthAction; QPointer m_rootHeightAction; + QPointer m_backgroundAction; QPointer m_resetAction; }; diff --git a/src/plugins/qmldesigner/components/formeditor/snapper.cpp b/src/plugins/qmldesigner/components/formeditor/snapper.cpp index 367b2678f9f..71286cb66ef 100644 --- a/src/plugins/qmldesigner/components/formeditor/snapper.cpp +++ b/src/plugins/qmldesigner/components/formeditor/snapper.cpp @@ -587,7 +587,6 @@ static QmlItemNode findItemOnSnappingLine(const QmlItemNode &sourceQmlItemNode, if (possibleAchorItemNode != sourceQmlItemNode) { if (sourceQmlItemNode.instanceParent() == possibleAchorItemNode) { targetQmlItemNode = possibleAchorItemNode; - targetAnchorLine = currentToAnchorLine; break; } else if (currentToAnchorLine < targetAnchorLine) { targetQmlItemNode = possibleAchorItemNode; diff --git a/src/plugins/qmldesigner/components/formeditor/zoomaction.cpp b/src/plugins/qmldesigner/components/formeditor/zoomaction.cpp index 4f4c7e2904b..4d06391a228 100644 --- a/src/plugins/qmldesigner/components/formeditor/zoomaction.cpp +++ b/src/plugins/qmldesigner/components/formeditor/zoomaction.cpp @@ -79,20 +79,30 @@ QWidget *ZoomAction::createWidget(QWidget *parent) if (m_comboBoxModel.isNull()) { m_comboBoxModel = comboBox->model(); - comboBox->addItem("10 %", 0.1); - comboBox->addItem("25 %", 0.25); - comboBox->addItem("50 %", 0.5); - comboBox->addItem("100 %", 1.0); - comboBox->addItem("200 %", 2.0); - comboBox->addItem("400 %", 4.0); - comboBox->addItem("800 %", 8.0); - comboBox->addItem("1600 %", 16.0); - + comboBox->addItem(QLatin1String("6.25 %"), 0.0625); + comboBox->addItem(QLatin1String("12.5 %"), 0.125); + comboBox->addItem(QLatin1String("25 %"), 0.25); + comboBox->addItem(QLatin1String("33 %"), 0.33); + comboBox->addItem(QLatin1String("50 %"), 0.5); + comboBox->addItem(QLatin1String("66 %"), 0.66); + comboBox->addItem(QLatin1String("75 %"), 0.75); + comboBox->addItem(QLatin1String("90 %"), 0.90); + comboBox->addItem(QLatin1String("100 %"), 1.0); + comboBox->addItem(QLatin1String("125 %"), 1.25); + comboBox->addItem(QLatin1String("150 %"), 1.5); + comboBox->addItem(QLatin1String("175 %"), 1.75); + comboBox->addItem(QLatin1String("200 %"), 2.0); + comboBox->addItem(QLatin1String("300 %"), 3.0); + comboBox->addItem(QLatin1String("400 %"), 4.0); + comboBox->addItem(QLatin1String("600 %"), 6.0); + comboBox->addItem(QLatin1String("800 %"), 8.0); + comboBox->addItem(QLatin1String("1000 %"), 10.0); + comboBox->addItem(QLatin1String("1600 %"), 16.0); } else { comboBox->setModel(m_comboBoxModel.data()); } - comboBox->setCurrentIndex(3); + comboBox->setCurrentIndex(8); connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(emitZoomLevelChanged(int))); connect(this, SIGNAL(indexChanged(int)), comboBox, SLOT(setCurrentIndex(int))); diff --git a/src/plugins/qmljseditor/qmljscompletionassist.h b/src/plugins/qmljseditor/qmljscompletionassist.h index 495afbbd871..b281cf63fae 100644 --- a/src/plugins/qmljseditor/qmljscompletionassist.h +++ b/src/plugins/qmljseditor/qmljscompletionassist.h @@ -49,10 +49,11 @@ namespace QmlJS { class Value; } namespace QmlJSEditor { -namespace Internal { class QmlJSCompletionAssistInterface; +namespace Internal { + class QmlJSAssistProposalItem : public TextEditor::AssistProposalItem { public: @@ -117,8 +118,9 @@ private: TextEditor::SnippetAssistCollector m_snippetCollector; }; +} // Internal -class QmlJSCompletionAssistInterface : public TextEditor::AssistInterface +class QMLJSEDITOR_EXPORT QmlJSCompletionAssistInterface : public TextEditor::AssistInterface { public: QmlJSCompletionAssistInterface(QTextDocument *textDocument, @@ -138,7 +140,6 @@ private: QIcon m_darkCyanIcon; }; -} // Internal } // QmlJSEditor #endif // QMLJSCOMPLETIONASSIST_H diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp index a5357373b2d..75912ba5b78 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp @@ -104,6 +104,7 @@ void QmlProjectRunConfiguration::ctor() setDisplayName(tr("QML Scene", "QMLRunConfiguration display name.")); else setDisplayName(tr("QML Viewer", "QMLRunConfiguration display name.")); + updateEnabled(); } QString QmlProjectRunConfiguration::executable() const diff --git a/src/plugins/qnx/Qnx.mimetypes.xml b/src/plugins/qnx/Qnx.mimetypes.xml index 7a784969035..e9ac133fc79 100644 --- a/src/plugins/qnx/Qnx.mimetypes.xml +++ b/src/plugins/qnx/Qnx.mimetypes.xml @@ -1,6 +1,6 @@ - + BAR descriptor file (BlackBerry) diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index f7ab0230d05..4e63381c514 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -1202,11 +1202,6 @@ void BaseQtVersion::recheckDumper() m_versionInfoUpToDate = false; } -bool BaseQtVersion::supportsShadowBuilds() const -{ - return true; -} - QList BaseQtVersion::reportIssuesImpl(const QString &proFile, const QString &buildDir) const { QList results; diff --git a/src/plugins/qtsupport/baseqtversion.h b/src/plugins/qtsupport/baseqtversion.h index 87f385546ab..728466ab8a2 100644 --- a/src/plugins/qtsupport/baseqtversion.h +++ b/src/plugins/qtsupport/baseqtversion.h @@ -172,7 +172,6 @@ public: virtual QmakeBuildConfigs defaultBuildConfig() const; virtual void recheckDumper(); - virtual bool supportsShadowBuilds() const; /// Check a .pro-file/Qt version combination on possible issues /// @return a list of tasks, ordered on severity (errors first, then diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index 0c5ca6ef773..bce6f4016bb 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -42,7 +42,6 @@ #include #include #include -#include #include #include @@ -51,9 +50,10 @@ #include #include +using namespace Core; +using namespace DiffEditor; using namespace Utils; using namespace VcsBase; -using namespace Core; namespace Subversion { namespace Internal { @@ -164,13 +164,12 @@ QString SubversionClient::synchronousTopic(const QString &repository) return QString(); } -class SubversionDiffEditorReloader : public DiffEditor::DiffEditorReloader +class DiffController : public DiffEditorController { Q_OBJECT public: - SubversionDiffEditorReloader(const SubversionClient *client); + DiffController(IDocument *document, const SubversionClient *client, const QString &directory); - void setWorkingDirectory(const QString &workingDirectory); void setFilesList(const QStringList &filesList); void setChangeNumber(int changeNumber); @@ -191,41 +190,33 @@ private: QString m_workingDirectory; QStringList m_filesList; int m_changeNumber; - const QString m_waitMessage; }; -SubversionDiffEditorReloader::SubversionDiffEditorReloader(const SubversionClient *client) - : DiffEditor::DiffEditorReloader(), - m_client(client), - m_changeNumber(0), - m_waitMessage(tr("Waiting for data...")) +DiffController::DiffController(IDocument *document, const SubversionClient *client, const QString &directory) : + DiffEditorController(document), + m_client(client), + m_workingDirectory(directory), + m_changeNumber(0) { + forceContextLineCount(3); // SVN can not change that when using internal diff } -int SubversionDiffEditorReloader::timeout() const +int DiffController::timeout() const { return m_client->settings()->intValue(VcsBaseClientSettings::timeoutKey); } -FileName SubversionDiffEditorReloader::subversionPath() const +FileName DiffController::subversionPath() const { return m_client->settings()->binaryPath(); } -QProcessEnvironment SubversionDiffEditorReloader::processEnvironment() const +QProcessEnvironment DiffController::processEnvironment() const { return m_client->processEnvironment(); } -void SubversionDiffEditorReloader::setWorkingDirectory(const QString &workingDirectory) -{ - if (isReloading()) - return; - - m_workingDirectory = workingDirectory; -} - -void SubversionDiffEditorReloader::setFilesList(const QStringList &filesList) +void DiffController::setFilesList(const QStringList &filesList) { if (isReloading()) return; @@ -233,7 +224,7 @@ void SubversionDiffEditorReloader::setFilesList(const QStringList &filesList) m_filesList = filesList; } -void SubversionDiffEditorReloader::setChangeNumber(int changeNumber) +void DiffController::setChangeNumber(int changeNumber) { if (isReloading()) return; @@ -241,7 +232,7 @@ void SubversionDiffEditorReloader::setChangeNumber(int changeNumber) m_changeNumber = qMax(changeNumber, 0); } -QString SubversionDiffEditorReloader::getDescription() const +QString DiffController::getDescription() const { QStringList args(QLatin1String("log")); args << SubversionClient::addAuthenticationOptions(*m_client->settings()); @@ -258,13 +249,8 @@ QString SubversionDiffEditorReloader::getDescription() const return logResponse.stdOut; } -void SubversionDiffEditorReloader::postCollectTextualDiffOutput() +void DiffController::postCollectTextualDiffOutput() { - if (!controller()) - return; - - controller()->requestSaveState(); - controller()->clear(m_waitMessage); auto command = new VcsCommand(subversionPath(), m_workingDirectory, processEnvironment()); command->setCodec(EditorManager::defaultTextCodec()); connect(command, SIGNAL(output(QString)), @@ -275,7 +261,7 @@ void SubversionDiffEditorReloader::postCollectTextualDiffOutput() args << QLatin1String("diff"); args << m_client->addAuthenticationOptions(*m_client->settings()); args << QLatin1String("--internal-diff"); - if (controller()->isIgnoreWhitespace()) + if (ignoreWhitespace()) args << QLatin1String("-x") << QLatin1String("-uw"); if (m_changeNumber) { args << QLatin1String("-r") << QString::number(m_changeNumber - 1) @@ -288,58 +274,35 @@ void SubversionDiffEditorReloader::postCollectTextualDiffOutput() command->execute(); } -void SubversionDiffEditorReloader::slotTextualDiffOutputReceived(const QString &contents) +void DiffController::slotTextualDiffOutputReceived(const QString &contents) { - if (!controller()) - return; - bool ok; - QList fileDataList - = DiffEditor::DiffUtils::readPatch(contents, &ok); - controller()->setDiffFiles(fileDataList, m_workingDirectory); - controller()->requestRestoreState(); + QList fileDataList + = DiffUtils::readPatch(contents, &ok); + setDiffFiles(fileDataList, m_workingDirectory); - reloadFinished(); + reloadFinished(true); } -void SubversionDiffEditorReloader::reload() +void DiffController::reload() { - if (!controller()) - return; - const QString description = m_changeNumber ? getDescription() : QString(); postCollectTextualDiffOutput(); - controller()->setDescription(description); + setDescription(description); } -SubversionDiffEditorReloader *SubversionClient::findOrCreateDiffEditor(const QString &documentId, - const QString &source, - const QString &title, - const QString &workingDirectory) const +DiffController *SubversionClient::findOrCreateDiffEditor(const QString &documentId, + const QString &source, + const QString &title, + const QString &workingDirectory) const { - DiffEditor::DiffEditorController *controller = 0; - SubversionDiffEditorReloader *reloader = 0; - Core::IDocument *document = DiffEditor::DiffEditorManager::find(documentId); - if (document) { - controller = DiffEditor::DiffEditorManager::controller(document); - reloader = static_cast(controller->reloader()); - } else { - document = DiffEditor::DiffEditorManager::findOrCreate(documentId, title); - QTC_ASSERT(document, return 0); - controller = DiffEditor::DiffEditorManager::controller(document); - QTC_ASSERT(controller, return 0); - - reloader = new SubversionDiffEditorReloader(this); - controller->setReloader(reloader); - controller->setContextLinesNumberEnabled(false); - } - QTC_ASSERT(reloader, return 0); - - reloader->setWorkingDirectory(workingDirectory); + IDocument *document = DiffEditorManager::findOrCreate(documentId, title); + DiffController *controller = qobject_cast(DiffEditorManager::controller(document)); + if (!controller) + controller = new DiffController(document, this, workingDirectory); VcsBasePlugin::setSource(document, source); - - return reloader; + return controller; } void SubversionClient::diff(const QString &workingDirectory, const QStringList &files, const QStringList &extraOptions) @@ -350,10 +313,10 @@ void SubversionClient::diff(const QString &workingDirectory, const QStringList & const QString documentId = VcsBaseEditor::getTitleId(workingDirectory, files); const QString title = vcsEditorTitle(vcsCmdString, documentId); - SubversionDiffEditorReloader *reloader = findOrCreateDiffEditor(documentId, workingDirectory, title, workingDirectory); - QTC_ASSERT(reloader, return); - reloader->setFilesList(files); - reloader->requestReload(); + DiffController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title, + workingDirectory); + controller->setFilesList(files); + controller->requestReload(); } void SubversionClient::log(const QString &workingDir, @@ -384,11 +347,9 @@ void SubversionClient::describe(const QString &workingDirectory, int changeNumbe QStringList(), QString::number(changeNumber)); - SubversionDiffEditorReloader *reloader = findOrCreateDiffEditor(documentId, workingDirectory, title, workingDirectory); - QTC_ASSERT(reloader, return); - reloader->setChangeNumber(changeNumber); - reloader->controller()->setDescriptionEnabled(true); - reloader->requestReload(); + DiffController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title, workingDirectory); + controller->setChangeNumber(changeNumber); + controller->requestReload(); } QString SubversionClient::findTopLevelForFile(const QFileInfo &file) const diff --git a/src/plugins/subversion/subversionclient.h b/src/plugins/subversion/subversionclient.h index ee283cfca6b..5db0327b169 100644 --- a/src/plugins/subversion/subversionclient.h +++ b/src/plugins/subversion/subversionclient.h @@ -41,7 +41,7 @@ namespace Subversion { namespace Internal { class SubversionSettings; -class SubversionDiffEditorReloader; +class DiffController; class SubversionClient : public VcsBase::VcsBaseClient { @@ -83,10 +83,8 @@ protected: Core::Id vcsEditorKind(VcsCommandTag cmd) const; private: - SubversionDiffEditorReloader *findOrCreateDiffEditor(const QString &documentId, - const QString &source, - const QString &title, - const QString &workingDirectory) const; + DiffController *findOrCreateDiffEditor(const QString &documentId, const QString &source, + const QString &title, const QString &workingDirectory) const; mutable Utils::FileName m_svnVersionBinary; mutable QString m_svnVersion; diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index f7e912840b7..7499d8b836c 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -345,7 +345,7 @@ void ChangeTextCursorHandler::slotCopyRevision() QAction *ChangeTextCursorHandler::createDescribeAction(const QString &change) const { - auto a = new QAction(VcsBaseEditorWidget::tr("Describe Change %1").arg(change), 0); + auto a = new QAction(VcsBaseEditorWidget::tr("&Describe Change %1").arg(change), 0); connect(a, &QAction::triggered, this, &ChangeTextCursorHandler::slotDescribe); return a; } diff --git a/src/shared/qbs b/src/shared/qbs index 6b9b900b699..cdc439efee5 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 6b9b900b699f507d0e7914ebca7e56d9f643c07f +Subproject commit cdc439efee5023c94ee1b5b5488011816b0f0f99 diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index ff3da1dd52d..1f6c947ca73 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -1287,6 +1287,8 @@ void tst_Dumpers::dumper() debugger.setWorkingDirectory(t->buildPath); debugger.start(QString::fromLatin1(exe), args); QVERIFY(debugger.waitForStarted()); + // FIXME: next line is necessary for LLDB <= 310 - remove asap + debugger.waitForReadyRead(1000); debugger.write(cmds); QVERIFY(debugger.waitForFinished()); output = debugger.readAllStandardOutput(); diff --git a/tests/system/objects.map b/tests/system/objects.map index 54f9da63b21..431ce20e569 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -14,6 +14,8 @@ :*Qt Creator.JavaScript_QTabBar {aboveWidget=':*Qt Creator.JavaScript_QDockWidget' type='QTabBar' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.Run_Core::Internal::FancyToolButton {text='Run' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.Start Debugging_Core::Internal::FancyToolButton {text='Start Debugging' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} +:*Qt Creator.Timeline_QDockWidget {name='QML ProfilerDockWidget' type='QDockWidget' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Timeline'} +:*Qt Creator.Timeline_QTabBar {aboveWidget=':*Qt Creator.Timeline_QDockWidget' type='QTabBar' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.Widget Box_QDockWidget {name='WidgetBoxDockWidget' type='QDockWidget' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Widget Box'} :*Qt Creator.findEdit_Utils::FilterLineEdit {name='findEdit' type='Utils::FancyLineEdit' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator_Core::Internal::FancyToolButton {occurrence='3' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} diff --git a/tests/system/suite_WELP/tst_WELP01/test.py b/tests/system/suite_WELP/tst_WELP01/test.py index bf87d76473b..c63b3ecf808 100755 --- a/tests/system/suite_WELP/tst_WELP01/test.py +++ b/tests/system/suite_WELP/tst_WELP01/test.py @@ -90,8 +90,8 @@ def main(): testDetails = "Verifying: Help with Creator Documentation is being opened." clickItemVerifyHelpCombo(gettingStartedText, expectedText, testDetails) - textUrls = {'Online Community':'http://qt-project.org/forums', - 'Blogs':'http://planet.qt-project.org', + textUrls = {'Online Community':'http://forum.qt.io', + 'Blogs':'http://planet.qt.io', 'Qt Account':'https://account.qt.io', 'Qt Cloud Services':'https://developer.qtcloudservices.com', 'User Guide':'qthelp://org.qt-project.qtcreator/doc/index.html' diff --git a/tests/system/suite_debugger/tst_simple_analyze/test.py b/tests/system/suite_debugger/tst_simple_analyze/test.py index c792dc14b46..9c4f1c73254 100644 --- a/tests/system/suite_debugger/tst_simple_analyze/test.py +++ b/tests/system/suite_debugger/tst_simple_analyze/test.py @@ -168,13 +168,14 @@ def containsOnce(tuple, items): def safeClickTab(tab): for bar in [":*Qt Creator.JavaScript_QTabBar", - ":*Qt Creator.Events_QTabBar"]: + ":*Qt Creator.Events_QTabBar", + ":*Qt Creator.Timeline_QTabBar"]: try: clickOnTab(bar, tab, 1000) return True except: pass - test.fail("Tab %s is not being shown." % tab) + test.fatal("Tab %s is not being shown." % tab) return False def init(): diff --git a/tests/system/suite_editors/tst_generic_highlighter/test.py b/tests/system/suite_editors/tst_generic_highlighter/test.py index dfcf18681a7..2d1e4c245b1 100644 --- a/tests/system/suite_editors/tst_generic_highlighter/test.py +++ b/tests/system/suite_editors/tst_generic_highlighter/test.py @@ -97,6 +97,8 @@ def getOrModifyFilePatternsFor(mimeType, filter='', toBePresent=None): result = toSuffixArray(patterns) test.passes("Added suffixes") return result + else: + result = toSuffixArray(patterns) else: result = toSuffixArray(patterns) elif model.rowCount() > 1: @@ -136,9 +138,11 @@ def addHighlighterDefinition(language): "type='QPushButton' visible='1'}") # downloading happens asynchronously languageFile = os.path.join(tmpSettingsDir, "QtProject", "qtcreator", - "generic-highlighter", "%s.xml" % language.lower()) + "generic-highlighter", "%s.xml" + % language.lower().replace(" ", "-")) test.verify(waitFor("os.path.exists(languageFile)", 10000), - "Verifying whether file has been downloaded and placed to settings.") + "Verifying whether highlight definition file for '%s' has been downloaded " + "and placed to settings." % language) clickButton("{text='Download Definitions...' type='QPushButton' unnamed='1' " "visible='1'}") table = waitForObject("{name='definitionsTable' type='QTableWidget' visible='1'}") @@ -160,13 +164,24 @@ def hasSuffix(fileName, suffixPatterns): return True return False +def displayHintForHighlighterDefinition(fileName, patterns, lPatterns, added, addedLiterate): + if hasSuffix(fileName, patterns): + return not added + if hasSuffix(fileName, lPatterns): + return not addedLiterate + test.warning("Got an unexpected suffix.", "Filename: %s, Patterns: %s" + % (fileName, str(patterns + lPatterns))) + return False + def main(): miss = "A highlight definition was not found for this file. Would you like to try to find one?" startApplication("qtcreator" + SettingsPath) if not startedWithoutPluginError(): return uncheckGenericHighlighterFallback() - patterns = getOrModifyFilePatternsFor("text/x-haskell", "haskell") + patterns = getOrModifyFilePatternsFor("text/x-haskell", "x-haskell") + lPatterns = getOrModifyFilePatternsFor("text/x-literate-haskell", "literate-haskell") + folder = tempDir() filesToTest = ["Main.lhs", "Main.hs"] code = ['module Main where', '', 'main :: IO ()', '', 'main = putStrLn "Hello World!"'] @@ -177,7 +192,7 @@ def main(): if editor == None: earlyExit("Something's really wrong! (did the UI change?)") return - expectHint = hasSuffix(current, patterns) + expectHint = hasSuffix(current, patterns) or hasSuffix(current, lPatterns) mssg = "Verifying whether hint for missing highlight definition is present. (expected: %s)" try: waitForObject("{text='%s' type='QLabel' unnamed='1' visible='1' " @@ -194,7 +209,9 @@ def main(): invokeMenuItem("File", "Save All") invokeMenuItem("File", "Close All") addedHighlighterDefinition = addHighlighterDefinition("Haskell") - patterns = getOrModifyFilePatternsFor('text/x-haskell', 'haskell', ['.lhs', '.hs']) + addedLiterateHighlighterDefinition = addHighlighterDefinition("Literate Haskell") + patterns = getOrModifyFilePatternsFor('text/x-haskell', 'x-haskell', ['.hs']) + lPatterns = getOrModifyFilePatternsFor('text/x-literate-haskell', 'literate-haskell', ['.lhs']) home = os.path.expanduser("~") for current in filesToTest: @@ -203,14 +220,17 @@ def main(): recentFile = recentFile.replace(home, "~", 1) invokeMenuItem("File", "Recent Files", recentFile) editor = getEditorForFileSuffix(current) + display = displayHintForHighlighterDefinition(current, patterns, lPatterns, + addedHighlighterDefinition, + addedLiterateHighlighterDefinition) try: waitForObject("{text='%s' type='QLabel' unnamed='1' visible='1' " "window=':Qt Creator_Core::Internal::MainWindow'}" % miss, 2000) - test.verify(not addedHighlighterDefinition and hasSuffix(current, patterns), - "Hint for missing highlight definition was present.") + test.verify(display, "Hint for missing highlight definition was present " + "- current file: %s" % current) except: - test.verify(addedHighlighterDefinition or not hasSuffix(current, patterns), - "Hint for missing highlight definition is not shown.") + test.verify(not display, "Hint for missing highlight definition is not shown " + "- current file: %s" % current) placeCursorToLine(editor, '.*%s' % code[-1], True) for _ in range(23): type(editor, "")