diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..3d8ec313
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+# Variable definitions
+VERSION = 0.12
+DATE = $(shell date +%Y%m%d)
+
+all:
+ @echo "Usage:"
+ @echo " make snapshot - Tags the repository with $(VERSION)-$(DATE) and creates a tarball from that"
+
+snapshot:
+ git tag $(VERSION)-$(DATE)
+ git archive --prefix=fpdb-$(VERSION)-$(DATE)/ $(VERSION)-$(DATE) | gzip -9 > ../fpdb-$(VERSION)-$(DATE).tar.gz
diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py
index 1c44bb61..36fdd2d2 100644
--- a/pyfpdb/Database.py
+++ b/pyfpdb/Database.py
@@ -474,8 +474,9 @@ class Database:
else:
h_seats_min, h_seats_max = 0, 10
print "bad h_seats_style value:", h_seats_style
- print "opp seats style", seats_style, "hero seats style", h_seats_style
- print "opp seats:", seats_min, seats_max, " hero seats:", h_seats_min, h_seats_max
+ log.info("opp seats style %s %d %d hero seats style %s %d %d"
+ % (seats_style, seats_min, seats_max
+ ,h_seats_style, h_seats_min, h_seats_max) )
if hud_style == 'S' or h_hud_style == 'S':
self.get_stats_from_hand_session(hand, stat_dict, hero_id
diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py
index a63a3636..e4072d8a 100644
--- a/pyfpdb/DerivedStats.py
+++ b/pyfpdb/DerivedStats.py
@@ -231,8 +231,9 @@ class DerivedStats():
pas = set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners)
self.hands['playersAtShowdown'] = len(pas)
- for player in pas:
- self.handsplayers[player]['sawShowdown'] = True
+ if self.hands['playersAtShowdown'] > 1:
+ for player in pas:
+ self.handsplayers[player]['sawShowdown'] = True
def streetXRaises(self, hand):
# self.actions[street] is a list of all actions in a tuple, contining the action as the second element
diff --git a/pyfpdb/GuiLogView.py b/pyfpdb/GuiLogView.py
new file mode 100755
index 00000000..3b7b8aa6
--- /dev/null
+++ b/pyfpdb/GuiLogView.py
@@ -0,0 +1,175 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+#Copyright 2008 Carl Gherardi
+#This program is free software: you can redistribute it and/or modify
+#it under the terms of the GNU Affero General Public License as published by
+#the Free Software Foundation, version 3 of the License.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Affero General Public License
+#along with this program. If not, see .
+#In the "official" distribution you can find the license in
+#agpl-3.0.txt in the docs folder of the package.
+
+
+import mmap
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+import pango
+
+import Configuration
+
+log = Configuration.get_logger("logging.conf", "logview")
+
+MAX_LINES = 100000
+
+class GuiLogView:
+
+ def __init__(self, config, mainwin, vbox):
+ self.config = config
+ self.main_window = mainwin
+ self.vbox = vbox
+ gtk.Widget.set_size_request(self.vbox, 700, 400);
+
+ self.liststore = gtk.ListStore(str, str, str, str, gobject.TYPE_BOOLEAN) # date, module, level, text
+
+ # this is how to add a filter:
+ #
+ # # Creation of the filter, from the model
+ # filter = self.liststore.filter_new()
+ # filter.set_visible_column(1)
+ #
+ # # The TreeView gets the filter as model
+ # self.listview = gtk.TreeView(filter)
+
+ self.listview = gtk.TreeView(model=self.liststore)
+ self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE)
+ self.listcols = []
+
+ scrolledwindow = gtk.ScrolledWindow()
+ scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ scrolledwindow.add(self.listview)
+ self.vbox.pack_start(scrolledwindow, expand=True, fill=True, padding=0)
+
+ refreshbutton = gtk.Button("Refresh")
+ refreshbutton.connect("clicked", self.refresh, None)
+ self.vbox.pack_start(refreshbutton, False, False, 3)
+ refreshbutton.show()
+
+ self.listview.show()
+ scrolledwindow.show()
+ self.vbox.show()
+
+ col = self.addColumn("Date/Time", 0)
+ col = self.addColumn("Module", 1)
+ col = self.addColumn("Level", 2)
+ col = self.addColumn("Text", 3)
+
+ self.loadLog()
+ self.vbox.show_all()
+
+ def addColumn(self, title, n):
+ col = gtk.TreeViewColumn(title)
+ self.listview.append_column(col)
+ cRender = gtk.CellRendererText()
+ cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR)
+ col.pack_start(cRender, True)
+ col.add_attribute(cRender, 'text', n)
+ col.set_max_width(1000)
+ col.set_spacing(0) # no effect
+ self.listcols.append(col)
+ col.set_clickable(True)
+ col.connect("clicked", self.sortCols, n)
+ return(col)
+
+ 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.listcols = []
+
+ # count number of lines in file
+ f = open('logging.out', "r+")
+ buf = mmap.mmap(f.fileno(), 0)
+ readline = buf.readline
+ lines = 0
+ while readline():
+ lines += 1
+ f.close()
+
+ startline = 0
+ if lines > MAX_LINES:
+ # only display from startline if log file is large
+ startline = lines - MAX_LINES
+
+ f = open('logging.out', "r+")
+ buf = mmap.mmap(f.fileno(), 0)
+ readline = buf.readline
+ l = 0
+ line = readline()
+ while line:
+ # eg line:
+ # 2009-12-02 15:23:21,716 - config DEBUG config logger initialised
+ l = l + 1
+ if l > startline and len(line) > 49:
+ 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):
+ try:
+ if not col.get_sort_indicator() or col.get_sort_order() == gtk.SORT_ASCENDING:
+ col.set_sort_order(gtk.SORT_DESCENDING)
+ else:
+ col.set_sort_order(gtk.SORT_ASCENDING)
+ self.liststore.set_sort_column_id(n, col.get_sort_order())
+ #self.liststore.set_sort_func(n, self.sortnums, (n,grid))
+ for i in xrange(len(self.listcols)):
+ self.listcols[i].set_sort_indicator(False)
+ self.listcols[n].set_sort_indicator(True)
+ # use this listcols[col].set_sort_indicator(True)
+ # to turn indicator off for other cols
+ except:
+ err = traceback.extract_tb(sys.exc_info()[2])
+ print "***sortCols error: " + str(sys.exc_info()[1])
+ print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
+
+ def refresh(self, widget, data):
+ self.loadLog()
+
+
+
+if __name__=="__main__":
+
+ config = Configuration.Config()
+
+ win = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ win.set_title("Test Log Viewer")
+ win.set_border_width(1)
+ win.set_default_size(600, 500)
+ win.set_resizable(True)
+
+ dia = gtk.Dialog("Log Viewer",
+ win,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_CLOSE, gtk.RESPONSE_OK))
+ dia.set_default_size(500, 500)
+ log = GuiLogView(config, win, dia.vbox)
+ response = dia.run()
+ if response == gtk.RESPONSE_ACCEPT:
+ pass
+ dia.destroy()
+
+
+
+
diff --git a/pyfpdb/HUD_config.test.xml b/pyfpdb/HUD_config.test.xml
index 52905a70..1a5f77fa 100644
--- a/pyfpdb/HUD_config.test.xml
+++ b/pyfpdb/HUD_config.test.xml
@@ -574,7 +574,7 @@ Left-Drag to Move"
-
+
diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py
index c3599a3b..62025018 100755
--- a/pyfpdb/HUD_main.py
+++ b/pyfpdb/HUD_main.py
@@ -162,10 +162,10 @@ class HUD_main(object):
# function idle_func() to be run by the gui thread, at its leisure.
def idle_func():
gtk.gdk.threads_enter()
- self.hud_dict[table_name].update(new_hand_id, config)
+ try:
+ self.hud_dict[table_name].update(new_hand_id, config)
# The HUD could get destroyed in the above call ^^, which leaves us with a KeyError here vv
# if we ever get an error we need to expect ^^ then we need to handle it vv - Eric
- try:
[aw.update_gui(new_hand_id) for aw in self.hud_dict[table_name].aux_windows]
except KeyError:
pass
diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py
index efa9c0b6..9ff78249 100644
--- a/pyfpdb/Hand.py
+++ b/pyfpdb/Hand.py
@@ -54,6 +54,7 @@ class Hand(object):
self.starttime = 0
self.handText = handText
self.handid = 0
+ self.dbid_hands = 0
self.tablename = ""
self.hero = ""
self.maxseats = None
@@ -218,8 +219,8 @@ db: a connected fpdb_db object"""
# seats TINYINT NOT NULL,
hh['seats'] = len(sqlids)
- handid = db.storeHand(hh)
- db.storeHandsPlayers(handid, sqlids, self.stats.getHandsPlayers())
+ self.dbid_hands = db.storeHand(hh)
+ db.storeHandsPlayers(self.dbid_hands, sqlids, self.stats.getHandsPlayers())
# HandsActions - all actions for all players for all streets - self.actions
# HudCache data can be generated from HandsActions (HandsPlayers?)
# Tourneys ?
diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py
index eb9296ef..5a0d1965 100644
--- a/pyfpdb/SQL.py
+++ b/pyfpdb/SQL.py
@@ -1317,6 +1317,7 @@ class Sql:
1.25 would be a config value so user could change it)
*/
GROUP BY hc.PlayerId, hp.seatNo, p.name
+ ORDER BY hc.PlayerId, hp.seatNo, p.name
"""
# same as above except stats are aggregated for all blind/limit levels
@@ -1418,6 +1419,7 @@ class Sql:
)
)
GROUP BY hc.PlayerId, p.name
+ ORDER BY hc.PlayerId, p.name
"""
# NOTES on above cursor:
# - Do NOT include %s inside query in a comment - the db api thinks
diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py
index f6ad7e3f..bfea2132 100755
--- a/pyfpdb/fpdb.py
+++ b/pyfpdb/fpdb.py
@@ -66,7 +66,8 @@ if not options.errorsToConsole:
errorFile = open('fpdb-error-log.txt', 'w', 0)
sys.stderr = errorFile
-import logging
+#import logging
+import logging, logging.config
try:
import pygtk
@@ -81,6 +82,7 @@ import interlocks
import GuiPrefs
+import GuiLogView
import GuiBulkImport
import GuiPlayerStats
import GuiPositionalStats
@@ -96,6 +98,8 @@ import Exceptions
VERSION = "0.12"
+log = Configuration.get_logger("logging.conf", "fpdb")
+
class fpdb:
def tab_clicked(self, widget, tab_name):
"""called when a tab button is clicked to activate that tab"""
@@ -424,6 +428,29 @@ class fpdb:
self.release_global_lock()
+ def dia_logs(self, widget, data=None):
+ lock_set = False
+ if self.obtain_global_lock():
+ lock_set = True
+
+ dia = gtk.Dialog(title="Log Messages"
+ ,parent=None
+ ,flags=0
+ ,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:
+ self.release_global_lock()
+
+ def addLogText(self, text):
+ end_iter = self.logbuffer.get_end_iter()
+ self.logbuffer.insert(end_iter, text)
+ self.logview.scroll_to_mark(self.logbuffer.get_insert(), 0)
+
def __calendar_dialog(self, widget, entry):
self.dia_confirm.set_modal(False)
d = gtk.Window(gtk.WINDOW_TOPLEVEL)
@@ -526,6 +553,7 @@ class fpdb: