#!/usr/bin/python
#
#IOApps, IO profiler and IO traces replayer
#
#	Copyright (C) 2010 Jiri Horky <jiri.horky@gmail.com>
#
#	This program is free software; you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation; either version 2 of the License, or
#	(at your option) any later version.
#
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#
#	You should have received a copy of the GNU General Public License
#	along with this program; if not, write to the Free Software
#	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#


import sys
from PyQt4 import QtCore
from PyQt4.QtGui import *
from PyQt4.QtCore import * 
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.ticker import FuncFormatter
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
from matplotlib.figure import Figure
import numpy as np
import ioapps
import getopt
#import cProfile
from grapher import *

#locale.setlocale(locale.LC_ALL, 'en_US')

	
class MyDelegate(QStyledItemDelegate):
	def __init__(self, parent=None, *args):
		QStyledItemDelegate.__init__(self, parent, *args)

	def paint(self, painter, option, index):
		data = index.data()	  
		if data.type() == QVariant.Double:					
		#if data.type() == QVariant.Date:
			painter.save()			
			if option.state & QStyle.State_Selected:				
				painter.fillRect(option.rect, option.palette.highlight())			 
				pen = painter.pen()
				pen.setColor(QApplication.palette().color(QPalette.HighlightedText))
				painter.setPen(pen)
			else:
				painter.fillRect(option.rect, QBrush(index.data(Qt.BackgroundRole)))											
			val = data.toPyObject()
			if val > 1:
				formatString = "%0.1f"				
			else:
				formatString = "%0.3f"
						  
			text = locale.format(formatString, val, grouping=False)			
			#text = formatString % val
			painter.drawText(option.rect, Qt.AlignCenter, text)
			painter.restore()
		else:
			QStyledItemDelegate.paint(self, painter, option, index);				
			 
class DetailTable(QStandardItemModel):
	""" Table of operations """
	#dataLoaded = QtCore.pyqtSignal()	
	
	def __init__(self, *args):
		QStandardItemModel.__init__(self, *args)
		header = QStringList()
		header.append("Start[s]")		
		header.append("Offset[kiB]")   
		header.append("Size[kiB]")		
		header.append("Dur[ms]")
		self.setHorizontalHeaderLabels(header)	
		self.setSortRole(Qt.DisplayRole)
				
	
	def setData(self, dict):
		timeOpened = dict[0]
		data = dict[1]  
		
			
		#rootItem = self.invisibleRootItem()		
		#self.beginInsertRows(QModelIndex(), 0, len(data)-1)			 
		for item in data:
			myList = []
			off = item[0]
			size = item[1]
			start = item[2] - timeOpened
			dur = item[3]
				
			stdItem = QStandardItem()   
			a = QVariant(start)
			stdItem.setData(a, Qt.DisplayRole)			
			myList.append(stdItem)
	
			stdItem = QStandardItem()   
			a = QVariant(off)
			stdItem.setData(a, Qt.DisplayRole)			
			myList.append(stdItem)					
			
			stdItem = QStandardItem()   
			a = QVariant(size)
			stdItem.setData(a, Qt.DisplayRole)			
			myList.append(stdItem)		
			
			stdItem = QStandardItem()   
			a = QVariant(dur)
			stdItem.setData(a, Qt.DisplayRole)			
			myList.append(stdItem)
								
			self.appendRow(myList)								
		#self.dataLoaded.emit()
		self.emit(SIGNAL("dataLoaded"),()) 
						

class MyTableView(QTableView):
	expandableSection = 0
	
	def __init__(self, parent = None):
		QTableView.__init__(self, parent)
		self.setSortingEnabled(True)
		self.setEditTriggers(QAbstractItemView.NoEditTriggers)
		self.setSelectionBehavior(QAbstractItemView.SelectRows)
		self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
		
	def resizeEvent(self, event):
		self.setUpdatesEnabled(False)
		self.horizontalHeader().setStretchLastSection(False) #To make sure it don't get resized before we compute what we want
		self.horizontalHeader().resizeSections(QHeaderView.ResizeToContents)		
		
		
		headerLen = self.horizontalHeader().length()
		sectionLen = self.horizontalHeader().sectionSize(self.expandableSection)
		viewLen = self.viewport().width()
					
		if headerLen < viewLen:
			self.horizontalHeader().setStretchLastSection(True)			
		else:
			newLen = sectionLen - (headerLen - viewLen)
			self.horizontalHeader().resizeSection(self.expandableSection, newLen)
			
		self.setUpdatesEnabled(True)
		self.emit(SIGNAL("sizeChanged"),())
		
		
class MyTableWidget(QTableWidget):
	expandableSection = 0
	dataSource = None
	def __init__(self, parent = None):
		QTableWidget.__init__(self, parent)	
		self.setRowCount(1);
		self.setColumnCount(5);
		self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
		
		header = QStringList()
		header.append("#Count")
		header.append("# ops")
		header.append("fileSize[MiB]")		
		header.append("sumSize[MiB]")
		header.append("duration[s]")
		self.setHorizontalHeaderLabels(header)
		self.setMaximumHeight(60)					
		self.setSortingEnabled(False)
		self.setEditTriggers(QAbstractItemView.NoEditTriggers)		
			
	def resizeEvent(self, event):
		self.setUpdatesEnabled(False)
		self.horizontalHeader().setStretchLastSection(False) #To make sure it don't get resized before we compute what we want
		self.horizontalHeader().resizeSections(QHeaderView.ResizeToContents)		
		
		
		headerLen = self.horizontalHeader().length()
		sectionLen = self.horizontalHeader().sectionSize(self.expandableSection)
		viewLen = self.viewport().width()
					
		if headerLen < viewLen:
			self.horizontalHeader().setStretchLastSection(True)			
		else:
			newLen = sectionLen - (headerLen - viewLen)
			self.horizontalHeader().resizeSection(self.expandableSection, newLen)
			
		self.setUpdatesEnabled(True)
	def setDataSource(self, dataSource):
		self.dataSource = dataSource
	
	def recomputeData(self):
		ops = 0
		fileSize = 0
		sumSize = 0		
		dur = 0
		count = self.dataSource.rowCount()
		for i in range(0, count):			
			ops += int(self.dataSource.index(i, 1).data().toPyObject())
			fileSize += float(self.dataSource.index(i, 2).data().toPyObject() / 1024)
			sumSize += float(self.dataSource.index(i, 3).data().toPyObject() / 1024)
			dur += float(self.dataSource.index(i, 4).data().toPyObject() / 1000)
		self.setItem(0,0, QTableWidgetItem(QString.number(count)));
		self.setItem(0,1, QTableWidgetItem(QString.number(ops)))
		self.setItem(0,2, QTableWidgetItem(QString.number(fileSize)))
		self.setItem(0,3, QTableWidgetItem(QString.number(sumSize)))
		self.setItem(0,4, QTableWidgetItem(QString.number(dur)))
					
		
		
		
#class NameFilterProxyModel(QSortFilterProxyModel):
#	def __init(self, column = 0, parent = None):
#		QSortFilterProxyModel.__init__(self,parent)		 
# int source_row, const QModelIndex & source_parent		 
#	def filterAcceptsRow(self, row, parent):
		

class DetailDialog(QDialog):
	reads = "reads";
	writes = "writes";
	def __init__(self, fileName, reads, dataHolder, parent = None):
		QDialog.__init__(self, parent);				   
		if reads:
			self.mode = self.reads;
		else:
			self.mode = self.writes;
			 
		self.fileName = fileName
		self.dataHolder = dataHolder
		self.setWindowTitle(fileName + " - " + self.mode)
		
		self.grapher = SubGrapher()
		if reads:
			self.grapher.setType(self.grapher.READS)
		else:
			self.grapher.setType(self.grapher.WRITES)
		self.grapher.setName(self.fileName)
		self.grapher.setTimeMode('relfile')
		self.grapher.setDataHolder(dataHolder)
		
		self.highlightedItems = []
		self.standardBrush = None		
								  
		# Create the mpl Figure and FigCanvas objects. 
		# 5x4 inches, 72 dots-per-inch
		#
		self.dpi = 72
		self.fig = Figure((6.0, 5.0), dpi=self.dpi)
		self.canvas = FigureCanvas(self.fig)
		self.canvas.setParent(self)
		self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
		
		#our table:
		self.model = None
		self.view = QTableView()						
		self.view.setSortingEnabled(True)
		self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
		self.view.horizontalHeader()
		self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
		delegate = MyDelegate()
		self.view.setItemDelegate(delegate)		
		self.view.setMinimumWidth(415)
		self.view.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
		
	
		# Since we have only one plot, we can use add_axes 
		# instead of add_subplot, but then the subplot
		# configuration tool in the navigation toolbar wouldn't
		# work.
		#
		self.axes = self.fig.add_subplot(111)
		self.grapher.setAxes(self.axes)
		self.grapher.setFig(self.fig)
				
		self.canvas.mpl_connect('pick_event', self.on_pick)			
		self.mpl_toolbar = NavigationToolbar(self.canvas, self)
		
		# Other GUI controls
		#						 
		self.draw_button = QPushButton("&Highlight selected")		
		QObject.connect(self.draw_button, SIGNAL("clicked()"), self.__highlightSelected)
		QObject.connect(self.draw_button, SIGNAL("clicked()"), self.__highlightSelected)
		self.displayStatistics = QCheckBox("Display statistics")
		QObject.connect(self.displayStatistics, SIGNAL("stateChanged(int)"), self.__showPlot)							   
		
		plot_label = QLabel('Type of plot:')		
		
		self.patternButton = QRadioButton("Pattern diagram")
		self.histSizeButton = QRadioButton("Size histogram")
		self.histTimeButton = QRadioButton("Time histogram")
		self.histSpeedButton = QRadioButton("Speed histogram")		
		
	
		self.patternButton.setChecked(True)
		QObject.connect(self.patternButton, SIGNAL("toggled(bool)"), self.__showPlot)
		QObject.connect(self.histSizeButton, SIGNAL("toggled(bool)"), self.__showPlot)
		QObject.connect(self.histTimeButton, SIGNAL("toggled(bool)"), self.__showPlot)
		QObject.connect(self.histSpeedButton, SIGNAL("toggled(bool)"), self.__showPlot)		 
					
		
		#
		# Layout with box sizers
		# 
		hbox = QHBoxLayout()
		
		hbox.addWidget(self.draw_button)
		hbox.addWidget(self.displayStatistics);
		hbox.addStretch()
		for w in [plot_label, self.patternButton, self.histSizeButton, self.histTimeButton, self.histSpeedButton]:
			hbox.addWidget(w)
			hbox.setAlignment(w, Qt.AlignVCenter)
		
		vvbox = QVBoxLayout()
		vvbox.addWidget(self.canvas)
		vvbox.addWidget(self.mpl_toolbar)
		
		hhbox = QHBoxLayout()
		hhbox.addWidget(self.view)		
		hhbox.addLayout(vvbox)
		
		vbox = QVBoxLayout()
						
		vbox.addLayout(hhbox)				
		vbox.addLayout(hbox)		
		self.setLayout(vbox)
				
		self.__showPlot()
		
	def __clearHighlighted(self):
		if self.standardBrush:
			for item in self.highlightedItems:							   
				item.setBackground(self.standardBrush)
	
	def __highlightRows(self, rows):
		if self.standardBrush == None: #this is the first time we are called
			self.standardBrush = self.view.model().item(0,0).background()
		l = []
		brush = QBrush(Qt.red)
		for row in rows:
			for i in xrange(self.view.model().columnCount()):
				item = self.view.model().item(row, i)	
				item.setBackground(brush)
				l.append(item);
		return l
				
	def __highlightSelected(self):
		self.__clearHighlighted();
		
		indexes = self.view.selectedIndexes()
		rows = []	 
		for index in indexes:
			rows.append(index.row())
		rowset = set(rows);
		
		self.highlightedItems = self.__highlightRows(rowset)
		self.__highlightLines(rowset, self.grapher.lineCollection())
		self.__highlightRows(rowset)
			 
		self.canvas.draw()
		
	def __highlightLines(self, lines, artist):		
		cmap = []
		for i in xrange(len(artist.get_paths())):
			if i in lines:
				cmap.append('r')
			else:
				cmap.append('b')			
		artist.set_color(cmap)
				
	def setModel(self, model):
		self.model = model
		self.connect(self.model, SIGNAL("dataLoaded()"), self.view.resizeColumnsToContents)
		self.connect(self.model, SIGNAL("dataLoaded()"), self.view.resizeRowsToContents)		
		#model.dataLoaded.connect(self.view.resizeColumnsToContents)
		#model.dataLoaded.connect(self.view.resizeRowsToContents)		
		self.view.setModel(self.model)	 
		self.view.resizeColumnsToContents()
		self.view.resizeRowsToContents()		
	
	def on_pick(self, event):
		# The event received here is of the type
		# matplotlib.backend_bases.PickEvent
		#
		# It carries lots of information, of which we're using
		# only a small amount here.
		#		 
		if not self.pickEnabled:
			return;
		
		indexes = []
		print "event ind is", event.ind		
		for i in event.ind:
			path = event.artist.get_paths()[i]			
			for t in path.iter_segments():
				startTime = t[0][1] / 1000		 
				modelIndex = self.view.model().index(0,0)
				startTime = str(startTime)[:7]		
				inds = self.view.model().match(modelIndex, Qt.DisplayRole, startTime)
				indexes += inds								
				break; #we know that the Path consists by one line, so this is sufficient
			
		#highlight it 
		self.__highlightLines(event.ind, event.artist)		
			
		self.view.scrollTo(indexes[0], QAbstractItemView.PositionAtCenter)				 
		
			
		self.__clearHighlighted();		
		
		rows = []		  
		for index in indexes:
			row = index.row()
			rows.append(row)
			
		self.highlightedItems = self.__highlightRows(set(rows))					
		self.canvas.draw()		
		
	def plotData(self):			
		self.grapher.setNames(self.fileName)
		if self.mode == self.reads:
			self.grapher.plotReads()
		else: 
			self.grapher.plotWrites()	  
		  
			   
	def __showPlot(self):
		""" Redraws the figure
		"""			  
		if self.patternButton.isChecked():
			self.pickEnabled = True
			if self.mode == self.reads:
				self.grapher.plotReads(self.displayStatistics.isChecked())
			else: 
				self.grapher.plotWrites(self.displayStatistics.isChecked())
		elif self.histSizeButton.isChecked():			
			self.grapher.plotHistSize(self.displayStatistics.isChecked())
			self.pickEnabled = False
			self.__clearHighlighted()
		elif self.histTimeButton.isChecked():
			self.grapher.plotHistTime(self.displayStatistics.isChecked())
			self.pickEnabled=  False
			self.__clearHighlighted()
		elif self.histSpeedButton.isChecked():
			self.grapher.plotHistSpeed(self.displayStatistics.isChecked())
			self.pickEnabled=  False
			self.__clearHighlighted()
		self.canvas.draw()   
	
		
class CentralWidget(QWidget):	
	READS = "reads"
	WRITES = "writes"
	
	def printing(self, a, b):
		print "changed"	
	
	def __init__(self, parent = None):
		QWidget.__init__(self, parent)
	
		self.connect(QCoreApplication.instance(), SIGNAL("aboutToQuit()"), self.__clean)
		#QCoreApplication.instance().aboutToQuit.connect(self.__clean)
	
		self.showing = None
		self.fileName = None
		self.dialogs = []														
				
		self.dataHolder = DataHolder()
		
		self.model = MyTable(0,0, self)
		self.filter = QSortFilterProxyModel(self)
		self.filter.setSourceModel(self.model)
		
		self.tableW = MyTableWidget(self)		
		self.tableW.setDataSource(self.filter)			
								
		#self.setSelectionBehavior(QAbstractItemView.SelectRows)   
		
		lineEdit = QLineEdit('Name regexp filter', self)
		self.connect(lineEdit, SIGNAL("textChanged(QString)"), self.filter.setFilterRegExp)   
		#lineEdit.textChanged.connect(self.filter.setFilterRegExp)
					
		self.view = MyTableView()
		self.view.setModel(self.filter)		
		#self.view.horizontalHeader().setStretchLastSection(True)
				
		
			
		delegate = MyDelegate()
		self.view.setItemDelegate(delegate)
						
		self.buttonD = QPushButton("Details", self)
		
		layout = QHBoxLayout()
		self.readRadioButton = QRadioButton("Reads")
		self.writeRadioButton = QRadioButton("Writes")
		self.connect(self.readRadioButton, SIGNAL("toggled(bool)"), self.__showTable)
		self.connect(self.writeRadioButton, SIGNAL("toggled(bool)"), self.__showTable)
		#self.readRadioButton.toggled.connect(self.__showTable)
		#self.writeRadioButton.toggled.connect(self.__showTable)
		layout.addWidget(self.readRadioButton)
		layout.addWidget(self.writeRadioButton)
		self.readRadioButton.setChecked(True)
		layout.addWidget(self.buttonD)
						
		self.connect(self.buttonD, SIGNAL("clicked()"), self.showDetails)						
		#buttonD.clicked.connect(self.showDetails)							
				
		vlayoutMain = QVBoxLayout(self)
		vlayoutMain.addWidget(self.view)
		vlayoutMain.addWidget(self.tableW)	   
		vlayoutMain.addWidget(lineEdit)		
		vlayoutMain.addLayout(layout)

	def __clean(self):
		for diag in self.dialogs:
			diag.close();

	def showDetails(self):		
		indexes = self.view.selectedIndexes()
		rows = []	 
		for index in indexes:
			rows.append(self.filter.mapToSource(index).row())
		rowset = set(rows)

		if not len(rowset) == 1:
			QMessageBox.warning(self, "Warning", "Exactly one file has to be specified.", );
			return
		
		fileName = self.model.getNames(rowset)[0]
		if self.readRadioButton.isChecked():			
			data = self.dataHolder.data()[self.READS][fileName]			
			reads = True			
		else:
			data = self.dataHolder.data()[self.WRITES][fileName]
			reads = False
								
		dialog = DetailDialog(fileName, reads, self.dataHolder, self)
		model = DetailTable(0,0, self)
		model.setData(data)
		dialog.setModel(model)
		
		dialog.show()
		self.dialogs.append(dialog)
		self.connect(dialog, SIGNAL("finished(int)"), self.__dialogClosed)
		#dialog.finished.connect(self.__dialogClosed)
	
	def __dialogClosed(self, retVal):		
		dial = self.sender()
		self.dialogs.remove(dial)				
		
	def newFileOpened(self, fileName):
		if not self.fileName == None:
			model = self.filter.sourceModel(); # detach for performance reasons
			modelView = self.view.model();		
			self.filter.setSourceModel(None)
			self.view.setModel(None)
			model.clear()  #clear
			self.filter.setSourceModel(model)
			self.view.setModel(modelView) # attach again
			ioapps.finish()
						
			 
		self.fileName = fileName
		if fileName.endsWith(".bin"):
			ioapps.init_items_bin(fileName.toLocal8Bit().data());
		else:
			ioapps.init_items_strace(fileName.toLocal8Bit().data());
		
		ioapps.simulate();		
		ioapps.free_items();		
		
		reads = ioapps.get_reads()
		writes = ioapps.get_writes()		
		self.dict = {}
		self.dict[self.READS] = reads;
		self.dict[self.WRITES] = writes;
		self.dataHolder.setData(self.dict)
		self.__showTable()
		self.tableW.recomputeData()
		self.filter.rowsRemoved.connect(self.tableW.recomputeData)
		self.filter.rowsInserted.connect(self.tableW.recomputeData)
		
	def __showTable(self):		
		if not self.fileName:
			return			
			
		if self.readRadioButton.isChecked():
			if self.showing == self.READS: #already showing reads
				return 
			sumDict = self.dataHolder.getSummary(self.READS)
			self.showing = self.READS
		else:
			if self.showing == self.WRITES:
				return
			self.showing = self.WRITES			
			sumDict = self.dataHolder.getSummary(self.WRITES)
		
		model = None
			
		if not self.showing == None:
			model = self.filter.sourceModel()
			self.filter.setSourceModel(None) #for performance reasons
			self.view.setModel(None) #detach model completely for performance reasons?					  
			self.model.clear()
			self.showing = None			  
					  
		for k,v in sumDict.iteritems():
			list = [k] + v
			self.model.addRow(list)
				
		if self.filter.sourceModel() == None:
			self.filter.setSourceModel(model)
		
		if self.view.model() == None:
			self.view.setModel(self.filter)			
		
		self.tableW.recomputeData()
		

class MainWindow(QMainWindow):
	appName = "IOprofiler - IOapps suite"
	
	def __init__(self, parent = None):
		QMainWindow.__init__(self, parent)

		self.fileName = None 

		self.resize(800, 600)		
		self.setWindowTitle(self.appName)
		
		open = QAction(QIcon('icons/open.png'), '&Open', self)
		open.setShortcut('Ctrl+O')
		open.setStatusTip('Load file containing recording traces')
		self.connect(open, SIGNAL('triggered()'), self.slotFile)
		
		exit = QAction(QIcon('icons/exit.png'), '&Exit', self)
		exit.setShortcut('Ctrl+W')
		exit.setStatusTip('Exit application')
		self.connect(exit, SIGNAL('triggered()'), self.close)
			
		self.setWindowIcon(QIcon('/usr/kde/3.5/share/icons/default.kde/64x64/devices/hdd_unmount.png'))
			 
		self.statusBar()
		menubar = self.menuBar()
		file = menubar.addMenu('&File')
		file.addAction(open)
		file.addAction(exit)
		
		aboutQt = QAction(QIcon('icons/about.png'), '&About Qt', self)
		aboutQt.setStatusTip('Show about Qt dialog')
		self.connect(aboutQt, SIGNAL('triggered()'), self.slotAboutQt)
		
		self.centralW = CentralWidget()
		self.setCentralWidget(self.centralW)
		
		ioHelp = QAction(QIcon('icons/help.png'), '&Help', self)
		ioHelp.setShortcut('F1')
		ioHelp.setStatusTip('Displays a brief help of the program')
		self.connect(ioHelp, SIGNAL('triggered()'), self.slotIoHelp)
		help = menubar.addMenu('&Help')
		help.addAction(ioHelp)
		help.addAction(aboutQt)

		if len(sys.argv) > 1:
			self.fileName = QString(sys.argv[1])
			self.slotFile(self.fileName)
		
		
	def slotFile(self, fileName=None):
		print fileName
		if not fileName:
			fileName = QFileDialog.getOpenFileName(self, "", "~/", "Repio binary files (*.bin);;Pure strace output (*)")		
		print fileName
		if fileName:
			self.fileName = fileName			
			self.updateWindowTitle()
			self.centralW.newFileOpened(self.fileName)
		
	def slotAboutQt(self):
		QMessageBox.aboutQt(self)
	
	def slotIoHelp(self):
		QMessageBox.about(self, "Help", "IOprofiler v1.4-r2 - part of the IOapps suite<br>\
				<a href=\"https://code.google.com/p/ioapps/\">https://code.google.com/p/ioapps/</a> <br> \
				Written by Jiri Horky.<br><hr>\
				GUI application for IO profiling. It can read strace output as well as binary traces converted by <bold>ioreplay</bold> application.<br>\
				You can get traces of your applications by running a wrapper script:<br>\
				<br>\
				ioprofiler-trace &lt;program&gt; &lt;arguments&gt;<br>\
				<br>\
				which	will produce ioproftrace.log file. <br>\
				See the project web page for more examples and description.");

	def updateWindowTitle(self):
		if self.fileName:
			self.setWindowTitle(self.appName + " - " + self.fileName)
		
			
class MyTable(QStandardItemModel):
	""" Table of operations """	
	
	def __init__(self, *args):
		QStandardItemModel.__init__(self, *args)	
		self.setSortRole(Qt.DisplayRole)	
		self.__setHeader()
	
	def __setHeader(self):
		header = QStringList()
		header.append("Name")
		header.append("# ops")
		header.append("fileSize[kiB]")		
		header.append("sumSize[kiB]")
		header.append("Dur[ms]")
		self.setHorizontalHeaderLabels(header)
			
	def clear(self):
		QStandardItemModel.clear(self)
		self.__setHeader()		
	
	def addRow(self, list):		
		myList = []
		for item in list: 
			#print "item", i, item		
			stdItem = QStandardItem()   
			if type(item) in [np.float64, np.float64]: # as of PyQt 4.7, we have specifically convert numpy.float* numbers to python's float, to make sure QVariant understands it
				a = QVariant(float(item))
			else:
				a = QVariant(item)
			stdItem.setData(a, Qt.DisplayRole)			
			myList.append(stdItem)			   
		self.appendRow(myList)		
		
	def getNames(self, rows):
		names = []
		for row in rows:
			names.append(self.item(row).data(Qt.DisplayRole).toPyObject().toLocal8Bit().data())
			
		return names

if __name__ == "__main__":
	app = QApplication(sys.argv)
	main = MainWindow()
	main.show()
	app.exec_()
	#cProfile.run('app.exec_()', '/tmp/profile')
	sys.exit(0)
	sys.exit(app.exec_())
	
