Merge remote-tracking branch 'origin/3.0'
BIN
doc/images/analyzer-issues.png
Normal file → Executable file
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 30 KiB |
BIN
doc/images/qtcreator-analyze-menu.png
Normal file → Executable file
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 26 KiB |
BIN
doc/images/qtcreator-qml-performance-monitor.png
Normal file → Executable file
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 81 KiB |
BIN
doc/images/qtcreator-valgrind-callgrind.png
Normal file → Executable file
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 85 KiB |
BIN
doc/images/qtcreator-valgrind-memcheck-options.png
Normal file → Executable file
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 28 KiB |
@@ -36,8 +36,8 @@
|
||||
to use them from \QC.
|
||||
|
||||
To run the Valgrind tools on a remote host over SSH, select \gui {Analyze
|
||||
> Valgrind Memory Analyzer (External)} or \gui {Valgrind Function Profiler
|
||||
(External)}.
|
||||
> Valgrind Memory Analyzer (Remote)} or \gui {Valgrind Function Profiler
|
||||
(Remote)}.
|
||||
|
||||
To stop the currently running analyzer, select \gui {Analyze
|
||||
> Stop}.
|
||||
|
||||
@@ -97,6 +97,25 @@
|
||||
uninitialized memory} check box is selected by default. You can deselect it
|
||||
to make Memcheck run faster.
|
||||
|
||||
Memcheck searches for memory leaks when the client application finishes. To
|
||||
view the amount of leaks that occurred, select \gui {Summary Only} in the
|
||||
\gui {Check for leaks on finish} field. To also view details of each leak,
|
||||
select \gui Full.
|
||||
|
||||
\section2 Showing Reachable and Indirectly Lost Blocks
|
||||
|
||||
\e Reachable blocks are blocks that are pointed at by a pointer or chain
|
||||
of pointers and that might have been freed before the application exited.
|
||||
\e {Indirectly lost} blocks are considered lost because all the blocks that
|
||||
point to them are themselves lost. For example, all the children of a lost
|
||||
root node are indirectly lost.
|
||||
|
||||
By default, Memcheck does not report reachable and indirectly lost blocks.
|
||||
To have them reported, select the \gui {Show reachable and indirectly lost
|
||||
blocks}.
|
||||
|
||||
\section2 Suppressing Errors
|
||||
|
||||
Memcheck detects numerous problems in the system libraries, such as the C
|
||||
library, which come pre-installed with your OS. As you cannot easily fix
|
||||
them, you want to suppress them. Valgrind reads a list of errors to suppress
|
||||
@@ -252,8 +271,8 @@
|
||||
|
||||
\list 1
|
||||
|
||||
\li Select \gui {Analyze > Valgrind Memory Analyzer (External)} or
|
||||
\gui {Valgrind Function Profiler (External)}.
|
||||
\li Select \gui {Analyze > Valgrind Memory Analyzer (Remote)} or
|
||||
\gui {Valgrind Function Profiler (Remote)}.
|
||||
|
||||
\image qtcreator-valgrind-remote-settings.png "Start Analyzer dialog"
|
||||
|
||||
|
||||
@@ -800,15 +800,13 @@
|
||||
A snapshot contains the complete state of the debugged program
|
||||
at a time, including the full memory contents.
|
||||
|
||||
To create snapshots of a debugged program, select \gui Create in the
|
||||
context menu in the \gui Snapshot view.
|
||||
To create snapshots of a debugged program, select \gui {Create Snapshot} in
|
||||
the context menu in the \gui Snapshots view.
|
||||
|
||||
Double-click on entries in the snapshot view to switch between
|
||||
Double-click on entries in the \gui Snapshots view to switch between
|
||||
snapshots. The debugger views are updated to reflect the
|
||||
state of the program at time of taking the snapshot.
|
||||
|
||||
By default, the \gui{Snapshots} view is hidden.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -901,7 +899,7 @@
|
||||
|
||||
\li There is no GDB to communicate with MSVC compiled applications on
|
||||
Windows. So information can be displayed nicely only in a limited
|
||||
fashion by using a cdb extension DLL.
|
||||
fashion by using a CDB extension DLL.
|
||||
|
||||
\endlist
|
||||
|
||||
@@ -986,13 +984,13 @@
|
||||
]}"
|
||||
\endcode
|
||||
|
||||
The value of the \gui{iname} field is the internal name of the object,
|
||||
The value of the \c iname field is the internal name of the object,
|
||||
constituting a dot-separated list of identifiers, corresponding to the
|
||||
position of the object's representation in the view. If it is not
|
||||
present, is it generated by concatenating the parent object's iname,
|
||||
a dot, and a sequential number.
|
||||
|
||||
The value of the\gui{name} field is displayed in the \gui{name} column
|
||||
The value of the \c name field is displayed in the \gui{Name} column
|
||||
of the view. If it is not specified, a simple number in brackets
|
||||
is used instead.
|
||||
|
||||
@@ -1003,44 +1001,44 @@
|
||||
enums, known and unknown structs as well as some convenience functions to
|
||||
handle common situations.
|
||||
|
||||
The member functions of the \gui{Dumper} class are the following:
|
||||
The member functions of the \c Dumper class are the following:
|
||||
|
||||
\list
|
||||
|
||||
\li \gui{__init__(self)} - Initializes the output to an empty string and
|
||||
\li \c{__init__(self)} - Initializes the output to an empty string and
|
||||
empties the child stack. This should not be used in user code.
|
||||
|
||||
\li \gui{put(self, value)} - Low level function to directly append to the
|
||||
\li \c{put(self, value)} - Low level function to directly append to the
|
||||
output string. That is also the fastest way to append output.
|
||||
|
||||
\li \gui{putField(self, name, value)} - Appends a name='value' field.
|
||||
\li \c{putField(self, name, value)} - Appends a \c{name='value'} field.
|
||||
|
||||
\li \gui{childRange(self)} - Returns the range of children specified in
|
||||
\li \c{childRange(self)} - Returns the range of children specified in
|
||||
the current \c Children scope.
|
||||
|
||||
\li \gui{putItemCount(self, count)} - Appends a field
|
||||
\li \c{putItemCount(self, count)} - Appends a field
|
||||
\c {value='<%d items'} to the output.
|
||||
|
||||
\li \gui{putEllipsis(self)} - Appends fields
|
||||
\li \c{putEllipsis(self)} - Appends fields
|
||||
\c {'{name="<incomplete>",value="",type="",numchild="0"}'}. This is
|
||||
automatically done by \c endChildren if the number of children to
|
||||
print is smaller than the number of actual children.
|
||||
|
||||
\li \gui{putName(self, name)} - Appends a \c {name=''} field.
|
||||
\li \c{putName(self, name)} - Appends a \c {name=''} field.
|
||||
|
||||
\li \gui{putType(self, type, priority=0)} - Appends a field \c {type=''}
|
||||
\li \c{putType(self, type, priority=0)} - Appends a field \c {type=''}
|
||||
unless the \a type coincides with the parent's default child type or
|
||||
\c putType was already called for the current item with a higher
|
||||
value of \c priority.
|
||||
|
||||
\li \gui{putBetterType(self, type)} - Overrides the last recorded
|
||||
\li \c{putBetterType(self, type)} - Overrides the last recorded
|
||||
\c type.
|
||||
|
||||
\li \gui{putNumChild(self, numchild)} - Appends a field \c {numchild=''}
|
||||
\li \c{putNumChild(self, numchild)} - Appends a field \c {numchild=''}
|
||||
unless the \c numchild coincides with the parent's default child
|
||||
numchild value.
|
||||
|
||||
\li \gui{putValue(self, value, encoding = None)} - Append a file \c {value=''},
|
||||
\li \c{putValue(self, value, encoding = None)} - Append a file \c {value=''},
|
||||
optionally followed by a field \c {valueencoding=''}. The \c value
|
||||
needs to be convertible to a string entirely consisting of
|
||||
alphanumerical values. The \c encoding parameter can be used to
|
||||
@@ -1072,16 +1070,16 @@
|
||||
double quotes are added.
|
||||
\endlist
|
||||
|
||||
\li \gui{putStringValue(self, value)} - Encodes a QString and calls
|
||||
\li \c{putStringValue(self, value)} - Encodes a QString and calls
|
||||
\c putValue with the correct \c encoding setting.
|
||||
|
||||
\li \gui{putByteArrayValue(self, value)} - Encodes a QByteArray and calls
|
||||
\li \c{putByteArrayValue(self, value)} - Encodes a QByteArray and calls
|
||||
\c putValue with the correct \c encoding setting.
|
||||
|
||||
\li \gui{isExpanded()} - Checks whether the current item
|
||||
\li \c{isExpanded()} - Checks whether the current item
|
||||
is expanded in the view.
|
||||
|
||||
\li \gui{putIntItem(self, name, value)} - Equivalent to:
|
||||
\li \c{putIntItem(self, name, value)} - Equivalent to:
|
||||
\code
|
||||
with SubItem(self, name):
|
||||
self.putValue(value)
|
||||
@@ -1090,7 +1088,7 @@
|
||||
self.putNumChild(0)
|
||||
\endcode
|
||||
|
||||
\li \gui{putBoolItem(self, name, value)} - Equivalent to:
|
||||
\li \c{putBoolItem(self, name, value)} - Equivalent to:
|
||||
\code
|
||||
with SubItem(self, name):
|
||||
self.putValue(value)
|
||||
@@ -1098,7 +1096,7 @@
|
||||
self.putNumChild(0)
|
||||
\endcode
|
||||
|
||||
\li \gui{putCallItem(self, name, value, func, *args)} -
|
||||
\li \c{putCallItem(self, name, value, func, *args)} -
|
||||
Uses GDB to call the function \c func on the value specified by
|
||||
\a {value} and output the resulting item. Use \c{putCallItem}
|
||||
only if there is no other way to access the data.
|
||||
@@ -1107,12 +1105,12 @@
|
||||
and have the potential to change the state of the debugged
|
||||
program.
|
||||
|
||||
\li \gui{putItem(self, value)} - The "master function", handling
|
||||
\li \c{putItem(self, value)} - The "master function", handling
|
||||
basic types, references, pointers and enums directly, iterates
|
||||
over base classes and class members of compound types and calls
|
||||
\c qdump__* functions whenever appropriate.
|
||||
|
||||
\li \gui{putSubItem(self, component, value)} - Equivalent to:
|
||||
\li \c{putSubItem(self, component, value)} - Equivalent to:
|
||||
\code
|
||||
with SubItem(self, component):
|
||||
self.putItem(value)
|
||||
@@ -1135,7 +1133,7 @@
|
||||
use \c Children and \c SubItem \e{Context Managers} to create the nested
|
||||
items.
|
||||
|
||||
The \c Children constructor \gui{__init__(self, dumper, numChild = 1,
|
||||
The \c Children constructor \c{__init__(self, dumper, numChild = 1,
|
||||
childType = None, childNumChild = None, maxNumChild = None, addrBase = None,
|
||||
addrStep = None)} uses one mandatory argument and several
|
||||
optional arguments. The mandatory argument refers to the current \c Dumper
|
||||
|
||||
@@ -110,6 +110,69 @@
|
||||
For more information about known issues for the current version, see
|
||||
\l{Known Issues}.
|
||||
|
||||
\section1 Deploying CMake Projects to Embedded Linux Devices
|
||||
|
||||
\QC cannot extract files to be installed from a CMake project, and
|
||||
therefore, only executable targets are automatically added to deployment
|
||||
files. You must specify all other files in the \c QtCreatorDeployment.txt
|
||||
file that you create and place in the root directory of the CMake project.
|
||||
|
||||
Use the following syntax in the file:
|
||||
|
||||
\code
|
||||
<deployment/prefix>
|
||||
<relative/source/file1>:<relative/destination/dir1>
|
||||
...
|
||||
<relative/source/filen>:<relative/destination/dirn>
|
||||
\endcode
|
||||
|
||||
Where:
|
||||
|
||||
\list
|
||||
|
||||
\li \c{<deployment/prefix>} is the (absolute) path prefix to where files
|
||||
are copied on the remote machine.
|
||||
|
||||
\li \c{<relative/source/file>} is the file path relative to the CMake
|
||||
project root. No directories or wildcards are allowed in this
|
||||
value.
|
||||
|
||||
\li \c{<relative/destination/dir>} is the destination directory path
|
||||
relative to \c{deployment/prefix}.
|
||||
|
||||
\endlist
|
||||
|
||||
To automate the creation of \c QtCreatorDeployment.txt file:
|
||||
|
||||
\list 1
|
||||
|
||||
\li Define the following macros in the top level \c CMakeLists.txt file:
|
||||
|
||||
\code
|
||||
file(WRITE "${CMAKE_SOURCE_DIR}/QtCreatorDeployment.txt" "<deployment/prefix>\n")
|
||||
|
||||
macro(add_deployment_file SRC DEST)
|
||||
file(RELATIVE_PATH path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
file(APPEND "${CMAKE_SOURCE_DIR}/QtCreatorDeployment.txt" "${path}/${SRC}:${DEST}\n")
|
||||
endmacro()
|
||||
|
||||
macro(add_deployment_directory SRC DEST)
|
||||
file(GLOB_RECURSE files RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${SRC}/*")
|
||||
foreach(filename ${files})
|
||||
get_filename_component(path ${filename} PATH)
|
||||
add_deployment_file("${filename}" "${DEST}/${path}")
|
||||
endforeach(filename)
|
||||
endmacro()
|
||||
\endcode
|
||||
|
||||
\li Use \c {add_deployment_file(<file/name>)} to add files and
|
||||
\c {add_deployment_directory(<folder/name>)} to add directories
|
||||
(including subdirectories) to the \c QtCreatorDeployment.txt file.
|
||||
|
||||
\li Re-run \c cmake after you add or remove files using the macros.
|
||||
|
||||
\endlist
|
||||
|
||||
\section1 Adding External Libraries to CMake Projects
|
||||
|
||||
Through external libraries, \QC can support code completion and syntax
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
To use Qbs to build a project, you must create a .qbs file for the project.
|
||||
For more information, see the
|
||||
\l{http://doc-snapshot.qt-project.org/qbs/index.html}{Qbs Manual}.
|
||||
\l{http://qt-project.org/doc/qbs/index.html}{Qbs Manual}.
|
||||
|
||||
\section1 Enabling the Qbs Plugin
|
||||
|
||||
@@ -58,18 +58,20 @@
|
||||
|
||||
\list 1
|
||||
|
||||
\li Create a .qbs file for your project. For examples, see the
|
||||
\c {tests\manual} directory in the qbs repository.
|
||||
|
||||
\li In \QC, select \gui File > \gui {Open File or Project}.
|
||||
|
||||
\li Select the .qbs file for your project.
|
||||
\li Select \gui File > \gui {New File or Project} > \gui {Plain C
|
||||
Project (Qbs Build)} or \gui {Plain C++ Project (Qbs Build)} >
|
||||
\gui Choose, and follow the instructions of the wizard to create a
|
||||
Qbs project.
|
||||
|
||||
\image creator-qbs-project.png
|
||||
|
||||
\li Edit the .qbs file for you project. Usually, you must add the
|
||||
\c Depends item for a Qt application. For examples, see the
|
||||
\c {examples} directory in the qbs repository.
|
||||
|
||||
\li Click the
|
||||
\inlineimage qtcreator-run.png
|
||||
(\gui Run) button to run the application.
|
||||
(\gui Run) button to build, deploy, and run the application.
|
||||
|
||||
\endlist
|
||||
|
||||
|
||||
@@ -420,7 +420,7 @@ class LocalItem:
|
||||
#######################################################################
|
||||
|
||||
def bbedit(args):
|
||||
theDumper.bbedit(args.split(","))
|
||||
theDumper.bbedit(args)
|
||||
|
||||
registerCommand("bbedit", bbedit)
|
||||
|
||||
@@ -706,7 +706,8 @@ class Dumper(DumperBase):
|
||||
if type.find(":") >= 0:
|
||||
type = "'" + type + "'"
|
||||
# 'class' is needed, see http://sourceware.org/bugzilla/show_bug.cgi?id=11912
|
||||
exp = "((class %s*)%s)->%s(%s)" % (type, value.address, func, arg)
|
||||
#exp = "((class %s*)%s)->%s(%s)" % (type, value.address, func, arg)
|
||||
exp = "((%s*)%s)->%s(%s)" % (type, value.address, func, arg)
|
||||
#warn("CALL: %s" % exp)
|
||||
result = None
|
||||
try:
|
||||
@@ -903,6 +904,15 @@ class Dumper(DumperBase):
|
||||
# Try _some_ fallback (good enough for the std::complex dumper)
|
||||
return gdb.parse_and_eval("{%s}%s" % (referencedType, address))
|
||||
|
||||
def setValue(self, address, type, value):
|
||||
cmd = "set {%s}%s=%s" % (type, address, value)
|
||||
gdb.execute(cmd)
|
||||
|
||||
def setValues(self, address, type, values):
|
||||
cmd = "set {%s[%s]}%s={%s}" \
|
||||
% (type, len(values), address, ','.join(map(str, values)))
|
||||
gdb.execute(cmd)
|
||||
|
||||
def selectedInferior(self):
|
||||
try:
|
||||
# gdb.Inferior is new in gdb 7.2
|
||||
@@ -1630,6 +1640,10 @@ class Dumper(DumperBase):
|
||||
return out
|
||||
|
||||
def threadnames(self, maximalStackDepth):
|
||||
# FIXME: This needs a proper implementation for MinGW, and only there.
|
||||
# Linux, Mac and QNX mirror the objectName()to the underlying threads,
|
||||
# so we get the names already as part of the -thread-info output.
|
||||
return '[]'
|
||||
out = '['
|
||||
oldthread = gdb.selected_thread()
|
||||
if oldthread:
|
||||
@@ -1676,22 +1690,25 @@ class Dumper(DumperBase):
|
||||
|
||||
return namespace
|
||||
|
||||
def bbedit(self, type, expr, value):
|
||||
type = b16decode(type)
|
||||
def bbedit(self, args):
|
||||
(typeName, expr, data) = args.split(',')
|
||||
typeName = b16decode(typeName)
|
||||
ns = self.qtNamespace()
|
||||
if type.startswith(ns):
|
||||
type = type[len(ns):]
|
||||
type = type.replace("::", "__")
|
||||
pos = type.find('<')
|
||||
if typeName.startswith(ns):
|
||||
typeName = typeName[len(ns):]
|
||||
typeName = typeName.replace("::", "__")
|
||||
pos = typeName.find('<')
|
||||
if pos != -1:
|
||||
type = type[0:pos]
|
||||
typeName = typeName[0:pos]
|
||||
expr = b16decode(expr)
|
||||
value = b16decode(value)
|
||||
#warn("EDIT: %s %s %s %s: " % (pos, type, expr, value))
|
||||
if self.qqEditable.has_key(type):
|
||||
self.qqEditable[type](expr, value)
|
||||
data = b16decode(data)
|
||||
if typeName in self.qqEditable:
|
||||
#self.qqEditable[typeName](self, expr, data)
|
||||
value = gdb.parse_and_eval(expr)
|
||||
self.qqEditable[typeName](self, value, data)
|
||||
else:
|
||||
gdb.execute("set (%s)=%s" % (expr, value))
|
||||
cmd = "set variable (%s)=%s" % (expr, data)
|
||||
gdb.execute(cmd)
|
||||
|
||||
def hasVTable(self, type):
|
||||
fields = type.fields()
|
||||
|
||||
@@ -618,7 +618,10 @@ class Dumper(DumperBase):
|
||||
self.report('state="inferiorrunfailed"')
|
||||
return
|
||||
self.report('pid="%s"' % self.process.GetProcessID())
|
||||
self.report('state="enginerunandinferiorstopok"')
|
||||
# even if it stops it seems that lldb assumes it is running and later detects that
|
||||
# it did stop after all, so it is be better to mirror that and wait for the spontaneous
|
||||
# stop
|
||||
self.report('state="enginerunandinferiorrunok"')
|
||||
elif len(self.remoteChannel_) > 0:
|
||||
self.process = self.target.ConnectRemote(
|
||||
self.debugger.GetListener(),
|
||||
@@ -626,7 +629,10 @@ class Dumper(DumperBase):
|
||||
if not error.Success():
|
||||
self.report('state="inferiorrunfailed"')
|
||||
return
|
||||
self.report('state="enginerunandinferiorstopok"')
|
||||
# even if it stops it seems that lldb assumes it is running and later detects that
|
||||
# it did stop after all, so it is be better to mirror that and wait for the spontaneous
|
||||
# stop
|
||||
self.report('state="enginerunandinferiorrunok"')
|
||||
else:
|
||||
launchInfo = lldb.SBLaunchInfo(self.processArgs_.split())
|
||||
launchInfo.SetWorkingDirectory(os.getcwd())
|
||||
|
||||
@@ -165,7 +165,7 @@ def qdump__QModelIndex(d, value):
|
||||
v = val["d"]["data"]["ptr"]
|
||||
d.putStringValue(d.makeValue(ns + 'QString', v))
|
||||
except:
|
||||
d.putValue("(invalid)")
|
||||
d.putValue("")
|
||||
|
||||
d.putNumChild(rowCount * columnCount)
|
||||
if d.isExpanded():
|
||||
@@ -1645,17 +1645,10 @@ def qdump__QStandardItem(d, value):
|
||||
d.putPlainChildren(value)
|
||||
|
||||
|
||||
def qedit__QString(expr, value):
|
||||
cmd = "call (%s).resize(%d)" % (expr, len(value))
|
||||
gdb.execute(cmd)
|
||||
d = gdb.parse_and_eval(expr)["d"]["data"]
|
||||
cmd = "set {short[%d]}%s={" % (len(value), d.pointerValue(d))
|
||||
for i in range(len(value)):
|
||||
if i != 0:
|
||||
cmd += ','
|
||||
cmd += str(ord(value[i]))
|
||||
cmd += '}'
|
||||
gdb.execute(cmd)
|
||||
def qedit__QString(d, value, data):
|
||||
d.call(value, "resize", str(len(data)))
|
||||
(base, size, alloc) = d.stringData(value)
|
||||
d.setValues(base, "short", [ord(c) for c in data])
|
||||
|
||||
def qform__QString():
|
||||
return "Inline,Separate Window"
|
||||
@@ -1981,15 +1974,19 @@ def qdump__QVariant(d, value):
|
||||
return tdata.type
|
||||
|
||||
|
||||
def qedit__QVector(expr, value):
|
||||
values = value.split(',')
|
||||
ob = gdb.parse_and_eval(expr)
|
||||
cmd = "call (%s).resize(%d)" % (expr, len(values))
|
||||
gdb.execute(cmd)
|
||||
innerType = d.templateArgument(ob.type, 0)
|
||||
ptr = ob["p"]["array"].cast(d.voidPtrType())
|
||||
cmd = "set {%s[%d]}%s={%s}" % (innerType, len(values), d.pointerValue(ptr), value)
|
||||
gdb.execute(cmd)
|
||||
def qedit__QVector(d, value, data):
|
||||
values = data.split(',')
|
||||
size = len(values)
|
||||
d.call(value, "resize", str(size))
|
||||
innerType = d.templateArgument(value.type, 0)
|
||||
try:
|
||||
# Qt 5. Will fail on Qt 4 due to the missing 'offset' member.
|
||||
offset = value["d"]["offset"]
|
||||
base = d.pointerValue(value["d"].cast(d.charPtrType()) + offset)
|
||||
except:
|
||||
# Qt 4.
|
||||
base = d.pointerValue(value["p"]["array"])
|
||||
d.setValues(base, innerType, values)
|
||||
|
||||
|
||||
def qform__QVector():
|
||||
|
||||
@@ -659,16 +659,16 @@ def qdump__std____debug__unordered_set(d, value):
|
||||
qdump__std__unordered_set(d, value)
|
||||
|
||||
|
||||
def qedit__std__vector(expr, value):
|
||||
values = value.split(',')
|
||||
def qedit__std__vector(d, value, data):
|
||||
import gdb
|
||||
values = data.split(',')
|
||||
n = len(values)
|
||||
ob = gdb.parse_and_eval(expr)
|
||||
innerType = d.templateArgument(ob.type, 0)
|
||||
innerType = d.templateArgument(value.type, 0)
|
||||
cmd = "set $d = (%s*)calloc(sizeof(%s)*%s,1)" % (innerType, innerType, n)
|
||||
gdb.execute(cmd)
|
||||
cmd = "set {void*[3]}%s = {$d, $d+%s, $d+%s}" % (ob.address, n, n)
|
||||
cmd = "set {void*[3]}%s = {$d, $d+%s, $d+%s}" % (value.address, n, n)
|
||||
gdb.execute(cmd)
|
||||
cmd = "set (%s[%d])*$d={%s}" % (innerType, n, value)
|
||||
cmd = "set (%s[%d])*$d={%s}" % (innerType, n, data)
|
||||
gdb.execute(cmd)
|
||||
|
||||
def qdump__std__vector(d, value):
|
||||
@@ -766,12 +766,11 @@ def qdump__std____1__vector(d, value):
|
||||
def qdump__std____debug__vector(d, value):
|
||||
qdump__std__vector(d, value)
|
||||
|
||||
def qedit__std__string(expr, value):
|
||||
cmd = "print (%s).assign(\"%s\")" % (expr, value)
|
||||
gdb.execute(cmd)
|
||||
def qedit__std__string(d, value, data):
|
||||
d.call(value, "assign", '"%s"' % data.replace('"', '\\"'))
|
||||
|
||||
def qedit__string(expr, value):
|
||||
qedit__std__string(expr, value)
|
||||
def qedit__string(d, expr, value):
|
||||
qedit__std__string(d, expr, value)
|
||||
|
||||
def qdump__string(d, value):
|
||||
qdump__std__string(d, value)
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include <private/qsimulatorconnection_p.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <qt4nodeinstanceclientproxy.h>
|
||||
|
||||
#ifdef ENABLE_QT_BREAKPAD
|
||||
@@ -60,11 +62,11 @@ int main(int argc, char *argv[])
|
||||
QCoreApplication::setOrganizationName("QtProject");
|
||||
QCoreApplication::setOrganizationDomain("qt-project.org");
|
||||
QCoreApplication::setApplicationName("QmlPuppet");
|
||||
QCoreApplication::setApplicationVersion("1.1.0");
|
||||
QCoreApplication::setApplicationVersion("2.0.0");
|
||||
|
||||
|
||||
if (application.arguments().count() == 2 && application.arguments().at(1) == "--version") {
|
||||
qDebug() << QCoreApplication::applicationVersion();
|
||||
std::cout << 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,11 +10,6 @@ DEPLOYMENTFOLDERS = folder_01
|
||||
# TOUCH_OPTIMIZED_NAVIGATION #
|
||||
DEFINES += TOUCH_OPTIMIZED_NAVIGATION
|
||||
|
||||
# If your application uses the Qt Mobility libraries, uncomment the following
|
||||
# lines and add the respective components to the MOBILITY variable.
|
||||
# CONFIG += mobility
|
||||
# MOBILITY +=
|
||||
|
||||
# The .cpp file which was generated for your project. Feel free to hack it.
|
||||
SOURCES += main.cpp
|
||||
|
||||
|
||||
@@ -101,13 +101,13 @@ ColumnLayout {
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
Text {
|
||||
NativeText {
|
||||
text: qsTr("New to Qt?")
|
||||
font.pixelSize: 18
|
||||
font.bold: false
|
||||
}
|
||||
|
||||
Text {
|
||||
NativeText {
|
||||
text: qsTr("Learn how to develop your own applications and explore Qt Creator.")
|
||||
font.pixelSize: 12
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "componentversion.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QCryptographicHash>
|
||||
|
||||
#include <limits>
|
||||
|
||||
@@ -80,6 +81,12 @@ QString ComponentVersion::toString() const
|
||||
QString::number(_minor));
|
||||
}
|
||||
|
||||
void ComponentVersion::addToHash(QCryptographicHash &hash) const
|
||||
{
|
||||
hash.addData(reinterpret_cast<const char *>(&_major), sizeof(_major));
|
||||
hash.addData(reinterpret_cast<const char *>(&_minor), sizeof(_minor));
|
||||
}
|
||||
|
||||
namespace LanguageUtils {
|
||||
|
||||
bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs)
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
|
||||
#include "languageutils_global.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QCryptographicHash;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace LanguageUtils {
|
||||
|
||||
class LANGUAGEUTILS_EXPORT ComponentVersion
|
||||
@@ -55,6 +59,7 @@ public:
|
||||
|
||||
bool isValid() const;
|
||||
QString toString() const;
|
||||
void addToHash(QCryptographicHash &hash) const;
|
||||
};
|
||||
|
||||
bool LANGUAGEUTILS_EXPORT operator<(const ComponentVersion &lhs, const ComponentVersion &rhs);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "fakemetaobject.h"
|
||||
#include <QCryptographicHash>
|
||||
|
||||
using namespace LanguageUtils;
|
||||
|
||||
@@ -62,6 +63,24 @@ QStringList FakeMetaEnum::keys() const
|
||||
bool FakeMetaEnum::hasKey(const QString &key) const
|
||||
{ return m_keys.contains(key); }
|
||||
|
||||
void FakeMetaEnum::addToHash(QCryptographicHash &hash) const
|
||||
{
|
||||
int len = m_name.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(m_name.constData()), len * sizeof(QChar));
|
||||
len = m_keys.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
foreach (const QString &key, m_keys) {
|
||||
len = key.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
|
||||
}
|
||||
len = m_values.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
foreach (int value, m_values)
|
||||
hash.addData(reinterpret_cast<const char *>(&value), sizeof(value));
|
||||
}
|
||||
|
||||
FakeMetaMethod::FakeMetaMethod(const QString &name, const QString &returnType)
|
||||
: m_name(name)
|
||||
, m_returnType(returnType)
|
||||
@@ -109,6 +128,33 @@ int FakeMetaMethod::revision() const
|
||||
void FakeMetaMethod::setRevision(int r)
|
||||
{ m_revision = r; }
|
||||
|
||||
void FakeMetaMethod::addToHash(QCryptographicHash &hash) const
|
||||
{
|
||||
int len = m_name.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(m_name.constData()), len * sizeof(QChar));
|
||||
hash.addData(reinterpret_cast<const char *>(&m_methodAccess), sizeof(m_methodAccess));
|
||||
hash.addData(reinterpret_cast<const char *>(&m_methodTy), sizeof(m_methodTy));
|
||||
hash.addData(reinterpret_cast<const char *>(&m_revision), sizeof(m_revision));
|
||||
len = m_paramNames.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
foreach (const QString &pName, m_paramNames) {
|
||||
len = pName.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(pName.constData()), len * sizeof(QChar));
|
||||
}
|
||||
len = m_paramTypes.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
foreach (const QString &pType, m_paramTypes) {
|
||||
len = pType.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(pType.constData()), len * sizeof(QChar));
|
||||
}
|
||||
len = m_returnType.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(m_returnType.constData()), len * sizeof(QChar));
|
||||
}
|
||||
|
||||
|
||||
FakeMetaProperty::FakeMetaProperty(const QString &name, const QString &type, bool isList,
|
||||
bool isWritable, bool isPointer, int revision)
|
||||
@@ -138,6 +184,21 @@ bool FakeMetaProperty::isPointer() const
|
||||
int FakeMetaProperty::revision() const
|
||||
{ return m_revision; }
|
||||
|
||||
void FakeMetaProperty::addToHash(QCryptographicHash &hash) const
|
||||
{
|
||||
int len = m_propertyName.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(m_propertyName.constData()), len * sizeof(QChar));
|
||||
hash.addData(reinterpret_cast<const char *>(&m_revision), sizeof(m_revision));
|
||||
int flags = (m_isList ? (1 << 0) : 0)
|
||||
+ (m_isPointer ? (1 << 1) : 0)
|
||||
+ (m_isWritable ? (1 << 2) : 0);
|
||||
hash.addData(reinterpret_cast<const char *>(&flags), sizeof(flags));
|
||||
len = m_type.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(m_type.constData()), len * sizeof(QChar));
|
||||
}
|
||||
|
||||
|
||||
FakeMetaObject::FakeMetaObject()
|
||||
{
|
||||
@@ -226,8 +287,85 @@ QString FakeMetaObject::attachedTypeName() const
|
||||
void FakeMetaObject::setAttachedTypeName(const QString &name)
|
||||
{ m_attachedTypeName = name; }
|
||||
|
||||
QByteArray FakeMetaObject::calculateFingerprint() const
|
||||
{
|
||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||
int len = m_className.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(m_className.constData()), len * sizeof(QChar));
|
||||
len = m_attachedTypeName.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(m_attachedTypeName.constData()), len * sizeof(QChar));
|
||||
len = m_defaultPropertyName.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(m_defaultPropertyName.constData()), len * sizeof(QChar));
|
||||
len = m_enumNameToIndex.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
{
|
||||
QStringList keys(m_enumNameToIndex.keys());
|
||||
keys.sort();
|
||||
foreach (const QString &key, keys) {
|
||||
len = key.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
|
||||
int value = m_enumNameToIndex.value(key);
|
||||
hash.addData(reinterpret_cast<const char *>(&value), sizeof(value)); // avoid? this adds order dependency to fingerprint...
|
||||
m_enums.at(value).addToHash(hash);
|
||||
}
|
||||
}
|
||||
len = m_exports.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
foreach (const Export &e, m_exports)
|
||||
e.addToHash(hash); // normalize order?
|
||||
len = m_exports.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
foreach (const FakeMetaMethod &m, m_methods)
|
||||
m.addToHash(hash); // normalize order?
|
||||
{
|
||||
QStringList keys(m_propNameToIdx.keys());
|
||||
keys.sort();
|
||||
foreach (const QString &key, keys) {
|
||||
len = key.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
|
||||
int value = m_propNameToIdx.value(key);
|
||||
hash.addData(reinterpret_cast<const char *>(&value), sizeof(value)); // avoid? this adds order dependency to fingerprint...
|
||||
m_props.at(value).addToHash(hash);
|
||||
}
|
||||
}
|
||||
len = m_superName.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(m_superName.constData()), len * sizeof(QChar));
|
||||
|
||||
QByteArray res = hash.result();
|
||||
res.append('F');
|
||||
return res;
|
||||
}
|
||||
|
||||
void FakeMetaObject::updateFingerprint()
|
||||
{
|
||||
m_fingerprint = calculateFingerprint();
|
||||
}
|
||||
|
||||
QByteArray FakeMetaObject::fingerprint() const
|
||||
{
|
||||
return m_fingerprint;
|
||||
}
|
||||
|
||||
FakeMetaObject::Export::Export()
|
||||
: metaObjectRevision(0)
|
||||
{}
|
||||
bool FakeMetaObject::Export::isValid() const
|
||||
{ return version.isValid() || !package.isEmpty() || !type.isEmpty(); }
|
||||
|
||||
void FakeMetaObject::Export::addToHash(QCryptographicHash &hash) const
|
||||
{
|
||||
int len = package.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(package.constData()), len * sizeof(QChar));
|
||||
len = type.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(type.constData()), len * sizeof(QChar));
|
||||
version.addToHash(hash);
|
||||
hash.addData(reinterpret_cast<const char *>(&metaObjectRevision), sizeof(metaObjectRevision));
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
#include <QHash>
|
||||
#include <QSharedPointer>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QCryptographicHash;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace LanguageUtils {
|
||||
|
||||
class LANGUAGEUTILS_EXPORT FakeMetaEnum {
|
||||
@@ -60,6 +64,7 @@ public:
|
||||
int keyCount() const;
|
||||
QStringList keys() const;
|
||||
bool hasKey(const QString &key) const;
|
||||
void addToHash(QCryptographicHash &hash) const;
|
||||
};
|
||||
|
||||
class LANGUAGEUTILS_EXPORT FakeMetaMethod {
|
||||
@@ -96,6 +101,7 @@ public:
|
||||
|
||||
int revision() const;
|
||||
void setRevision(int r);
|
||||
void addToHash(QCryptographicHash &hash) const;
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
@@ -125,6 +131,7 @@ public:
|
||||
bool isWritable() const;
|
||||
bool isPointer() const;
|
||||
int revision() const;
|
||||
void addToHash(QCryptographicHash &hash) const;
|
||||
};
|
||||
|
||||
class LANGUAGEUTILS_EXPORT FakeMetaObject {
|
||||
@@ -144,6 +151,7 @@ public:
|
||||
int metaObjectRevision;
|
||||
|
||||
bool isValid() const;
|
||||
void addToHash(QCryptographicHash &hash) const;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -157,6 +165,7 @@ private:
|
||||
QList<FakeMetaMethod> m_methods;
|
||||
QString m_defaultPropertyName;
|
||||
QString m_attachedTypeName;
|
||||
QByteArray m_fingerprint;
|
||||
|
||||
public:
|
||||
FakeMetaObject();
|
||||
@@ -195,6 +204,9 @@ public:
|
||||
|
||||
QString attachedTypeName() const;
|
||||
void setAttachedTypeName(const QString &name);
|
||||
QByteArray calculateFingerprint() const;
|
||||
void updateFingerprint();
|
||||
QByteArray fingerprint() const;
|
||||
};
|
||||
|
||||
} // namespace LanguageUtils
|
||||
|
||||
@@ -39,7 +39,9 @@ HEADERS += \
|
||||
$$PWD/qmljssimplereader.h \
|
||||
$$PWD/persistenttrie.h \
|
||||
$$PWD/qmljsqrcparser.h \
|
||||
$$PWD/qmljsconstants.h
|
||||
$$PWD/qmljsconstants.h \
|
||||
$$PWD/qmljsimportdependencies.h \
|
||||
$$PWD/qmljsviewercontext.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/qmljsbind.cpp \
|
||||
@@ -70,7 +72,10 @@ SOURCES += \
|
||||
$$PWD/consoleitem.cpp \
|
||||
$$PWD/qmljssimplereader.cpp \
|
||||
$$PWD/persistenttrie.cpp \
|
||||
$$PWD/qmljsqrcparser.cpp
|
||||
$$PWD/qmljsqrcparser.cpp \
|
||||
$$PWD/qmljsimportdependencies.cpp \
|
||||
$$PWD/qmljsviewercontext.cpp
|
||||
|
||||
|
||||
RESOURCES += \
|
||||
$$PWD/qmljs.qrc
|
||||
|
||||
@@ -35,6 +35,7 @@ QtcLibrary {
|
||||
"qmljsevaluate.cpp", "qmljsevaluate.h",
|
||||
"qmljsicons.cpp", "qmljsicons.h",
|
||||
"qmljsicontextpane.h",
|
||||
"qmljsimportdependencies.cpp", "qmljsimportdependencies.h",
|
||||
"qmljsindenter.cpp", "qmljsindenter.h",
|
||||
"qmljsinterpreter.cpp", "qmljsinterpreter.h",
|
||||
"qmljslineinfo.cpp", "qmljslineinfo.h",
|
||||
@@ -52,7 +53,8 @@ QtcLibrary {
|
||||
"qmljsstaticanalysismessage.cpp", "qmljsstaticanalysismessage.h",
|
||||
"qmljstypedescriptionreader.cpp", "qmljstypedescriptionreader.h",
|
||||
"qmljsutils.cpp", "qmljsutils.h",
|
||||
"qmljsvalueowner.cpp", "qmljsvalueowner.h"
|
||||
"qmljsvalueowner.cpp", "qmljsvalueowner.h",
|
||||
"qmljsviewercontext.cpp", "qmljsviewercontext.h"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -35,14 +35,22 @@ namespace QmlJS {
|
||||
namespace ImportType {
|
||||
enum Enum {
|
||||
Invalid,
|
||||
ImplicitDirectory,
|
||||
Library,
|
||||
File,
|
||||
Directory,
|
||||
QrcFile,
|
||||
ImplicitDirectory,
|
||||
File,
|
||||
UnknownFile, // refers a file/directory that wasn't found (or to an url)
|
||||
QrcDirectory,
|
||||
ImplicitQrcDirectory,
|
||||
UnknownFile // refers a file/directory that wasn't found
|
||||
QrcFile
|
||||
};
|
||||
}
|
||||
|
||||
namespace ImportKind {
|
||||
enum Enum {
|
||||
Invalid,
|
||||
Library,
|
||||
Path,
|
||||
QrcPath,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -54,17 +54,20 @@ using namespace QmlJS::AST;
|
||||
QmlJSTextEditorWidget::semanticInfo()::context.
|
||||
*/
|
||||
|
||||
ContextPtr Context::create(const QmlJS::Snapshot &snapshot, ValueOwner *valueOwner, const ImportsPerDocument &imports)
|
||||
ContextPtr Context::create(const QmlJS::Snapshot &snapshot, ValueOwner *valueOwner,
|
||||
const ImportsPerDocument &imports, const ViewerContext &vContext)
|
||||
{
|
||||
QSharedPointer<Context> result(new Context(snapshot, valueOwner, imports));
|
||||
QSharedPointer<Context> result(new Context(snapshot, valueOwner, imports, vContext));
|
||||
result->_ptr = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
Context::Context(const QmlJS::Snapshot &snapshot, ValueOwner *valueOwner, const ImportsPerDocument &imports)
|
||||
Context::Context(const QmlJS::Snapshot &snapshot, ValueOwner *valueOwner,
|
||||
const ImportsPerDocument &imports, const ViewerContext &vContext)
|
||||
: _snapshot(snapshot),
|
||||
_valueOwner(valueOwner),
|
||||
_imports(imports)
|
||||
_imports(imports),
|
||||
_vContext(vContext)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "qmljs_global.h"
|
||||
#include "qmljsvalueowner.h"
|
||||
#include "qmljsviewercontext.h"
|
||||
|
||||
#include <QSharedPointer>
|
||||
|
||||
@@ -50,7 +51,8 @@ public:
|
||||
typedef QHash<const Document *, QSharedPointer<const Imports> > ImportsPerDocument;
|
||||
|
||||
// Context takes ownership of valueOwner
|
||||
static ContextPtr create(const Snapshot &snapshot, ValueOwner *valueOwner, const ImportsPerDocument &imports);
|
||||
static ContextPtr create(const Snapshot &snapshot, ValueOwner *valueOwner,
|
||||
const ImportsPerDocument &imports, const ViewerContext &vContext);
|
||||
~Context();
|
||||
|
||||
ContextPtr ptr() const;
|
||||
@@ -69,11 +71,13 @@ public:
|
||||
|
||||
private:
|
||||
// Context takes ownership of valueOwner
|
||||
Context(const Snapshot &snapshot, ValueOwner *valueOwner, const ImportsPerDocument &imports);
|
||||
Context(const Snapshot &snapshot, ValueOwner *valueOwner, const ImportsPerDocument &imports,
|
||||
const ViewerContext &vContext);
|
||||
|
||||
Snapshot _snapshot;
|
||||
QSharedPointer<ValueOwner> _valueOwner;
|
||||
ImportsPerDocument _imports;
|
||||
ViewerContext _vContext;
|
||||
QWeakPointer<const Context> _ptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -30,11 +30,17 @@
|
||||
#include "qmljsdocument.h"
|
||||
#include "qmljsbind.h"
|
||||
#include "qmljsconstants.h"
|
||||
#include "qmljsimportdependencies.h"
|
||||
#include <qmljs/parser/qmljslexer_p.h>
|
||||
#include <qmljs/parser/qmljsparser_p.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QDir>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace QmlJS;
|
||||
using namespace QmlJS::AST;
|
||||
|
||||
@@ -204,6 +210,16 @@ void Document::setLanguage(Language::Enum l)
|
||||
_language = l;
|
||||
}
|
||||
|
||||
QString Document::importId() const
|
||||
{
|
||||
return _fileName;
|
||||
}
|
||||
|
||||
QByteArray Document::fingerprint() const
|
||||
{
|
||||
return _fingerprint;
|
||||
}
|
||||
|
||||
AST::UiProgram *Document::qmlProgram() const
|
||||
{
|
||||
return cast<UiProgram *>(_ast);
|
||||
@@ -245,6 +261,9 @@ QString Document::source() const
|
||||
void Document::setSource(const QString &source)
|
||||
{
|
||||
_source = source;
|
||||
QCryptographicHash sha(QCryptographicHash::Sha1);
|
||||
sha.addData(source.toUtf8());
|
||||
_fingerprint = sha.result();
|
||||
}
|
||||
|
||||
int Document::editorRevision() const
|
||||
@@ -373,21 +392,88 @@ LibraryInfo::LibraryInfo(Status status)
|
||||
: _status(status)
|
||||
, _dumpStatus(NoTypeInfo)
|
||||
{
|
||||
updateFingerprint();
|
||||
}
|
||||
|
||||
LibraryInfo::LibraryInfo(const QmlDirParser &parser)
|
||||
LibraryInfo::LibraryInfo(const QmlDirParser &parser, const QByteArray &fingerprint)
|
||||
: _status(Found)
|
||||
, _components(parser.components().values())
|
||||
, _plugins(parser.plugins())
|
||||
, _typeinfos(parser.typeInfos())
|
||||
, _fingerprint(fingerprint)
|
||||
, _dumpStatus(NoTypeInfo)
|
||||
{
|
||||
if (_fingerprint.isEmpty())
|
||||
updateFingerprint();
|
||||
}
|
||||
|
||||
LibraryInfo::~LibraryInfo()
|
||||
{
|
||||
}
|
||||
|
||||
QByteArray LibraryInfo::calculateFingerprint() const
|
||||
{
|
||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||
hash.addData(reinterpret_cast<const char *>(&_status), sizeof(_status));
|
||||
int len = _components.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
foreach (const QmlDirParser::Component &component, _components) {
|
||||
len = component.fileName.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(component.fileName.constData()), len * sizeof(QChar));
|
||||
hash.addData(reinterpret_cast<const char *>(&component.majorVersion), sizeof(component.majorVersion));
|
||||
hash.addData(reinterpret_cast<const char *>(&component.minorVersion), sizeof(component.minorVersion));
|
||||
len = component.typeName.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(component.typeName.constData()), component.typeName.size() * sizeof(QChar));
|
||||
int flags = (component.singleton ? (1 << 0) : 0) + (component.internal ? (1 << 1) : 0);
|
||||
hash.addData(reinterpret_cast<const char *>(&flags), sizeof(flags));
|
||||
}
|
||||
len = _plugins.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
foreach (const QmlDirParser::Plugin &plugin, _plugins) {
|
||||
len = plugin.path.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(plugin.path.constData()), len * sizeof(QChar));
|
||||
len = plugin.name.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(plugin.name.constData()), len * sizeof(QChar));
|
||||
}
|
||||
len = _typeinfos.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
foreach (const QmlDirParser::TypeInfo &typeinfo, _typeinfos) {
|
||||
len = typeinfo.fileName.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(typeinfo.fileName.constData()), len * sizeof(QChar));
|
||||
}
|
||||
len = _metaObjects.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
QList<QByteArray> metaFingerprints;
|
||||
foreach (const LanguageUtils::FakeMetaObject::ConstPtr &metaObject, _metaObjects)
|
||||
metaFingerprints.append(metaObject->fingerprint());
|
||||
std::sort(metaFingerprints.begin(), metaFingerprints.end());
|
||||
foreach (const QByteArray &fp, metaFingerprints)
|
||||
hash.addData(fp);
|
||||
hash.addData(reinterpret_cast<const char *>(&_dumpStatus), sizeof(_dumpStatus));
|
||||
len = _dumpError.size(); // localization dependent (avoid?)
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(_dumpError.constData()), len * sizeof(QChar));
|
||||
|
||||
len = _moduleApis.size();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
foreach (const ModuleApiInfo &moduleInfo, _moduleApis)
|
||||
moduleInfo.addToHash(hash); // make it order independent?
|
||||
|
||||
QByteArray res(hash.result());
|
||||
res.append('L');
|
||||
return res;
|
||||
}
|
||||
|
||||
void LibraryInfo::updateFingerprint()
|
||||
{
|
||||
_fingerprint = calculateFingerprint();
|
||||
}
|
||||
|
||||
Snapshot::Snapshot()
|
||||
{
|
||||
}
|
||||
@@ -396,21 +482,67 @@ Snapshot::~Snapshot()
|
||||
{
|
||||
}
|
||||
|
||||
Snapshot::Snapshot(const Snapshot &o)
|
||||
: _documents(o._documents),
|
||||
_documentsByPath(o._documentsByPath),
|
||||
_libraries(o._libraries),
|
||||
_dependencies(o._dependencies)
|
||||
{
|
||||
}
|
||||
|
||||
void Snapshot::insert(const Document::Ptr &document, bool allowInvalid)
|
||||
{
|
||||
if (document && (allowInvalid || document->qmlProgram() || document->jsProgram())) {
|
||||
const QString fileName = document->fileName();
|
||||
const QString path = document->path();
|
||||
|
||||
remove(fileName);
|
||||
_documentsByPath[path].append(document);
|
||||
_documents.insert(fileName, document);
|
||||
CoreImport cImport;
|
||||
cImport.importId = document->importId();
|
||||
cImport.language = document->language();
|
||||
cImport.possibleExports << Export(ImportKey(ImportType::File, fileName),
|
||||
QString(), true);
|
||||
cImport.fingerprint = document->fingerprint();
|
||||
_dependencies.addCoreImport(cImport);
|
||||
}
|
||||
}
|
||||
|
||||
void Snapshot::insertLibraryInfo(const QString &path, const LibraryInfo &info)
|
||||
{
|
||||
QTC_CHECK(info.fingerprint() == info.calculateFingerprint());
|
||||
_libraries.insert(QDir::cleanPath(path), info);
|
||||
if (!info.wasFound()) return;
|
||||
CoreImport cImport;
|
||||
cImport.importId = path;
|
||||
cImport.language = Language::Unknown;
|
||||
QSet<ImportKey> packages;
|
||||
foreach (const ModuleApiInfo &moduleInfo, info.moduleApis()) {
|
||||
ImportKey iKey(ImportType::Library, moduleInfo.uri, moduleInfo.version.majorVersion(),
|
||||
moduleInfo.version.minorVersion());
|
||||
packages.insert(iKey);
|
||||
}
|
||||
foreach (const LanguageUtils::FakeMetaObject::ConstPtr &metaO, info.metaObjects()) {
|
||||
foreach (const LanguageUtils::FakeMetaObject::Export &e, metaO->exports()) {
|
||||
ImportKey iKey(ImportType::Library, e.package, e.version.majorVersion(),
|
||||
e.version.minorVersion());
|
||||
packages.insert(iKey);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList splitPath = path.split(QLatin1Char('/'));
|
||||
foreach (const ImportKey &importKey, packages) {
|
||||
QString requiredPath = QStringList(splitPath.mid(0, splitPath.size() - importKey.splitPath.size()))
|
||||
.join(QLatin1String("/"));
|
||||
cImport.possibleExports << Export(importKey, requiredPath, true);
|
||||
}
|
||||
foreach (const QmlDirParser::Component &component, info.components()) {
|
||||
foreach (const Export &e, cImport.possibleExports)
|
||||
// renaming of type name not really represented here... fix?
|
||||
_dependencies.addExport(component.fileName, e.exportName, e.pathRequired);
|
||||
}
|
||||
cImport.fingerprint = info.fingerprint();
|
||||
_dependencies.addCoreImport(cImport);
|
||||
}
|
||||
|
||||
void Snapshot::remove(const QString &fileName)
|
||||
@@ -427,6 +559,16 @@ void Snapshot::remove(const QString &fileName)
|
||||
}
|
||||
}
|
||||
|
||||
const QmlJS::ImportDependencies *Snapshot::importDependencies() const
|
||||
{
|
||||
return &_dependencies;
|
||||
}
|
||||
|
||||
QmlJS::ImportDependencies *Snapshot::importDependencies()
|
||||
{
|
||||
return &_dependencies;
|
||||
}
|
||||
|
||||
Document::MutablePtr Snapshot::documentFromSource(
|
||||
const QString &code, const QString &fileName,
|
||||
Language::Enum language) const
|
||||
@@ -454,3 +596,15 @@ LibraryInfo Snapshot::libraryInfo(const QString &path) const
|
||||
{
|
||||
return _libraries.value(QDir::cleanPath(path));
|
||||
}
|
||||
|
||||
|
||||
void ModuleApiInfo::addToHash(QCryptographicHash &hash) const
|
||||
{
|
||||
int len = uri.length();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(uri.constData()), len * sizeof(QChar));
|
||||
version.addToHash(hash);
|
||||
len = cppName.length();
|
||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
hash.addData(reinterpret_cast<const char *>(cppName.constData()), len * sizeof(QChar));
|
||||
}
|
||||
|
||||
@@ -39,11 +39,13 @@
|
||||
#include "parser/qmljsengine_p.h"
|
||||
#include "qmljs_global.h"
|
||||
#include "qmljsconstants.h"
|
||||
#include "qmljsimportdependencies.h"
|
||||
|
||||
namespace QmlJS {
|
||||
|
||||
class Bind;
|
||||
class Snapshot;
|
||||
class ImportDependencies;
|
||||
|
||||
class QMLJS_EXPORT Document
|
||||
{
|
||||
@@ -69,6 +71,8 @@ public:
|
||||
Language::Enum language() const;
|
||||
void setLanguage(Language::Enum l);
|
||||
|
||||
QString importId() const;
|
||||
QByteArray fingerprint() const;
|
||||
AST::UiProgram *qmlProgram() const;
|
||||
AST::Program *jsProgram() const;
|
||||
AST::ExpressionNode *expression() const;
|
||||
@@ -111,6 +115,7 @@ private:
|
||||
QString _componentName;
|
||||
QString _source;
|
||||
QWeakPointer<Document> _ptr;
|
||||
QByteArray _fingerprint;
|
||||
int _editorRevision;
|
||||
Language::Enum _language;
|
||||
bool _parsedCorrectly;
|
||||
@@ -125,6 +130,8 @@ public:
|
||||
QString uri;
|
||||
LanguageUtils::ComponentVersion version;
|
||||
QString cppName;
|
||||
|
||||
void addToHash(QCryptographicHash &hash) const;
|
||||
};
|
||||
|
||||
class QMLJS_EXPORT LibraryInfo
|
||||
@@ -152,15 +159,21 @@ private:
|
||||
typedef QList<LanguageUtils::FakeMetaObject::ConstPtr> FakeMetaObjectList;
|
||||
FakeMetaObjectList _metaObjects;
|
||||
QList<ModuleApiInfo> _moduleApis;
|
||||
QByteArray _fingerprint;
|
||||
|
||||
PluginTypeInfoStatus _dumpStatus;
|
||||
QString _dumpError;
|
||||
|
||||
public:
|
||||
explicit LibraryInfo(Status status = NotScanned);
|
||||
explicit LibraryInfo(const QmlDirParser &parser);
|
||||
explicit LibraryInfo(const QmlDirParser &parser, const QByteArray &fingerprint = QByteArray());
|
||||
~LibraryInfo();
|
||||
|
||||
QByteArray calculateFingerprint() const;
|
||||
void updateFingerprint();
|
||||
QByteArray fingerprint() const
|
||||
{ return _fingerprint; }
|
||||
|
||||
QList<QmlDirParser::Component> components() const
|
||||
{ return _components; }
|
||||
|
||||
@@ -188,6 +201,9 @@ public:
|
||||
bool wasScanned() const
|
||||
{ return _status != NotScanned; }
|
||||
|
||||
bool wasFound() const
|
||||
{ return _status != NotFound; }
|
||||
|
||||
PluginTypeInfoStatus pluginTypeInfoStatus() const
|
||||
{ return _dumpStatus; }
|
||||
|
||||
@@ -204,9 +220,11 @@ class QMLJS_EXPORT Snapshot
|
||||
QHash<QString, Document::Ptr> _documents;
|
||||
QHash<QString, QList<Document::Ptr> > _documentsByPath;
|
||||
QHash<QString, LibraryInfo> _libraries;
|
||||
ImportDependencies _dependencies;
|
||||
|
||||
public:
|
||||
Snapshot();
|
||||
Snapshot(const Snapshot &o);
|
||||
~Snapshot();
|
||||
|
||||
typedef _Base::iterator iterator;
|
||||
@@ -219,6 +237,9 @@ public:
|
||||
void insertLibraryInfo(const QString &path, const LibraryInfo &info);
|
||||
void remove(const QString &fileName);
|
||||
|
||||
const ImportDependencies *importDependencies() const;
|
||||
ImportDependencies *importDependencies();
|
||||
|
||||
Document::Ptr document(const QString &fileName) const;
|
||||
QList<Document::Ptr> documentsInDirectory(const QString &path) const;
|
||||
LibraryInfo libraryInfo(const QString &path) const;
|
||||
|
||||
931
src/libs/qmljs/qmljsimportdependencies.cpp
Normal file
@@ -0,0 +1,931 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmljsimportdependencies.h"
|
||||
#include "qmljsinterpreter.h"
|
||||
#include "qmljsqrcparser.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/function.h>
|
||||
|
||||
#include <QCryptographicHash>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace QmlJS {
|
||||
|
||||
static bool debugImportDependencies = false;
|
||||
|
||||
ImportKind::Enum toImportKind(ImportType::Enum type)
|
||||
{
|
||||
switch (type) {
|
||||
case ImportType::Invalid:
|
||||
break;
|
||||
case ImportType::Library:
|
||||
return ImportKind::Library;
|
||||
case ImportType::ImplicitDirectory:
|
||||
case ImportType::File:
|
||||
case ImportType::Directory:
|
||||
case ImportType::UnknownFile:
|
||||
return ImportKind::Path;
|
||||
case ImportType::QrcFile:
|
||||
case ImportType::QrcDirectory:
|
||||
return ImportKind::QrcPath;
|
||||
}
|
||||
return ImportKind::Invalid;
|
||||
}
|
||||
|
||||
ImportMatchStrength::ImportMatchStrength(QList<int> match)
|
||||
: m_match(match)
|
||||
{ }
|
||||
|
||||
int ImportMatchStrength::compareMatch(const ImportMatchStrength &o) const
|
||||
{
|
||||
int len1 = m_match.size();
|
||||
int len2 = o.m_match.size();
|
||||
int len = ((len1 < len2) ? len1 : len2);
|
||||
for (int i = 0; i < len; ++ i) {
|
||||
int v1 = m_match.at(i);
|
||||
int v2 = o.m_match.at(i);
|
||||
if (v1 < v2)
|
||||
return -1;
|
||||
if (v2 > v1)
|
||||
return 1;
|
||||
}
|
||||
if (len1 < len2)
|
||||
return -1;
|
||||
if (len1 > len2)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ImportMatchStrength::hasNoMatch()
|
||||
{
|
||||
return m_match.isEmpty();
|
||||
}
|
||||
|
||||
bool ImportMatchStrength::hasMatch()
|
||||
{
|
||||
return !m_match.isEmpty();
|
||||
}
|
||||
|
||||
bool operator ==(const ImportMatchStrength &m1, const ImportMatchStrength &m2)
|
||||
{
|
||||
return m1.m_match == m2.m_match;
|
||||
}
|
||||
|
||||
bool operator !=(const ImportMatchStrength &m1, const ImportMatchStrength &m2)
|
||||
{
|
||||
return !(m1 == m2);
|
||||
}
|
||||
|
||||
bool operator <(const ImportMatchStrength &m1, const ImportMatchStrength &m2)
|
||||
{
|
||||
return m1.compareMatch(m2) < 0;
|
||||
}
|
||||
|
||||
ImportKey::ImportKey()
|
||||
: type(ImportType::Invalid),
|
||||
majorVersion(LanguageUtils::ComponentVersion::NoVersion),
|
||||
minorVersion(LanguageUtils::ComponentVersion::NoVersion)
|
||||
{ }
|
||||
|
||||
ImportKey::ImportKey(const ImportInfo &info)
|
||||
: type(info.type())
|
||||
, majorVersion(info.version().majorVersion())
|
||||
, minorVersion(info.version().minorVersion())
|
||||
{
|
||||
splitPath = QFileInfo(info.path()).canonicalFilePath().split(QLatin1Char('/'),
|
||||
QString::KeepEmptyParts);
|
||||
}
|
||||
|
||||
ImportKey::ImportKey(ImportType::Enum type, const QString &path, int majorVersion, int minorVersion)
|
||||
: type(type)
|
||||
, majorVersion(majorVersion)
|
||||
, minorVersion(minorVersion)
|
||||
{
|
||||
switch (type) {
|
||||
case ImportType::Library:
|
||||
splitPath = path.split(QLatin1Char('.'));
|
||||
break;
|
||||
case ImportType::ImplicitDirectory:
|
||||
case ImportType::Directory:
|
||||
splitPath = path.split(QLatin1Char('/'));
|
||||
if (splitPath.length() > 1 && splitPath.last().isEmpty())
|
||||
splitPath.removeLast();
|
||||
break;
|
||||
case ImportType::File:
|
||||
case ImportType::QrcFile:
|
||||
splitPath = QrcParser::normalizedQrcFilePath(path).split(QLatin1Char('/'));
|
||||
break;
|
||||
case ImportType::QrcDirectory:
|
||||
splitPath = QrcParser::normalizedQrcDirectoryPath(path).split(QLatin1Char('/'));
|
||||
if (splitPath.length() > 1 && splitPath.last().isEmpty())
|
||||
splitPath.removeLast();
|
||||
break;
|
||||
case ImportType::Invalid:
|
||||
case ImportType::UnknownFile:
|
||||
splitPath = path.split(QLatin1Char('/'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ImportKey::addToHash(QCryptographicHash &hash) const
|
||||
{
|
||||
hash.addData(reinterpret_cast<const char *>(&type), sizeof(type));
|
||||
hash.addData(reinterpret_cast<const char *>(&majorVersion), sizeof(majorVersion));
|
||||
hash.addData(reinterpret_cast<const char *>(&minorVersion), sizeof(minorVersion));
|
||||
foreach (const QString &s, splitPath) {
|
||||
hash.addData("/", 1);
|
||||
hash.addData(reinterpret_cast<const char *>(s.constData()), sizeof(QChar) * s.size());
|
||||
}
|
||||
hash.addData("/", 1);
|
||||
}
|
||||
|
||||
ImportKey ImportKey::flatKey() const {
|
||||
switch (type) {
|
||||
case ImportType::Invalid:
|
||||
return *this;
|
||||
case ImportType::ImplicitDirectory:
|
||||
case ImportType::Library:
|
||||
case ImportType::File:
|
||||
case ImportType::Directory:
|
||||
case ImportType::QrcFile:
|
||||
case ImportType::QrcDirectory:
|
||||
case ImportType::UnknownFile:
|
||||
break;
|
||||
}
|
||||
QStringList flatPath = splitPath;
|
||||
int i = 0;
|
||||
while (i < flatPath.size()) {
|
||||
if (flatPath.at(i).startsWith(QLatin1Char('+')))
|
||||
flatPath.removeAt(i);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
if (flatPath.size() == splitPath.size())
|
||||
return *this;
|
||||
ImportKey res = *this;
|
||||
res.splitPath = flatPath;
|
||||
return res;
|
||||
}
|
||||
|
||||
QString ImportKey::path() const
|
||||
{
|
||||
QString res = splitPath.join(QString::fromLatin1("/"));
|
||||
if (res.isEmpty() && !splitPath.isEmpty())
|
||||
return QLatin1String("/");
|
||||
return res;
|
||||
}
|
||||
|
||||
ImportMatchStrength ImportKey::matchImport(const ImportKey &o, const ViewerContext &vContext) const
|
||||
{
|
||||
if (majorVersion != o.majorVersion || minorVersion > o.minorVersion)
|
||||
return ImportMatchStrength();
|
||||
bool dirToFile = false;
|
||||
switch (o.type) {
|
||||
case ImportType::Invalid:
|
||||
return ImportMatchStrength();
|
||||
case ImportType::ImplicitDirectory:
|
||||
case ImportType::Directory:
|
||||
switch (type) {
|
||||
case ImportType::File:
|
||||
case ImportType::UnknownFile:
|
||||
dirToFile = true;
|
||||
break;
|
||||
case ImportType::ImplicitDirectory:
|
||||
case ImportType::Directory:
|
||||
break;
|
||||
default:
|
||||
return ImportMatchStrength();
|
||||
}
|
||||
break;
|
||||
case ImportType::Library:
|
||||
if (type != ImportType::Library)
|
||||
return ImportMatchStrength();
|
||||
break;
|
||||
case ImportType::QrcDirectory:
|
||||
switch (type) {
|
||||
case ImportType::QrcFile:
|
||||
dirToFile = true;
|
||||
break;
|
||||
case ImportType::QrcDirectory:
|
||||
break;
|
||||
default:
|
||||
return ImportMatchStrength();
|
||||
}
|
||||
break;
|
||||
case ImportType::QrcFile:
|
||||
if (type != ImportType::QrcFile)
|
||||
return ImportMatchStrength();
|
||||
case ImportType::UnknownFile:
|
||||
case ImportType::File:
|
||||
switch (type) {
|
||||
case ImportType::UnknownFile:
|
||||
case ImportType::File:
|
||||
break;
|
||||
default:
|
||||
return ImportMatchStrength();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
QList<int> res;
|
||||
int iPath1 = 0;
|
||||
int lenPath1 = splitPath.size();
|
||||
int iPath2 = 0;
|
||||
int lenPath2 = o.splitPath.size();
|
||||
if (dirToFile)
|
||||
--lenPath1;
|
||||
int iSelector = 0;
|
||||
int nSelectors = vContext.selectors.size();
|
||||
while (iPath1 < lenPath1) {
|
||||
if (lenPath2 - iPath2 > lenPath1 - iPath1)
|
||||
return ImportMatchStrength();
|
||||
QString p1 = splitPath.at(iPath1);
|
||||
if (iPath2 < lenPath2) {
|
||||
QString p2 = splitPath.at(iPath2);
|
||||
if (p1 == p2) {
|
||||
++iPath1;
|
||||
++iPath2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!p1.startsWith(QLatin1Char('+')))
|
||||
return QList<int>();
|
||||
QStringRef selectorAtt(&p1, 1, p1.size()-1);
|
||||
while (iSelector < nSelectors) {
|
||||
if (selectorAtt == vContext.selectors.at(iSelector))
|
||||
break;
|
||||
++iSelector;
|
||||
}
|
||||
if (iSelector == nSelectors)
|
||||
return QList<int>();
|
||||
res << (nSelectors - iSelector);
|
||||
++iSelector;
|
||||
++iPath1;
|
||||
}
|
||||
if (iPath2 != lenPath2)
|
||||
return QList<int>();
|
||||
if (res.isEmpty())
|
||||
res << 0;
|
||||
return ImportMatchStrength(res);
|
||||
}
|
||||
|
||||
int ImportKey::compare(const ImportKey &other) const
|
||||
{
|
||||
ImportKind::Enum k1 = toImportKind(type);
|
||||
ImportKind::Enum k2 = toImportKind(other.type);
|
||||
if (k1 < k2)
|
||||
return -1;
|
||||
if (k1 > k2)
|
||||
return 1;
|
||||
int len1 = splitPath.size();
|
||||
int len2 = other.splitPath.size();
|
||||
int len = ((len1 < len2) ? len1 : len2);
|
||||
for (int i = 0; i < len; ++ i) {
|
||||
QString v1 = splitPath.at(i);
|
||||
QString v2 = other.splitPath.at(i);
|
||||
if (v1 < v2)
|
||||
return -1;
|
||||
if (v2 > v1)
|
||||
return 1;
|
||||
}
|
||||
if (len1 < len2)
|
||||
return -1;
|
||||
if (len1 > len2)
|
||||
return 1;
|
||||
if (majorVersion < other.majorVersion)
|
||||
return -1;
|
||||
if (majorVersion > other.majorVersion)
|
||||
return 1;
|
||||
if (minorVersion < other.minorVersion)
|
||||
return -1;
|
||||
if (minorVersion > other.minorVersion)
|
||||
return 1;
|
||||
if (type < other.type)
|
||||
return -1;
|
||||
if (type > other.type)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ImportKey::isDirectoryLike() const
|
||||
{
|
||||
switch (type) {
|
||||
case ImportType::Directory:
|
||||
case ImportType::ImplicitDirectory:
|
||||
case ImportType::QrcDirectory:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ImportKey::DirCompareInfo ImportKey::compareDir(const ImportKey &superDir) const
|
||||
{
|
||||
// assumes dir/+selectors/file (i.e. no directories inside selectors)
|
||||
switch (superDir.type) {
|
||||
case ImportType::UnknownFile:
|
||||
case ImportType::File:
|
||||
case ImportType::Directory:
|
||||
case ImportType::ImplicitDirectory:
|
||||
if (type != ImportType::File && type != ImportType::ImplicitDirectory
|
||||
&& type != ImportType::Directory && type != ImportType::UnknownFile)
|
||||
return Incompatible;
|
||||
break;
|
||||
case ImportType::QrcDirectory:
|
||||
case ImportType::QrcFile:
|
||||
if (type != ImportType::QrcDirectory && type != ImportType::QrcFile)
|
||||
return Incompatible;
|
||||
break;
|
||||
case ImportType::Invalid:
|
||||
case ImportType::Library:
|
||||
return Incompatible;
|
||||
}
|
||||
bool isDir1 = isDirectoryLike();
|
||||
bool isDir2 = superDir.isDirectoryLike();
|
||||
int len1 = splitPath.size();
|
||||
int len2 = superDir.splitPath.size();
|
||||
if (isDir1 && len1 > 0)
|
||||
--len1;
|
||||
if (isDir2 && len2 > 0)
|
||||
--len2;
|
||||
|
||||
int i1 = 0;
|
||||
int i2 = 0;
|
||||
while (i1 < len1 && i2 < len2) {
|
||||
QString p1 = splitPath.at(i1);
|
||||
QString p2 = superDir.splitPath.at(i2);
|
||||
if (p1 == p2) {
|
||||
++i1;
|
||||
++i2;
|
||||
continue;
|
||||
}
|
||||
if (p1.startsWith(QLatin1Char('+'))) {
|
||||
if (p2.startsWith(QLatin1Char('+')))
|
||||
return SameDir;
|
||||
return SecondInFirst;
|
||||
}
|
||||
if (p2.startsWith(QLatin1Char('+')))
|
||||
return FirstInSecond;
|
||||
return Different;
|
||||
}
|
||||
if (i1 < len1) {
|
||||
if (splitPath.at(i1).startsWith(QLatin1Char('+')))
|
||||
return SameDir;
|
||||
return SecondInFirst;
|
||||
}
|
||||
if (i2 < len2) {
|
||||
if (superDir.splitPath.at(i2).startsWith(QLatin1Char('+')))
|
||||
return SameDir;
|
||||
return SecondInFirst;
|
||||
}
|
||||
return SameDir;
|
||||
}
|
||||
|
||||
QString ImportKey::toString() const
|
||||
{
|
||||
QString res;
|
||||
switch (type) {
|
||||
case ImportType::UnknownFile:
|
||||
case ImportType::File:
|
||||
res = path();
|
||||
break;
|
||||
case ImportType::Directory:
|
||||
case ImportType::ImplicitDirectory:
|
||||
res = path() + QLatin1Char('/');
|
||||
break;
|
||||
case ImportType::QrcDirectory:
|
||||
res = QLatin1String("qrc:") + path() + QLatin1Char('/');
|
||||
break;
|
||||
case ImportType::QrcFile:
|
||||
res = QLatin1String("qrc:") + path() + QLatin1Char('/');
|
||||
break;
|
||||
case ImportType::Invalid:
|
||||
res = path();
|
||||
break;
|
||||
case ImportType::Library:
|
||||
res = splitPath.join(QLatin1String("."));
|
||||
break;
|
||||
}
|
||||
|
||||
if (majorVersion != LanguageUtils::ComponentVersion::NoVersion
|
||||
|| minorVersion != LanguageUtils::ComponentVersion::NoVersion)
|
||||
return res + QLatin1Char(' ') + QString::number(majorVersion)
|
||||
+ QLatin1Char('.') + QString::number(minorVersion);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
uint qHash(const ImportKey &info)
|
||||
{
|
||||
uint res = ::qHash(info.type) ^
|
||||
::qHash(info.majorVersion) ^ ::qHash(info.minorVersion);
|
||||
foreach (const QString &s, info.splitPath)
|
||||
res = res ^ ::qHash(s);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool operator==(const ImportKey &i1, const ImportKey &i2)
|
||||
{
|
||||
return i1.type == i2.type
|
||||
&& i1.splitPath == i2.splitPath
|
||||
&& i1.majorVersion == i2.majorVersion
|
||||
&& i1.minorVersion == i2.minorVersion;
|
||||
}
|
||||
|
||||
bool operator !=(const ImportKey &i1, const ImportKey &i2)
|
||||
{
|
||||
return ! (i1 == i2);
|
||||
}
|
||||
|
||||
bool operator <(const ImportKey &i1, const ImportKey &i2)
|
||||
{
|
||||
return i1.compare(i2) < 0;
|
||||
}
|
||||
|
||||
Export::Export()
|
||||
: intrinsic(false)
|
||||
{ }
|
||||
|
||||
Export::Export(ImportKey exportName, QString pathRequired, bool intrinsic)
|
||||
: exportName(exportName), pathRequired(pathRequired), intrinsic(intrinsic)
|
||||
{ }
|
||||
|
||||
bool Export::visibleInVContext(const ViewerContext &vContext) const
|
||||
{
|
||||
return pathRequired.isEmpty() || vContext.paths.contains(pathRequired);
|
||||
}
|
||||
|
||||
bool operator ==(const Export &i1, const Export &i2)
|
||||
{
|
||||
return i1.exportName == i2.exportName
|
||||
&& i1.pathRequired == i2.pathRequired
|
||||
&& i1.intrinsic == i2.intrinsic;
|
||||
}
|
||||
|
||||
bool operator !=(const Export &i1, const Export &i2)
|
||||
{
|
||||
return !(i1 == i2);
|
||||
}
|
||||
|
||||
CoreImport::CoreImport() : language(Language::Qml) { }
|
||||
|
||||
CoreImport::CoreImport(const QString &importId, const QList<Export> &possibleExports,
|
||||
Language::Enum language, const QByteArray &fingerprint)
|
||||
: importId(importId), possibleExports(possibleExports), language(language),
|
||||
fingerprint(fingerprint)
|
||||
{ }
|
||||
|
||||
bool CoreImport::valid() {
|
||||
return !fingerprint.isEmpty();
|
||||
}
|
||||
|
||||
QByteArray DependencyInfo::calculateFingerprint(const ImportDependencies &deps)
|
||||
{
|
||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||
rootImport.addToHash(hash);
|
||||
QStringList coreImports = allCoreImports.toList();
|
||||
coreImports.sort();
|
||||
foreach (const QString importId, coreImports) {
|
||||
hash.addData(reinterpret_cast<const char*>(importId.constData()), importId.size() * sizeof(QChar));
|
||||
QByteArray coreImportFingerprint = deps.coreImport(importId).fingerprint;
|
||||
hash.addData(coreImportFingerprint);
|
||||
}
|
||||
hash.addData("/", 1);
|
||||
QList<ImportKey> imports(allImports.toList());
|
||||
std::sort(imports.begin(), imports.end());
|
||||
foreach (const ImportKey &k, imports)
|
||||
k.addToHash(hash);
|
||||
return hash.result();
|
||||
}
|
||||
|
||||
MatchedImport::MatchedImport()
|
||||
{ }
|
||||
|
||||
MatchedImport::MatchedImport(ImportMatchStrength matchStrength, ImportKey importKey,
|
||||
const QString &coreImportId)
|
||||
: matchStrength(matchStrength), importKey(importKey), coreImportId(coreImportId)
|
||||
{ }
|
||||
|
||||
int MatchedImport::compare(const MatchedImport &o) const {
|
||||
int res = matchStrength.compareMatch(o.matchStrength);
|
||||
if (res != 0)
|
||||
return res;
|
||||
res = importKey.compare(o.importKey);
|
||||
if (res != 0)
|
||||
return res;
|
||||
if (coreImportId < o.coreImportId)
|
||||
return -1;
|
||||
if (coreImportId > o.coreImportId)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool operator ==(const MatchedImport &m1, const MatchedImport &m2)
|
||||
{
|
||||
return m1.compare(m2) == 0;
|
||||
}
|
||||
|
||||
bool operator !=(const MatchedImport &m1, const MatchedImport &m2)
|
||||
{
|
||||
return m1.compare(m2) != 0;
|
||||
}
|
||||
|
||||
bool operator <(const MatchedImport &m1, const MatchedImport &m2)
|
||||
{
|
||||
return m1.compare(m2) < 0;
|
||||
}
|
||||
|
||||
ImportDependencies::ImportDependencies()
|
||||
{ }
|
||||
|
||||
ImportDependencies::~ImportDependencies()
|
||||
{ }
|
||||
|
||||
void ImportDependencies::filter(const ViewerContext &vContext)
|
||||
{
|
||||
QMap<QString, CoreImport> newCoreImports;
|
||||
QMap<ImportKey, QStringList> newImportCache;
|
||||
QMapIterator<QString, CoreImport> j(m_coreImports);
|
||||
bool hasChanges = false;
|
||||
while (j.hasNext()) {
|
||||
j.next();
|
||||
const CoreImport &cImport = j.value();
|
||||
if (vContext.languageIsCompatible(cImport.language)) {
|
||||
QList<Export> newExports;
|
||||
foreach (const Export &e, cImport.possibleExports) {
|
||||
if (e.visibleInVContext(vContext)) {
|
||||
newExports.append(e);
|
||||
QStringList &candidateImports = newImportCache[e.exportName];
|
||||
if (!candidateImports.contains(cImport.importId))
|
||||
candidateImports.append(cImport.importId);
|
||||
}
|
||||
}
|
||||
if (newExports.size() == cImport.possibleExports.size()) {
|
||||
newCoreImports.insert(cImport.importId, cImport);
|
||||
} else if (newExports.length() > 0) {
|
||||
CoreImport newCImport = cImport;
|
||||
newCImport.possibleExports = newExports;
|
||||
newCoreImports.insert(newCImport.importId, newCImport);
|
||||
hasChanges = true;
|
||||
} else {
|
||||
hasChanges = true;
|
||||
}
|
||||
} else {
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
if (!hasChanges)
|
||||
return;
|
||||
m_coreImports = newCoreImports;
|
||||
m_importCache = newImportCache;
|
||||
}
|
||||
|
||||
CoreImport ImportDependencies::coreImport(const QString &importId) const
|
||||
{
|
||||
return m_coreImports.value(importId);
|
||||
}
|
||||
|
||||
void ImportDependencies::iterateOnCandidateImports(
|
||||
const ImportKey &key, const ViewerContext &vContext,
|
||||
Utils::function<bool (const ImportMatchStrength &,const Export &,const CoreImport &)>
|
||||
const &iterF) const
|
||||
{
|
||||
switch (key.type) {
|
||||
case ImportType::Directory:
|
||||
case ImportType::QrcDirectory:
|
||||
case ImportType::ImplicitDirectory:
|
||||
break;
|
||||
default:
|
||||
{
|
||||
QStringList imp = m_importCache.value(key.flatKey());
|
||||
foreach (const QString &cImportName, imp) {
|
||||
CoreImport cImport = coreImport(cImportName);
|
||||
if (vContext.languageIsCompatible(cImport.language)) {
|
||||
foreach (const Export e, cImport.possibleExports) {
|
||||
if (e.visibleInVContext(vContext)) {
|
||||
ImportMatchStrength m = e.exportName.matchImport(key, vContext);
|
||||
if (m.hasMatch()) {
|
||||
if (!iterF(m, e, cImport))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
QMap<ImportKey, QStringList>::const_iterator lb = m_importCache.lowerBound(key.flatKey());
|
||||
QMap<ImportKey, QStringList>::const_iterator end = m_importCache.constEnd();
|
||||
while (lb != end) {
|
||||
ImportKey::DirCompareInfo c = key.compareDir(lb.key());
|
||||
if (c == ImportKey::SameDir) {
|
||||
foreach (const QString &cImportName, lb.value()) {
|
||||
CoreImport cImport = coreImport(cImportName);
|
||||
if (vContext.languageIsCompatible(cImport.language)) {
|
||||
foreach (const Export e, cImport.possibleExports) {
|
||||
if (e.visibleInVContext(vContext)) {
|
||||
ImportMatchStrength m = e.exportName.matchImport(key, vContext);
|
||||
if (m.hasMatch()) {
|
||||
if (!iterF(m, e, cImport))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (c != ImportKey::SecondInFirst) {
|
||||
break;
|
||||
}
|
||||
++lb;
|
||||
}
|
||||
}
|
||||
|
||||
class CollectCandidateImports
|
||||
{
|
||||
public:
|
||||
ImportDependencies::ImportElements &res;
|
||||
|
||||
CollectCandidateImports(ImportDependencies::ImportElements & res)
|
||||
: res(res)
|
||||
{ }
|
||||
|
||||
bool operator ()(const ImportMatchStrength &m, const Export &e, const CoreImport &cI) const
|
||||
{
|
||||
ImportKey flatName = e.exportName.flatKey();
|
||||
res[flatName].append(MatchedImport(m, e.exportName, cI.importId));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
ImportDependencies::ImportElements ImportDependencies::candidateImports(
|
||||
const ImportKey &key,
|
||||
const ViewerContext &vContext) const
|
||||
{
|
||||
ImportDependencies::ImportElements res;
|
||||
CollectCandidateImports collector(res);
|
||||
iterateOnCandidateImports(key, vContext, collector);
|
||||
typedef QMap<ImportKey, QList<MatchedImport> >::iterator iter_t;
|
||||
iter_t i = res.begin();
|
||||
iter_t end = res.end();
|
||||
while (i != end) {
|
||||
std::sort(i.value().begin(), i.value().end());
|
||||
++i;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
QList<DependencyInfo::ConstPtr> ImportDependencies::createDependencyInfos(
|
||||
const ImportKey &mainDoc, const ViewerContext &vContext) const
|
||||
{
|
||||
Q_UNUSED(mainDoc);
|
||||
Q_UNUSED(vContext);
|
||||
QList<DependencyInfo::ConstPtr> res;
|
||||
QTC_CHECK(false);
|
||||
return res;
|
||||
}
|
||||
|
||||
void ImportDependencies::addCoreImport(const CoreImport &import)
|
||||
{
|
||||
CoreImport newImport = import;
|
||||
if (m_coreImports.contains(import.importId)) {
|
||||
CoreImport oldVal = m_coreImports.value(import.importId);
|
||||
foreach (const Export &e, oldVal.possibleExports) {
|
||||
if (e.intrinsic)
|
||||
removeImportCacheEntry(e.exportName, import.importId);
|
||||
else
|
||||
newImport.possibleExports.append(e);
|
||||
}
|
||||
}
|
||||
foreach (const Export &e, import.possibleExports)
|
||||
m_importCache[e.exportName].append(import.importId);
|
||||
m_coreImports.insert(newImport.importId, newImport);
|
||||
if (debugImportDependencies) {
|
||||
QDebug dbg(qDebug());
|
||||
dbg << "added import "<< newImport.importId << " for";
|
||||
foreach (const Export &e, newImport.possibleExports)
|
||||
dbg << " " << e.exportName.toString() << "(" << e.pathRequired << ")";
|
||||
}
|
||||
}
|
||||
|
||||
void ImportDependencies::removeCoreImport(const QString &importId)
|
||||
{
|
||||
if (!m_coreImports.contains(importId)) {
|
||||
qDebug() << "missing importId in removeCoreImport(" << importId << ")";
|
||||
return;
|
||||
}
|
||||
CoreImport &cImport = m_coreImports[importId];
|
||||
QList<Export> newExports;
|
||||
foreach (const Export &e, cImport.possibleExports)
|
||||
if (e.intrinsic)
|
||||
removeImportCacheEntry(e.exportName, importId);
|
||||
else
|
||||
newExports.append(e);
|
||||
if (newExports.size()>0)
|
||||
cImport.possibleExports = newExports;
|
||||
else
|
||||
m_coreImports.remove(importId);
|
||||
|
||||
if (debugImportDependencies)
|
||||
qDebug() << "removed import with id:"<< importId;
|
||||
}
|
||||
|
||||
void ImportDependencies::removeImportCacheEntry(const ImportKey &importKey, const QString &importId)
|
||||
{
|
||||
QStringList &cImp = m_importCache[importKey];
|
||||
if (!cImp.removeOne(importId)) {
|
||||
qDebug() << "missing possibleExport backpointer for " << importKey.toString() << " to "
|
||||
<< importId;
|
||||
}
|
||||
if (cImp.isEmpty())
|
||||
m_importCache.remove(importKey);
|
||||
}
|
||||
|
||||
void ImportDependencies::addExport(const QString &importId, const ImportKey &importKey,
|
||||
const QString &requiredPath)
|
||||
{
|
||||
if (!m_coreImports.contains(importId)) {
|
||||
CoreImport newImport(importId);
|
||||
newImport.language = Language::Unknown;
|
||||
newImport.possibleExports.append(Export(importKey, requiredPath, false));
|
||||
m_coreImports.insert(newImport.importId, newImport);
|
||||
m_importCache[importKey].append(importId);
|
||||
return;
|
||||
}
|
||||
CoreImport &importValue = m_coreImports[importId];
|
||||
importValue.possibleExports.append(Export(importKey, requiredPath, false));
|
||||
m_importCache[importKey].append(importId);
|
||||
if (debugImportDependencies)
|
||||
qDebug() << "added export "<< importKey.toString() << " for id " <<importId
|
||||
<< " (" << requiredPath << ")";
|
||||
}
|
||||
|
||||
void ImportDependencies::removeExport(const QString &importId, const ImportKey &importKey,
|
||||
const QString &requiredPath)
|
||||
{
|
||||
if (!m_coreImports.contains(importId)) {
|
||||
qDebug() << "non existing core import for removeExport(" << importId << ", "
|
||||
<< importKey.toString() << ")";
|
||||
} else {
|
||||
CoreImport &importValue = m_coreImports[importId];
|
||||
if (!importValue.possibleExports.removeOne(Export(importKey, requiredPath, false))) {
|
||||
qDebug() << "non existing export for removeExport(" << importId << ", "
|
||||
<< importKey.toString() << ")";
|
||||
}
|
||||
if (importValue.possibleExports.isEmpty() && importValue.fingerprint.isEmpty())
|
||||
m_coreImports.remove(importId);
|
||||
}
|
||||
if (!m_importCache.contains(importKey)) {
|
||||
qDebug() << "missing possibleExport for " << importKey.toString() << " when removing export of "
|
||||
<< importId;
|
||||
} else {
|
||||
removeImportCacheEntry(importKey, importId);
|
||||
}
|
||||
if (debugImportDependencies)
|
||||
qDebug() << "removed export "<< importKey.toString() << " for id " << importId
|
||||
<< " (" << requiredPath << ")";
|
||||
}
|
||||
|
||||
void ImportDependencies::iterateOnCoreImports(
|
||||
const ViewerContext &vContext,
|
||||
Utils::function<bool (const CoreImport &)> const &iterF) const
|
||||
{
|
||||
QMapIterator<QString, CoreImport> i(m_coreImports);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (vContext.languageIsCompatible(i.value().language))
|
||||
iterF(i.value()); // check also that at least one export is visible?
|
||||
}
|
||||
}
|
||||
|
||||
void ImportDependencies::iterateOnLibraryImports(
|
||||
const ViewerContext &vContext,
|
||||
Utils::function<bool (const ImportMatchStrength &,
|
||||
const Export &,
|
||||
const CoreImport &)> const &iterF) const
|
||||
{
|
||||
typedef QMap<ImportKey, QStringList>::const_iterator iter_t;
|
||||
ImportKey firstLib;
|
||||
firstLib.type = ImportType::Library;
|
||||
iter_t i = m_importCache.lowerBound(firstLib);
|
||||
iter_t end = m_importCache.constEnd();
|
||||
while (i != end && i.key().type == ImportType::Library) {
|
||||
if (debugImportDependencies)
|
||||
qDebug() << "libloop:" << i.key().toString() << i.value();
|
||||
foreach (const QString &cImportName, i.value()) {
|
||||
CoreImport cImport = coreImport(cImportName);
|
||||
if (vContext.languageIsCompatible(cImport.language)) {
|
||||
foreach (const Export &e, cImport.possibleExports) {
|
||||
if (e.visibleInVContext(vContext) && e.exportName.type == ImportType::Library) {
|
||||
ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext);
|
||||
if (m.hasMatch()) {
|
||||
if (debugImportDependencies)
|
||||
qDebug() << "import iterate:" << e.exportName.toString()
|
||||
<< " (" << e.pathRequired << "), id:" << cImport.importId;
|
||||
if (!iterF(m, e, cImport))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void ImportDependencies::iterateOnSubImports(
|
||||
const ImportKey &baseKey,
|
||||
const ViewerContext &vContext,
|
||||
Utils::function<bool (const ImportMatchStrength &,
|
||||
const Export &,
|
||||
const CoreImport &)> const &iterF) const
|
||||
{
|
||||
typedef QMap<ImportKey, QStringList>::const_iterator iter_t;
|
||||
iter_t i = m_importCache.lowerBound(baseKey);
|
||||
iter_t end = m_importCache.constEnd();
|
||||
while (i != end) {
|
||||
ImportKey::DirCompareInfo c = baseKey.compareDir(i.key());
|
||||
if (c != ImportKey::SameDir && c != ImportKey::SecondInFirst)
|
||||
break;
|
||||
foreach (const QString &cImportName, i.value()) {
|
||||
CoreImport cImport = coreImport(cImportName);
|
||||
if (vContext.languageIsCompatible(cImport.language)) {
|
||||
foreach (const Export &e, cImport.possibleExports) {
|
||||
if (e.visibleInVContext(vContext)) {
|
||||
ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext);
|
||||
if (m.hasMatch()) {
|
||||
if (!iterF(m, e, cImport))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
class CollectImportKeys {
|
||||
public:
|
||||
QSet<ImportKey> &imports;
|
||||
CollectImportKeys(QSet<ImportKey> &imports)
|
||||
: imports(imports)
|
||||
{ }
|
||||
bool operator()(const ImportMatchStrength &m,
|
||||
const Export &e,
|
||||
const CoreImport &cI) const
|
||||
{
|
||||
Q_UNUSED(m);
|
||||
Q_UNUSED(cI);
|
||||
imports.insert(e.exportName.flatKey());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
QSet<ImportKey> ImportDependencies::libraryImports(const ViewerContext &viewContext) const
|
||||
{
|
||||
QSet<ImportKey> res;
|
||||
CollectImportKeys importCollector(res);
|
||||
iterateOnLibraryImports(viewContext, importCollector);
|
||||
return res;
|
||||
}
|
||||
|
||||
QSet<ImportKey> ImportDependencies::subdirImports(
|
||||
const ImportKey &baseKey, const ViewerContext &viewContext) const
|
||||
{
|
||||
QSet<ImportKey> res;
|
||||
CollectImportKeys importCollector(res);
|
||||
iterateOnSubImports(baseKey, viewContext, importCollector);
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace QmlJS
|
||||
235
src/libs/qmljs/qmljsimportdependencies.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QMLJSIMPORTCACHE_H
|
||||
#define QMLJSIMPORTCACHE_H
|
||||
|
||||
#include "qmljsviewercontext.h"
|
||||
|
||||
#include <languageutils/componentversion.h>
|
||||
#include <utils/qtcoverride.h>
|
||||
#include <utils/function.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QSharedPointer>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QCryptographicHash;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace QmlJS {
|
||||
class ImportInfo;
|
||||
namespace Internal {
|
||||
class ImportDependenciesPrivate;
|
||||
}
|
||||
class ImportDependencies;
|
||||
|
||||
// match strenght wrt to the selectors of a ViewerContext
|
||||
// this is valid only within a ViewerContext
|
||||
class QMLJS_EXPORT ImportMatchStrength
|
||||
{
|
||||
public:
|
||||
explicit ImportMatchStrength() {}
|
||||
ImportMatchStrength(QList<int> match);
|
||||
|
||||
int compareMatch(const ImportMatchStrength &o) const;
|
||||
|
||||
bool hasNoMatch();
|
||||
|
||||
bool hasMatch();
|
||||
private:
|
||||
friend bool operator ==(const ImportMatchStrength &m1, const ImportMatchStrength &m2);
|
||||
QList<int> m_match;
|
||||
};
|
||||
bool operator ==(const ImportMatchStrength &m1, const ImportMatchStrength &m2);
|
||||
bool operator !=(const ImportMatchStrength &m1, const ImportMatchStrength &m2);
|
||||
bool operator <(const ImportMatchStrength &m1, const ImportMatchStrength &m2);
|
||||
|
||||
/*!
|
||||
* \brief The ImportKey class represent an import (or export), and can be used as hash key
|
||||
*
|
||||
* This represent only what is to be imported, *not* how (i.e. no as clause)
|
||||
*
|
||||
* Order is defined so that files in the same directory are contiguous, and different
|
||||
* ImportKind are separated.
|
||||
* This is used to efficiently iterate just on library imports, or just on a directory
|
||||
* while preserving space.
|
||||
*/
|
||||
class QMLJS_EXPORT ImportKey
|
||||
{
|
||||
public:
|
||||
enum DirCompareInfo {
|
||||
SameDir,
|
||||
FirstInSecond,
|
||||
SecondInFirst,
|
||||
Different,
|
||||
Incompatible
|
||||
};
|
||||
|
||||
explicit ImportKey();
|
||||
explicit ImportKey(const ImportInfo &info);
|
||||
ImportKey(ImportType::Enum type, const QString &path,
|
||||
int majorVersion = LanguageUtils::ComponentVersion::NoVersion,
|
||||
int minorVersion = LanguageUtils::ComponentVersion::NoVersion);
|
||||
|
||||
ImportType::Enum type;
|
||||
QStringList splitPath;
|
||||
int majorVersion;
|
||||
int minorVersion;
|
||||
|
||||
QString path() const;
|
||||
|
||||
void addToHash(QCryptographicHash &hash) const;
|
||||
ImportKey flatKey() const;
|
||||
|
||||
// wrap QList in a special type?
|
||||
ImportMatchStrength matchImport(const ImportKey &o, const ViewerContext &vContext) const;
|
||||
int compare(const ImportKey &other) const;
|
||||
bool isDirectoryLike() const;
|
||||
DirCompareInfo compareDir(const ImportKey &other) const;
|
||||
QString toString() const;
|
||||
};
|
||||
|
||||
uint qHash(const ImportKey &info);
|
||||
bool operator ==(const ImportKey &i1, const ImportKey &i2);
|
||||
bool operator !=(const ImportKey &i1, const ImportKey &i2);
|
||||
bool operator <(const ImportKey &i1, const ImportKey &i2);
|
||||
|
||||
class QMLJS_EXPORT Export
|
||||
{
|
||||
public:
|
||||
Export();
|
||||
Export(ImportKey exportName, QString pathRequired, bool intrinsic = false);
|
||||
ImportKey exportName;
|
||||
QString pathRequired;
|
||||
bool intrinsic;
|
||||
bool visibleInVContext(const ViewerContext &vContext) const;
|
||||
};
|
||||
bool operator ==(const Export &i1, const Export &i2);
|
||||
bool operator !=(const Export &i1, const Export &i2);
|
||||
|
||||
class QMLJS_EXPORT CoreImport
|
||||
{
|
||||
public:
|
||||
CoreImport();
|
||||
CoreImport(const QString &importId, const QList<Export> &possibleExports = QList<Export>(),
|
||||
Language::Enum language = Language::Qml, const QByteArray &fingerprint = QByteArray());
|
||||
QString importId;
|
||||
QList<Export> possibleExports;
|
||||
Language::Enum language;
|
||||
QByteArray fingerprint;
|
||||
bool valid();
|
||||
};
|
||||
|
||||
class QMLJS_EXPORT DependencyInfo
|
||||
{
|
||||
public:
|
||||
typedef QSharedPointer<const DependencyInfo> ConstPtr;
|
||||
typedef QSharedPointer<DependencyInfo> Ptr;
|
||||
|
||||
QByteArray calculateFingerprint(const ImportDependencies &deps);
|
||||
|
||||
ImportKey rootImport;
|
||||
QSet<QString> allCoreImports;
|
||||
QSet<ImportKey> allImports;
|
||||
QByteArray fingerprint;
|
||||
};
|
||||
|
||||
class QMLJS_EXPORT MatchedImport
|
||||
{
|
||||
public:
|
||||
MatchedImport();
|
||||
MatchedImport(ImportMatchStrength matchStrength, ImportKey importKey,
|
||||
const QString &coreImportId);
|
||||
|
||||
ImportMatchStrength matchStrength;
|
||||
ImportKey importKey;
|
||||
QString coreImportId;
|
||||
int compare(const MatchedImport &o) const;
|
||||
};
|
||||
bool operator ==(const MatchedImport &m1, const MatchedImport &m2);
|
||||
bool operator !=(const MatchedImport &m1, const MatchedImport &m2);
|
||||
bool operator <(const MatchedImport &m1, const MatchedImport &m2);
|
||||
|
||||
class QMLJS_EXPORT ImportDependencies
|
||||
{
|
||||
public:
|
||||
typedef QMap<ImportKey, QList<MatchedImport> > ImportElements;
|
||||
|
||||
explicit ImportDependencies();
|
||||
~ImportDependencies();
|
||||
|
||||
void filter(const ViewerContext &vContext);
|
||||
|
||||
CoreImport coreImport(const QString &importId) const;
|
||||
void iterateOnCandidateImports(const ImportKey &key, const ViewerContext &vContext,
|
||||
Utils::function<bool(const ImportMatchStrength &,
|
||||
const Export &,
|
||||
const CoreImport &)> const &iterF) const;
|
||||
ImportElements candidateImports(const ImportKey &key, const ViewerContext &vContext) const;
|
||||
|
||||
QList<DependencyInfo::ConstPtr> createDependencyInfos(const ImportKey &mainDoc,
|
||||
const ViewerContext &vContext) const;
|
||||
|
||||
void addCoreImport(const CoreImport &import);
|
||||
void removeCoreImport(const QString &importId);
|
||||
|
||||
void addExport(const QString &importId, const ImportKey &importKey,
|
||||
const QString &requiredPath);
|
||||
void removeExport(const QString &importId, const ImportKey &importKey,
|
||||
const QString &requiredPath);
|
||||
|
||||
void iterateOnCoreImports(const ViewerContext &vContext,
|
||||
Utils::function<bool(const CoreImport &)> const &iterF) const;
|
||||
void iterateOnLibraryImports(const ViewerContext &vContext,
|
||||
Utils::function<bool(const ImportMatchStrength &,
|
||||
const Export &,
|
||||
const CoreImport &)> const &iterF) const;
|
||||
void iterateOnSubImports(const ImportKey &baseKey, const ViewerContext &vContext,
|
||||
Utils::function<bool(const ImportMatchStrength &,
|
||||
const Export &,
|
||||
const CoreImport &)> const &iterF) const;
|
||||
|
||||
QSet<ImportKey> libraryImports(const ViewerContext &viewContext) const;
|
||||
QSet<ImportKey> subdirImports(const ImportKey &baseKey, const ViewerContext &viewContext) const;
|
||||
private:
|
||||
void removeImportCacheEntry(const ImportKey &importKey, const QString &importId);
|
||||
|
||||
QMap<ImportKey, QStringList> m_importCache;
|
||||
QMap<QString, CoreImport> m_coreImports;
|
||||
};
|
||||
|
||||
} // namespace QmlJS
|
||||
|
||||
#endif // QMLJSIMPORTCACHE_H
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
#include <qmljs/qmljs_global.h>
|
||||
#include <qmljs/qmljsconstants.h>
|
||||
#include <qmljs/qmljsimportdependencies.h>
|
||||
|
||||
#include <QFileInfoList>
|
||||
#include <QList>
|
||||
@@ -912,6 +913,7 @@ public:
|
||||
// const!
|
||||
ObjectValue *object;
|
||||
ImportInfo info;
|
||||
DependencyInfo::ConstPtr deps;
|
||||
// uri imports: path to library, else empty
|
||||
QString libraryPath;
|
||||
// whether the import succeeded
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
#include "qmljsbind.h"
|
||||
#include "qmljsutils.h"
|
||||
#include "qmljsmodelmanagerinterface.h"
|
||||
#include <qmljs/qmljsqrcparser.h>
|
||||
#include "qmljsqrcparser.h"
|
||||
#include "qmljsconstants.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
@@ -83,6 +84,7 @@ public:
|
||||
ValueOwner *valueOwner;
|
||||
QStringList importPaths;
|
||||
LibraryInfo builtins;
|
||||
ViewerContext vContext;
|
||||
|
||||
QHash<ImportCacheKey, Import> importCache;
|
||||
|
||||
@@ -131,13 +133,14 @@ public:
|
||||
\l{QmlJSEditor::SemanticInfo} of a \l{QmlJSEditor::QmlJSTextEditorWidget}.
|
||||
*/
|
||||
|
||||
Link::Link(const Snapshot &snapshot, const QStringList &importPaths, const LibraryInfo &builtins)
|
||||
Link::Link(const Snapshot &snapshot, const ViewerContext &vContext, const LibraryInfo &builtins)
|
||||
: d(new LinkPrivate)
|
||||
{
|
||||
d->valueOwner = new ValueOwner;
|
||||
d->snapshot = snapshot;
|
||||
d->importPaths = importPaths;
|
||||
d->importPaths = vContext.paths;
|
||||
d->builtins = builtins;
|
||||
d->vContext = vContext;
|
||||
|
||||
d->diagnosticMessages = 0;
|
||||
d->allDiagnosticMessages = 0;
|
||||
@@ -173,14 +176,14 @@ Link::Link(const Snapshot &snapshot, const QStringList &importPaths, const Libra
|
||||
ContextPtr Link::operator()(QHash<QString, QList<DiagnosticMessage> > *messages)
|
||||
{
|
||||
d->allDiagnosticMessages = messages;
|
||||
return Context::create(d->snapshot, d->valueOwner, d->linkImports());
|
||||
return Context::create(d->snapshot, d->valueOwner, d->linkImports(), d->vContext);
|
||||
}
|
||||
|
||||
ContextPtr Link::operator()(const Document::Ptr &doc, QList<DiagnosticMessage> *messages)
|
||||
{
|
||||
d->document = doc;
|
||||
d->diagnosticMessages = messages;
|
||||
return Context::create(d->snapshot, d->valueOwner, d->linkImports());
|
||||
return Context::create(d->snapshot, d->valueOwner, d->linkImports(), d->vContext);
|
||||
}
|
||||
|
||||
Link::~Link()
|
||||
|
||||
@@ -48,7 +48,7 @@ class QMLJS_EXPORT Link
|
||||
Q_DECLARE_TR_FUNCTIONS(QmlJS::Link)
|
||||
|
||||
public:
|
||||
Link(const Snapshot &snapshot, const QStringList &importPaths, const LibraryInfo &builtins);
|
||||
Link(const Snapshot &snapshot, const ViewerContext &vContext, const LibraryInfo &builtins);
|
||||
|
||||
// Link all documents in snapshot, collecting all diagnostic messages (if messages != 0)
|
||||
ContextPtr operator()(QHash<QString, QList<DiagnosticMessage> > *messages = 0);
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
#include "qmljs_global.h"
|
||||
#include "qmljsdocument.h"
|
||||
#include "qmljsbundle.h"
|
||||
|
||||
#include "qmljsconstants.h"
|
||||
#include "qmljsviewercontext.h"
|
||||
#include <utils/environment.h>
|
||||
|
||||
#include <QObject>
|
||||
@@ -175,6 +176,12 @@ public:
|
||||
|
||||
virtual LibraryInfo builtins(const Document::Ptr &doc) const = 0;
|
||||
|
||||
virtual ViewerContext completeVContext(const ViewerContext &vCtx,
|
||||
const Document::Ptr &doc = Document::Ptr(0)) const = 0;
|
||||
virtual ViewerContext defaultVContext(bool autoComplete = true,
|
||||
const Document::Ptr &doc = Document::Ptr(0)) const = 0;
|
||||
virtual void setDefaultVContext(const ViewerContext &vContext) = 0;
|
||||
|
||||
// Blocks until all parsing threads are done. Used for testing.
|
||||
virtual void joinAllThreads() = 0;
|
||||
|
||||
|
||||
@@ -223,6 +223,7 @@ void TypeDescriptionReader::readComponent(UiObjectDefinition *ast)
|
||||
|
||||
// ### add implicit export into the package of c++ types
|
||||
fmo->addExport(fmo->className(), QmlJS::CppQmlTypes::cppPackage, ComponentVersion());
|
||||
fmo->updateFingerprint();
|
||||
_objects->insert(fmo->className(), fmo);
|
||||
}
|
||||
|
||||
|
||||
79
src/libs/qmljs/qmljsviewercontext.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmljsviewercontext.h"
|
||||
|
||||
namespace QmlJS {
|
||||
/*!
|
||||
\class QmlJS::ViewerContext
|
||||
\brief The ViewerContext class encapsulate selector and paths for a given viewer.
|
||||
|
||||
Using a a different viewer context can emulate (the pure qml part) of a device.
|
||||
This allows checking how a given qml would be interpreted on another platform/viewer.
|
||||
|
||||
Screen information will also most likely need to be added here.
|
||||
*/
|
||||
ViewerContext::ViewerContext()
|
||||
: language(Language::Qml), flags(AddAllPaths)
|
||||
{ }
|
||||
|
||||
ViewerContext::ViewerContext(QStringList selectors, QStringList paths,
|
||||
QmlJS::Language::Enum language,
|
||||
QmlJS::ViewerContext::Flags flags)
|
||||
: selectors(selectors), paths(paths), language(language),
|
||||
flags(flags)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
which languages might be imported in this context
|
||||
*/
|
||||
bool ViewerContext::languageIsCompatible(Language::Enum l) const
|
||||
{
|
||||
switch (language) {
|
||||
case Language::JavaScript:
|
||||
case Language::Json:
|
||||
case Language::QmlProject:
|
||||
case Language::QmlQbs:
|
||||
case Language::QmlTypeInfo:
|
||||
return language == l;
|
||||
case Language::Qml:
|
||||
return l == Language::Qml || l == Language::QmlQtQuick1 || l == Language::QmlQtQuick2
|
||||
|| Language::JavaScript;
|
||||
case Language::QmlQtQuick1:
|
||||
return l == Language::Qml || l == Language::QmlQtQuick1 || Language::JavaScript;
|
||||
case Language::QmlQtQuick2:
|
||||
return l == Language::Qml || l == Language::QmlQtQuick2 || Language::JavaScript;
|
||||
case Language::Unknown: // ?
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace QmlJS
|
||||
63
src/libs/qmljs/qmljsviewercontext.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef VIEWERCONTEXT_H
|
||||
#define VIEWERCONTEXT_H
|
||||
|
||||
#include "qmljs_global.h"
|
||||
#include "qmljsconstants.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
namespace QmlJS {
|
||||
|
||||
class QMLJS_EXPORT ViewerContext
|
||||
{
|
||||
public:
|
||||
enum Flags {
|
||||
Complete,
|
||||
AddAllPaths,
|
||||
AddQtPath
|
||||
};
|
||||
|
||||
ViewerContext();
|
||||
ViewerContext(QStringList selectors, QStringList paths,
|
||||
Language::Enum language = Language::Qml,
|
||||
Flags flags = AddAllPaths);
|
||||
|
||||
bool languageIsCompatible(Language::Enum l) const;
|
||||
|
||||
QStringList selectors;
|
||||
QStringList paths;
|
||||
Language::Enum language;
|
||||
Flags flags;
|
||||
};
|
||||
|
||||
} // namespace QmlJS
|
||||
#endif // VIEWERCONTEXT_H
|
||||
@@ -422,7 +422,7 @@ AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(ProjectExplorer::Proje
|
||||
return info;
|
||||
}
|
||||
|
||||
AndroidDeviceDialog dialog(apiLevel, abi);
|
||||
AndroidDeviceDialog dialog(apiLevel, abi, Core::ICore::mainWindow());
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
AndroidDeviceInfo info = dialog.device();
|
||||
if (dialog.saveDeviceSelection()) {
|
||||
@@ -496,9 +496,9 @@ QVector<AndroidDeviceInfo> AndroidConfigurations::connectedDevices(QString *erro
|
||||
return devices;
|
||||
}
|
||||
|
||||
QString AndroidConfigurations::createAVD(int minApiLevel, QString targetArch) const
|
||||
QString AndroidConfigurations::createAVD(QWidget *parent, int minApiLevel, QString targetArch) const
|
||||
{
|
||||
QDialog d;
|
||||
QDialog d(parent);
|
||||
Ui::AddNewAVDDialog avdDialog;
|
||||
avdDialog.setupUi(&d);
|
||||
// NOTE: adb list targets does actually include information on which abis are supported per apilevel
|
||||
|
||||
@@ -102,7 +102,7 @@ public:
|
||||
Utils::FileName zipalignPath() const;
|
||||
Utils::FileName stripPath(ProjectExplorer::Abi::Architecture architecture, const QString &ndkToolChainVersion) const;
|
||||
Utils::FileName readelfPath(ProjectExplorer::Abi::Architecture architecture, const QString &ndkToolChainVersion) const;
|
||||
QString createAVD(int minApiLevel = 0, QString targetArch = QString()) const;
|
||||
QString createAVD(QWidget *parent, int minApiLevel = 0, QString targetArch = QString()) const;
|
||||
QString createAVD(const QString &target, const QString &name, const QString &abi, int sdcardSize) const;
|
||||
bool removeAVD(const QString &name) const;
|
||||
QVector<AndroidDeviceInfo> connectedDevices(QString *error = 0) const;
|
||||
|
||||
@@ -388,7 +388,7 @@ bool AndroidDeployQtStep::fromMap(const QVariantMap &map)
|
||||
m_deployAction = AndroidDeployQtAction(map.value(QLatin1String(DeployActionKey),
|
||||
BundleLibrariesDeployment).toInt());
|
||||
m_keystorePath = Utils::FileName::fromString(map.value(KeystoreLocationKey).toString());
|
||||
m_signPackage = map.value(SignPackageKey).toBool();
|
||||
m_signPackage = false; // don't restore this
|
||||
m_buildTargetSdk = map.value(BuildTargetSdkKey).toString();
|
||||
m_verbose = map.value(VerboseOutputKey).toBool();
|
||||
m_inputFile = map.value(InputFile).toString();
|
||||
|
||||
@@ -82,9 +82,11 @@ AndroidDeployQtWidget::AndroidDeployQtWidget(AndroidDeployQtStep *step)
|
||||
}
|
||||
|
||||
// signing
|
||||
m_ui->signPackageCheckBox->setChecked(m_step->signPackage());
|
||||
m_ui->KeystoreLocationLineEdit->setText(m_step->keystorePath().toUserOutput());
|
||||
m_ui->signingDebugWarningIcon->hide();
|
||||
m_ui->signingDebugWarningLabel->hide();
|
||||
signPackageCheckBoxToggled(m_step->signPackage());
|
||||
|
||||
m_ui->verboseOutputCheckBox->setChecked(m_step->verboseOutput());
|
||||
m_ui->openPackageLocationCheckBox->setChecked(m_step->openPackageLocation());
|
||||
|
||||
@@ -446,7 +446,7 @@ void AndroidDeviceDialog::refreshDeviceList()
|
||||
|
||||
void AndroidDeviceDialog::createAvd()
|
||||
{
|
||||
QString avd = AndroidConfigurations::instance().createAVD(m_apiLevel, m_abi);
|
||||
QString avd = AndroidConfigurations::instance().createAVD(this, m_apiLevel, m_abi);
|
||||
if (avd.isEmpty())
|
||||
return;
|
||||
refreshDeviceList();
|
||||
|
||||
@@ -402,14 +402,16 @@ void AndroidSettingsWidget::browseOpenJDKLocation()
|
||||
|
||||
void AndroidSettingsWidget::addAVD()
|
||||
{
|
||||
AndroidConfigurations::instance().createAVD();
|
||||
AndroidConfigurations::instance().createAVD(this);
|
||||
m_AVDModel.setAvdList(AndroidConfigurations::instance().androidVirtualDevices());
|
||||
avdActivated(m_ui->AVDTableView->currentIndex());
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::removeAVD()
|
||||
{
|
||||
AndroidConfigurations::instance().removeAVD(m_AVDModel.avdName(m_ui->AVDTableView->currentIndex()));
|
||||
m_AVDModel.setAvdList(AndroidConfigurations::instance().androidVirtualDevices());
|
||||
avdActivated(m_ui->AVDTableView->currentIndex());
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::startAVD()
|
||||
|
||||
@@ -76,6 +76,7 @@ ChooseProFilePage::ChooseProFilePage(CreateAndroidManifestWizard *wizard, const
|
||||
foreach (QmakeProFileNode *node, nodes)
|
||||
m_comboBox->addItem(node->displayName(), QVariant::fromValue(static_cast<void *>(node))); // TODO something more?
|
||||
|
||||
nodeSelected(0);
|
||||
connect(m_comboBox, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(nodeSelected(int)));
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ DebuggerStartParameters BareMetalRunControlFactory::startParameters(const BareMe
|
||||
params.languages |= CppLanguage;
|
||||
params.processArgs = runConfig->arguments();
|
||||
params.startMode = AttachToRemoteServer;
|
||||
params.executable = Utils::HostOsInfo::withExecutableSuffix(runConfig->localExecutableFilePath());
|
||||
params.executable = runConfig->localExecutableFilePath();
|
||||
params.remoteSetupNeeded = false; //FIXME probably start debugserver with that, how?
|
||||
params.displayName = runConfig->displayName();
|
||||
if (const Project *project = target->project()) {
|
||||
|
||||
@@ -1551,7 +1551,7 @@ bool ClearCasePlugin::vcsOpen(const QString &workingDir, const QString &fileName
|
||||
QFile::rename(absPath + QLatin1String(".hijack"), absPath);
|
||||
}
|
||||
|
||||
if ((!response.error || response.stdOut.contains(QLatin1String("already checked out")))
|
||||
if ((!response.error || response.stdErr.contains(QLatin1String("already checked out")))
|
||||
&& !m_settings.disableIndexer) {
|
||||
setStatus(absPath, FileStatus::CheckedOut);
|
||||
}
|
||||
@@ -1683,7 +1683,7 @@ bool ClearCasePlugin::ccFileOp(const QString &workingDir, const QString &title,
|
||||
runCleartool(workingDir, args, m_settings.timeOutMS(),
|
||||
ShowStdOutInLogWindow | FullySynchronously);
|
||||
if (coResponse.error) {
|
||||
if (coResponse.stdOut.contains(QLatin1String("already checked out")))
|
||||
if (coResponse.stdErr.contains(QLatin1String("already checked out")))
|
||||
noCheckout = true;
|
||||
else
|
||||
return false;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<file>images/clean_pane_small.png</file>
|
||||
<file>images/clear.png</file>
|
||||
<file>images/closebutton.png</file>
|
||||
<file>images/compile_error_taskbar.png</file>
|
||||
<file>images/dir.png</file>
|
||||
<file>images/editcopy.png</file>
|
||||
<file>images/editcut.png</file>
|
||||
|
||||
@@ -114,8 +114,6 @@ using namespace Utils;
|
||||
|
||||
//===================EditorManager=====================
|
||||
|
||||
EditorManagerPlaceHolder *EditorManagerPlaceHolder::m_current = 0;
|
||||
|
||||
EditorManagerPlaceHolder::EditorManagerPlaceHolder(Core::IMode *mode, QWidget *parent)
|
||||
: QWidget(parent), m_mode(mode)
|
||||
{
|
||||
@@ -129,16 +127,17 @@ EditorManagerPlaceHolder::EditorManagerPlaceHolder(Core::IMode *mode, QWidget *p
|
||||
|
||||
EditorManagerPlaceHolder::~EditorManagerPlaceHolder()
|
||||
{
|
||||
if (m_current == this) {
|
||||
EditorManager::instance()->setParent(0);
|
||||
EditorManager::instance()->hide();
|
||||
// EditorManager will be deleted in ~MainWindow()
|
||||
EditorManager *em = EditorManager::instance();
|
||||
if (em && em->parent() == this) {
|
||||
em->hide();
|
||||
em->setParent(0);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorManagerPlaceHolder::currentModeChanged(Core::IMode *mode)
|
||||
{
|
||||
if (m_mode == mode) {
|
||||
m_current = this;
|
||||
QWidget *previousFocus = 0;
|
||||
if (EditorManager::instance()->focusWidget() && EditorManager::instance()->focusWidget()->hasFocus())
|
||||
previousFocus = EditorManager::instance()->focusWidget();
|
||||
@@ -146,16 +145,9 @@ void EditorManagerPlaceHolder::currentModeChanged(Core::IMode *mode)
|
||||
EditorManager::instance()->show();
|
||||
if (previousFocus)
|
||||
previousFocus->setFocus();
|
||||
} else if (m_current == this) {
|
||||
m_current = 0;
|
||||
}
|
||||
}
|
||||
|
||||
EditorManagerPlaceHolder* EditorManagerPlaceHolder::current()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
// ---------------- EditorManager
|
||||
|
||||
namespace Core {
|
||||
|
||||
@@ -79,12 +79,10 @@ class CORE_EXPORT EditorManagerPlaceHolder : public QWidget
|
||||
public:
|
||||
explicit EditorManagerPlaceHolder(Core::IMode *mode, QWidget *parent = 0);
|
||||
~EditorManagerPlaceHolder();
|
||||
static EditorManagerPlaceHolder* current();
|
||||
private slots:
|
||||
void currentModeChanged(Core::IMode *);
|
||||
private:
|
||||
Core::IMode *m_mode;
|
||||
static EditorManagerPlaceHolder* m_current;
|
||||
};
|
||||
|
||||
class CORE_EXPORT EditorManager : public QWidget
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
: m_unknownFileIcon(qApp->style()->standardIcon(QStyle::SP_FileIcon))
|
||||
{}
|
||||
|
||||
QIcon icon(const QFileInfo &info) const;
|
||||
QIcon icon(const QFileInfo &info);
|
||||
using QFileIconProvider::icon;
|
||||
|
||||
void registerIconOverlayForSuffix(const QIcon &icon, const QString &suffix)
|
||||
@@ -113,23 +113,26 @@ QFileIconProvider *iconProvider()
|
||||
return instance();
|
||||
}
|
||||
|
||||
QIcon FileIconProviderImplementation::icon(const QFileInfo &fileInfo) const
|
||||
QIcon FileIconProviderImplementation::icon(const QFileInfo &fileInfo)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << "FileIconProvider::icon" << fileInfo.absoluteFilePath();
|
||||
// Check for cached overlay icons by file suffix.
|
||||
if (!m_cache.isEmpty() && !fileInfo.isDir()) {
|
||||
const QString suffix = fileInfo.suffix();
|
||||
if (!suffix.isEmpty() && m_cache.contains(suffix)) {
|
||||
bool isDir = fileInfo.isDir();
|
||||
QString suffix = !isDir ? fileInfo.suffix() : QString();
|
||||
if (!m_cache.isEmpty() && !isDir && !suffix.isEmpty()) {
|
||||
if (m_cache.contains(suffix))
|
||||
return m_cache.value(suffix);
|
||||
}
|
||||
}
|
||||
// Get icon from OS.
|
||||
QIcon icon;
|
||||
if (HostOsInfo::isWindowsHost() || HostOsInfo::isMacHost())
|
||||
return QFileIconProvider::icon(fileInfo);
|
||||
|
||||
// File icons are unknown on linux systems.
|
||||
return fileInfo.isDir() ? QFileIconProvider::icon(fileInfo) : m_unknownFileIcon;
|
||||
icon = QFileIconProvider::icon(fileInfo);
|
||||
else // File icons are unknown on linux systems.
|
||||
icon = isDir ? QFileIconProvider::icon(fileInfo) : m_unknownFileIcon;
|
||||
if (!isDir && !suffix.isEmpty())
|
||||
m_cache.insert(suffix, icon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
BIN
src/plugins/coreplugin/images/compile_error_taskbar.png
Normal file
|
After Width: | Height: | Size: 618 B |
@@ -122,7 +122,7 @@ void Core::Internal::ProgressManagerPrivate::doSetApplicationLabel(const QString
|
||||
if (text.isEmpty()) {
|
||||
pITask->SetOverlayIcon(winId, NULL, NULL);
|
||||
} else {
|
||||
QPixmap pix = QPixmap(QLatin1String(":/projectexplorer/images/compile_error.png"));
|
||||
QPixmap pix = QPixmap(QLatin1String(":/core/images/compile_error_taskbar.png"));
|
||||
QPainter p(&pix);
|
||||
p.setPen(Qt::white);
|
||||
QFont font = p.font();
|
||||
|
||||
@@ -51,6 +51,9 @@ using namespace CPlusPlus;
|
||||
using namespace CppEditor::Internal;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef QByteArray _;
|
||||
|
||||
/**
|
||||
* Encapsulates the whole process of setting up an editor,
|
||||
* pressing ENTER and checking the result.
|
||||
@@ -140,205 +143,149 @@ void TestCase::run(const QByteArray &expected, int undoCount)
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
void CppEditorPlugin::test_doxygen_comments_qt_style()
|
||||
void CppEditorPlugin::test_doxygen_comments_data()
|
||||
{
|
||||
const QByteArray given =
|
||||
QTest::addColumn<QByteArray>("given");
|
||||
QTest::addColumn<QByteArray>("expected");
|
||||
|
||||
QTest::newRow("qt_style") << _(
|
||||
"bool preventFolding;\n"
|
||||
"/*!|\n"
|
||||
"int a;\n"
|
||||
;
|
||||
const QByteArray expected =
|
||||
) << _(
|
||||
"bool preventFolding;\n"
|
||||
"/*!\n"
|
||||
" * \\brief a\n"
|
||||
" */\n"
|
||||
"int a;\n"
|
||||
;
|
||||
);
|
||||
|
||||
TestCase data(given);
|
||||
data.run(expected);
|
||||
}
|
||||
|
||||
void CppEditorPlugin::test_doxygen_comments_qt_style_continuation()
|
||||
{
|
||||
const QByteArray given =
|
||||
QTest::newRow("qt_style_continuation") << _(
|
||||
"bool preventFolding;\n"
|
||||
"/*!\n"
|
||||
" * \\brief a|\n"
|
||||
" */\n"
|
||||
"int a;\n"
|
||||
;
|
||||
const QByteArray expected =
|
||||
) << _(
|
||||
"bool preventFolding;\n"
|
||||
"/*!\n"
|
||||
" * \\brief a\n"
|
||||
" * \n"
|
||||
" */\n"
|
||||
"int a;\n"
|
||||
;
|
||||
);
|
||||
|
||||
TestCase data(given);
|
||||
data.run(expected);
|
||||
}
|
||||
|
||||
void CppEditorPlugin::test_doxygen_comments_java_style()
|
||||
{
|
||||
const QByteArray given =
|
||||
QTest::newRow("java_style") << _(
|
||||
"bool preventFolding;\n"
|
||||
"/**|\n"
|
||||
"int a;\n"
|
||||
;
|
||||
const QByteArray expected =
|
||||
) << _(
|
||||
"bool preventFolding;\n"
|
||||
"/**\n"
|
||||
" * @brief a\n"
|
||||
" */\n"
|
||||
"int a;\n"
|
||||
;
|
||||
);
|
||||
|
||||
TestCase data(given);
|
||||
data.run(expected);
|
||||
}
|
||||
|
||||
void CppEditorPlugin::test_doxygen_comments_java_style_continuation()
|
||||
{
|
||||
const QByteArray given =
|
||||
QTest::newRow("java_style_continuation") << _(
|
||||
"bool preventFolding;\n"
|
||||
"/**\n"
|
||||
" * @brief a|\n"
|
||||
" */\n"
|
||||
"int a;\n"
|
||||
;
|
||||
const QByteArray expected =
|
||||
) << _(
|
||||
"bool preventFolding;\n"
|
||||
"/**\n"
|
||||
" * @brief a\n"
|
||||
" * \n"
|
||||
" */\n"
|
||||
"int a;\n"
|
||||
;
|
||||
);
|
||||
|
||||
TestCase data(given);
|
||||
data.run(expected);
|
||||
}
|
||||
|
||||
void CppEditorPlugin::test_doxygen_comments_cpp_styleA()
|
||||
{
|
||||
const QByteArray given =
|
||||
QTest::newRow("cpp_styleA") << _(
|
||||
"bool preventFolding;\n"
|
||||
"///|\n"
|
||||
"int a;\n"
|
||||
;
|
||||
|
||||
const QByteArray expected =
|
||||
) << _(
|
||||
"bool preventFolding;\n"
|
||||
"///\n"
|
||||
"/// \\brief a\n"
|
||||
"///\n"
|
||||
"int a;\n"
|
||||
;
|
||||
TestCase data(given);
|
||||
data.run(expected);
|
||||
}
|
||||
);
|
||||
|
||||
void CppEditorPlugin::test_doxygen_comments_cpp_styleB()
|
||||
{
|
||||
const QByteArray given =
|
||||
QTest::newRow("cpp_styleB") << _(
|
||||
"bool preventFolding;\n"
|
||||
"//!|\n"
|
||||
"int a;\n"
|
||||
;
|
||||
|
||||
const QByteArray expected =
|
||||
) << _(
|
||||
"bool preventFolding;\n"
|
||||
"//!\n"
|
||||
"//! \\brief a\n"
|
||||
"//!\n"
|
||||
"int a;\n"
|
||||
;
|
||||
TestCase data(given);
|
||||
data.run(expected);
|
||||
}
|
||||
);
|
||||
|
||||
void CppEditorPlugin::test_doxygen_comments_cpp_styleA_continuation()
|
||||
{
|
||||
const QByteArray given =
|
||||
QTest::newRow("cpp_styleA_continuation") << _(
|
||||
"bool preventFolding;\n"
|
||||
"///\n"
|
||||
"/// \\brief a|\n"
|
||||
"///\n"
|
||||
"int a;\n"
|
||||
;
|
||||
const QByteArray expected =
|
||||
) << _(
|
||||
"bool preventFolding;\n"
|
||||
"///\n"
|
||||
"/// \\brief a\n"
|
||||
"/// \n"
|
||||
"///\n"
|
||||
"int a;\n"
|
||||
;
|
||||
|
||||
TestCase data(given);
|
||||
data.run(expected);
|
||||
}
|
||||
);
|
||||
|
||||
/// test cpp style doxygen comment when inside a indented scope
|
||||
void CppEditorPlugin::test_doxygen_comments_cpp_styleA_indented()
|
||||
{
|
||||
const QByteArray given =
|
||||
QTest::newRow("cpp_styleA_indented") << _(
|
||||
" bool preventFolding;\n"
|
||||
" ///|\n"
|
||||
" int a;\n"
|
||||
;
|
||||
|
||||
const QByteArray expected =
|
||||
) << _(
|
||||
" bool preventFolding;\n"
|
||||
" ///\n"
|
||||
" /// \\brief a\n"
|
||||
" ///\n"
|
||||
" int a;\n"
|
||||
;
|
||||
TestCase data(given);
|
||||
data.run(expected);
|
||||
}
|
||||
);
|
||||
|
||||
/// test cpp style doxygen comment continuation when inside a indented scope
|
||||
void CppEditorPlugin::test_doxygen_comments_cpp_styleA_indented_continuation()
|
||||
{
|
||||
const QByteArray given =
|
||||
QTest::newRow("cpp_styleA_indented_continuation") << _(
|
||||
" bool preventFolding;\n"
|
||||
" ///\n"
|
||||
" /// \\brief a|\n"
|
||||
" ///\n"
|
||||
" int a;\n"
|
||||
;
|
||||
const QByteArray expected =
|
||||
) << _(
|
||||
" bool preventFolding;\n"
|
||||
" ///\n"
|
||||
" /// \\brief a\n"
|
||||
" /// \n"
|
||||
" ///\n"
|
||||
" int a;\n"
|
||||
;
|
||||
);
|
||||
|
||||
TestCase data(given);
|
||||
data.run(expected);
|
||||
}
|
||||
|
||||
void CppEditorPlugin::test_doxygen_comments_cpp_styleA_corner_case()
|
||||
{
|
||||
const QByteArray given =
|
||||
QTest::newRow("cpp_styleA_corner_case") << _(
|
||||
"bool preventFolding;\n"
|
||||
"///\n"
|
||||
"void d(); ///|\n"
|
||||
;
|
||||
const QByteArray expected =
|
||||
) << _(
|
||||
"bool preventFolding;\n"
|
||||
"///\n"
|
||||
"void d(); ///\n"
|
||||
"\n"
|
||||
;
|
||||
);
|
||||
}
|
||||
|
||||
void CppEditorPlugin::test_doxygen_comments()
|
||||
{
|
||||
QFETCH(QByteArray, given);
|
||||
QFETCH(QByteArray, expected);
|
||||
TestCase data(given);
|
||||
data.run(expected);
|
||||
}
|
||||
|
||||
@@ -430,6 +430,7 @@ bool handleDoxygenCppStyleContinuation(QTextCursor &cursor,
|
||||
|
||||
const QString commentMarker = text.mid(offset, 3);
|
||||
newLine.append(commentMarker);
|
||||
newLine.append(QLatin1Char(' '));
|
||||
|
||||
cursor.insertText(newLine);
|
||||
e->accept();
|
||||
@@ -487,6 +488,7 @@ bool handleDoxygenContinuation(QTextCursor &cursor,
|
||||
while (offset < blockPos && text.at(offset) == QLatin1Char('*'))
|
||||
++offset;
|
||||
newLine.append(QString(offset - start, QLatin1Char('*')));
|
||||
newLine.append(QLatin1Char(' '));
|
||||
}
|
||||
cursor.insertText(newLine);
|
||||
e->accept();
|
||||
|
||||
@@ -116,16 +116,8 @@ private slots:
|
||||
void test_FollowSymbolUnderCursor_virtualFunctionCall();
|
||||
void test_FollowSymbolUnderCursor_virtualFunctionCall_multipleDocuments();
|
||||
|
||||
void test_doxygen_comments_qt_style();
|
||||
void test_doxygen_comments_qt_style_continuation();
|
||||
void test_doxygen_comments_java_style();
|
||||
void test_doxygen_comments_java_style_continuation();
|
||||
void test_doxygen_comments_cpp_styleA();
|
||||
void test_doxygen_comments_cpp_styleB();
|
||||
void test_doxygen_comments_cpp_styleA_indented();
|
||||
void test_doxygen_comments_cpp_styleA_continuation();
|
||||
void test_doxygen_comments_cpp_styleA_indented_continuation();
|
||||
void test_doxygen_comments_cpp_styleA_corner_case();
|
||||
void test_doxygen_comments_data();
|
||||
void test_doxygen_comments();
|
||||
|
||||
void test_quickfix_CompleteSwitchCaseStatement_basic1();
|
||||
void test_quickfix_CompleteSwitchCaseStatement_basic2();
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "cppincludehierarchymodel.h"
|
||||
#include "cppincludehierarchytreeview.h"
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <cplusplus/CppDocument.h>
|
||||
|
||||
#include <utils/annotateditemdelegate.h>
|
||||
@@ -89,7 +90,8 @@ CppIncludeHierarchyWidget::CppIncludeHierarchyWidget() :
|
||||
m_treeView(0),
|
||||
m_model(0),
|
||||
m_delegate(0),
|
||||
m_includeHierarchyInfoLabel(0)
|
||||
m_includeHierarchyInfoLabel(0),
|
||||
m_editor(0)
|
||||
{
|
||||
m_inspectedFile = new CppIncludeLabel(this);
|
||||
m_inspectedFile->setMargin(5);
|
||||
@@ -118,6 +120,9 @@ CppIncludeHierarchyWidget::CppIncludeHierarchyWidget() :
|
||||
setLayout(layout);
|
||||
|
||||
connect(CppEditorPlugin::instance(), SIGNAL(includeHierarchyRequested()), SLOT(perform()));
|
||||
connect(Core::EditorManager::instance(), SIGNAL(editorsClosed(QList<Core::IEditor *>)),
|
||||
this, SLOT(editorsClosed(QList<Core::IEditor *>)));
|
||||
|
||||
}
|
||||
|
||||
CppIncludeHierarchyWidget::~CppIncludeHierarchyWidget()
|
||||
@@ -128,15 +133,16 @@ void CppIncludeHierarchyWidget::perform()
|
||||
{
|
||||
showNoIncludeHierarchyLabel();
|
||||
|
||||
CPPEditor *editor = qobject_cast<CPPEditor *>(Core::EditorManager::currentEditor());
|
||||
if (!editor)
|
||||
m_editor = qobject_cast<CPPEditor *>(Core::EditorManager::currentEditor());
|
||||
if (!m_editor)
|
||||
return;
|
||||
CPPEditorWidget *widget = qobject_cast<CPPEditorWidget *>(editor->widget());
|
||||
|
||||
CPPEditorWidget *widget = qobject_cast<CPPEditorWidget *>(m_editor->widget());
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
m_model->clear();
|
||||
m_model->buildHierarchy(widget->editorDocument()->filePath());
|
||||
m_model->buildHierarchy(m_editor, widget->editorDocument()->filePath());
|
||||
if (m_model->isEmpty())
|
||||
return;
|
||||
|
||||
@@ -162,6 +168,14 @@ void CppIncludeHierarchyWidget::onItemClicked(const QModelIndex &index)
|
||||
Constants::CPPEDITOR_ID);
|
||||
}
|
||||
|
||||
void CppIncludeHierarchyWidget::editorsClosed(QList<Core::IEditor *> editors)
|
||||
{
|
||||
foreach (Core::IEditor *editor, editors) {
|
||||
if (m_editor == editor)
|
||||
perform();
|
||||
}
|
||||
}
|
||||
|
||||
void CppIncludeHierarchyWidget::showNoIncludeHierarchyLabel()
|
||||
{
|
||||
m_inspectedFile->hide();
|
||||
|
||||
@@ -55,6 +55,7 @@ class FileName;
|
||||
namespace CppEditor {
|
||||
namespace Internal {
|
||||
|
||||
class CPPEditor;
|
||||
class CPPEditorWidget;
|
||||
class CppInclude;
|
||||
class CppIncludeLabel;
|
||||
@@ -73,6 +74,7 @@ public slots:
|
||||
|
||||
private slots:
|
||||
void onItemClicked(const QModelIndex &index);
|
||||
void editorsClosed(QList<Core::IEditor *> editors);
|
||||
|
||||
private:
|
||||
void showNoIncludeHierarchyLabel();
|
||||
@@ -84,6 +86,7 @@ private:
|
||||
Utils::AnnotatedItemDelegate *m_delegate;
|
||||
CppIncludeLabel *m_inspectedFile;
|
||||
QLabel *m_includeHierarchyInfoLabel;
|
||||
CPPEditor *m_editor;
|
||||
};
|
||||
|
||||
// @todo: Pretty much the same design as the OutlineWidgetStack. Maybe we can generalize the
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppincludehierarchymodel.h"
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <cppeditor/cppeditor.h>
|
||||
#include <cpptools/cppmodelmanagerinterface.h>
|
||||
#include <utils/fileutils.h>
|
||||
|
||||
@@ -47,6 +49,7 @@ class TestCase
|
||||
public:
|
||||
TestCase(const QList<QByteArray> &sourceList)
|
||||
: m_cmm(CppModelManagerInterface::instance())
|
||||
, m_editor(0)
|
||||
{
|
||||
QStringList filePaths;
|
||||
const int sourceListSize = sourceList.size();
|
||||
@@ -82,22 +85,30 @@ public:
|
||||
|
||||
~TestCase()
|
||||
{
|
||||
// Close editor
|
||||
if (m_editor)
|
||||
Core::EditorManager::closeEditor(m_editor, false);
|
||||
|
||||
m_cmm->GC();
|
||||
QVERIFY(m_cmm->snapshot().isEmpty());
|
||||
}
|
||||
|
||||
void run(int includesCount, int includedByCount) const
|
||||
void run(int includesCount, int includedByCount)
|
||||
{
|
||||
const QString fileName = QDir::tempPath() + QLatin1String("/file1.h");
|
||||
|
||||
m_editor = qobject_cast<CPPEditor *>(Core::EditorManager::openEditor(fileName));
|
||||
QVERIFY(m_editor);
|
||||
|
||||
CppIncludeHierarchyModel model(0);
|
||||
model.buildHierarchy(fileName);
|
||||
model.buildHierarchy(m_editor, fileName);
|
||||
QCOMPARE(model.rowCount(model.index(0, 0)), includesCount);
|
||||
QCOMPARE(model.rowCount(model.index(1, 0)), includedByCount);
|
||||
}
|
||||
|
||||
private:
|
||||
CppModelManagerInterface *m_cmm;
|
||||
CPPEditor *m_editor;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -35,10 +35,12 @@
|
||||
#include <cplusplus/CppDocument.h>
|
||||
#include <cppeditor/cppeditor.h>
|
||||
#include <cpptools/cppmodelmanagerinterface.h>
|
||||
#include <cpptools/cpptoolseditorsupport.h>
|
||||
|
||||
#include <QSet>
|
||||
|
||||
using namespace CPlusPlus;
|
||||
using namespace CppTools;
|
||||
|
||||
namespace CppEditor {
|
||||
namespace Internal {
|
||||
@@ -48,7 +50,7 @@ CppIncludeHierarchyModel::CppIncludeHierarchyModel(QObject *parent)
|
||||
, m_rootItem(new CppIncludeHierarchyItem(QString()))
|
||||
, m_includesItem(new CppIncludeHierarchyItem(tr("Includes"), m_rootItem))
|
||||
, m_includedByItem(new CppIncludeHierarchyItem(tr("Included by"), m_rootItem))
|
||||
|
||||
, m_editor(0)
|
||||
{
|
||||
m_rootItem->appendChild(m_includesItem);
|
||||
m_rootItem->appendChild(m_includedByItem);
|
||||
@@ -199,6 +201,15 @@ void CppIncludeHierarchyModel::clear()
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void CppIncludeHierarchyModel::buildHierarchy(CPPEditor *editor, const QString &filePath)
|
||||
{
|
||||
m_editor = editor;
|
||||
beginResetModel();
|
||||
buildHierarchyIncludes(filePath);
|
||||
buildHierarchyIncludedBy(filePath);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
bool CppIncludeHierarchyModel::hasChildren(const QModelIndex &parent) const
|
||||
{
|
||||
if (!parent.isValid())
|
||||
@@ -210,14 +221,6 @@ bool CppIncludeHierarchyModel::hasChildren(const QModelIndex &parent) const
|
||||
return parentItem->hasChildren();
|
||||
}
|
||||
|
||||
void CppIncludeHierarchyModel::buildHierarchy(const QString &filePath)
|
||||
{
|
||||
beginResetModel();
|
||||
buildHierarchyIncludes(filePath);
|
||||
buildHierarchyIncludedBy(filePath);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
bool CppIncludeHierarchyModel::isEmpty() const
|
||||
{
|
||||
return !m_includesItem->hasChildren() && !m_includedByItem->hasChildren();
|
||||
@@ -233,7 +236,11 @@ void CppIncludeHierarchyModel::buildHierarchyIncludes_helper(const QString &file
|
||||
CppIncludeHierarchyItem *parent,
|
||||
QSet<QString> *cyclic, bool recursive)
|
||||
{
|
||||
const Snapshot &snapshot = CppTools::CppModelManagerInterface::instance()->snapshot();
|
||||
if (!m_editor)
|
||||
return;
|
||||
|
||||
CppModelManagerInterface *cppMM = CppModelManagerInterface::instance();
|
||||
const Snapshot &snapshot = cppMM->cppEditorSupport(m_editor)->snapshotUpdater()->snapshot();
|
||||
Document::Ptr doc = snapshot.document(filePath);
|
||||
if (!doc)
|
||||
return;
|
||||
|
||||
@@ -41,9 +41,14 @@ enum ItemRole {
|
||||
|
||||
} // Anonymous
|
||||
|
||||
namespace Core {
|
||||
class IEditor;
|
||||
}
|
||||
|
||||
namespace CppEditor {
|
||||
namespace Internal {
|
||||
|
||||
class CPPEditor;
|
||||
class CppIncludeHierarchyItem;
|
||||
|
||||
class CppIncludeHierarchyModel : public QAbstractItemModel
|
||||
@@ -63,7 +68,7 @@ public:
|
||||
bool hasChildren(const QModelIndex &parent) const;
|
||||
|
||||
void clear();
|
||||
void buildHierarchy(const QString &filePath);
|
||||
void buildHierarchy(CPPEditor *editor, const QString &filePath);
|
||||
bool isEmpty() const;
|
||||
|
||||
private:
|
||||
@@ -77,6 +82,7 @@ private:
|
||||
CppIncludeHierarchyItem *m_rootItem;
|
||||
CppIncludeHierarchyItem *m_includesItem;
|
||||
CppIncludeHierarchyItem *m_includedByItem;
|
||||
CPPEditor *m_editor;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -169,6 +169,7 @@ CppEditorSupport::~CppEditorSupport()
|
||||
m_highlighter.cancel();
|
||||
m_futureSemanticInfo.cancel();
|
||||
|
||||
m_documentParser.waitForFinished();
|
||||
m_highlighter.waitForFinished();
|
||||
m_futureSemanticInfo.waitForFinished();
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ public:
|
||||
attachPID(-1),
|
||||
useTerminal(false),
|
||||
breakOnMain(false),
|
||||
continueAfterAttach(false),
|
||||
multiProcess(false),
|
||||
languages(AnyLanguage),
|
||||
qmlServerAddress(QLatin1String("127.0.0.1")),
|
||||
@@ -102,6 +103,7 @@ public:
|
||||
qint64 attachPID;
|
||||
bool useTerminal;
|
||||
bool breakOnMain;
|
||||
bool continueAfterAttach;
|
||||
bool multiProcess;
|
||||
DebuggerLanguages languages;
|
||||
|
||||
|
||||
@@ -3603,6 +3603,7 @@ void GdbEngine::handleStackSelectThread(const GdbResponse &)
|
||||
void GdbEngine::reloadFullStack()
|
||||
{
|
||||
PENDING_DEBUG("RELOAD FULL STACK");
|
||||
resetLocation();
|
||||
postCommand("-stack-list-frames", Discardable, CB(handleStackListFrames),
|
||||
QVariant::fromValue<StackCookie>(StackCookie(true, true)));
|
||||
}
|
||||
@@ -4307,10 +4308,8 @@ void GdbEngine::assignValueInDebugger(const WatchData *data,
|
||||
+ value.toString().toUtf8().toHex();
|
||||
postCommand(cmd, Discardable, CB(handleVarAssign));
|
||||
} else {
|
||||
postCommand("-var-delete assign");
|
||||
postCommand("-var-create assign * " + expression.toLatin1());
|
||||
postCommand("-var-assign assign " +
|
||||
GdbMi::escapeCString(value.toString().toLatin1()),
|
||||
postCommand("set variable (" + expression.toLatin1() + ")="
|
||||
+ GdbMi::escapeCString(value.toString().toLatin1()),
|
||||
Discardable, CB(handleVarAssign));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ static QByteArray tooltipIName(const QString &exp)
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
LldbEngine::LldbEngine(const DebuggerStartParameters &startParameters)
|
||||
: DebuggerEngine(startParameters)
|
||||
: DebuggerEngine(startParameters), m_continueAtNextSpontaneousStop(false)
|
||||
{
|
||||
m_lastAgentId = 0;
|
||||
m_lastToken = 0;
|
||||
@@ -197,13 +197,19 @@ void LldbEngine::setupInferior()
|
||||
cmd.arg("executable", QFileInfo(sp.executable).absoluteFilePath());
|
||||
cmd.arg("startMode", sp.startMode); // directly relying on this is brittle wrt. insertions, so check it here
|
||||
cmd.arg("processArgs", sp.processArgs);
|
||||
cmd.arg("attachPid", ((sp.startMode == AttachCrashedExternal || sp.startMode == AttachExternal)
|
||||
? sp.attachPID : 0));
|
||||
|
||||
QTC_CHECK(!sp.attachPID || (sp.startMode == AttachCrashedExternal
|
||||
|| sp.startMode == AttachExternal));
|
||||
cmd.arg("attachPid", sp.attachPID);
|
||||
cmd.arg("sysRoot", sp.sysRoot);
|
||||
cmd.arg("remoteChannel", ((sp.startMode == AttachToRemoteProcess
|
||||
|| sp.startMode == AttachToRemoteServer)
|
||||
? sp.remoteChannel : QString()));
|
||||
cmd.arg("platform", sp.platform);
|
||||
QTC_CHECK(!sp.continueAfterAttach || (sp.startMode == AttachToRemoteProcess
|
||||
|| sp.startMode == AttachExternal
|
||||
|| sp.startMode == AttachToRemoteServer));
|
||||
m_continueAtNextSpontaneousStop = false;
|
||||
runCommand(cmd);
|
||||
updateLocals(); // update display options
|
||||
}
|
||||
@@ -1014,9 +1020,13 @@ void LldbEngine::refreshState(const GdbMi &reportedState)
|
||||
notifyInferiorRunOk();
|
||||
else if (newState == "inferiorrunfailed")
|
||||
notifyInferiorRunFailed();
|
||||
else if (newState == "stopped")
|
||||
else if (newState == "stopped") {
|
||||
notifyInferiorSpontaneousStop();
|
||||
else if (newState == "inferiorstopok")
|
||||
if (m_continueAtNextSpontaneousStop) {
|
||||
m_continueAtNextSpontaneousStop = false;
|
||||
continueInferior();
|
||||
}
|
||||
} else if (newState == "inferiorstopok")
|
||||
notifyInferiorStopOk();
|
||||
else if (newState == "inferiorstopfailed")
|
||||
notifyInferiorStopFailed();
|
||||
@@ -1028,9 +1038,11 @@ void LldbEngine::refreshState(const GdbMi &reportedState)
|
||||
notifyEngineRunFailed();
|
||||
else if (newState == "inferiorsetupok")
|
||||
notifyInferiorSetupOk();
|
||||
else if (newState == "enginerunandinferiorrunok")
|
||||
else if (newState == "enginerunandinferiorrunok") {
|
||||
if (startParameters().continueAfterAttach)
|
||||
m_continueAtNextSpontaneousStop = true;
|
||||
notifyEngineRunAndInferiorRunOk();
|
||||
else if (newState == "enginerunandinferiorstopok")
|
||||
} else if (newState == "enginerunandinferiorstopok")
|
||||
notifyEngineRunAndInferiorStopOk();
|
||||
else if (newState == "inferiorshutdownok")
|
||||
notifyInferiorShutdownOk();
|
||||
|
||||
@@ -201,6 +201,7 @@ private:
|
||||
// FIXME: Make generic.
|
||||
int m_lastAgentId;
|
||||
int m_lastToken;
|
||||
int m_continueAtNextSpontaneousStop;
|
||||
QMap<QPointer<DisassemblerAgent>, int> m_disassemblerAgents;
|
||||
QMap<QPointer<MemoryAgent>, int> m_memoryAgents;
|
||||
QHash<int, QPointer<QObject> > m_memoryAgentTokens;
|
||||
|
||||
@@ -36,12 +36,11 @@
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
void mergeThreadData(ThreadData &data, const ThreadData &other)
|
||||
static void mergeThreadData(ThreadData &data, const ThreadData &other)
|
||||
{
|
||||
if (!other.core.isEmpty())
|
||||
data.core = other.core;
|
||||
@@ -67,6 +66,40 @@ void mergeThreadData(ThreadData &data, const ThreadData &other)
|
||||
data.lineNumber = other.lineNumber;
|
||||
}
|
||||
|
||||
static QVariant threadPart(const ThreadData &thread, int column)
|
||||
{
|
||||
switch (column) {
|
||||
case ThreadData::IdColumn:
|
||||
return thread.id.raw();
|
||||
case ThreadData::FunctionColumn:
|
||||
return thread.function;
|
||||
case ThreadData::FileColumn:
|
||||
return thread.fileName.isEmpty() ? thread.module : thread.fileName;
|
||||
case ThreadData::LineColumn:
|
||||
return thread.lineNumber >= 0
|
||||
? QString::number(thread.lineNumber) : QString();
|
||||
case ThreadData::AddressColumn:
|
||||
return thread.address > 0
|
||||
? QLatin1String("0x") + QString::number(thread.address, 16)
|
||||
: QString();
|
||||
case ThreadData::CoreColumn:
|
||||
return thread.core;
|
||||
case ThreadData::StateColumn:
|
||||
return thread.state;
|
||||
case ThreadData::TargetIdColumn:
|
||||
if (thread.targetId.startsWith(QLatin1String("Thread ")))
|
||||
return thread.targetId.mid(7);
|
||||
return thread.targetId;
|
||||
case ThreadData::NameColumn:
|
||||
return thread.name;
|
||||
case ThreadData::DetailsColumn:
|
||||
return thread.details;
|
||||
case ThreadData::ComboNameColumn:
|
||||
return QString::fromLatin1("#%1 %2").arg(thread.id.raw()).arg(thread.name);
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ThreadsHandler
|
||||
@@ -137,8 +170,6 @@ ThreadsHandler::ThreadsHandler()
|
||||
{
|
||||
m_resetLocationScheduled = false;
|
||||
setObjectName(QLatin1String("ThreadsModel"));
|
||||
m_proxyModel = new QSortFilterProxyModel(this);
|
||||
m_proxyModel->setSourceModel(this);
|
||||
}
|
||||
|
||||
int ThreadsHandler::currentThreadIndex() const
|
||||
@@ -168,35 +199,7 @@ QVariant ThreadsHandler::data(const QModelIndex &index, int role) const
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column()) {
|
||||
case ThreadData::IdColumn:
|
||||
return thread.id.raw();
|
||||
case ThreadData::FunctionColumn:
|
||||
return thread.function;
|
||||
case ThreadData::FileColumn:
|
||||
return thread.fileName.isEmpty() ? thread.module : thread.fileName;
|
||||
case ThreadData::LineColumn:
|
||||
return thread.lineNumber >= 0
|
||||
? QString::number(thread.lineNumber) : QString();
|
||||
case ThreadData::AddressColumn:
|
||||
return thread.address > 0
|
||||
? QLatin1String("0x") + QString::number(thread.address, 16)
|
||||
: QString();
|
||||
case ThreadData::CoreColumn:
|
||||
return thread.core;
|
||||
case ThreadData::StateColumn:
|
||||
return thread.state;
|
||||
case ThreadData::TargetIdColumn:
|
||||
if (thread.targetId.startsWith(QLatin1String("Thread ")))
|
||||
return thread.targetId.mid(7);
|
||||
return thread.targetId;
|
||||
case ThreadData::NameColumn:
|
||||
return thread.name;
|
||||
case ThreadData::DetailsColumn:
|
||||
return thread.details;
|
||||
case ThreadData::ComboNameColumn:
|
||||
return QString::fromLatin1("#%1 %2").arg(thread.id.raw()).arg(thread.name);
|
||||
}
|
||||
return threadPart(thread, index.column());
|
||||
case Qt::ToolTipRole:
|
||||
return threadToolTip(thread);
|
||||
case Qt::DecorationRole:
|
||||
@@ -250,6 +253,33 @@ Qt::ItemFlags ThreadsHandler::flags(const QModelIndex &index) const
|
||||
return stopped ? QAbstractTableModel::flags(index) : Qt::ItemFlags(0);
|
||||
}
|
||||
|
||||
struct Sorter
|
||||
{
|
||||
Sorter(int column, Qt::SortOrder order)
|
||||
: m_column(column), m_order(order)
|
||||
{}
|
||||
|
||||
bool operator()(const ThreadData &t1, const ThreadData &t2) const
|
||||
{
|
||||
const QVariant v1 = threadPart(t1, m_column);
|
||||
const QVariant v2 = threadPart(t2, m_column);
|
||||
if (v1 == v2)
|
||||
return false;
|
||||
// FIXME: Use correct toXXX();
|
||||
return (v1.toString() < v2.toString()) ^ (m_order == Qt::DescendingOrder);
|
||||
}
|
||||
|
||||
int m_column;
|
||||
Qt::SortOrder m_order;
|
||||
};
|
||||
|
||||
void ThreadsHandler::sort(int column, Qt::SortOrder order)
|
||||
{
|
||||
layoutAboutToBeChanged();
|
||||
qSort(m_threads.begin(), m_threads.end(), Sorter(column, order));
|
||||
layoutChanged();
|
||||
}
|
||||
|
||||
ThreadId ThreadsHandler::currentThread() const
|
||||
{
|
||||
return m_currentId;
|
||||
@@ -490,7 +520,7 @@ void ThreadsHandler::resetLocation()
|
||||
|
||||
QAbstractItemModel *ThreadsHandler::model()
|
||||
{
|
||||
return m_proxyModel;
|
||||
return this;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -30,14 +30,10 @@
|
||||
#ifndef THREADSHANDLER_H
|
||||
#define THREADSHANDLER_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QIcon>
|
||||
|
||||
#include "threaddata.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QSortFilterProxyModel;
|
||||
QT_END_NAMESPACE
|
||||
#include <QAbstractTableModel>
|
||||
#include <QIcon>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -92,6 +88,7 @@ private:
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
void sort(int, Qt::SortOrder);
|
||||
void updateThreadBox();
|
||||
void threadDataChanged(ThreadId id);
|
||||
|
||||
@@ -101,7 +98,6 @@ private:
|
||||
const QIcon m_emptyIcon;
|
||||
|
||||
bool m_resetLocationScheduled;
|
||||
QSortFilterProxyModel *m_proxyModel;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -784,6 +784,12 @@ static const QMap<QString, int> &vimKeyNames()
|
||||
return k;
|
||||
}
|
||||
|
||||
bool isControlModifier(const Qt::KeyboardModifiers &mods)
|
||||
{
|
||||
static const int ctrl = HostOsInfo::controlModifier();
|
||||
return (mods & ctrl) == ctrl;
|
||||
}
|
||||
|
||||
|
||||
Range::Range()
|
||||
: beginPos(-1), endPos(-1), rangemode(RangeCharMode)
|
||||
@@ -938,12 +944,12 @@ public:
|
||||
|
||||
bool is(int c) const
|
||||
{
|
||||
return m_xkey == c && m_modifiers != HostOsInfo::controlModifier();
|
||||
return m_xkey == c && !isControl();
|
||||
}
|
||||
|
||||
bool isControl() const
|
||||
{
|
||||
return m_modifiers == HostOsInfo::controlModifier();
|
||||
return isControlModifier(m_modifiers);
|
||||
}
|
||||
|
||||
bool isControl(int c) const
|
||||
@@ -2215,7 +2221,7 @@ bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev)
|
||||
}
|
||||
|
||||
// We are interested in overriding most Ctrl key combinations.
|
||||
if (mods == HostOsInfo::controlModifier()
|
||||
if (isControlModifier(mods)
|
||||
&& !config(ConfigPassControlKey).toBool()
|
||||
&& ((key >= Key_A && key <= Key_Z && key != Key_K)
|
||||
|| key == Key_BracketLeft || key == Key_BracketRight)) {
|
||||
|
||||
@@ -1443,7 +1443,7 @@ void GitClient::show(const QString &source, const QString &id,
|
||||
|
||||
GitDiffHandler *handler = new GitDiffHandler(diffEditor,
|
||||
gitBinaryPath(),
|
||||
workingDirectory,
|
||||
findRepositoryForDirectory(workingDirectory),
|
||||
processEnvironment(),
|
||||
settings()->intValue(GitSettings::timeoutKey));
|
||||
handler->show(id);
|
||||
|
||||
@@ -84,6 +84,8 @@ RunControl *IosDebugSupport::createDebugRunControl(IosRunConfiguration *runConfi
|
||||
}
|
||||
params.displayName = runConfig->appName();
|
||||
params.remoteSetupNeeded = true;
|
||||
if (!params.breakOnMain)
|
||||
params.continueAfterAttach = true;
|
||||
|
||||
Debugger::DebuggerRunConfigurationAspect *aspect
|
||||
= runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>();
|
||||
|
||||
@@ -249,9 +249,6 @@ void QtQuickApp::handleCurrentProFileTemplateLine(const QString &line,
|
||||
if (!nextLine.startsWith(QLatin1String("QML_IMPORT_PATH =")))
|
||||
return;
|
||||
proFile << nextLine << endl;
|
||||
} else if (line.contains(QLatin1String("# HARMATTAN_BOOSTABLE"))) {
|
||||
QString nextLine = proFileTemplate.readLine(); // eats '# CONFIG += qdeclarative-boostable'
|
||||
proFile << nextLine << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,6 +119,9 @@ void FormEditorItem::setHighlightBoundingRect(bool highlight)
|
||||
|
||||
void FormEditorItem::blurContent(bool blurContent)
|
||||
{
|
||||
if (!scene())
|
||||
return;
|
||||
|
||||
if (m_blurContent != blurContent) {
|
||||
m_blurContent = blurContent;
|
||||
update();
|
||||
|
||||
@@ -510,7 +510,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
|
||||
|
||||
if ((valid || entry.forceImport())
|
||||
&& (entry.requiredImport().isEmpty()
|
||||
|| model->hasImport(entryToImport(entry), true, false) || entry.forceImport())) {
|
||||
|| model->hasImport(entryToImport(entry), true, true) || entry.forceImport())) {
|
||||
QString itemSectionName = entry.category();
|
||||
ItemLibrarySectionModel *sectionModel;
|
||||
ItemLibraryItemModel *itemModel;
|
||||
|
||||
@@ -367,13 +367,10 @@ void ItemLibraryWidget::startDragAndDrop(int itemLibId)
|
||||
{
|
||||
QMimeData *mimeData = m_itemLibraryModel->getMimeData(itemLibId);
|
||||
QDrag *drag = new QDrag(this);
|
||||
const QImage image = qvariant_cast<QImage>(mimeData->imageData());
|
||||
|
||||
drag->setPixmap(m_itemLibraryModel->getIcon(itemLibId).pixmap(32, 32));
|
||||
drag->setMimeData(mimeData);
|
||||
|
||||
QQuickItem *rootItem = qobject_cast<QQuickItem*>(m_itemsView->rootObject());
|
||||
|
||||
drag->exec();
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,8 @@ public:
|
||||
QList<Import> possibleImports() const;
|
||||
QList<Import> usedImports() const;
|
||||
void changeImports(const QList<Import> &importsToBeAdded, const QList<Import> &importsToBeRemoved);
|
||||
void setPossibleImports(const QList<Import> &possibleImports);
|
||||
void setUsedImports(const QList<Import> &usedImports);
|
||||
bool hasImport(const Import &import, bool ignoreAlias = true, bool allowHigherVersion = false);
|
||||
QString pathForImport(const Import &import);
|
||||
|
||||
|
||||
@@ -75,6 +75,8 @@ static inline QStringList importPaths() {
|
||||
|
||||
static inline bool checkIfDerivedFromItem(const QString &fileName)
|
||||
{
|
||||
return true;
|
||||
|
||||
QmlJS::Snapshot snapshot;
|
||||
|
||||
|
||||
@@ -101,7 +103,7 @@ static inline bool checkIfDerivedFromItem(const QString &fileName)
|
||||
|
||||
snapshot.insert(document);
|
||||
|
||||
QmlJS::Link link(snapshot, modelManager->importPaths(), QmlJS::ModelManagerInterface::instance()->builtins(document));
|
||||
QmlJS::Link link(snapshot, modelManager->defaultVContext(), QmlJS::ModelManagerInterface::instance()->builtins(document));
|
||||
|
||||
QList<QmlJS::DiagnosticMessage> diagnosticLinkMessages;
|
||||
QmlJS::ContextPtr context = link(document, &diagnosticLinkMessages);
|
||||
|
||||
@@ -1731,25 +1731,12 @@ QList<Import> Model::imports() const
|
||||
|
||||
QList<Import> Model::possibleImports() const
|
||||
{
|
||||
QList<Import> possibleImportList;
|
||||
|
||||
possibleImportList.append(Import::createLibraryImport("QtQuick.Controls", "1.0"));
|
||||
possibleImportList.append(Import::createLibraryImport("QtQuick.Layouts", "1.0"));
|
||||
possibleImportList.append(Import::createLibraryImport("QtQuick.Window", "2.0"));
|
||||
|
||||
return possibleImportList;
|
||||
return d->m_possibleImportList;
|
||||
}
|
||||
|
||||
QList<Import> Model::usedImports() const
|
||||
{
|
||||
QList<Import> usedImportList;
|
||||
|
||||
usedImportList.append(Import::createLibraryImport("QtQuick", "1.0"));
|
||||
usedImportList.append(Import::createLibraryImport("QtQuick", "1.1"));
|
||||
usedImportList.append(Import::createLibraryImport("QtQuick", "2.0"));
|
||||
usedImportList.append(Import::createLibraryImport("QtQuick", "2.1"));
|
||||
|
||||
return usedImportList;
|
||||
return d->m_usedImportList;
|
||||
}
|
||||
|
||||
void Model::changeImports(const QList<Import> &importsToBeAdded, const QList<Import> &importsToBeRemoved)
|
||||
@@ -1757,6 +1744,16 @@ void Model::changeImports(const QList<Import> &importsToBeAdded, const QList<Imp
|
||||
d->changeImports(importsToBeAdded, importsToBeRemoved);
|
||||
}
|
||||
|
||||
void Model::setPossibleImports(const QList<Import> &possibleImports)
|
||||
{
|
||||
d->m_possibleImportList = possibleImports;
|
||||
}
|
||||
|
||||
void Model::setUsedImports(const QList<Import> &usedImports)
|
||||
{
|
||||
d->m_usedImportList = usedImports;
|
||||
}
|
||||
|
||||
|
||||
static bool compareVersions(const QString &version1, const QString &version2, bool allowHigherVersion)
|
||||
{
|
||||
|
||||
@@ -236,6 +236,8 @@ private:
|
||||
Model *m_q;
|
||||
MetaInfo m_metaInfo;
|
||||
QList<Import> m_imports;
|
||||
QList<Import> m_possibleImportList;
|
||||
QList<Import> m_usedImportList;
|
||||
QList<QWeakPointer<AbstractView> > m_viewList;
|
||||
QList<InternalNodePointer> m_selectedInternalNodeList;
|
||||
QHash<QString,InternalNodePointer> m_idNodeHash;
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <qmljs/qmljsutils.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
#include <qmljs/qmljsqrcparser.h>
|
||||
#include <qmljs/qmljsinterpreter.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
@@ -306,10 +307,10 @@ class ReadingContext
|
||||
{
|
||||
public:
|
||||
ReadingContext(const Snapshot &snapshot, const Document::Ptr &doc,
|
||||
const QStringList importPaths)
|
||||
const ViewerContext &vContext)
|
||||
: m_snapshot(snapshot)
|
||||
, m_doc(doc)
|
||||
, m_link(snapshot, importPaths,
|
||||
, m_link(snapshot, vContext,
|
||||
QmlJS::ModelManagerInterface::instance()->builtins(doc))
|
||||
, m_context(m_link(doc, &m_diagnosticLinkMessages))
|
||||
, m_scopeChain(doc, m_context)
|
||||
@@ -726,6 +727,67 @@ void TextToModelMerger::setupImports(const Document::Ptr &doc,
|
||||
differenceHandler.importAbsentInQMl(import);
|
||||
}
|
||||
|
||||
void TextToModelMerger::setupPossibleImports(const QmlJS::Snapshot &snapshot, const QmlJS::ViewerContext &viewContext)
|
||||
{
|
||||
QList<Import> possibleImports;
|
||||
|
||||
QSet<ImportKey> possibleImportKeys = snapshot.importDependencies()->libraryImports(viewContext);
|
||||
|
||||
QHash<QString, ImportKey> filteredPossibleImportKeys;
|
||||
foreach (const ImportKey &importKey, possibleImportKeys) {
|
||||
if (!filteredPossibleImportKeys.contains(importKey.path())
|
||||
|| filteredPossibleImportKeys.value(importKey.path()).majorVersion < importKey.majorVersion
|
||||
|| (filteredPossibleImportKeys.value(importKey.path()).majorVersion == importKey.majorVersion
|
||||
&& filteredPossibleImportKeys.value(importKey.path()).minorVersion < importKey.minorVersion))
|
||||
filteredPossibleImportKeys.insert(importKey.path(), importKey);
|
||||
}
|
||||
|
||||
filteredPossibleImportKeys.remove(QLatin1String("<cpp>"));
|
||||
filteredPossibleImportKeys.remove(QLatin1String("QML"));
|
||||
filteredPossibleImportKeys.remove(QLatin1String("QtQml"));
|
||||
filteredPossibleImportKeys.remove(QLatin1String("QtQuick/PrivateWidgets"));
|
||||
|
||||
QList<QmlJS::Import> allImports = m_scopeChain->context()->imports(m_document.data())->all();
|
||||
|
||||
foreach (const QmlJS::Import &import, allImports) {
|
||||
filteredPossibleImportKeys.remove(import.info.path());
|
||||
}
|
||||
|
||||
foreach (const ImportKey &importKey, filteredPossibleImportKeys) {
|
||||
QString libraryName = importKey.splitPath.join(QLatin1Char('.'));
|
||||
QString version = QString(QStringLiteral("%1.%2").arg(importKey.majorVersion).arg(importKey.minorVersion));
|
||||
possibleImports.append(Import::createLibraryImport(libraryName, version));
|
||||
}
|
||||
|
||||
if ( m_rewriterView->isAttached())
|
||||
m_rewriterView->model()->setPossibleImports(possibleImports);
|
||||
}
|
||||
|
||||
void TextToModelMerger::setupUsedImports()
|
||||
{
|
||||
QList<QmlJS::Import> allImports = m_scopeChain->context()->imports(m_document.data())->all();
|
||||
|
||||
QList<Import> usedImports;
|
||||
|
||||
foreach (const QmlJS::Import &import, allImports) {
|
||||
if (import.used) {
|
||||
if (import.info.type() == ImportType::Library) {
|
||||
usedImports.append(Import::createLibraryImport(import.info.name(), import.info.version().toString(), import.info.as()));
|
||||
} else if (import.info.type() == ImportType::Directory || import.info.type() == ImportType::File) {
|
||||
usedImports.append(Import::createFileImport(import.info.name(), import.info.version().toString(), import.info.as()));
|
||||
}
|
||||
}
|
||||
}
|
||||
// even if not explicitly used we probably want to keep QtQuick imports
|
||||
usedImports.append(Import::createLibraryImport("QtQuick", "1.0"));
|
||||
usedImports.append(Import::createLibraryImport("QtQuick", "1.1"));
|
||||
usedImports.append(Import::createLibraryImport("QtQuick", "2.0"));
|
||||
usedImports.append(Import::createLibraryImport("QtQuick", "2.1"));
|
||||
|
||||
if (m_rewriterView->isAttached())
|
||||
m_rewriterView->model()->setUsedImports(usedImports);
|
||||
}
|
||||
|
||||
bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceHandler)
|
||||
{
|
||||
// qDebug() << "TextToModelMerger::load with data:" << data;
|
||||
@@ -751,7 +813,11 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH
|
||||
return false;
|
||||
}
|
||||
snapshot.insert(doc);
|
||||
ReadingContext ctxt(snapshot, doc, importPaths);
|
||||
QmlJS::ViewerContext vContext;
|
||||
vContext.language = QmlJS::Language::Qml;
|
||||
vContext.paths = importPaths;
|
||||
vContext.flags = QmlJS::ViewerContext::Complete;
|
||||
ReadingContext ctxt(snapshot, doc, vContext);
|
||||
m_scopeChain = QSharedPointer<const ScopeChain>(
|
||||
new ScopeChain(ctxt.scopeChain()));
|
||||
m_document = doc;
|
||||
@@ -764,6 +830,8 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH
|
||||
}
|
||||
|
||||
setupImports(doc, differenceHandler);
|
||||
setupPossibleImports(snapshot, vContext);
|
||||
setupUsedImports();
|
||||
|
||||
if (m_rewriterView->model()->imports().isEmpty()) {
|
||||
const QmlJS::DiagnosticMessage diagnosticMessage(QmlJS::Severity::Error, AST::SourceLocation(0, 0, 0, 0), QCoreApplication::translate("QmlDesigner::TextToModelMerger", "No import statements found"));
|
||||
|
||||
@@ -59,6 +59,8 @@ public:
|
||||
bool isActive() const;
|
||||
|
||||
void setupImports(const QmlJS::Document::Ptr &doc, DifferenceHandler &differenceHandler);
|
||||
void setupPossibleImports(const QmlJS::Snapshot &snapshot, const QmlJS::ViewerContext &viewContext);
|
||||
void setupUsedImports();
|
||||
bool load(const QString &data, DifferenceHandler &differenceHandler);
|
||||
|
||||
RewriterView *view() const
|
||||
|
||||
@@ -831,7 +831,7 @@ static void find_helper(QFutureInterface<FindReferences::Usage> &future,
|
||||
|
||||
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
|
||||
|
||||
Link link(snapshot, modelManager->importPaths(), modelManager->builtins(doc));
|
||||
Link link(snapshot, modelManager->defaultVContext(), modelManager->builtins(doc));
|
||||
ContextPtr context = link();
|
||||
|
||||
ScopeChain scopeChain(doc, context);
|
||||
|
||||
@@ -122,7 +122,7 @@ QmlJSTools::SemanticInfo SemanticInfoUpdater::makeNewSemanticInfo(const QmlJS::D
|
||||
|
||||
ModelManagerInterface *modelManager = ModelManagerInterface::instance();
|
||||
|
||||
Link link(semanticInfo.snapshot, modelManager->importPaths(), modelManager->builtins(doc));
|
||||
Link link(semanticInfo.snapshot, modelManager->defaultVContext(), modelManager->builtins(doc));
|
||||
semanticInfo.context = link(doc, &semanticInfo.semanticMessages);
|
||||
|
||||
ScopeChain *scopeChain = new ScopeChain(doc, semanticInfo.context);
|
||||
|
||||
@@ -92,13 +92,13 @@ static QList<ProjectExplorer::Task> convertToTasks(const QList<StaticAnalysis::M
|
||||
void QmlTaskManager::collectMessages(
|
||||
QFutureInterface<FileErrorMessages> &future,
|
||||
Snapshot snapshot, QList<ModelManagerInterface::ProjectInfo> projectInfos,
|
||||
QStringList importPaths, bool updateSemantic)
|
||||
ViewerContext vContext, bool updateSemantic)
|
||||
{
|
||||
foreach (const ModelManagerInterface::ProjectInfo &info, projectInfos) {
|
||||
QHash<QString, QList<DiagnosticMessage> > linkMessages;
|
||||
ContextPtr context;
|
||||
if (updateSemantic) {
|
||||
Link link(snapshot, importPaths, snapshot.libraryInfo(info.qtImportsPath));
|
||||
Link link(snapshot, vContext, snapshot.libraryInfo(info.qtImportsPath));
|
||||
context = link(&linkMessages);
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ void QmlTaskManager::updateMessagesNow(bool updateSemantic)
|
||||
QFuture<FileErrorMessages> future =
|
||||
QtConcurrent::run<FileErrorMessages>(
|
||||
&collectMessages, modelManager->newestSnapshot(), modelManager->projectInfos(),
|
||||
modelManager->importPaths(), updateSemantic);
|
||||
modelManager->defaultVContext(), updateSemantic);
|
||||
m_messageCollector.setFuture(future);
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ private:
|
||||
static void collectMessages(QFutureInterface<FileErrorMessages> &future,
|
||||
QmlJS::Snapshot snapshot,
|
||||
QList<QmlJS::ModelManagerInterface::ProjectInfo> projectInfos,
|
||||
QStringList importPaths,
|
||||
QmlJS::ViewerContext vContext,
|
||||
bool updateSemantic);
|
||||
|
||||
private:
|
||||
|
||||
@@ -609,14 +609,12 @@ static LanguageUtils::FakeMetaObject::Ptr buildFakeMetaObject(
|
||||
BaseClass *base = klass->baseClassAt(0);
|
||||
if (!base->name())
|
||||
return fmo;
|
||||
|
||||
const QString baseClassName = namePrinter.prettyName(base->name());
|
||||
fmo->setSuperclassName(baseClassName);
|
||||
|
||||
Class *baseClass = lookupClass(baseClassName, klass, typeOf);
|
||||
if (!baseClass)
|
||||
return fmo;
|
||||
|
||||
buildFakeMetaObject(baseClass, fakeMetaObjects, typeOf);
|
||||
}
|
||||
|
||||
@@ -735,9 +733,11 @@ void FindExportedCppTypes::operator()(const CPlusPlus::Document::Ptr &document)
|
||||
|
||||
// convert to list of FakeMetaObject::ConstPtr
|
||||
m_exportedTypes.reserve(fakeMetaObjects.size());
|
||||
foreach (const LanguageUtils::FakeMetaObject::Ptr &fmo, fakeMetaObjects)
|
||||
foreach (const LanguageUtils::FakeMetaObject::Ptr &fmo, fakeMetaObjects) {
|
||||
fmo->updateFingerprint();
|
||||
m_exportedTypes += fmo;
|
||||
}
|
||||
}
|
||||
|
||||
QList<LanguageUtils::FakeMetaObject::ConstPtr> FindExportedCppTypes::exportedTypes() const
|
||||
{
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include <qtsupport/qmldumptool.h>
|
||||
#include <qtsupport/qtsupportconstants.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/function.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <QDir>
|
||||
@@ -360,7 +361,7 @@ QFuture<void> ModelManager::refreshSourceFiles(const QStringList &sourceFiles,
|
||||
|
||||
QFuture<void> result = QtConcurrent::run(&ModelManager::parse,
|
||||
workingCopy(), sourceFiles,
|
||||
this,
|
||||
this, Language::Qml,
|
||||
emitDocumentOnDiskChanged);
|
||||
|
||||
if (m_synchronizer.futures().size() > 10) {
|
||||
@@ -386,7 +387,7 @@ void ModelManager::fileChangedOnDisk(const QString &path)
|
||||
{
|
||||
QtConcurrent::run(&ModelManager::parse,
|
||||
workingCopy(), QStringList() << path,
|
||||
this, true);
|
||||
this, Language::Unknown, true);
|
||||
}
|
||||
|
||||
void ModelManager::removeFiles(const QStringList &files)
|
||||
@@ -700,7 +701,8 @@ static bool findNewQmlLibraryInPath(const QString &path,
|
||||
ModelManager *modelManager,
|
||||
QStringList *importedFiles,
|
||||
QSet<QString> *scannedPaths,
|
||||
QSet<QString> *newLibraries)
|
||||
QSet<QString> *newLibraries,
|
||||
bool ignoreMissing)
|
||||
{
|
||||
// if we know there is a library, done
|
||||
const LibraryInfo &existingInfo = snapshot.libraryInfo(path);
|
||||
@@ -715,8 +717,10 @@ static bool findNewQmlLibraryInPath(const QString &path,
|
||||
const QDir dir(path);
|
||||
QFile qmldirFile(dir.filePath(QLatin1String("qmldir")));
|
||||
if (!qmldirFile.exists()) {
|
||||
if (!ignoreMissing) {
|
||||
LibraryInfo libraryInfo(LibraryInfo::NotFound);
|
||||
modelManager->updateLibraryInfo(path, libraryInfo);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -765,18 +769,18 @@ static void findNewQmlLibrary(
|
||||
QString::number(version.minorVersion()));
|
||||
findNewQmlLibraryInPath(
|
||||
libraryPath, snapshot, modelManager,
|
||||
importedFiles, scannedPaths, newLibraries);
|
||||
importedFiles, scannedPaths, newLibraries, false);
|
||||
|
||||
libraryPath = QString::fromLatin1("%1.%2").arg(
|
||||
path,
|
||||
QString::number(version.majorVersion()));
|
||||
findNewQmlLibraryInPath(
|
||||
libraryPath, snapshot, modelManager,
|
||||
importedFiles, scannedPaths, newLibraries);
|
||||
importedFiles, scannedPaths, newLibraries, false);
|
||||
|
||||
findNewQmlLibraryInPath(
|
||||
path, snapshot, modelManager,
|
||||
importedFiles, scannedPaths, newLibraries);
|
||||
importedFiles, scannedPaths, newLibraries, false);
|
||||
}
|
||||
|
||||
static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snapshot,
|
||||
@@ -785,7 +789,7 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap
|
||||
{
|
||||
// scan current dir
|
||||
findNewQmlLibraryInPath(doc->path(), snapshot, modelManager,
|
||||
importedFiles, scannedPaths, newLibraries);
|
||||
importedFiles, scannedPaths, newLibraries, false);
|
||||
|
||||
// scan dir and lib imports
|
||||
const QStringList importPaths = modelManager->importPaths();
|
||||
@@ -793,7 +797,7 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap
|
||||
if (import.type() == ImportType::Directory) {
|
||||
const QString targetPath = import.path();
|
||||
findNewQmlLibraryInPath(targetPath, snapshot, modelManager,
|
||||
importedFiles, scannedPaths, newLibraries);
|
||||
importedFiles, scannedPaths, newLibraries, false);
|
||||
}
|
||||
|
||||
if (import.type() == ImportType::Library) {
|
||||
@@ -808,24 +812,18 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap
|
||||
}
|
||||
}
|
||||
|
||||
void ModelManager::parse(QFutureInterface<void> &future,
|
||||
void ModelManager::parseLoop(QSet<QString> &scannedPaths,
|
||||
QSet<QString> &newLibraries,
|
||||
WorkingCopy workingCopy,
|
||||
QStringList files,
|
||||
ModelManager *modelManager,
|
||||
bool emitDocChangedOnDisk)
|
||||
Language::Enum mainLanguage,
|
||||
bool emitDocChangedOnDisk,
|
||||
Utils::function<bool(qreal)> reportProgress)
|
||||
{
|
||||
int progressRange = files.size();
|
||||
future.setProgressRange(0, progressRange);
|
||||
|
||||
// paths we have scanned for files and added to the files list
|
||||
QSet<QString> scannedPaths;
|
||||
// libraries we've found while scanning imports
|
||||
QSet<QString> newLibraries;
|
||||
|
||||
for (int i = 0; i < files.size(); ++i) {
|
||||
if (future.isCanceled())
|
||||
break;
|
||||
future.setProgressValue(qreal(i) / files.size() * progressRange);
|
||||
if (!reportProgress(qreal(i) / files.size()))
|
||||
return;
|
||||
|
||||
const QString fileName = files.at(i);
|
||||
|
||||
@@ -835,7 +833,9 @@ void ModelManager::parse(QFutureInterface<void> &future,
|
||||
modelManager->updateQrcFile(fileName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (language == Language::Qml
|
||||
&& (mainLanguage == Language::QmlQtQuick1 || Language::QmlQtQuick2))
|
||||
language = mainLanguage;
|
||||
QString contents;
|
||||
int documentRevision = 0;
|
||||
|
||||
@@ -878,7 +878,116 @@ void ModelManager::parse(QFutureInterface<void> &future,
|
||||
if (emitDocChangedOnDisk)
|
||||
modelManager->emitDocumentChangedOnDisk(doc);
|
||||
}
|
||||
}
|
||||
|
||||
class FutureReporter
|
||||
{
|
||||
public:
|
||||
FutureReporter(QFutureInterface<void> &future, int multiplier = 100, int base = 0)
|
||||
:future(future), multiplier(multiplier), base(base)
|
||||
{ }
|
||||
bool operator()(qreal val)
|
||||
{
|
||||
if (future.isCanceled())
|
||||
return false;
|
||||
future.setProgressValue(int(base + multiplier * val));
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
QFutureInterface<void> &future;
|
||||
int multiplier;
|
||||
int base;
|
||||
};
|
||||
|
||||
void ModelManager::parse(QFutureInterface<void> &future,
|
||||
WorkingCopy workingCopy,
|
||||
QStringList files,
|
||||
ModelManager *modelManager,
|
||||
Language::Enum mainLanguage,
|
||||
bool emitDocChangedOnDisk)
|
||||
{
|
||||
FutureReporter reporter(future);
|
||||
future.setProgressRange(0, 100);
|
||||
|
||||
// paths we have scanned for files and added to the files list
|
||||
QSet<QString> scannedPaths;
|
||||
// libraries we've found while scanning imports
|
||||
QSet<QString> newLibraries;
|
||||
parseLoop(scannedPaths, newLibraries, workingCopy, files, modelManager, mainLanguage,
|
||||
emitDocChangedOnDisk, reporter);
|
||||
future.setProgressValue(100);
|
||||
}
|
||||
|
||||
struct ScanItem {
|
||||
QString path;
|
||||
int depth;
|
||||
ScanItem(QString path = QString(), int depth = 0)
|
||||
: path(path), depth(depth)
|
||||
{ }
|
||||
};
|
||||
|
||||
void ModelManager::importScan(QFutureInterface<void> &future,
|
||||
ModelManagerInterface::WorkingCopy workingCopy,
|
||||
QStringList paths, ModelManager *modelManager,
|
||||
Language::Enum language,
|
||||
bool emitDocChangedOnDisk)
|
||||
{
|
||||
// paths we have scanned for files and added to the files list
|
||||
QSet<QString> scannedPaths = modelManager->m_scannedPaths;
|
||||
// libraries we've found while scanning imports
|
||||
QSet<QString> newLibraries;
|
||||
|
||||
QVector<ScanItem> pathsToScan;
|
||||
pathsToScan.reserve(paths.size());
|
||||
foreach (const QString &path, paths) {
|
||||
QString cPath = QDir::cleanPath(path);
|
||||
if (modelManager->m_scannedPaths.contains(cPath))
|
||||
continue;
|
||||
pathsToScan.append(ScanItem(cPath));
|
||||
}
|
||||
const int maxScanDepth = 5;
|
||||
int progressRange = pathsToScan.size() * (1 << (2 + maxScanDepth));
|
||||
int totalWork(progressRange), workDone(0);
|
||||
future.setProgressRange(0, progressRange); // update max length while iterating?
|
||||
const bool libOnly = true; // FIXME remove when tested more
|
||||
while (!pathsToScan.isEmpty() && !future.isCanceled()) {
|
||||
ScanItem toScan = pathsToScan.last();
|
||||
pathsToScan.pop_back();
|
||||
int pathBudget = (maxScanDepth + 2 - toScan.depth);
|
||||
if (!scannedPaths.contains(toScan.path)) {
|
||||
QStringList importedFiles;
|
||||
const Snapshot snapshot = modelManager->snapshot();
|
||||
if (!findNewQmlLibraryInPath(toScan.path, snapshot, modelManager, &importedFiles,
|
||||
&scannedPaths, &newLibraries, true)
|
||||
&& !libOnly && snapshot.documentsInDirectory(toScan.path).isEmpty())
|
||||
importedFiles += qmlFilesInDirectory(toScan.path);
|
||||
workDone += 1;
|
||||
future.setProgressValue(progressRange * workDone / totalWork);
|
||||
if (!importedFiles.isEmpty()) {
|
||||
FutureReporter reporter(future, progressRange * pathBudget / (4 * totalWork),
|
||||
progressRange * workDone / totalWork);
|
||||
parseLoop(scannedPaths, newLibraries, workingCopy, importedFiles, modelManager,
|
||||
language, emitDocChangedOnDisk, reporter); // run in parallel??
|
||||
importedFiles.clear();
|
||||
}
|
||||
workDone += pathBudget / 4 - 1;
|
||||
future.setProgressValue(progressRange * workDone / totalWork);
|
||||
} else {
|
||||
workDone += pathBudget / 4;
|
||||
}
|
||||
// always descend tree, as we might have just scanned with a smaller depth
|
||||
if (toScan.depth < maxScanDepth) {
|
||||
QDir dir(toScan.path);
|
||||
QStringList subDirs(dir.entryList(QDir::Dirs));
|
||||
workDone += 1;
|
||||
totalWork += pathBudget / 2 * subDirs.size() - pathBudget * 3 / 4 + 1;
|
||||
foreach (const QString path, subDirs)
|
||||
pathsToScan.append(ScanItem(dir.absoluteFilePath(path), toScan.depth + 1));
|
||||
} else {
|
||||
workDone += pathBudget *3 / 4;
|
||||
}
|
||||
future.setProgressValue(progressRange * workDone / totalWork);
|
||||
}
|
||||
future.setProgressValue(progressRange);
|
||||
}
|
||||
|
||||
@@ -993,6 +1102,33 @@ void ModelManager::updateImportPaths()
|
||||
findNewLibraryImports(doc, snapshot, this, &importedFiles, &scannedPaths, &newLibraries);
|
||||
|
||||
updateSourceFiles(importedFiles, true);
|
||||
|
||||
QStringList pathToScan;
|
||||
foreach (QString importPath, allImportPaths)
|
||||
if (!m_scannedPaths.contains(importPath))
|
||||
pathToScan.append(importPath);
|
||||
|
||||
if (pathToScan.count() > 1) {
|
||||
QFuture<void> result = QtConcurrent::run(&ModelManager::importScan,
|
||||
workingCopy(), pathToScan,
|
||||
this, Language::Qml,
|
||||
true);
|
||||
|
||||
if (m_synchronizer.futures().size() > 10) {
|
||||
QList<QFuture<void> > futures = m_synchronizer.futures();
|
||||
|
||||
m_synchronizer.clearFutures();
|
||||
|
||||
foreach (const QFuture<void> &future, futures) {
|
||||
if (! (future.isFinished() || future.isCanceled()))
|
||||
m_synchronizer.addFuture(future);
|
||||
}
|
||||
}
|
||||
|
||||
m_synchronizer.addFuture(result);
|
||||
|
||||
ProgressManager::addTask(result, tr("Qml import scan"), Constants::TASK_IMPORT_SCAN);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelManager::loadPluginTypes(const QString &libraryPath, const QString &importPath,
|
||||
@@ -1121,6 +1257,35 @@ LibraryInfo ModelManager::builtins(const Document::Ptr &doc) const
|
||||
return _validSnapshot.libraryInfo(info.qtImportsPath);
|
||||
}
|
||||
|
||||
ViewerContext ModelManager::completeVContext(const ViewerContext &vCtx,
|
||||
const Document::Ptr &doc) const
|
||||
{
|
||||
Q_UNUSED(doc);
|
||||
ViewerContext res = vCtx;
|
||||
switch (res.flags) {
|
||||
case ViewerContext::Complete:
|
||||
break;
|
||||
case ViewerContext::AddQtPath:
|
||||
case ViewerContext::AddAllPaths:
|
||||
res.paths << importPaths();
|
||||
}
|
||||
res.flags = ViewerContext::Complete;
|
||||
return res;
|
||||
}
|
||||
|
||||
ViewerContext ModelManager::defaultVContext(bool autoComplete, const Document::Ptr &doc) const
|
||||
{
|
||||
if (autoComplete)
|
||||
return completeVContext(m_vContext, doc);
|
||||
else
|
||||
return m_vContext;
|
||||
}
|
||||
|
||||
void ModelManager::setDefaultVContext(const ViewerContext &vContext)
|
||||
{
|
||||
m_vContext = vContext;
|
||||
}
|
||||
|
||||
void ModelManager::joinAllThreads()
|
||||
{
|
||||
foreach (QFuture<void> future, m_synchronizer.futures())
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
#include <qmljs/qmljsqrcparser.h>
|
||||
#include <qmljs/qmljsconstants.h>
|
||||
|
||||
#include <cplusplus/CppDocument.h>
|
||||
#include <utils/qtcoverride.h>
|
||||
@@ -115,6 +116,14 @@ public:
|
||||
|
||||
QmlJS::LibraryInfo builtins(const QmlJS::Document::Ptr &doc) const QTC_OVERRIDE;
|
||||
|
||||
QmlJS::ViewerContext completeVContext(
|
||||
const QmlJS::ViewerContext &vCtx,
|
||||
const QmlJS::Document::Ptr &doc = QmlJS::Document::Ptr(0)) const QTC_OVERRIDE;
|
||||
QmlJS::ViewerContext defaultVContext(
|
||||
bool autoComplete = true,
|
||||
const QmlJS::Document::Ptr &doc = QmlJS::Document::Ptr(0)) const QTC_OVERRIDE;
|
||||
void setDefaultVContext(const QmlJS::ViewerContext &vContext) QTC_OVERRIDE;
|
||||
|
||||
void joinAllThreads() QTC_OVERRIDE;
|
||||
|
||||
public slots:
|
||||
@@ -127,10 +136,21 @@ protected:
|
||||
QFuture<void> refreshSourceFiles(const QStringList &sourceFiles,
|
||||
bool emitDocumentOnDiskChanged);
|
||||
|
||||
static void parseLoop(QSet<QString> &scannedPaths, QSet<QString> &newLibraries,
|
||||
WorkingCopy workingCopy, QStringList files, ModelManager *modelManager,
|
||||
QmlJS::Language::Enum mainLanguage, bool emitDocChangedOnDisk,
|
||||
Utils::function<bool (qreal)> reportProgress);
|
||||
static void parse(QFutureInterface<void> &future,
|
||||
WorkingCopy workingCopy,
|
||||
QStringList files,
|
||||
ModelManager *modelManager,
|
||||
QmlJS::Language::Enum mainLanguage,
|
||||
bool emitDocChangedOnDisk);
|
||||
static void importScan(QFutureInterface<void> &future,
|
||||
WorkingCopy workingCopy,
|
||||
QStringList paths,
|
||||
ModelManager *modelManager,
|
||||
QmlJS::Language::Enum mainLanguage,
|
||||
bool emitDocChangedOnDisk);
|
||||
|
||||
void loadQmlTypeDescriptions();
|
||||
@@ -158,6 +178,8 @@ private:
|
||||
QStringList m_defaultImportPaths;
|
||||
QmlJS::QmlLanguageBundles m_activeBundles;
|
||||
QmlJS::QmlLanguageBundles m_extendedBundles;
|
||||
QmlJS::ViewerContext m_vContext;
|
||||
QSet<QString> m_scannedPaths;
|
||||
|
||||
QTimer *m_updateCppQmlTypesTimer;
|
||||
QTimer *m_asyncResetTimer;
|
||||
|
||||
@@ -339,6 +339,7 @@ void PluginDumper::qmlPluginTypeDumpDone(int exitCode)
|
||||
if (!warning.isEmpty())
|
||||
printParseWarnings(libraryPath, warning);
|
||||
}
|
||||
libraryInfo.updateFingerprint();
|
||||
|
||||
m_modelManager->updateLibraryInfo(libraryPath, libraryInfo);
|
||||
}
|
||||
@@ -361,6 +362,7 @@ void PluginDumper::qmlPluginTypeDumpError(QProcess::ProcessError)
|
||||
const Snapshot snapshot = m_modelManager->snapshot();
|
||||
LibraryInfo libraryInfo = snapshot.libraryInfo(libraryPath);
|
||||
libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError, qmldumpFailedMessage(libraryPath, errorMessages));
|
||||
libraryInfo.updateFingerprint();
|
||||
m_modelManager->updateLibraryInfo(libraryPath, libraryInfo);
|
||||
}
|
||||
}
|
||||
@@ -418,6 +420,7 @@ void PluginDumper::loadQmltypesFile(const QStringList &qmltypesFilePaths,
|
||||
if (!warnings.isEmpty())
|
||||
printParseWarnings(libraryPath, warnings.join(QLatin1String("\n")));
|
||||
|
||||
libraryInfo.updateFingerprint();
|
||||
m_modelManager->updateLibraryInfo(libraryPath, libraryInfo);
|
||||
}
|
||||
|
||||
@@ -456,6 +459,7 @@ void PluginDumper::dump(const Plugin &plugin)
|
||||
}
|
||||
|
||||
libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError, errorMessage);
|
||||
libraryInfo.updateFingerprint();
|
||||
m_modelManager->updateLibraryInfo(plugin.qmldirPath, libraryInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ void QmlJSTools::Internal::QmlJSToolsPlugin::test_basic()
|
||||
Document::Ptr doc = snapshot.document(welcomescreenRootPath);
|
||||
QVERIFY(doc && doc->isQmlDocument());
|
||||
|
||||
ContextPtr context = Link(snapshot, QStringList(), LibraryInfo())();
|
||||
ContextPtr context = Link(snapshot, ViewerContext(), LibraryInfo())();
|
||||
QVERIFY(context);
|
||||
|
||||
const CppComponentValue *rectangleValue = context->valueOwner()->cppQmlTypes().objectByQualifiedName(
|
||||
|
||||
@@ -43,6 +43,7 @@ const char JS_MIMETYPE[] = "application/javascript";
|
||||
const char JSON_MIMETYPE[] = "application/json";
|
||||
|
||||
const char TASK_INDEX[] = "QmlJSEditor.TaskIndex";
|
||||
const char TASK_IMPORT_SCAN[] = "QmlJSEditor.TaskImportScan";
|
||||
|
||||
const char QML_JS_CODE_STYLE_SETTINGS_ID[] = "A.Code Style";
|
||||
const char QML_JS_CODE_STYLE_SETTINGS_NAME[] = QT_TRANSLATE_NOOP("QmlJSTools", "Code Style");
|
||||
|
||||
@@ -92,6 +92,13 @@ void QmlProfilerCanvas::componentComplete()
|
||||
QMetaObject::connect(this, p.notifySignalIndex(), this, requestPaintMethod, 0, 0);
|
||||
}
|
||||
QQuickItem::componentComplete();
|
||||
requestRedraw();
|
||||
}
|
||||
|
||||
void QmlProfilerCanvas::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
|
||||
{
|
||||
QQuickItem::geometryChanged(newGeometry, oldGeometry);
|
||||
requestRedraw();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ private slots:
|
||||
protected:
|
||||
virtual void paint(QPainter *);
|
||||
virtual void componentComplete();
|
||||
virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
|
||||
|
||||
private:
|
||||
Context2D *m_context2d;
|
||||
|
||||
@@ -330,6 +330,7 @@ Rectangle {
|
||||
contentWidth: 0
|
||||
height: labels.height + labelsTail.height
|
||||
flickableDirection: Flickable.HorizontalFlick
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
onContentXChanged: view.updateZoomControl()
|
||||
clip:true
|
||||
|
||||
@@ -69,6 +69,11 @@ RangeMover {
|
||||
}
|
||||
|
||||
function setPos(pos) {
|
||||
if (pos < 0)
|
||||
pos = 0;
|
||||
else if (pos > width)
|
||||
pos = width;
|
||||
|
||||
switch (creationState) {
|
||||
case 1: {
|
||||
setLeft(pos);
|
||||
|
||||
@@ -38,17 +38,6 @@ Canvas2D {
|
||||
property real endTime : 0
|
||||
property real timePerPixel: 0
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
requestRedraw();
|
||||
}
|
||||
onWidthChanged: {
|
||||
requestRedraw();
|
||||
}
|
||||
onHeightChanged: {
|
||||
requestRedraw();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: zoomControl
|
||||
onRangeChanged: {
|
||||
|
||||
@@ -38,21 +38,6 @@ Canvas2D {
|
||||
property real endTime
|
||||
property real timePerPixel
|
||||
|
||||
Component.onCompleted: {
|
||||
requestRedraw();
|
||||
}
|
||||
|
||||
onWidthChanged: {
|
||||
requestRedraw();
|
||||
}
|
||||
onHeightChanged: {
|
||||
requestRedraw();
|
||||
}
|
||||
|
||||
onYChanged: {
|
||||
requestRedraw();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: labels
|
||||
onHeightChanged: { requestRedraw(); }
|
||||
|
||||
@@ -73,27 +73,27 @@ BlackBerryConfiguration::BlackBerryConfiguration(const FileName &ndkEnvFile, boo
|
||||
m_qnxEnv = QnxUtils::qnxEnvironmentFromNdkFile(m_ndkEnvFile.toString());
|
||||
|
||||
QString ndkTarget;
|
||||
QString qnxHost;
|
||||
foreach (const Utils::EnvironmentItem &item, m_qnxEnv) {
|
||||
if (item.name == QLatin1String("QNX_TARGET"))
|
||||
ndkTarget = item.value;
|
||||
|
||||
else if (item.name == QLatin1String("QNX_HOST"))
|
||||
qnxHost = item.value;
|
||||
m_qnxHost = item.value;
|
||||
|
||||
}
|
||||
|
||||
QString sep = QString::fromLatin1("%1qnx6").arg(QDir::separator());
|
||||
m_targetName = ndkTarget.split(sep).first().split(QDir::separator()).last();
|
||||
// The QNX_TARGET value is using Unix-like separator on all platforms.
|
||||
QString sep = QString::fromLatin1("/qnx6");
|
||||
m_targetName = ndkTarget.split(sep).first().split(QLatin1Char('/')).last();
|
||||
|
||||
if (QDir(ndkTarget).exists())
|
||||
m_sysRoot = FileName::fromString(ndkTarget);
|
||||
|
||||
FileName qmake4Path = QnxUtils::executableWithExtension(FileName::fromString(qnxHost + QLatin1String("/usr/bin/qmake")));
|
||||
FileName qmake5Path = QnxUtils::executableWithExtension(FileName::fromString(qnxHost + QLatin1String("/usr/bin/qt5/qmake")));
|
||||
FileName gccPath = QnxUtils::executableWithExtension(FileName::fromString(qnxHost + QLatin1String("/usr/bin/qcc")));
|
||||
FileName deviceGdbPath = QnxUtils::executableWithExtension(FileName::fromString(qnxHost + QLatin1String("/usr/bin/ntoarm-gdb")));
|
||||
FileName simulatorGdbPath = QnxUtils::executableWithExtension(FileName::fromString(qnxHost + QLatin1String("/usr/bin/ntox86-gdb")));
|
||||
FileName qmake4Path = QnxUtils::executableWithExtension(FileName::fromString(m_qnxHost + QLatin1String("/usr/bin/qmake")));
|
||||
FileName qmake5Path = QnxUtils::executableWithExtension(FileName::fromString(m_qnxHost + QLatin1String("/usr/bin/qt5/qmake")));
|
||||
FileName gccPath = QnxUtils::executableWithExtension(FileName::fromString(m_qnxHost + QLatin1String("/usr/bin/qcc")));
|
||||
FileName deviceGdbPath = QnxUtils::executableWithExtension(FileName::fromString(m_qnxHost + QLatin1String("/usr/bin/ntoarm-gdb")));
|
||||
FileName simulatorGdbPath = QnxUtils::executableWithExtension(FileName::fromString(m_qnxHost + QLatin1String("/usr/bin/ntox86-gdb")));
|
||||
|
||||
if (qmake4Path.toFileInfo().exists())
|
||||
m_qmake4BinaryFile = qmake4Path;
|
||||
@@ -126,6 +126,11 @@ QString BlackBerryConfiguration::targetName() const
|
||||
return m_targetName;
|
||||
}
|
||||
|
||||
QString BlackBerryConfiguration::qnxHost() const
|
||||
{
|
||||
return m_qnxHost;
|
||||
}
|
||||
|
||||
bool BlackBerryConfiguration::isAutoDetected() const
|
||||
{
|
||||
return m_isAutoDetected;
|
||||
|
||||
@@ -66,6 +66,7 @@ public:
|
||||
QString ndkPath() const;
|
||||
QString displayName() const;
|
||||
QString targetName() const;
|
||||
QString qnxHost() const;
|
||||
bool isAutoDetected() const;
|
||||
bool isActive() const;
|
||||
bool isValid() const;
|
||||
@@ -81,6 +82,7 @@ public:
|
||||
private:
|
||||
QString m_displayName;
|
||||
QString m_targetName;
|
||||
QString m_qnxHost;
|
||||
bool m_isAutoDetected;
|
||||
Utils::FileName m_ndkEnvFile;
|
||||
Utils::FileName m_qmake4BinaryFile;
|
||||
|
||||
@@ -64,10 +64,13 @@ NdkPathChooser::NdkPathChooser(Mode mode, QWidget *parent)
|
||||
: Utils::PathChooser(parent)
|
||||
, m_mode(mode)
|
||||
{
|
||||
if (m_mode == NdkPathChooser::InstallMode)
|
||||
if (m_mode == NdkPathChooser::InstallMode) {
|
||||
setExpectedKind(Utils::PathChooser::Directory);
|
||||
else
|
||||
} else {
|
||||
setExpectedKind(Utils::PathChooser::File);
|
||||
setPromptDialogFilter(Utils::HostOsInfo::isWindowsHost() ? QLatin1String("*.bat") :
|
||||
QLatin1String("*.sh"));
|
||||
}
|
||||
}
|
||||
|
||||
bool NdkPathChooser::validatePath(const QString &path, QString *errorMessage)
|
||||
@@ -80,7 +83,10 @@ bool NdkPathChooser::validatePath(const QString &path, QString *errorMessage)
|
||||
return !(QnxUtils::sdkInstallerPath(path).isEmpty());
|
||||
|
||||
QFileInfo fi(path);
|
||||
return (fi.suffix() == QLatin1String("sh") || fi.suffix() == QLatin1String("bat"));
|
||||
if (Utils::HostOsInfo::isWindowsHost())
|
||||
return fi.suffix() == QLatin1String("bat");
|
||||
|
||||
return fi.suffix() == QLatin1String("sh");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
||||