Merge branch 'master' of git://git.assembla.com/fpdb-sql.git

This commit is contained in:
Eric Blade 2009-12-09 21:36:34 -05:00
commit e221c9c0f6
2 changed files with 148 additions and 59 deletions

View File

@ -17,7 +17,8 @@
#agpl-3.0.txt in the docs folder of the package. #agpl-3.0.txt in the docs folder of the package.
import mmap import os
import Queue
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')
@ -29,18 +30,27 @@ import Configuration
log = Configuration.get_logger("logging.conf", "logview") log = Configuration.get_logger("logging.conf", "logview")
MAX_LINES = 100000 MAX_LINES = 100000 # max lines to display in window
EST_CHARS_PER_LINE = 150 # used to guesstimate number of lines in log file
logfile = 'logging.out' # name of logfile
class GuiLogView: class GuiLogView:
def __init__(self, config, mainwin, vbox): def __init__(self, config, mainwin, closeq):
self.config = config self.config = config
self.main_window = mainwin self.main_window = mainwin
self.vbox = vbox self.closeq = closeq
self.dia = gtk.Dialog(title="Log Messages"
,parent=None
,flags=gtk.DIALOG_DESTROY_WITH_PARENT
,buttons=(gtk.STOCK_CLOSE,gtk.RESPONSE_OK))
self.dia.set_modal(False)
self.vbox = self.dia.vbox
gtk.Widget.set_size_request(self.vbox, 700, 400); gtk.Widget.set_size_request(self.vbox, 700, 400);
self.liststore = gtk.ListStore(str, str, str, str, gobject.TYPE_BOOLEAN) # date, module, level, text self.liststore = gtk.ListStore(str, str, str, str, gobject.TYPE_BOOLEAN) # date, module, level, text
# this is how to add a filter: # this is how to add a filter:
# #
# # Creation of the filter, from the model # # Creation of the filter, from the model
@ -49,7 +59,6 @@ class GuiLogView:
# #
# # The TreeView gets the filter as model # # The TreeView gets the filter as model
# self.listview = gtk.TreeView(filter) # self.listview = gtk.TreeView(filter)
self.listview = gtk.TreeView(model=self.liststore) self.listview = gtk.TreeView(model=self.liststore)
self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE) self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE)
self.listcols = [] self.listcols = []
@ -67,6 +76,7 @@ class GuiLogView:
self.listview.show() self.listview.show()
scrolledwindow.show() scrolledwindow.show()
self.vbox.show() self.vbox.show()
self.dia.set_focus(self.listview)
col = self.addColumn("Date/Time", 0) col = self.addColumn("Date/Time", 0)
col = self.addColumn("Module", 1) col = self.addColumn("Module", 1)
@ -75,6 +85,17 @@ class GuiLogView:
self.loadLog() self.loadLog()
self.vbox.show_all() self.vbox.show_all()
self.dia.show()
self.dia.connect('response', self.dialog_response_cb)
def dialog_response_cb(self, dialog, response_id):
# this is called whether close button is pressed or window is closed
self.closeq.put(self.__class__)
dialog.destroy()
def get_dialog(self):
return self.dia
def addColumn(self, title, n): def addColumn(self, title, n):
col = gtk.TreeViewColumn(title) col = gtk.TreeViewColumn(title)
@ -92,39 +113,28 @@ class GuiLogView:
def loadLog(self): def loadLog(self):
#self.configStore = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING)
#self.configView = gtk.TreeView(self.configStore)
#self.configView.set_enable_tree_lines(True)
self.liststore.clear() self.liststore.clear()
self.listcols = [] self.listcols = []
# count number of lines in file # guesstimate number of lines in file
f = open('logging.out', "r+") if os.path.exists(logfile):
buf = mmap.mmap(f.fileno(), 0) stat_info = os.stat(logfile)
readline = buf.readline lines = stat_info.st_size / EST_CHARS_PER_LINE
lines = 0 print "logview: size =", stat_info.st_size, "lines =", lines
while readline():
lines += 1
f.close()
# set startline to line number to start display from
startline = 0 startline = 0
if lines > MAX_LINES: if lines > MAX_LINES:
# only display from startline if log file is large # only display from startline if log file is large
startline = lines - MAX_LINES startline = lines - MAX_LINES
f = open('logging.out', "r+")
buf = mmap.mmap(f.fileno(), 0)
readline = buf.readline
l = 0 l = 0
line = readline() for line in open(logfile):
while line:
# eg line: # eg line:
# 2009-12-02 15:23:21,716 - config DEBUG config logger initialised # 2009-12-02 15:23:21,716 - config DEBUG config logger initialised
l = l + 1 l = l + 1
if l > startline and len(line) > 49: if l > startline and len(line) > 49:
iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) ) iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) )
line = readline()
f.close()
def sortCols(self, col, n): def sortCols(self, col, n):
try: try:

View File

@ -18,6 +18,7 @@
import os import os
import sys import sys
import re import re
import Queue
# if path is set to use an old version of python look for a new one: # if path is set to use an old version of python look for a new one:
# (does this work in linux?) # (does this work in linux?)
@ -73,6 +74,7 @@ try:
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import pango
except: except:
print "Unable to load PYGTK modules required for GUI. Please install PyCairo, PyGObject, and PyGTK from www.pygtk.org." print "Unable to load PYGTK modules required for GUI. Please install PyCairo, PyGObject, and PyGTK from www.pygtk.org."
raw_input("Press ENTER to continue.") raw_input("Press ENTER to continue.")
@ -80,6 +82,24 @@ except:
import interlocks import interlocks
# these imports not required in this module, imported here to report version in About dialog
try:
import matplotlib
matplotlib_version = matplotlib.__version__
except:
matplotlib_version = 'not found'
try:
import numpy
numpy_version = numpy.__version__
except:
numpy_version = 'not found'
try:
import sqlite3
sqlite3_version = sqlite3.version
sqlite_version = sqlite3.sqlite_version
except:
sqlite3_version = 'not found'
sqlite_version = 'not found'
import GuiPrefs import GuiPrefs
import GuiLogView import GuiLogView
@ -112,12 +132,12 @@ class fpdb:
def add_tab(self, new_page, new_tab_name): def add_tab(self, new_page, new_tab_name):
"""adds a tab, namely creates the button and displays it and appends all the relevant arrays""" """adds a tab, namely creates the button and displays it and appends all the relevant arrays"""
for name in self.nb_tabs: #todo: check this is valid for name in self.nb_tab_names: #todo: check this is valid
if name == new_tab_name: if name == new_tab_name:
return # if tab already exists, just go to it return # if tab already exists, just go to it
used_before = False used_before = False
for i, name in enumerate(self.tab_names): #todo: check this is valid for i, name in enumerate(self.tab_names):
if name == new_tab_name: if name == new_tab_name:
used_before = True used_before = True
event_box = self.tabs[i] event_box = self.tabs[i]
@ -133,13 +153,13 @@ class fpdb:
#self.nb.append_page(new_page, gtk.Label(new_tab_name)) #self.nb.append_page(new_page, gtk.Label(new_tab_name))
self.nb.append_page(page, event_box) self.nb.append_page(page, event_box)
self.nb_tabs.append(new_tab_name) self.nb_tab_names.append(new_tab_name)
page.show() page.show()
def display_tab(self, new_tab_name): def display_tab(self, new_tab_name):
"""displays the indicated tab""" """displays the indicated tab"""
tab_no = -1 tab_no = -1
for i, name in enumerate(self.nb_tabs): for i, name in enumerate(self.nb_tab_names):
if new_tab_name == name: if new_tab_name == name:
tab_no = i tab_no = i
break break
@ -190,13 +210,13 @@ class fpdb:
(nb, text) = data (nb, text) = data
page = -1 page = -1
#print "\n remove_tab: start", text #print "\n remove_tab: start", text
for i, tab in enumerate(self.nb_tabs): for i, tab in enumerate(self.nb_tab_names):
if text == tab: if text == tab:
page = i page = i
#print " page =", page #print " page =", page
if page >= 0 and page < self.nb.get_n_pages(): if page >= 0 and page < self.nb.get_n_pages():
#print " removing page", page #print " removing page", page
del self.nb_tabs[page] del self.nb_tab_names[page]
nb.remove_page(page) nb.remove_page(page)
# Need to refresh the widget -- # Need to refresh the widget --
# This forces the widget to redraw itself. # This forces the widget to redraw itself.
@ -219,8 +239,39 @@ class fpdb:
dia.set_website("http://fpdb.sourceforge.net/") dia.set_website("http://fpdb.sourceforge.net/")
dia.set_authors("Steffen, Eratosthenes, s0rrow, EricBlade, _mt, sqlcoder, Bostik, and others") dia.set_authors("Steffen, Eratosthenes, s0rrow, EricBlade, _mt, sqlcoder, Bostik, and others")
dia.set_program_name("Free Poker Database (FPDB)") dia.set_program_name("Free Poker Database (FPDB)")
db_version = ""
#if self.db is not None:
# db_version = self.db.get_version()
nums = [ ('Operating System', os.name)
, ('Python', sys.version[0:3])
, ('GTK+', '.'.join([str(x) for x in gtk.gtk_version]))
, ('PyGTK', '.'.join([str(x) for x in gtk.pygtk_version]))
, ('matplotlib', matplotlib_version)
, ('numpy', numpy_version)
, ('sqlite3', sqlite3_version)
, ('sqlite', sqlite_version)
, ('database', self.settings['db-server'] + db_version)
]
versions = gtk.TextBuffer()
w = 20 # width used for module names and version numbers
versions.set_text( '\n'.join( [x[0].rjust(w)+' '+ x[1].ljust(w) for x in nums] ) )
view = gtk.TextView(versions)
view.set_editable(False)
view.set_justification(gtk.JUSTIFY_CENTER)
view.modify_font(pango.FontDescription('monospace 10'))
view.show()
dia.vbox.pack_end(view, True, True, 2)
l = gtk.Label('Version Information:')
l.set_alignment(0.5, 0.5)
l.show()
dia.vbox.pack_end(l, True, True, 2)
dia.run() dia.run()
dia.destroy() dia.destroy()
log.debug("Threads: ")
for t in self.threads:
log.debug("........." + str(t.__class__))
def dia_preferences(self, widget, data=None): def dia_preferences(self, widget, data=None):
dia = gtk.Dialog("Preferences", dia = gtk.Dialog("Preferences",
@ -429,28 +480,52 @@ class fpdb:
self.release_global_lock() self.release_global_lock()
def dia_logs(self, widget, data=None): def dia_logs(self, widget, data=None):
lock_set = False """opens the log viewer window"""
if self.obtain_global_lock():
lock_set = True
dia = gtk.Dialog(title="Log Messages" #lock_set = False
,parent=None #if self.obtain_global_lock():
,flags=0 # lock_set = True
,buttons=(gtk.STOCK_CLOSE,gtk.RESPONSE_OK))
logviewer = GuiLogView.GuiLogView(self.config, self.window, dia.vbox)
response = dia.run()
if response == gtk.RESPONSE_ACCEPT:
pass
dia.destroy()
if lock_set: # remove members from self.threads if close messages received
self.release_global_lock() self.process_close_messages()
viewer = None
for i, t in enumerate(self.threads):
if str(t.__class__) == 'GuiLogView.GuiLogView':
viewer = t
break
if viewer is None:
#print "creating new log viewer"
new_thread = GuiLogView.GuiLogView(self.config, self.window, self.closeq)
self.threads.append(new_thread)
else:
#print "showing existing log viewer"
viewer.get_dialog().present()
#if lock_set:
# self.release_global_lock()
def addLogText(self, text): def addLogText(self, text):
end_iter = self.logbuffer.get_end_iter() end_iter = self.logbuffer.get_end_iter()
self.logbuffer.insert(end_iter, text) self.logbuffer.insert(end_iter, text)
self.logview.scroll_to_mark(self.logbuffer.get_insert(), 0) self.logview.scroll_to_mark(self.logbuffer.get_insert(), 0)
def process_close_messages(self):
# check for close messages
try:
while True:
name = self.closeq.get(False)
for i, t in enumerate(self.threads):
if str(t.__class__) == str(name):
# thread has ended so remove from list:
del self.threads[i]
break
except Queue.Empty:
# no close messages on queue, do nothing
pass
def __calendar_dialog(self, widget, entry): def __calendar_dialog(self, widget, entry):
self.dia_confirm.set_modal(False) self.dia_confirm.set_modal(False)
d = gtk.Window(gtk.WINDOW_TOPLEVEL) d = gtk.Window(gtk.WINDOW_TOPLEVEL)
@ -632,9 +707,11 @@ class fpdb:
try: try:
self.db = Database.Database(self.config, sql = self.sql) self.db = Database.Database(self.config, sql = self.sql)
except Exceptions.FpdbMySQLAccessDenied: except Exceptions.FpdbMySQLAccessDenied:
#self.db = None
self.warning_box("MySQL Server reports: Access denied. Are your permissions set correctly?") self.warning_box("MySQL Server reports: Access denied. Are your permissions set correctly?")
exit() exit()
except Exceptions.FpdbMySQLNoDatabase: except Exceptions.FpdbMySQLNoDatabase:
#self.db = None
msg = "MySQL client reports: 2002 or 2003 error. Unable to connect - Please check that the MySQL service has been started" msg = "MySQL client reports: 2002 or 2003 error. Unable to connect - Please check that the MySQL service has been started"
self.warning_box(msg) self.warning_box(msg)
exit exit
@ -769,7 +846,6 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.add_and_display_tab(gv_tab, "Graphs") self.add_and_display_tab(gv_tab, "Graphs")
def __init__(self): def __init__(self):
self.threads = []
# no more than 1 process can this lock at a time: # no more than 1 process can this lock at a time:
self.lock = interlocks.InterProcessLock(name="fpdb_global_lock") self.lock = interlocks.InterProcessLock(name="fpdb_global_lock")
self.db = None self.db = None
@ -793,14 +869,17 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
menubar.show() menubar.show()
#done menubar #done menubar
self.threads = [] # objects used by tabs - no need for threads, gtk handles it
self.closeq = Queue.Queue(20) # used to signal ending of a thread (only logviewer for now)
self.nb = gtk.Notebook() self.nb = gtk.Notebook()
self.nb.set_show_tabs(True) self.nb.set_show_tabs(True)
self.nb.show() self.nb.show()
self.main_vbox.pack_start(self.nb, True, True, 0) self.main_vbox.pack_start(self.nb, True, True, 0)
self.pages=[] self.tabs=[] # the event_boxes forming the actual tabs
self.tabs=[] self.tab_names=[] # names of tabs used since program started, not removed if tab is closed
self.tab_names=[] self.pages=[] # the contents of the page, not removed if tab is closed
self.nb_tabs=[] self.nb_tab_names=[] # list of tab names currently displayed in notebook
self.tab_main_help(None, None) self.tab_main_help(None, None)