forked from qt-creator/qt-creator
Debugger: Use primitive internal widget instead of matplotview
This practically removes any functionality beyond plain plot display, but does that at least reliably, cross-platform, without dependency on 3rd party python packages. Change-Id: Iaff2f78595394522f32264c642df20dd48b83f8b Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
@@ -36,13 +36,6 @@ import re
|
|||||||
import time
|
import time
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
try:
|
|
||||||
import subprocess
|
|
||||||
hasSubprocess = True
|
|
||||||
except:
|
|
||||||
hasSubprocess = False
|
|
||||||
hasPlot = False
|
|
||||||
|
|
||||||
if sys.version_info[0] >= 3:
|
if sys.version_info[0] >= 3:
|
||||||
xrange = range
|
xrange = range
|
||||||
toInteger = int
|
toInteger = int
|
||||||
@@ -105,81 +98,53 @@ WatchpointAtExpression, \
|
|||||||
BreakpointOnQmlSignalEmit, \
|
BreakpointOnQmlSignalEmit, \
|
||||||
BreakpointAtJavaScriptThrow, \
|
BreakpointAtJavaScriptThrow, \
|
||||||
= range(0, 14)
|
= range(0, 14)
|
||||||
#
|
|
||||||
# matplot based display for array-like structures.
|
|
||||||
#
|
|
||||||
try:
|
|
||||||
import matplotlib
|
|
||||||
hasPlot = True
|
|
||||||
except:
|
|
||||||
hasPlot = False
|
|
||||||
|
|
||||||
if hasSubprocess and hasPlot:
|
# Encodings. Keep that synchronized with DebuggerEncoding in debuggerprotocol.h
|
||||||
matplotFigure = {}
|
Unencoded8Bit, \
|
||||||
matplotCount = 0
|
Base64Encoded8BitWithQuotes, \
|
||||||
matplotProc = None
|
Base64Encoded16BitWithQuotes, \
|
||||||
devNull = None
|
Base64Encoded32BitWithQuotes, \
|
||||||
|
Base64Encoded16Bit, \
|
||||||
|
Base64Encoded8Bit, \
|
||||||
|
Hex2EncodedLatin1, \
|
||||||
|
Hex4EncodedLittleEndian, \
|
||||||
|
Hex8EncodedLittleEndian, \
|
||||||
|
Hex2EncodedUtf8, \
|
||||||
|
Hex8EncodedBigEndian, \
|
||||||
|
Hex4EncodedBigEndian, \
|
||||||
|
Hex4EncodedLittleEndianWithoutQuotes, \
|
||||||
|
Hex2EncodedLocal8Bit, \
|
||||||
|
JulianDate, \
|
||||||
|
MillisecondsSinceMidnight, \
|
||||||
|
JulianDateAndMillisecondsSinceMidnight, \
|
||||||
|
Hex2EncodedInt1, \
|
||||||
|
Hex2EncodedInt2, \
|
||||||
|
Hex2EncodedInt4, \
|
||||||
|
Hex2EncodedInt8, \
|
||||||
|
Hex2EncodedUInt1, \
|
||||||
|
Hex2EncodedUInt2, \
|
||||||
|
Hex2EncodedUInt4, \
|
||||||
|
Hex2EncodedUInt8, \
|
||||||
|
Hex2EncodedFloat4, \
|
||||||
|
Hex2EncodedFloat8, \
|
||||||
|
IPv6AddressAndHexScopeId, \
|
||||||
|
Hex2EncodedUtf8WithoutQuotes, \
|
||||||
|
DateTimeInternal \
|
||||||
|
= range(30)
|
||||||
|
|
||||||
def matplotInit():
|
# Display modes. Keep that synchronized with DebuggerDisplay in watchutils.h
|
||||||
global matplotProc
|
StopDisplay, \
|
||||||
global devNull
|
DisplayImageData, \
|
||||||
|
DisplayUtf16String, \
|
||||||
|
DisplayImageFile, \
|
||||||
|
DisplayLatin1String, \
|
||||||
|
DisplayUtf8String, \
|
||||||
|
DisplayPlotData \
|
||||||
|
= range(7)
|
||||||
|
|
||||||
if matplotProc is None:
|
|
||||||
devNull = open(os.devnull)
|
|
||||||
# FIXME: That might not be the one we want.
|
|
||||||
pythonExecutable = sys.executable
|
|
||||||
matplotProc = subprocess.Popen(args=[pythonExecutable, "-i"],
|
|
||||||
bufsize=0, stdin=subprocess.PIPE, stdout=devNull, stderr=devNull)
|
|
||||||
|
|
||||||
matplotProc.stdin.write(b"import sys\n")
|
|
||||||
matplotProc.stdin.write(b"sys.ps1=''\n")
|
|
||||||
matplotProc.stdin.write(b"from matplotlib import pyplot\n")
|
|
||||||
matplotProc.stdin.write(b"import time\n")
|
|
||||||
matplotProc.stdin.write(b"pyplot.ion()\n")
|
|
||||||
matplotProc.stdin.flush()
|
|
||||||
|
|
||||||
def matplotSend(iname, show, data):
|
|
||||||
global matplotFigure
|
|
||||||
global matplotCount
|
|
||||||
|
|
||||||
matplotInit()
|
|
||||||
|
|
||||||
def s(line):
|
|
||||||
matplotProc.stdin.write(line.encode("latin1"))
|
|
||||||
matplotProc.stdin.write(b"\n")
|
|
||||||
sys.stdout.flush()
|
|
||||||
matplotProc.stdin.flush()
|
|
||||||
|
|
||||||
if show:
|
|
||||||
s("pyplot.ion()")
|
|
||||||
if not iname in matplotFigure:
|
|
||||||
matplotCount += 1
|
|
||||||
matplotFigure[iname] = matplotCount
|
|
||||||
s("pyplot.figure(%s)" % matplotFigure[iname])
|
|
||||||
s("pyplot.suptitle('%s')" % iname)
|
|
||||||
s("data = %s" % data)
|
|
||||||
s("pyplot.plot([i for i in range(len(data))], data, 'b.-')")
|
|
||||||
time.sleep(0.2)
|
|
||||||
s("pyplot.draw()")
|
|
||||||
matplotProc.stdin.flush()
|
|
||||||
else:
|
|
||||||
if iname in matplotFigure:
|
|
||||||
s("pyplot.figure(%s)" % matplotFigure[iname])
|
|
||||||
s("pyplot.close()")
|
|
||||||
del matplotFigure[iname]
|
|
||||||
|
|
||||||
matplotProc.stdin.flush()
|
|
||||||
|
|
||||||
def matplotQuit():
|
|
||||||
global matplotProc
|
|
||||||
if not matplotProc is None:
|
|
||||||
matplotProc.stdin.write(b"exit")
|
|
||||||
matplotProc.kill()
|
|
||||||
devNull.close()
|
|
||||||
|
|
||||||
def arrayForms():
|
def arrayForms():
|
||||||
global hasPlot
|
return [ArrayPlotFormat]
|
||||||
return [ArrayPlotFormat] if hasPlot else []
|
|
||||||
|
|
||||||
def mapForms():
|
def mapForms():
|
||||||
return [CompactMapFormat]
|
return [CompactMapFormat]
|
||||||
@@ -612,10 +577,7 @@ class DumperBase:
|
|||||||
self.putNumChild(0)
|
self.putNumChild(0)
|
||||||
self.putValue(mem, encodingType, elided=elided)
|
self.putValue(mem, encodingType, elided=elided)
|
||||||
|
|
||||||
if displayFormat == Latin1StringFormat \
|
if displayFormat == SeparateLatin1StringFormat \
|
||||||
or displayFormat == Utf8StringFormat:
|
|
||||||
self.putDisplay(StopDisplay)
|
|
||||||
elif displayFormat == SeparateLatin1StringFormat \
|
|
||||||
or displayFormat == SeparateUtf8StringFormat:
|
or displayFormat == SeparateUtf8StringFormat:
|
||||||
self.putField("editformat", displayType)
|
self.putField("editformat", displayType)
|
||||||
elided, shown = self.computeLimit(bytelen, 100000)
|
elided, shown = self.computeLimit(bytelen, 100000)
|
||||||
@@ -916,14 +878,14 @@ class DumperBase:
|
|||||||
def putCStyleArray(self, value):
|
def putCStyleArray(self, value):
|
||||||
arrayType = value.type.unqualified()
|
arrayType = value.type.unqualified()
|
||||||
innerType = value[0].type
|
innerType = value[0].type
|
||||||
|
innerTypeName = str(innerType.unqualified())
|
||||||
ts = innerType.sizeof
|
ts = innerType.sizeof
|
||||||
#self.putAddress(value.address)
|
|
||||||
try:
|
try:
|
||||||
self.putValue("@0x%x" % self.addressOf(value), priority = -1)
|
self.putValue("@0x%x" % self.addressOf(value), priority = -1)
|
||||||
except:
|
except:
|
||||||
self.putEmptyValue()
|
self.putEmptyValue()
|
||||||
self.putType(arrayType)
|
self.putType(arrayType)
|
||||||
self.putNumChild(1)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
p = self.addressOf(value)
|
p = self.addressOf(value)
|
||||||
@@ -933,20 +895,20 @@ class DumperBase:
|
|||||||
displayFormat = self.currentItemFormat()
|
displayFormat = self.currentItemFormat()
|
||||||
n = int(arrayType.sizeof / ts)
|
n = int(arrayType.sizeof / ts)
|
||||||
|
|
||||||
if p and self.tryPutSimpleFormattedPointer(p, str(arrayType), displayFormat, arrayType.sizeof):
|
if displayFormat != RawFormat:
|
||||||
self.putNumChild(n)
|
|
||||||
pass
|
|
||||||
elif displayFormat is None:
|
|
||||||
innerTypeName = str(innerType.unqualified())
|
|
||||||
blob = self.readMemory(self.addressOf(value), arrayType.sizeof)
|
|
||||||
if innerTypeName == "char":
|
if innerTypeName == "char":
|
||||||
# Use Latin1 as default for char [].
|
# Use Latin1 as default for char [].
|
||||||
|
blob = self.readMemory(self.addressOf(value), arrayType.sizeof)
|
||||||
self.putValue(blob, Hex2EncodedLatin1)
|
self.putValue(blob, Hex2EncodedLatin1)
|
||||||
elif innerTypeName == "wchar_t":
|
elif innerTypeName == "wchar_t":
|
||||||
|
blob = self.readMemory(self.addressOf(value), arrayType.sizeof)
|
||||||
if innerType.sizeof == 2:
|
if innerType.sizeof == 2:
|
||||||
self.putValue(blob, Hex4EncodedLittleEndian)
|
self.putValue(blob, Hex4EncodedLittleEndian)
|
||||||
else:
|
else:
|
||||||
self.putValue(blob, Hex8EncodedLittleEndian)
|
self.putValue(blob, Hex8EncodedLittleEndian)
|
||||||
|
elif p:
|
||||||
|
self.tryPutSimpleFormattedPointer(p, arrayType, innerTypeName, displayFormat, arrayType.sizeof)
|
||||||
|
self.putNumChild(n)
|
||||||
|
|
||||||
if self.isExpanded():
|
if self.isExpanded():
|
||||||
try:
|
try:
|
||||||
@@ -958,17 +920,7 @@ class DumperBase:
|
|||||||
with Children(self, childType=innerType):
|
with Children(self, childType=innerType):
|
||||||
self.putFields(value)
|
self.putFields(value)
|
||||||
|
|
||||||
if hasPlot and self.isSimpleType(innerType):
|
self.putPlotDataHelper(p, n, innerType)
|
||||||
show = displayFormat == ArrayPlotFormat
|
|
||||||
iname = self.currentIName
|
|
||||||
data = []
|
|
||||||
if show:
|
|
||||||
base = self.createPointerValue(p, innerType)
|
|
||||||
data = [str(base[i]) for i in range(0, n)]
|
|
||||||
matplotSend(iname, show, data)
|
|
||||||
else:
|
|
||||||
#self.putValue(self.currentValue.value + " (not plottable)")
|
|
||||||
self.putField("plottable", "0")
|
|
||||||
|
|
||||||
def cleanAddress(self, addr):
|
def cleanAddress(self, addr):
|
||||||
if addr is None:
|
if addr is None:
|
||||||
@@ -1038,29 +990,23 @@ class DumperBase:
|
|||||||
data = self.readMemory(base, shown)
|
data = self.readMemory(base, shown)
|
||||||
self.putValue(data, Hex2EncodedLatin1, elided=elided)
|
self.putValue(data, Hex2EncodedLatin1, elided=elided)
|
||||||
|
|
||||||
def putDisplay(self, editFormat, value = None, cmd = None):
|
def putDisplay(self, editFormat, value):
|
||||||
self.put('editformat="%s",' % editFormat)
|
self.put('editformat="%s",' % editFormat)
|
||||||
if cmd is None:
|
|
||||||
if not value is None:
|
|
||||||
self.put('editvalue="%s",' % value)
|
self.put('editvalue="%s",' % value)
|
||||||
else:
|
|
||||||
self.put('editvalue="%s|%s",' % (cmd, value))
|
|
||||||
|
|
||||||
# This is shared by pointer and array formatting.
|
# This is shared by pointer and array formatting.
|
||||||
def tryPutSimpleFormattedPointer(self, value, typeName, displayFormat, limit):
|
def tryPutSimpleFormattedPointer(self, value, typeName, innerTypeName, displayFormat, limit):
|
||||||
if displayFormat == AutomaticFormat and typeName == "char":
|
if displayFormat == AutomaticFormat and innerTypeName == "char":
|
||||||
# Use Latin1 as default for char *.
|
# Use Latin1 as default for char *.
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
(elided, data) = self.encodeCArray(value, 1, limit)
|
(elided, data) = self.encodeCArray(value, 1, limit)
|
||||||
self.putValue(data, Hex2EncodedLatin1, elided=elided)
|
self.putValue(data, Hex2EncodedLatin1, elided=elided)
|
||||||
self.putDisplay(StopDisplay)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if displayFormat == Latin1StringFormat:
|
if displayFormat == Latin1StringFormat:
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
(elided, data) = self.encodeCArray(value, 1, limit)
|
(elided, data) = self.encodeCArray(value, 1, limit)
|
||||||
self.putValue(data, Hex2EncodedLatin1, elided=elided)
|
self.putValue(data, Hex2EncodedLatin1, elided=elided)
|
||||||
self.putDisplay(StopDisplay)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if displayFormat == SeparateLatin1StringFormat:
|
if displayFormat == SeparateLatin1StringFormat:
|
||||||
@@ -1074,7 +1020,6 @@ class DumperBase:
|
|||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
(elided, data) = self.encodeCArray(value, 1, limit)
|
(elided, data) = self.encodeCArray(value, 1, limit)
|
||||||
self.putValue(data, Hex2EncodedUtf8, elided=elided)
|
self.putValue(data, Hex2EncodedUtf8, elided=elided)
|
||||||
self.putDisplay(StopDisplay)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if displayFormat == SeparateUtf8StringFormat:
|
if displayFormat == SeparateUtf8StringFormat:
|
||||||
@@ -1088,21 +1033,18 @@ class DumperBase:
|
|||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
(elided, data) = self.encodeCArray(value, 1, limit)
|
(elided, data) = self.encodeCArray(value, 1, limit)
|
||||||
self.putValue(data, Hex2EncodedLocal8Bit, elided=elided)
|
self.putValue(data, Hex2EncodedLocal8Bit, elided=elided)
|
||||||
self.putDisplay(StopDisplay)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if displayFormat == Utf16StringFormat:
|
if displayFormat == Utf16StringFormat:
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
(elided, data) = self.encodeCArray(value, 2, limit)
|
(elided, data) = self.encodeCArray(value, 2, limit)
|
||||||
self.putValue(data, Hex4EncodedLittleEndian, elided=elided)
|
self.putValue(data, Hex4EncodedLittleEndian, elided=elided)
|
||||||
self.putDisplay(StopDisplay)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if displayFormat == Ucs4StringFormat:
|
if displayFormat == Ucs4StringFormat:
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
(elided, data) = self.encodeCArray(value, 4, limit)
|
(elided, data) = self.encodeCArray(value, 4, limit)
|
||||||
self.putValue(data, Hex8EncodedLittleEndian, elided=elided)
|
self.putValue(data, Hex8EncodedLittleEndian, elided=elided)
|
||||||
self.putDisplay(StopDisplay)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@@ -1155,7 +1097,7 @@ class DumperBase:
|
|||||||
if displayFormat == SeparateLatin1StringFormat \
|
if displayFormat == SeparateLatin1StringFormat \
|
||||||
or displayFormat == SeparateUtf8StringFormat:
|
or displayFormat == SeparateUtf8StringFormat:
|
||||||
limit = 1000000
|
limit = 1000000
|
||||||
if self.tryPutSimpleFormattedPointer(value, typeName, displayFormat, limit):
|
if self.tryPutSimpleFormattedPointer(value, typeName, innerTypeName, displayFormat, limit):
|
||||||
self.putNumChild(0)
|
self.putNumChild(0)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -1555,22 +1497,18 @@ class DumperBase:
|
|||||||
self.putArrayData(addr, n, self.lookupType(typeName))
|
self.putArrayData(addr, n, self.lookupType(typeName))
|
||||||
self.putAddress(addr)
|
self.putAddress(addr)
|
||||||
|
|
||||||
def putPlotData(self, base, n, typeobj):
|
def putPlotDataHelper(self, base, n, innerType):
|
||||||
|
if self.currentItemFormat() == ArrayPlotFormat and self.isSimpleType(innerType):
|
||||||
|
enc = self.simpleEncoding(innerType)
|
||||||
|
if enc:
|
||||||
|
self.putField("editencoding", enc)
|
||||||
|
self.putField("editvalue", self.readMemory(base, n * innerType.sizeof))
|
||||||
|
self.putField("editformat", DisplayPlotData)
|
||||||
|
|
||||||
|
def putPlotData(self, base, n, innerType):
|
||||||
|
self.putPlotDataHelper(base, n, innerType)
|
||||||
if self.isExpanded():
|
if self.isExpanded():
|
||||||
self.putArrayData(base, n, typeobj)
|
self.putArrayData(base, n, innerType)
|
||||||
if hasPlot:
|
|
||||||
if self.isSimpleType(typeobj):
|
|
||||||
show = self.currentItemFormat() == ArrayPlotFormat
|
|
||||||
iname = self.currentIName
|
|
||||||
data = []
|
|
||||||
if show:
|
|
||||||
base = self.createPointerValue(base, typeobj)
|
|
||||||
data = [str(base[i]) for i in range(0, toInteger(n))]
|
|
||||||
matplotSend(iname, show, data)
|
|
||||||
else:
|
|
||||||
#self.putValue(self.currentValue.value + " (not plottable)")
|
|
||||||
self.putValue(self.currentValue.value)
|
|
||||||
self.putField("plottable", "0")
|
|
||||||
|
|
||||||
def putSpecialArgv(self, value):
|
def putSpecialArgv(self, value):
|
||||||
"""
|
"""
|
||||||
@@ -1757,10 +1695,6 @@ class DumperBase:
|
|||||||
self.qqEditable = {}
|
self.qqEditable = {}
|
||||||
self.typeCache = {}
|
self.typeCache = {}
|
||||||
|
|
||||||
if hasPlot: # Hack for generic array type. [] is used as "type" name.
|
|
||||||
self.qqDumpers['[]'] = ""
|
|
||||||
self.qqFormats['[]'] = arrayForms()
|
|
||||||
|
|
||||||
for mod in self.dumpermodules:
|
for mod in self.dumpermodules:
|
||||||
m = importlib.import_module(mod)
|
m = importlib.import_module(mod)
|
||||||
dic = m.__dict__
|
dic = m.__dict__
|
||||||
@@ -1981,48 +1915,3 @@ class DumperBase:
|
|||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
# Some "Enums"
|
|
||||||
|
|
||||||
# Encodings. Keep that synchronized with DebuggerEncoding in debuggerprotocol.h
|
|
||||||
Unencoded8Bit, \
|
|
||||||
Base64Encoded8BitWithQuotes, \
|
|
||||||
Base64Encoded16BitWithQuotes, \
|
|
||||||
Base64Encoded32BitWithQuotes, \
|
|
||||||
Base64Encoded16Bit, \
|
|
||||||
Base64Encoded8Bit, \
|
|
||||||
Hex2EncodedLatin1, \
|
|
||||||
Hex4EncodedLittleEndian, \
|
|
||||||
Hex8EncodedLittleEndian, \
|
|
||||||
Hex2EncodedUtf8, \
|
|
||||||
Hex8EncodedBigEndian, \
|
|
||||||
Hex4EncodedBigEndian, \
|
|
||||||
Hex4EncodedLittleEndianWithoutQuotes, \
|
|
||||||
Hex2EncodedLocal8Bit, \
|
|
||||||
JulianDate, \
|
|
||||||
MillisecondsSinceMidnight, \
|
|
||||||
JulianDateAndMillisecondsSinceMidnight, \
|
|
||||||
Hex2EncodedInt1, \
|
|
||||||
Hex2EncodedInt2, \
|
|
||||||
Hex2EncodedInt4, \
|
|
||||||
Hex2EncodedInt8, \
|
|
||||||
Hex2EncodedUInt1, \
|
|
||||||
Hex2EncodedUInt2, \
|
|
||||||
Hex2EncodedUInt4, \
|
|
||||||
Hex2EncodedUInt8, \
|
|
||||||
Hex2EncodedFloat4, \
|
|
||||||
Hex2EncodedFloat8, \
|
|
||||||
IPv6AddressAndHexScopeId, \
|
|
||||||
Hex2EncodedUtf8WithoutQuotes, \
|
|
||||||
DateTimeInternal \
|
|
||||||
= range(30)
|
|
||||||
|
|
||||||
# Display modes. Keep that synchronized with DebuggerDisplay in watchutils.h
|
|
||||||
StopDisplay, \
|
|
||||||
DisplayImageData, \
|
|
||||||
DisplayUtf16String, \
|
|
||||||
DisplayImageFile, \
|
|
||||||
DisplayLatin1String, \
|
|
||||||
DisplayUtf8String \
|
|
||||||
= range(6)
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1615,8 +1615,6 @@ class Dumper(DumperBase):
|
|||||||
self.qmlBreakpoints.append(Resolver(self, args))
|
self.qmlBreakpoints.append(Resolver(self, args))
|
||||||
|
|
||||||
def exitGdb(self, _):
|
def exitGdb(self, _):
|
||||||
if hasPlot:
|
|
||||||
matplotQuit()
|
|
||||||
gdb.execute("quit")
|
gdb.execute("quit")
|
||||||
|
|
||||||
def loadDumpers(self, args):
|
def loadDumpers(self, args):
|
||||||
|
|||||||
@@ -62,14 +62,12 @@ def qdump__QByteArray(d, value):
|
|||||||
elided, p = d.encodeByteArrayHelper(d.extractPointer(value), d.displayStringLimit)
|
elided, p = d.encodeByteArrayHelper(d.extractPointer(value), d.displayStringLimit)
|
||||||
displayFormat = d.currentItemFormat()
|
displayFormat = d.currentItemFormat()
|
||||||
if displayFormat == AutomaticFormat or displayFormat == Latin1StringFormat:
|
if displayFormat == AutomaticFormat or displayFormat == Latin1StringFormat:
|
||||||
d.putDisplay(StopDisplay)
|
|
||||||
d.putValue(p, Hex2EncodedLatin1, elided=elided)
|
d.putValue(p, Hex2EncodedLatin1, elided=elided)
|
||||||
elif displayFormat == SeparateLatin1StringFormat:
|
elif displayFormat == SeparateLatin1StringFormat:
|
||||||
d.putValue(p, Hex2EncodedLatin1, elided=elided)
|
d.putValue(p, Hex2EncodedLatin1, elided=elided)
|
||||||
d.putField("editformat", DisplayLatin1String)
|
d.putField("editformat", DisplayLatin1String)
|
||||||
d.putField("editvalue", d.encodeByteArray(value, limit=100000))
|
d.putField("editvalue", d.encodeByteArray(value, limit=100000))
|
||||||
elif displayFormat == Utf8StringFormat:
|
elif displayFormat == Utf8StringFormat:
|
||||||
d.putDisplay(StopDisplay)
|
|
||||||
d.putValue(p, Hex2EncodedUtf8, elided=elided)
|
d.putValue(p, Hex2EncodedUtf8, elided=elided)
|
||||||
elif displayFormat == SeparateUtf8StringFormat:
|
elif displayFormat == SeparateUtf8StringFormat:
|
||||||
d.putValue(p, Hex2EncodedUtf8, elided=elided)
|
d.putValue(p, Hex2EncodedUtf8, elided=elided)
|
||||||
@@ -546,7 +544,6 @@ def qdump__QFiniteStack(d, value):
|
|||||||
size = int(value["_size"])
|
size = int(value["_size"])
|
||||||
d.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
|
d.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
|
||||||
d.putItemCount(size)
|
d.putItemCount(size)
|
||||||
if d.isExpanded():
|
|
||||||
d.putPlotData(value["_array"], size, d.templateArgument(value.type, 0))
|
d.putPlotData(value["_array"], size, d.templateArgument(value.type, 0))
|
||||||
|
|
||||||
|
|
||||||
@@ -847,9 +844,7 @@ def qdump__QImage(d, value):
|
|||||||
d.putType("void *")
|
d.putType("void *")
|
||||||
|
|
||||||
displayFormat = d.currentItemFormat()
|
displayFormat = d.currentItemFormat()
|
||||||
if displayFormat == SimpleFormat:
|
if displayFormat == SeparateFormat:
|
||||||
d.putDisplay(StopDisplay)
|
|
||||||
elif displayFormat == SeparateFormat:
|
|
||||||
# This is critical for performance. Writing to an external
|
# This is critical for performance. Writing to an external
|
||||||
# file using the following is faster when using GDB.
|
# file using the following is faster when using GDB.
|
||||||
# file = tempfile.mkstemp(prefix="gdbpy_")
|
# file = tempfile.mkstemp(prefix="gdbpy_")
|
||||||
@@ -1743,9 +1738,7 @@ def qdump__QString(d, value):
|
|||||||
data, size, alloc = d.stringData(value)
|
data, size, alloc = d.stringData(value)
|
||||||
d.putNumChild(size)
|
d.putNumChild(size)
|
||||||
displayFormat = d.currentItemFormat()
|
displayFormat = d.currentItemFormat()
|
||||||
if displayFormat == SimpleFormat:
|
if displayFormat == SeparateFormat:
|
||||||
d.putDisplay(StopDisplay)
|
|
||||||
elif displayFormat == SeparateFormat:
|
|
||||||
d.putField("editformat", DisplayUtf16String)
|
d.putField("editformat", DisplayUtf16String)
|
||||||
d.putField("editvalue", d.encodeString(value, limit=100000))
|
d.putField("editvalue", d.encodeString(value, limit=100000))
|
||||||
if d.isExpanded():
|
if d.isExpanded():
|
||||||
@@ -1897,9 +1890,7 @@ def qdump__QUrl(d, value):
|
|||||||
d.putValue(url, Hex4EncodedLittleEndian)
|
d.putValue(url, Hex4EncodedLittleEndian)
|
||||||
|
|
||||||
displayFormat = d.currentItemFormat()
|
displayFormat = d.currentItemFormat()
|
||||||
if displayFormat == SimpleFormat:
|
if displayFormat == SeparateFormat:
|
||||||
d.putDisplay(StopDisplay)
|
|
||||||
elif displayFormat == SeparateFormat:
|
|
||||||
d.putField("editformat", DisplayUtf16String)
|
d.putField("editformat", DisplayUtf16String)
|
||||||
d.putField("editvalue", url)
|
d.putField("editvalue", url)
|
||||||
|
|
||||||
|
|||||||
@@ -711,8 +711,8 @@ def qdump__std__vector(d, value):
|
|||||||
d.checkPointer(alloc)
|
d.checkPointer(alloc)
|
||||||
|
|
||||||
d.putItemCount(size)
|
d.putItemCount(size)
|
||||||
if d.isExpanded():
|
|
||||||
if isBool:
|
if isBool:
|
||||||
|
if d.isExpanded():
|
||||||
with Children(d, size, maxNumChild=10000, childType=type):
|
with Children(d, size, maxNumChild=10000, childType=type):
|
||||||
base = d.pointerValue(start)
|
base = d.pointerValue(start)
|
||||||
for i in d.childRange():
|
for i in d.childRange():
|
||||||
|
|||||||
@@ -246,7 +246,8 @@ enum DebuggerDisplay {
|
|||||||
DisplayUtf16String = 2,
|
DisplayUtf16String = 2,
|
||||||
DisplayImageFile = 3,
|
DisplayImageFile = 3,
|
||||||
DisplayLatin1String = 4,
|
DisplayLatin1String = 4,
|
||||||
DisplayUtf8String = 5
|
DisplayUtf8String = 5,
|
||||||
|
DisplayPlotData = 6
|
||||||
};
|
};
|
||||||
// Decode string data as returned by the dumper helpers.
|
// Decode string data as returned by the dumper helpers.
|
||||||
QString decodeData(const QByteArray &baIn, int encoding);
|
QString decodeData(const QByteArray &baIn, int encoding);
|
||||||
|
|||||||
@@ -114,11 +114,15 @@ ImageViewer::ImageViewer(QWidget *parent)
|
|||||||
connect(m_imageWidget, &ImageWidget::clicked, this, &ImageViewer::clicked);
|
connect(m_imageWidget, &ImageWidget::clicked, this, &ImageViewer::clicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageViewer::setImage(const QImage &i)
|
void ImageViewer::setImage(const QImage &image)
|
||||||
{
|
{
|
||||||
m_imageWidget->setImage(i);
|
m_imageWidget->setImage(image);
|
||||||
m_info = tr("Size: %1x%2, %3 byte, format: %4, depth: %5")
|
clicked(QString());
|
||||||
.arg(i.width()).arg(i.height()).arg(i.byteCount()).arg(i.format()).arg(i.depth());
|
}
|
||||||
|
|
||||||
|
void ImageViewer::setInfo(const QString &info)
|
||||||
|
{
|
||||||
|
m_info = info;
|
||||||
clicked(QString());
|
clicked(QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,4 +169,77 @@ void ImageViewer::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
openImageViewer(image);
|
openImageViewer(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
PlotViewer::PlotViewer(QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlotViewer::setData(const PlotViewer::Data &data)
|
||||||
|
{
|
||||||
|
m_data = data;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlotViewer::setInfo(const QString &description)
|
||||||
|
{
|
||||||
|
m_info = description;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlotViewer::paintEvent(QPaintEvent *)
|
||||||
|
{
|
||||||
|
QPainter pain(this);
|
||||||
|
|
||||||
|
const int n = int(m_data.size());
|
||||||
|
const int w = width();
|
||||||
|
const int h = height();
|
||||||
|
const int b = 10; // Border width.
|
||||||
|
|
||||||
|
pain.fillRect(rect(), Qt::white);
|
||||||
|
|
||||||
|
double ymin = 0;
|
||||||
|
double ymax = 0;
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
const double v = m_data.at(i);
|
||||||
|
if (v < ymin)
|
||||||
|
ymin = v;
|
||||||
|
else if (v > ymax)
|
||||||
|
ymax = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
const double d = ymin == ymax ? (h / 2 - b) : (ymax - ymin);
|
||||||
|
const int k = 1; // Length of cross marker arms.
|
||||||
|
|
||||||
|
for (int i = 0; i + 1 < n; ++i) {
|
||||||
|
// Lines between points.
|
||||||
|
const int x1 = b + i * (w - 2 * b) / (n - 1);
|
||||||
|
const int x2 = b + (i + 1) * (w - 2 * b) / (n - 1);
|
||||||
|
const int y1 = h - (b + int((m_data[i] - ymin) * (h - 2 * b) / d));
|
||||||
|
const int y2 = h - (b + int((m_data[i + 1] - ymin) * (h - 2 * b) / d));
|
||||||
|
pain.drawLine(x1, y1, x2, y2);
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
// Little cross marker on first point
|
||||||
|
pain.drawLine(x1 - k, y1 - k, x1 + k, y1 + k);
|
||||||
|
pain.drawLine(x1 + k, y1 - k, x1 - k, y1 + k);
|
||||||
|
}
|
||||||
|
// ... and all subsequent points.
|
||||||
|
pain.drawLine(x2 - k, y2 - k, x2 + k, y2 + k);
|
||||||
|
pain.drawLine(x2 + k, y2 - k, x2 - k, y2 + k);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n) {
|
||||||
|
pain.drawText(10, 10,
|
||||||
|
QString::fromLatin1("%5 items. X: %1..%2, Y: %3...%4").arg(0).arg(n).arg(ymin).arg(ymax).arg(n));
|
||||||
|
} else {
|
||||||
|
pain.drawText(10, 10,
|
||||||
|
QString::fromLatin1("Container is empty"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include "imageviewer.moc"
|
#include "imageviewer.moc"
|
||||||
|
|||||||
@@ -33,6 +33,8 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QScrollArea;
|
class QScrollArea;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
@@ -49,19 +51,36 @@ class ImageViewer : public QWidget
|
|||||||
public:
|
public:
|
||||||
explicit ImageViewer(QWidget *parent = 0);
|
explicit ImageViewer(QWidget *parent = 0);
|
||||||
|
|
||||||
void setImage(const QImage &);
|
void setImage(const QImage &image);
|
||||||
|
void setInfo(const QString &description);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void contextMenuEvent(QContextMenuEvent *);
|
void contextMenuEvent(QContextMenuEvent *);
|
||||||
|
|
||||||
private slots:
|
private:
|
||||||
void clicked(const QString &);
|
void clicked(const QString &);
|
||||||
|
|
||||||
private:
|
|
||||||
QScrollArea *m_scrollArea;
|
QScrollArea *m_scrollArea;
|
||||||
ImageWidget *m_imageWidget;
|
ImageWidget *m_imageWidget;
|
||||||
QLabel *m_infoLabel;
|
QLabel *m_infoLabel;
|
||||||
QString m_info;
|
QString m_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PlotViewer : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit PlotViewer(QWidget *parent = 0);
|
||||||
|
|
||||||
|
typedef std::vector<double> Data;
|
||||||
|
void setData(const Data &data);
|
||||||
|
void setInfo(const QString &description);
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent *ev);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Data m_data;
|
||||||
|
QString m_info;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // IMAGEVIEWER_H
|
#endif // IMAGEVIEWER_H
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ WatchData::WatchData() :
|
|||||||
id(0),
|
id(0),
|
||||||
state(InitialState),
|
state(InitialState),
|
||||||
editformat(StopDisplay),
|
editformat(StopDisplay),
|
||||||
|
editencoding(Unencoded8Bit),
|
||||||
address(0),
|
address(0),
|
||||||
origaddr(0),
|
origaddr(0),
|
||||||
size(0),
|
size(0),
|
||||||
@@ -552,14 +553,12 @@ void parseChildrenData(const WatchData &data0, const GdbMi &item,
|
|||||||
GdbMi children = item["children"];
|
GdbMi children = item["children"];
|
||||||
|
|
||||||
data.updateType(item["type"]);
|
data.updateType(item["type"]);
|
||||||
GdbMi mi = item["editvalue"];
|
|
||||||
if (mi.isValid())
|
|
||||||
data.editvalue = mi.data();
|
|
||||||
|
|
||||||
mi = item["editformat"];
|
data.editvalue = item["editvalue"].data();
|
||||||
data.editformat = DebuggerDisplay(mi.toInt());
|
data.editformat = DebuggerDisplay(item["editformat"].toInt());
|
||||||
|
data.editencoding = DebuggerEncoding(item["editencoding"].toInt());
|
||||||
|
|
||||||
mi = item["valueelided"];
|
GdbMi mi = item["valueelided"];
|
||||||
if (mi.isValid())
|
if (mi.isValid())
|
||||||
data.elided = mi.toInt();
|
data.elided = mi.toInt();
|
||||||
|
|
||||||
@@ -658,6 +657,52 @@ void parseWatchData(const WatchData &data0, const GdbMi &input,
|
|||||||
parseChildrenData(data0, input, itemHandler, childHandler, arrayDecoder);
|
parseChildrenData(data0, input, itemHandler, childHandler, arrayDecoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void readNumericVectorHelper(std::vector<double> *v, const QByteArray &ba)
|
||||||
|
{
|
||||||
|
const T *p = (const T *) ba.data();
|
||||||
|
std::copy(p, p + ba.size() / sizeof(T), std::back_insert_iterator<std::vector<double> >(*v));
|
||||||
|
}
|
||||||
|
|
||||||
|
void readNumericVector(std::vector<double> *v, const QByteArray &rawData, DebuggerEncoding encoding)
|
||||||
|
{
|
||||||
|
switch (encoding) {
|
||||||
|
case Hex2EncodedInt1:
|
||||||
|
readNumericVectorHelper<signed char>(v, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedInt2:
|
||||||
|
readNumericVectorHelper<short>(v, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedInt4:
|
||||||
|
readNumericVectorHelper<int>(v, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedInt8:
|
||||||
|
readNumericVectorHelper<qint64>(v, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedUInt1:
|
||||||
|
readNumericVectorHelper<uchar>(v, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedUInt2:
|
||||||
|
readNumericVectorHelper<ushort>(v, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedUInt4:
|
||||||
|
readNumericVectorHelper<uint>(v, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedUInt8:
|
||||||
|
readNumericVectorHelper<quint64>(v, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedFloat4:
|
||||||
|
readNumericVectorHelper<float>(v, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedFloat8:
|
||||||
|
readNumericVectorHelper<double>(v, rawData);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qDebug() << "ENCODING ERROR: " << encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -113,6 +114,7 @@ public:
|
|||||||
QString value; // Displayed value
|
QString value; // Displayed value
|
||||||
QByteArray editvalue; // Displayed value
|
QByteArray editvalue; // Displayed value
|
||||||
DebuggerDisplay editformat; // Format of displayed value
|
DebuggerDisplay editformat; // Format of displayed value
|
||||||
|
DebuggerEncoding editencoding; // Encoding of displayed value
|
||||||
QByteArray type; // Type for further processing
|
QByteArray type; // Type for further processing
|
||||||
QString displayedType; // Displayed type (optional)
|
QString displayedType; // Displayed type (optional)
|
||||||
quint64 address; // Displayed address of the actual object
|
quint64 address; // Displayed address of the actual object
|
||||||
@@ -134,6 +136,10 @@ void decodeArrayData(std::function<void(const WatchData &)> itemHandler,
|
|||||||
const QByteArray &rawData,
|
const QByteArray &rawData,
|
||||||
int encoding);
|
int encoding);
|
||||||
|
|
||||||
|
void readNumericVector(std::vector<double> *,
|
||||||
|
const QByteArray &rawData,
|
||||||
|
DebuggerEncoding encoding);
|
||||||
|
|
||||||
void parseChildrenData(const WatchData &parent, const GdbMi &child,
|
void parseChildrenData(const WatchData &parent, const GdbMi &child,
|
||||||
std::function<void(const WatchData &)> itemHandler,
|
std::function<void(const WatchData &)> itemHandler,
|
||||||
std::function<void(const WatchData &, const GdbMi &)> childHandler,
|
std::function<void(const WatchData &, const GdbMi &)> childHandler,
|
||||||
|
|||||||
@@ -53,11 +53,13 @@
|
|||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QPainter>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QTabWidget>
|
#include <QTabWidget>
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
@@ -109,6 +111,52 @@ static void saveWatchers()
|
|||||||
setSessionValue("Watchers", WatchHandler::watchedExpressions());
|
setSessionValue("Watchers", WatchHandler::watchedExpressions());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void loadFormats()
|
||||||
|
{
|
||||||
|
QVariant value = sessionValue("DefaultFormats");
|
||||||
|
QMapIterator<QString, QVariant> it(value.toMap());
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
if (!it.key().isEmpty())
|
||||||
|
theTypeFormats.insert(it.key().toUtf8(), it.value().toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
value = sessionValue("IndividualFormats");
|
||||||
|
it = QMapIterator<QString, QVariant>(value.toMap());
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
if (!it.key().isEmpty())
|
||||||
|
theIndividualFormats.insert(it.key().toUtf8(), it.value().toInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveFormats()
|
||||||
|
{
|
||||||
|
QMap<QString, QVariant> formats;
|
||||||
|
QHashIterator<QByteArray, int> it(theTypeFormats);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
const int format = it.value();
|
||||||
|
if (format != AutomaticFormat) {
|
||||||
|
const QByteArray key = it.key().trimmed();
|
||||||
|
if (!key.isEmpty())
|
||||||
|
formats.insert(QString::fromLatin1(key), format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setSessionValue("DefaultFormats", formats);
|
||||||
|
|
||||||
|
formats.clear();
|
||||||
|
it = QHashIterator<QByteArray, int>(theIndividualFormats);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
const int format = it.value();
|
||||||
|
const QByteArray key = it.key().trimmed();
|
||||||
|
if (!key.isEmpty())
|
||||||
|
formats.insert(QString::fromLatin1(key), format);
|
||||||
|
}
|
||||||
|
setSessionValue("IndividualFormats", formats);
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SeparatedView
|
// SeparatedView
|
||||||
@@ -126,17 +174,29 @@ public:
|
|||||||
setWindowTitle(WatchHandler::tr("Debugger - Qt Creator"));
|
setWindowTitle(WatchHandler::tr("Debugger - Qt Creator"));
|
||||||
|
|
||||||
QVariant geometry = sessionValue("DebuggerSeparateWidgetGeometry");
|
QVariant geometry = sessionValue("DebuggerSeparateWidgetGeometry");
|
||||||
if (geometry.isValid())
|
if (geometry.isValid()) {
|
||||||
setGeometry(geometry.toRect());
|
QRect rc = geometry.toRect();
|
||||||
|
if (rc.width() < 200)
|
||||||
|
rc.setWidth(200);
|
||||||
|
if (rc.height() < 200)
|
||||||
|
rc.setHeight(200);
|
||||||
|
setGeometry(rc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~SeparatedView()
|
void saveGeometry()
|
||||||
{
|
{
|
||||||
setSessionValue("DebuggerSeparateWidgetGeometry", geometry());
|
setSessionValue("DebuggerSeparateWidgetGeometry", geometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~SeparatedView()
|
||||||
|
{
|
||||||
|
saveGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
void removeObject(const QByteArray &key)
|
void removeObject(const QByteArray &key)
|
||||||
{
|
{
|
||||||
|
saveGeometry();
|
||||||
if (QWidget *w = findWidget(key)) {
|
if (QWidget *w = findWidget(key)) {
|
||||||
removeTab(indexOf(w));
|
removeTab(indexOf(w));
|
||||||
sanitize();
|
sanitize();
|
||||||
@@ -145,9 +205,11 @@ public:
|
|||||||
|
|
||||||
void closeTab(int index)
|
void closeTab(int index)
|
||||||
{
|
{
|
||||||
|
saveGeometry();
|
||||||
if (QObject *o = widget(index)) {
|
if (QObject *o = widget(index)) {
|
||||||
QByteArray iname = o->property(INameProperty).toByteArray();
|
QByteArray iname = o->property(INameProperty).toByteArray();
|
||||||
theIndividualFormats.remove(iname);
|
theIndividualFormats.remove(iname);
|
||||||
|
saveFormats();
|
||||||
}
|
}
|
||||||
removeTab(index);
|
removeTab(index);
|
||||||
sanitize();
|
sanitize();
|
||||||
@@ -170,7 +232,7 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> T *prepareObject(const QByteArray &key, const QString &title)
|
template <class T> T *prepareObject(const QByteArray &key, const QString &tabName)
|
||||||
{
|
{
|
||||||
T *t = 0;
|
T *t = 0;
|
||||||
if (QWidget *w = findWidget(key)) {
|
if (QWidget *w = findWidget(key)) {
|
||||||
@@ -181,7 +243,7 @@ public:
|
|||||||
if (!t) {
|
if (!t) {
|
||||||
t = new T;
|
t = new T;
|
||||||
t->setProperty(KeyProperty, key);
|
t->setProperty(KeyProperty, key);
|
||||||
addTab(t, title);
|
addTab(t, tabName);
|
||||||
}
|
}
|
||||||
|
|
||||||
setCurrentWidget(t);
|
setCurrentWidget(t);
|
||||||
@@ -218,8 +280,9 @@ public:
|
|||||||
void insertItem(WatchItem *item);
|
void insertItem(WatchItem *item);
|
||||||
void reexpandItems();
|
void reexpandItems();
|
||||||
|
|
||||||
void showEditValue(const WatchData &data);
|
void showEditValue(const WatchItem *item);
|
||||||
void setFormat(const QByteArray &type, int format);
|
void setTypeFormat(const QByteArray &type, int format);
|
||||||
|
void setIndividualFormat(const QByteArray &iname, int format);
|
||||||
|
|
||||||
QString removeNamespaces(QString str) const;
|
QString removeNamespaces(QString str) const;
|
||||||
|
|
||||||
@@ -884,16 +947,12 @@ bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case LocalsTypeFormatRole:
|
case LocalsTypeFormatRole:
|
||||||
setFormat(item->type, value.toInt());
|
setTypeFormat(item->type, value.toInt());
|
||||||
m_engine->updateWatchItem(item);
|
m_engine->updateWatchItem(item);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LocalsIndividualFormatRole: {
|
case LocalsIndividualFormatRole: {
|
||||||
const int format = value.toInt();
|
setIndividualFormat(item->iname, value.toInt());
|
||||||
if (format == AutomaticFormat)
|
|
||||||
theIndividualFormats.remove(item->iname);
|
|
||||||
else
|
|
||||||
theIndividualFormats[item->iname] = format;
|
|
||||||
m_engine->updateWatchItem(item);
|
m_engine->updateWatchItem(item);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1010,7 +1069,7 @@ DisplayFormats WatchItem::typeFormatList() const
|
|||||||
formats << watchModel()->m_reportedTypeFormats.value(t);
|
formats << watchModel()->m_reportedTypeFormats.value(t);
|
||||||
|
|
||||||
if (t.contains(QLatin1Char(']')))
|
if (t.contains(QLatin1Char(']')))
|
||||||
formats << watchModel()->m_reportedTypeFormats.value(QLatin1String("[]"));
|
formats.append(ArrayPlotFormat);
|
||||||
|
|
||||||
// Fixed artificial string and pointer types.
|
// Fixed artificial string and pointer types.
|
||||||
if (origaddr || isPointerType(type)) {
|
if (origaddr || isPointerType(type)) {
|
||||||
@@ -1132,7 +1191,7 @@ void WatchModel::reinsertAllData()
|
|||||||
emit inameIsExpanded(parent->iname);
|
emit inameIsExpanded(parent->iname);
|
||||||
emit itemIsExpanded(indexFromItem(parent));
|
emit itemIsExpanded(indexFromItem(parent));
|
||||||
}
|
}
|
||||||
showEditValue(data);
|
showEditValue(newItem); // FIXME: Needed?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1192,7 +1251,7 @@ void WatchModel::insertItem(WatchItem *item)
|
|||||||
const int row = findInsertPosition(parent->children(), item);
|
const int row = findInsertPosition(parent->children(), item);
|
||||||
parent->insertChild(row, item);
|
parent->insertChild(row, item);
|
||||||
|
|
||||||
item->walkTree([this](TreeItem *sub) { showEditValue(*static_cast<WatchItem *>(sub)); });
|
item->walkTree([this](TreeItem *sub) { showEditValue(static_cast<WatchItem *>(sub)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchModel::reexpandItems()
|
void WatchModel::reexpandItems()
|
||||||
@@ -1326,20 +1385,20 @@ static void swapEndian(char *d, int nchar)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchModel::showEditValue(const WatchData &data)
|
void WatchModel::showEditValue(const WatchItem *item)
|
||||||
{
|
{
|
||||||
const QByteArray key = data.address ? data.hexAddress() : data.iname;
|
const QByteArray key = item->address ? item->hexAddress() : item->iname;
|
||||||
switch (data.editformat) {
|
switch (item->editformat) {
|
||||||
case StopDisplay:
|
case StopDisplay:
|
||||||
m_separatedView->removeObject(data.iname);
|
m_separatedView->removeObject(key);
|
||||||
break;
|
break;
|
||||||
case DisplayImageData:
|
case DisplayImageData:
|
||||||
case DisplayImageFile: { // QImage
|
case DisplayImageFile: { // QImage
|
||||||
int width = 0, height = 0, nbytes = 0, format = 0;
|
int width = 0, height = 0, nbytes = 0, format = 0;
|
||||||
QByteArray ba;
|
QByteArray ba;
|
||||||
uchar *bits = 0;
|
uchar *bits = 0;
|
||||||
if (data.editformat == DisplayImageData) {
|
if (item->editformat == DisplayImageData) {
|
||||||
ba = QByteArray::fromHex(data.editvalue);
|
ba = QByteArray::fromHex(item->editvalue);
|
||||||
QTC_ASSERT(ba.size() > 16, return);
|
QTC_ASSERT(ba.size() > 16, return);
|
||||||
const int *header = (int *)(ba.data());
|
const int *header = (int *)(ba.data());
|
||||||
if (!ba.at(0) && !ba.at(1)) // Check on 'width' for Python dumpers returning 4-byte swapped-data.
|
if (!ba.at(0) && !ba.at(1)) // Check on 'width' for Python dumpers returning 4-byte swapped-data.
|
||||||
@@ -1349,8 +1408,8 @@ void WatchModel::showEditValue(const WatchData &data)
|
|||||||
height = header[1];
|
height = header[1];
|
||||||
nbytes = header[2];
|
nbytes = header[2];
|
||||||
format = header[3];
|
format = header[3];
|
||||||
} else if (data.editformat == DisplayImageFile) {
|
} else if (item->editformat == DisplayImageFile) {
|
||||||
QTextStream ts(data.editvalue);
|
QTextStream ts(item->editvalue);
|
||||||
QString fileName;
|
QString fileName;
|
||||||
ts >> width >> height >> nbytes >> format >> fileName;
|
ts >> width >> height >> nbytes >> format >> fileName;
|
||||||
QFile f(fileName);
|
QFile f(fileName);
|
||||||
@@ -1365,33 +1424,45 @@ void WatchModel::showEditValue(const WatchData &data)
|
|||||||
QTC_ASSERT(0 < format && format < 32, return);
|
QTC_ASSERT(0 < format && format < 32, return);
|
||||||
QImage im(width, height, QImage::Format(format));
|
QImage im(width, height, QImage::Format(format));
|
||||||
std::memcpy(im.bits(), bits, nbytes);
|
std::memcpy(im.bits(), bits, nbytes);
|
||||||
const QString title = data.address ?
|
ImageViewer *v = m_separatedView->prepareObject<ImageViewer>(key, item->name);
|
||||||
tr("%1 Object at %2").arg(QLatin1String(data.type),
|
v->setProperty(INameProperty, item->iname);
|
||||||
QLatin1String(data.hexAddress())) :
|
v->setInfo(item->address ?
|
||||||
tr("%1 Object at Unknown Address").arg(QLatin1String(data.type));
|
tr("%1 Object at %2").arg(QLatin1String(item->type),
|
||||||
ImageViewer *v = m_separatedView->prepareObject<ImageViewer>(key, title);
|
QLatin1String(item->hexAddress())) :
|
||||||
v->setProperty(INameProperty, data.iname);
|
tr("%1 Object at Unknown Address").arg(QLatin1String(item->type))
|
||||||
|
+ QLatin1String(" ") +
|
||||||
|
ImageViewer::tr("Size: %1x%2, %3 byte, format: %4, depth: %5")
|
||||||
|
.arg(width).arg(height).arg(nbytes).arg(im.format()).arg(im.depth())
|
||||||
|
);
|
||||||
v->setImage(im);
|
v->setImage(im);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DisplayUtf16String:
|
case DisplayUtf16String:
|
||||||
case DisplayLatin1String:
|
case DisplayLatin1String:
|
||||||
case DisplayUtf8String: { // String data.
|
case DisplayUtf8String: { // String data.
|
||||||
QByteArray ba = QByteArray::fromHex(data.editvalue);
|
QByteArray ba = QByteArray::fromHex(item->editvalue);
|
||||||
QString str;
|
QString str;
|
||||||
if (data.editformat == DisplayUtf16String)
|
if (item->editformat == DisplayUtf16String)
|
||||||
str = QString::fromUtf16((ushort *)ba.constData(), ba.size()/2);
|
str = QString::fromUtf16((ushort *)ba.constData(), ba.size()/2);
|
||||||
else if (data.editformat == DisplayLatin1String)
|
else if (item->editformat == DisplayLatin1String)
|
||||||
str = QString::fromLatin1(ba.constData(), ba.size());
|
str = QString::fromLatin1(ba.constData(), ba.size());
|
||||||
else if (data.editformat == DisplayUtf8String)
|
else if (item->editformat == DisplayUtf8String)
|
||||||
str = QString::fromUtf8(ba.constData(), ba.size());
|
str = QString::fromUtf8(ba.constData(), ba.size());
|
||||||
QTextEdit *t = m_separatedView->prepareObject<QTextEdit>(key, data.name);
|
QTextEdit *t = m_separatedView->prepareObject<QTextEdit>(key, item->name);
|
||||||
t->setProperty(INameProperty, data.iname);
|
t->setProperty(INameProperty, item->iname);
|
||||||
t->setText(str);
|
t->setText(str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DisplayPlotData: { // Plots
|
||||||
|
std::vector<double> data;
|
||||||
|
readNumericVector(&data, QByteArray::fromHex(item->editvalue), item->editencoding);
|
||||||
|
PlotViewer *v = m_separatedView->prepareObject<PlotViewer>(key, item->name);
|
||||||
|
v->setProperty(INameProperty, item->iname);
|
||||||
|
v->setData(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
QTC_ASSERT(false, qDebug() << "Display format: " << data.editformat);
|
QTC_ASSERT(false, qDebug() << "Display format: " << item->editformat);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1439,52 +1510,6 @@ QStringList WatchHandler::watchedExpressions()
|
|||||||
return watcherNames;
|
return watcherNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loadFormats()
|
|
||||||
{
|
|
||||||
QVariant value = sessionValue("DefaultFormats");
|
|
||||||
QMapIterator<QString, QVariant> it(value.toMap());
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next();
|
|
||||||
if (!it.key().isEmpty())
|
|
||||||
theTypeFormats.insert(it.key().toUtf8(), it.value().toInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
value = sessionValue("IndividualFormats");
|
|
||||||
it = QMapIterator<QString, QVariant>(value.toMap());
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next();
|
|
||||||
if (!it.key().isEmpty())
|
|
||||||
theIndividualFormats.insert(it.key().toUtf8(), it.value().toInt());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void saveFormats()
|
|
||||||
{
|
|
||||||
QMap<QString, QVariant> formats;
|
|
||||||
QHashIterator<QByteArray, int> it(theTypeFormats);
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next();
|
|
||||||
const int format = it.value();
|
|
||||||
if (format != AutomaticFormat) {
|
|
||||||
const QByteArray key = it.key().trimmed();
|
|
||||||
if (!key.isEmpty())
|
|
||||||
formats.insert(QString::fromLatin1(key), format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setSessionValue("DefaultFormats", formats);
|
|
||||||
|
|
||||||
formats.clear();
|
|
||||||
it = QHashIterator<QByteArray, int>(theIndividualFormats);
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next();
|
|
||||||
const int format = it.value();
|
|
||||||
const QByteArray key = it.key().trimmed();
|
|
||||||
if (!key.isEmpty())
|
|
||||||
formats.insert(QString::fromLatin1(key), format);
|
|
||||||
}
|
|
||||||
setSessionValue("IndividualFormats", formats);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchHandler::saveSessionData()
|
void WatchHandler::saveSessionData()
|
||||||
{
|
{
|
||||||
saveWatchers();
|
saveWatchers();
|
||||||
@@ -1537,7 +1562,7 @@ const WatchItem *WatchHandler::findCppLocalVariable(const QString &name) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchModel::setFormat(const QByteArray &type0, int format)
|
void WatchModel::setTypeFormat(const QByteArray &type0, int format)
|
||||||
{
|
{
|
||||||
const QByteArray type = stripForFormat(type0);
|
const QByteArray type = stripForFormat(type0);
|
||||||
if (format == AutomaticFormat)
|
if (format == AutomaticFormat)
|
||||||
@@ -1548,6 +1573,15 @@ void WatchModel::setFormat(const QByteArray &type0, int format)
|
|||||||
reinsertAllData();
|
reinsertAllData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WatchModel::setIndividualFormat(const QByteArray &iname, int format)
|
||||||
|
{
|
||||||
|
if (format == AutomaticFormat)
|
||||||
|
theIndividualFormats.remove(iname);
|
||||||
|
else
|
||||||
|
theIndividualFormats[iname] = format;
|
||||||
|
saveFormats();
|
||||||
|
}
|
||||||
|
|
||||||
int WatchHandler::format(const QByteArray &iname) const
|
int WatchHandler::format(const QByteArray &iname) const
|
||||||
{
|
{
|
||||||
int result = AutomaticFormat;
|
int result = AutomaticFormat;
|
||||||
|
|||||||
Reference in New Issue
Block a user