self.partial = partial self.grid = QGridLayout() for row in xrange(len(self.data_items)): self.grid.addWidget(QLabel(self.data_items[row].label), row, 0) self.grid.addWidget(self.data_items[row].widget, row, 1) self.status = QLabel() self.ok_button = QPushButton("Ok", self) self.ok_button.setDefault(True) self.ok_button.released.connect(self.Ok) self.ok_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.cancel_button = QPushButton("Cancel", self) self.cancel_button.released.connect(self.reject) self.cancel_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.hbox = QHBoxLayout() #self.hbox.addStretch() self.hbox.addWidget(self.status) self.hbox.addWidget(self.ok_button) self.hbox.addWidget(self.cancel_button) self.vbox = QVBoxLayout() self.vbox.addLayout(self.grid) self.vbox.addLayout(self.hbox) self.setLayout(self.vbox); def Ok(self): vars = self.report_vars for d in self.data_items: if d.id == "REPORTNAME": vars.name = d.value if not vars.name: self.ShowMessage("Report name is required") return for d in self.data_items: if not d.IsValid(): return for d in self.data_items[1:]: if d.id == "LIMIT": vars.limit = d.value elif len(d.value): if len(vars.where_clause): vars.where_clause += " AND " vars.where_clause += d.value if len(vars.where_clause): if self.partial: vars.where_clause = " AND ( " + vars.where_clause + " ) " else: vars.where_clause = " WHERE " + vars.where_clause + " " self.accept() def ShowMessage(self, msg): self.status.setText("<font color=#FF0000>" + msg) def ClearMessage(self): self.status.setText("") # Selected branch report creation dialog class SelectedBranchDialog(ReportDialogBase): def __init__(self, glb, parent=None): title = "Selected Branches" items = (lambda g, p: LineEditDataItem(g, "Report name:", "Enter a name to appear in the window title bar", p, "REPORTNAME"), lambda g, p: SampleTimeRangesDataItem(g, "Time ranges:", "Enter time ranges", "samples.id", p), lambda g, p: NonNegativeIntegerRangesDataItem(g, "CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "cpu", p), lambda g, p: SQLTableDataItem(g, "Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", "", p), lambda g, p: SQLTableDataItem(g, "PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", "", p), lambda g, p: SQLTableDataItem(g, "TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", "", p), lambda g, p: SQLTableDataItem(g, "DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id", p), lambda g, p: SQLTableDataItem(g, "Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id", p), lambda g, p: LineEditDataItem(g, "Raw SQL clause: ", "Enter a raw SQL WHERE clause", p)) super(SelectedBranchDialog, self).__init__(glb, title, items, True, parent) # Event list def GetEventList(db): events = [] query = QSqlQuery(db) QueryExec(query, "SELECT name FROM selected_events WHERE id > 0 ORDER BY id") while query.next(): events.append(query.value(0)) return events # Is a table selectable def IsSelectable(db, table, sql = ""): query = QSqlQuery(db) try: QueryExec(query, "SELECT * FROM " + table + " " + sql + " LIMIT 1") except: return False return True # SQL table data model item class SQLTableItem(): def __init__(self, row, data): self.row = row self.data = data def getData(self, column): return self.data[column] # SQL table data model class SQLTableModel(TableModel): progress = Signal(object) def __init__(self, glb, sql, column_headers, parent=None): super(SQLTableModel, self).__init__(parent) self.glb = glb self.more = True self.populated = 0 self.column_headers = column_headers self.fetcher = SQLFetcher(glb, sql, lambda x, y=len(column_headers): self.SQLTableDataPrep(x, y), self.AddSample) self.fetcher.done.connect(self.Update) self.fetcher.Fetch(glb_chunk_sz) def DisplayData(self, item, index): self.FetchIfNeeded(item.row) return item.getData(index.column()) def AddSample(self, data): child = SQLTableItem(self.populated, data) self.child_items.append(child) self.populated += 1 def Update(self, fetched): if not fetched: self.more = False self.progress.emit(0) child_count = self.child_count count = self.populated - child_count if count > 0: parent = QModelIndex() self.beginInsertRows(parent, child_count, child_count + count - 1) self.insertRows(child_count, count, parent) self.child_count += count self.endInsertRows() self.progress.emit(self.child_count) def FetchMoreRecords(self, count): current = self.child_count if self.more: self.fetcher.Fetch(count) else: self.progress.emit(0) return current def HasMoreRecords(self): return self.more def columnCount(self, parent=None): return len(self.column_headers) def columnHeader(self, column): return self.column_headers[column] def SQLTableDataPrep(self, query, count): data = [] for i in xrange(count): data.append(query.value(i)) return data # SQL automatic table data model class SQLAutoTableModel(SQLTableModel): def __init__(self, glb, table_name, parent=None): sql = "SELECT * FROM " + table_name + " WHERE id > $$last_id$$ ORDER BY id LIMIT " + str(glb_chunk_sz) if table_name == "comm_threads_view": # For now, comm_threads_view has no id column sql = "SELECT * FROM " + table_name + " WHERE comm_id > $$last_id$$ ORDER BY comm_id LIMIT " + str(glb_chunk_sz) column_headers = [] query = QSqlQuery(glb.db) if glb.dbref.is_sqlite3: QueryExec(query, "PRAGMA table_info(" + table_name + ")") while query.next(): column_headers.append(query.value(1)) if table_name == "sqlite_master": sql = "SELECT * FROM " + table_name else: if table_name[:19] == "information_schema.": sql = "SELECT * FROM " + table_name select_table_name = table_name[19:] schema = "information_schema" else: select_table_name = table_name schema = "public" QueryExec(query, "SELECT column_name FROM information_schema.columns WHERE table_schema = '" + schema + "' and table_name = '" + select_table_name + "'") while query.next(): column_headers.append(query.value(0)) if pyside_version_1 and sys.version_info[0] == 3: if table_name == "samples_view": self.SQLTableDataPrep = self.samples_view_DataPrep if table_name == "samples": self.SQLTableDataPrep = self.samples_DataPrep super(SQLAutoTableModel, self).__init__(glb, sql, column_headers, parent) def samples_view_DataPrep(self, query, count): data = [] data.append(query.value(0)) # Workaround pyside failing to handle large integers (i.e. time) in python3 by converting to a string data.append("{:>19}".format(query.value(1))) for i in xrange(2, count): data.append(query.value(i)) return data def samples_DataPrep(self, query, count): data = [] for i in xrange(9): data.append(query.value(i)) # Workaround pyside failing to handle large integers (i.e. time) in python3 by converting to a string data.append("{:>19}".format(query.value(9))) for i in xrange(10, count): data.append(query.value(i)) return data # Base class for custom ResizeColumnsToContents class ResizeColumnsToContentsBase(QObject): def __init__(self, parent=None): super(ResizeColumnsToContentsBase, self).__init__(parent) def ResizeColumnToContents(self, column, n): # Using the view's resizeColumnToContents() here is extrememly slow # so implement a crude alternative font = self.view.font() metrics = QFontMetrics(font) max = 0 for row in xrange(n): val = self.data_model.child_items[row].data[column] len = metrics.width(str(val) + "MM") max = len if len > max else max val = self.data_model.columnHeader(column) len = metrics.width(str(val) + "MM") max = len if len > max else max self.view.setColumnWidth(column, max) def ResizeColumnsToContents(self): n = min(self.data_model.child_count, 100) if n < 1: # No data yet, so connect a signal to notify when there is self.data_model.rowsInserted.connect(self.UpdateColumnWidths) return columns = self.data_model.columnCount() for i in xrange(columns): self.ResizeColumnToContents(i, n) def UpdateColumnWidths(self, *x): # This only needs to be done once, so disconnect the signal now self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths) self.ResizeColumnsToContents() # Table window class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase): def __init__(self, glb, table_name, parent=None): super(TableWindow, self).__init__(parent) self.data_model = LookupCreateModel(table_name + " Table", lambda: SQLAutoTableModel(glb, table_name)) self.model = QSortFilterProxyModel() self.model.setSourceModel(self.data_model) self.view = QTableView() self.view.setModel(self.model) self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.view.verticalHeader().setVisible(False) self.view.sortByColumn(-1, Qt.AscendingOrder) self.view.setSortingEnabled(True) self.ResizeColumnsToContents() self.find_bar = FindBar(self, self, True) self.finder = ChildDataItemFinder(self.data_model) self.fetch_bar = FetchMoreRecordsBar(self.data_model, self) self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) self.setWidget(self.vbox.Widget()) AddSubWindow(glb.mainwindow.mdi_area, self, table_name + " Table") def Find(self, value, direction, pattern, context): self.view.setFocus() self.find_bar.Busy() self.finder.Find(value, direction, pattern, context, self.FindDone) def FindDone(self, row): self.find_bar.Idle() if row >= 0: self.view.setCurrentIndex(self.model.mapFromSource(self.data_model.index(row, 0, QModelIndex()))) else: self.find_bar.NotFound() # Table list def GetTableList(glb): tables = [] query = QSqlQuery(glb.db) if glb.dbref.is_sqlite3: QueryExec(query, "SELECT name FROM sqlite_master WHERE type IN ( 'table' , 'view' ) ORDER BY name") else: QueryExec(query, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type IN ( 'BASE TABLE' , 'VIEW' ) ORDER BY table_name") while query.next(): tables.append(query.value(0)) if glb.dbref.is_sqlite3: tables.append("sqlite_master") else: tables.append("information_schema.tables") tables.append("information_schema.views") tables.append("information_schema.columns") return tables # Top Calls data model class TopCallsModel(SQLTableModel): def __init__(self, glb, report_vars, parent=None): text = "" if not glb.dbref.is_sqlite3: text = "::text" limit = "" if len(report_vars.limit): limit = " LIMIT " + report_vars.limit sql = ("SELECT comm, pid, tid, name," " CASE" " WHEN (short_name = '[kernel.kallsyms]') THEN '[kernel]'" + text + " ELSE short_name" " END AS dso," " call_time, return_time, (return_time - call_time) AS elapsed_time, branch_count, " " CASE" " WHEN (calls.flags = 1) THEN 'no call'" + text + " WHEN (calls.flags = 2) THEN 'no return'" + text + " WHEN (calls.flags = 3) THEN 'no call/return'" + text + " ELSE ''" + text + " END AS flags" " FROM calls" " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" " INNER JOIN dsos ON symbols.dso_id = dsos.id" " INNER JOIN comms ON calls.comm_id = comms.id" " INNER JOIN threads ON calls.thread_id = threads.id" + report_vars.where_clause + " ORDER BY elapsed_time DESC" + limit ) column_headers = ("Command", "PID", "TID", "Symbol", "Object", "Call Time", "Return Time", "Elapsed Time (ns)", "Branch Count", "Flags") self.alignment = (Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignLeft) super(TopCallsModel, self).__init__(glb, sql, column_headers, parent) def columnAlignment(self, column): return self.alignment[column] # Top Calls report creation dialog class TopCallsDialog(ReportDialogBase): def __init__(self, glb, parent=None): title = "Top Calls by Elapsed Time" items = (lambda g, p: LineEditDataItem(g, "Report name:", "Enter a name to appear in the window title bar", p, "REPORTNAME"), lambda g, p: SQLTableDataItem(g, "Commands:", "Only calls with these commands will be included", "comms", "comm", "comm_id", "", p), lambda g, p: SQLTableDataItem(g, "PIDs:", "Only calls with these process IDs will be included", "threads", "pid", "thread_id", "", p), lambda g, p: SQLTableDataItem(g, "TIDs:", "Only calls with these thread IDs will be included", "threads", "tid", "thread_id", "", p), lambda g, p: SQLTableDataItem(g, "DSOs:", "Only calls with these DSOs will be included", "dsos", "short_name", "dso_id", "", p), lambda g, p: SQLTableDataItem(g, "Symbols:", "Only calls with these symbols will be included", "symbols", "name", "symbol_id", "", p), lambda g, p: LineEditDataItem(g, "Raw SQL clause: ", "Enter a raw SQL WHERE clause", p), lambda g, p: PositiveIntegerDataItem(g, "Record limit:", "Limit selection to this number of records", p, "LIMIT", "100")) super(TopCallsDialog, self).__init__(glb, title, items, False, parent) # Top Calls window class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase): def __init__(self, glb, report_vars, parent=None): super(TopCallsWindow, self).__init__(parent) self.data_model = LookupCreateModel("Top Calls " + report_vars.UniqueId(), lambda: TopCallsModel(glb, report_vars)) self.model = self.data_model self.view = QTableView() self.view.setModel(self.model) self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.view.verticalHeader().setVisible(False) self.ResizeColumnsToContents() self.find_bar = FindBar(self, self, True) self.finder = ChildDataItemFinder(self.model) self.fetch_bar = FetchMoreRecordsBar(self.data_model, self) self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) self.setWidget(self.vbox.Widget()) AddSubWindow(glb.mainwindow.mdi_area, self, report_vars.name) def Find(self, value, direction, pattern, context): self.view.setFocus() self.find_bar.Busy() self.finder.Find(value, direction, pattern, context, self.FindDone) def FindDone(self, row): self.find_bar.Idle() if row >= 0: self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) else: self.find_bar.NotFound() # Action Definition def CreateAction(label, tip, callback, parent=None, shortcut=None): action = QAction(label, parent) if shortcut != None: action.setShortcuts(shortcut) action.setStatusTip(tip) action.triggered.connect(callback) return action # Typical application actions def CreateExitAction(app, parent=None): return CreateAction("&Quit", "Exit the application", app.closeAllWindows, parent, QKeySequence.Quit) # Typical MDI actions def CreateCloseActiveWindowAction(mdi_area): return CreateAction("Cl&ose", "Close the active window", mdi_area.closeActiveSubWindow, mdi_area) def CreateCloseAllWindowsAction(mdi_area): return CreateAction("Close &All", "Close all the windows", mdi_area.closeAllSubWindows, mdi_area) def CreateTileWindowsAction(mdi_area): return CreateAction("&Tile", "Tile the windows", mdi_area.tileSubWindows, mdi_area) def CreateCascadeWindowsAction(mdi_area): return CreateAction("&Cascade", "Cascade the windows", mdi_area.cascadeSubWindows, mdi_area) def CreateNextWindowAction(mdi_area): return CreateAction("Ne&xt", "Move the focus to the next window", mdi_area.activateNextSubWindow, mdi_area, QKeySequence.NextChild) def CreatePreviousWindowAction(mdi_area): return CreateAction("Pre&vious", "Move the focus to the previous window", mdi_area.activatePreviousSubWindow, mdi_area, QKeySequence.PreviousChild) # Typical MDI window menu class WindowMenu(): def __init__(self, mdi_area, menu): self.mdi_area = mdi_area self.window_menu = menu.addMenu("&Windows") self.close_active_window = CreateCloseActiveWindowAction(mdi_area) self.close_all_windows = CreateCloseAllWindowsAction(mdi_area) self.tile_windows = CreateTileWindowsAction(mdi_area) self.cascade_windows = CreateCascadeWindowsAction(mdi_area) self.next_window = CreateNextWindowAction(mdi_area) self.previous_window = CreatePreviousWindowAction(mdi_area) self.window_menu.aboutToShow.connect(self.Update) def Update(self): self.window_menu.clear() sub_window_count = len(self.mdi_area.subWindowList()) have_sub_windows = sub_window_count != 0 self.close_active_window.setEnabled(have_sub_windows) self.close_all_windows.setEnabled(have_sub_windows) self.tile_windows.setEnabled(have_sub_windows) self.cascade_windows.setEnabled(have_sub_windows) self.next_window.setEnabled(have_sub_windows) self.previous_window.setEnabled(have_sub_windows) self.window_menu.addAction(self.close_active_window) self.window_menu.addAction(self.close_all_windows) self.window_menu.addSeparator() self.window_menu.addAction(self.tile_windows) self.window_menu.addAction(self.cascade_windows) self.window_menu.addSeparator() self.window_menu.addAction(self.next_window) self.window_menu.addAction(self.previous_window) if sub_window_count == 0: return self.window_menu.addSeparator() nr = 1 for sub_window in self.mdi_area.subWindowList(): label = str(nr) + " " + sub_window.name if nr < 10: label = "&" + labelLines 2001–2500 of 3073. Previous lines Load more
self.partial = partial self.grid = QGridLayout() for row in xrange(len(self.data_items)): self.grid.addWidget(QLabel(self.data_items[row].label), row, 0) self.grid.addWidget(self.data_items[row].widget, row, 1) self.status = QLabel() self.ok_button = QPushButton("Ok", self) self.ok_button.setDefault(True) self.ok_button.released.connect(self.Ok) self.ok_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.cancel_button = QPushButton("Cancel", self) self.cancel_button.released.connect(self.reject) self.cancel_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.hbox = QHBoxLayout() #self.hbox.addStretch() self.hbox.addWidget(self.status) self.hbox.addWidget(self.ok_button) self.hbox.addWidget(self.cancel_button) self.vbox = QVBoxLayout() self.vbox.addLayout(self.grid) self.vbox.addLayout(self.hbox) self.setLayout(self.vbox); def Ok(self): vars = self.report_vars for d in self.data_items: if d.id == "REPORTNAME": vars.name = d.value if not vars.name: self.ShowMessage("Report name is required") return for d in self.data_items: if not d.IsValid(): return for d in self.data_items[1:]: if d.id == "LIMIT": vars.limit = d.value elif len(d.value): if len(vars.where_clause): vars.where_clause += " AND " vars.where_clause += d.value if len(vars.where_clause): if self.partial: vars.where_clause = " AND ( " + vars.where_clause + " ) " else: vars.where_clause = " WHERE " + vars.where_clause + " " self.accept() def ShowMessage(self, msg): self.status.setText("<font color=#FF0000>" + msg) def ClearMessage(self): self.status.setText("") # Selected branch report creation dialog class SelectedBranchDialog(ReportDialogBase): def __init__(self, glb, parent=None): title = "Selected Branches" items = (lambda g, p: LineEditDataItem(g, "Report name:", "Enter a name to appear in the window title bar", p, "REPORTNAME"), lambda g, p: SampleTimeRangesDataItem(g, "Time ranges:", "Enter time ranges", "samples.id", p), lambda g, p: NonNegativeIntegerRangesDataItem(g, "CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "cpu", p), lambda g, p: SQLTableDataItem(g, "Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", "", p), lambda g, p: SQLTableDataItem(g, "PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", "", p), lambda g, p: SQLTableDataItem(g, "TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", "", p), lambda g, p: SQLTableDataItem(g, "DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id", p), lambda g, p: SQLTableDataItem(g, "Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id", p), lambda g, p: LineEditDataItem(g, "Raw SQL clause: ", "Enter a raw SQL WHERE clause", p)) super(SelectedBranchDialog, self).__init__(glb, title, items, True, parent) # Event list def GetEventList(db): events = [] query = QSqlQuery(db) QueryExec(query, "SELECT name FROM selected_events WHERE id > 0 ORDER BY id") while query.next(): events.append(query.value(0)) return events # Is a table selectable def IsSelectable(db, table, sql = ""): query = QSqlQuery(db) try: QueryExec(query, "SELECT * FROM " + table + " " + sql + " LIMIT 1") except: return False return True # SQL table data model item class SQLTableItem(): def __init__(self, row, data): self.row = row self.data = data def getData(self, column): return self.data[column] # SQL table data model class SQLTableModel(TableModel): progress = Signal(object) def __init__(self, glb, sql, column_headers, parent=None): super(SQLTableModel, self).__init__(parent) self.glb = glb self.more = True self.populated = 0 self.column_headers = column_headers self.fetcher = SQLFetcher(glb, sql, lambda x, y=len(column_headers): self.SQLTableDataPrep(x, y), self.AddSample) self.fetcher.done.connect(self.Update) self.fetcher.Fetch(glb_chunk_sz) def DisplayData(self, item, index): self.FetchIfNeeded(item.row) return item.getData(index.column()) def AddSample(self, data): child = SQLTableItem(self.populated, data) self.child_items.append(child) self.populated += 1 def Update(self, fetched): if not fetched: self.more = False self.progress.emit(0) child_count = self.child_count count = self.populated - child_count if count > 0: parent = QModelIndex() self.beginInsertRows(parent, child_count, child_count + count - 1) self.insertRows(child_count, count, parent) self.child_count += count self.endInsertRows() self.progress.emit(self.child_count) def FetchMoreRecords(self, count): current = self.child_count if self.more: self.fetcher.Fetch(count) else: self.progress.emit(0) return current def HasMoreRecords(self): return self.more def columnCount(self, parent=None): return len(self.column_headers) def columnHeader(self, column): return self.column_headers[column] def SQLTableDataPrep(self, query, count): data = [] for i in xrange(count): data.append(query.value(i)) return data # SQL automatic table data model class SQLAutoTableModel(SQLTableModel): def __init__(self, glb, table_name, parent=None): sql = "SELECT * FROM " + table_name + " WHERE id > $$last_id$$ ORDER BY id LIMIT " + str(glb_chunk_sz) if table_name == "comm_threads_view": # For now, comm_threads_view has no id column sql = "SELECT * FROM " + table_name + " WHERE comm_id > $$last_id$$ ORDER BY comm_id LIMIT " + str(glb_chunk_sz) column_headers = [] query = QSqlQuery(glb.db) if glb.dbref.is_sqlite3: QueryExec(query, "PRAGMA table_info(" + table_name + ")") while query.next(): column_headers.append(query.value(1)) if table_name == "sqlite_master": sql = "SELECT * FROM " + table_name else: if table_name[:19] == "information_schema.": sql = "SELECT * FROM " + table_name select_table_name = table_name[19:] schema = "information_schema" else: select_table_name = table_name schema = "public" QueryExec(query, "SELECT column_name FROM information_schema.columns WHERE table_schema = '" + schema + "' and table_name = '" + select_table_name + "'") while query.next(): column_headers.append(query.value(0)) if pyside_version_1 and sys.version_info[0] == 3: if table_name == "samples_view": self.SQLTableDataPrep = self.samples_view_DataPrep if table_name == "samples": self.SQLTableDataPrep = self.samples_DataPrep super(SQLAutoTableModel, self).__init__(glb, sql, column_headers, parent) def samples_view_DataPrep(self, query, count): data = [] data.append(query.value(0)) # Workaround pyside failing to handle large integers (i.e. time) in python3 by converting to a string data.append("{:>19}".format(query.value(1))) for i in xrange(2, count): data.append(query.value(i)) return data def samples_DataPrep(self, query, count): data = [] for i in xrange(9): data.append(query.value(i)) # Workaround pyside failing to handle large integers (i.e. time) in python3 by converting to a string data.append("{:>19}".format(query.value(9))) for i in xrange(10, count): data.append(query.value(i)) return data # Base class for custom ResizeColumnsToContents class ResizeColumnsToContentsBase(QObject): def __init__(self, parent=None): super(ResizeColumnsToContentsBase, self).__init__(parent) def ResizeColumnToContents(self, column, n): # Using the view's resizeColumnToContents() here is extrememly slow # so implement a crude alternative font = self.view.font() metrics = QFontMetrics(font) max = 0 for row in xrange(n): val = self.data_model.child_items[row].data[column] len = metrics.width(str(val) + "MM") max = len if len > max else max val = self.data_model.columnHeader(column) len = metrics.width(str(val) + "MM") max = len if len > max else max self.view.setColumnWidth(column, max) def ResizeColumnsToContents(self): n = min(self.data_model.child_count, 100) if n < 1: # No data yet, so connect a signal to notify when there is self.data_model.rowsInserted.connect(self.UpdateColumnWidths) return columns = self.data_model.columnCount() for i in xrange(columns): self.ResizeColumnToContents(i, n) def UpdateColumnWidths(self, *x): # This only needs to be done once, so disconnect the signal now self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths) self.ResizeColumnsToContents() # Table window class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase): def __init__(self, glb, table_name, parent=None): super(TableWindow, self).__init__(parent) self.data_model = LookupCreateModel(table_name + " Table", lambda: SQLAutoTableModel(glb, table_name)) self.model = QSortFilterProxyModel() self.model.setSourceModel(self.data_model) self.view = QTableView() self.view.setModel(self.model) self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.view.verticalHeader().setVisible(False) self.view.sortByColumn(-1, Qt.AscendingOrder) self.view.setSortingEnabled(True) self.ResizeColumnsToContents() self.find_bar = FindBar(self, self, True) self.finder = ChildDataItemFinder(self.data_model) self.fetch_bar = FetchMoreRecordsBar(self.data_model, self) self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) self.setWidget(self.vbox.Widget()) AddSubWindow(glb.mainwindow.mdi_area, self, table_name + " Table") def Find(self, value, direction, pattern, context): self.view.setFocus() self.find_bar.Busy() self.finder.Find(value, direction, pattern, context, self.FindDone) def FindDone(self, row): self.find_bar.Idle() if row >= 0: self.view.setCurrentIndex(self.model.mapFromSource(self.data_model.index(row, 0, QModelIndex()))) else: self.find_bar.NotFound() # Table list def GetTableList(glb): tables = [] query = QSqlQuery(glb.db) if glb.dbref.is_sqlite3: QueryExec(query, "SELECT name FROM sqlite_master WHERE type IN ( 'table' , 'view' ) ORDER BY name") else: QueryExec(query, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type IN ( 'BASE TABLE' , 'VIEW' ) ORDER BY table_name") while query.next(): tables.append(query.value(0)) if glb.dbref.is_sqlite3: tables.append("sqlite_master") else: tables.append("information_schema.tables") tables.append("information_schema.views") tables.append("information_schema.columns") return tables # Top Calls data model class TopCallsModel(SQLTableModel): def __init__(self, glb, report_vars, parent=None): text = "" if not glb.dbref.is_sqlite3: text = "::text" limit = "" if len(report_vars.limit): limit = " LIMIT " + report_vars.limit sql = ("SELECT comm, pid, tid, name," " CASE" " WHEN (short_name = '[kernel.kallsyms]') THEN '[kernel]'" + text + " ELSE short_name" " END AS dso," " call_time, return_time, (return_time - call_time) AS elapsed_time, branch_count, " " CASE" " WHEN (calls.flags = 1) THEN 'no call'" + text + " WHEN (calls.flags = 2) THEN 'no return'" + text + " WHEN (calls.flags = 3) THEN 'no call/return'" + text + " ELSE ''" + text + " END AS flags" " FROM calls" " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" " INNER JOIN dsos ON symbols.dso_id = dsos.id" " INNER JOIN comms ON calls.comm_id = comms.id" " INNER JOIN threads ON calls.thread_id = threads.id" + report_vars.where_clause + " ORDER BY elapsed_time DESC" + limit ) column_headers = ("Command", "PID", "TID", "Symbol", "Object", "Call Time", "Return Time", "Elapsed Time (ns)", "Branch Count", "Flags") self.alignment = (Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignLeft) super(TopCallsModel, self).__init__(glb, sql, column_headers, parent) def columnAlignment(self, column): return self.alignment[column] # Top Calls report creation dialog class TopCallsDialog(ReportDialogBase): def __init__(self, glb, parent=None): title = "Top Calls by Elapsed Time" items = (lambda g, p: LineEditDataItem(g, "Report name:", "Enter a name to appear in the window title bar", p, "REPORTNAME"), lambda g, p: SQLTableDataItem(g, "Commands:", "Only calls with these commands will be included", "comms", "comm", "comm_id", "", p), lambda g, p: SQLTableDataItem(g, "PIDs:", "Only calls with these process IDs will be included", "threads", "pid", "thread_id", "", p), lambda g, p: SQLTableDataItem(g, "TIDs:", "Only calls with these thread IDs will be included", "threads", "tid", "thread_id", "", p), lambda g, p: SQLTableDataItem(g, "DSOs:", "Only calls with these DSOs will be included", "dsos", "short_name", "dso_id", "", p), lambda g, p: SQLTableDataItem(g, "Symbols:", "Only calls with these symbols will be included", "symbols", "name", "symbol_id", "", p), lambda g, p: LineEditDataItem(g, "Raw SQL clause: ", "Enter a raw SQL WHERE clause", p), lambda g, p: PositiveIntegerDataItem(g, "Record limit:", "Limit selection to this number of records", p, "LIMIT", "100")) super(TopCallsDialog, self).__init__(glb, title, items, False, parent) # Top Calls window class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase): def __init__(self, glb, report_vars, parent=None): super(TopCallsWindow, self).__init__(parent) self.data_model = LookupCreateModel("Top Calls " + report_vars.UniqueId(), lambda: TopCallsModel(glb, report_vars)) self.model = self.data_model self.view = QTableView() self.view.setModel(self.model) self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.view.verticalHeader().setVisible(False) self.ResizeColumnsToContents() self.find_bar = FindBar(self, self, True) self.finder = ChildDataItemFinder(self.model) self.fetch_bar = FetchMoreRecordsBar(self.data_model, self) self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) self.setWidget(self.vbox.Widget()) AddSubWindow(glb.mainwindow.mdi_area, self, report_vars.name) def Find(self, value, direction, pattern, context): self.view.setFocus() self.find_bar.Busy() self.finder.Find(value, direction, pattern, context, self.FindDone) def FindDone(self, row): self.find_bar.Idle() if row >= 0: self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) else: self.find_bar.NotFound() # Action Definition def CreateAction(label, tip, callback, parent=None, shortcut=None): action = QAction(label, parent) if shortcut != None: action.setShortcuts(shortcut) action.setStatusTip(tip) action.triggered.connect(callback) return action # Typical application actions def CreateExitAction(app, parent=None): return CreateAction("&Quit", "Exit the application", app.closeAllWindows, parent, QKeySequence.Quit) # Typical MDI actions def CreateCloseActiveWindowAction(mdi_area): return CreateAction("Cl&ose", "Close the active window", mdi_area.closeActiveSubWindow, mdi_area) def CreateCloseAllWindowsAction(mdi_area): return CreateAction("Close &All", "Close all the windows", mdi_area.closeAllSubWindows, mdi_area) def CreateTileWindowsAction(mdi_area): return CreateAction("&Tile", "Tile the windows", mdi_area.tileSubWindows, mdi_area) def CreateCascadeWindowsAction(mdi_area): return CreateAction("&Cascade", "Cascade the windows", mdi_area.cascadeSubWindows, mdi_area) def CreateNextWindowAction(mdi_area): return CreateAction("Ne&xt", "Move the focus to the next window", mdi_area.activateNextSubWindow, mdi_area, QKeySequence.NextChild) def CreatePreviousWindowAction(mdi_area): return CreateAction("Pre&vious", "Move the focus to the previous window", mdi_area.activatePreviousSubWindow, mdi_area, QKeySequence.PreviousChild) # Typical MDI window menu class WindowMenu(): def __init__(self, mdi_area, menu): self.mdi_area = mdi_area self.window_menu = menu.addMenu("&Windows") self.close_active_window = CreateCloseActiveWindowAction(mdi_area) self.close_all_windows = CreateCloseAllWindowsAction(mdi_area) self.tile_windows = CreateTileWindowsAction(mdi_area) self.cascade_windows = CreateCascadeWindowsAction(mdi_area) self.next_window = CreateNextWindowAction(mdi_area) self.previous_window = CreatePreviousWindowAction(mdi_area) self.window_menu.aboutToShow.connect(self.Update) def Update(self): self.window_menu.clear() sub_window_count = len(self.mdi_area.subWindowList()) have_sub_windows = sub_window_count != 0 self.close_active_window.setEnabled(have_sub_windows) self.close_all_windows.setEnabled(have_sub_windows) self.tile_windows.setEnabled(have_sub_windows) self.cascade_windows.setEnabled(have_sub_windows) self.next_window.setEnabled(have_sub_windows) self.previous_window.setEnabled(have_sub_windows) self.window_menu.addAction(self.close_active_window) self.window_menu.addAction(self.close_all_windows) self.window_menu.addSeparator() self.window_menu.addAction(self.tile_windows) self.window_menu.addAction(self.cascade_windows) self.window_menu.addSeparator() self.window_menu.addAction(self.next_window) self.window_menu.addAction(self.previous_window) if sub_window_count == 0: return self.window_menu.addSeparator() nr = 1 for sub_window in self.mdi_area.subWindowList(): label = str(nr) + " " + sub_window.name if nr < 10: label = "&" + label