]> git.rmz.io Git - dotfiles.git/blob - gdb/qt.py
nvim: add FPP copyright snippet
[dotfiles.git] / gdb / qt.py
1 # -*- coding: iso-8859-1 -*-
2 # Pretty-printers for Qt 4 and Qt 5.
3
4 # Copyright (C) 2009 Niko Sams <niko.sams@gmail.com>
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19 import gdb
20 import itertools
21 import re
22 import time
23
24 from helper import *
25
26 class QStringPrinter:
27
28 def __init__(self, val):
29 self.val = val
30
31 def to_string(self):
32 size = self.val['d']['size']
33 ret = ""
34
35 # The QString object might be not yet initialized. In this case size is a bogus value
36 # and the following 2 lines might throw memory access error. Hence the try/catch.
37 try:
38 isQt4 = has_field(self.val['d'], 'data') # Qt4 has d->data, Qt5 doesn't.
39 if isQt4:
40 dataAsCharPointer = self.val['d']['data'].cast(gdb.lookup_type("char").pointer())
41 else:
42 dataAsCharPointer = (self.val['d'] + 1).cast(gdb.lookup_type("char").pointer())
43 ret = dataAsCharPointer.string(encoding = 'UTF-16', length = size * 2)
44 except Exception:
45 # swallow the exception and return empty string
46 pass
47 return ret
48
49 def display_hint (self):
50 return 'string'
51
52 class QByteArrayPrinter:
53
54 def __init__(self, val):
55 self.val = val
56 # Qt4 has 'data', Qt5 doesn't
57 self.isQt4 = has_field(self.val['d'], 'data')
58
59 class _iterator(Iterator):
60 def __init__(self, data, size):
61 self.data = data
62 self.size = size
63 self.count = 0
64
65 def __iter__(self):
66 return self
67
68 def __next__(self):
69 if self.count >= self.size:
70 raise StopIteration
71 count = self.count
72 self.count = self.count + 1
73 return ('[%d]' % count, self.data[count])
74
75 def stringData(self):
76 if self.isQt4:
77 return self.val['d']['data']
78 else:
79 return self.val['d'].cast(gdb.lookup_type("char").const().pointer()) + self.val['d']['offset']
80
81 def children(self):
82 return self._iterator(self.stringData(), self.val['d']['size'])
83
84 def to_string(self):
85 #todo: handle charset correctly
86 return self.stringData()
87
88 def display_hint (self):
89 return 'string'
90
91 class QListPrinter:
92 "Print a QList"
93
94 class _iterator(Iterator):
95 def __init__(self, nodetype, d):
96 self.nodetype = nodetype
97 self.d = d
98 self.count = 0
99
100 #from QTypeInfo::isLarge
101 isLarge = self.nodetype.sizeof > gdb.lookup_type('void').pointer().sizeof
102
103 isPointer = self.nodetype.code == gdb.TYPE_CODE_PTR
104
105 #unfortunately we can't use QTypeInfo<T>::isStatic as it's all inlined, so use
106 #this list of types that use Q_DECLARE_TYPEINFO(T, Q_MOVABLE_TYPE)
107 #(obviously it won't work for custom types)
108 movableTypes = ['QRect', 'QRectF', 'QString', 'QMargins', 'QLocale', 'QChar', 'QDate', 'QTime', 'QDateTime', 'QVector',
109 'QRegExpr', 'QPoint', 'QPointF', 'QByteArray', 'QSize', 'QSizeF', 'QBitArray', 'QLine', 'QLineF', 'QModelIndex', 'QPersitentModelIndex',
110 'QVariant', 'QFileInfo', 'QUrl', 'QXmlStreamAttribute', 'QXmlStreamNamespaceDeclaration', 'QXmlStreamNotationDeclaration',
111 'QXmlStreamEntityDeclaration', 'QPair<int, int>']
112 #this list of types that use Q_DECLARE_TYPEINFO(T, Q_PRIMITIVE_TYPE) (from qglobal.h)
113 primitiveTypes = ['bool', 'char', 'signed char', 'unsigned char', 'short', 'unsigned short', 'int', 'unsigned int', 'long', 'unsigned long', 'long long', 'unsigned long long', 'float', 'double']
114
115 if movableTypes.count(self.nodetype.tag) or primitiveTypes.count(str(self.nodetype)):
116 isStatic = False
117 else:
118 isStatic = not isPointer
119
120 self.externalStorage = isLarge or isStatic #see QList::Node::t()
121
122
123 def __iter__(self):
124 return self
125
126 def __next__(self):
127 if self.count >= self.d['end'] - self.d['begin']:
128 raise StopIteration
129 count = self.count
130 array = self.d['array'].address + self.d['begin'] + count
131 if self.externalStorage:
132 value = array.cast(gdb.lookup_type('QList<%s>::Node' % self.nodetype).pointer())['v']
133 else:
134 value = array
135 self.count = self.count + 1
136 return ('[%d]' % count, value.cast(self.nodetype.pointer()).dereference())
137
138 def __init__(self, val, container, itype):
139 self.d = val['d']
140 self.container = container
141 self.size = self.d['end'] - self.d['begin']
142 if itype == None:
143 self.itype = val.type.template_argument(0)
144 else:
145 self.itype = gdb.lookup_type(itype)
146
147 def children(self):
148 return self._iterator(self.itype, self.d)
149
150 def to_string(self):
151 return "%s<%s> (size = %s)" % ( self.container, self.itype, self.size )
152
153 class QVectorPrinter:
154 "Print a QVector"
155
156 class _iterator(Iterator):
157 def __init__(self, nodetype, data, size):
158 self.nodetype = nodetype
159 self.data = data
160 self.size = size
161 self.count = 0
162
163 def __iter__(self):
164 return self
165
166 def __next__(self):
167 if self.count >= self.size:
168 raise StopIteration
169 count = self.count
170
171 self.count = self.count + 1
172 return ('[%d]' % count, self.data[count])
173
174 def __init__(self, val, container):
175 self.val = val
176 self.container = container
177 self.itype = self.val.type.template_argument(0)
178
179 def children(self):
180 isQt4 = has_field(self.val['d'], 'p') # Qt4 has 'p', Qt5 doesn't
181 if isQt4:
182 return self._iterator(self.itype, self.val['p']['array'], self.val['p']['size'])
183 else:
184 data = self.val['d'].cast(gdb.lookup_type("char").const().pointer()) + self.val['d']['offset']
185 return self._iterator(self.itype, data.cast(self.itype.pointer()), self.val['d']['size'])
186
187 def to_string(self):
188 size = self.val['d']['size']
189
190 return "%s<%s> (size = %s)" % ( self.container, self.itype, size )
191
192 class QLinkedListPrinter:
193 "Print a QLinkedList"
194
195 class _iterator(Iterator):
196 def __init__(self, nodetype, begin, size):
197 self.nodetype = nodetype
198 self.it = begin
199 self.pos = 0
200 self.size = size
201
202 def __iter__(self):
203 return self
204
205 def __next__(self):
206 if self.pos >= self.size:
207 raise StopIteration
208
209 pos = self.pos
210 val = self.it['t']
211 self.it = self.it['n']
212 self.pos = self.pos + 1
213 return ('[%d]' % pos, val)
214
215 def __init__(self, val):
216 self.val = val
217 self.itype = self.val.type.template_argument(0)
218
219 def children(self):
220 return self._iterator(self.itype, self.val['e']['n'], self.val['d']['size'])
221
222 def to_string(self):
223 size = self.val['d']['size']
224
225 return "QLinkedList<%s> (size = %s)" % ( self.itype, size )
226
227 class QMapPrinter:
228 "Print a QMap"
229
230 class _iteratorQt4(Iterator):
231 def __init__(self, val):
232 self.val = val
233 self.ktype = self.val.type.template_argument(0)
234 self.vtype = self.val.type.template_argument(1)
235 self.data_node = self.val['e']['forward'][0]
236 self.count = 0
237
238 def __iter__(self):
239 return self
240
241 def payload (self):
242 if gdb.parse_and_eval:
243 ret = int(gdb.parse_and_eval('QMap<%s, %s>::payload()' % (self.ktype, self.vtype)))
244 if (ret): return ret;
245
246 #if the inferior function call didn't work, let's try to calculate ourselves
247
248 #we can't use QMapPayloadNode as it's inlined
249 #as a workaround take the sum of sizeof(members)
250 ret = self.ktype.sizeof
251 ret += self.vtype.sizeof
252 ret += gdb.lookup_type('void').pointer().sizeof
253
254 #but because of data alignment the value can be higher
255 #so guess it's aliged by sizeof(void*)
256 #TODO: find a real solution for this problem
257 ret += ret % gdb.lookup_type('void').pointer().sizeof
258
259 #for some reason booleans are different
260 if str(self.vtype) == 'bool':
261 ret += 2
262
263 ret -= gdb.lookup_type('void').pointer().sizeof
264
265 return ret
266
267 def concrete (self, data_node):
268 node_type = gdb.lookup_type('QMapNode<%s, %s>' % (self.ktype, self.vtype)).pointer()
269 return (data_node.cast(gdb.lookup_type('char').pointer()) - self.payload()).cast(node_type)
270
271 def __next__(self):
272 if self.data_node == self.val['e']:
273 raise StopIteration
274 node = self.concrete(self.data_node).dereference()
275 if self.count % 2 == 0:
276 item = node['key']
277 else:
278 item = node['value']
279 self.data_node = node['forward'][0]
280
281 result = ('[%d]' % self.count, item)
282 self.count = self.count + 1
283 return result
284
285 class _iteratorQt5:
286 def __init__(self, val):
287 realtype = val.type.strip_typedefs()
288 keytype = realtype.template_argument(0)
289 valtype = realtype.template_argument(1)
290 node_type = gdb.lookup_type('QMapData<' + keytype.name + ',' + valtype.name + '>::Node')
291 self.node_p_type = node_type.pointer()
292 self.root = val['d']['header']
293 self.current = None
294 self.next_is_key = True
295 self.i = -1
296 # we store the path here to avoid keeping re-fetching
297 # values from the inferior (also, skips the pointer
298 # arithmetic involved in using the parent pointer)
299 self.path = []
300
301 def __iter__(self):
302 return self
303
304 def moveToNextNode(self):
305 if self.current is None:
306 # find the leftmost node
307 if not self.root['left']:
308 return False
309 self.current = self.root
310 while self.current['left']:
311 self.path.append(self.current)
312 self.current = self.current['left']
313 elif self.current['right']:
314 self.path.append(self.current)
315 self.current = self.current['right']
316 while self.current['left']:
317 self.path.append(self.current)
318 self.current = self.current['left']
319 else:
320 last = self.current
321 self.current = self.path.pop()
322 while self.current['right'] == last:
323 last = self.current
324 self.current = self.path.pop()
325 # if there are no more parents, we are at the root
326 if len(self.path) == 0:
327 return False
328 return True
329
330 def __next__(self):
331 if self.next_is_key:
332 if not self.moveToNextNode():
333 raise StopIteration
334 self.current_typed = self.current.reinterpret_cast(self.node_p_type)
335 self.next_is_key = False
336 self.i += 1
337 return ('key' + str(self.i), self.current_typed['key'])
338 else:
339 self.next_is_key = True
340 return ('value' + str(self.i), self.current_typed['value'])
341
342 def next(self):
343 return self.__next__()
344
345 def __init__(self, val, container):
346 self.val = val
347 self.container = container
348
349 def children(self):
350 if self.val['d']['size'] == 0:
351 return []
352
353 isQt4 = has_field(self.val, 'e') # Qt4 has 'e', Qt5 doesn't
354 if isQt4:
355 return self._iteratorQt4(self.val)
356 else:
357 return self._iteratorQt5(self.val)
358
359 def to_string(self):
360 size = self.val['d']['size']
361
362 return "%s<%s, %s> (size = %s)" % ( self.container, self.val.type.template_argument(0), self.val.type.template_argument(1), size )
363
364 def display_hint (self):
365 return 'map'
366
367 class QHashPrinter:
368 "Print a QHash"
369
370 class _iterator(Iterator):
371 def __init__(self, val):
372 self.val = val
373 self.d = self.val['d']
374 self.ktype = self.val.type.template_argument(0)
375 self.vtype = self.val.type.template_argument(1)
376 self.end_node = self.d.cast(gdb.lookup_type('QHashData::Node').pointer())
377 self.data_node = self.firstNode()
378 self.count = 0
379
380 def __iter__(self):
381 return self
382
383 def hashNode (self):
384 "Casts the current QHashData::Node to a QHashNode and returns the result. See also QHash::concrete()"
385 return self.data_node.cast(gdb.lookup_type('QHashNode<%s, %s>' % (self.ktype, self.vtype)).pointer())
386
387 def firstNode (self):
388 "Get the first node, See QHashData::firstNode()."
389 e = self.d.cast(gdb.lookup_type('QHashData::Node').pointer())
390 #print "QHashData::firstNode() e %s" % e
391 bucketNum = 0
392 bucket = self.d['buckets'][bucketNum]
393 #print "QHashData::firstNode() *bucket %s" % bucket
394 n = self.d['numBuckets']
395 #print "QHashData::firstNode() n %s" % n
396 while n:
397 #print "QHashData::firstNode() in while, n %s" % n;
398 if bucket != e:
399 #print "QHashData::firstNode() in while, return *bucket %s" % bucket
400 return bucket
401 bucketNum += 1
402 bucket = self.d['buckets'][bucketNum]
403 #print "QHashData::firstNode() in while, new bucket %s" % bucket
404 n -= 1
405 #print "QHashData::firstNode() return e %s" % e
406 return e
407
408
409 def nextNode (self, node):
410 "Get the nextNode after the current, see also QHashData::nextNode()."
411 #print "******************************** nextNode"
412 #print "nextNode: node %s" % node
413 next = node['next'].cast(gdb.lookup_type('QHashData::Node').pointer())
414 e = next
415
416 #print "nextNode: next %s" % next
417 if next['next']:
418 #print "nextNode: return next"
419 return next
420
421 #print "nextNode: node->h %s" % node['h']
422 #print "nextNode: numBuckets %s" % self.d['numBuckets']
423 start = (node['h'] % self.d['numBuckets']) + 1
424 bucketNum = start
425 #print "nextNode: start %s" % start
426 bucket = self.d['buckets'][start]
427 #print "nextNode: bucket %s" % bucket
428 n = self.d['numBuckets'] - start
429 #print "nextNode: n %s" % n
430 while n:
431 #print "nextNode: in while; n %s" % n
432 #print "nextNode: in while; e %s" % e
433 #print "nextNode: in while; *bucket %s" % bucket
434 if bucket != e:
435 #print "nextNode: in while; return bucket %s" % bucket
436 return bucket
437 bucketNum += 1
438 bucket = self.d['buckets'][bucketNum]
439 n -= 1
440 #print "nextNode: return e %s" % e
441 return e
442
443 def __next__(self):
444 "GDB iteration, first call returns key, second value and then jumps to the next hash node."
445 if self.data_node == self.end_node:
446 raise StopIteration
447
448 node = self.hashNode()
449
450 if self.count % 2 == 0:
451 item = node['key']
452 else:
453 item = node['value']
454 self.data_node = self.nextNode(self.data_node)
455
456 self.count = self.count + 1
457 return ('[%d]' % self.count, item)
458
459 def __init__(self, val, container):
460 self.val = val
461 self.container = container
462
463 def children(self):
464 return self._iterator(self.val)
465
466 def to_string(self):
467 size = self.val['d']['size']
468
469 return "%s<%s, %s> (size = %s)" % ( self.container, self.val.type.template_argument(0), self.val.type.template_argument(1), size )
470
471 def display_hint (self):
472 return 'map'
473
474 class QDatePrinter:
475
476 def __init__(self, val):
477 self.val = val
478
479 def to_string(self):
480 julianDay = self.val['jd']
481
482 if julianDay == 0:
483 return "invalid QDate"
484
485 # Copied from Qt sources
486 if julianDay >= 2299161:
487 # Gregorian calendar starting from October 15, 1582
488 # This algorithm is from Henry F. Fliegel and Thomas C. Van Flandern
489 ell = julianDay + 68569;
490 n = (4 * ell) / 146097;
491 ell = ell - (146097 * n + 3) / 4;
492 i = (4000 * (ell + 1)) / 1461001;
493 ell = ell - (1461 * i) / 4 + 31;
494 j = (80 * ell) / 2447;
495 d = ell - (2447 * j) / 80;
496 ell = j / 11;
497 m = j + 2 - (12 * ell);
498 y = 100 * (n - 49) + i + ell;
499 else:
500 # Julian calendar until October 4, 1582
501 # Algorithm from Frequently Asked Questions about Calendars by Claus Toendering
502 julianDay += 32082;
503 dd = (4 * julianDay + 3) / 1461;
504 ee = julianDay - (1461 * dd) / 4;
505 mm = ((5 * ee) + 2) / 153;
506 d = ee - (153 * mm + 2) / 5 + 1;
507 m = mm + 3 - 12 * (mm / 10);
508 y = dd - 4800 + (mm / 10);
509 if y <= 0:
510 --y;
511 return "%d-%02d-%02d" % (y, m, d)
512
513 class QTimePrinter:
514
515 def __init__(self, val):
516 self.val = val
517
518 def to_string(self):
519 ds = self.val['mds']
520
521 if ds == -1:
522 return "invalid QTime"
523
524 MSECS_PER_HOUR = 3600000
525 SECS_PER_MIN = 60
526 MSECS_PER_MIN = 60000
527
528 hour = ds / MSECS_PER_HOUR
529 minute = (ds % MSECS_PER_HOUR) / MSECS_PER_MIN
530 second = (ds / 1000)%SECS_PER_MIN
531 msec = ds % 1000
532 return "%02d:%02d:%02d.%03d" % (hour, minute, second, msec)
533
534 class QDateTimePrinter:
535
536 def __init__(self, val):
537 self.val = val
538
539 def to_string(self):
540 time_t = gdb.parse_and_eval("reinterpret_cast<const QDateTime*>(%s)->toTime_t()" % self.val.address)
541 return time.ctime(int(time_t))
542
543 class QUrlPrinter:
544
545 def __init__(self, val):
546 self.val = val
547
548 def to_string(self):
549 # first try to access the Qt 5 data
550 try:
551 int_type = gdb.lookup_type('int')
552 string_type = gdb.lookup_type('QString')
553 string_pointer = string_type.pointer()
554
555 addr = self.val['d'].cast(gdb.lookup_type('char').pointer())
556 # skip QAtomicInt ref
557 addr += int_type.sizeof
558 # handle int port
559 port = addr.cast(int_type.pointer()).dereference()
560 addr += int_type.sizeof
561 # handle QString scheme
562 scheme = QStringPrinter(addr.cast(string_pointer).dereference()).to_string()
563 addr += string_type.sizeof
564 # handle QString username
565 username = QStringPrinter(addr.cast(string_pointer).dereference()).to_string()
566 addr += string_type.sizeof
567 # skip QString password
568 addr += string_type.sizeof
569 # handle QString host
570 host = QStringPrinter(addr.cast(string_pointer).dereference()).to_string()
571 addr += string_type.sizeof
572 # handle QString path
573 path = QStringPrinter(addr.cast(string_pointer).dereference()).to_string()
574 addr += string_type.sizeof
575 # handle QString query
576 query = QStringPrinter(addr.cast(string_pointer).dereference()).to_string()
577 addr += string_type.sizeof
578 # handle QString fragment
579 fragment = QStringPrinter(addr.cast(string_pointer).dereference()).to_string()
580
581 url = ""
582 if len(scheme) > 0:
583 # TODO: always adding // is apparently not compliant in all cases
584 url += scheme + "://"
585 if len(host) > 0:
586 if len(username) > 0:
587 url += username + "@"
588 url += host
589 if port != -1:
590 url += ":" + str(port)
591 url += path
592 if len(query) > 0:
593 url += "?" + query
594 if len(fragment) > 0:
595 url += "#" + fragment
596
597 return url
598 except:
599 pass
600 # then try to print directly, but that might lead to issues (see http://sourceware-org.1504.n7.nabble.com/help-Calling-malloc-from-a-Python-pretty-printer-td284031.html)
601 try:
602 return gdb.parse_and_eval("reinterpret_cast<const QUrl*>(%s)->toString((QUrl::FormattingOptions)QUrl::PrettyDecoded)" % self.val.address)
603 except:
604 pass
605 # if everything fails, maybe we deal with Qt 4 code
606 try:
607 return self.val['d']['encodedOriginal']
608 except RuntimeError:
609 #if no debug information is available for Qt, try guessing the correct address for encodedOriginal
610 #problem with this is that if QUrlPrivate members get changed, this fails
611 offset = gdb.lookup_type('int').sizeof
612 offset += offset % gdb.lookup_type('void').pointer().sizeof #alignment
613 offset += gdb.lookup_type('QString').sizeof * 6
614 offset += gdb.lookup_type('QByteArray').sizeof
615 encodedOriginal = self.val['d'].cast(gdb.lookup_type('char').pointer());
616 encodedOriginal += offset
617 encodedOriginal = encodedOriginal.cast(gdb.lookup_type('QByteArray').pointer()).dereference();
618 encodedOriginal = encodedOriginal['d']['data'].string()
619 return encodedOriginal
620
621 class QSetPrinter:
622 "Print a QSet"
623
624 def __init__(self, val):
625 self.val = val
626
627 class _iterator(Iterator):
628 def __init__(self, hashIterator):
629 self.hashIterator = hashIterator
630 self.count = 0
631
632 def __iter__(self):
633 return self
634
635 def __next__(self):
636 if self.hashIterator.data_node == self.hashIterator.end_node:
637 raise StopIteration
638
639 node = self.hashIterator.hashNode()
640
641 item = node['key']
642 self.hashIterator.data_node = self.hashIterator.nextNode(self.hashIterator.data_node)
643
644 self.count = self.count + 1
645 return ('[%d]' % (self.count-1), item)
646
647 def children(self):
648 hashPrinter = QHashPrinter(self.val['q_hash'], None)
649 hashIterator = hashPrinter._iterator(self.val['q_hash'])
650 return self._iterator(hashIterator)
651
652 def to_string(self):
653 size = self.val['q_hash']['d']['size']
654
655 return "QSet<%s> (size = %s)" % ( self.val.type.template_argument(0), size )
656
657
658 class QCharPrinter:
659
660 def __init__(self, val):
661 self.val = val
662
663 def to_string(self):
664 return unichr(self.val['ucs'])
665
666 def display_hint (self):
667 return 'string'
668
669 class QUuidPrinter:
670
671 def __init__(self, val):
672 self.val = val
673
674 def to_string(self):
675 return "QUuid({%x-%x-%x-%x%x-%x%x%x%x%x%x})" % (int(self.val['data1']), int(self.val['data2']), int(self.val['data3']),
676 int(self.val['data4'][0]), int(self.val['data4'][1]),
677 int(self.val['data4'][2]), int(self.val['data4'][3]),
678 int(self.val['data4'][4]), int(self.val['data4'][5]),
679 int(self.val['data4'][6]), int(self.val['data4'][7]))
680
681 def display_hint (self):
682 return 'string'
683
684 pretty_printers_dict = {}
685
686 def register_qt_printers (obj):
687 if obj == None:
688 obj = gdb
689
690 obj.pretty_printers.append(FunctionLookup(gdb, pretty_printers_dict))
691
692 def build_dictionary ():
693 pretty_printers_dict[re.compile('^QString$')] = lambda val: QStringPrinter(val)
694 pretty_printers_dict[re.compile('^QByteArray$')] = lambda val: QByteArrayPrinter(val)
695 pretty_printers_dict[re.compile('^QList<.*>$')] = lambda val: QListPrinter(val, 'QList', None)
696 pretty_printers_dict[re.compile('^QStringList$')] = lambda val: QListPrinter(val, 'QStringList', 'QString')
697 pretty_printers_dict[re.compile('^QQueue')] = lambda val: QListPrinter(val, 'QQueue', None)
698 pretty_printers_dict[re.compile('^QVector<.*>$')] = lambda val: QVectorPrinter(val, 'QVector')
699 pretty_printers_dict[re.compile('^QStack<.*>$')] = lambda val: QVectorPrinter(val, 'QStack')
700 pretty_printers_dict[re.compile('^QLinkedList<.*>$')] = lambda val: QLinkedListPrinter(val)
701 pretty_printers_dict[re.compile('^QMap<.*>$')] = lambda val: QMapPrinter(val, 'QMap')
702 pretty_printers_dict[re.compile('^QMultiMap<.*>$')] = lambda val: QMapPrinter(val, 'QMultiMap')
703 pretty_printers_dict[re.compile('^QHash<.*>$')] = lambda val: QHashPrinter(val, 'QHash')
704 pretty_printers_dict[re.compile('^QMultiHash<.*>$')] = lambda val: QHashPrinter(val, 'QMultiHash')
705 pretty_printers_dict[re.compile('^QDate$')] = lambda val: QDatePrinter(val)
706 pretty_printers_dict[re.compile('^QTime$')] = lambda val: QTimePrinter(val)
707 pretty_printers_dict[re.compile('^QDateTime$')] = lambda val: QDateTimePrinter(val)
708 pretty_printers_dict[re.compile('^QUrl$')] = lambda val: QUrlPrinter(val)
709 pretty_printers_dict[re.compile('^QSet<.*>$')] = lambda val: QSetPrinter(val)
710 pretty_printers_dict[re.compile('^QChar$')] = lambda val: QCharPrinter(val)
711 pretty_printers_dict[re.compile('^QUuid')] = lambda val: QUuidPrinter(val)
712
713
714 build_dictionary ()