class SqlPage: name="SQL" order=800 def __init__(self, notebook): from _sqledit import SqlEditor self.control=SqlEditor(notebook) self.control.SetMarginWidth(1, 2) self.notebook=notebook self.lastNode=None def GetControl(self): return self.control def Display(self, node, _detached): if hasattr(node, "GetSql"): sql=node.GetSql().strip().replace("\n\r", "\n").replace("\r\n", "\n") else: sql=xlt("No SQL query available.") self.control.SetReadOnly(False) self.control.SetValue(sql) self.control.SetReadOnly(True) self.control.SetSelection(0,0)
def __init__(self, parentWin, node, params={}): SqlFrame.__init__(self, parentWin, xlt("Query Tool"), "SqlQuery") self.server=node.GetServer() self.application="%s Query Tool" % adm.appTitle snippet_table=self.server.info.get('snippet_table') if self.server.adminspace and snippet_table: self.snippet_table="%s.%s" % (quoteIdent(self.server.adminspace), quoteIdent(snippet_table)) else: self.snippet_table=None dbName=params.get('dbname') if not dbName: if hasattr(node, "GetDatabase"): dbName=node.GetDatabase().name else: dbName=self.server.maintDb self.worker=None self.sqlChanged=False self.previousCols=[] self.fileManager=FileManager(self, adm.config) toolbar=self.toolbar toolbar.Add(self.OnFileOpen, xlt("Load from file"),"file_open") toolbar.Add(self.OnFileSave, xlt("Save to file"), "file_save") toolbar.Add(self.OnToggleSnippets, xlt("Show snippets browser"), "snippets") toolbar.AddSeparator() toolbar.Add(self.OnCopy, xlt("Copy"), "clip_copy") toolbar.Add(self.OnCut, xlt("Cut"), "clip_cut") toolbar.Add(self.OnPaste, xlt("Paste"), "clip_paste") toolbar.Add(self.OnClear, xlt("Clear"), "edit_clear") toolbar.AddSeparator() toolbar.Add(self.OnUndo, xlt("Undo"), "edit_undo") toolbar.Add(self.OnRedo, xlt("Redo"), "edit_redo") # toolbar.Add((self.OnFind, xlt("Find"), "edit_find") toolbar.AddSeparator() cbClass=xmlres.getControlClass("whComboBox") allDbs=self.server.GetConnectableDbs() size=max(map(lambda db: toolbar.GetTextExtent(db)[0], allDbs)) BUTTONOFFS=30 self.databases=cbClass(toolbar, size=(size+BUTTONOFFS, -1)) self.databases.Append(allDbs) self.databases.Append(xlt("Connect...")) self.databases.SetStringSelection(dbName) self.OnChangeDatabase() self.databases.Bind(wx.EVT_COMBOBOX, self.OnChangeDatabase) toolbar.Add(self.OnExecuteQuery, xlt("Execute Query"), "query_execute") toolbar.Add(self.OnExplainQuery, xlt("Explain Query"), "query_explain") toolbar.Add(self.OnCancelQuery, xlt("Execute Query"), "query_cancel") toolbar.AddControl(self.databases) toolbar.AddSeparator() toolbar.Add(self.OnAddSnippet, xlt("Add snippet"), "snippet_add") toolbar.Add(self.OnReplaceSnippet, xlt("Replace snippet"), "snippet_replace") toolbar.Realize() menubar=wx.MenuBar() self.filemenu=menu=Menu(self) menu.Add(self.OnFileOpen, xlt("&Open"), xlt("Open query file")) menu.AppendMenu(-1, xlt("Open recent..."), self.fileManager.GetRecentFilesMenu()) menu.Add(self.OnFileInsert, xlt("&Insert"), xlt("Insert query file")) menu.Add(self.OnFileSave, xlt("&Save"), xlt("Save current file")) menu.Add(self.OnFileSaveAs, xlt("Save &as.."), xlt("Save file under new name")) menu.AppendSeparator() # menu.Add(xlt("Preferences"), xlt("Preferences"), self.OnPreferences) menu.Add(self.OnClose, xlt("Quit SQL"), xlt("Quit Sql")) menubar.Append(menu, xlt("&File")) self.viewmenu=menu=Menu(self) menu.AddCheck(self.OnToggleSnippets, xlt("Snippets"), xlt("Show or hide snippet browser")) self.registerToggles(True, True) menubar.Append(self.viewmenu, xlt("&View")) self.editmenu=menu=Menu(self) menu.Add(self.OnUndo, xlt("&Undo"), xlt("Undo last action")) menu.Add(self.OnRedo, xlt("&Redo"), xlt("Redo last action")) # menu.Add(xlt("&Find"), xlt("Find string"), self.OnFind) menu.AppendSeparator() menu.Add(self.OnCut, xlt("Cu&t"), xlt("Cut selected text to clipboard")) menu.Add(self.OnCopy, xlt("&Copy"), xlt("Copy selected text to clipboard")) menu.Add(self.OnPaste, xlt("&Paste"), xlt("Paste text from clipboard")) menu.Add(self.OnClear, xlt("C&lear"), xlt("Clear editor")) menu.AppendSeparator() menu.Add(self.OnAddSnippet, xlt("Add snippet"), xlt("Add selected text to snippets")) menu.Add(self.OnReplaceSnippet, xlt("Modify snippet"), xlt("Replace snippet with selected text")) menubar.Append(menu, xlt("&Edit")) self.querymenu=menu=Menu(self) menu.Add(self.OnExecuteQuery, xlt("Execute"), xlt("Execute query")) menu.Add(self.OnExplainQuery, xlt("Explain"), xlt("Explain query")) menu.Add(self.OnCancelQuery, xlt("Cancel"), xlt("Cancel query execution")) menubar.Append(menu, xlt("&Query")) self.helpmenu=menu=Menu(self) menu.Add(self.OnHelp, xlt("Help"), xlt("Show help"), wx.ID_HELP) menubar.Append(menu, xlt("&Help")) self.EnableMenu(self.querymenu, self.OnCancelQuery, False) self.SetMenuBar(menubar) ah=AcceleratorHelper(self) ah.Add(wx.ACCEL_CTRL, 'X', self.OnCut) ah.Add(wx.ACCEL_CTRL, 'C', self.OnCopy) ah.Add(wx.ACCEL_CTRL, 'V', self.OnPaste) ah.Add(wx.ACCEL_NORMAL,wx.WXK_F5, self.OnExecuteQuery) ah.Add(wx.ACCEL_NORMAL,wx.WXK_F7, self.OnExplainQuery) ah.Add(wx.ACCEL_ALT,wx.WXK_PAUSE, self.OnCancelQuery) ah.Realize() self.editor=SqlEditor(self) self.editor.SetAcceleratorTable(ah.GetTable()) self.editor.BindProcs(self.OnChangeStc, self.OnStatusPos) self.manager.AddPane(self.editor, wx.aui.AuiPaneInfo().Top().PaneBorder().Resizable().MinSize((200,100)).BestSize((400,200)).CloseButton(False) \ .Name("sqlQuery").Caption(xlt("SQL Query"))) self.snippets=SnippetTree(self, self.server, self.editor) self.manager.AddPane(self.snippets, wx.aui.AuiPaneInfo().Left().Top().PaneBorder().Resizable().MinSize((100,100)).BestSize((100,100)).CloseButton(True) \ .Name("snippets").Caption(xlt("SQL Snippets"))) if not self.snippet_table: self.manager.GetPane("snippets").Show(False) self.output=wx.Notebook(self) self.result=SqlResultGrid(self.output) self.explain = ExplainCanvas(self.output) self.explain.Hide() font=self.editor.GetFont() self.messages=wx.TextCtrl(self.output, style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP) self.msgHistory=wx.TextCtrl(self.output, style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP) self.messages.SetFont(font) self.msgHistory.SetFont(font) self.output.AddPage(self.result, xlt("Output")) self.output.AddPage(self.messages, xlt("Messages")) self.output.AddPage(self.msgHistory, xlt("History")) self.manager.AddPane(self.output, wx.aui.AuiPaneInfo().Center().MinSize((200,100)).BestSize((400,200)).CloseButton(False) \ .Name("Result").Caption(xlt("Result")).CaptionVisible(False)) self.manager.Bind(wx.aui.EVT_AUI_PANE_CLOSE, self.OnAuiCloseEvent) self.SetStatus(xlt("ready")) self.restorePerspective() self.manager.GetPane("Result").Show() self.manager.Update() self.viewmenu.Check(self.OnToggleSnippets, self.manager.GetPane("snippets").IsShown()) self.OnToggleToolBar() self.OnToggleStatusBar() self.updateMenu() query=params.get('query') if query: self.editor.SetText(query) pos=params.get('errline', -1) if pos: line=self.editor.LineFromPosition(int(pos)) self.editor.MarkerSet(line) msg=params.get('message') if msg: self.messages.AppendText(msg) hint=params.get('hint') if hint: self.messages.AppendText("\n\nHINT:\n") self.messages.AppendText(hint) self.output.SetSelection(1) self.Show() self.editor.SetFocus()
class QueryFrame(SqlFrame): def __init__(self, parentWin, node, params={}): SqlFrame.__init__(self, parentWin, xlt("Query Tool"), "SqlQuery") self.server=node.GetServer() self.application="%s Query Tool" % adm.appTitle snippet_table=self.server.info.get('snippet_table') if self.server.adminspace and snippet_table: self.snippet_table="%s.%s" % (quoteIdent(self.server.adminspace), quoteIdent(snippet_table)) else: self.snippet_table=None dbName=params.get('dbname') if not dbName: if hasattr(node, "GetDatabase"): dbName=node.GetDatabase().name else: dbName=self.server.maintDb self.worker=None self.sqlChanged=False self.previousCols=[] self.fileManager=FileManager(self, adm.config) toolbar=self.toolbar toolbar.Add(self.OnFileOpen, xlt("Load from file"),"file_open") toolbar.Add(self.OnFileSave, xlt("Save to file"), "file_save") toolbar.Add(self.OnToggleSnippets, xlt("Show snippets browser"), "snippets") toolbar.AddSeparator() toolbar.Add(self.OnCopy, xlt("Copy"), "clip_copy") toolbar.Add(self.OnCut, xlt("Cut"), "clip_cut") toolbar.Add(self.OnPaste, xlt("Paste"), "clip_paste") toolbar.Add(self.OnClear, xlt("Clear"), "edit_clear") toolbar.AddSeparator() toolbar.Add(self.OnUndo, xlt("Undo"), "edit_undo") toolbar.Add(self.OnRedo, xlt("Redo"), "edit_redo") # toolbar.Add((self.OnFind, xlt("Find"), "edit_find") toolbar.AddSeparator() cbClass=xmlres.getControlClass("whComboBox") allDbs=self.server.GetConnectableDbs() size=max(map(lambda db: toolbar.GetTextExtent(db)[0], allDbs)) BUTTONOFFS=30 self.databases=cbClass(toolbar, size=(size+BUTTONOFFS, -1)) self.databases.Append(allDbs) self.databases.Append(xlt("Connect...")) self.databases.SetStringSelection(dbName) self.OnChangeDatabase() self.databases.Bind(wx.EVT_COMBOBOX, self.OnChangeDatabase) toolbar.Add(self.OnExecuteQuery, xlt("Execute Query"), "query_execute") toolbar.Add(self.OnExplainQuery, xlt("Explain Query"), "query_explain") toolbar.Add(self.OnCancelQuery, xlt("Execute Query"), "query_cancel") toolbar.AddControl(self.databases) toolbar.AddSeparator() toolbar.Add(self.OnAddSnippet, xlt("Add snippet"), "snippet_add") toolbar.Add(self.OnReplaceSnippet, xlt("Replace snippet"), "snippet_replace") toolbar.Realize() menubar=wx.MenuBar() self.filemenu=menu=Menu(self) menu.Add(self.OnFileOpen, xlt("&Open"), xlt("Open query file")) menu.AppendMenu(-1, xlt("Open recent..."), self.fileManager.GetRecentFilesMenu()) menu.Add(self.OnFileInsert, xlt("&Insert"), xlt("Insert query file")) menu.Add(self.OnFileSave, xlt("&Save"), xlt("Save current file")) menu.Add(self.OnFileSaveAs, xlt("Save &as.."), xlt("Save file under new name")) menu.AppendSeparator() # menu.Add(xlt("Preferences"), xlt("Preferences"), self.OnPreferences) menu.Add(self.OnClose, xlt("Quit SQL"), xlt("Quit Sql")) menubar.Append(menu, xlt("&File")) self.viewmenu=menu=Menu(self) menu.AddCheck(self.OnToggleSnippets, xlt("Snippets"), xlt("Show or hide snippet browser")) self.registerToggles(True, True) menubar.Append(self.viewmenu, xlt("&View")) self.editmenu=menu=Menu(self) menu.Add(self.OnUndo, xlt("&Undo"), xlt("Undo last action")) menu.Add(self.OnRedo, xlt("&Redo"), xlt("Redo last action")) # menu.Add(xlt("&Find"), xlt("Find string"), self.OnFind) menu.AppendSeparator() menu.Add(self.OnCut, xlt("Cu&t"), xlt("Cut selected text to clipboard")) menu.Add(self.OnCopy, xlt("&Copy"), xlt("Copy selected text to clipboard")) menu.Add(self.OnPaste, xlt("&Paste"), xlt("Paste text from clipboard")) menu.Add(self.OnClear, xlt("C&lear"), xlt("Clear editor")) menu.AppendSeparator() menu.Add(self.OnAddSnippet, xlt("Add snippet"), xlt("Add selected text to snippets")) menu.Add(self.OnReplaceSnippet, xlt("Modify snippet"), xlt("Replace snippet with selected text")) menubar.Append(menu, xlt("&Edit")) self.querymenu=menu=Menu(self) menu.Add(self.OnExecuteQuery, xlt("Execute"), xlt("Execute query")) menu.Add(self.OnExplainQuery, xlt("Explain"), xlt("Explain query")) menu.Add(self.OnCancelQuery, xlt("Cancel"), xlt("Cancel query execution")) menubar.Append(menu, xlt("&Query")) self.helpmenu=menu=Menu(self) menu.Add(self.OnHelp, xlt("Help"), xlt("Show help"), wx.ID_HELP) menubar.Append(menu, xlt("&Help")) self.EnableMenu(self.querymenu, self.OnCancelQuery, False) self.SetMenuBar(menubar) ah=AcceleratorHelper(self) ah.Add(wx.ACCEL_CTRL, 'X', self.OnCut) ah.Add(wx.ACCEL_CTRL, 'C', self.OnCopy) ah.Add(wx.ACCEL_CTRL, 'V', self.OnPaste) ah.Add(wx.ACCEL_NORMAL,wx.WXK_F5, self.OnExecuteQuery) ah.Add(wx.ACCEL_NORMAL,wx.WXK_F7, self.OnExplainQuery) ah.Add(wx.ACCEL_ALT,wx.WXK_PAUSE, self.OnCancelQuery) ah.Realize() self.editor=SqlEditor(self) self.editor.SetAcceleratorTable(ah.GetTable()) self.editor.BindProcs(self.OnChangeStc, self.OnStatusPos) self.manager.AddPane(self.editor, wx.aui.AuiPaneInfo().Top().PaneBorder().Resizable().MinSize((200,100)).BestSize((400,200)).CloseButton(False) \ .Name("sqlQuery").Caption(xlt("SQL Query"))) self.snippets=SnippetTree(self, self.server, self.editor) self.manager.AddPane(self.snippets, wx.aui.AuiPaneInfo().Left().Top().PaneBorder().Resizable().MinSize((100,100)).BestSize((100,100)).CloseButton(True) \ .Name("snippets").Caption(xlt("SQL Snippets"))) if not self.snippet_table: self.manager.GetPane("snippets").Show(False) self.output=wx.Notebook(self) self.result=SqlResultGrid(self.output) self.explain = ExplainCanvas(self.output) self.explain.Hide() font=self.editor.GetFont() self.messages=wx.TextCtrl(self.output, style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP) self.msgHistory=wx.TextCtrl(self.output, style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP) self.messages.SetFont(font) self.msgHistory.SetFont(font) self.output.AddPage(self.result, xlt("Output")) self.output.AddPage(self.messages, xlt("Messages")) self.output.AddPage(self.msgHistory, xlt("History")) self.manager.AddPane(self.output, wx.aui.AuiPaneInfo().Center().MinSize((200,100)).BestSize((400,200)).CloseButton(False) \ .Name("Result").Caption(xlt("Result")).CaptionVisible(False)) self.manager.Bind(wx.aui.EVT_AUI_PANE_CLOSE, self.OnAuiCloseEvent) self.SetStatus(xlt("ready")) self.restorePerspective() self.manager.GetPane("Result").Show() self.manager.Update() self.viewmenu.Check(self.OnToggleSnippets, self.manager.GetPane("snippets").IsShown()) self.OnToggleToolBar() self.OnToggleStatusBar() self.updateMenu() query=params.get('query') if query: self.editor.SetText(query) pos=params.get('errline', -1) if pos: line=self.editor.LineFromPosition(int(pos)) self.editor.MarkerSet(line) msg=params.get('message') if msg: self.messages.AppendText(msg) hint=params.get('hint') if hint: self.messages.AppendText("\n\nHINT:\n") self.messages.AppendText(hint) self.output.SetSelection(1) self.Show() self.editor.SetFocus() def SetTitle(self, dbName): title=xlt("PostGreSQL Query Tool - Database \"%(dbname)s\" on Server \"%(server)s\"" % { 'dbname': dbName, 'server': self.server.name}) adm.Frame.SetTitle(self, title) def OnHelp(self, evt): wx.LaunchDefaultBrowser("http://www.admin4.org/docs/pgsql/querytool") def OnClose(self, evt): self.OnCancelQuery(None) for i in range(self.databases.GetCount()): conn=self.databases.GetClientData(i) if conn: conn.disconnect() super(QueryFrame, self).OnClose(evt) self.Destroy() def OnChangeDatabase(self, evt=None): i=self.databases.GetSelection() if i == self.databases.GetCount()-1: class ConnectDlg(adm.CheckedDialog): def __init__(self, frame): adm.CheckedDialog.__init__(self, frame) self.frame=frame def Go(self): self['Database'].AppendItems(self.frame.server.GetConnectableDbs()) self['Database'].SetStringSelection(self.frame.server.maintDb) def Execute(self): user=dlg.User if user: dbName="%s@%s" % (user, self.Database) else: dbName=self.Database if self.frame.databases.FindString(dbName) < 0: try: conn = pgConnection(self.frame.server.GetDsn(self.Database, self.frame.application, user, self.password)) self.frame.lastDatabaseSelection=self.frame.databases.GetCount()-1 self.frame.databases.Insert(dbName, self.frame.lastDatabaseSelection, conn) except Exception as e: self.SetStatus(str(e)) return False return True dlg=ConnectDlg(self) dlg.GoModal() self.databases.SetSelection(self.lastDatabaseSelection) return elif i >= 0: dbName=self.databases.GetString(i) self.conn = self.databases.GetClientData(i) if not self.conn: try: self.conn = pgConnection(self.server.GetDsn(dbName, self.application)) self.databases.SetClientData(i, self.conn) except Exception as e: print str(e) self.SetTitle(dbName) self.lastDatabaseSelection=i def updateMenu(self, ctl=None): if not self.GetToolBar(): return canCut=canPaste=canUndo=canRedo=False if not ctl or ctl == self.editor: canUndo=self.editor.CanUndo(); canRedo=self.editor.CanRedo(); canPaste=self.editor.CanPaste(); canCut = True; a,e=self.editor.GetSelection() canQuery = not self.worker and ( a!=e or self.editor.GetLineCount() >1 or self.getSql() ) self.EnableMenu(self.editmenu, self.OnAddSnippet, self.snippet_table) self.EnableMenu(self.editmenu, self.OnReplaceSnippet, self.snippets.CanReplace()) self.EnableMenu(self.editmenu, self.OnCut, canCut) self.EnableMenu(self.editmenu, self.OnPaste, canPaste) self.EnableMenu(self.editmenu, self.OnUndo, canUndo) self.EnableMenu(self.editmenu, self.OnRedo, canRedo) self.EnableMenu(self.editmenu, self.OnClear, canQuery) # self.EnableMenu(self.editmenu, self.OnFind, canQuery) self.EnableMenu(self.filemenu, self.OnFileSave, self.sqlChanged) self.EnableMenu(self.querymenu, self.OnExecuteQuery, canQuery) self.EnableMenu(self.querymenu, self.OnExplainQuery, canQuery) def executeSql(self, targetPage, sql, _queryOffset=0, resultToMsg=False): self.EnableMenu(self.querymenu, self.OnCancelQuery, True) self.EnableMenu(self.querymenu, self.OnExecuteQuery, False) self.EnableMenu(self.querymenu, self.OnExplainQuery, False) wx.YieldIfNeeded() self.startTime=localTimeMillis(); self.worker=worker=self.conn.GetCursor().ExecuteAsync(sql) rowcount=0 rowset=None worker.start() self.SetStatus(xlt("Query is running.")); self.SetStatusText("", self.STATUSPOS_SECS); self.SetStatusText("", self.STATUSPOS_ROWS); self.msgHistory.AppendText(xlt("-- Executing query:\n")); self.msgHistory.AppendText(sql); self.msgHistory.AppendText("\n"); self.editor.MarkerDelete() self.messages.Clear() durationTxt=self.pollWorker() self.worker=None self.EnableMenu(self.querymenu, self.OnCancelQuery, False) self.EnableMenu(self.querymenu, self.OnExecuteQuery, True) self.EnableMenu(self.querymenu, self.OnExplainQuery, True) if worker.error: errmsg=worker.error.error errlines=errmsg.splitlines() self.messages.SetValue(errmsg) self.msgHistory.AppendText(errmsg) for i in range(1, len(errlines)): if errlines[i].startswith("LINE "): lineinfo=errlines[i].split(':')[0][5:] colinfo=errlines[i+1].find('^') dummy=colinfo self.editor.MarkerSet(int(lineinfo)-1 + self.editor.GetSelectOffset()) break if worker.cancelled: self.SetStatus(xlt("Cancelled.")); elif worker.error: self.SetStatus(errlines[0]); else: self.SetStatus(xlt("OK.")); rowcount=worker.GetRowcount() rowset=worker.GetResult() if worker.error: self.SetStatusText("", self.STATUSPOS_ROWS) else: if rowcount == 1: rowsMsg=xlt("1 row affected") elif rowcount < 0: rowsMsg=xlt("Executed") else: rowsMsg= xlt("%d rows affected") % rowcount self.SetStatusText(rowsMsg, self.STATUSPOS_ROWS) self.msgHistory.AppendText("-- %s\n" % rowsMsg) rowsMsg += xlt("; %s execution time.") % durationTxt self.msgHistory.AppendText("\n") currentPage=self.output.GetPage(0) if currentPage != targetPage: self.output.RemovePage(0) currentPage.Hide() targetPage.Show() self.output.InsertPage(0, targetPage, xlt("Data output"), True) if rowset and rowset.colNames: self.output.SetSelection(0) targetPage.SetData(rowset) else: self.output.SetSelection(1) targetPage.SetEmpty() for notice in self.conn.conn.notices: self.messages.AppendText(notice); self.messages.AppendText("\n") if not worker.error: if resultToMsg: self.messages.SetValue("\n".join(targetPage.GetResult())) else: self.messages.SetValue(rowsMsg) self.editor.SetFocus() def getSql(self): sql=self.editor.GetSelectedText() if not sql: sql=self.editor.GetText() return sql.strip() def OnAuiCloseEvent(self, evt): if evt.GetPane().name == "snippets": self.filemenu.Check(self.OnToggleSnippets, False) def OnToggleSnippets(self, evt): paneInfo=self.manager.GetPane("snippets") how=self.viewmenu.IsChecked(self.OnToggleSnippets) if isinstance(evt.EventObject, wx.ToolBar): how=not how self.viewmenu.Check(self.OnToggleSnippets, how) paneInfo.Show(how) self.manager.Update() def OnAddSnippet(self, evt): sql=self.getSql() if sql: dlg=wx.TextEntryDialog(self, xlt("Snippet name"), xlt("Add snippet")) if dlg.ShowModal() == wx.ID_OK: name=dlg.GetValue() self.snippets.AppendSnippet(name, sql) self.SetStatus(xlt("Snipped stored.")) def OnReplaceSnippet(self, evt): sql=self.getSql() if sql: self.snippets.ReplaceSnippet(sql) def OnCancelQuery(self, evt): self.EnableMenu(self.querymenu, self.OnCancelQuery, False) if self.worker: self.worker.Cancel() def OnExecuteQuery(self, evt): sql=self.getSql() if not sql.strip(): return self.executeSql(self.result, sql) def OnExplainQuery(self, evt): sql=self.getSql() if not sql: return self.executeSql(self.explain, "EXPLAIN %s" % sql, 8, True) def readFile(self, message, filename=None): if not filename: filename=self.fileManager.OpenFile(self, self.filePatterns, message) if filename: try: f=open(filename, 'r') sql=f.read() f.close() return sql except: self.SetStatus(xlt("Failed to read %s") % filename) return None def fileOpen(self, header, filename=None): sql=self.readFile(header, filename) if sql: self.editor.ClearAll() self.editor.ReplaceSelection(sql) self.SetStatus(xlt("%d characters read from %s") % (len(sql), self.fileManager.currentFile)) self.updateMenu() def OnRecentFileOpened(self, filename): self.fileOpen(None, filename) def OnFileOpen(self, evt): self.fileOpen(xlt("Open SQL file")) def OnFileInsert(self, evt): sql=self.readFile(xlt("Insert SQL from file")) if sql: self.editor.ReplaceSelection(sql) self.SetStatus(xlt("%d characters inserted from %s") % (len(sql), self.fileManager.currentFile)) self.updateMenu() def saveFile(self, proc): try: ok=proc(self, self.editor.GetText(), self.filePatterns, xlt("Save SQL Query")) if ok: self.SetStatus(xlt("Saved SQL query to %s") % self.fileManager.filename) self.sqlChanged=False self.updateMenu() else: self.StatusText(xlt("Nothing saved")) except: self.SetStatus(xlt("Failed to save to %s") % self.fileManager.filename) def OnFileSave(self, evt): self.saveFile(self.fileManager.SaveFile) def OnFileSaveAs(self, evt): self.saveFile(self.fileManager.SaveFileAs) def OnUndo(self, evt): self.editor.Undo() def OnClear(self, evt): self.editor.ClearAll() self.updateMenu() def OnFind(self, evt): pass def OnRedo(self, evt): self.editor.Redo() def OnChangeStc(self, evt): self.sqlChanged=True self.updateMenu() def OnStatusPos(self, evt): row=self.editor.LineFromPosition(self.editor.GetCurrentPos())+1 col=self.editor.GetColumn(self.editor.GetCurrentPos())+1 self.SetStatusText(xlt("Ln %d Col %d") % (row, col), self.STATUSPOS_POS)
def __init__(self, parentWin, connectionPool, name, server): self.tableSpecs=TableSpecs(connectionPool, name) self.connectionPool=connectionPool self.worker=None self.output=None self.server=server querypreset_table=self.server.info.get('querypreset_table') if self.server.adminspace and querypreset_table: self.querypreset_table="%s.%s" % (quoteIdent(self.server.adminspace), quoteIdent(querypreset_table)) else: self.querypreset_table=None title=xlt("%(appTitle)s Data Tool - %(tableName)s") % { 'appTitle': adm.appTitle, 'tableName': name} SqlFrame.__init__(self, parentWin, title, "SqlData") toolbar=self.GetToolBar() toolbar.Add(self.OnRefresh, xlt("Refresh"), "data_refresh") toolbar.Add(self.OnCancelRefresh, xlt("Cancel refresh"), "query_cancel") toolbar.Add(self.OnSave, xlt("Save data"), "data_save") toolbar.Add(self.OnToggleFilter, xlt("Show filter window"), "filter") toolbar.AddSeparator() toolbar.Add(self.OnCopy, xlt("Copy"), "clip_copy") toolbar.Add(self.OnCut, xlt("Cut"), "clip_cut") toolbar.Add(self.OnPaste, xlt("Paste"), "clip_paste") toolbar.Add(self.OnUndo, xlt("Undo"), "edit_undo") toolbar.AddSeparator() toolbar.Add(self.OnDelete, xlt("Delete"), "delete") menubar=wx.MenuBar() self.filemenu=menu=Menu(self) menu.Add(self.OnClose, xlt("Quit tool"), xlt("Quit data tool")) menubar.Append(menu, xlt("&File")) self.datamenu=menu=Menu(self) menu.Add(self.OnRefresh, xlt("Refresh"), xlt("Refresh data")) menu.Add(self.OnCancelRefresh, xlt("Cancel"), xlt("Cancel refresh")) menu.Add(self.OnSave, xlt("Save"), xlt("Save data")) menu.Add(self.OnDelete, xlt("Delete"), xlt("Delete row(s)")) menubar.Append(menu, xlt("&Data")) self.viewmenu=menu=Menu(self) menu.AddCheck(self.OnToggleFilter, xlt("Filter"), xlt("Show or hide filter window")) self.registerToggles(True, True) menubar.Append(menu, xlt("&View")) self.editmenu=menu=Menu(self) menu.Add(self.OnCut, xlt("Cu&t"), xlt("Cut selected data to clipboard")) menu.Add(self.OnCopy, xlt("&Copy"), xlt("Copy selected data to clipboard")) menu.Add(self.OnPaste, xlt("&Paste"), xlt("Paste data from clipboard")) menu.Add(self.OnUndo, xlt("&Undo"), xlt("discard last editing")) menubar.Append(menu, xlt("&Edit")) self.helpmenu=menu=Menu(self) menu.Add(self.OnHelp, xlt("Help"), xlt("Show help"), wx.ID_HELP) menubar.Append(menu, xlt("&Help")) self.EnableMenu(self.datamenu, self.OnCancelRefresh, False) self.SetMenuBar(menubar) toolbar.Realize() ah=AcceleratorHelper(self) ah.Add(wx.ACCEL_CTRL, 'X', self.OnCut) ah.Add(wx.ACCEL_CTRL, 'C', self.OnCopy) ah.Add(wx.ACCEL_CTRL, 'V', self.OnPaste) ah.Add(wx.ACCEL_CTRL, 'S', self.OnSave) ah.Add(wx.ACCEL_NORMAL,wx.WXK_F5, self.OnRefresh) ah.Add(wx.ACCEL_ALT,wx.WXK_PAUSE, self.OnCancelRefresh) ah.Realize() self.notebook=wx.Notebook(self) self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnCheck) self.filter=FilterPanel(self, self.notebook) self.notebook.AddPage(self.filter, xlt("Filter, Order, Limit")) self.editor=SqlEditor(self.notebook) self.editor.SetAcceleratorTable(ah.GetTable()) self.notebook.AddPage(self.editor, xlt("Manual SQL")) self.manager.AddPane(self.notebook, wx.aui.AuiPaneInfo().Top().PaneBorder().Resizable().MinSize((200,200)).BestSize((400,200)).CloseButton(True) \ .Name("filter").Caption(xlt("SQL query parameter")).Hide()) self.output = SqlEditGrid(self, self.tableSpecs) self.manager.AddPane(self.output, wx.aui.AuiPaneInfo().Center().MinSize((200,100)).BestSize((400,200)).CloseButton(False) \ .Name("Edit Data").Caption(xlt("Edit Data")).CaptionVisible(False)) self.restorePerspective() self.manager.GetPane("Edit data").Show() self.manager.Update() self.manager.Bind(wx.aui.EVT_AUI_PANE_CLOSE, self.OnAuiCloseEvent) self.viewmenu.Check(self.OnToggleFilter, self.manager.GetPane("filter").IsShown()) self.OnToggleToolBar() self.OnToggleStatusBar() self.updateMenu() self.filter.Go(self.tableSpecs) if not self.editor.GetText(): # otherwise set from default preset self.editor.SetText("/*\n%s\n*/\n\n%s" % (xlt( "Caution: Don't mess with table and column names!\nYou may experience unwanted behaviour or data loss."), self.filter.GetQuery()))
class DataFrame(SqlFrame): def __init__(self, parentWin, connectionPool, name, server): self.tableSpecs=TableSpecs(connectionPool, name) self.connectionPool=connectionPool self.worker=None self.output=None self.server=server querypreset_table=self.server.info.get('querypreset_table') if self.server.adminspace and querypreset_table: self.querypreset_table="%s.%s" % (quoteIdent(self.server.adminspace), quoteIdent(querypreset_table)) else: self.querypreset_table=None title=xlt("%(appTitle)s Data Tool - %(tableName)s") % { 'appTitle': adm.appTitle, 'tableName': name} SqlFrame.__init__(self, parentWin, title, "SqlData") toolbar=self.GetToolBar() toolbar.Add(self.OnRefresh, xlt("Refresh"), "data_refresh") toolbar.Add(self.OnCancelRefresh, xlt("Cancel refresh"), "query_cancel") toolbar.Add(self.OnSave, xlt("Save data"), "data_save") toolbar.Add(self.OnToggleFilter, xlt("Show filter window"), "filter") toolbar.AddSeparator() toolbar.Add(self.OnCopy, xlt("Copy"), "clip_copy") toolbar.Add(self.OnCut, xlt("Cut"), "clip_cut") toolbar.Add(self.OnPaste, xlt("Paste"), "clip_paste") toolbar.Add(self.OnUndo, xlt("Undo"), "edit_undo") toolbar.AddSeparator() toolbar.Add(self.OnDelete, xlt("Delete"), "delete") menubar=wx.MenuBar() self.filemenu=menu=Menu(self) menu.Add(self.OnClose, xlt("Quit tool"), xlt("Quit data tool")) menubar.Append(menu, xlt("&File")) self.datamenu=menu=Menu(self) menu.Add(self.OnRefresh, xlt("Refresh"), xlt("Refresh data")) menu.Add(self.OnCancelRefresh, xlt("Cancel"), xlt("Cancel refresh")) menu.Add(self.OnSave, xlt("Save"), xlt("Save data")) menu.Add(self.OnDelete, xlt("Delete"), xlt("Delete row(s)")) menubar.Append(menu, xlt("&Data")) self.viewmenu=menu=Menu(self) menu.AddCheck(self.OnToggleFilter, xlt("Filter"), xlt("Show or hide filter window")) self.registerToggles(True, True) menubar.Append(menu, xlt("&View")) self.editmenu=menu=Menu(self) menu.Add(self.OnCut, xlt("Cu&t"), xlt("Cut selected data to clipboard")) menu.Add(self.OnCopy, xlt("&Copy"), xlt("Copy selected data to clipboard")) menu.Add(self.OnPaste, xlt("&Paste"), xlt("Paste data from clipboard")) menu.Add(self.OnUndo, xlt("&Undo"), xlt("discard last editing")) menubar.Append(menu, xlt("&Edit")) self.helpmenu=menu=Menu(self) menu.Add(self.OnHelp, xlt("Help"), xlt("Show help"), wx.ID_HELP) menubar.Append(menu, xlt("&Help")) self.EnableMenu(self.datamenu, self.OnCancelRefresh, False) self.SetMenuBar(menubar) toolbar.Realize() ah=AcceleratorHelper(self) ah.Add(wx.ACCEL_CTRL, 'X', self.OnCut) ah.Add(wx.ACCEL_CTRL, 'C', self.OnCopy) ah.Add(wx.ACCEL_CTRL, 'V', self.OnPaste) ah.Add(wx.ACCEL_CTRL, 'S', self.OnSave) ah.Add(wx.ACCEL_NORMAL,wx.WXK_F5, self.OnRefresh) ah.Add(wx.ACCEL_ALT,wx.WXK_PAUSE, self.OnCancelRefresh) ah.Realize() self.notebook=wx.Notebook(self) self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnCheck) self.filter=FilterPanel(self, self.notebook) self.notebook.AddPage(self.filter, xlt("Filter, Order, Limit")) self.editor=SqlEditor(self.notebook) self.editor.SetAcceleratorTable(ah.GetTable()) self.notebook.AddPage(self.editor, xlt("Manual SQL")) self.manager.AddPane(self.notebook, wx.aui.AuiPaneInfo().Top().PaneBorder().Resizable().MinSize((200,200)).BestSize((400,200)).CloseButton(True) \ .Name("filter").Caption(xlt("SQL query parameter")).Hide()) self.output = SqlEditGrid(self, self.tableSpecs) self.manager.AddPane(self.output, wx.aui.AuiPaneInfo().Center().MinSize((200,100)).BestSize((400,200)).CloseButton(False) \ .Name("Edit Data").Caption(xlt("Edit Data")).CaptionVisible(False)) self.restorePerspective() self.manager.GetPane("Edit data").Show() self.manager.Update() self.manager.Bind(wx.aui.EVT_AUI_PANE_CLOSE, self.OnAuiCloseEvent) self.viewmenu.Check(self.OnToggleFilter, self.manager.GetPane("filter").IsShown()) self.OnToggleToolBar() self.OnToggleStatusBar() self.updateMenu() self.filter.Go(self.tableSpecs) if not self.editor.GetText(): # otherwise set from default preset self.editor.SetText("/*\n%s\n*/\n\n%s" % (xlt( "Caution: Don't mess with table and column names!\nYou may experience unwanted behaviour or data loss."), self.filter.GetQuery())) def OnHelp(self, evt): wx.LaunchDefaultBrowser("http://www.admin4.org/docs/pgsql/datatool") def OnAuiCloseEvent(self, evt): if evt.GetPane().name == "filter": self.datamenu.Check(self.OnToggleFilter, False) def OnToggleFilter(self, evt): paneInfo=self.manager.GetPane("filter") how=self.viewmenu.IsChecked(self.OnToggleFilter) if isinstance(evt.EventObject, wx.ToolBar): how=not how self.viewmenu.Check(self.OnToggleFilter, how) paneInfo.Show(how) self.manager.Update() def OnCheck(self, evt): if evt.GetSelection(): self.editor.Show() self.updateMenu(evt.GetSelection()) def updateMenu(self, sel=None): if sel == None: sel=self.notebook.GetSelection() if sel: queryOk=True else: queryOk=self.filter.valid if self.output: if self.output.table: canSave=self.output.dirty canUndo=(self.output.table.currentRow!=None) else: canSave=canUndo=False self.EnableMenu(self.editmenu, self.OnUndo, canUndo) self.EnableMenu(self.datamenu, self.OnRefresh, queryOk) self.EnableMenu(self.datamenu, self.OnSave, canSave) def OnDelete(self, evt): self.output.OnDeleteRows(evt) def executeQuery(self, sql): self.output.SetEmpty() self.worker=None self.EnableMenu(self.datamenu, self.OnRefresh, False) self.EnableMenu(self.datamenu, self.OnCancelRefresh, True) self.startTime=localTimeMillis(); self.worker=worker=self.tableSpecs.GetCursor().ExecuteAsync(sql) worker.start() self.SetStatus(xlt("Refreshing data...")); self.SetStatusText("", self.STATUSPOS_ROWS) self.pollWorker() self.EnableMenu(self.datamenu, self.OnCancelRefresh, False) self.EnableMenu(self.datamenu, self.OnRefresh, True) txt=xlt("%d rows") % worker.GetRowcount() if not self.notebook.GetSelection() and self.filter.LimitCheck and self.filter.LimitValue == worker.GetRowcount(): txt += " LIMIT" self.SetStatusText(txt, self.STATUSPOS_ROWS) if worker.cancelled: self.SetStatus(xlt("Cancelled.")); self.output.SetData(worker.GetResult()) elif worker.error: errlines=worker.error.error.splitlines() self.output.SetEmpty() self.SetStatus(errlines[0]); else: self.SetStatus(xlt("OK.")); self.output.SetData(worker.GetResult()) def OnSave(self, evt): self.output.DoCommit() self.output.Refresh() def OnRefresh(self, evt=None): if self.notebook.GetSelection(): sql=self.editor.GetSelectedText() if not sql: sql=self.editor.GetText() if not sql.strip(): return else: sql=self.filter.GetQuery() self.executeQuery(sql) def OnCancelRefresh(self, evt): self.EnableMenu(self.datamenu, self.OnCancelRefresh, False) if self.worker: self.worker.Cancel() def OnUndo(self, evt): self.output.RevertEdit() def OnClose(self, evt): self.OnCancelRefresh(None) if self.output.table and self.output.table.currentRow: dlg=wx.MessageDialog(self, xlt("Data is changed but not written.\nSave now?"), xlt("Unsaved data"), wx.YES_NO|wx.CANCEL|wx.CANCEL_DEFAULT|wx.ICON_EXCLAMATION) rc=dlg.ShowModal() if rc == wx.ID_CANCEL: return elif rc == wx.ID_YES: self.output.table.Commit() self.worker = None self.connectionPool.Disconnect() super(DataFrame, self).OnClose(evt) self.Destroy()
def AddExtraControls(self, res): self.FilterValue=SqlEditor(self) res.AttachUnknownControl("FilterValuePlaceholder", self.FilterValue) self.FilterValue.SetMarginWidth(1, 0)
class FilterPanel(adm.NotebookPanel): def __init__(self, dlg, notebook): adm.NotebookPanel.__init__(self, dlg, notebook) self.Bind("LimitCheck", self.OnLimitCheck) self.Bind("FilterCheck", self.OnFilterCheck) self.Bind("FilterValidate", self.OnFilterValidate) self.FilterValue.BindProcs(self.OnFilterValueChanged, None) self.Bind("FilterPreset", wx.EVT_COMBOBOX, self.OnPresetSelect) self.Bind("FilterPreset", wx.EVT_TEXT, self.OnPresetChange) self.Bind("FilterSave", self.OnFilterSave) self['SortCols'].Bind(wx.EVT_LISTBOX_DCLICK, self.OnDclickSort) # TODO unfortunately we need 3.x here if True: # wx.Platform == "__WXMAC__" and wx.VERSION < (3,0): event=wx.EVT_LEFT_DOWN else: event=wx.EVT_MOTION self['DisplayCols'].Bind(event, self.OnBeginDrag) self['SortCols'].Bind(event, self.OnBeginDrag) self['DisplayCols'].Bind(wx.EVT_CHECKLISTBOX, self.OnClickCol) self.OnLimitCheck() self.OnFilterCheck() self.valid=True self.dialog=dlg self.EnableControls("FilterPreset", dlg.querypreset_table) self.EnableControls("FilterSave", False) def AddExtraControls(self, res): self.FilterValue=SqlEditor(self) res.AttachUnknownControl("FilterValuePlaceholder", self.FilterValue) self.FilterValue.SetMarginWidth(1, 0) def OnPresetSelect(self, evt): preset=self.FilterPreset.strip() if not preset: return query=pgQuery(self.dialog.querypreset_table, self.dialog.server.GetCursor()) query.AddCol('querylimit') query.AddCol('filter') query.AddCol('sort') query.AddCol('display') query.AddCol('sql') query.AddWhere('dbname', self.tableSpecs.dbName) query.AddWhere('tabname', self.tableSpecs.tabName) query.AddWhere('presetname', preset) res=query.Select() for row in res: limit=row['querylimit'] filter=row['filter'] sort=evalAsPython(row['sort']) display=evalAsPython(row['display']) sql=row['sql'] if limit: self.LimitCheck=True self.OnLimitCheck() self.LimitValue=limit else: self.LimitCheck=False if sql: self.dialog.editor.SetText(sql) if sort: sc=self['SortCols'] sc.Clear() cols=self.tableSpecs.colNames[:] for col in sort: if col.endswith(' DESC'): colpure=col[:-5] else: colpure=col if colpure in cols: id=sc.Append(col) sc.Check(id, True) cols.remove(colpure) sc.AppendItems(cols) if display: dc=self['DisplayCols'] dc.Clear() cols=self.tableSpecs.colNames[:] for col in display: if col in cols: id=dc.Append(col) dc.Check(id, True) cols.remove(col) dc.AppendItems(cols) if filter: self.FilterCheck=True self.OnFilterCheck() self.FilterValue.SetText(filter) self.OnFilterValidate(evt) else: self.FilterCheck=False break # only one row, hopefully self.OnPresetChange(evt) def OnPresetChange(self, evt): self.EnableControls("FilterSave", self.FilterPreset) def OnClickCol(self, evt): if evt.String in self.dialog.tableSpecs.keyCols: # don't un-display key colums; we need them evt.EventObject.Check(evt.Selection, True) pass def OnBeginDrag(self, evt): if evt.GetPosition().x < 30 or not evt.LeftDown(): evt.Skip() return lb=evt.EventObject i=lb.HitTest(evt.GetPosition()) if i >= 0: lb.SetDropTarget(TextDropTarget(lb)) data=wx.PyTextDataObject(str(i)) ds=wx.DropSource(lb) ds.SetData(data) ds.DoDragDrop(False) lb.SetDropTarget(None) def OnDclickSort(self, evt): colname=self['SortCols'].GetString(evt.Selection) if colname.endswith(" DESC"): colname=colname[:-5] else: colname = colname+" DESC" self['SortCols'].SetString(evt.Selection, colname) def OnFilterSave(self, evt): preset=self.FilterPreset if self.LimitCheck: limit=self.LimitValue else: limit=None if self.FilterCheck: filter=self.FilterValue.GetText() else: filter=None sort=self['SortCols'].GetCheckedStrings() display=self['DisplayCols'].GetCheckedStrings() sql=self.dialog.editor.GetText() query=pgQuery(self.dialog.querypreset_table, self.dialog.server.GetCursor()) query.AddColVal('querylimit', limit) query.AddColVal('filter', filter) query.AddColVal('sort', unicode(sort)) query.AddColVal('display', unicode(display)) query.AddColVal('sql', sql) fp=self['FilterPreset'] if fp.FindString(preset) < 0: query.AddColVal('dbname', self.tableSpecs.dbName) query.AddColVal('tabname', self.tableSpecs.tabName) query.AddColVal('presetname', preset) query.Insert() fp.Append(preset) else: query.AddWhere('dbname', self.tableSpecs.dbName) query.AddWhere('tabname', self.tableSpecs.tabName) query.AddWhere('presetname', preset) query.Update() def OnLimitCheck(self, evt=None): self.EnableControls("LimitValue", self.LimitCheck) def OnFilterCheck(self, evt=None): self.EnableControls("FilterValidate", self.FilterCheck) self.FilterValue.Enable(self.FilterCheck) self.OnFilterValueChanged(evt) def OnFilterValueChanged(self, evt): self.valid=not self.FilterCheck self.dialog.updateMenu() def OnFilterValidate(self, evt): self.valid=False sql="EXPLAIN " + self.GetQuery() cursor=self.tableSpecs.GetCursor() cursor.ExecuteSet(sql) # will throw and show exception if invalid self.dialog.SetStatus(xlt("Filter expression valid")) self.valid=True self.dialog.updateMenu() def Go(self, tableSpecs): self.tableSpecs=tableSpecs dc=self['DisplayCols'] sc=self['SortCols'] for colName in self.tableSpecs.colNames: i=dc.Append(colName) dc.Check(i, True) i=sc.Append(colName) if colName in self.tableSpecs.keyCols: sc.Check(i, True) if self.dialog.querypreset_table: query=pgQuery(self.dialog.querypreset_table, self.dialog.server.GetCursor()) query.AddCol('presetname') query.AddWhere('dbname', self.tableSpecs.dbName) query.AddWhere('tabname', self.tableSpecs.tabName) query.AddOrder('presetname') res=query.Select() fp=self['FilterPreset'] for row in res: fp.Append(row[0]) default=fp.FindString('default') if id >= 0: fp.SetSelection(default) self.OnPresetSelect(None) def GetQuery(self): query=pgQuery(self.tableSpecs.tabName) for colName in self['DisplayCols'].GetCheckedStrings(): query.AddCol(colName, True) for colName in self['SortCols'].GetCheckedStrings(): if colName.endswith(' DESC'): query.AddOrder(query.quoteIdent(colName[:-5]) + " DESC", False) else: query.AddOrder(colName, True) if self.FilterCheck: filter=self.FilterValue.GetText().strip() query.AddWhere(filter) sql= query.SelectQueryString() if self.LimitCheck: sql += "\n LIMIT %d" % self.LimitValue return sql
def __init__(self, notebook): from _sqledit import SqlEditor self.control = SqlEditor(notebook) self.control.SetMarginWidth(1, 2) self.notebook = notebook self.lastNode = None