2010-07-08 20:01:03 +02:00
#!/usr/bin/env python
2010-07-04 03:05:16 +02:00
# -*- coding: utf-8 -*-
2008-08-19 00:53:25 +02:00
2011-03-10 06:16:31 +01:00
# Copyright 2008-2011, Ray E. Barker
2009-11-22 06:00:23 +01:00
#
2008-08-19 00:53:25 +02:00
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
2009-11-22 06:00:23 +01:00
#
2008-08-19 00:53:25 +02:00
# 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.
2009-11-22 06:00:23 +01:00
#
2008-08-19 00:53:25 +02:00
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
2010-07-04 03:05:16 +02:00
""" Hud_main.py
Main for FreePokerTools HUD .
"""
2011-02-06 08:57:32 +01:00
import L10n
_ = L10n . get_translation ( )
2008-08-19 00:53:25 +02:00
# Standard Library modules
import sys
2009-06-15 05:14:53 +02:00
import os
2009-08-02 00:15:04 +02:00
import traceback
2008-09-15 22:31:55 +02:00
import thread
2008-10-16 21:15:28 +02:00
import time
2008-10-18 03:28:33 +02:00
import string
2008-08-19 00:53:25 +02:00
# pyGTK modules
import gtk
import gobject
# FreePokerTools modules
import Configuration
import Database
2010-11-22 22:37:37 +01:00
import Hud
2010-12-03 00:04:13 +01:00
import Options
( options , argv ) = Options . fpdb_options ( )
2010-11-22 22:37:37 +01:00
2009-11-06 23:34:42 +01:00
# get the correct module for the current os
2010-12-18 04:16:19 +01:00
if sys . platform == ' linux2 ' :
2009-11-06 23:34:42 +01:00
import XTables as Tables
2010-12-18 04:16:19 +01:00
elif sys . platform == ' darwin ' :
import OSXTables as Tables
else : # This is bad--figure out the values for the various windows flavors
2011-03-03 03:56:30 +01:00
is_windows = True
2009-11-06 23:34:42 +01:00
import WinTables as Tables
2008-08-19 00:53:25 +02:00
2010-02-12 09:18:42 +01:00
# get config and set up logger
2010-02-20 17:24:07 +01:00
c = Configuration . Config ( file = options . config , dbname = options . dbname )
2010-02-12 09:18:42 +01:00
log = Configuration . get_logger ( " logging.conf " , " hud " , log_dir = c . dir_log , log_file = ' HUD-log.txt ' )
2010-02-01 23:31:00 +01:00
2009-02-22 00:19:49 +01:00
class HUD_main ( object ) :
""" A main() object to own both the read_stdin thread and the gui. """
# This class mainly provides state for controlling the multiple HUDs.
2010-09-27 11:08:34 +02:00
def __init__ ( self , db_name = ' fpdb ' ) :
2010-02-07 12:21:50 +01:00
self . db_name = db_name
2010-02-13 18:26:47 +01:00
self . config = c
2011-03-10 02:26:42 +01:00
log . info ( _ ( " HUD_main starting: using db name = %s " ) % ( db_name ) )
2010-02-02 22:53:03 +01:00
2010-02-07 12:21:50 +01:00
try :
2010-02-02 22:53:03 +01:00
if not options . errorsToConsole :
2010-02-20 17:24:07 +01:00
fileName = os . path . join ( self . config . dir_log , ' HUD-errors.txt ' )
2011-03-10 02:26:42 +01:00
log . info ( _ ( " Note: error output is being diverted to: " ) + fileName )
log . info ( _ ( " Any major error will be reported there _only_. " ) )
2010-02-20 17:24:07 +01:00
errorFile = open ( fileName , ' w ' , 0 )
sys . stderr = errorFile
2011-03-10 02:26:42 +01:00
log . info ( _ ( " HUD_main: starting ... \n " ) )
2010-02-02 22:53:03 +01:00
2010-01-31 12:25:24 +01:00
self . hud_dict = { }
self . hud_params = self . config . get_hud_ui_parameters ( )
2011-03-18 00:11:47 +01:00
# a thread to read stdin
2010-09-27 11:08:34 +02:00
gobject . threads_init ( ) # this is required
thread . start_new_thread ( self . read_stdin , ( ) ) # starts the thread
2010-01-31 12:25:24 +01:00
2011-03-18 00:11:47 +01:00
# a main window
2010-01-31 12:25:24 +01:00
self . main_window = gtk . Window ( )
2011-03-18 00:11:47 +01:00
if os . name == ' nt ' : # Check for admin rights, don't start auto import if we don't have them
if ( os . sys . getwindowsversion ( ) [ 0 ] > = 6 ) :
import ctypes
if not ctypes . windll . shell32 . IsUserAnAdmin ( ) :
dia = gtk . MessageDialog ( parent = self . main_window , flags = gtk . DIALOG_DESTROY_WITH_PARENT , type = gtk . MESSAGE_ERROR , buttons = ( gtk . BUTTONS_OK ) , message_format = _ ( " No admin rights for HUD " ) )
dia . format_secondary_text ( _ ( " Please right click fpdb.exe and HUD_main.exe, select properties, and set them both to run as admin. " ) + " " + _ ( " You will need to restart fpdb afterwards. " ) )
response = dia . run ( )
dia . destroy ( )
return
2010-11-28 02:35:34 +01:00
if options . minimized :
self . main_window . iconify ( )
if options . hidden :
self . main_window . hide ( )
2010-11-28 01:16:15 +01:00
if options . xloc is not None or options . yloc is not None :
if options . xloc is None :
options . xloc = 0
if options . yloc is None :
options . yloc = 0
self . main_window . move ( options . xloc , options . yloc )
2010-09-17 02:29:58 +02:00
self . main_window . connect ( " client_moved " , self . client_moved )
self . main_window . connect ( " client_resized " , self . client_resized )
self . main_window . connect ( " client_destroyed " , self . client_destroyed )
self . main_window . connect ( " game_changed " , self . game_changed )
self . main_window . connect ( " table_changed " , self . table_changed )
2010-01-31 12:25:24 +01:00
self . main_window . connect ( " destroy " , self . destroy )
self . vb = gtk . VBox ( )
2011-03-10 02:26:42 +01:00
self . label = gtk . Label ( _ ( ' Closing this window will exit from the HUD. ' ) )
2010-01-31 12:25:24 +01:00
self . vb . add ( self . label )
self . main_window . add ( self . vb )
2010-12-04 21:29:23 +01:00
self . main_window . set_title ( " HUD Main Window " )
2010-10-04 22:35:34 +02:00
cards = os . path . join ( os . getcwd ( ) , ' .. ' , ' gfx ' , ' fpdb-cards.png ' )
if os . path . exists ( cards ) :
self . main_window . set_icon_from_file ( cards )
elif os . path . exists ( ' /usr/share/pixmaps/fpdb-cards.png ' ) :
self . main_window . set_icon_from_file ( ' /usr/share/pixmaps/fpdb-cards.png ' )
else :
self . main_window . set_icon_stock ( gtk . STOCK_HOME )
2010-11-28 02:35:34 +01:00
if not options . hidden :
self . main_window . show_all ( )
2011-02-22 23:22:44 +01:00
gobject . timeout_add ( 800 , self . check_tables )
2010-11-04 13:07:17 +01:00
2010-01-31 12:25:24 +01:00
except :
2011-03-09 23:28:45 +01:00
log . exception ( _ ( " Error initializing main_window " ) )
2010-12-03 00:04:13 +01:00
gtk . main_quit ( ) # we're hosed, just terminate
2010-01-31 12:25:24 +01:00
2010-09-17 02:29:58 +02:00
def client_moved ( self , widget , hud ) :
2010-11-18 05:36:59 +01:00
hud . up_update_table_position ( )
2010-09-17 02:29:58 +02:00
def client_resized ( self , widget , hud ) :
2011-03-09 23:28:45 +01:00
#TODO Don't forget to get rid of this.
2011-03-03 03:56:30 +01:00
if not is_windows :
gigobject . idle_add ( idle_resize , hud )
2010-09-17 02:29:58 +02:00
def client_destroyed ( self , widget , hud ) : # call back for terminating the main eventloop
2010-11-22 22:37:37 +01:00
self . kill_hud ( None , hud . table . key )
2010-09-17 02:29:58 +02:00
def game_changed ( self , widget , hud ) :
2011-03-10 02:26:42 +01:00
print _ ( " hud_main: Game changed. " )
2010-09-17 02:29:58 +02:00
def table_changed ( self , widget , hud ) :
2010-11-22 22:37:37 +01:00
self . kill_hud ( None , hud . table . key )
2009-02-22 00:19:49 +01:00
2009-11-04 03:52:40 +01:00
def destroy ( self , * args ) : # call back for terminating the main eventloop
2011-03-12 21:47:14 +01:00
log . info ( _ ( " Quitting normally " ) )
2009-02-22 00:19:49 +01:00
gtk . main_quit ( )
2009-02-28 01:47:52 +01:00
def kill_hud ( self , event , table ) :
2010-12-01 07:54:42 +01:00
gobject . idle_add ( idle_kill , self , table )
2010-09-17 02:29:58 +02:00
def check_tables ( self ) :
for hud in self . hud_dict . keys ( ) :
self . hud_dict [ hud ] . table . check_table ( self . hud_dict [ hud ] )
return True
2010-12-04 21:29:23 +01:00
def create_HUD ( self , new_hand_id , table , temp_key , max , poker_game , type , stat_dict , cards ) :
2009-09-30 00:34:52 +02:00
""" type is " ring " or " tour " used to set hud_params """
2009-11-22 06:00:23 +01:00
2010-12-04 21:29:23 +01:00
self . hud_dict [ temp_key ] = Hud . Hud ( self , table , max , poker_game , self . config , self . db_connection )
self . hud_dict [ temp_key ] . table_name = temp_key
self . hud_dict [ temp_key ] . stat_dict = stat_dict
self . hud_dict [ temp_key ] . cards = cards
table . hud = self . hud_dict [ temp_key ]
2010-11-22 22:37:37 +01:00
2009-11-17 22:47:43 +01:00
# set agg_bb_mult so that aggregate_tour and aggregate_ring can be ignored,
# agg_bb_mult == 1 means no aggregation after these if statements:
2009-09-30 00:34:52 +02:00
if type == " tour " and self . hud_params [ ' aggregate_tour ' ] == False :
2010-12-04 21:29:23 +01:00
self . hud_dict [ temp_key ] . hud_params [ ' agg_bb_mult ' ] = 1
2009-09-30 00:34:52 +02:00
elif type == " ring " and self . hud_params [ ' aggregate_ring ' ] == False :
2010-12-04 21:29:23 +01:00
self . hud_dict [ temp_key ] . hud_params [ ' agg_bb_mult ' ] = 1
2009-09-30 00:34:52 +02:00
if type == " tour " and self . hud_params [ ' h_aggregate_tour ' ] == False :
2010-12-04 21:29:23 +01:00
self . hud_dict [ temp_key ] . hud_params [ ' h_agg_bb_mult ' ] = 1
2009-09-30 00:34:52 +02:00
elif type == " ring " and self . hud_params [ ' h_aggregate_ring ' ] == False :
2010-12-04 21:29:23 +01:00
self . hud_dict [ temp_key ] . hud_params [ ' h_agg_bb_mult ' ] = 1
2009-11-17 22:47:43 +01:00
# sqlcoder: I forget why these are set to true (aren't they ignored from now on?)
# but I think it's needed:
2009-11-30 03:53:15 +01:00
self . hud_params [ ' aggregate_ring ' ] = True
self . hud_params [ ' h_aggregate_ring ' ] = True
2009-11-17 22:47:43 +01:00
# so maybe the tour ones should be set as well? does this fix the bug I see mentioned?
self . hud_params [ ' aggregate_tour ' ] = True
2009-11-30 03:53:15 +01:00
self . hud_params [ ' h_aggregate_tour ' ] = True
2009-09-30 00:34:52 +02:00
2010-12-04 21:29:23 +01:00
[ aw . update_data ( new_hand_id , self . db_connection ) for aw in self . hud_dict [ temp_key ] . aux_windows ]
gobject . idle_add ( idle_create , self , new_hand_id , table , temp_key , max , poker_game , type , stat_dict , cards )
2009-11-22 06:00:23 +01:00
2009-02-26 05:35:15 +01:00
def update_HUD ( self , new_hand_id , table_name , config ) :
2009-02-22 00:19:49 +01:00
""" Update a HUD gui from inside the non-gui read_stdin thread. """
2010-12-01 07:54:42 +01:00
gobject . idle_add ( idle_update , self , new_hand_id , table_name , config )
2009-11-22 06:00:23 +01:00
2009-02-22 00:19:49 +01:00
def read_stdin ( self ) : # This is the thread function
""" Do all the non-gui heavy lifting for the HUD program. """
# This db connection is for the read_stdin thread only. It should not
# be passed to HUDs for use in the gui thread. HUD objects should not
# need their own access to the database, but should open their own
# if it is required.
2009-10-29 00:53:31 +01:00
self . db_connection = Database . Database ( self . config )
2009-11-22 06:00:23 +01:00
2009-10-29 00:53:31 +01:00
# get hero's screen names and player ids
self . hero , self . hero_ids = { } , { }
2010-02-13 18:26:47 +01:00
found = False
2009-11-24 01:34:40 +01:00
2010-09-27 11:08:34 +02:00
while 1 : # wait for a new hand number on stdin
2009-10-29 00:53:31 +01:00
new_hand_id = sys . stdin . readline ( )
new_hand_id = string . rstrip ( new_hand_id )
2011-03-10 02:26:42 +01:00
log . debug ( _ ( " Received hand no %s " ) % new_hand_id )
2009-10-29 00:53:31 +01:00
if new_hand_id == " " : # blank line means quit
self . destroy ( )
break # this thread is not always killed immediately with gtk.main_quit()
2009-11-04 03:52:40 +01:00
2010-11-22 22:37:37 +01:00
# This block cannot be hoisted outside the while loop, because it would
# cause a problem when auto importing into an empty db.
2010-12-03 00:04:13 +01:00
# FIXME: This doesn't work in the case of the player playing on 2
# sites at once (???) Eratosthenes
2010-02-13 18:26:47 +01:00
if not found :
for site in self . config . get_supported_sites ( ) :
result = self . db_connection . get_site_id ( site )
if result :
site_id = result [ 0 ] [ 0 ]
self . hero [ site_id ] = self . config . supported_sites [ site ] . screen_name
self . hero_ids [ site_id ] = self . db_connection . get_player_id ( self . config , site , self . hero [ site_id ] )
if self . hero_ids [ site_id ] is not None :
found = True
else :
self . hero_ids [ site_id ] = - 1
2009-09-26 12:30:12 +02:00
# get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed
2011-03-10 02:26:42 +01:00
log . info ( _ ( " HUD_main.read_stdin: hand processing starting ... " ) )
2009-10-29 00:53:31 +01:00
try :
2009-11-26 22:28:05 +01:00
( table_name , max , poker_game , type , site_id , site_name , num_seats , tour_number , tab_number ) = \
2009-11-04 03:52:40 +01:00
self . db_connection . get_table_info ( new_hand_id )
2010-02-20 17:24:07 +01:00
except Exception :
2011-03-10 02:26:42 +01:00
log . exception ( _ ( " db error: skipping %s " ) % new_hand_id )
2009-10-29 00:53:31 +01:00
continue
2009-09-26 12:30:12 +02:00
2009-10-29 00:53:31 +01:00
if type == " tour " : # hand is from a tournament
2010-12-01 00:33:44 +01:00
temp_key = " %s Table %s " % ( tour_number , tab_number )
2009-10-29 00:53:31 +01:00
else :
temp_key = table_name
2009-09-26 12:30:12 +02:00
# Update an existing HUD
2009-10-29 00:53:31 +01:00
if temp_key in self . hud_dict :
2009-11-22 06:00:23 +01:00
# get stats using hud's specific params and get cards
2009-11-04 03:52:40 +01:00
self . db_connection . init_hud_stat_vars ( self . hud_dict [ temp_key ] . hud_params [ ' hud_days ' ]
, self . hud_dict [ temp_key ] . hud_params [ ' h_hud_days ' ] )
2010-09-27 11:08:34 +02:00
stat_dict = self . db_connection . get_stats_from_hand ( new_hand_id , type , self . hud_dict [ temp_key ] . hud_params ,
self . hero_ids [ site_id ] , num_seats )
2010-09-17 02:29:58 +02:00
2009-11-25 19:31:01 +01:00
try :
self . hud_dict [ temp_key ] . stat_dict = stat_dict
except KeyError : # HUD instance has been killed off, key is stale
2011-03-10 02:26:42 +01:00
log . error ( _ ( ' hud_dict[ %s ] was not found \n ' ) % temp_key )
log . error ( _ ( ' will not send hand \n ' ) )
2009-11-25 19:31:01 +01:00
# Unlocks table, copied from end of function
self . db_connection . connection . rollback ( )
return
2010-12-03 00:04:13 +01:00
self . hud_dict [ temp_key ] . cards = self . get_cards ( new_hand_id )
2009-10-29 00:53:31 +01:00
[ aw . update_data ( new_hand_id , self . db_connection ) for aw in self . hud_dict [ temp_key ] . aux_windows ]
self . update_HUD ( new_hand_id , temp_key , self . config )
2009-11-22 06:00:23 +01:00
2009-09-26 12:30:12 +02:00
# Or create a new HUD
2009-10-29 00:53:31 +01:00
else :
2009-11-04 03:52:40 +01:00
# get stats using default params--also get cards
self . db_connection . init_hud_stat_vars ( self . hud_params [ ' hud_days ' ] , self . hud_params [ ' h_hud_days ' ] )
2010-09-27 11:08:34 +02:00
stat_dict = self . db_connection . get_stats_from_hand ( new_hand_id , type , self . hud_params ,
self . hero_ids [ site_id ] , num_seats )
2010-12-03 00:04:13 +01:00
cards = self . get_cards ( new_hand_id )
2010-09-27 11:08:34 +02:00
table_kwargs = dict ( table_name = table_name , tournament = tour_number , table_number = tab_number )
2010-09-17 02:29:58 +02:00
tablewindow = Tables . Table ( self . config , site_name , * * table_kwargs )
2011-03-01 18:22:48 +01:00
if tablewindow . number is None :
2009-09-26 12:30:12 +02:00
# If no client window is found on the screen, complain and continue
2009-10-29 00:53:31 +01:00
if type == " tour " :
table_name = " %s %s " % ( tour_number , tab_number )
2011-03-10 02:26:42 +01:00
log . error ( _ ( " HUD create: table name %s not found, skipping. " ) % table_name )
2009-10-29 00:53:31 +01:00
else :
2010-12-07 16:24:06 +01:00
tablewindow . key = temp_key
2009-11-06 23:34:42 +01:00
tablewindow . max = max
tablewindow . site = site_name
2009-11-25 19:31:01 +01:00
# Test that the table window still exists
if hasattr ( tablewindow , ' number ' ) :
self . create_HUD ( new_hand_id , tablewindow , temp_key , max , poker_game , type , stat_dict , cards )
else :
2010-08-13 05:32:09 +02:00
log . error ( _ ( ' Table " %s " no longer exists \n ' ) % table_name )
2010-11-27 05:13:14 +01:00
return
2009-11-25 19:31:01 +01:00
2009-10-29 00:53:31 +01:00
self . db_connection . connection . rollback ( )
2010-11-22 22:37:37 +01:00
if type == " tour " :
2010-11-27 05:13:14 +01:00
try :
self . hud_dict [ temp_key ] . table . check_table_no ( self . hud_dict [ temp_key ] )
except KeyError :
pass
2010-11-22 22:37:37 +01:00
2010-12-03 00:04:13 +01:00
def get_cards ( self , new_hand_id ) :
cards = self . db_connection . get_cards ( new_hand_id )
comm_cards = self . db_connection . get_common_cards ( new_hand_id )
if comm_cards != { } : # stud!
cards [ ' common ' ] = comm_cards [ ' common ' ]
return cards
2010-12-01 07:54:42 +01:00
######################################################################
# idle FUNCTIONS
#
# These are passed to the event loop by the non-gui thread to do
# gui things in a thread-safe way. They are passed to the event
# loop using the gobject.idle_add() function.
#
# A general rule for gtk is that only 1 thread should be messing
# with the gui.
def idle_resize ( hud ) :
gtk . gdk . threads_enter ( )
try :
[ aw . update_card_positions ( ) for aw in hud . aux_windows ]
hud . resize_windows ( )
except :
2010-12-18 21:28:01 +01:00
log . exception ( _ ( " Error resizing HUD for table: %s . " ) % hud . table . title )
2010-12-01 07:54:42 +01:00
finally :
gtk . gdk . threads_leave ( )
def idle_kill ( hud_main , table ) :
gtk . gdk . threads_enter ( )
try :
if table in hud_main . hud_dict :
hud_main . vb . remove ( hud_main . hud_dict [ table ] . tablehudlabel )
2010-12-10 19:41:04 +01:00
hud_main . hud_dict [ table ] . main_window . destroy ( )
hud_main . hud_dict [ table ] . kill ( )
2010-12-01 07:54:42 +01:00
del ( hud_main . hud_dict [ table ] )
hud_main . main_window . resize ( 1 , 1 )
except :
2010-12-18 21:28:01 +01:00
log . exception ( _ ( " Error killing HUD for table: %s . " ) % table . title )
2010-12-01 07:54:42 +01:00
finally :
gtk . gdk . threads_leave ( )
2010-12-04 21:29:23 +01:00
def idle_create ( hud_main , new_hand_id , table , temp_key , max , poker_game , type , stat_dict , cards ) :
2010-12-01 07:54:42 +01:00
gtk . gdk . threads_enter ( )
try :
2010-12-11 16:42:04 +01:00
if table . gdkhandle is not None : # on windows this should already be set
table . gdkhandle = gtk . gdk . window_foreign_new ( table . number )
2010-12-04 21:29:23 +01:00
newlabel = gtk . Label ( " %s - %s " % ( table . site , temp_key ) )
2010-12-01 07:54:42 +01:00
hud_main . vb . add ( newlabel )
newlabel . show ( )
hud_main . main_window . resize_children ( )
2010-12-04 21:29:23 +01:00
hud_main . hud_dict [ temp_key ] . tablehudlabel = newlabel
hud_main . hud_dict [ temp_key ] . create ( new_hand_id , hud_main . config , stat_dict , cards )
for m in hud_main . hud_dict [ temp_key ] . aux_windows :
2010-12-01 07:54:42 +01:00
m . create ( )
m . update_gui ( new_hand_id )
2010-12-04 21:29:23 +01:00
hud_main . hud_dict [ temp_key ] . update ( new_hand_id , hud_main . config )
hud_main . hud_dict [ temp_key ] . reposition_windows ( )
2010-12-01 07:54:42 +01:00
except :
2010-12-18 21:28:01 +01:00
log . exception ( _ ( " Error creating HUD for hand %s . " ) % new_hand_id )
2010-12-01 07:54:42 +01:00
finally :
gtk . gdk . threads_leave ( )
return False
def idle_update ( hud_main , new_hand_id , table_name , config ) :
gtk . gdk . threads_enter ( )
try :
hud_main . hud_dict [ table_name ] . update ( new_hand_id , config )
[ aw . update_gui ( new_hand_id ) for aw in hud_main . hud_dict [ table_name ] . aux_windows ]
2010-12-03 00:04:13 +01:00
except :
2010-12-18 21:28:01 +01:00
log . exception ( _ ( " Error updating HUD for hand %s . " ) % new_hand_id )
2010-12-01 07:54:42 +01:00
finally :
gtk . gdk . threads_leave ( )
return False
2008-08-19 00:53:25 +02:00
if __name__ == " __main__ " :
2008-09-15 22:31:55 +02:00
2009-02-22 00:19:49 +01:00
# start the HUD_main object
2009-06-15 05:14:53 +02:00
hm = HUD_main ( db_name = options . dbname )
2008-10-14 16:33:32 +02:00
2009-02-22 00:19:49 +01:00
# start the event loop
2008-08-19 00:53:25 +02:00
gtk . main ( )