PgConsole: add app.py, splitted from pgconsole.py.
--- a/.hgignore Tue Aug 16 23:53:54 2011 +0200
+++ b/.hgignore Fri Aug 19 17:08:34 2011 +0200
@@ -1,2 +1,3 @@
.*\.pyc
pgtoolkit\.conf
+build
--- a/pgconsole.py Tue Aug 16 23:53:54 2011 +0200
+++ b/pgconsole.py Fri Aug 19 17:08:34 2011 +0200
@@ -1,485 +1,7 @@
-#!/usr/bin/env python
-
-import time
-import gobject, gtk, pango, cairo
-import gtksourceview2 as gtksourceview
-
-import psycopg2
-import psycopg2.extensions
-import psycopg2.extras
+#!/usr/bin/env python3.2
from pgconsole.config import cfg
-from pgconsole.editor import Editor
-from pgconsole.dataview import DataView
-from pgconsole.database import Database, BadConnectionError, DatabaseError
-from pgconsole.settings import Settings
-from pgconsole.panedext import HPanedExt, VPanedExt
-
-
-class PgConsoleApp:
- def __init__(self):
- self.db = Database()
- self.conn = None
-
- win = gtk.Window(gtk.WINDOW_TOPLEVEL)
- self.win = win
- win.set_title('PostgreSQL Console')
- win.set_size_request(300, 200) # minimal size
- win.set_default_size(800, 600)
- self.restore_window_size()
- win.connect("destroy", self.destroy)
- win.connect("key_press_event", self.keypress)
- win.connect('configure-event', self.on_configure)
-
- # toolbar
- toolbar = gtk.Toolbar()
- toolbar.set_style(gtk.TOOLBAR_ICONS)
- toolbar.set_property("icon-size", gtk.ICON_SIZE_SMALL_TOOLBAR)
-
- tb = gtk.ToolButton(gtk.STOCK_PREFERENCES)
- tb.set_label('Settings')
- tb.set_tooltip_text('Settings')
- tb.connect('clicked', self.settings)
- self.tb_settings = tb
- toolbar.add(tb)
-
- self.cb_server = gtk.combo_box_entry_new_text()
- self.cb_server.set_tooltip_text('Server')
- self.cb_server.get_child().set_property("editable", False)
- self.cb_server.set_property("add_tearoffs", True)
- #self.cb_server.set_property("focus-on-click", False)
- self.cb_server.set_property("can-focus", True)
- self.cb_server.connect('changed', self.on_server_changed)
- self.cb_server.connect("key_press_event", self.toolbar_server_keypress)
- ti = gtk.ToolItem()
- ti.add(self.cb_server)
- toolbar.add(ti)
-
- self.cb_dbname = gtk.combo_box_entry_new_text()
- self.cb_dbname.set_tooltip_text('Database')
- self.cb_dbname.get_child().set_property("editable", False)
- self.cb_dbname.set_property("add_tearoffs", True)
- #self.cb_dbname.set_property("focus-on-click", False)
- self.cb_dbname.set_property("can-focus", True)
- ti = gtk.ToolItem()
- ti.add(self.cb_dbname)
- toolbar.add(ti)
-
- tb = gtk.ToolButton(gtk.STOCK_CONNECT)
- tb.set_label('Connect')
- tb.set_tooltip_text('Connect')
- tb.connect('clicked', self.connect)
- toolbar.add(tb)
- self.tb_connect = tb
-
- sep = gtk.SeparatorToolItem()
- toolbar.add(sep)
-
- tb = gtk.ToolButton(gtk.STOCK_EXECUTE)
- tb.set_label('Execute')
- tb.set_tooltip_text('Execute')
- tb.connect('clicked', self.execute)
- toolbar.add(tb)
- tb.set_sensitive(False)
- self.tb_execute = tb
- tb = gtk.ToolButton(gtk.STOCK_NEW)
- tb.set_label('Begin transaction')
- tb.set_tooltip_text('Begin transaction')
- tb.connect('clicked', self.begin)
- tb.set_sensitive(False)
- toolbar.add(tb)
- self.tb_begin = tb
- tb = gtk.ToolButton(gtk.STOCK_APPLY)
- tb.set_label('Commit')
- tb.set_tooltip_text('Commit')
- tb.connect('clicked', self.commit)
- tb.set_sensitive(False)
- self.tb_commit = tb
- toolbar.add(tb)
- tb = gtk.ToolButton(gtk.STOCK_CANCEL)
- tb.set_label('Rollback')
- tb.set_tooltip_text('Rollback')
- tb.connect('clicked', self.rollback)
- tb.set_sensitive(False)
- self.tb_rollback = tb
- toolbar.add(tb)
-
- sep = gtk.SeparatorToolItem()
- toolbar.add(sep)
-
- # editor
- self.editor = Editor()
-
- # data view
- self.dataview = DataView()
-
-
- vbox = gtk.VBox(False, 2)
-
- sep = gtk.SeparatorToolItem()
- sep.set_expand(True)
- sep.set_draw(False)
- toolbar.add(sep)
-
- self.throbber_anim = gtk.gdk.PixbufAnimation('data/Throbber.gif')
- self.throbber = gtk.Image()
- tb = gtk.ToolItem()
- tb.add(self.throbber)
- toolbar.add(tb)
- sep = gtk.SeparatorToolItem()
- sep.set_draw(False)
- toolbar.add(sep)
-
- vbox.pack_start(toolbar, False, False, 0)
-
- vpaned = VPanedExt()
- vpaned.set_border_width(5)
-
- hpaned = HPanedExt()
- hpaned.set_border_width(0)
- hpaned.add1(self.editor)
- hpaned.child_set_property(self.editor, 'shrink', False)
- hpaned.set_snap2(80)
- hpaned.set_property('position', 500)
-
- vpaned.add1(hpaned)
- vpaned.set_snap1(80)
- vpaned.set_property('position', 300)
-
- vpaned.add2(self.dataview)
- vpaned.set_snap2(80)
-
- self.vpaned = vpaned
- self.hpaned = hpaned
-
- # log
- self.logbuf = gtk.TextBuffer()
- view = gtk.TextView(self.logbuf)
- view.set_editable(False)
- font_desc = pango.FontDescription('monospace')
- if font_desc:
- view.modify_font(font_desc)
-
- sw = gtk.ScrolledWindow()
- sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
- sw.add(view)
- hpaned.add2(sw)
-
- vbox.pack_start(vpaned, padding=0)
-
- win.add(vbox)
-
- self.editor.view.grab_focus()
-
- self.reload_server_list(0)
-
- win.show_all()
-
- self.restore_win_state()
-
-
- def main(self):
- gtk.main()
-
-
- def destroy(self, widget, data=None):
- self.save_win_state()
- cfg.save()
- gtk.main_quit()
-
-
- def on_configure(self, w, ev):
- cfg.root.window.size.width = ev.width
- cfg.root.window.size.height = ev.height
-
-
- def restore_window_size(self):
- self.win.resize(cfg.root.window.size.width, cfg.root.window.size.height)
-
-
- def save_win_state(self):
- cfg.root.window.dividers.verticaldivider = self.vpaned.get_position()
- cfg.root.window.dividers.horizontaldivider = self.hpaned.get_position()
- cfg.root.window.dividers.editordivider = self.editor.get_position()
-
-
- def restore_win_state(self):
- pos = cfg.root.window.dividers.verticaldivider
- if pos >= 0:
- self.vpaned.set_position(pos)
- pos = cfg.root.window.dividers.horizontaldivider
- if pos >= 0:
- self.hpaned.set_position(pos)
- pos = cfg.root.window.dividers.editordivider
- if pos >= 0:
- self.editor.set_position(pos)
-
-
- def get_typename(self, oid, size):
- self.curs.execute('SELECT typname FROM pg_type WHERE oid=%s', [oid])
- psycopg2.extras.wait_select(self.curs.connection)
- row = self.curs.fetchone()
-
- typname = None
- if row:
- typname = row[0]
- if typname == 'int4':
- return 'integer'
- if typname in ('timestamp', 'interval', 'date'):
- return typname
- if size and size > 0 and size < 65535:
- typname += '(%s)' % size
- return typname
-
-
- def get_conninfo(self, nodb=False):
- sel = self.cb_server.get_active()
- srv = cfg.servers.server[sel]
- if nodb:
- dbname = 'postgres'
- else:
- dbname = self.cb_dbname.get_active_text()
- conninfo = 'host=%s port=%s dbname=%s user=%s password=%s' \
- % (srv.host, srv.port, dbname, srv.user, srv.password)
- return conninfo
-
-
- def connect(self, w):
- conninfo = self.get_conninfo()
- if self.conn:
- # disconnect
- self.db.put_conn(conninfo, self.conn)
- self.conn = None
- self.cb_server.set_sensitive(True)
- self.cb_dbname.set_sensitive(True)
- self.tb_connect.set_stock_id(gtk.STOCK_CONNECT)
- self.tb_connect.set_label('Connect')
- self.tb_connect.set_tooltip_text('Connect')
- self.tb_execute.set_sensitive(False)
- self.tb_begin.set_sensitive(False)
- else:
- # connect
- self.logbuf.insert(self.logbuf.get_end_iter(), 'Connect %s\n' % conninfo)
- try:
- self.conn = self.db.get_conn(conninfo)
- except DatabaseError, e:
- self.logbuf.insert(self.logbuf.get_end_iter(), 'Error:\n%s\n' % e)
- return
- self.cb_server.set_sensitive(False)
- self.cb_dbname.set_sensitive(False)
- self.tb_connect.set_stock_id(gtk.STOCK_DISCONNECT)
- self.tb_connect.set_label('Disconnect')
- self.tb_connect.set_tooltip_text('Disconnect')
- self.tb_execute.set_sensitive(True)
- self.tb_begin.set_sensitive(True)
-
-
- def begin(self, w):
- self.logbuf.insert(self.logbuf.get_end_iter(), 'Begin transaction\n')
- curs = self.conn.cursor()
- curs.execute('BEGIN')
- psycopg2.extras.wait_select(curs.connection)
-
- self.tb_connect.set_sensitive(False)
- self.tb_begin.set_sensitive(False)
- self.tb_commit.set_sensitive(True)
- self.tb_rollback.set_sensitive(True)
-
-
- def commit(self, w):
- self.logbuf.insert(self.logbuf.get_end_iter(), 'Commit\n')
- curs = self.conn.cursor()
- curs.execute('COMMIT')
- psycopg2.extras.wait_select(curs.connection)
-
- self.tb_connect.set_sensitive(True)
- self.tb_begin.set_sensitive(True)
- self.tb_commit.set_sensitive(False)
- self.tb_rollback.set_sensitive(False)
-
-
- def rollback(self, w):
- self.logbuf.insert(self.logbuf.get_end_iter(), 'Rollback\n')
- curs = self.conn.cursor()
- curs.execute('ROLLBACK')
- psycopg2.extras.wait_select(curs.connection)
-
- self.tb_connect.set_sensitive(True)
- self.tb_begin.set_sensitive(True)
- self.tb_commit.set_sensitive(False)
- self.tb_rollback.set_sensitive(False)
-
-
- def execute(self, widget):
- query = self.editor.get_selection() or self.editor.get_text()
-
- self.tb_connect.set_sensitive(False)
- self.tb_execute.set_sensitive(False)
- self.tb_begin.set_sensitive(False)
- self.tb_commit.set_sensitive(False)
- self.tb_rollback.set_sensitive(False)
- self.throbber.set_from_animation(self.throbber_anim)
-
- self.curs = self.conn.cursor()
-
- self.t1 = time.time()
- try:
- self.curs.execute(query)
- except (psycopg2.OperationalError, psycopg2.DatabaseError), e:
- self.logbuf.insert(self.logbuf.get_end_iter(), 'Error:\n' + str(e))
- return
-
- self.execute_poll()
-
-
- def execute_poll(self, source=None, cond=None):
- try:
- state = self.conn.poll()
- except (psycopg2.OperationalError, psycopg2.DatabaseError), e:
- self.logbuf.insert(self.logbuf.get_end_iter(), 'Error:\n' + str(e))
- return
-
- if state == psycopg2.extensions.POLL_OK:
- self.execute_finish()
- elif state == psycopg2.extensions.POLL_WRITE:
- gobject.io_add_watch(self.conn.fileno(), gobject.IO_OUT, self.execute_poll)
- elif state == psycopg2.extensions.POLL_READ:
- gobject.io_add_watch(self.conn.fileno(), gobject.IO_IN, self.execute_poll)
- else:
- self.logbuf.insert(self.logbuf.get_end_iter(), "poll() returned %s" % state)
- return
-
-
- def execute_finish(self):
- t2 = time.time()
- t = (t2 - self.t1)*1000
-
- self.throbber.clear()
-
- self.logbuf.insert(self.logbuf.get_end_iter(),
- 'Query successful (%d ms, %d rows)\n' % (t, self.curs.rowcount))
-
- # notices
- for n in self.conn.notices:
- self.logbuf.insert(self.logbuf.get_end_iter(), n)
-
- if self.curs.rowcount >= 0:
- rows = self.curs.fetchall()
-
- names = []
- for c in self.curs.description:
- name = c[0]
- typename = self.get_typename(c[1], c[3])
- names += [(name, typename)]
-
- self.dataview.load_data(names, rows)
-
- self.tb_execute.set_sensitive(True)
- if self.conn.get_transaction_status() == psycopg2.extensions.TRANSACTION_STATUS_INTRANS:
- self.tb_commit.set_sensitive(True)
- self.tb_rollback.set_sensitive(True)
- else:
- self.tb_connect.set_sensitive(True)
- self.tb_begin.set_sensitive(True)
-
-
- def simulate_click(self, tb):
- if tb.get_property('sensitive'):
- tb.get_child().activate()
-
-
- def keypress(self, w, event):
- keyname = gtk.gdk.keyval_name(event.keyval)
- if keyname == 'F1':
- self.simulate_click(self.tb_settings)
- return True
- if keyname == 'F2':
- print self.cb_server.popup()
- return True
- if keyname == 'F3':
- print self.cb_dbname.popup()
- return True
- if keyname == 'F4':
- self.simulate_click(self.tb_connect)
- return True
- if keyname == 'F5':
- self.simulate_click(self.tb_execute)
- return True
- if keyname == 'F6':
- self.simulate_click(self.tb_begin)
- return True
- if keyname == 'F7':
- self.simulate_click(self.tb_commit)
- return True
- if keyname == 'F8':
- self.simulate_click(self.tb_rollback)
- return True
-
- return False
-
-
- def toolbar_server_keypress(self, w, event):
- keyname = gtk.gdk.keyval_name(event.keyval)
- if keyname == 'Tab':
- self.populate_db_list()
- self.cb_dbname.grab_focus()
- return True
-
-
- def on_server_changed(self, w):
- if self.cb_server.get_active() != -1:
- self.populate_db_list()
-
-
- def populate_db_list(self):
- conninfo = self.get_conninfo(True)
- try:
- conn = self.db.get_conn(conninfo)
- except DatabaseError, e:
- self.logbuf.insert(self.logbuf.get_end_iter(), 'Error:\n%s\n' % e)
- return
-
- curs = conn.cursor()
- curs.execute('SELECT * FROM pg_catalog.pg_database WHERE NOT datistemplate ORDER BY 1')
- psycopg2.extras.wait_select(conn)
- rows = curs.fetchall()
-
- self.db.put_conn(conninfo, conn)
-
- for i in range(self.cb_dbname.get_model().iter_n_children(None)):
- self.cb_dbname.remove_text(0)
-
- for row in rows:
- self.cb_dbname.append_text(row[0])
-
- self.cb_dbname.set_active(0)
-
-
- def reload_server_list(self, sel=None):
- # clean
- for i in range(self.cb_server.get_model().iter_n_children(None)):
- self.cb_server.remove_text(0)
- self.cb_server.get_child().set_text('')
-
- try:
- # populate
- for server in cfg.servers.server:
- if str(server.name):
- title = '%s (%s)' % (str(server.name), str(server.host))
- else:
- title = str(server.host)
- self.cb_server.append_text(title)
- except AttributeError:
- pass
-
- if not sel is None:
- self.cb_server.set_active(sel)
-
-
- def settings(self, w):
- Settings(self)
-
+from pgconsole.app import PgConsoleApp
if __name__ == '__main__':
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pgconsole/app.py Fri Aug 19 17:08:34 2011 +0200
@@ -0,0 +1,480 @@
+import time
+import gobject, gtk, pango, cairo
+import gtksourceview2 as gtksourceview
+
+import psycopg2
+import psycopg2.extensions
+import psycopg2.extras
+
+from pgconsole.config import cfg
+from pgconsole.editor import Editor
+from pgconsole.dataview import DataView
+from pgconsole.database import Database, BadConnectionError, DatabaseError
+from pgconsole.settings import Settings
+from pgconsole.panedext import HPanedExt, VPanedExt
+
+
+class PgConsoleApp:
+ def __init__(self):
+ self.db = Database()
+ self.conn = None
+
+ win = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ self.win = win
+ win.set_title('PostgreSQL Console')
+ win.set_size_request(300, 200) # minimal size
+ win.set_default_size(800, 600)
+ self.restore_window_size()
+ win.connect("destroy", self.destroy)
+ win.connect("key_press_event", self.keypress)
+ win.connect('configure-event', self.on_configure)
+
+ # toolbar
+ toolbar = gtk.Toolbar()
+ toolbar.set_style(gtk.TOOLBAR_ICONS)
+ toolbar.set_property("icon-size", gtk.ICON_SIZE_SMALL_TOOLBAR)
+
+ tb = gtk.ToolButton(gtk.STOCK_PREFERENCES)
+ tb.set_label('Settings')
+ tb.set_tooltip_text('Settings')
+ tb.connect('clicked', self.settings)
+ self.tb_settings = tb
+ toolbar.add(tb)
+
+ self.cb_server = gtk.combo_box_entry_new_text()
+ self.cb_server.set_tooltip_text('Server')
+ self.cb_server.get_child().set_property("editable", False)
+ self.cb_server.set_property("add_tearoffs", True)
+ #self.cb_server.set_property("focus-on-click", False)
+ self.cb_server.set_property("can-focus", True)
+ self.cb_server.connect('changed', self.on_server_changed)
+ self.cb_server.connect("key_press_event", self.toolbar_server_keypress)
+ ti = gtk.ToolItem()
+ ti.add(self.cb_server)
+ toolbar.add(ti)
+
+ self.cb_dbname = gtk.combo_box_entry_new_text()
+ self.cb_dbname.set_tooltip_text('Database')
+ self.cb_dbname.get_child().set_property("editable", False)
+ self.cb_dbname.set_property("add_tearoffs", True)
+ #self.cb_dbname.set_property("focus-on-click", False)
+ self.cb_dbname.set_property("can-focus", True)
+ ti = gtk.ToolItem()
+ ti.add(self.cb_dbname)
+ toolbar.add(ti)
+
+ tb = gtk.ToolButton(gtk.STOCK_CONNECT)
+ tb.set_label('Connect')
+ tb.set_tooltip_text('Connect')
+ tb.connect('clicked', self.connect)
+ toolbar.add(tb)
+ self.tb_connect = tb
+
+ sep = gtk.SeparatorToolItem()
+ toolbar.add(sep)
+
+ tb = gtk.ToolButton(gtk.STOCK_EXECUTE)
+ tb.set_label('Execute')
+ tb.set_tooltip_text('Execute')
+ tb.connect('clicked', self.execute)
+ toolbar.add(tb)
+ tb.set_sensitive(False)
+ self.tb_execute = tb
+ tb = gtk.ToolButton(gtk.STOCK_NEW)
+ tb.set_label('Begin transaction')
+ tb.set_tooltip_text('Begin transaction')
+ tb.connect('clicked', self.begin)
+ tb.set_sensitive(False)
+ toolbar.add(tb)
+ self.tb_begin = tb
+ tb = gtk.ToolButton(gtk.STOCK_APPLY)
+ tb.set_label('Commit')
+ tb.set_tooltip_text('Commit')
+ tb.connect('clicked', self.commit)
+ tb.set_sensitive(False)
+ self.tb_commit = tb
+ toolbar.add(tb)
+ tb = gtk.ToolButton(gtk.STOCK_CANCEL)
+ tb.set_label('Rollback')
+ tb.set_tooltip_text('Rollback')
+ tb.connect('clicked', self.rollback)
+ tb.set_sensitive(False)
+ self.tb_rollback = tb
+ toolbar.add(tb)
+
+ sep = gtk.SeparatorToolItem()
+ toolbar.add(sep)
+
+ # editor
+ self.editor = Editor()
+
+ # data view
+ self.dataview = DataView()
+
+
+ vbox = gtk.VBox(False, 2)
+
+ sep = gtk.SeparatorToolItem()
+ sep.set_expand(True)
+ sep.set_draw(False)
+ toolbar.add(sep)
+
+ self.throbber_anim = gtk.gdk.PixbufAnimation('data/Throbber.gif')
+ self.throbber = gtk.Image()
+ tb = gtk.ToolItem()
+ tb.add(self.throbber)
+ toolbar.add(tb)
+ sep = gtk.SeparatorToolItem()
+ sep.set_draw(False)
+ toolbar.add(sep)
+
+ vbox.pack_start(toolbar, False, False, 0)
+
+ vpaned = VPanedExt()
+ vpaned.set_border_width(5)
+
+ hpaned = HPanedExt()
+ hpaned.set_border_width(0)
+ hpaned.add1(self.editor)
+ hpaned.child_set_property(self.editor, 'shrink', False)
+ hpaned.set_snap2(80)
+ hpaned.set_property('position', 500)
+
+ vpaned.add1(hpaned)
+ vpaned.set_snap1(80)
+ vpaned.set_property('position', 300)
+
+ vpaned.add2(self.dataview)
+ vpaned.set_snap2(80)
+
+ self.vpaned = vpaned
+ self.hpaned = hpaned
+
+ # log
+ self.logbuf = gtk.TextBuffer()
+ view = gtk.TextView(self.logbuf)
+ view.set_editable(False)
+ font_desc = pango.FontDescription('monospace')
+ if font_desc:
+ view.modify_font(font_desc)
+
+ sw = gtk.ScrolledWindow()
+ sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
+ sw.add(view)
+ hpaned.add2(sw)
+
+ vbox.pack_start(vpaned, padding=0)
+
+ win.add(vbox)
+
+ self.editor.view.grab_focus()
+
+ self.reload_server_list(0)
+
+ win.show_all()
+
+ self.restore_win_state()
+
+
+ def main(self):
+ gtk.main()
+
+
+ def destroy(self, widget, data=None):
+ self.save_win_state()
+ cfg.save()
+ gtk.main_quit()
+
+
+ def on_configure(self, w, ev):
+ cfg.root.window.size.width = ev.width
+ cfg.root.window.size.height = ev.height
+
+
+ def restore_window_size(self):
+ self.win.resize(cfg.root.window.size.width, cfg.root.window.size.height)
+
+
+ def save_win_state(self):
+ cfg.root.window.dividers.verticaldivider = self.vpaned.get_position()
+ cfg.root.window.dividers.horizontaldivider = self.hpaned.get_position()
+ cfg.root.window.dividers.editordivider = self.editor.get_position()
+
+
+ def restore_win_state(self):
+ pos = cfg.root.window.dividers.verticaldivider
+ if pos >= 0:
+ self.vpaned.set_position(pos)
+ pos = cfg.root.window.dividers.horizontaldivider
+ if pos >= 0:
+ self.hpaned.set_position(pos)
+ pos = cfg.root.window.dividers.editordivider
+ if pos >= 0:
+ self.editor.set_position(pos)
+
+
+ def get_typename(self, oid, size):
+ self.curs.execute('SELECT typname FROM pg_type WHERE oid=%s', [oid])
+ psycopg2.extras.wait_select(self.curs.connection)
+ row = self.curs.fetchone()
+
+ typname = None
+ if row:
+ typname = row[0]
+ if typname == 'int4':
+ return 'integer'
+ if typname in ('timestamp', 'interval', 'date'):
+ return typname
+ if size and size > 0 and size < 65535:
+ typname += '(%s)' % size
+ return typname
+
+
+ def get_conninfo(self, nodb=False):
+ sel = self.cb_server.get_active()
+ srv = cfg.servers.server[sel]
+ if nodb:
+ dbname = 'postgres'
+ else:
+ dbname = self.cb_dbname.get_active_text()
+ conninfo = 'host=%s port=%s dbname=%s user=%s password=%s' \
+ % (srv.host, srv.port, dbname, srv.user, srv.password)
+ return conninfo
+
+
+ def connect(self, w):
+ conninfo = self.get_conninfo()
+ if self.conn:
+ # disconnect
+ self.db.put_conn(conninfo, self.conn)
+ self.conn = None
+ self.cb_server.set_sensitive(True)
+ self.cb_dbname.set_sensitive(True)
+ self.tb_connect.set_stock_id(gtk.STOCK_CONNECT)
+ self.tb_connect.set_label('Connect')
+ self.tb_connect.set_tooltip_text('Connect')
+ self.tb_execute.set_sensitive(False)
+ self.tb_begin.set_sensitive(False)
+ else:
+ # connect
+ self.logbuf.insert(self.logbuf.get_end_iter(), 'Connect %s\n' % conninfo)
+ try:
+ self.conn = self.db.get_conn(conninfo)
+ except DatabaseError as e:
+ self.logbuf.insert(self.logbuf.get_end_iter(), 'Error:\n%s\n' % e)
+ return
+ self.cb_server.set_sensitive(False)
+ self.cb_dbname.set_sensitive(False)
+ self.tb_connect.set_stock_id(gtk.STOCK_DISCONNECT)
+ self.tb_connect.set_label('Disconnect')
+ self.tb_connect.set_tooltip_text('Disconnect')
+ self.tb_execute.set_sensitive(True)
+ self.tb_begin.set_sensitive(True)
+
+
+ def begin(self, w):
+ self.logbuf.insert(self.logbuf.get_end_iter(), 'Begin transaction\n')
+ curs = self.conn.cursor()
+ curs.execute('BEGIN')
+ psycopg2.extras.wait_select(curs.connection)
+
+ self.tb_connect.set_sensitive(False)
+ self.tb_begin.set_sensitive(False)
+ self.tb_commit.set_sensitive(True)
+ self.tb_rollback.set_sensitive(True)
+
+
+ def commit(self, w):
+ self.logbuf.insert(self.logbuf.get_end_iter(), 'Commit\n')
+ curs = self.conn.cursor()
+ curs.execute('COMMIT')
+ psycopg2.extras.wait_select(curs.connection)
+
+ self.tb_connect.set_sensitive(True)
+ self.tb_begin.set_sensitive(True)
+ self.tb_commit.set_sensitive(False)
+ self.tb_rollback.set_sensitive(False)
+
+
+ def rollback(self, w):
+ self.logbuf.insert(self.logbuf.get_end_iter(), 'Rollback\n')
+ curs = self.conn.cursor()
+ curs.execute('ROLLBACK')
+ psycopg2.extras.wait_select(curs.connection)
+
+ self.tb_connect.set_sensitive(True)
+ self.tb_begin.set_sensitive(True)
+ self.tb_commit.set_sensitive(False)
+ self.tb_rollback.set_sensitive(False)
+
+
+ def execute(self, widget):
+ query = self.editor.get_selection() or self.editor.get_text()
+
+ self.tb_connect.set_sensitive(False)
+ self.tb_execute.set_sensitive(False)
+ self.tb_begin.set_sensitive(False)
+ self.tb_commit.set_sensitive(False)
+ self.tb_rollback.set_sensitive(False)
+ self.throbber.set_from_animation(self.throbber_anim)
+
+ self.curs = self.conn.cursor()
+
+ self.t1 = time.time()
+ try:
+ self.curs.execute(query)
+ except (psycopg2.OperationalError, psycopg2.DatabaseError) as e:
+ self.logbuf.insert(self.logbuf.get_end_iter(), 'Error:\n' + str(e))
+ return
+
+ self.execute_poll()
+
+
+ def execute_poll(self, source=None, cond=None):
+ try:
+ state = self.conn.poll()
+ except (psycopg2.OperationalError, psycopg2.DatabaseError) as e:
+ self.logbuf.insert(self.logbuf.get_end_iter(), 'Error:\n' + str(e))
+ return
+
+ if state == psycopg2.extensions.POLL_OK:
+ self.execute_finish()
+ elif state == psycopg2.extensions.POLL_WRITE:
+ gobject.io_add_watch(self.conn.fileno(), gobject.IO_OUT, self.execute_poll)
+ elif state == psycopg2.extensions.POLL_READ:
+ gobject.io_add_watch(self.conn.fileno(), gobject.IO_IN, self.execute_poll)
+ else:
+ self.logbuf.insert(self.logbuf.get_end_iter(), "poll() returned %s" % state)
+ return
+
+
+ def execute_finish(self):
+ t2 = time.time()
+ t = (t2 - self.t1)*1000
+
+ self.throbber.clear()
+
+ self.logbuf.insert(self.logbuf.get_end_iter(),
+ 'Query successful (%d ms, %d rows)\n' % (t, self.curs.rowcount))
+
+ # notices
+ for n in self.conn.notices:
+ self.logbuf.insert(self.logbuf.get_end_iter(), n)
+
+ if self.curs.rowcount >= 0:
+ rows = self.curs.fetchall()
+
+ names = []
+ for c in self.curs.description:
+ name = c[0]
+ typename = self.get_typename(c[1], c[3])
+ names += [(name, typename)]
+
+ self.dataview.load_data(names, rows)
+
+ self.tb_execute.set_sensitive(True)
+ if self.conn.get_transaction_status() == psycopg2.extensions.TRANSACTION_STATUS_INTRANS:
+ self.tb_commit.set_sensitive(True)
+ self.tb_rollback.set_sensitive(True)
+ else:
+ self.tb_connect.set_sensitive(True)
+ self.tb_begin.set_sensitive(True)
+
+
+ def simulate_click(self, tb):
+ if tb.get_property('sensitive'):
+ tb.get_child().activate()
+
+
+ def keypress(self, w, event):
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname == 'F1':
+ self.simulate_click(self.tb_settings)
+ return True
+ if keyname == 'F2':
+ print(self.cb_server.popup())
+ return True
+ if keyname == 'F3':
+ print(self.cb_dbname.popup())
+ return True
+ if keyname == 'F4':
+ self.simulate_click(self.tb_connect)
+ return True
+ if keyname == 'F5':
+ self.simulate_click(self.tb_execute)
+ return True
+ if keyname == 'F6':
+ self.simulate_click(self.tb_begin)
+ return True
+ if keyname == 'F7':
+ self.simulate_click(self.tb_commit)
+ return True
+ if keyname == 'F8':
+ self.simulate_click(self.tb_rollback)
+ return True
+
+ return False
+
+
+ def toolbar_server_keypress(self, w, event):
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname == 'Tab':
+ self.populate_db_list()
+ self.cb_dbname.grab_focus()
+ return True
+
+
+ def on_server_changed(self, w):
+ if self.cb_server.get_active() != -1:
+ self.populate_db_list()
+
+
+ def populate_db_list(self):
+ conninfo = self.get_conninfo(True)
+ try:
+ conn = self.db.get_conn(conninfo)
+ except DatabaseError as e:
+ self.logbuf.insert(self.logbuf.get_end_iter(), 'Error:\n%s\n' % e)
+ return
+
+ curs = conn.cursor()
+ curs.execute('SELECT * FROM pg_catalog.pg_database WHERE NOT datistemplate ORDER BY 1')
+ psycopg2.extras.wait_select(conn)
+ rows = curs.fetchall()
+
+ self.db.put_conn(conninfo, conn)
+
+ for i in range(self.cb_dbname.get_model().iter_n_children(None)):
+ self.cb_dbname.remove_text(0)
+
+ for row in rows:
+ self.cb_dbname.append_text(row[0])
+
+ self.cb_dbname.set_active(0)
+
+
+ def reload_server_list(self, sel=None):
+ # clean
+ for i in range(self.cb_server.get_model().iter_n_children(None)):
+ self.cb_server.remove_text(0)
+ self.cb_server.get_child().set_text('')
+
+ try:
+ # populate
+ for server in cfg.servers.server:
+ if str(server.name):
+ title = '%s (%s)' % (str(server.name), str(server.host))
+ else:
+ title = str(server.host)
+ self.cb_server.append_text(title)
+ except AttributeError:
+ pass
+
+ if not sel is None:
+ self.cb_server.set_active(sel)
+
+
+ def settings(self, w):
+ Settings(self)
+
--- a/pgconsole/config.py Tue Aug 16 23:53:54 2011 +0200
+++ b/pgconsole/config.py Fri Aug 19 17:08:34 2011 +0200
@@ -68,6 +68,6 @@
if __name__ == '__main__':
cfg.load('../psqlconsole.xml.gz')
- print cfg.root.servers.server[0].host.text
+ print(cfg.root.servers.server[0].host.text)
cfg.save()
--- a/pgtoolkit/toolbase.py Tue Aug 16 23:53:54 2011 +0200
+++ b/pgtoolkit/toolbase.py Fri Aug 19 17:08:34 2011 +0200
@@ -1,6 +1,6 @@
import argparse
-from pgtookit import pgmanager, config
+from pgtoolkit import pgmanager, config
class ToolBase: