Merge remote-tracking branch 'origin/3.0'

This commit is contained in:
Eike Ziller
2013-11-22 09:11:51 +01:00
105 changed files with 2534 additions and 463 deletions

BIN
doc/images/analyzer-issues.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 30 KiB

BIN
doc/images/qtcreator-analyze-menu.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 26 KiB

BIN
doc/images/qtcreator-qml-performance-monitor.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 81 KiB

BIN
doc/images/qtcreator-valgrind-callgrind.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 85 KiB

BIN
doc/images/qtcreator-valgrind-memcheck-options.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -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}.

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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())

View File

@@ -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():

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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);

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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

View File

@@ -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"
]
}

View File

@@ -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,
};
}

View File

@@ -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)
{
}

View File

@@ -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;
};

View File

@@ -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));
}

View File

@@ -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;

View 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

View 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

View File

@@ -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

View File

@@ -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()

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}

View 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

View 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

View File

@@ -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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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());

View File

@@ -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();

View File

@@ -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()

View File

@@ -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)));

View File

@@ -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()) {

View File

@@ -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;

View File

@@ -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>

View 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 {

View File

@@ -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

View File

@@ -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;
}
/*!

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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

View File

@@ -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;
};
}

View File

@@ -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;

View File

@@ -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

View File

@@ -169,6 +169,7 @@ CppEditorSupport::~CppEditorSupport()
m_highlighter.cancel();
m_futureSemanticInfo.cancel();
m_documentParser.waitForFinished();
m_highlighter.waitForFinished();
m_futureSemanticInfo.waitForFinished();
}

View File

@@ -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;

View File

@@ -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));
}
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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)) {

View File

@@ -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);

View File

@@ -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>();

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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"));

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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:

View File

@@ -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
{

View File

@@ -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())

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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(

View File

@@ -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");

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -330,6 +330,7 @@ Rectangle {
contentWidth: 0
height: labels.height + labelsTail.height
flickableDirection: Flickable.HorizontalFlick
boundsBehavior: Flickable.StopAtBounds
onContentXChanged: view.updateZoomControl()
clip:true

View File

@@ -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);

View File

@@ -38,17 +38,6 @@ Canvas2D {
property real endTime : 0
property real timePerPixel: 0
Component.onCompleted: {
requestRedraw();
}
onWidthChanged: {
requestRedraw();
}
onHeightChanged: {
requestRedraw();
}
Connections {
target: zoomControl
onRangeChanged: {

View File

@@ -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(); }

View File

@@ -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;

View File

@@ -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;

View File

@@ -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");
}
//------------------------------------------------------------------

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