Merge remote-tracking branch 'origin/4.3'

Change-Id: I266a41de38789922363d1d88e73726cdca608920
This commit is contained in:
Eike Ziller
2017-03-22 10:26:01 +01:00
67 changed files with 560 additions and 703 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -1570,36 +1570,54 @@
\list \list
\li \uicontrol {All Projects} searches files matching the \li \uicontrol {All Projects} searches from all currently open
defined file pattern in all currently open projects. projects.
For example, to search for a string only in \c {.cpp}
and \c {.h} files, enter in \uicontrol {File pattern}
\c {*.cpp,*.h}.
\image qtcreator-search-allprojects.png \image qtcreator-search-allprojects.png
\li \uicontrol {Current Project} searches files matching the \li \uicontrol {Current Project} searches from the project you
defined file pattern only in the project you are currently are currently editing.
editing.
\li \uicontrol {Files in File System} recursively searches files \li \uicontrol {Files in File System} recursively searches from
matching the defined file pattern in the selected directory. the selected directory.
\image qtcreator-search-filesystem.png \image qtcreator-search-filesystem.png
Select the \uicontrol {Use Git Grep} check box to use Git to In the \uicontrol {Search engine} field, select the search
only search tracked files in the Git work tree. To restrict engine to use:
the search to the HEAD, a tag, a local or remote branch, or
a commit hash, enter a reference in the field. Leave the
field empty to search through the file system.
\li \uicontrol {Current File} searches only the current file. \list
\li Select \uicontrol Internal to use the \QC search
engine.
\li \uicontrol {Open Documents} searches all open files. \li Select \uicontrol {Git Grep} to use Git to only
search tracked files in the Git work tree. To
restrict the search to the HEAD, a tag, a local or
remote branch, or a commit hash, enter a reference.
Leave the field empty to search through the file
system.
\li Select \uicontrol {Silver Searcher} to use the
experimental Silver Searcher plugin. For more
information, see \l{Enabling Silver Searcher}.
\endlist
\li \uicontrol {Current File} searches only from the current
file.
\li \uicontrol {Open Documents} searches from all open files.
\endlist \endlist
\li In the \uicontrol {File pattern} field, specify file patterns to
restrict the search to files that match the pattern. For example, to
search for a string only in \c {.cpp} and \c {.h} files, enter
\c {*.cpp,*.h}.
\li In the \uicontrol {Exclusion pattern} field, specify file patterns
to omit files from the search.
\li Enter the text you are looking for and click \uicontrol Search. \li Enter the text you are looking for and click \uicontrol Search.
\image qtcreator-searchresults.png \image qtcreator-searchresults.png
@@ -1628,6 +1646,32 @@
\note You can use \uicontrol {Advanced Find} also to search for symbols. For \note You can use \uicontrol {Advanced Find} also to search for symbols. For
more information, see \l{Finding Symbols}. more information, see \l{Finding Symbols}.
\section1 Enabling Silver Searcher
You can use Silver Searcher as a search engine in \QC if you install
Silver Searcher on the development PC and enable the experimental plugin.
To use Silver Searcher:
\list 1
\li Download and install Silver Searcher from
\l {https://geoff.greer.fm/ag/}{The Silver Searcher} or
\l {https://github.com/ggreer/the_silver_searcher}{GitHub}.
You might have to build Silver Searcher from sources for some
platforms.
\li Select \uicontrol Help > \uicontrol {About Plugins} >
\uicontrol {Utilities} > \uicontrol {SilverSearcher} to enable the
plugin.
\li Restart \QC to be able to use the plugin.
\li When searching, select \uicontrol {Silver Searcher} in the
\uicontrol {Search engine} field.
\endlist
*/ */

View File

@@ -85,10 +85,9 @@
\endlist \endlist
\QC creates the test in the \c{tests\auto} directory in the project \QC creates the test in the specified project directory. Edit the .cpp file
directory. Edit the .cpp file to add private slots for each test to add private slots for each test function in your test. For more information
function in your test. For more information about creating Qt tests, see about creating Qt tests, see \l{Creating a Test}.
\l{Creating a Test}.
\section2 Creating Google Tests \section2 Creating Google Tests
@@ -133,8 +132,7 @@
\endlist \endlist
\QC creates the test in the \c{tests\auto} directory in the project \QC creates the test in the specified project directory.
directory.
\section1 Setting Up the Google C++ Testing Framework \section1 Setting Up the Google C++ Testing Framework

View File

@@ -318,28 +318,6 @@ class Dumper(DumperBase):
% (self.qtCoreModuleName(), namespace)) % (self.qtCoreModuleName(), namespace))
return namespace return namespace
def couldBeQObjectVTable(self, vtablePtr):
try:
customEventFunc = self.extractPointer(vtablePtr + 8 * self.ptrSize())
except:
self.bump('nostruct-3')
return False
if customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc):
return True
try:
delta = int.from_bytes(self.readRawMemory(customEventFunc + 1, 4), byteorder='little')
if (customEventFunc + 5 + delta) in (self.qtCustomEventFunc, self.qtCustomEventPltFunc):
return True
except:
pass
try:
return 'QObject::customEvent' in cdbext.getNameByAddress(customEventFunc)
except:
return False
def qtVersion(self): def qtVersion(self):
qtVersion = self.findValueByExpression('((void**)&%s)[2]' % self.qtHookDataSymbolName()) qtVersion = self.findValueByExpression('((void**)&%s)[2]' % self.qtHookDataSymbolName())
if qtVersion is None and self.qtCoreModuleName() is not None: if qtVersion is None and self.qtCoreModuleName() is not None:

View File

@@ -37,7 +37,7 @@ def extractPointerType(d, value):
postfix = "" postfix = ""
while stripTypeName(value) == "CPlusPlus::PointerType": while stripTypeName(value) == "CPlusPlus::PointerType":
postfix += "*" postfix += "*"
value = d.downcast(value["_elementType"]["_type"]) value = value["_elementType"]["_type"]
try: try:
return readLiteral(d, value["_name"]) + postfix return readLiteral(d, value["_name"]) + postfix
except: except:
@@ -60,7 +60,7 @@ def readTemplateName(d, value):
for i in range(int(size)): for i in range(int(size)):
if i > 0: if i > 0:
name += ", " name += ", "
name += extractPointerType(d, d.downcast(start[i]["_type"])) name += extractPointerType(d, start[i]["_type"])
except: except:
return "<not accessible>" return "<not accessible>"
name += ">" name += ">"
@@ -69,7 +69,6 @@ def readTemplateName(d, value):
def readLiteral(d, value): def readLiteral(d, value):
if d.isNull(value): if d.isNull(value):
return "<null>" return "<null>"
value = d.downcast(value)
type = value.type.unqualified() type = value.type.unqualified()
try: try:
type = type.target() type = type.target()
@@ -147,7 +146,7 @@ def qdump__CPlusPlus__IntegerType(d, value):
d.putPlainChildren(value) d.putPlainChildren(value)
def qdump__CPlusPlus__FullySpecifiedType(d, value): def qdump__CPlusPlus__FullySpecifiedType(d, value):
type = d.downcast(value["_type"]) type = value["_type"]
typeName = stripTypeName(type) typeName = stripTypeName(type)
if typeName == "CPlusPlus::NamedType": if typeName == "CPlusPlus::NamedType":
dumpLiteral(d, type["_name"]) dumpLiteral(d, type["_name"])

View File

@@ -1494,12 +1494,49 @@ class DumperBase:
return self.couldBeQObjectVTable(vtablePtr) return self.couldBeQObjectVTable(vtablePtr)
def couldBeQObjectVTable(self, vtablePtr): def couldBeQObjectVTable(self, vtablePtr):
def getJumpAddress_x86(dumper, address):
relativeJumpCode = 0xe9
jumpCode = 0xff
data = dumper.readRawMemory(address, 6)
primaryOpcode = data[0]
if primaryOpcode == relativeJumpCode:
# relative jump on 32 and 64 bit with a 32bit offset
offset = int.from_bytes(data[1:5], byteorder='little')
return address + 5 + offset
if primaryOpcode == jumpCode:
if data[1] != 0x25: # check for known extended opcode
return 0
# 0xff25 is a relative jump on 64bit and an absolute jump on 32 bit
if self.ptrSize() == 8:
offset = int.from_bytes(data[2:6], byteorder='little')
return address + 6 + offset
else:
return int.from_bytes(data[2:6], byteorder='little')
return 0
# Do not try to extract a function pointer if there are no values to compare with
if self.qtCustomEventFunc == 0 and self.qtCustomEventPltFunc == 0:
return False
try: try:
customEventFunc = self.extractPointer(vtablePtr + 9 * self.ptrSize()) customEventOffset = 8 if self.isMsvcTarget() else 9
customEventFunc = self.extractPointer(vtablePtr + customEventOffset * self.ptrSize())
except: except:
self.bump('nostruct-3') self.bump('nostruct-3')
return False return False
if self.isWindowsTarget():
if customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc):
return True
# The vtable may point to a function that is just calling the customEvent function
customEventFunc = getJumpAddress_x86(self, customEventFunc)
if customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc):
return True
customEventFunc = self.extractPointer(customEventFunc)
if customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc):
return True
# If the object is defined in another module there may be another level of indirection
customEventFunc = getJumpAddress_x86(self, customEventFunc)
return customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc) return customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc)
# def extractQObjectProperty(objectPtr): # def extractQObjectProperty(objectPtr):
@@ -3121,10 +3158,6 @@ class DumperBase:
val.type = self.dumper.createType(typish) val.type = self.dumper.createType(typish)
return val return val
def downcast(self):
self.check()
return self
def address(self): def address(self):
self.check() self.check()
return self.laddress return self.laddress

View File

@@ -487,12 +487,20 @@ def qdump__QFile(d, value):
# 9fc0965 and a373ffcd change the layout of the private structure # 9fc0965 and a373ffcd change the layout of the private structure
qtVersion = d.qtVersion() qtVersion = d.qtVersion()
is32bit = d.ptrSize() == 4 is32bit = d.ptrSize() == 4
if qtVersion >= 0x050600: if qtVersion >= 0x050700:
if d.isWindowsTarget(): if d.isWindowsTarget():
if d.isMsvcTarget(): if d.isMsvcTarget():
offset = 184 if is32bit else 248 offset = 184 if is32bit else 248
else: else:
offset = 164 if is32bit else 248 offset = 172 if is32bit else 248
else:
offset = 168 if is32bit else 248
elif qtVersion >= 0x050600:
if d.isWindowsTarget():
if d.isMsvcTarget():
offset = 184 if is32bit else 248
else:
offset = 180 if is32bit else 248
else: else:
offset = 168 if is32bit else 248 offset = 168 if is32bit else 248
elif qtVersion >= 0x050500: elif qtVersion >= 0x050500:

View File

@@ -1,3 +0,0 @@
TEMPLATE = subdirs
SUBDIRS += %{JS: '%{TestCaseName}'.toLowerCase()}

View File

@@ -1,26 +0,0 @@
import qbs
@if "%{TestFrameWork}" == "GTest"
import qbs.Environment
@endif
Project {
name: "auto tests"
@if "%{TestFrameWork}" == "GTest"
property string googletestDir: {
if (typeof Environment.getEnv("GOOGLETEST_DIR") === 'undefined') {
console.warn("Using googletest src dir specified at Qt Creator wizard")
console.log("set GOOGLETEST_DIR as environment variable or Qbs property to get rid of this message")
return "%{GTestRepository}"
} else {
return Environment.getEnv("GOOGLETEST_DIR")
}
}
@endif
@if "%{BuildAutoTests}" == "debug"
condition: qbs.buildVariant === "debug"
@endif
references: [
"%{JS: '%{TestCaseName}'.toLowerCase()}/%{JS: '%{TestCaseName}'.toLowerCase()}.qbs"
]
}

View File

@@ -1,31 +0,0 @@
%{Cpp:LicenseTemplate}\
@if "%{TestFrameWork}" == "QtTest"
@if "%{RequireGUI}" == "true"
%{JS: QtSupport.qtIncludes([ 'QtGui/QApplication' ],
[ 'QtWidgets/QApplication' ]) }\
@else
%{JS: QtSupport.qtIncludes([ 'QtCore/QCoreApplication' ],
[ 'QtCore/QCoreApplication' ]) }\
@endif
// add necessary includes here
int main(int argc, char *argv[])
{
@if "%{RequireGUI}" == "true"
QApplication a(argc, argv);
@else
QCoreApplication a(argc, argv);
@endif
return a.exec();
}
@else
#include <iostream>
int main(int , char **)
{
std::cout << "Hello World!\\n";
return 0;
}
@endif

View File

@@ -1,18 +0,0 @@
@if "%{TestFrameWork}" == "QtTest"
@if "%{RequireGUI}" == "true"
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
@else
QT -= gui
@endif
@else
CONFIG -= qt
@endif
CONFIG += console c++11
CONFIG -= app_bundle
TEMPLATE = app
TARGET = %{ProjectName}
SOURCES += %{MainCppName}

View File

@@ -1,27 +0,0 @@
import qbs
CppApplication {
type: "application"
consoleApplication: true
name: "%{ProjectName}"
@if "%{TestFrameWork}" == "QtTest"
@if "%{RequireGUI}" == "true"
Depends { name: "Qt.core" }
Depends { name: "Qt.gui" }
Depends {
name: "Qt.widgets"
condition: Qt.core.versionMajor > 4
}
@else
Depends { name: "Qt.core" }
@endif
@endif
cpp.cxxLanguageVersion: "c++11"
files: [
"%{MainCppName}"
]
}

View File

@@ -1,3 +0,0 @@
TEMPLATE = subdirs
SUBDIRS += auto

View File

@@ -1,8 +0,0 @@
import qbs
Project {
name: "%{ProjectName} tests"
references: [
"auto/auto.qbs"
]
}

View File

@@ -1,12 +0,0 @@
TEMPLATE = subdirs
@if "%{BuildAutoTests}" == "always"
SUBDIRS += src \
tests
@else
SUBDIRS += src
CONFIG(debug, debug|release) {
SUBDIRS += tests
}
@endif

View File

@@ -1,8 +0,0 @@
import qbs
Project {
references: [
"src/src.qbs",
"tests/tests.qbs"
]
}

View File

@@ -14,7 +14,7 @@ TEMPLATE = app
SOURCES += %{TestCaseFileWithCppSuffix} SOURCES += %{TestCaseFileWithCppSuffix}
@else @else
include(../gtest_dependency.pri) include(gtest_dependency.pri)
TEMPLATE = app TEMPLATE = app
@if "%{GTestCXX11}" == "true" @if "%{GTestCXX11}" == "true"

View File

@@ -1,6 +1,7 @@
import qbs import qbs
@if "%{TestFrameWork}" == "GTest" @if "%{TestFrameWork}" == "GTest"
import "../googlecommon.js" as googleCommon import qbs.Environment
import "googlecommon.js" as googleCommon
@endif @endif
CppApplication { CppApplication {
@@ -16,6 +17,19 @@ CppApplication {
] ]
@else @else
consoleApplication: true consoleApplication: true
@if "%{TestFrameWork}" == "GTest"
property string googletestDir: {
if (typeof Environment.getEnv("GOOGLETEST_DIR") === 'undefined') {
console.warn("Using googletest src dir specified at Qt Creator wizard")
console.log("set GOOGLETEST_DIR as environment variable or Qbs property to get rid of this message")
return "%{GTestRepository}"
} else {
return Environment.getEnv("GOOGLETEST_DIR")
}
}
@endif
@if "%{GTestCXX11}" == "true" @if "%{GTestCXX11}" == "true"
cpp.cxxLanguageVersion: "c++11" cpp.cxxLanguageVersion: "c++11"
cpp.defines: [ "GTEST_LANG_CXX11" ] cpp.defines: [ "GTEST_LANG_CXX11" ]
@@ -23,13 +37,13 @@ CppApplication {
cpp.dynamicLibraries: [ "pthread" ] cpp.dynamicLibraries: [ "pthread" ]
cpp.includePaths: [].concat(googleCommon.getGTestIncludes(project.googletestDir)) cpp.includePaths: [].concat(googleCommon.getGTestIncludes(googletestDir))
.concat(googleCommon.getGMockIncludes(project.googletestDir)) .concat(googleCommon.getGMockIncludes(googletestDir))
files: [ files: [
"%{MainCppName}", "%{MainCppName}",
"%{TestCaseFileWithHeaderSuffix}", "%{TestCaseFileWithHeaderSuffix}",
].concat(googleCommon.getGTestAll(project.googletestDir)) ].concat(googleCommon.getGTestAll(googletestDir))
.concat(googleCommon.getGMockAll(project.googletestDir)) .concat(googleCommon.getGMockAll(googletestDir))
@endif @endif
} }

View File

@@ -0,0 +1,57 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.1)
PROJECT(%{TestCaseName}
LANGUAGES CXX)
@if "%{TestFrameWork}" == "QtTest"
find_package(Qt5Test REQUIRED)
@if "%{RequireGUI}" == "true"
find_package(Qt5Gui REQUIRED)
@endif
SET(CMAKE_AUTOMOC ON)
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
SET(CMAKE_CXX_STANDARD 11)
ENABLE_TESTING()
add_executable(${PROJECT_NAME} %{TestCaseFileWithCppSuffix})
add_test(${PROJECT_NAME} COMMAND ${PROJECT_NAME})
@if "%{RequireGUI}" == "true"
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Gui Qt5::Test)
@else
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Test)
@endif
@else
@if "%{GTestCXX11}" == "true"
add_definitions(-DGTEST_LANGUAGE_CXX11)
@endif
find_package(Threads REQUIRED)
if ($ENV{GOOGLETEST_DIR})
SET(GOOGLETEST_DIR $ENV{GOOGLETEST_DIR})
else ()
message(WARNING "Using googletest src dir specified at Qt Creator wizard")
SET(GOOGLETEST_DIR "%{GTestRepository}")
endif ()
if (EXISTS ${GOOGLETEST_DIR})
SET(GTestSrc ${GOOGLETEST_DIR}/googletest)
SET(GMockSrc ${GOOGLETEST_DIR}/googlemock)
else ()
message( FATAL_ERROR "No googletest src dir found - set GOOGLETEST_DIR to enable!")
endif ()
include_directories(${GTestSrc} ${GTestSrc}/include ${GMockSrc} ${GMockSrc}/include)
add_executable(${PROJECT_NAME} %{MainCppName} %{TestCaseFileWithHeaderSuffix}
${GTestSrc}/src/gtest-all.cc
${GMockSrc}/src/gmock-all.cc)
add_test(${PROJECT_NAME} COMMAND ${PROJECT_NAME})
target_link_libraries(${PROJECT_NAME} PRIVATE Threads::Threads)
@endif

View File

@@ -3,7 +3,7 @@
"supportedProjectTypes": [ "Qt4ProjectManager.Qt4Project" ], "supportedProjectTypes": [ "Qt4ProjectManager.Qt4Project" ],
"id": "R.AutoTest", "id": "R.AutoTest",
"category": "H.Project", "category": "H.Project",
"trDescription": "Creates a new project including an auto test skeleton.", "trDescription": "Creates a new unit test project. Unit tests allow you to verify that the code is fit for use and that there are no regressions.",
"trDisplayName": "Auto Test Project", "trDisplayName": "Auto Test Project",
"trDisplayCategory": "Other Project", "trDisplayCategory": "Other Project",
"icon": "autotest_24.png", "icon": "autotest_24.png",
@@ -13,7 +13,7 @@
"options": "options":
[ [
{ "key": "ProjectFilePath", { "key": "ProjectFilePath",
"value": "%{JS: '%{BuildSystem}' == 'qmake' ? '%{ProFileName}' : '%{QbsFileName}' }" "value": "%{JS: '%{BuildSystem}' == 'qmake' ? '%{ProFileName}' : ('%{BuildSystem}' == 'qbs' ? '%{QbsFileName}' : '%{CMakeFileName}') }"
}, },
{ "key": "ProFileName", { "key": "ProFileName",
"value": "%{JS: Util.fileName('%{ProjectDirectory}/%{ProjectName}', 'pro')}" "value": "%{JS: Util.fileName('%{ProjectDirectory}/%{ProjectName}', 'pro')}"
@@ -22,6 +22,10 @@
"key": "QbsFileName", "key": "QbsFileName",
"value": "%{JS: Util.fileName('%{ProjectDirectory}/%{ProjectName}', 'qbs')}" "value": "%{JS: Util.fileName('%{ProjectDirectory}/%{ProjectName}', 'qbs')}"
}, },
{
"key": "CMakeFileName",
"value": "%{ProjectDirectory}/CMakeLists.txt"
},
{ "key": "IsTopLevelProject", { "key": "IsTopLevelProject",
"value": "%{JS: !'%{Exists:ProjectExplorer.Profile.Ids}' }" "value": "%{JS: !'%{Exists:ProjectExplorer.Profile.Ids}' }"
}, },
@@ -46,7 +50,7 @@
"typeId": "Project", "typeId": "Project",
"data": "data":
{ {
"trDescription": "This wizard creates a simple project with an additional auto test skeleton." "trDescription": "This wizard creates a simple unit test project."
} }
}, },
{ {
@@ -133,26 +137,6 @@
"uncheckedValue": "false" "uncheckedValue": "false"
} }
}, },
{
"name": "BuildAutoTests",
"trDisplayName": "Build auto tests",
"type": "ComboBox",
"data":
{
"index": 0,
"items":
[
{
"trKey": "always",
"value": "always"
},
{
"trKey": "debug only",
"value": "debug"
}
]
}
},
{ {
"name": "GTestRepository", "name": "GTestRepository",
"trDisplayName": "Googletest repository:", "trDisplayName": "Googletest repository:",
@@ -179,6 +163,11 @@
"trKey": "Qbs", "trKey": "Qbs",
"value": "qbs", "value": "qbs",
"condition": "%{JS: [ %{Plugins} ].indexOf('QbsProjectManager') >= 0}" "condition": "%{JS: [ %{Plugins} ].indexOf('QbsProjectManager') >= 0}"
},
{
"trKey": "CMake",
"value": "cmake",
"condition": "%{JS: [ %{Plugins} ].indexOf('CMakeProjectManager') >= 0}"
} }
] ]
} }
@@ -191,7 +180,8 @@
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{IsTopLevelProject}", "enabled": "%{IsTopLevelProject}",
"data": { "data": {
"projectFilePath": "%{ProjectFilePath}" "projectFilePath": "%{ProjectFilePath}",
"requiredFeatures": [ "%{JS: ('%{BuildSystem}' == 'cmake' && '%{TestFrameWork}' == 'QtTest') ? 'QtSupport.Wizards.FeatureQt.5' : 'QtSupport.Wizards.FeatureQt' }" ]
} }
}, },
{ {
@@ -206,98 +196,54 @@
"typeId": "File", "typeId": "File",
"data": "data":
[ [
{
"source": "files/tmp.pro",
"target": "%{ProFileName}",
"condition": "%{JS: '%{BuildSystem}' == 'qmake'}",
"openAsProject": true
},
{
"source": "files/tmp.qbs",
"target": "%{QbsFileName}",
"condition": "%{JS: '%{BuildSystem}' == 'qbs'}",
"openAsProject": true
},
{
"source": "files/src.pro",
"target": "src/src.pro",
"condition": "%{JS: '%{BuildSystem}' == 'qmake'}",
"openInEditor": false
},
{
"source": "files/src.qbs",
"target": "src/src.qbs",
"condition": "%{JS: '%{BuildSystem}' == 'qbs'}",
"openInEditor": false
},
{
"source": "files/main.cpp",
"target": "src/%{MainCppName}",
"openInEditor": true
},
{
"source": "files/tests.pro",
"target": "tests/tests.pro",
"condition": "%{JS: '%{BuildSystem}' == 'qmake'}",
"openInEditor": false
},
{
"source": "files/tests.qbs",
"target": "tests/tests.qbs",
"condition": "%{JS: '%{BuildSystem}' == 'qbs'}",
"openInEditor": false
},
{
"source": "files/auto.pro",
"target": "tests/auto/auto.pro",
"condition": "%{JS: '%{BuildSystem}' == 'qmake'}",
"openInEditor": false
},
{
"source": "files/auto.qbs",
"target": "tests/auto/auto.qbs",
"condition": "%{JS: '%{BuildSystem}' == 'qbs'}",
"openInEditor": false
},
{ {
"source": "files/gtest_dependency.pri", "source": "files/gtest_dependency.pri",
"target": "tests/auto/gtest_dependency.pri", "target": "gtest_dependency.pri",
"condition": "%{JS: '%{TestFrameWork}' == 'GTest' && '%{BuildSystem}' == 'qmake'}", "condition": "%{JS: '%{TestFrameWork}' == 'GTest' && '%{BuildSystem}' == 'qmake'}",
"openInEditor": false "openInEditor": false
}, },
{ {
"source": "files/googlecommon.js", "source": "files/googlecommon.js",
"target": "tests/auto/googlecommon.js", "target": "googlecommon.js",
"condition": "%{JS: '%{TestFrameWork}' == 'GTest' && '%{BuildSystem}' == 'qbs'}", "condition": "%{JS: '%{TestFrameWork}' == 'GTest' && '%{BuildSystem}' == 'qbs'}",
"openInEditor": false "openInEditor": false
}, },
{ {
"source": "files/tst.pro", "source": "files/tst.pro",
"target": "%{JS: 'tests/auto/' + '%{TestCaseName}/%{TestCaseName}'.toLowerCase() + '.pro' }", "target": "%{ProjectFilePath}",
"condition": "%{JS: '%{BuildSystem}' == 'qmake'}", "condition": "%{JS: '%{BuildSystem}' == 'qmake'}",
"openInEditor": false "openInEditor": false,
"openAsProject": true
}, },
{ {
"source": "files/tst.qbs", "source": "files/tst.qbs",
"target": "%{JS: 'tests/auto/' + '%{TestCaseName}/%{TestCaseName}'.toLowerCase() + '.qbs' }", "target": "%{ProjectFilePath}",
"condition": "%{JS: '%{BuildSystem}' == 'qbs'}", "condition": "%{JS: '%{BuildSystem}' == 'qbs'}",
"openInEditor": false "openInEditor": false,
"openAsProject": true
},
{
"source": "files/tst.txt",
"target": "CMakeLists.txt",
"condition": "%{JS: '%{BuildSystem}' == 'cmake'}",
"openInEditor": false,
"openAsProject": true
}, },
{ {
"source": "files/tst_src.h", "source": "files/tst_src.h",
"target": "%{JS: 'tests/auto/' + '%{TestCaseName}/'.toLowerCase() + '%{TestCaseFileWithHeaderSuffix}' }", "target": "%{TestCaseFileWithHeaderSuffix}",
"condition": "%{JS: '%{TestFrameWork}' == 'GTest'}", "condition": "%{JS: '%{TestFrameWork}' == 'GTest'}",
"openInEditor": true "openInEditor": true
}, },
{ {
"source": "files/tst_src.cpp", "source": "files/tst_src.cpp",
"target": "%{JS: 'tests/auto/' + '%{TestCaseName}/'.toLowerCase() + '%{TestCaseFileWithCppSuffix}' }", "target": "%{TestCaseFileWithCppSuffix}",
"condition": "%{JS: '%{TestFrameWork}' == 'QtTest'}", "condition": "%{JS: '%{TestFrameWork}' == 'QtTest'}",
"openInEditor": true "openInEditor": true
}, },
{ {
"source": "files/tst_main.cpp", "source": "files/tst_main.cpp",
"target": "%{JS: 'tests/auto/' + '%{TestCaseName}'.toLowerCase() + '/%{MainCppName}' }", "target": "%{MainCppName}",
"condition": "%{JS: '%{TestFrameWork}' == 'GTest'}", "condition": "%{JS: '%{TestFrameWork}' == 'GTest'}",
"openInEditor": true "openInEditor": true
}, },

View File

@@ -62,10 +62,7 @@ QString NameController::convertFileNameToElementName(const QString &fileName)
elementName += baseName.at(i).toTitleCase(); elementName += baseName.at(i).toTitleCase();
makeTitlecase = false; makeTitlecase = false;
} else { } else {
if (insertSpace) { // insertSpace must be false here
elementName += QLatin1Char(' ');
insertSpace = false;
}
elementName += baseName.at(i); elementName += baseName.at(i);
} }
} }

View File

@@ -589,7 +589,7 @@ void ClassItem::updateMembers(const Style *style)
bool addSpace = false; bool addSpace = false;
if (currentVisibility) if (currentVisibility)
*currentVisibility = member.visibility(); *currentVisibility = member.visibility();
if (member.group() != currentGroup) { if (currentGroup && member.group() != *currentGroup) {
*text += QString(QStringLiteral("[%1]")).arg(member.group()); *text += QString(QStringLiteral("[%1]")).arg(member.group());
addNewline = true; addNewline = true;
*currentGroup = member.group(); *currentGroup = member.group();

View File

@@ -26,6 +26,7 @@
#include "basetreeview.h" #include "basetreeview.h"
#include "progressindicator.h" #include "progressindicator.h"
#include "treemodel.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -271,35 +272,14 @@ BaseTreeView::~BaseTreeView()
void BaseTreeView::setModel(QAbstractItemModel *m) void BaseTreeView::setModel(QAbstractItemModel *m)
{ {
struct ExtraConnection { if (BaseTreeModel *oldModel = qobject_cast<BaseTreeModel *>(model()))
const char *signature; disconnect(oldModel, &BaseTreeModel::requestExpansion, this, &BaseTreeView::expand);
const char *qsignal;
QObject *receiver;
const char *qslot;
};
#define DESC(sign, receiver, slot) { #sign, SIGNAL(sign), receiver, SLOT(slot) }
const ExtraConnection c[] = {
DESC(requestExpansion(QModelIndex), this, expand(QModelIndex))
};
#undef DESC
QAbstractItemModel *oldModel = model();
if (oldModel) {
for (unsigned i = 0; i < sizeof(c) / sizeof(c[0]); ++i) {
int index = model()->metaObject()->indexOfSignal(c[i].signature);
if (index != -1)
disconnect(model(), c[i].qsignal, c[i].receiver, c[i].qslot);
}
}
TreeView::setModel(m); TreeView::setModel(m);
if (m) { if (m) {
for (unsigned i = 0; i < sizeof(c) / sizeof(c[0]); ++i) { if (BaseTreeModel *newModel = qobject_cast<BaseTreeModel *>(m))
int index = m->metaObject()->indexOfSignal(c[i].signature); connect(newModel, &BaseTreeModel::requestExpansion, this, &BaseTreeView::expand);
if (index != -1)
connect(model(), c[i].qsignal, c[i].receiver, c[i].qslot);
}
d->restoreState(); d->restoreState();
QVariant delegateBlob = m->data(QModelIndex(), ItemDelegateRole); QVariant delegateBlob = m->data(QModelIndex(), ItemDelegateRole);

View File

@@ -183,7 +183,7 @@ bool AbstractMacroExpander::expandNestedMacros(const QString &str, int *pos, QSt
if (!expandNestedMacros(str, &i, ret)) if (!expandNestedMacros(str, &i, ret))
return false; return false;
varName.chop(1); varName.chop(1);
varName += ret; varName += *ret;
} else if (currArg == &varName && c == '-' && prev == ':' && validateVarName(varName)) { } else if (currArg == &varName && c == '-' && prev == ':' && validateVarName(varName)) {
varName.chop(1); varName.chop(1);
currArg = &defaultValue; currArg = &defaultValue;

View File

@@ -37,13 +37,9 @@
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QFileSystemWatcher>
namespace Autotest { namespace Autotest {
namespace Internal { namespace Internal {
static QFileSystemWatcher s_directoryWatcher;
TestTreeItem *QuickTestParseResult::createTestTreeItem() const TestTreeItem *QuickTestParseResult::createTestTreeItem() const
{ {
if (itemType == TestTreeItem::Root || itemType == TestTreeItem::TestDataTag) if (itemType == TestTreeItem::Root || itemType == TestTreeItem::TestDataTag)
@@ -126,7 +122,7 @@ static QString quickTestName(const CPlusPlus::Document::Ptr &doc)
return QString(); return QString();
} }
static QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QString &srcDir) QList<QmlJS::Document::Ptr> QuickTestParser::scanDirectoryForQuickTestQmlFiles(const QString &srcDir) const
{ {
QStringList dirs(srcDir); QStringList dirs(srcDir);
QmlJS::ModelManagerInterface *qmlJsMM = QmlJSTools::Internal::ModelManager::instance(); QmlJS::ModelManagerInterface *qmlJsMM = QmlJSTools::Internal::ModelManager::instance();
@@ -142,9 +138,9 @@ static QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QStri
while (it.hasNext()) { while (it.hasNext()) {
it.next(); it.next();
QFileInfo fi(it.fileInfo().canonicalFilePath()); QFileInfo fi(it.fileInfo().canonicalFilePath());
dirs << fi.filePath(); dirs.append(fi.filePath());
} }
s_directoryWatcher.addPaths(dirs); emit updateWatchPaths(dirs);
QList<QmlJS::Document::Ptr> foundDocs; QList<QmlJS::Document::Ptr> foundDocs;
@@ -211,9 +207,9 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr
return true; return true;
} }
static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface, bool QuickTestParser::handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface,
CPlusPlus::Document::Ptr document, CPlusPlus::Document::Ptr document,
const Core::Id &id) const Core::Id &id) const
{ {
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
if (quickTestName(document).isEmpty()) if (quickTestName(document).isEmpty())
@@ -229,32 +225,35 @@ static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterfa
if (srcDir.isEmpty()) if (srcDir.isEmpty())
return false; return false;
if (futureInterface.isCanceled())
return false;
const QList<QmlJS::Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir); const QList<QmlJS::Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir);
bool result = false; bool result = false;
for (const QmlJS::Document::Ptr &qmlJSDoc : qmlDocs) for (const QmlJS::Document::Ptr &qmlJSDoc : qmlDocs) {
if (futureInterface.isCanceled())
break;
result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, id, proFile); result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, id, proFile);
}
return result; return result;
} }
QuickTestParser::QuickTestParser() QuickTestParser::QuickTestParser()
: CppParser() : CppParser()
{ {
QObject::connect(ProjectExplorer::SessionManager::instance(), connect(ProjectExplorer::SessionManager::instance(),
&ProjectExplorer::SessionManager::startupProjectChanged, [] { &ProjectExplorer::SessionManager::startupProjectChanged, [this] {
const QStringList &dirs = s_directoryWatcher.directories(); const QStringList &dirs = m_directoryWatcher.directories();
if (!dirs.isEmpty()) if (!dirs.isEmpty())
s_directoryWatcher.removePaths(dirs); m_directoryWatcher.removePaths(dirs);
}); });
QObject::connect(&s_directoryWatcher, &QFileSystemWatcher::directoryChanged, connect(&m_directoryWatcher, &QFileSystemWatcher::directoryChanged,
[this] { TestTreeModel::instance()->parser()->emitUpdateTestTree(this); }); [this] { TestTreeModel::instance()->parser()->emitUpdateTestTree(this); });
connect(this, &QuickTestParser::updateWatchPaths,
&m_directoryWatcher, &QFileSystemWatcher::addPaths, Qt::QueuedConnection);
} }
QuickTestParser::~QuickTestParser() QuickTestParser::~QuickTestParser()
{ {
QObject::disconnect(&s_directoryWatcher, 0, 0, 0);
const QStringList &dirs = s_directoryWatcher.directories();
if (!dirs.isEmpty())
s_directoryWatcher.removePaths(dirs);
} }
void QuickTestParser::init(const QStringList &filesToParse) void QuickTestParser::init(const QStringList &filesToParse)

View File

@@ -29,6 +29,8 @@
#include <qmljs/qmljsdocument.h> #include <qmljs/qmljsdocument.h>
#include <QFileSystemWatcher>
namespace Autotest { namespace Autotest {
namespace Internal { namespace Internal {
@@ -39,8 +41,9 @@ public:
TestTreeItem *createTestTreeItem() const override; TestTreeItem *createTestTreeItem() const override;
}; };
class QuickTestParser : public CppParser class QuickTestParser : public QObject, public CppParser
{ {
Q_OBJECT
public: public:
QuickTestParser(); QuickTestParser();
virtual ~QuickTestParser(); virtual ~QuickTestParser();
@@ -48,9 +51,15 @@ public:
void release() override; void release() override;
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface, bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
const QString &fileName) override; const QString &fileName) override;
signals:
void updateWatchPaths(const QStringList &directories) const;
private: private:
bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface,
CPlusPlus::Document::Ptr document, const Core::Id &id) const;
QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QString &srcDir) const;
QmlJS::Snapshot m_qmlSnapshot; QmlJS::Snapshot m_qmlSnapshot;
QHash<QString, QString> m_proFilesForQmlFiles; QHash<QString, QString> m_proFilesForQmlFiles;
QFileSystemWatcher m_directoryWatcher;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -645,7 +645,7 @@ int BinEditorWidget::dataLastIndexOf(const QByteArray &pattern, qint64 from, boo
int block = from / m_blockSize; int block = from / m_blockSize;
const int lowerBound = qMax(qint64(0), from - SearchStride); const int lowerBound = qMax(qint64(0), from - SearchStride);
while (from > lowerBound) { while (from > lowerBound) {
if (!requestDataAt(block * m_blockSize)) if (!requestDataAt(qint64(block) * m_blockSize))
return -1; return -1;
QByteArray data = blockData(block); QByteArray data = blockData(block);
::memcpy(b + m_blockSize, b, trailing); ::memcpy(b + m_blockSize, b, trailing);
@@ -658,7 +658,7 @@ int BinEditorWidget::dataLastIndexOf(const QByteArray &pattern, qint64 from, boo
if (pos >= 0) if (pos >= 0)
return pos + block * m_blockSize; return pos + block * m_blockSize;
--block; --block;
from = block * m_blockSize + (m_blockSize-1) + trailing; from = qint64(block) * m_blockSize + (m_blockSize-1) + trailing;
} }
return lowerBound == 0 ? -1 : -2; return lowerBound == 0 ? -1 : -2;
} }

View File

@@ -313,9 +313,9 @@ QStringList CMakeProject::files(FilesMode fileMode) const
if (ProjectNode *rpn = rootProjectNode()) { if (ProjectNode *rpn = rootProjectNode()) {
rpn->forEachNode([&](const FileNode *fn) { rpn->forEachNode([&](const FileNode *fn) {
const bool isGenerated = fn->isGenerated(); const bool isGenerated = fn->isGenerated();
if (fileMode == Project::SourceFiles && !isGenerated) if ((fileMode & Project::SourceFiles) && !isGenerated)
result.append(fn->filePath().toString()); result.append(fn->filePath().toString());
if (fileMode == Project::GeneratedFiles && isGenerated) if ((fileMode & Project::GeneratedFiles) && isGenerated)
result.append(fn->filePath().toString()); result.append(fn->filePath().toString());
}); });
} }

View File

@@ -1033,6 +1033,12 @@ void EditorManagerPrivate::readSettings()
d->m_autoSaveEnabled = qs->value(autoSaveEnabledKey).toBool(); d->m_autoSaveEnabled = qs->value(autoSaveEnabledKey).toBool();
d->m_autoSaveInterval = qs->value(autoSaveIntervalKey).toInt(); d->m_autoSaveInterval = qs->value(autoSaveIntervalKey).toInt();
} }
if (qs->contains(autoSuspendEnabledKey)) {
d->m_autoSuspendEnabled = qs->value(autoSuspendEnabledKey).toBool();
d->m_autoSuspendMinDocumentCount = qs->value(autoSuspendMinDocumentCountKey).toInt();
}
updateAutoSave(); updateAutoSave();
} }

View File

@@ -1696,10 +1696,16 @@ QmlV8ObjectData QmlEnginePrivate::extractData(const QVariant &data) const
if (dataMap.contains("value")) { if (dataMap.contains("value")) {
QVariant value = dataMap.value("value"); QVariant value = dataMap.value("value");
if (value.isNull()) // The QVariant representation of null has changed across various Qt versions
// 5.6, 5.7: QVariant::Invalid
// 5.8: isValid(), !isNull(), type() == 51; only typeName() is unique: "std::nullptr_t"
// 5.9: isValid(), isNull(); We can then use isNull()
if (!value.isValid() || value.isNull()
|| strcmp(value.typeName(), "std::nullptr_t") == 0) {
objectData.value = "null"; // Yes, null is an object. objectData.value = "null"; // Yes, null is an object.
else if (value.isValid()) } else if (value.isValid()) {
objectData.expectedProperties = value.toInt(); objectData.expectedProperties = value.toInt();
}
} }
if (dataMap.contains("properties")) if (dataMap.contains("properties"))

View File

@@ -737,10 +737,15 @@ static GerritChangePtr parseSshOutput(const QJsonObject &object)
} }
*/ */
static int restNumberValue(const QJsonObject &object)
{
return object.value("_number").toInt();
}
static GerritChangePtr parseRestOutput(const QJsonObject &object, const GerritServer &server) static GerritChangePtr parseRestOutput(const QJsonObject &object, const GerritServer &server)
{ {
GerritChangePtr change(new GerritChange); GerritChangePtr change(new GerritChange);
change->number = object.value("_number").toInt(); change->number = restNumberValue(object);
change->url = QString("%1/%2").arg(server.url()).arg(change->number); change->url = QString("%1/%2").arg(server.url()).arg(change->number);
change->title = object.value("subject").toString(); change->title = object.value("subject").toString();
change->owner = parseGerritUser(object.value("owner").toObject()); change->owner = parseGerritUser(object.value("owner").toObject());
@@ -751,10 +756,11 @@ static GerritChangePtr parseRestOutput(const QJsonObject &object, const GerritSe
Qt::DateFormat::ISODate).toLocalTime(); Qt::DateFormat::ISODate).toLocalTime();
// Read current patch set. // Read current patch set.
const QJsonObject patchSet = object.value("revisions").toObject().begin().value().toObject(); const QJsonObject patchSet = object.value("revisions").toObject().begin().value().toObject();
change->currentPatchSet.patchSetNumber = qMax(1, patchSet.value("number").toString().toInt()); change->currentPatchSet.patchSetNumber = qMax(1, restNumberValue(patchSet));
change->currentPatchSet.ref = patchSet.value("ref").toString(); const QJsonObject fetchInfo = patchSet.value("fetch").toObject().value("http").toObject();
change->currentPatchSet.ref = fetchInfo.value("ref").toString();
// Replace * in ssh://*:29418/qt-creator/qt-creator with the hostname // Replace * in ssh://*:29418/qt-creator/qt-creator with the hostname
change->currentPatchSet.url = patchSet.value("url").toString().replace('*', server.host); change->currentPatchSet.url = fetchInfo.value("url").toString().replace('*', server.host);
const QJsonObject labels = object.value("labels").toObject(); const QJsonObject labels = object.value("labels").toObject();
for (auto it = labels.constBegin(), end = labels.constEnd(); it != end; ++it) { for (auto it = labels.constBegin(), end = labels.constEnd(); it != end; ++it) {
const QJsonArray all = it.value().toObject().value("all").toArray(); const QJsonArray all = it.value().toObject().value("all").toArray();

View File

@@ -91,6 +91,7 @@ bool FindMacroHandler::executeEvent(const MacroEvent &macroEvent)
currentFind->replace(macroEvent.value(BEFORE).toString(), currentFind->replace(macroEvent.value(BEFORE).toString(),
macroEvent.value(AFTER).toString(), macroEvent.value(AFTER).toString(),
(Core::FindFlags)macroEvent.value(FLAGS).toInt()); (Core::FindFlags)macroEvent.value(FLAGS).toInt());
break;
case REPLACESTEP: case REPLACESTEP:
currentFind->replaceStep(macroEvent.value(BEFORE).toString(), currentFind->replaceStep(macroEvent.value(BEFORE).toString(),
macroEvent.value(AFTER).toString(), macroEvent.value(AFTER).toString(),

View File

@@ -198,8 +198,6 @@ void PxNodeController::addExplorerNode(const ProjectExplorer::Node *node,
menu->popup(QCursor::pos()); menu->popup(QCursor::pos());
break; break;
} }
case ProjectExplorer::NodeType::Session:
break;
} }
} }

View File

@@ -80,9 +80,6 @@ QString PxNodeUtilities::calcRelativePath(const ProjectExplorer::Node *node,
case ProjectExplorer::NodeType::Project: case ProjectExplorer::NodeType::Project:
nodePath = node->filePath().toString(); nodePath = node->filePath().toString();
break; break;
case ProjectExplorer::NodeType::Session:
QTC_ASSERT(false, return QString());
break;
} }
return qmt::NameController::calcRelativePath(nodePath, anchorFolder); return qmt::NameController::calcRelativePath(nodePath, anchorFolder);

View File

@@ -39,6 +39,9 @@
#include <coreplugin/idocument.h> #include <coreplugin/idocument.h>
#include <coreplugin/icontext.h> #include <coreplugin/icontext.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
#include <projectexplorer/buildmanager.h> #include <projectexplorer/buildmanager.h>
#include <projectexplorer/kitmanager.h> #include <projectexplorer/kitmanager.h>
#include <projectexplorer/projecttree.h> #include <projectexplorer/projecttree.h>
@@ -80,18 +83,52 @@ const char PLUGIN_SETTINGS_KEY[] = "ProjectExplorer.Project.PluginSettings";
} // namespace } // namespace
namespace ProjectExplorer { namespace ProjectExplorer {
class ContainerNode : public ProjectNode
{
public:
ContainerNode(Project *project)
: ProjectNode(Utils::FileName()),
m_project(project)
{}
QString displayName() const final
{
QString name = m_project->displayName();
const QFileInfo fi = m_project->projectFilePath().toFileInfo();
const QString dir = fi.isDir() ? fi.absoluteFilePath() : fi.absolutePath();
if (Core::IVersionControl *vc = Core::VcsManager::findVersionControlForDirectory(dir)) {
QString vcsTopic = vc->vcsTopic(dir);
if (!vcsTopic.isEmpty())
name += " [" + vcsTopic + ']';
}
return name;
}
QList<ProjectAction> supportedActions(Node *) const final
{
return {};
}
private:
Project *m_project;
};
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Project // Project
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
class ProjectPrivate class ProjectPrivate
{ {
public: public:
ProjectPrivate(Project *owner) : m_containerNode(owner) {}
~ProjectPrivate(); ~ProjectPrivate();
Core::Id m_id; Core::Id m_id;
Core::IDocument *m_document = nullptr; Core::IDocument *m_document = nullptr;
ProjectNode *m_rootProjectNode = nullptr; ProjectNode *m_rootProjectNode = nullptr;
ContainerNode m_containerNode;
QList<Target *> m_targets; QList<Target *> m_targets;
Target *m_activeTarget = nullptr; Target *m_activeTarget = nullptr;
EditorConfiguration m_editorConfiguration; EditorConfiguration m_editorConfiguration;
@@ -117,7 +154,7 @@ ProjectPrivate::~ProjectPrivate()
delete m_accessor; delete m_accessor;
} }
Project::Project() : d(new ProjectPrivate) Project::Project() : d(new ProjectPrivate(this))
{ {
d->m_macroExpander.setDisplayName(tr("Project")); d->m_macroExpander.setDisplayName(tr("Project"));
d->m_macroExpander.registerVariable("Project:Name", tr("Project Name"), d->m_macroExpander.registerVariable("Project:Name", tr("Project Name"),
@@ -426,9 +463,13 @@ void Project::setRootProjectNode(ProjectNode *root)
ProjectTree::applyTreeManager(root); ProjectTree::applyTreeManager(root);
ProjectNode *oldNode = d->m_rootProjectNode;
d->m_rootProjectNode = root; d->m_rootProjectNode = root;
emit projectTreeChanged(this, QPrivateSignal()); if (root)
// Do not delete oldNode! The ProjectTree owns that! root->setParentFolderNode(&d->m_containerNode);
ProjectTree::emitSubtreeChanged(root);
delete oldNode;
} }
Target *Project::restoreTarget(const QVariantMap &data) Target *Project::restoreTarget(const QVariantMap &data)
@@ -532,6 +573,11 @@ ProjectNode *Project::rootProjectNode() const
return d->m_rootProjectNode; return d->m_rootProjectNode;
} }
ProjectNode *Project::containerNode() const
{
return &d->m_containerNode;
}
Project::RestoreResult Project::fromMap(const QVariantMap &map, QString *errorMessage) Project::RestoreResult Project::fromMap(const QVariantMap &map, QString *errorMessage)
{ {
Q_UNUSED(errorMessage); Q_UNUSED(errorMessage);

View File

@@ -81,6 +81,7 @@ public:
static Utils::FileName projectDirectory(const Utils::FileName &top); static Utils::FileName projectDirectory(const Utils::FileName &top);
virtual ProjectNode *rootProjectNode() const; virtual ProjectNode *rootProjectNode() const;
ProjectNode *containerNode() const;
bool hasActiveBuildSettings() const; bool hasActiveBuildSettings() const;
@@ -142,7 +143,6 @@ public:
Utils::MacroExpander *macroExpander() const; Utils::MacroExpander *macroExpander() const;
signals: signals:
void projectTreeChanged(Project *project, QPrivateSignal);
void displayNameChanged(); void displayNameChanged();
void fileListChanged(); void fileListChanged();

View File

@@ -71,7 +71,7 @@ static bool sortWrapperNodes(const WrapperNode *w1, const WrapperNode *w2)
} }
FlatModel::FlatModel(QObject *parent) FlatModel::FlatModel(QObject *parent)
: TreeModel<WrapperNode, WrapperNode>(new WrapperNode(SessionManager::sessionNode()), parent) : TreeModel<WrapperNode, WrapperNode>(new WrapperNode(nullptr), parent)
{ {
ProjectTree *tree = ProjectTree::instance(); ProjectTree *tree = ProjectTree::instance();
connect(tree, &ProjectTree::subtreeChanged, this, &FlatModel::update); connect(tree, &ProjectTree::subtreeChanged, this, &FlatModel::update);
@@ -93,17 +93,7 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const
FolderNode *folderNode = node->asFolderNode(); FolderNode *folderNode = node->asFolderNode();
switch (role) { switch (role) {
case Qt::DisplayRole: { case Qt::DisplayRole: {
QString name = node->displayName(); result = node->displayName();
if (node->nodeType() == NodeType::Project
&& node->parentFolderNode()
&& node->parentFolderNode()->nodeType() == NodeType::Session) {
const QString vcsTopic = static_cast<ProjectNode *>(node)->vcsTopic();
if (!vcsTopic.isEmpty())
name += QLatin1String(" [") + vcsTopic + QLatin1Char(']');
}
result = name;
break; break;
} }
case Qt::EditRole: { case Qt::EditRole: {
@@ -124,7 +114,7 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const
case Qt::FontRole: { case Qt::FontRole: {
QFont font; QFont font;
if (Project *project = SessionManager::startupProject()) { if (Project *project = SessionManager::startupProject()) {
if (node == SessionManager::nodeForProject(project)) if (node == project->containerNode())
font.setBold(true); font.setBold(true);
} }
result = font; result = font;
@@ -187,23 +177,44 @@ void FlatModel::update()
void FlatModel::rebuildModel() void FlatModel::rebuildModel()
{ {
QList<Project *> projects = SessionManager::projects();
Utils::sort(projects, [](Project *p1, Project *p2) {
const int displayNameResult = caseFriendlyCompare(p1->displayName(), p2->displayName());
if (displayNameResult != 0)
return displayNameResult < 0;
return p1 < p2; // sort by pointer value
});
QSet<Node *> seen; QSet<Node *> seen;
rootItem()->removeChildren(); rootItem()->removeChildren();
for (Node *node : SessionManager::sessionNode()->nodes()) { for (Project *project : projects) {
if (ProjectNode *projectNode = node->asProjectNode()) { WrapperNode *container = new WrapperNode(project->containerNode());
if (!seen.contains(projectNode))
addProjectNode(rootItem(), projectNode, &seen); ProjectNode *projectNode = project->rootProjectNode();
if (projectNode) {
addFolderNode(container, projectNode, &seen);
} else {
FileNode *projectFileNode = new FileNode(project->projectFilePath(), FileType::Project, false);
seen.insert(projectFileNode);
container->appendChild(new WrapperNode(projectFileNode));
} }
container->sortChildren(&sortWrapperNodes);
rootItem()->appendChild(container);
} }
rootItem()->sortChildren(&sortWrapperNodes);
forAllItems([this](WrapperNode *node) { forAllItems([this](WrapperNode *node) {
const QString path = node->m_node->filePath().toString(); if (node->m_node) {
const QString displayName = node->m_node->displayName(); const QString path = node->m_node->filePath().toString();
ExpandData ed(path, displayName); const QString displayName = node->m_node->displayName();
if (m_toExpand.contains(ed)) ExpandData ed(path, displayName);
if (m_toExpand.contains(ed))
emit requestExpansion(node->index());
} else {
emit requestExpansion(node->index()); emit requestExpansion(node->index());
}
}); });
} }
@@ -227,7 +238,7 @@ ExpandData FlatModel::expandDataForNode(const Node *node) const
void FlatModel::handleProjectAdded(Project *project) void FlatModel::handleProjectAdded(Project *project)
{ {
Node *node = SessionManager::nodeForProject(project); Node *node = project->rootProjectNode();
m_toExpand.insert(expandDataForNode(node)); m_toExpand.insert(expandDataForNode(node));
if (WrapperNode *wrapper = wrapperForNode(node)) { if (WrapperNode *wrapper = wrapperForNode(node)) {
wrapper->forFirstLevelChildren([this](WrapperNode *child) { wrapper->forFirstLevelChildren([this](WrapperNode *child) {
@@ -251,21 +262,6 @@ void FlatModel::saveExpandData()
SessionManager::setValue(QLatin1String("ProjectTree.ExpandData"), data); SessionManager::setValue(QLatin1String("ProjectTree.ExpandData"), data);
} }
void FlatModel::addProjectNode(WrapperNode *parent, ProjectNode *projectNode, QSet<Node *> *seen)
{
seen->insert(projectNode);
auto node = new WrapperNode(projectNode);
parent->appendChild(node);
addFolderNode(node, projectNode, seen);
for (Node *subNode : projectNode->nodes()) {
if (ProjectNode *subProjectNode = subNode->asProjectNode()) {
if (!seen->contains(subProjectNode))
addProjectNode(node, subProjectNode, seen);
}
}
node->sortChildren(&sortWrapperNodes);
}
void FlatModel::addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen) void FlatModel::addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen)
{ {
const QList<FolderNode *> subFolderNodes = folderNode->folderNodes(); const QList<FolderNode *> subFolderNodes = folderNode->folderNodes();
@@ -374,16 +370,6 @@ const QLoggingCategory &FlatModel::logger()
return logger; return logger;
} }
bool isSorted(const QList<Node *> &nodes)
{
int size = nodes.size();
for (int i = 0; i < size -1; ++i) {
if (!sortNodes(nodes.at(i), nodes.at(i+1)))
return false;
}
return true;
}
namespace Internal { namespace Internal {
int caseFriendlyCompare(const QString &a, const QString &b) int caseFriendlyCompare(const QString &a, const QString &b)

View File

@@ -94,7 +94,6 @@ private:
void update(); void update();
void rebuildModel(); void rebuildModel();
void addProjectNode(WrapperNode *parent, ProjectNode *projectNode, QSet<Node *> *seen);
void addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen); void addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen);
ExpandData expandDataForNode(const Node *node) const; ExpandData expandDataForNode(const Node *node) const;

View File

@@ -214,9 +214,12 @@ bool Node::isEnabled() const
QList<ProjectAction> Node::supportedActions(Node *node) const QList<ProjectAction> Node::supportedActions(Node *node) const
{ {
QList<ProjectAction> list = parentFolderNode()->supportedActions(node); if (FolderNode *folder = parentFolderNode()) {
list.append(InheritedFromParent); QList<ProjectAction> list = folder->supportedActions(node);
return list; list.append(InheritedFromParent);
return list;
}
return {};
} }
void Node::setEnabled(bool enabled) void Node::setEnabled(bool enabled)
@@ -702,18 +705,6 @@ ProjectNode::ProjectNode(const Utils::FileName &projectFilePath) :
setDisplayName(projectFilePath.fileName()); setDisplayName(projectFilePath.fileName());
} }
QString ProjectNode::vcsTopic() const
{
const QFileInfo fi = filePath().toFileInfo();
const QString dir = fi.isDir() ? fi.absoluteFilePath() : fi.absolutePath();
if (Core::IVersionControl *const vc =
Core::VcsManager::findVersionControlForDirectory(dir))
return vc->vcsTopic(dir);
return QString();
}
bool ProjectNode::canAddSubProject(const QString &proFilePath) const bool ProjectNode::canAddSubProject(const QString &proFilePath) const
{ {
Q_UNUSED(proFilePath) Q_UNUSED(proFilePath)
@@ -797,28 +788,4 @@ bool FolderNode::isEmpty() const
return m_nodes.isEmpty(); return m_nodes.isEmpty();
} }
/*!
\class ProjectExplorer::SessionNode
*/
SessionNode::SessionNode() :
FolderNode(Utils::FileName::fromString("session"), NodeType::Session)
{ }
QList<ProjectAction> SessionNode::supportedActions(Node *node) const
{
Q_UNUSED(node)
return QList<ProjectAction>();
}
bool SessionNode::showInSimpleTree() const
{
return true;
}
QString SessionNode::addFileFilter() const
{
return QString::fromLatin1("*.c; *.cc; *.cpp; *.cp; *.cxx; *.c++; *.h; *.hh; *.hpp; *.hxx;");
}
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -40,14 +40,12 @@ namespace Utils { class MimeType; }
namespace ProjectExplorer { namespace ProjectExplorer {
class RunConfiguration; class RunConfiguration;
class SessionManager;
enum class NodeType : quint16 { enum class NodeType : quint16 {
File = 1, File = 1,
Folder, Folder,
VirtualFolder, VirtualFolder,
Project, Project
Session
}; };
// File types common for qt projects // File types common for qt projects
@@ -275,8 +273,6 @@ private:
class PROJECTEXPLORER_EXPORT ProjectNode : public FolderNode class PROJECTEXPLORER_EXPORT ProjectNode : public FolderNode
{ {
public: public:
QString vcsTopic() const;
virtual bool canAddSubProject(const QString &proFilePath) const; virtual bool canAddSubProject(const QString &proFilePath) const;
virtual bool addSubProject(const QString &proFile); virtual bool addSubProject(const QString &proFile);
virtual bool removeSubProject(const QString &proFilePath); virtual bool removeSubProject(const QString &proFilePath);
@@ -298,24 +294,7 @@ public:
const ProjectNode *asProjectNode() const final { return this; } const ProjectNode *asProjectNode() const final { return this; }
protected: protected:
// this is just the in-memory representation, a subclass
// will add the persistent stuff
explicit ProjectNode(const Utils::FileName &projectFilePath); explicit ProjectNode(const Utils::FileName &projectFilePath);
friend class SessionManager;
};
// Documentation inside.
class PROJECTEXPLORER_EXPORT SessionNode : public FolderNode
{
public:
SessionNode();
private:
QList<ProjectAction> supportedActions(Node *node) const final;
QString addFileFilter() const final;
bool showInSimpleTree() const final;
}; };
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -261,9 +261,6 @@ void ProjectTree::updateContext()
void ProjectTree::emitSubtreeChanged(FolderNode *node) void ProjectTree::emitSubtreeChanged(FolderNode *node)
{ {
if (!SessionManager::sessionNode()->isAncesterOf(node))
return;
emit s_instance->subtreeChanged(node); emit s_instance->subtreeChanged(node);
} }
@@ -318,16 +315,15 @@ bool ProjectTree::hasFocus(ProjectTreeWidget *widget)
void ProjectTree::showContextMenu(ProjectTreeWidget *focus, const QPoint &globalPos, Node *node) void ProjectTree::showContextMenu(ProjectTreeWidget *focus, const QPoint &globalPos, Node *node)
{ {
QMenu *contextMenu = nullptr; QMenu *contextMenu = nullptr;
Project *project = SessionManager::projectForNode(node);
emit s_instance->aboutToShowContextMenu(project, node);
if (!node) if (!node) {
node = SessionManager::sessionNode(); contextMenu = Core::ActionManager::actionContainer(Constants::M_SESSIONCONTEXT)->menu();
if (node->nodeType() != NodeType::Session) { } else {
Project *project = SessionManager::projectForNode(node);
emit s_instance->aboutToShowContextMenu(project, node);
switch (node->nodeType()) { switch (node->nodeType()) {
case NodeType::Project: case NodeType::Project:
if (node->parentFolderNode() == SessionManager::sessionNode()) if (node->parentFolderNode())
contextMenu = Core::ActionManager::actionContainer(Constants::M_PROJECTCONTEXT)->menu(); contextMenu = Core::ActionManager::actionContainer(Constants::M_PROJECTCONTEXT)->menu();
else else
contextMenu = Core::ActionManager::actionContainer(Constants::M_SUBPROJECTCONTEXT)->menu(); contextMenu = Core::ActionManager::actionContainer(Constants::M_SUBPROJECTCONTEXT)->menu();
@@ -342,10 +338,6 @@ void ProjectTree::showContextMenu(ProjectTreeWidget *focus, const QPoint &global
default: default:
qWarning("ProjectExplorerPlugin::showContextMenu - Missing handler for node type"); qWarning("ProjectExplorerPlugin::showContextMenu - Missing handler for node type");
} }
} else { // session item
emit s_instance->aboutToShowContextMenu(nullptr, node);
contextMenu = Core::ActionManager::actionContainer(Constants::M_SESSIONCONTEXT)->menu();
} }
if (contextMenu && contextMenu->actions().count() > 0) { if (contextMenu && contextMenu->actions().count() > 0) {

View File

@@ -70,6 +70,9 @@ public:
void collapseAll(); void collapseAll();
// for nodes to emit signals, do not call unless you are a node
static void emitSubtreeChanged(FolderNode *node);
signals: signals:
void currentProjectChanged(ProjectExplorer::Project *project); void currentProjectChanged(ProjectExplorer::Project *project);
void currentNodeChanged(); void currentNodeChanged();
@@ -80,9 +83,6 @@ signals:
void aboutToShowContextMenu(ProjectExplorer::Project *project, void aboutToShowContextMenu(ProjectExplorer::Project *project,
ProjectExplorer::Node *node); ProjectExplorer::Node *node);
public: // for nodes to emit signals, do not call unless you are a node
static void emitSubtreeChanged(FolderNode *node);
private: private:
void sessionChanged(); void sessionChanged();
void focusChanged(); void focusChanged();

View File

@@ -275,23 +275,27 @@ Node *ProjectTreeWidget::nodeForFile(const Utils::FileName &fileName)
Node *bestNode = nullptr; Node *bestNode = nullptr;
int bestNodeExpandCount = INT_MAX; int bestNodeExpandCount = INT_MAX;
SessionManager::sessionNode()->forEachGenericNode([&](Node *node) { for (Project *project : SessionManager::projects()) {
if (node->filePath() == fileName) { if (ProjectNode *projectNode = project->rootProjectNode()) {
if (!bestNode) { projectNode->forEachGenericNode([&](Node *node) {
bestNode = node; if (node->filePath() == fileName) {
bestNodeExpandCount = ProjectTreeWidget::expandedCount(node); if (!bestNode) {
} else if (node->nodeType() < bestNode->nodeType()) { bestNode = node;
bestNode = node; bestNodeExpandCount = ProjectTreeWidget::expandedCount(node);
bestNodeExpandCount = ProjectTreeWidget::expandedCount(node); } else if (node->nodeType() < bestNode->nodeType()) {
} else if (node->nodeType() == bestNode->nodeType()) { bestNode = node;
int nodeExpandCount = ProjectTreeWidget::expandedCount(node); bestNodeExpandCount = ProjectTreeWidget::expandedCount(node);
if (nodeExpandCount < bestNodeExpandCount) { } else if (node->nodeType() == bestNode->nodeType()) {
bestNode = node; int nodeExpandCount = ProjectTreeWidget::expandedCount(node);
bestNodeExpandCount = ProjectTreeWidget::expandedCount(node); if (nodeExpandCount < bestNodeExpandCount) {
bestNode = node;
bestNodeExpandCount = ProjectTreeWidget::expandedCount(node);
}
}
} }
} });
} }
}); }
return bestNode; return bestNode;
} }

View File

@@ -55,6 +55,8 @@
using namespace Core; using namespace Core;
using namespace Utils; using namespace Utils;
const int LINK_HEIGHT = 35;
namespace ProjectExplorer { namespace ProjectExplorer {
namespace Internal { namespace Internal {
@@ -154,13 +156,18 @@ class BaseDelegate : public QAbstractItemDelegate
{ {
protected: protected:
virtual QString entryType() = 0; virtual QString entryType() = 0;
virtual QRect toolTipArea(const QRect &itemRect, const QModelIndex &) const
{
return itemRect;
}
bool helpEvent(QHelpEvent *ev, QAbstractItemView *view, bool helpEvent(QHelpEvent *ev, QAbstractItemView *view,
const QStyleOptionViewItem &option, const QModelIndex &idx) final const QStyleOptionViewItem &option, const QModelIndex &idx) final
{ {
const int y = ev->pos().y(); if (!toolTipArea(option.rect, idx).contains(ev->pos())) {
if (y > option.rect.bottom() - 20) QToolTip::hideText();
return false; return false;
}
QString shortcut; QString shortcut;
if (idx.row() < m_shortcuts.size()) if (idx.row() < m_shortcuts.size())
@@ -188,6 +195,13 @@ class SessionDelegate : public BaseDelegate
{ {
protected: protected:
QString entryType() override { return tr("session", "Appears in \"Open session <name>\""); } QString entryType() override { return tr("session", "Appears in \"Open session <name>\""); }
QRect toolTipArea(const QRect &itemRect, const QModelIndex &idx) const override
{
// in expanded state bottom contains 'Clone', 'Rename', etc links, where the tool tip
// would be confusing
const bool expanded = m_expandedSessions.contains(idx.data(Qt::DisplayRole).toString());
return expanded ? itemRect.adjusted(0, 0, 0, -LINK_HEIGHT) : itemRect;
}
public: public:
SessionDelegate() { SessionDelegate() {
@@ -312,7 +326,7 @@ public:
QString sessionName = idx.data(Qt::DisplayRole).toString(); QString sessionName = idx.data(Qt::DisplayRole).toString();
if (m_expandedSessions.contains(sessionName)) { if (m_expandedSessions.contains(sessionName)) {
QStringList projects = SessionManager::projectsForSessionName(sessionName); QStringList projects = SessionManager::projectsForSessionName(sessionName);
h += projects.size() * 40 + 35; h += projects.size() * 40 + LINK_HEIGHT;
} }
return QSize(380, h); return QSize(380, h);
} }
@@ -408,7 +422,7 @@ public:
painter->drawPixmap(x + 11, y + 3, pixmap("project", Theme::Welcome_ForegroundSecondaryColor)); painter->drawPixmap(x + 11, y + 3, pixmap("project", Theme::Welcome_ForegroundSecondaryColor));
QString projectName = idx.data(Qt::DisplayRole).toString(); QString projectName = idx.data(Qt::DisplayRole).toString();
QString projectPath = idx.data(Qt::UserRole + 1).toString(); QString projectPath = idx.data(ProjectModel::FilePathRole).toString();
painter->setPen(themeColor(Theme::Welcome_ForegroundSecondaryColor)); painter->setPen(themeColor(Theme::Welcome_ForegroundSecondaryColor));
painter->setFont(sizedFont(10, option.widget)); painter->setFont(sizedFont(10, option.widget));
@@ -429,7 +443,7 @@ public:
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &idx) const final QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &idx) const final
{ {
QString projectName = idx.data(Qt::DisplayRole).toString(); QString projectName = idx.data(Qt::DisplayRole).toString();
QString projectPath = idx.data(Qt::UserRole + 1).toString(); QString projectPath = idx.data(ProjectModel::FilePathRole).toString();
QFontMetrics fm(sizedFont(13, option.widget)); QFontMetrics fm(sizedFont(13, option.widget));
int width = std::max(fm.width(projectName), fm.width(projectPath)) + 36; int width = std::max(fm.width(projectName), fm.width(projectPath)) + 36;
return QSize(width, 48); return QSize(width, 48);
@@ -439,7 +453,7 @@ public:
const QStyleOptionViewItem &, const QModelIndex &idx) final const QStyleOptionViewItem &, const QModelIndex &idx) final
{ {
if (ev->type() == QEvent::MouseButtonRelease) { if (ev->type() == QEvent::MouseButtonRelease) {
QString projectFile = idx.data(Qt::UserRole + 1).toString(); QString projectFile = idx.data(ProjectModel::FilePathRole).toString();
ProjectExplorerPlugin::openProjectWelcomePage(projectFile); ProjectExplorerPlugin::openProjectWelcomePage(projectFile);
return true; return true;
} }

View File

@@ -26,6 +26,7 @@
#include "projectwizardpage.h" #include "projectwizardpage.h"
#include "ui_projectwizardpage.h" #include "ui_projectwizardpage.h"
#include "project.h"
#include "projectexplorer.h" #include "projectexplorer.h"
#include "session.h" #include "session.h"
@@ -300,18 +301,14 @@ ProjectWizardPage::~ProjectWizardPage()
{ {
disconnect(m_ui->projectComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), disconnect(m_ui->projectComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &ProjectWizardPage::projectChanged); this, &ProjectWizardPage::projectChanged);
delete m_model;
delete m_ui; delete m_ui;
} }
void ProjectWizardPage::setModel(Utils::TreeModel<> *model) void ProjectWizardPage::setModel(Utils::TreeModel<> *model)
{ {
delete m_model;
m_model = model;
// TODO see OverViewCombo and OverView for click event filter // TODO see OverViewCombo and OverView for click event filter
m_ui->projectComboBox->setModel(model); m_ui->projectComboBox->setModel(model);
bool enabled = m_model->rowCount(QModelIndex()) > 1; bool enabled = m_model.rowCount(QModelIndex()) > 1;
m_ui->projectComboBox->setEnabled(enabled); m_ui->projectComboBox->setEnabled(enabled);
expandTree(QModelIndex()); expandTree(QModelIndex());
@@ -324,9 +321,9 @@ bool ProjectWizardPage::expandTree(const QModelIndex &root)
expand = true; expand = true;
// Check children // Check children
int count = m_model->rowCount(root); int count = m_model.rowCount(root);
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
if (expandTree(m_model->index(i, 0, root))) if (expandTree(m_model.index(i, 0, root)))
expand = true; expand = true;
} }
@@ -346,7 +343,7 @@ bool ProjectWizardPage::expandTree(const QModelIndex &root)
void ProjectWizardPage::setBestNode(AddNewTree *tree) void ProjectWizardPage::setBestNode(AddNewTree *tree)
{ {
QModelIndex index = tree ? m_model->indexForItem(tree) : QModelIndex(); QModelIndex index = tree ? m_model.indexForItem(tree) : QModelIndex();
m_ui->projectComboBox->setCurrentIndex(index); m_ui->projectComboBox->setCurrentIndex(index);
while (index.isValid()) { while (index.isValid()) {
@@ -454,28 +451,22 @@ void ProjectWizardPage::initializeProjectTree(Node *context, const QStringList &
{ {
BestNodeSelector selector(m_commonDirectory, paths); BestNodeSelector selector(m_commonDirectory, paths);
AddNewTree *tree; TreeItem *root = m_model.rootItem();
SessionNode *root = SessionManager::sessionNode(); root->removeChildren();
QList<AddNewTree *> children; for (Project *project : SessionManager::projects()) {
if (ProjectNode *pn = project->rootProjectNode()) {
for (Node *node : root->nodes()) {
if (ProjectNode *pn = node->asProjectNode()) {
if (kind == IWizardFactory::ProjectWizard) { if (kind == IWizardFactory::ProjectWizard) {
if (AddNewTree *child = buildAddProjectTree(pn, paths.first(), context, &selector)) if (AddNewTree *child = buildAddProjectTree(pn, paths.first(), context, &selector))
children.append(child); root->appendChild(child);
} else { } else {
if (AddNewTree *child = buildAddFilesTree(pn, paths, context, &selector)) if (AddNewTree *child = buildAddFilesTree(pn, paths, context, &selector))
children.append(child); root->appendChild(child);
} }
} }
} }
root->prependChild(createNoneNode(&selector));
children.prepend(createNoneNode(&selector));
tree = new AddNewTree(root, children, root->displayName());
setAdditionalInfo(selector.deployingProjects()); setAdditionalInfo(selector.deployingProjects());
setModel(new TreeModel<>(tree));
setBestNode(selector.bestChoice()); setBestNode(selector.bestChoice());
setAddingSubProject(action == AddSubProject); setAddingSubProject(action == AddSubProject);
} }

View File

@@ -95,7 +95,7 @@ private:
Ui::WizardPage *m_ui; Ui::WizardPage *m_ui;
QStringList m_projectToolTips; QStringList m_projectToolTips;
Utils::TreeModel<> *m_model = nullptr; Utils::TreeModel<> m_model;
QList<Core::IVersionControl*> m_activeVersionControls; QList<Core::IVersionControl*> m_activeVersionControls;
QString m_commonDirectory; QString m_commonDirectory;

View File

@@ -92,13 +92,7 @@ public:
static QString sessionTitle(const QString &filePath); static QString sessionTitle(const QString &filePath);
bool hasProjects() const { return !m_projects.isEmpty(); } bool hasProjects() const { return !m_projects.isEmpty(); }
bool hasProject(Project *p) const
{
return Utils::contains(m_projects,
[p](const QPair<Project *, ProjectNode *> &pair) { return pair.first == p; });
}
SessionNode m_sessionNode;
QString m_sessionName = QLatin1String("default"); QString m_sessionName = QLatin1String("default");
bool m_virginSession = true; bool m_virginSession = true;
bool m_loadingSession = false; bool m_loadingSession = false;
@@ -110,7 +104,7 @@ public:
mutable QHash<Project *, QStringList> m_projectFileCache; mutable QHash<Project *, QStringList> m_projectFileCache;
Project *m_startupProject = nullptr; Project *m_startupProject = nullptr;
QList<QPair<Project *,ProjectNode*>> m_projects; QList<Project *> m_projects;
QStringList m_failedProjects; QStringList m_failedProjects;
QMap<QString, QStringList> m_depMap; QMap<QString, QStringList> m_depMap;
QMap<QString, QVariant> m_values; QMap<QString, QVariant> m_values;
@@ -188,36 +182,6 @@ void SessionManager::clearProjectFileCache()
d->m_projectFileCache.clear(); d->m_projectFileCache.clear();
} }
void SessionManager::updateProjectTree(Project *pro)
{
if (!pro)
return;
QPair<Project *, ProjectNode *> *currentPair = nullptr;
for (QPair<Project *, ProjectNode *> &pair : d->m_projects) {
if (pair.first == pro) {
currentPair = &pair;
break;
}
}
if (!currentPair)
return; // Project was already de-registered and is shutting down
ProjectNode *const oldNode = currentPair->second;
ProjectNode *newNode = pro->rootProjectNode();
if (!newNode) {
// Set up generic project structure if the project does not provide any!
newNode = new ProjectNode(pro->projectDirectory());
newNode->setDisplayName(pro->displayName());
newNode->addNode(new FileNode(pro->projectFilePath(), FileType::Project, false));
}
d->m_sessionNode.replaceSubtree(oldNode, newNode);
currentPair->second = newNode;
}
bool SessionManagerPrivate::recursiveDependencyCheck(const QString &newDep, const QString &checkDep) const bool SessionManagerPrivate::recursiveDependencyCheck(const QString &newDep, const QString &checkDep) const
{ {
if (newDep == checkDep) if (newDep == checkDep)
@@ -393,8 +357,8 @@ void SessionManager::setActiveDeployConfiguration(Target *target, DeployConfigur
void SessionManager::setStartupProject(Project *startupProject) void SessionManager::setStartupProject(Project *startupProject)
{ {
QTC_ASSERT((!startupProject) QTC_ASSERT(!startupProject
|| (startupProject && hasProject(startupProject)), return); || (startupProject && d->m_projects.contains(startupProject)), return);
if (d->m_startupProject == startupProject) if (d->m_startupProject == startupProject)
return; return;
@@ -413,13 +377,11 @@ void SessionManager::addProject(Project *pro)
QTC_ASSERT(pro, return); QTC_ASSERT(pro, return);
d->m_virginSession = false; d->m_virginSession = false;
QTC_ASSERT(!hasProject(pro), return); QTC_ASSERT(!d->m_projects.contains(pro), return);
d->m_projects.append(qMakePair(pro, nullptr)); d->m_projects.append(pro);
m_instance->updateProjectTree(pro);
connect(pro, &Project::fileListChanged, m_instance, &SessionManager::clearProjectFileCache); connect(pro, &Project::fileListChanged, m_instance, &SessionManager::clearProjectFileCache);
connect(pro, &Project::projectTreeChanged, m_instance, &SessionManager::updateProjectTree);
emit m_instance->projectAdded(pro); emit m_instance->projectAdded(pro);
configureEditors(pro); configureEditors(pro);
@@ -522,8 +484,7 @@ void SessionManager::closeAllProjects()
const QList<Project *> SessionManager::projects() const QList<Project *> SessionManager::projects()
{ {
return Utils::transform(d->m_projects, return d->m_projects;
[](const QPair<Project *, ProjectNode *> &pair) { return pair.first; });
} }
bool SessionManager::hasProjects() bool SessionManager::hasProjects()
@@ -533,7 +494,7 @@ bool SessionManager::hasProjects()
bool SessionManager::hasProject(Project *p) bool SessionManager::hasProject(Project *p)
{ {
return d->hasProject(p); return d->m_projects.contains(p);
} }
QStringList SessionManagerPrivate::dependencies(const QString &proName) const QStringList SessionManagerPrivate::dependencies(const QString &proName) const
@@ -604,8 +565,8 @@ QStringList SessionManagerPrivate::dependenciesOrder() const
QStringList ordered; QStringList ordered;
// copy the map to a temporary list // copy the map to a temporary list
for (const QPair<Project *, ProjectNode *> &pro : m_projects) { for (const Project *pro : m_projects) {
const QString proName = pro.first->projectFilePath().toString(); const QString proName = pro->projectFilePath().toString();
unordered << QPair<QString, QStringList>(proName, m_depMap.value(proName)); unordered << QPair<QString, QStringList>(proName, m_depMap.value(proName));
} }
@@ -658,13 +619,17 @@ QList<Project *> SessionManager::projectOrder(const Project *project)
Node *SessionManager::nodeForFile(const Utils::FileName &fileName) Node *SessionManager::nodeForFile(const Utils::FileName &fileName)
{ {
Node *node = nullptr; Node *node = nullptr;
sessionNode()->forEachGenericNode([&](Node *n) { for (Project *project : d->m_projects) {
if (n->filePath() == fileName) { if (ProjectNode *projectNode = project->rootProjectNode()) {
// prefer file nodes projectNode->forEachGenericNode([&](Node *n) {
if (!node || (node->nodeType() != NodeType::File && n->nodeType() == NodeType::File)) if (n->filePath() == fileName) {
node = n; // prefer file nodes
if (!node || (node->nodeType() != NodeType::File && n->nodeType() == NodeType::File))
node = n;
}
});
} }
}); }
return node; return node;
} }
@@ -673,25 +638,16 @@ Project *SessionManager::projectForNode(Node *node)
if (!node) if (!node)
return nullptr; return nullptr;
FolderNode *rootProjectNode = node->asFolderNode(); FolderNode *folder = node->asFolderNode();
if (!rootProjectNode) if (!folder)
rootProjectNode = node->parentFolderNode(); folder = node->parentFolderNode();
while (rootProjectNode && rootProjectNode->parentFolderNode() != &d->m_sessionNode) while (folder && folder->parentFolderNode())
rootProjectNode = rootProjectNode->parentFolderNode(); folder = folder->parentFolderNode();
for (const QPair<Project *, ProjectNode *> &pair : d->m_projects) { for (Project *pro : d->m_projects) {
if (pair.second == rootProjectNode) if (pro->containerNode() == folder)
return pair.first; return pro;
}
return nullptr;
}
Node *SessionManager::nodeForProject(Project *project)
{
for (const QPair<Project *,ProjectNode*> &pair : d->m_projects) {
if (pair.first == project)
return pair.second;
} }
return nullptr; return nullptr;
} }
@@ -771,17 +727,9 @@ void SessionManager::removeProjects(QList<Project *> remove)
// Delete projects // Delete projects
foreach (Project *pro, remove) { foreach (Project *pro, remove) {
pro->saveSettings(); pro->saveSettings();
pro->setRootProjectNode(nullptr); // Deregister project with sessionnode!
// Remove the project node: // Remove the project node:
Node *projectNode = nodeForProject(pro); d->m_projects.removeOne(pro);
d->m_sessionNode.removeNode(projectNode);
d->m_projects
= Utils::filtered(d->m_projects, [pro](const QPair<Project *, ProjectNode *> &pair)
{
return pair.first != pro;
});
if (pro == d->m_startupProject) if (pro == d->m_startupProject)
setStartupProject(nullptr); setStartupProject(nullptr);
@@ -965,9 +913,9 @@ void SessionManagerPrivate::restoreStartupProject(const PersistentSettingsReader
{ {
const QString startupProject = reader.restoreValue(QLatin1String("StartupProject")).toString(); const QString startupProject = reader.restoreValue(QLatin1String("StartupProject")).toString();
if (!startupProject.isEmpty()) { if (!startupProject.isEmpty()) {
for (const QPair<Project *, ProjectNode *> &pro : m_projects) { for (Project *pro : m_projects) {
if (pro.first->projectFilePath().toString() == startupProject) { if (pro->projectFilePath().toString() == startupProject) {
m_instance->setStartupProject(pro.first); m_instance->setStartupProject(pro);
break; break;
} }
} }
@@ -976,7 +924,7 @@ void SessionManagerPrivate::restoreStartupProject(const PersistentSettingsReader
if (!startupProject.isEmpty()) if (!startupProject.isEmpty())
qWarning() << "Could not find startup project" << startupProject; qWarning() << "Could not find startup project" << startupProject;
if (hasProjects()) if (hasProjects())
m_instance->setStartupProject(m_projects.first().first); m_instance->setStartupProject(m_projects.first());
} }
} }
@@ -1140,11 +1088,6 @@ QString SessionManager::lastSession()
return ICore::settings()->value(QLatin1String("ProjectExplorer/StartupSession")).toString(); return ICore::settings()->value(QLatin1String("ProjectExplorer/StartupSession")).toString();
} }
SessionNode *SessionManager::sessionNode()
{
return &d->m_sessionNode;
}
void SessionManager::reportProjectLoadingProgress() void SessionManager::reportProjectLoadingProgress()
{ {
d->sessionLoadingProgress(); d->sessionLoadingProgress();

View File

@@ -44,7 +44,6 @@ class Target;
class BuildConfiguration; class BuildConfiguration;
class DeployConfiguration; class DeployConfiguration;
class Node; class Node;
class SessionNode;
enum class SetActive { Cascade, NoCascade }; enum class SetActive { Cascade, NoCascade };
@@ -113,10 +112,7 @@ public:
// NBS rewrite projectOrder (dependency management) // NBS rewrite projectOrder (dependency management)
static QList<Project *> projectOrder(const Project *project = 0); static QList<Project *> projectOrder(const Project *project = 0);
static SessionNode *sessionNode();
static Project *projectForNode(Node *node); static Project *projectForNode(Node *node);
static Node *nodeForProject(Project *project);
static Node *nodeForFile(const Utils::FileName &fileName); static Node *nodeForFile(const Utils::FileName &fileName);
static Project *projectForFile(const Utils::FileName &fileName); static Project *projectForFile(const Utils::FileName &fileName);
@@ -126,8 +122,7 @@ public:
static bool loadingSession(); static bool loadingSession();
signals: signals:
void projectAdded(ProjectExplorer::Project *project); void projectAdded(ProjectExplorer::Project *project); void aboutToRemoveProject(ProjectExplorer::Project *project);
void aboutToRemoveProject(ProjectExplorer::Project *project);
void projectDisplayNameChanged(ProjectExplorer::Project *project); void projectDisplayNameChanged(ProjectExplorer::Project *project);
void projectRemoved(ProjectExplorer::Project *project); void projectRemoved(ProjectExplorer::Project *project);
@@ -145,7 +140,6 @@ signals: // for tests only
private: private:
static void saveActiveMode(Core::Id mode); static void saveActiveMode(Core::Id mode);
void clearProjectFileCache(); void clearProjectFileCache();
void updateProjectTree(Project *pro);
static void configureEditor(Core::IEditor *editor, const QString &fileName); static void configureEditor(Core::IEditor *editor, const QString &fileName);
static void markSessionFileDirty(bool makeDefaultVirginDirty = true); static void markSessionFileDirty(bool makeDefaultVirginDirty = true);
static void configureEditors(Project *project); static void configureEditors(Project *project);

View File

@@ -42,6 +42,7 @@
#include <QtDebug> #include <QtDebug>
#include <QDir> #include <QDir>
#include <QIcon>
#include <QStyle> #include <QStyle>
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@@ -64,10 +65,6 @@ static QIcon generateIcon(const QString &overlay)
namespace QbsProjectManager { namespace QbsProjectManager {
namespace Internal { namespace Internal {
QIcon QbsGroupNode::m_groupIcon;
QIcon QbsProjectNode::m_projectIcon;
QIcon QbsProductNode::m_productIcon;
static QbsProjectNode *parentQbsProjectNode(ProjectExplorer::Node *node) static QbsProjectNode *parentQbsProjectNode(ProjectExplorer::Node *node)
{ {
for (ProjectExplorer::FolderNode *pn = node->managingProject(); pn; pn = pn->parentProjectNode()) { for (ProjectExplorer::FolderNode *pn = node->managingProject(); pn; pn = pn->parentProjectNode()) {
@@ -263,9 +260,8 @@ QString QbsFileNode::displayName() const
QbsFolderNode::QbsFolderNode(const Utils::FileName &folderPath, ProjectExplorer::NodeType nodeType, QbsFolderNode::QbsFolderNode(const Utils::FileName &folderPath, ProjectExplorer::NodeType nodeType,
const QString &displayName, bool isGeneratedFilesFolder) const QString &displayName)
: ProjectExplorer::FolderNode(folderPath, nodeType, displayName), : ProjectExplorer::FolderNode(folderPath, nodeType, displayName)
m_isGeneratedFilesFolder(isGeneratedFilesFolder)
{ {
} }
@@ -300,10 +296,8 @@ QList<ProjectExplorer::ProjectAction> QbsBaseProjectNode::supportedActions(Proje
QbsGroupNode::QbsGroupNode(const qbs::GroupData &grp, const QString &productPath) : QbsGroupNode::QbsGroupNode(const qbs::GroupData &grp, const QString &productPath) :
QbsBaseProjectNode(Utils::FileName()) QbsBaseProjectNode(Utils::FileName())
{ {
if (m_groupIcon.isNull()) static QIcon groupIcon = QIcon(QString(Constants::QBS_GROUP_ICON));
m_groupIcon = QIcon(QString::fromLatin1(Constants::QBS_GROUP_ICON)); setIcon(groupIcon);
setIcon(m_groupIcon);
m_productPath = productPath; m_productPath = productPath;
m_qbsGroupData = grp; m_qbsGroupData = grp;
@@ -379,10 +373,8 @@ QbsProductNode::QbsProductNode(const qbs::ProductData &prd) :
QbsBaseProjectNode(Utils::FileName::fromString(prd.location().filePath())), QbsBaseProjectNode(Utils::FileName::fromString(prd.location().filePath())),
m_qbsProductData(prd) m_qbsProductData(prd)
{ {
if (m_productIcon.isNull()) static QIcon productIcon = generateIcon(QString(Constants::QBS_PRODUCT_OVERLAY_ICON));
m_productIcon = generateIcon(QString::fromLatin1(Constants::QBS_PRODUCT_OVERLAY_ICON)); setIcon(productIcon);
setIcon(m_productIcon);
} }
bool QbsProductNode::showInSimpleTree() const bool QbsProductNode::showInSimpleTree() const
@@ -464,16 +456,6 @@ QList<ProjectExplorer::RunConfiguration *> QbsProductNode::runConfigurations() c
return result; return result;
} }
QbsGroupNode *QbsProductNode::findGroupNode(const QString &name)
{
for (ProjectExplorer::Node *n : nodes()) {
if (QbsGroupNode *qn = dynamic_cast<QbsGroupNode *>(n))
if (qn->qbsGroupData().name() == name)
return qn;
}
return 0;
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// QbsProjectNode: // QbsProjectNode:
// -------------------------------------------------------------------- // --------------------------------------------------------------------
@@ -481,15 +463,8 @@ QbsGroupNode *QbsProductNode::findGroupNode(const QString &name)
QbsProjectNode::QbsProjectNode(const Utils::FileName &projectDirectory) : QbsProjectNode::QbsProjectNode(const Utils::FileName &projectDirectory) :
QbsBaseProjectNode(projectDirectory) QbsBaseProjectNode(projectDirectory)
{ {
if (m_projectIcon.isNull()) static QIcon projectIcon = generateIcon(QString(ProjectExplorer::Constants::FILEOVERLAY_QT));
m_projectIcon = generateIcon(QString::fromLatin1(ProjectExplorer::Constants::FILEOVERLAY_QT)); setIcon(projectIcon);
setIcon(m_projectIcon);
}
QbsProjectNode::~QbsProjectNode()
{
// do not delete m_project
} }
QbsProject *QbsProjectNode::project() const QbsProject *QbsProjectNode::project() const

View File

@@ -29,15 +29,11 @@
#include <qbs.h> #include <qbs.h>
#include <QIcon>
namespace QbsProjectManager { namespace QbsProjectManager {
namespace Internal { namespace Internal {
class FileTreeNode;
class QbsNodeTreeBuilder; class QbsNodeTreeBuilder;
class QbsProject; class QbsProject;
class QbsProjectFile;
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// QbsFileNode: // QbsFileNode:
@@ -56,14 +52,10 @@ class QbsFolderNode : public ProjectExplorer::FolderNode
{ {
public: public:
QbsFolderNode(const Utils::FileName &folderPath, ProjectExplorer::NodeType nodeType, QbsFolderNode(const Utils::FileName &folderPath, ProjectExplorer::NodeType nodeType,
const QString &displayName, bool isGeneratedFilesFolder); const QString &displayName);
bool isGeneratedFilesFolder() const { return m_isGeneratedFilesFolder; }
private: private:
QList<ProjectExplorer::ProjectAction> supportedActions(ProjectExplorer::Node *node) const override; QList<ProjectExplorer::ProjectAction> supportedActions(ProjectExplorer::Node *node) const override;
const bool m_isGeneratedFilesFolder;
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -100,13 +92,9 @@ public:
qbs::GroupData qbsGroupData() const { return m_qbsGroupData; } qbs::GroupData qbsGroupData() const { return m_qbsGroupData; }
QString productPath() const;
private: private:
qbs::GroupData m_qbsGroupData; qbs::GroupData m_qbsGroupData;
QString m_productPath; QString m_productPath;
static QIcon m_groupIcon;
}; };
// -------------------------------------------------------------------- // --------------------------------------------------------------------
@@ -129,10 +117,7 @@ public:
QList<ProjectExplorer::RunConfiguration *> runConfigurations() const override; QList<ProjectExplorer::RunConfiguration *> runConfigurations() const override;
private: private:
QbsGroupNode *findGroupNode(const QString &name);
const qbs::ProductData m_qbsProductData; const qbs::ProductData m_qbsProductData;
static QIcon m_productIcon;
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -143,18 +128,15 @@ class QbsProjectNode : public QbsBaseProjectNode
{ {
public: public:
explicit QbsProjectNode(const Utils::FileName &projectDirectory); explicit QbsProjectNode(const Utils::FileName &projectDirectory);
~QbsProjectNode() override;
virtual QbsProject *project() const; virtual QbsProject *project() const;
const qbs::Project qbsProject() const; const qbs::Project qbsProject() const;
const qbs::ProjectData qbsProjectData() const { return m_projectData; } const qbs::ProjectData qbsProjectData() const { return m_projectData; }
bool showInSimpleTree() const override; bool showInSimpleTree() const override;
void setProjectData(const qbs::ProjectData &data); // FIXME: Needed?
void setProjectData(const qbs::ProjectData &data);
private: private:
static QIcon m_projectIcon;
qbs::ProjectData m_projectData; qbs::ProjectData m_projectData;
friend class QbsNodeTreeBuilder; friend class QbsNodeTreeBuilder;

View File

@@ -148,6 +148,8 @@ void setupProjectNode(QbsProjectManager::Internal::QbsProjectNode *node, const q
node->setDisplayName(prjData.name()); node->setDisplayName(prjData.name());
else else
node->setDisplayName(node->project()->displayName()); node->setDisplayName(node->project()->displayName());
node->setProjectData(prjData);
} }
QSet<QString> referencedBuildSystemFiles(const qbs::ProjectData &data) QSet<QString> referencedBuildSystemFiles(const qbs::ProjectData &data)

View File

@@ -325,8 +325,9 @@ void resetSize(const SelectionContext &selectionState)
try { try {
RewriterTransaction transaction(selectionState.view(), QByteArrayLiteral("DesignerActionManager|resetSize")); RewriterTransaction transaction(selectionState.view(), QByteArrayLiteral("DesignerActionManager|resetSize"));
foreach (ModelNode node, selectionState.selectedModelNodes()) { foreach (ModelNode node, selectionState.selectedModelNodes()) {
node.removeProperty("width"); QmlItemNode itemNode(node);
node.removeProperty("height"); itemNode.removeProperty("width");
itemNode.removeProperty("height");
} }
} catch (const RewritingException &e) { //better save then sorry } catch (const RewritingException &e) { //better save then sorry
e.showException(); e.showException();
@@ -341,8 +342,9 @@ void resetPosition(const SelectionContext &selectionState)
try { try {
RewriterTransaction transaction(selectionState.view(), QByteArrayLiteral("DesignerActionManager|resetPosition")); RewriterTransaction transaction(selectionState.view(), QByteArrayLiteral("DesignerActionManager|resetPosition"));
foreach (ModelNode node, selectionState.selectedModelNodes()) { foreach (ModelNode node, selectionState.selectedModelNodes()) {
node.removeProperty("x"); QmlItemNode itemNode(node);
node.removeProperty("y"); itemNode.removeProperty("x");
itemNode.removeProperty("y");
} }
transaction.commit(); transaction.commit();
} catch (const RewritingException &e) { //better save then sorry } catch (const RewritingException &e) { //better save then sorry
@@ -366,7 +368,8 @@ void resetZ(const SelectionContext &selectionState)
RewriterTransaction transaction(selectionState.view(), QByteArrayLiteral("DesignerActionManager|resetZ")); RewriterTransaction transaction(selectionState.view(), QByteArrayLiteral("DesignerActionManager|resetZ"));
foreach (ModelNode node, selectionState.selectedModelNodes()) { foreach (ModelNode node, selectionState.selectedModelNodes()) {
node.removeProperty("z"); QmlItemNode itemNode(node);
itemNode.removeProperty("z");
} }
} }

View File

@@ -301,15 +301,12 @@ void FormEditorView::selectedNodesChanged(const QList<ModelNode> &selectedNodeLi
m_scene->update(); m_scene->update();
} }
void FormEditorView::documentMessagesChanged(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings) void FormEditorView::documentMessagesChanged(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &)
{ {
if (!errors.isEmpty()) if (!errors.isEmpty())
formEditorWidget()->showErrorMessageBox(errors); formEditorWidget()->showErrorMessageBox(errors);
else else
formEditorWidget()->hideErrorMessageBox(); formEditorWidget()->hideErrorMessageBox();
if (!warnings.isEmpty())
formEditorWidget()->showWarningMessageBox(warnings);
} }
void FormEditorView::customNotification(const AbstractView * /*view*/, const QString &identifier, const QList<ModelNode> &/*nodeList*/, const QList<QVariant> &/*data*/) void FormEditorView::customNotification(const AbstractView * /*view*/, const QString &identifier, const QList<ModelNode> &/*nodeList*/, const QList<QVariant> &/*data*/)

View File

@@ -286,8 +286,6 @@ void FormEditorWidget::showWarningMessageBox(const QList<DocumentMessage> &warni
errorWidget()->setWarnings(warnings); errorWidget()->setWarnings(warnings);
errorWidget()->setVisible(true); errorWidget()->setVisible(true);
m_graphicsView->setDisabled(true);
m_toolBox->setDisabled(true);
} }
ZoomAction *FormEditorWidget::zoomAction() const ZoomAction *FormEditorWidget::zoomAction() const

View File

@@ -82,10 +82,10 @@ public:
void setResourcePath(const QString &resourcePath); void setResourcePath(const QString &resourcePath);
void startDragAndDrop(QVariant itemLibId);
void setModel(Model *model); void setModel(Model *model);
Q_INVOKABLE void startDragAndDrop(QVariant itemLibId);
protected: protected:
void removeImport(const QString &name); void removeImport(const QString &name);
void addImport(const QString &name, const QString &version); void addImport(const QString &name, const QString &version);

View File

@@ -66,6 +66,25 @@ static Q_LOGGING_CATEGORY(puppetBuild, "qtc.puppet.build")
namespace QmlDesigner { namespace QmlDesigner {
class EventFilter : public QObject {
public:
EventFilter()
{}
bool eventFilter(QObject *o, QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress
|| event->type() == QEvent::MouseButtonRelease
|| event->type() == QEvent::KeyPress
|| event->type() == QEvent::KeyRelease) {
return true;
}
return QObject::eventFilter(o, event);
}
};
QHash<Core::Id, PuppetCreator::PuppetType> PuppetCreator::m_qml2PuppetForKitPuppetHash; QHash<Core::Id, PuppetCreator::PuppetType> PuppetCreator::m_qml2PuppetForKitPuppetHash;
QByteArray PuppetCreator::qtHash() const QByteArray PuppetCreator::qtHash() const
@@ -241,6 +260,7 @@ static QString idealProcessCount()
bool PuppetCreator::build(const QString &qmlPuppetProjectFilePath) const bool PuppetCreator::build(const QString &qmlPuppetProjectFilePath) const
{ {
PuppetBuildProgressDialog progressDialog; PuppetBuildProgressDialog progressDialog;
progressDialog.setParent(Core::ICore::mainWindow());
m_compileLog.clear(); m_compileLog.clear();
@@ -248,6 +268,16 @@ bool PuppetCreator::build(const QString &qmlPuppetProjectFilePath) const
bool buildSucceeded = false; bool buildSucceeded = false;
/* Ensure the model dialog is shown and no events are delivered to the rest of Qt Creator. */
EventFilter eventFilter;
QCoreApplication::instance()->installEventFilter(&eventFilter);
progressDialog.show();
QCoreApplication::processEvents();
QCoreApplication::instance()->removeEventFilter(&eventFilter);
/* Now the modal dialog will block input to the rest of Qt Creator.
We can call process events without risking a mode change. */
if (qtIsSupported()) { if (qtIsSupported()) {
if (buildDirectory.isValid()) { if (buildDirectory.isValid()) {
QStringList qmakeArguments; QStringList qmakeArguments;

View File

@@ -188,7 +188,6 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
bool QmlDesignerPlugin::delayedInitialize() bool QmlDesignerPlugin::delayedInitialize()
{ {
integrateIntoQtCreator(d->mainWidget);
// adding default path to item library plugins // adding default path to item library plugins
const QString pluginPath = Utils::HostOsInfo::isMacHost() const QString pluginPath = Utils::HostOsInfo::isMacHost()
? QString(QCoreApplication::applicationDirPath() + "/../PlugIns/QmlDesigner") ? QString(QCoreApplication::applicationDirPath() + "/../PlugIns/QmlDesigner")
@@ -210,6 +209,7 @@ bool QmlDesignerPlugin::delayedInitialize()
void QmlDesignerPlugin::extensionsInitialized() void QmlDesignerPlugin::extensionsInitialized()
{ {
integrateIntoQtCreator(d->mainWidget);
} }
static QStringList allUiQmlFilesforCurrentProject(const Utils::FileName &fileName) static QStringList allUiQmlFilesforCurrentProject(const Utils::FileName &fileName)

View File

@@ -84,6 +84,7 @@ QVariantMap InputEventsModel::details(int index) const
switch (event.type) { switch (event.type) {
case InputKeyPress: case InputKeyPress:
type = tr("Key Press"); type = tr("Key Press");
// fallthrough
case InputKeyRelease: case InputKeyRelease:
if (type.isEmpty()) if (type.isEmpty())
type = tr("Key Release"); type = tr("Key Release");
@@ -97,9 +98,11 @@ QVariantMap InputEventsModel::details(int index) const
break; break;
case InputMouseDoubleClick: case InputMouseDoubleClick:
type = tr("Double Click"); type = tr("Double Click");
// fallthrough
case InputMousePress: case InputMousePress:
if (type.isEmpty()) if (type.isEmpty())
type = tr("Mouse Press"); type = tr("Mouse Press");
// fallthrough
case InputMouseRelease: case InputMouseRelease:
if (type.isEmpty()) if (type.isEmpty())
type = tr("Mouse Release"); type = tr("Mouse Release");

View File

@@ -208,9 +208,10 @@ void PixmapCacheModel::loadEvent(const QmlEvent &event, const QmlEventType &type
PixmapState &state = pixmap.sizes[newEvent.sizeIndex]; PixmapState &state = pixmap.sizes[newEvent.sizeIndex];
if (state.cacheState == ToBeCached) { if (state.cacheState == ToBeCached) {
m_lastCacheSizeEvent = updateCacheCount(m_lastCacheSizeEvent, pixmapStartTime, m_lastCacheSizeEvent = updateCacheCount(
state.size.width() * state.size.height(), newEvent, m_lastCacheSizeEvent, pixmapStartTime,
event.typeIndex()); (qint64) state.size.width() * (qint64) state.size.height(),
newEvent, event.typeIndex());
state.cacheState = Cached; state.cacheState = Cached;
} }
break; break;
@@ -230,7 +231,7 @@ void PixmapCacheModel::loadEvent(const QmlEvent &event, const QmlEventType &type
} else if (!uncache && i->cacheState == Uncached) { } else if (!uncache && i->cacheState == Uncached) {
newEvent.sizeIndex = i - pixmap.sizes.begin(); newEvent.sizeIndex = i - pixmap.sizes.begin();
if (i->size.isValid()) { if (i->size.isValid()) {
pixSize = i->size.width() * i->size.height(); pixSize = (qint64) i->size.width() * i->size.height();
i->cacheState = Cached; i->cacheState = Cached;
} else { } else {
i->cacheState = ToBeCached; i->cacheState = ToBeCached;
@@ -247,7 +248,7 @@ void PixmapCacheModel::loadEvent(const QmlEvent &event, const QmlEventType &type
if (uncache && (i->cacheState == Cached || i->cacheState == ToBeCached)) { if (uncache && (i->cacheState == Cached || i->cacheState == ToBeCached)) {
newEvent.sizeIndex = i - pixmap.sizes.begin(); newEvent.sizeIndex = i - pixmap.sizes.begin();
if (i->size.isValid()) if (i->size.isValid())
pixSize = -i->size.width() * i->size.height(); pixSize = (qint64) -i->size.width() * i->size.height();
i->cacheState = Uncached; i->cacheState = Uncached;
break; break;
} else if (!uncache && i->cacheState == Uncacheable) { } else if (!uncache && i->cacheState == Uncacheable) {

View File

@@ -638,7 +638,7 @@ void QmlProfilerStatisticsMainView::parseModel()
newRow << new StatisticsViewItem(QString::number(stats.calls), stats.calls); newRow << new StatisticsViewItem(QString::number(stats.calls), stats.calls);
if (d->m_fieldShown[TimePerCall]) { if (d->m_fieldShown[TimePerCall]) {
const qint64 timePerCall = stats.duration / stats.calls; const qint64 timePerCall = stats.calls > 0 ? stats.duration / stats.calls : 0;
newRow << new StatisticsViewItem(Timeline::formatTime(timePerCall), newRow << new StatisticsViewItem(Timeline::formatTime(timePerCall),
timePerCall); timePerCall);
} }

View File

@@ -243,6 +243,7 @@ Kit *TestQtProjectImporter::createKit(void *directoryData) const
QList<BuildInfo *> TestQtProjectImporter::buildInfoListForKit(const Kit *k, void *directoryData) const QList<BuildInfo *> TestQtProjectImporter::buildInfoListForKit(const Kit *k, void *directoryData) const
{ {
Q_UNUSED(directoryData);
assert(m_testData.contains(directoryData)); assert(m_testData.contains(directoryData));
assert(!m_deletedTestData.contains(directoryData)); assert(!m_deletedTestData.contains(directoryData));
assert(static_cast<const DirectoryData *>(directoryData)->importPath == m_path); assert(static_cast<const DirectoryData *>(directoryData)->importPath == m_path);

View File

@@ -192,7 +192,7 @@ IEditor *FindInFilesSilverSearcher::openEditor(const SearchResultItem & /*item*/
return 0; return 0;
} }
void FindInFilesSilverSearcher::readSettings(QSettings */*settings*/) void FindInFilesSilverSearcher::readSettings(QSettings * /*settings*/)
{ {
} }

View File

@@ -2724,7 +2724,8 @@ void tst_Dumpers::dumper_data()
+ Check("ob", "\"An Object\"", "@QWidget") + Check("ob", "\"An Object\"", "@QWidget")
+ Check("ob1", "\"Another Object\"", "@QObject") + Check("ob1", "\"Another Object\"", "@QObject")
+ Check("ob2", "\"A Subobject\"", "@QObject") + Check("ob2", "\"A Subobject\"", "@QObject")
+ Check("ob.[extra].[connections].0.0.receiver", "\"Another Object\"", "@QObject"); + Check("ob.[extra].[connections].0.0.receiver", "\"Another Object\"",
"@QObject") % NoCdbEngine;
QString senderData = QString senderData =

View File

@@ -146,12 +146,22 @@ void tst_offsets::offsets_data()
const int qtVersion = QT_VERSION; const int qtVersion = QT_VERSION;
if (qtVersion >= 0x50600) if (qtVersion >= 0x50700)
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
# ifdef Q_CC_MSVC # ifdef Q_CC_MSVC
OFFSET_TEST(QFilePrivate, fileName) << 184 << 248; OFFSET_TEST(QFilePrivate, fileName) << 184 << 248;
# else // MinGW # else // MinGW
OFFSET_TEST(QFilePrivate, fileName) << 164 << 248; OFFSET_TEST(QFilePrivate, fileName) << 172 << 248;
# endif
#else
OFFSET_TEST(QFilePrivate, fileName) << 168 << 248;
#endif
else if (qtVersion >= 0x50600)
#ifdef Q_OS_WIN
# ifdef Q_CC_MSVC
OFFSET_TEST(QFilePrivate, fileName) << 184 << 248;
# else // MinGW
OFFSET_TEST(QFilePrivate, fileName) << 180 << 248;
# endif # endif
#else #else
OFFSET_TEST(QFilePrivate, fileName) << 168 << 248; OFFSET_TEST(QFilePrivate, fileName) << 168 << 248;

View File

@@ -128,8 +128,7 @@ def doSimpleDebugging(kitCount, currentKit, currentConfigName, pressContinueCoun
expectedLabelTexts = ['Stopped\.', 'Stopped at breakpoint \d+ \(\d+\) in thread \d+\.'] expectedLabelTexts = ['Stopped\.', 'Stopped at breakpoint \d+ \(\d+\) in thread \d+\.']
if len(expectedBPOrder) == 0: if len(expectedBPOrder) == 0:
expectedLabelTexts.append("Running\.") expectedLabelTexts.append("Running\.")
if JIRA.isBugStillOpen(17492): expectedLabelTexts.append("QML Debugger: Error: Unknown socket error 0")
expectedLabelTexts.append("QML Debugger: Error: Unknown socket error 0")
switchViewTo(ViewConstants.PROJECTS) switchViewTo(ViewConstants.PROJECTS)
switchToBuildOrRunSettingsFor(kitCount, currentKit, ProjectSettings.RUN) switchToBuildOrRunSettingsFor(kitCount, currentKit, ProjectSettings.RUN)
ensureChecked(waitForObject("{container=':Qt Creator.scrollArea_QScrollArea' text='Enable QML' " ensureChecked(waitForObject("{container=':Qt Creator.scrollArea_QScrollArea' text='Enable QML' "