From be6e747136a4dc8aad99259e47fd6f7362a43996 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 3 May 2019 15:08:24 +0300 Subject: perf scripts python: exported-sql-viewer.py: Move view creation As preparation for adding support for copying to clipboard, create view in TreeWindowBase instead of derived classes. Committer testing: Tested using an old .db used to test some older patches: $ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db Nothing breaks. Signed-off-by: Adrian Hunter Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Link: http://lkml.kernel.org/r/20190503120828.25326-3-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/exported-sql-viewer.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'tools/perf/scripts/python/exported-sql-viewer.py') diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index 74ef92f1d19a..db4655168ab1 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py @@ -877,9 +877,10 @@ class TreeWindowBase(QMdiSubWindow): super(TreeWindowBase, self).__init__(parent) self.model = None - self.view = None self.find_bar = None + self.view = QTreeView() + def DisplayFound(self, ids): if not len(ids): return False @@ -921,7 +922,6 @@ class CallGraphWindow(TreeWindowBase): self.model = LookupCreateModel("Context-Sensitive Call Graph", lambda x=glb: CallGraphModel(x)) - self.view = QTreeView() self.view.setModel(self.model) for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)): @@ -944,7 +944,6 @@ class CallTreeWindow(TreeWindowBase): self.model = LookupCreateModel("Call Tree", lambda x=glb: CallTreeModel(x)) - self.view = QTreeView() self.view.setModel(self.model) for c, w in ((0, 230), (1, 100), (2, 100), (3, 70), (4, 70), (5, 100)): -- cgit From 4b2084537e5f3b58337bce894391fb63bf3b0e28 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 3 May 2019 15:08:23 +0300 Subject: perf scripts python: exported-sql-viewer.py: Fix error when shrinking / enlarging font Fix the following error if shrink / enlarge font is used with the help window. Traceback (most recent call last): File "tools/perf/scripts/python/exported-sql-viewer.py", line 2791, in ShrinkFont ShrinkFont(win.view) AttributeError: 'HelpWindow' object has no attribute 'view' Committer testing: Before, matches above output: $ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db Traceback (most recent call last): File "/home/acme/libexec/perf-core/scripts/python/exported-sql-viewer.py", line 2780, in EnlargeFont EnlargeFont(win.view) AttributeError: 'HelpWindow' object has no attribute 'view' $ After: No more tracebacks, but the fonts don't get enlarged, which is kinda frustrating... Signed-off-by: Adrian Hunter Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Link: http://lkml.kernel.org/r/20190503120828.25326-2-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/exported-sql-viewer.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'tools/perf/scripts/python/exported-sql-viewer.py') diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index db4655168ab1..fd073e4af8da 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py @@ -2755,6 +2755,14 @@ class MainWindow(QMainWindow): help_menu = menu.addMenu("&Help") help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents)) + def Try(self, fn): + win = self.mdi_area.activeSubWindow() + if win: + try: + fn(win.view) + except: + pass + def Find(self): win = self.mdi_area.activeSubWindow() if win: @@ -2772,12 +2780,10 @@ class MainWindow(QMainWindow): pass def ShrinkFont(self): - win = self.mdi_area.activeSubWindow() - ShrinkFont(win.view) + self.Try(ShrinkFont) def EnlargeFont(self): - win = self.mdi_area.activeSubWindow() - EnlargeFont(win.view) + self.Try(EnlargeFont) def EventMenu(self, events, reports_menu): branches_events = 0 -- cgit From 3ac641f4acd66c109b74f108f8a61f2905702b10 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 3 May 2019 15:08:25 +0300 Subject: perf scripts python: exported-sql-viewer.py: Add tree level As preparation for adding support for copying to clipboard, keep track of what level each item is in tree items. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/20190503120828.25326-4-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/exported-sql-viewer.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools/perf/scripts/python/exported-sql-viewer.py') diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index fd073e4af8da..48953257a1f0 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py @@ -456,6 +456,10 @@ class CallGraphLevelItemBase(object): self.query_done = False; self.child_count = 0 self.child_items = [] + if parent_item: + self.level = parent_item.level + 1 + else: + self.level = 0 def getChildItem(self, row): return self.child_items[row] -- cgit From 96c43b9a7ab3b70bc35d762f7b76082dfd118a6a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 3 May 2019 15:08:26 +0300 Subject: perf scripts python: exported-sql-viewer.py: Add copy to clipboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for copying to clipboard. Two menu options are added to copy the selected rows / columns with normal spacing, or as comma-separated-values. In the case of trees, only entire rows can be copied. Comitter testing: $ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db Select the lines, press control+C and on the same terminal, press control+shift+V and voilà: Call Path Object Count Time (ns) Time (%) Branch Count Branch Count (%) ▼ 14503:14503 ▼ _start ld-2.28.so 1 156267 100.0 10602 100.0 unknown unknown 1 2276 1.5 1 0.0 ▼ _dl_start ld-2.28.so 1 137047 87.7 10088 95.2 ▶ unknown unknown 4 4127 3.0 4 0.0 _dl_setup_hash ld-2.28.so 1 0 0.0 1 0.0 ▶ _dl_sysdep_start ld-2.28.so 1 131342 95.8 9981 98.9 ▼ _dl_init ld-2.28.so 1 9142 5.9 326 3.1 ▼ call_init.part.0 ld-2.28.so 3 9133 99.9 319 97.9 ▶ _init libc-2.28.so 1 6877 75.3 110 34.5 ▶ check_stdfiles_vtables libc-2.28.so 1 76 0.8 2 0.6 ▶ init_cacheinfo libc-2.28.so 1 1991 21.8 197 61.8 ▶ _start simple-retpoline 1 7457 4.8 182 1.7 Signed-off-by: Adrian Hunter Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Link: http://lkml.kernel.org/r/20190503120828.25326-5-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/exported-sql-viewer.py | 217 +++++++++++++++++++++++ 1 file changed, 217 insertions(+) (limited to 'tools/perf/scripts/python/exported-sql-viewer.py') diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index 48953257a1f0..baa2b220238a 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py @@ -884,6 +884,8 @@ class TreeWindowBase(QMdiSubWindow): self.find_bar = None self.view = QTreeView() + self.view.setSelectionMode(QAbstractItemView.ContiguousSelection) + self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard def DisplayFound(self, ids): if not len(ids): @@ -1652,6 +1654,8 @@ class BranchWindow(QMdiSubWindow): self.view = QTreeView() self.view.setUniformRowHeights(True) + self.view.setSelectionMode(QAbstractItemView.ContiguousSelection) + self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard self.view.setModel(self.model) self.ResizeColumnsToContents() @@ -2264,6 +2268,207 @@ class ResizeColumnsToContentsBase(QObject): self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths) self.ResizeColumnsToContents() +# Convert value to CSV + +def ToCSValue(val): + if '"' in val: + val = val.replace('"', '""') + if "," in val or '"' in val: + val = '"' + val + '"' + return val + +# Key to sort table model indexes by row / column, assuming fewer than 1000 columns + +glb_max_cols = 1000 + +def RowColumnKey(a): + return a.row() * glb_max_cols + a.column() + +# Copy selected table cells to clipboard + +def CopyTableCellsToClipboard(view, as_csv=False, with_hdr=False): + indexes = sorted(view.selectedIndexes(), key=RowColumnKey) + idx_cnt = len(indexes) + if not idx_cnt: + return + if idx_cnt == 1: + with_hdr=False + min_row = indexes[0].row() + max_row = indexes[0].row() + min_col = indexes[0].column() + max_col = indexes[0].column() + for i in indexes: + min_row = min(min_row, i.row()) + max_row = max(max_row, i.row()) + min_col = min(min_col, i.column()) + max_col = max(max_col, i.column()) + if max_col > glb_max_cols: + raise RuntimeError("glb_max_cols is too low") + max_width = [0] * (1 + max_col - min_col) + for i in indexes: + c = i.column() - min_col + max_width[c] = max(max_width[c], len(str(i.data()))) + text = "" + pad = "" + sep = "" + if with_hdr: + model = indexes[0].model() + for col in range(min_col, max_col + 1): + val = model.headerData(col, Qt.Horizontal) + if as_csv: + text += sep + ToCSValue(val) + sep = "," + else: + c = col - min_col + max_width[c] = max(max_width[c], len(val)) + width = max_width[c] + align = model.headerData(col, Qt.Horizontal, Qt.TextAlignmentRole) + if align & Qt.AlignRight: + val = val.rjust(width) + text += pad + sep + val + pad = " " * (width - len(val)) + sep = " " + text += "\n" + pad = "" + sep = "" + last_row = min_row + for i in indexes: + if i.row() > last_row: + last_row = i.row() + text += "\n" + pad = "" + sep = "" + if as_csv: + text += sep + ToCSValue(str(i.data())) + sep = "," + else: + width = max_width[i.column() - min_col] + if i.data(Qt.TextAlignmentRole) & Qt.AlignRight: + val = str(i.data()).rjust(width) + else: + val = str(i.data()) + text += pad + sep + val + pad = " " * (width - len(val)) + sep = " " + QApplication.clipboard().setText(text) + +def CopyTreeCellsToClipboard(view, as_csv=False, with_hdr=False): + indexes = view.selectedIndexes() + if not len(indexes): + return + + selection = view.selectionModel() + + first = None + for i in indexes: + above = view.indexAbove(i) + if not selection.isSelected(above): + first = i + break + + if first is None: + raise RuntimeError("CopyTreeCellsToClipboard internal error") + + model = first.model() + row_cnt = 0 + col_cnt = model.columnCount(first) + max_width = [0] * col_cnt + + indent_sz = 2 + indent_str = " " * indent_sz + + expanded_mark_sz = 2 + if sys.version_info[0] == 3: + expanded_mark = "\u25BC " + not_expanded_mark = "\u25B6 " + else: + expanded_mark = unicode(chr(0xE2) + chr(0x96) + chr(0xBC) + " ", "utf-8") + not_expanded_mark = unicode(chr(0xE2) + chr(0x96) + chr(0xB6) + " ", "utf-8") + leaf_mark = " " + + if not as_csv: + pos = first + while True: + row_cnt += 1 + row = pos.row() + for c in range(col_cnt): + i = pos.sibling(row, c) + if c: + n = len(str(i.data())) + else: + n = len(str(i.data()).strip()) + n += (i.internalPointer().level - 1) * indent_sz + n += expanded_mark_sz + max_width[c] = max(max_width[c], n) + pos = view.indexBelow(pos) + if not selection.isSelected(pos): + break + + text = "" + pad = "" + sep = "" + if with_hdr: + for c in range(col_cnt): + val = model.headerData(c, Qt.Horizontal, Qt.DisplayRole).strip() + if as_csv: + text += sep + ToCSValue(val) + sep = "," + else: + max_width[c] = max(max_width[c], len(val)) + width = max_width[c] + align = model.headerData(c, Qt.Horizontal, Qt.TextAlignmentRole) + if align & Qt.AlignRight: + val = val.rjust(width) + text += pad + sep + val + pad = " " * (width - len(val)) + sep = " " + text += "\n" + pad = "" + sep = "" + + pos = first + while True: + row = pos.row() + for c in range(col_cnt): + i = pos.sibling(row, c) + val = str(i.data()) + if not c: + if model.hasChildren(i): + if view.isExpanded(i): + mark = expanded_mark + else: + mark = not_expanded_mark + else: + mark = leaf_mark + val = indent_str * (i.internalPointer().level - 1) + mark + val.strip() + if as_csv: + text += sep + ToCSValue(val) + sep = "," + else: + width = max_width[c] + if c and i.data(Qt.TextAlignmentRole) & Qt.AlignRight: + val = val.rjust(width) + text += pad + sep + val + pad = " " * (width - len(val)) + sep = " " + pos = view.indexBelow(pos) + if not selection.isSelected(pos): + break + text = text.rstrip() + "\n" + pad = "" + sep = "" + + QApplication.clipboard().setText(text) + +def CopyCellsToClipboard(view, as_csv=False, with_hdr=False): + view.CopyCellsToClipboard(view, as_csv, with_hdr) + +def CopyCellsToClipboardHdr(view): + CopyCellsToClipboard(view, False, True) + +def CopyCellsToClipboardCSV(view): + CopyCellsToClipboard(view, True, True) + # Table window class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase): @@ -2282,6 +2487,8 @@ class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase): self.view.verticalHeader().setVisible(False) self.view.sortByColumn(-1, Qt.AscendingOrder) self.view.setSortingEnabled(True) + self.view.setSelectionMode(QAbstractItemView.ContiguousSelection) + self.view.CopyCellsToClipboard = CopyTableCellsToClipboard self.ResizeColumnsToContents() @@ -2398,6 +2605,8 @@ class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase): self.view.setModel(self.model) self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.view.verticalHeader().setVisible(False) + self.view.setSelectionMode(QAbstractItemView.ContiguousSelection) + self.view.CopyCellsToClipboard = CopyTableCellsToClipboard self.ResizeColumnsToContents() @@ -2735,6 +2944,8 @@ class MainWindow(QMainWindow): file_menu.addAction(CreateExitAction(glb.app, self)) edit_menu = menu.addMenu("&Edit") + edit_menu.addAction(CreateAction("&Copy", "Copy to clipboard", self.CopyToClipboard, self, QKeySequence.Copy)) + edit_menu.addAction(CreateAction("Copy as CS&V", "Copy to clipboard as CSV", self.CopyToClipboardCSV, self)) edit_menu.addAction(CreateAction("&Find...", "Find items", self.Find, self, QKeySequence.Find)) edit_menu.addAction(CreateAction("Fetch &more records...", "Fetch more records", self.FetchMoreRecords, self, [QKeySequence(Qt.Key_F8)])) edit_menu.addAction(CreateAction("&Shrink Font", "Make text smaller", self.ShrinkFont, self, [QKeySequence("Ctrl+-")])) @@ -2767,6 +2978,12 @@ class MainWindow(QMainWindow): except: pass + def CopyToClipboard(self): + self.Try(CopyCellsToClipboardHdr) + + def CopyToClipboardCSV(self): + self.Try(CopyCellsToClipboardCSV) + def Find(self): win = self.mdi_area.activeSubWindow() if win: -- cgit From 9bc4e4bfe6169343a8f019cd5d7843a558b78363 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 3 May 2019 15:08:27 +0300 Subject: perf scripts python: exported-sql-viewer.py: Add context menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a context menu (right-click) that provides options for copying to clipboard, including, for trees, the ability to copy only the cell under the mouse pointer. Committer testing: $ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db Simply right click and pick "Copy selection", that at this point has just the first line, not expanded, then see what was copied by pressing shift+control+v on a terminal: Call Path,Object,Count,Time (ns),Time (%),Branch Count,Branch Count (%) ▶ simple-retpolin,,,,,, Ditto after expanding, i.e. the selection continues to be just one line: Call Path Object Count Time (ns) Time (%) Branch Count Branch Count (%) ▼ simple-retpolin Now select all the lines with the mouse and control+shift+v again: Call Path Object Count Time (ns) Time (%) Branch Count Branch Count (%) ▼ 14503:14503 ▼ _start ld-2.28.so 1 156267 100.0 10602 100.0 ▶ unknown unknown 1 2276 1.5 1 0.0 ▶ _dl_start ld-2.28.so 1 137047 87.7 10088 95.2 ▶ _dl_init ld-2.28.so 1 9142 5.9 326 3.1 ▼ _start simple-retpoline 1 7457 4.8 182 1.7 ▶ unknown unknown 1 805 10.8 1 0.5 ▶ __libc_start_main libc-2.28.so 1 6347 85.1 179 98.4 Signed-off-by: Adrian Hunter Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Link: http://lkml.kernel.org/r/20190503120828.25326-6-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/exported-sql-viewer.py | 41 ++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'tools/perf/scripts/python/exported-sql-viewer.py') diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index baa2b220238a..affd80ebcae0 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py @@ -887,6 +887,8 @@ class TreeWindowBase(QMdiSubWindow): self.view.setSelectionMode(QAbstractItemView.ContiguousSelection) self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard + self.context_menu = TreeContextMenu(self.view) + def DisplayFound(self, ids): if not len(ids): return False @@ -1660,6 +1662,8 @@ class BranchWindow(QMdiSubWindow): self.ResizeColumnsToContents() + self.context_menu = TreeContextMenu(self.view) + self.find_bar = FindBar(self, self, True) self.finder = ChildDataItemFinder(self.model.root) @@ -2469,6 +2473,39 @@ def CopyCellsToClipboardHdr(view): def CopyCellsToClipboardCSV(view): CopyCellsToClipboard(view, True, True) +# Context menu + +class ContextMenu(object): + + def __init__(self, view): + self.view = view + self.view.setContextMenuPolicy(Qt.CustomContextMenu) + self.view.customContextMenuRequested.connect(self.ShowContextMenu) + + def ShowContextMenu(self, pos): + menu = QMenu(self.view) + self.AddActions(menu) + menu.exec_(self.view.mapToGlobal(pos)) + + def AddCopy(self, menu): + menu.addAction(CreateAction("&Copy selection", "Copy to clipboard", lambda: CopyCellsToClipboardHdr(self.view), self.view)) + menu.addAction(CreateAction("Copy selection as CS&V", "Copy to clipboard as CSV", lambda: CopyCellsToClipboardCSV(self.view), self.view)) + + def AddActions(self, menu): + self.AddCopy(menu) + +class TreeContextMenu(ContextMenu): + + def __init__(self, view): + super(TreeContextMenu, self).__init__(view) + + def AddActions(self, menu): + i = self.view.currentIndex() + text = str(i.data()).strip() + if len(text): + menu.addAction(CreateAction('Copy "' + text + '"', "Copy to clipboard", lambda: QApplication.clipboard().setText(text), self.view)) + self.AddCopy(menu) + # Table window class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase): @@ -2492,6 +2529,8 @@ class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase): self.ResizeColumnsToContents() + self.context_menu = ContextMenu(self.view) + self.find_bar = FindBar(self, self, True) self.finder = ChildDataItemFinder(self.data_model) @@ -2608,6 +2647,8 @@ class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase): self.view.setSelectionMode(QAbstractItemView.ContiguousSelection) self.view.CopyCellsToClipboard = CopyTableCellsToClipboard + self.context_menu = ContextMenu(self.view) + self.ResizeColumnsToContents() self.find_bar = FindBar(self, self, True) -- cgit From b62d18aba1109506c1926ab7b564c4ac3bd48786 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 3 May 2019 15:08:28 +0300 Subject: perf scripts python: exported-sql-viewer.py: Add 'About' dialog box With support for Python 2 or 3 and PySide 1 or 2 (Qt 4 or 5), it is useful to see what versions are in use. Add an 'About' dialog box that displays Python, PySide, Qt and database server (SQLite or PostgreSQL) version numbers. Committer testing: $ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db Then go to 'Help', then 'About', select all the lines with the mouse press 'Control+C', then, on the same terminal press control+shift+V which shows my current environment: Python version: 2.7.16 PySide version: 1 Qt version: 4.8.7 SQLite version: 3.26.0 Signed-off-by: Adrian Hunter Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Link: http://lkml.kernel.org/r/20190503120828.25326-7-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/exported-sql-viewer.py | 59 ++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'tools/perf/scripts/python/exported-sql-viewer.py') diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index affd80ebcae0..affed7d149be 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py @@ -2913,6 +2913,60 @@ class HelpOnlyWindow(QMainWindow): self.setCentralWidget(self.text) +# PostqreSQL server version + +def PostqreSQLServerVersion(db): + query = QSqlQuery(db) + QueryExec(query, "SELECT VERSION()") + if query.next(): + v_str = query.value(0) + v_list = v_str.strip().split(" ") + if v_list[0] == "PostgreSQL" and v_list[2] == "on": + return v_list[1] + return v_str + return "Unknown" + +# SQLite version + +def SQLiteVersion(db): + query = QSqlQuery(db) + QueryExec(query, "SELECT sqlite_version()") + if query.next(): + return query.value(0) + return "Unknown" + +# About dialog + +class AboutDialog(QDialog): + + def __init__(self, glb, parent=None): + super(AboutDialog, self).__init__(parent) + + self.setWindowTitle("About Exported SQL Viewer") + self.setMinimumWidth(300) + + pyside_version = "1" if pyside_version_1 else "2" + + text = "
"
+		text += "Python version:     " + sys.version.split(" ")[0] + "\n"
+		text += "PySide version:     " + pyside_version + "\n"
+		text += "Qt version:         " + qVersion() + "\n"
+		if glb.dbref.is_sqlite3:
+			text += "SQLite version:     " + SQLiteVersion(glb.db) + "\n"
+		else:
+			text += "PostqreSQL version: " + PostqreSQLServerVersion(glb.db) + "\n"
+		text += "
" + + self.text = QTextBrowser() + self.text.setHtml(text) + self.text.setReadOnly(True) + self.text.setOpenExternalLinks(True) + + self.vbox = QVBoxLayout() + self.vbox.addWidget(self.text) + + self.setLayout(self.vbox); + # Font resize def ResizeFont(widget, diff): @@ -3010,6 +3064,7 @@ class MainWindow(QMainWindow): help_menu = menu.addMenu("&Help") help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents)) + help_menu.addAction(CreateAction("&About Exported SQL Viewer", "About this application", self.About, self)) def Try(self, fn): win = self.mdi_area.activeSubWindow() @@ -3095,6 +3150,10 @@ class MainWindow(QMainWindow): def Help(self): HelpWindow(self.glb, self) + def About(self): + dialog = AboutDialog(self.glb, self) + dialog.exec_() + # XED Disassembler class xed_state_t(Structure): -- cgit