diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py
index 0348bc21..d40f37f9 100755
--- a/pyfpdb/Configuration.py
+++ b/pyfpdb/Configuration.py
@@ -519,6 +519,9 @@ class Config:
file = None
return file
+ def get_doc(self):
+ return self.doc
+
def get_site_node(self, site):
for site_node in self.doc.getElementsByTagName("site"):
if site_node.getAttribute("site_name") == site:
@@ -553,11 +556,9 @@ class Config:
return location_node
def save(self, file = None):
- if file is not None:
- with open(file, 'w') as f:
- self.doc.writexml(f)
- else:
- shutil.move(self.file, self.file+".backup")
+ if file is None:
+ file = self.file
+ shutil.move(file, file+".backup")
with open(file, 'w') as f:
self.doc.writexml(f)
diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py
index dbd7afe1..42cd986c 100755
--- a/pyfpdb/Database.py
+++ b/pyfpdb/Database.py
@@ -1343,7 +1343,9 @@ class Database:
q = q.replace('%s', self.sql.query['placeholder'])
- self.cursor.execute(q, (
+ c = self.connection.cursor()
+
+ c.execute(q, (
p['tableName'],
p['gameTypeId'],
p['siteHandNo'],
@@ -1374,7 +1376,7 @@ class Database:
p['street4Pot'],
p['showdownPot']
))
- return self.get_last_insert_id(self.cursor)
+ return self.get_last_insert_id(c)
# def storeHand
def storeHandsPlayers(self, hid, pids, pdata):
@@ -1393,16 +1395,39 @@ class Database:
pdata[p]['card6'],
pdata[p]['card7'],
pdata[p]['winnings'],
+ pdata[p]['rake'],
+ pdata[p]['totalProfit'],
pdata[p]['street0VPI'],
pdata[p]['street1Seen'],
pdata[p]['street2Seen'],
pdata[p]['street3Seen'],
pdata[p]['street4Seen'],
+ pdata[p]['sawShowdown'],
+ pdata[p]['wonAtSD'],
pdata[p]['street0Aggr'],
pdata[p]['street1Aggr'],
pdata[p]['street2Aggr'],
pdata[p]['street3Aggr'],
- pdata[p]['street4Aggr']
+ pdata[p]['street4Aggr'],
+ pdata[p]['street1CBChance'],
+ pdata[p]['street2CBChance'],
+ pdata[p]['street3CBChance'],
+ pdata[p]['street4CBChance'],
+ pdata[p]['street1CBDone'],
+ pdata[p]['street2CBDone'],
+ pdata[p]['street3CBDone'],
+ pdata[p]['street4CBDone'],
+ pdata[p]['wonWhenSeenStreet1'],
+ pdata[p]['street0Calls'],
+ pdata[p]['street1Calls'],
+ pdata[p]['street2Calls'],
+ pdata[p]['street3Calls'],
+ pdata[p]['street4Calls'],
+ pdata[p]['street0Bets'],
+ pdata[p]['street1Bets'],
+ pdata[p]['street2Bets'],
+ pdata[p]['street3Bets'],
+ pdata[p]['street4Bets'],
) )
q = """INSERT INTO HandsPlayers (
@@ -1418,19 +1443,46 @@ class Database:
card6,
card7,
winnings,
+ rake,
+ totalProfit,
street0VPI,
street1Seen,
street2Seen,
street3Seen,
street4Seen,
+ sawShowdown,
+ wonAtSD,
street0Aggr,
street1Aggr,
street2Aggr,
street3Aggr,
- street4Aggr
+ street4Aggr,
+ street1CBChance,
+ street2CBChance,
+ street3CBChance,
+ street4CBChance,
+ street1CBDone,
+ street2CBDone,
+ street3CBDone,
+ street4CBDone,
+ wonWhenSeenStreet1,
+ street0Calls,
+ street1Calls,
+ street2Calls,
+ street3Calls,
+ street4Calls,
+ street0Bets,
+ street1Bets,
+ street2Bets,
+ street3Bets,
+ street4Bets
)
VALUES (
- %s, %s,
+ %s, %s, %s, %s, %s,
+ %s, %s, %s, %s, %s,
+ %s, %s, %s, %s, %s,
+ %s, %s, %s, %s, %s,
+ %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s,
@@ -1440,11 +1492,8 @@ class Database:
# position,
# tourneyTypeId,
# startCards,
-# rake,
-# totalProfit,
# street0_3BChance,
# street0_3BDone,
-# sawShowdown,
# otherRaisedStreet1,
# otherRaisedStreet2,
# otherRaisedStreet3,
@@ -1453,22 +1502,12 @@ class Database:
# foldToOtherRaisedStreet2,
# foldToOtherRaisedStreet3,
# foldToOtherRaisedStreet4,
-# wonWhenSeenStreet1,
-# wonAtSD,
# stealAttemptChance,
# stealAttempted,
# foldBbToStealChance,
# foldedBbToSteal,
# foldSbToStealChance,
# foldedSbToSteal,
-# street1CBChance,
-# street1CBDone,
-# street2CBChance,
-# street2CBDone,
-# street3CBChance,
-# street3CBDone,
-# street4CBChance,
-# street4CBDone,
# foldToStreet1CBChance,
# foldToStreet1CBDone,
# foldToStreet2CBChance,
@@ -1485,21 +1524,13 @@ class Database:
# street3CheckCallRaiseDone,
# street4CheckCallRaiseChance,
# street4CheckCallRaiseDone,
-# street0Calls,
-# street1Calls,
-# street2Calls,
-# street3Calls,
-# street4Calls,
-# street0Bets,
-# street1Bets,
-# street2Bets,
-# street3Bets,
-# street4Bets
q = q.replace('%s', self.sql.query['placeholder'])
#print "DEBUG: inserts: %s" %inserts
- self.cursor.executemany(q, inserts)
+ #print "DEBUG: q: %s" % q
+ c = self.connection.cursor()
+ c.executemany(q, inserts)
def storeHudCacheNew(self, gid, pid, hc):
q = """INSERT INTO HudCache (
@@ -1641,6 +1672,15 @@ class Database:
# street4CheckCallRaiseChance,
# street4CheckCallRaiseDone)
+ def isDuplicate(self, gametypeID, siteHandNo):
+ dup = False
+ c = self.get_cursor()
+ c.execute(self.sql.query['isAlreadyInDB'], (gametypeID, siteHandNo))
+ result = c.fetchall()
+ if len(result) > 0:
+ dup = True
+ return dup
+
def getGameTypeId(self, siteid, game):
c = self.get_cursor()
#FIXME: Fixed for NL at the moment
@@ -1680,6 +1720,13 @@ class Database:
q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s"
q = q.replace('%s', self.sql.query['placeholder'])
+ #NOTE/FIXME?: MySQL has ON DUPLICATE KEY UPDATE
+ #Usage:
+ # INSERT INTO `tags` (`tag`, `count`)
+ # VALUES ($tag, 1)
+ # ON DUPLICATE KEY UPDATE `count`=`count`+1;
+
+
#print "DEBUG: name: %s site: %s" %(name, site_id)
c.execute (q, (site_id, name))
diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py
index e4d59336..c5575ddc 100644
--- a/pyfpdb/DerivedStats.py
+++ b/pyfpdb/DerivedStats.py
@@ -18,7 +18,7 @@
#fpdb modules
import Card
-DEBUG = True
+DEBUG = False
if DEBUG:
import pprint
@@ -39,12 +39,24 @@ class DerivedStats():
#Init vars that may not be used, but still need to be inserted.
# All stud street4 need this when importing holdem
self.handsplayers[player[1]]['winnings'] = 0
+ self.handsplayers[player[1]]['rake'] = 0
+ self.handsplayers[player[1]]['totalProfit'] = 0
self.handsplayers[player[1]]['street4Seen'] = False
self.handsplayers[player[1]]['street4Aggr'] = False
+ self.handsplayers[player[1]]['wonWhenSeenStreet1'] = False
+ self.handsplayers[player[1]]['sawShowdown'] = False
+ self.handsplayers[player[1]]['wonAtSD'] = False
+ for i in range(5):
+ self.handsplayers[player[1]]['street%dCalls' % i] = 0
+ self.handsplayers[player[1]]['street%dBets' % i] = 0
+ for i in range(1,5):
+ self.handsplayers[player[1]]['street%dCBChance' %i] = False
+ self.handsplayers[player[1]]['street%dCBDone' %i] = False
self.assembleHands(self.hand)
self.assembleHandsPlayers(self.hand)
+
if DEBUG:
print "Hands:"
pp.pprint(self.hands)
@@ -95,33 +107,56 @@ class DerivedStats():
#print "DEBUG: playersAtStreet 1:'%s' 2:'%s' 3:'%s' 4:'%s'" %(self.hands['playersAtStreet1'],self.hands['playersAtStreet2'],self.hands['playersAtStreet3'],self.hands['playersAtStreet4'])
self.streetXRaises(hand) # Empty function currently
- # comment TEXT,
- # commentTs DATETIME
-
def assembleHandsPlayers(self, hand):
#street0VPI/vpip already called in Hand
+ # sawShowdown is calculated in playersAtStreetX, as that calculation gives us a convenient list of names
+
#hand.players = [[seat, name, chips],[seat, name, chips]]
for player in hand.players:
self.handsplayers[player[1]]['seatNo'] = player[0]
self.handsplayers[player[1]]['startCash'] = player[2]
- # Winnings is a non-negative value of money collected from the pot, which already includes the
- # rake taken out. hand.collectees is Decimal, database requires cents
- for player in hand.collectees:
- self.handsplayers[player]['winnings'] = int(100 * hand.collectees[player])
-
for i, street in enumerate(hand.actionStreets[2:]):
self.seen(self.hand, i+1)
for i, street in enumerate(hand.actionStreets[1:]):
self.aggr(self.hand, i)
+ self.calls(self.hand, i)
+ self.bets(self.hand, i)
- default_holecards = ["Xx", "Xx", "Xx", "Xx"]
+ # Winnings is a non-negative value of money collected from the pot, which already includes the
+ # rake taken out. hand.collectees is Decimal, database requires cents
+ for player in hand.collectees:
+ self.handsplayers[player]['winnings'] = int(100 * hand.collectees[player])
+ #FIXME: This is pretty dodgy, rake = hand.rake/#collectees
+ # You can really only pay rake when you collect money, but
+ # different sites calculate rake differently.
+ # Should be fine for split-pots, but won't be accurate for multi-way pots
+ self.handsplayers[player]['rake'] = int(100* hand.rake)/len(hand.collectees)
+ if self.handsplayers[player]['street1Seen'] == True:
+ self.handsplayers[player]['wonWhenSeenStreet1'] = True
+ if self.handsplayers[player]['sawShowdown'] == True:
+ self.handsplayers[player]['wonAtSD'] = True
+
+ for player in hand.pot.committed:
+ self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player]))
+
+ self.calcCBets(hand)
+
+ #default_holecards = ["Xx", "Xx", "Xx", "Xx"]
+ #if hand.gametype['base'] == "hold":
+ # pass
+ #elif hand.gametype['base'] == "stud":
+ # pass
+ #else:
+ # # Flop hopefully...
+ # pass
for street in hand.holeStreets:
for player in hand.players:
for i in range(1,8): self.handsplayers[player[1]]['card%d' % i] = 0
- if player[1] in hand.holecards[street].keys():
+ #print "DEBUG: hand.holecards[%s]: %s" % (street, hand.holecards[street])
+ if player[1] in hand.holecards[street].keys() and hand.gametype['base'] == "hold":
self.handsplayers[player[1]]['card1'] = Card.encodeCard(hand.holecards[street][player[1]][1][0])
self.handsplayers[player[1]]['card2'] = Card.encodeCard(hand.holecards[street][player[1]][1][1])
try:
@@ -174,7 +209,11 @@ class DerivedStats():
self.hands['playersAtStreet%d' % (i+1)] = len(set.union(alliners, actors))
actions = hand.actions[hand.actionStreets[-1]]
- self.hands['playersAtShowdown'] = len(set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners))
+ 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
def streetXRaises(self, hand):
# self.actions[street] is a list of all actions in a tuple, contining the action as the second element
@@ -188,6 +227,20 @@ class DerivedStats():
for (i, street) in enumerate(hand.actionStreets[1:]):
self.hands['street%dRaises' % i] = len(filter( lambda action: action[1] in ('raises','bets'), hand.actions[street]))
+ def calcCBets(self, hand):
+ # Continuation Bet chance, action:
+ # Had the last bet (initiative) on previous street, got called, close street action
+ # Then no bets before the player with initiatives first action on current street
+ # ie. if player on street-1 had initiative
+ # and no donkbets occurred
+ for i, street in enumerate(hand.actionStreets[2:], start=1):
+ name = self.lastBetOrRaiser(hand.actionStreets[i])
+ if name:
+ chance = self.noBetsBefore(hand.actionStreets[i+1], name)
+ self.handsplayers[name]['street%dCBChance' %i] = True
+ if chance == True:
+ self.handsplayers[name]['street%dCBDone' %i] = self.betStreet(hand.actionStreets[i+1], name)
+
def seen(self, hand, i):
pas = set()
for act in hand.actions[hand.actionStreets[i+1]]:
@@ -211,6 +264,20 @@ class DerivedStats():
else:
self.handsplayers[player[1]]['street%sAggr' % i] = False
+ def calls(self, hand, i):
+ callers = []
+ for act in hand.actions[hand.actionStreets[i+1]]:
+ if act[1] in ('calls'):
+ self.handsplayers[act[0]]['street%sCalls' % i] = 1 + self.handsplayers[act[0]]['street%sCalls' % i]
+
+ # CG - I'm sure this stat is wrong
+ # Best guess is that raise = 2 bets
+ def bets(self, hand, i):
+ betters = []
+ for act in hand.actions[hand.actionStreets[i+1]]:
+ if act[1] in ('bets'):
+ self.handsplayers[act[0]]['street%sBets' % i] = 1 + self.handsplayers[act[0]]['street%sBets' % i]
+
def countPlayers(self, hand):
pass
@@ -226,3 +293,35 @@ class DerivedStats():
if f is not None and action[1] in f: continue
players.add(action[0])
return players
+
+ def noBetsBefore(self, street, player):
+ """Returns true if there were no bets before the specified players turn, false otherwise"""
+ betOrRaise = False
+ for act in self.hand.actions[street]:
+ #Must test for player first in case UTG
+ if act[0] == player:
+ betOrRaise = True
+ break
+ if act[1] in ('bets', 'raises'):
+ break
+ return betOrRaise
+
+ def betStreet(self, street, player):
+ """Returns true if player bet/raised the street as their first action"""
+ betOrRaise = False
+ for act in self.hand.actions[street]:
+ if act[0] == player and act[1] in ('bets', 'raises'):
+ betOrRaise = True
+ else:
+ break
+ return betOrRaise
+
+
+ def lastBetOrRaiser(self, street):
+ """Returns player name that placed the last bet or raise for that street.
+ None if there were no bets or raises on that street"""
+ lastbet = None
+ for act in self.hand.actions[street]:
+ if act[1] in ('bets', 'raises'):
+ lastbet = act[0]
+ return lastbet
diff --git a/pyfpdb/GuiPrefs.py b/pyfpdb/GuiPrefs.py
new file mode 100755
index 00000000..ada9cb51
--- /dev/null
+++ b/pyfpdb/GuiPrefs.py
@@ -0,0 +1,169 @@
+#!/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 xml.dom.minidom
+from xml.dom.minidom import Node
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+
+import Configuration
+
+
+class GuiPrefs:
+
+ def __init__(self, config, mainwin, dia):
+ self.config = config
+ self.main_window = mainwin
+ self.dialog = dia
+
+ self.tree_box = gtk.ScrolledWindow()
+ self.tree_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+
+ self.dialog.add(self.tree_box)
+ self.dialog.show()
+
+ self.doc = None
+ self.configStore = None
+ self.configView = None
+
+ self.fillFrames()
+
+ def fillFrames(self):
+ self.doc = self.config.get_doc()
+
+ 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)
+
+ configColumn = gtk.TreeViewColumn("Setting")
+ self.configView.append_column(configColumn)
+ cRender = gtk.CellRendererText()
+ configColumn.pack_start(cRender, True)
+ configColumn.add_attribute(cRender, 'text', 1)
+
+ configColumn = gtk.TreeViewColumn("Value")
+ self.configView.append_column(configColumn)
+ cRender = gtk.CellRendererText()
+ configColumn.pack_start(cRender, True)
+ configColumn.add_attribute(cRender, 'text', 2)
+
+ if self.doc.documentElement.tagName == 'FreePokerToolsConfig':
+ self.configStore.clear()
+ self.root = self.configStore.append( None, [self.doc.documentElement, "fpdb", None] )
+ for elem in self.doc.documentElement.childNodes:
+ iter = self.addTreeRows(self.root, elem)
+ if self.root != None:
+ self.configView.expand_row(self.configStore.get_path(self.root), False)
+ self.configView.connect("row-activated", self.rowChosen)
+ self.configView.show()
+ self.tree_box.add(self.configView)
+ self.tree_box.show()
+ self.dialog.show()
+
+ def addTreeRows(self, parent, node):
+ if (node.nodeType == node.ELEMENT_NODE):
+ (setting, value) = (node.nodeName, None)
+ elif (node.nodeType == node.TEXT_NODE):
+ # text nodes hold the whitespace (or whatever) between the xml elements, not used here
+ (setting, value) = ("TEXT: ["+node.nodeValue+"|"+node.nodeValue+"]", node.data)
+ else:
+ (setting, value) = ("?? "+node.nodeValue, "type="+str(node.nodeType))
+
+ #iter = self.configStore.append( parent, [node.nodeValue, None] )
+ iter = None
+ if node.nodeType != node.TEXT_NODE and node.nodeType != node.COMMENT_NODE:
+ iter = self.configStore.append( parent, [node, setting, value] )
+ if node.hasAttributes():
+ for i in xrange(node.attributes.length):
+ self.configStore.append( iter, [node, node.attributes.item(i).localName, node.attributes.item(i).value] )
+ if node.hasChildNodes():
+ for elem in node.childNodes:
+ self.addTreeRows(iter, elem)
+ return iter
+
+ def rowChosen(self, tview, path, something2, data=None):
+ # tview should= self.configStore
+ tmodel = tview.get_model()
+ iter = tmodel.get_iter(path)
+ if tmodel.iter_has_child(iter):
+ # toggle children display
+ if tview.row_expanded(path):
+ tview.collapse_row(tmodel.get_path(iter))
+ else:
+ tview.expand_row(tmodel.get_path(iter), False)
+ else:
+ # display value and allow edit
+ name = tmodel.get_value( iter, 1 )
+ val = tmodel.get_value( iter, 2 )
+ dia_edit = gtk.Dialog(name,
+ self.main_window,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
+ gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
+ #dia_edit.set_default_size(350, 100)
+ entry = gtk.Entry()
+ if val:
+ entry.set_text(val)
+ entry.set_width_chars(40)
+ dia_edit.vbox.pack_start(entry, False, False, 0)
+ entry.show()
+ entry.connect("activate", self.__set_entry, dia_edit)
+ response = dia_edit.run()
+ if response == gtk.RESPONSE_ACCEPT:
+ # update configStore
+ new_val = entry.get_text()
+ tmodel.set_value(iter, 2, new_val)
+ tmodel.get_value(iter, 0).setAttribute(name, new_val)
+ dia_edit.destroy()
+
+ def __set_entry(self, w, dia=None):
+ if dia is not None:
+ dia.response(gtk.RESPONSE_ACCEPT)
+
+
+
+if __name__=="__main__":
+
+ config = Configuration.Config()
+
+ win = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ win.set_title("Test Preferences Dialog")
+ win.set_border_width(1)
+ win.set_default_size(600, 500)
+ win.set_resizable(True)
+
+ dia = gtk.Dialog("Preferences",
+ win,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
+ gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT))
+ dia.set_default_size(500, 500)
+ prefs = GuiPrefs(config, win, dia.vbox)
+ response = dia.run()
+ if response == gtk.RESPONSE_ACCEPT:
+ # save updated config
+ config.save()
+ dia.destroy()
+
+
+
+
diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py
index a5ea87ec..f6fa478e 100644
--- a/pyfpdb/Hand.py
+++ b/pyfpdb/Hand.py
@@ -210,24 +210,24 @@ db: a connected fpdb_db object"""
#####
# End prep functions
#####
-
- # HandsActions - all actions for all players for all streets - self.actions
- # HudCache data can be generated from HandsActions (HandsPlayers?)
-
- # Hands - Summary information of hand indexed by handId - gameinfo
hh = self.stats.getHands()
- hh['gameTypeId'] = gtid
- # seats TINYINT NOT NULL,
- hh['seats'] = len(sqlids)
- #print hh
- handid = db.storeHand(hh)
- # HandsPlayers - ? ... Do we fix winnings?
- db.storeHandsPlayers(handid, sqlids, self.stats.getHandsPlayers())
- # Tourneys ?
- # TourneysPlayers
+ if not db.isDuplicate(gtid, hh['siteHandNo']):
+ # Hands - Summary information of hand indexed by handId - gameinfo
+ hh['gameTypeId'] = gtid
+ # seats TINYINT NOT NULL,
+ hh['seats'] = len(sqlids)
- pass
+ handid = db.storeHand(hh)
+ db.storeHandsPlayers(handid, sqlids, self.stats.getHandsPlayers())
+ # HandsActions - all actions for all players for all streets - self.actions
+ # HudCache data can be generated from HandsActions (HandsPlayers?)
+ # Tourneys ?
+ # TourneysPlayers
+ else:
+ log.info("Hand.insert(): hid #: %s is a duplicate" % hh['siteHandNo'])
+ #Raise Duplicate exception?
+ pass
def select(self, handId):
""" Function to create Hand object from database """
diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py
index a662ca79..804b3534 100644
--- a/pyfpdb/HandHistoryConverter.py
+++ b/pyfpdb/HandHistoryConverter.py
@@ -94,7 +94,7 @@ follow : whether to tail -f the input"""
else:
log.info("Created directory '%s'" % out_dir)
try:
- self.out_fh = codecs.open(self.out_path, 'w', 'cp1252')
+ self.out_fh = codecs.open(self.out_path, 'w', 'utf8')
except:
log.error("out_path %s couldn't be opened" % (self.out_path))
else:
diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py
index d0a5b815..80d3fb93 100755
--- a/pyfpdb/fpdb.py
+++ b/pyfpdb/fpdb.py
@@ -69,6 +69,7 @@ import gtk
import interlocks
+import GuiPrefs
import GuiBulkImport
import GuiPlayerStats
import GuiPositionalStats
@@ -146,6 +147,20 @@ class fpdb:
dia.run()
dia.destroy()
+ def dia_preferences(self, widget, data=None):
+ dia = gtk.Dialog("Preferences",
+ self.window,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
+ gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT))
+ dia.set_default_size(500, 500)
+ prefs = GuiPrefs.GuiPrefs(self.config, self.window, dia.vbox)
+ response = dia.run()
+ if response == gtk.RESPONSE_ACCEPT:
+ # save updated config
+ self.config.save()
+ dia.destroy()
+
def dia_create_del_database(self, widget, data=None):
self.warning_box("Unimplemented: Create/Delete Database")
self.obtain_global_lock()
@@ -350,6 +365,7 @@ class fpdb:
+
@@ -396,6 +412,7 @@ class fpdb:
('LoadProf', None, '_Load Profile (broken)', 'L', 'Load your profile', self.dia_load_profile),
('EditProf', None, '_Edit Profile (todo)', 'E', 'Edit your profile', self.dia_edit_profile),
('SaveProf', None, '_Save Profile (todo)', 'S', 'Save your profile', self.dia_save_profile),
+ ('Preferences', None, '_Preferences', None, 'Edit your preferences', self.dia_preferences),
('import', None, '_Import'),
('sethharchive', None, '_Set HandHistory Archive Directory', None, 'Set HandHistory Archive Directory', self.select_hhArchiveBase),
('bulkimp', None, '_Bulk Import', 'B', 'Bulk Import', self.tab_bulk_import),
diff --git a/pyfpdb/test_Database.py b/pyfpdb/test_Database.py
index b348f741..25bd6dbc 100644
--- a/pyfpdb/test_Database.py
+++ b/pyfpdb/test_Database.py
@@ -64,5 +64,4 @@ def testSQLiteModFunction():
assert vars[idx]%13 == int(i[0])
idx = idx+1
- assert 0 == 1
cur.execute("DROP TABLE test")