def g_display(self): self.name = 'timeline ' + QString(self.node.name()) if not self.node.hasChildren(): self.setStateInfo(self.node.absolute() + ' doesn\'t have any children.') else: self.vfs = vfs.vfs() self.vlayout = QVBoxLayout() self.vlayout.setMargin(0) self.vlayout.setSpacing(0) self.hsplitter = QSplitter() self.ploter = PaintArea(self) self.options = OptionsLayout(self) self.hsplitter.addWidget(self.ploter) self.hsplitter.addWidget(self.options) self.vlayout.addWidget(self.hsplitter) self.setLayout(self.vlayout) self.draw = Drawer(self) # CountThread compute node amount self.countThread = CountThread(self, self.countThreadOver) self.populateThread = DataThread(self, self.dataThreadOver) self.maxOccThread = MaxOccThread(self, self.maxOccThreadOver) self.workerThread = WorkerThread(self) #comment it to avoid redraw everytime painter is resized self.connect(self.workerThread, SIGNAL('refresh'), self.reDraw)
class Timeline(QWidget, Script): def __init__(self): Script.__init__(self, 'timeline') QWidget.__init__(self, None) self.type = 'timeline' self.nodeCount = 0 self.timesCount = 0 self.timeMap = {} self.m = 40 # Padding self.lineHeight = 4 # Pixel height of line self.metricOk = False self.colors = [['blue', Qt.blue], ['red', Qt.red], ['green', Qt.green], ['yellow', Qt.yellow], ['magenta', Qt.magenta], ['cyan', Qt.cyan]] self.stateinfo = 'Initialized' self.dateMin = long(0xffffffffffffffff) self.dateMax = long(0) self.baseDateMin = self.dateMin self.baseDateMax = self.dateMax self.selDateMin = None self.selDateMax = None self.maxOcc = 0 self.maxOccZoom = 0 self.xHop = 0 self.xRange = 0 self.dataListsCreated = False def start(self, args): self.node = args['file'].value() def status(self): return 0 def updateWidget(self): pass def g_display(self): self.name = 'timeline ' + QString(self.node.name()) if not self.node.hasChildren(): self.setStateInfo(self.node.absolute() + ' doesn\'t have any children.') else: self.vfs = vfs.vfs() self.vlayout = QVBoxLayout() self.vlayout.setMargin(0) self.vlayout.setSpacing(0) self.hsplitter = QSplitter() self.ploter = PaintArea(self) self.options = OptionsLayout(self) self.hsplitter.addWidget(self.ploter) self.hsplitter.addWidget(self.options) self.vlayout.addWidget(self.hsplitter) self.setLayout(self.vlayout) self.draw = Drawer(self) # CountThread compute node amount self.countThread = CountThread(self, self.countThreadOver) self.populateThread = DataThread(self, self.dataThreadOver) self.maxOccThread = MaxOccThread(self, self.maxOccThreadOver) self.workerThread = WorkerThread(self) #comment it to avoid redraw everytime painter is resized self.connect(self.workerThread, SIGNAL('refresh'), self.reDraw) def fromUSec(self, usec2): usec = int(usec2) days = usec / (86400 * 1000000) seconds = (usec - days * 86400 * 1000000) / 1000000 misec = usec - days * 86400 * 1000000 - seconds * 1000000 if days >= 1 and datetime.fromordinal(days) >= datetime.fromordinal(1): return datetime.fromordinal(days) + timedelta(seconds = seconds, microseconds = misec) return None def toUSec(self, dtime): return dtime.toordinal() * 86400 * 1000000 + dtime.hour * 3600 * 1000000 + dtime.minute * 60 * 1000000 + dtime.second * 1000000 + dtime.microsecond def dumpTimeMap(self): print self.timeMap for k in self.timeMap.keys(): print 'module:', k for attr in self.timeMap[k]: sAttrPath = '/' for v in attr[:-1]: sAttrPath += v + '/' print ' ', sAttrPath, ':', attr[-1] def countThreadOver(self): if not self.nodeCount: self.setStateInfo('No timestamp found any subset of ' + self.node.absolute()) # self.disconnect(self.workerThread, SIGNAL('refresh'), self.reDraw) return self.setStateInfo(str(self.nodeCount) + ' nodes found') # self.dumpTimeMap() # Find/virtual draw maximum size of Y text painter = QPainter() nullPixmap = QPixmap(self.ploter.width, self.ploter.height) painter.begin(nullPixmap) rect = painter.drawText(self.draw.paddingYText, 10, 0, 0, 0, str(self.nodeCount) + '.0') painter.end() self.draw.yLeftMargin = self.draw.paddingYText * 2 + rect.width() self.options.newInformations() self.options.createMetricTools() self.metricOk = True # self.createFullTimeLists() self.workerThread.render() def createFullTimeLists(self): self.populateThread = DataThread(self, self.dataThreadOver) self.populateThread.start() def dataThreadOver(self): self.dataListsCreated = True for family in self.options.configuration: # family[0] = extended|static|usual for time in family[1]: if time[1][5][1]: dateMin = time[1][6][1][0] dateMax = time[1][6][1][1] if dateMin < self.baseDateMin: self.baseDateMin = dateMin if dateMax > self.baseDateMax: self.baseDateMax = dateMax self.options.newInformations() self.workerThread.render() def findMaxValue(self): self.xRange = (self.ploter.width - self.m - self.draw.yLeftMargin) / self.lineHeight self.xHop = (self.baseDateMax - self.baseDateMin) / self.xRange def maxOccThreadOver(self): self.updatePaintingArea() def zoomMaxOcc(self): self.xRange = (self.ploter.width - self.m - self.draw.yLeftMargin) / self.lineHeight xHop = (self.selDateMax - self.selDateMin) / self.xRange newMaxOcc = 0 for family in self.options.configuration: for time in family[1]: timeChecked = self.selDateMin if timeChecked == self.selDateMax: # Every nodes have the same time, setting maxOcc computing time + 100usec occ = self.elementsInRange(time[1][5][1], timeChecked, timeChecked + 100) if occ > newMaxOcc: newMaxOcc = occ while timeChecked <= self.selDateMax: occ = self.elementsInRange(time[1][5][1], timeChecked, timeChecked + xHop) if occ > newMaxOcc: newMaxOcc = occ timeChecked += xHop self.maxOccZoom = newMaxOcc def reDraw(self, resized = False): if resized: self.updatePaintingArea(True) def updatePaintingArea(self, resized = False): if not self.maxOcc: return self.painter = QPainter() self.mainPixmap = QPixmap(self.ploter.width, self.ploter.height) self.mainPixmap.fill(Qt.white) self.gridPixmap = QPixmap(self.ploter.width, self.ploter.height) self.gridPixmap.fill(Qt.transparent) self.painter.begin(self.gridPixmap) if self.options.zoom and not self.maxOccZoom: self.zoomMaxOcc() self.draw.setDynamicValues(self) self.draw.drawInfos() self.draw.drawGrid() self.painter.end() for family in self.options.configuration: for time in family[1]: if resized: time[1][8][1][0] = True time[1][7][1][0] = True if self.options.zoom and time[1][8][1][0]: # Create zoom pixmaps time[1][8][1][1] = QPixmap(self.ploter.width, self.ploter.height) time[1][8][1][1].fill(Qt.transparent) penColor = None for color in self.colors: if color[0] == time[1][1][1]: penColor = QColor(color[1]) penColor.setAlpha(163) break if penColor: self.painter.begin(time[1][8][1][1]) pen = self.painter.pen() pen.setColor(penColor) pen.setWidth(self.lineHeight) self.painter.setPen(pen) self.draw.drawTimeline(self.painter, time[1][5][1]) self.painter.end() time[1][8][1][0] = False elif not time[1][7][1][1] or time[1][7][1][0]: # Create main (original sized) pixmaps time[1][7][1][1] = QPixmap(self.ploter.width, self.ploter.height) time[1][7][1][1].fill(Qt.transparent) penColor = None for color in self.colors: if color[0] == time[1][1][1]: penColor = QColor(color[1]) penColor.setAlpha(163) break if penColor: self.painter.begin(time[1][7][1][1]) pen = self.painter.pen() pen.setColor(penColor) pen.setWidth(self.lineHeight) self.painter.setPen(pen) self.draw.drawTimeline(self.painter, time[1][5][1]) self.painter.end() time[1][7][1][0] = False self.painter.begin(self.mainPixmap) # Draw grid self.painter.drawImage(QPointF(0, 0), self.gridPixmap.toImage(), QRectF(0, 0, self.ploter.width, self.ploter.height)) for family in self.options.configuration: for time in family[1]: # Draw each time pixmap if not self.options.zoom: # Draw global view, if zoom not enabled if time[1][7][1][1] and time[1][0][1]: self.painter.drawImage(QPointF(0, 0), time[1][7][1][1].toImage(), QRectF(0, 0, self.ploter.width, self.ploter.height)) else: # Draw zoom pixmaps if time[1][8][1][1] and time[1][0][1]: self.painter.drawImage(QPointF(0, 0), time[1][8][1][1].toImage(), QRectF(0, 0, self.ploter.width, self.ploter.height)) self.painter.end() self.ploter.scene.clear() self.ploter.scene.addPixmap(self.mainPixmap) self.ploter.setEnabled(True) self.update() def setStateInfo(self, sinfo): self.stateinfo = str(sinfo) def stateInfo(self): if self.nodeCount: return self.stateinfo + ' - ' + str(self.nodeCount) + ' nodes' else: return self.stateinfo def nodesInRange(self, x1, x2): if not self.selDateMin: timeCheck = self.baseDateMin timeMax = self.baseDateMax else: timeCheck = self.selDateMin timeMax = self.selDateMax count = 0 while timeCheck < timeMax: for family in self.options.configuration: for time in family[1]: occ = self.elementsInRange(time[1][5][1], timeCheck, timeCheck + self.xHop) if occ: if self.lineMatched(timeCheck, occ, x1, x2) and time[1][0][1]: count += occ timeCheck += self.xHop if count: self.options.zoomButton.setEnabled(True) self.options.exportButton.setEnabled(True) if count > 1: self.options.selectedNodes.setText(str(count) + ' time values selected') else: self.options.selectedNodes.setText('One time value selected') else: self.options.zoomButton.setEnabled(False) self.options.exportButton.setEnabled(False) self.options.selectedNodes.setText('Nothing selected') def lineMatched(self, usec, occ, x1, x2): if not self.selDateMin: dateMin = self.baseDateMin dateMax = self.baseDateMax else: dateMin = self.selDateMin dateMax = self.selDateMax if (dateMax - dateMin) > 0: x = ((usec - dateMin) * (self.ploter.width - self.m - self.draw.yLeftMargin)) / (dateMax - dateMin) + self.draw.yLeftMargin if x <= self.draw.yLeftMargin: x += 3 x_min = x - 2 x_max = x + 2 if x_min >= x1 and x_max <= x2: return True return False def elementsInRange(self, root, tMin, tMax): ''' Returns amount of node in a date range, given as long Dichotomic search, but this can be improved because we only search for smaller timestamp and decrease index if greather. ''' if not tMin or not tMax: return 0 nodesCount = 0 iMin, iMax = 0, len(root['dates']) - 1 iCurrent = iMax / 2 # Sync cursor in dates list on tMin ; should be improved while iMin != iMax or not iMax: if tMin >= root['dates'][iCurrent] or not iCurrent: while iCurrent and tMin >= root['dates'][iCurrent]: # Should be improved iCurrent -= 1 break elif tMin < root['dates'][iCurrent]: iMax = iCurrent iCurrent = iMin + ((iCurrent - iMin) / 2) # Count amount of nodes between tMin and tMax endOfList = len(root['dates']) while iCurrent < endOfList and tMax >= root['dates'][iCurrent]: if tMin <= root['dates'][iCurrent]: nodesCount += len(root['nodes'][iCurrent]) iCurrent += 1 return nodesCount def elementsInRangeToNodeList(self, root, tMin, tMax): ''' Returns a list of nodes pointer, made of nodes in given date range. Dichotomic search, but this can be improved because we only search for smaller timestamp and decrease index if greather. ''' if not tMin or not tMax: return 0 nodesList = [] iMin, iMax = 0, len(root['dates']) - 1 iCurrent = iMax / 2 # Sync cursor in dates list on tMin ; should be improved while iMin != iMax or not iMax: if tMin >= root['dates'][iCurrent] or not iCurrent: while iCurrent and tMin >= root['dates'][iCurrent]: # Should be improved iCurrent -= 1 break elif tMin < root['dates'][iCurrent]: iMax = iCurrent iCurrent = iMin + ((iCurrent - iMin) / 2) # Count amount of nodes between tMin and tMax endOfList = len(root['dates']) while iCurrent < endOfList and tMax >= root['dates'][iCurrent]: if tMin <= root['dates'][iCurrent]: nodesList.append(root['nodes'][iCurrent]) iCurrent += 1 return nodesList
class Timeline(QWidget, Script): def __init__(self): Script.__init__(self, 'timeline') QWidget.__init__(self, None) self.type = 'timeline' self.nodeCount = 0 self.timesCount = 0 self.timeMap = {} self.m = 40 # Padding self.lineHeight = 4 # Pixel height of line self.metricOk = False self.colors = [['blue', Qt.blue], ['red', Qt.red], ['green', Qt.green], ['yellow', Qt.yellow], ['magenta', Qt.magenta], ['cyan', Qt.cyan]] self.stateinfo = 'Initialized' self.dateMin = long(0xffffffffffffffff) self.dateMax = long(0) self.baseDateMin = self.dateMin self.baseDateMax = self.dateMax self.selDateMin = None self.selDateMax = None self.maxOcc = 0 self.maxOccZoom = 0 self.xHop = 0 self.xRange = 0 self.dataListsCreated = False def start(self, args): self.node = args['file'].value() def status(self): return 0 def updateWidget(self): pass def g_display(self): self.name = 'timeline ' + QString(self.node.name()) if not self.node.hasChildren(): self.setStateInfo(self.node.absolute() + ' doesn\'t have any children.') else: self.vfs = vfs.vfs() self.vlayout = QVBoxLayout() self.vlayout.setMargin(0) self.vlayout.setSpacing(0) self.hsplitter = QSplitter() self.ploter = PaintArea(self) self.options = OptionsLayout(self) self.hsplitter.addWidget(self.ploter) self.hsplitter.addWidget(self.options) self.vlayout.addWidget(self.hsplitter) self.setLayout(self.vlayout) self.draw = Drawer(self) # CountThread compute node amount self.countThread = CountThread(self, self.countThreadOver) self.populateThread = DataThread(self, self.dataThreadOver) self.maxOccThread = MaxOccThread(self, self.maxOccThreadOver) self.workerThread = WorkerThread(self) #comment it to avoid redraw everytime painter is resized self.connect(self.workerThread, SIGNAL('refresh'), self.reDraw) def fromUSec(self, usec2): usec = int(usec2) days = usec / (86400 * 1000000) seconds = (usec - days * 86400 * 1000000) / 1000000 misec = usec - days * 86400 * 1000000 - seconds * 1000000 if days >= 1 and datetime.fromordinal(days) >= datetime.fromordinal(1): return datetime.fromordinal(days) + timedelta(seconds=seconds, microseconds=misec) return None def toUSec(self, dtime): return dtime.toordinal( ) * 86400 * 1000000 + dtime.hour * 3600 * 1000000 + dtime.minute * 60 * 1000000 + dtime.second * 1000000 + dtime.microsecond def dumpTimeMap(self): print self.timeMap for k in self.timeMap.keys(): print 'module:', k for attr in self.timeMap[k]: sAttrPath = '/' for v in attr[:-1]: sAttrPath += v + '/' print ' ', sAttrPath, ':', attr[-1] def countThreadOver(self): if not self.nodeCount: self.setStateInfo('No timestamp found any subset of ' + self.node.absolute()) # self.disconnect(self.workerThread, SIGNAL('refresh'), self.reDraw) return self.setStateInfo(str(self.nodeCount) + ' nodes found') # self.dumpTimeMap() # Find/virtual draw maximum size of Y text painter = QPainter() nullPixmap = QPixmap(self.ploter.width, self.ploter.height) painter.begin(nullPixmap) rect = painter.drawText(self.draw.paddingYText, 10, 0, 0, 0, str(self.nodeCount) + '.0') painter.end() self.draw.yLeftMargin = self.draw.paddingYText * 2 + rect.width() self.options.newInformations() self.options.createMetricTools() self.metricOk = True # self.createFullTimeLists() self.workerThread.render() def createFullTimeLists(self): self.populateThread = DataThread(self, self.dataThreadOver) self.populateThread.start() def dataThreadOver(self): self.dataListsCreated = True for family in self.options.configuration: # family[0] = extended|static|usual for time in family[1]: if time[1][5][1]: dateMin = time[1][6][1][0] dateMax = time[1][6][1][1] if dateMin != None and dateMin > 0 and dateMin < 18446744073709551615 and dateMin < self.baseDateMin: self.baseDateMin = dateMin if dateMax != None and dateMax > 0 and dateMax < 18446744073709551615 and dateMax > self.baseDateMax: self.baseDateMax = dateMax self.options.newInformations() self.workerThread.render() def findMaxValue(self): self.xRange = (self.ploter.width - self.m - self.draw.yLeftMargin) / self.lineHeight self.xHop = (self.baseDateMax - self.baseDateMin) / self.xRange def maxOccThreadOver(self): self.updatePaintingArea() def zoomMaxOcc(self): self.xRange = (self.ploter.width - self.m - self.draw.yLeftMargin) / self.lineHeight xHop = (self.selDateMax - self.selDateMin) / self.xRange newMaxOcc = 0 for family in self.options.configuration: for time in family[1]: timeChecked = self.selDateMin if timeChecked == self.selDateMax: # Every nodes have the same time, setting maxOcc computing time + 100usec occ = self.elementsInRange(time[1][5][1], timeChecked, timeChecked + 100) if occ > newMaxOcc: newMaxOcc = occ while timeChecked <= self.selDateMax: occ = self.elementsInRange(time[1][5][1], timeChecked, timeChecked + xHop) if occ > newMaxOcc: newMaxOcc = occ timeChecked += xHop self.maxOccZoom = newMaxOcc def reDraw(self, resized=False): if resized: self.updatePaintingArea(True) def updatePaintingArea(self, resized=False): if not self.maxOcc: return self.painter = QPainter() self.mainPixmap = QPixmap(self.ploter.width, self.ploter.height) self.mainPixmap.fill(Qt.white) self.gridPixmap = QPixmap(self.ploter.width, self.ploter.height) self.gridPixmap.fill(Qt.transparent) self.painter.begin(self.gridPixmap) if self.options.zoom and not self.maxOccZoom: self.zoomMaxOcc() self.draw.setDynamicValues(self) self.draw.drawInfos() self.draw.drawGrid() self.painter.end() for family in self.options.configuration: for time in family[1]: if resized: time[1][8][1][0] = True time[1][7][1][0] = True if self.options.zoom and time[1][8][1][0]: # Create zoom pixmaps time[1][8][1][1] = QPixmap(self.ploter.width, self.ploter.height) time[1][8][1][1].fill(Qt.transparent) penColor = None for color in self.colors: if color[0] == time[1][1][1]: penColor = QColor(color[1]) penColor.setAlpha(163) break if penColor: self.painter.begin(time[1][8][1][1]) pen = self.painter.pen() pen.setColor(penColor) pen.setWidth(self.lineHeight) self.painter.setPen(pen) self.draw.drawTimeline(self.painter, time[1][5][1]) self.painter.end() time[1][8][1][0] = False elif not time[1][7][1][1] or time[1][7][1][0]: # Create main (original sized) pixmaps time[1][7][1][1] = QPixmap(self.ploter.width, self.ploter.height) time[1][7][1][1].fill(Qt.transparent) penColor = None for color in self.colors: if color[0] == time[1][1][1]: penColor = QColor(color[1]) penColor.setAlpha(163) break if penColor: self.painter.begin(time[1][7][1][1]) pen = self.painter.pen() pen.setColor(penColor) pen.setWidth(self.lineHeight) self.painter.setPen(pen) self.draw.drawTimeline(self.painter, time[1][5][1]) self.painter.end() time[1][7][1][0] = False self.painter.begin(self.mainPixmap) # Draw grid self.painter.drawImage( QPointF(0, 0), self.gridPixmap.toImage(), QRectF(0, 0, self.ploter.width, self.ploter.height)) for family in self.options.configuration: for time in family[1]: # Draw each time pixmap if not self.options.zoom: # Draw global view, if zoom not enabled if time[1][7][1][1] and time[1][0][1]: self.painter.drawImage( QPointF(0, 0), time[1][7][1][1].toImage(), QRectF(0, 0, self.ploter.width, self.ploter.height)) else: # Draw zoom pixmaps if time[1][8][1][1] and time[1][0][1]: self.painter.drawImage( QPointF(0, 0), time[1][8][1][1].toImage(), QRectF(0, 0, self.ploter.width, self.ploter.height)) self.painter.end() self.ploter.scene.clear() self.ploter.scene.addPixmap(self.mainPixmap) self.ploter.setEnabled(True) self.update() def setStateInfo(self, sinfo): self.stateinfo = str(sinfo) def stateInfo(self): if self.nodeCount: return self.stateinfo + ' - ' + str(self.nodeCount) + ' nodes' else: return self.stateinfo def nodesInRange(self, x1, x2): if not self.selDateMin: timeCheck = self.baseDateMin timeMax = self.baseDateMax else: timeCheck = self.selDateMin timeMax = self.selDateMax count = 0 while timeCheck < timeMax: for family in self.options.configuration: for time in family[1]: occ = self.elementsInRange(time[1][5][1], timeCheck, timeCheck + self.xHop) if occ: if self.lineMatched(timeCheck, occ, x1, x2) and time[1][0][1]: count += occ timeCheck += self.xHop if count: self.options.zoomButton.setEnabled(True) self.options.exportButton.setEnabled(True) if count > 1: self.options.selectedNodes.setText( str(count) + ' time values selected') else: self.options.selectedNodes.setText('One time value selected') else: self.options.zoomButton.setEnabled(False) self.options.exportButton.setEnabled(False) self.options.selectedNodes.setText('Nothing selected') def lineMatched(self, usec, occ, x1, x2): if not self.selDateMin: dateMin = self.baseDateMin dateMax = self.baseDateMax else: dateMin = self.selDateMin dateMax = self.selDateMax if (dateMax - dateMin) > 0: x = ((usec - dateMin) * (self.ploter.width - self.m - self.draw.yLeftMargin)) / ( dateMax - dateMin) + self.draw.yLeftMargin if x <= self.draw.yLeftMargin: x += 3 x_min = x - 2 x_max = x + 2 if x_min >= x1 and x_max <= x2: return True return False def elementsInRange(self, root, tMin, tMax): ''' Returns amount of node in a date range, given as long Dichotomic search, but this can be improved because we only search for smaller timestamp and decrease index if greather. ''' if not tMin or not tMax: return 0 nodesCount = 0 if root['dates'] == None: return 0 iMin, iMax = 0, len(root['dates']) - 1 iCurrent = iMax / 2 # Sync cursor in dates list on tMin ; should be improved while iMin != iMax or not iMax: if tMin >= root['dates'][iCurrent] or not iCurrent: while iCurrent and tMin >= root['dates'][iCurrent]: # Should be improved iCurrent -= 1 break elif tMin < root['dates'][iCurrent]: iMax = iCurrent iCurrent = iMin + ((iCurrent - iMin) / 2) # Count amount of nodes between tMin and tMax endOfList = len(root['dates']) while iCurrent < endOfList and tMax >= root['dates'][iCurrent]: if tMin <= root['dates'][iCurrent]: nodesCount += len(root['nodes'][iCurrent]) iCurrent += 1 return nodesCount def elementsInRangeToNodeList(self, root, tMin, tMax): ''' Returns a list of nodes pointer, made of nodes in given date range. Dichotomic search, but this can be improved because we only search for smaller timestamp and decrease index if greather. ''' if not tMin or not tMax: return 0 nodesList = [] iMin, iMax = 0, len(root['dates']) - 1 iCurrent = iMax / 2 # Sync cursor in dates list on tMin ; should be improved while iMin != iMax or not iMax: if tMin >= root['dates'][iCurrent] or not iCurrent: while iCurrent and tMin >= root['dates'][iCurrent]: # Should be improved iCurrent -= 1 break elif tMin < root['dates'][iCurrent]: iMax = iCurrent iCurrent = iMin + ((iCurrent - iMin) / 2) # Count amount of nodes between tMin and tMax endOfList = len(root['dates']) while iCurrent < endOfList and tMax >= root['dates'][iCurrent]: if tMin <= root['dates'][iCurrent]: nodesList.append(root['nodes'][iCurrent]) iCurrent += 1 return nodesList