Merge branch 'master' of git://git.assembla.com/fpdboz
This commit is contained in:
		
						commit
						c02e6365e7
					
				
							
								
								
									
										
											BIN
										
									
								
								gfx/fpdb-cards.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gfx/fpdb-cards.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										92
									
								
								gfx/img-PokerStars-Small.xpm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								gfx/img-PokerStars-Small.xpm
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | |||
| /* XPM */ | ||||
| /* C:\Program Files\PokerStars\PokerStarsUpdate.exe */ | ||||
| static char *icon[] = { | ||||
| "48 48 40 2", | ||||
| "01 c #800000", | ||||
| "08 c #C0DCC0", | ||||
| "4C c #7F1F00", | ||||
| "6C c #AA0000", | ||||
| "6D c #AA0055", | ||||
| "70 c #AA1F00", | ||||
| "90 c #D40000", | ||||
| "91 c #D40055", | ||||
| "94 c #D41F00", | ||||
| "95 c #D41F55", | ||||
| "99 c #D43F55", | ||||
| "9D c #D45F55", | ||||
| "9E c #D45FAA", | ||||
| "A1 c #D47F55", | ||||
| "A2 c #D47FAA", | ||||
| "A5 c #D49F55", | ||||
| "A6 c #D49FAA", | ||||
| "AA c #D4BFAA", | ||||
| "AE c #D4DFAA", | ||||
| "AF c #D4DFFF", | ||||
| "B4 c #FF0055", | ||||
| "B6 c #FF1F00", | ||||
| "B7 c #FF1F55", | ||||
| "BA c #FF3F00", | ||||
| "BB c #FF3F55", | ||||
| "BE c #FF5F00", | ||||
| "BF c #FF5F55", | ||||
| "C3 c #FF7F55", | ||||
| "C4 c #FF7FAA", | ||||
| "C7 c #FF9F55", | ||||
| "C8 c #FF9FAA", | ||||
| "CC c #FFBFAA", | ||||
| "CD c #FFBFFF", | ||||
| "D0 c #FFDFAA", | ||||
| "D1 c #FFDFFF", | ||||
| "D5 c #FFCCFF", | ||||
| "F6 c #FFFBF0", | ||||
| "F9 c #FF0000", | ||||
| "FF c #FFFFFF", | ||||
| "   c None", | ||||
| "707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", | ||||
| "6CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAAD1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6949DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6BFBBF999F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "6CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A6A2C7B6F9F99DD1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A2C8CCBFB6B4F99099F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6C8CCC3BEB7F9F9F99099F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2C8D0C7BFBBB6F9B4F9F99099F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "6CFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A6AAD0C8C3C3BBF9F9F9F9B4F99099D1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFA6C8D0CCC7C3BFBAB6B4F9F9F99090909DF6FFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFA2CCF6CCC8C3BFBEBBF9F9F9B4F9F9B4909099F6FFFFFFFFFFFFFFFFFFFFFFFFFF6C", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFA6CCD1CCC7C3C3BFBAB6B7F9F9F9B490F990906C99FFFFFFD1FFFFFFD1FFFFFFD1FF70", | ||||
| "6CFFFFFFFFFFFFFFFFFFFFFFAAC8F6CCC7C8C3BFBFBFB6C4B7F9F9F9F9F99190906C9DFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFD1FFFFFFD1FFFFFFAAC8F6CCCCC8C3C3C3BEBBB6F6BFF9B4F9B490F99091906CA2FFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFD1A6F6CCCCC7C7C3C3BFBBBABFFFC8F9F9F990F9909090906C90AAFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFF6A6D0D1CCC8C7C3C3BFBEBFB6CCFFF6F9F9F9B4F9B49090906C6C95F6FFFFFFFFFFFFFFFFFF6C", | ||||
| "6CFFFFFFFFFFFFFFFFAACCF6CCCCC7C4C3BFBEBBBABBD1FFFFBFF9F9F990F9F99190956C6C99FFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFD1C8F6CCCCC8C7C7C8C7C8C7C3C8F6FFF6CDBFBBBFBBBFBF9090906C6C6CA6FFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFAAF6D0CCC8C7C3C4D0FFFFFFFFF6F6FFFFF6FFFFFFFFD199F9909090706C99F6FFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFD5CCD1CCCCC7C3C3C3BFC8F6FFFFFFFFFFFFFFFFFFFFC895F990B490916C016CA2FFFFFFFFFFFFFF6C", | ||||
| "6CFFFFFFFFFFF6AAD1D0CCC7C8C3C3C3BFBEBFD1FFFFFFFFFFFFFFFFA1F9F990F9909090906C0170F6FFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFD1CCD0CCC8C8C3C3BFBFBFBABBBACCFFFFFFFFFFD1BBF9F990B490B490906D6C6C6CA6FFFFFFFFFFFF70", | ||||
| "70FFFFFFFFF6AACCD1CCC7C7C3C3BFBEBFBABABBD1FFFFFFFFFFF699F990B4F990F99090906C700199FFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFA6D0CCC8C7C3C3BFBFBFBABBB6BFF6FFFFFFFFFFFFC8F9F990F99091F99190906C0194D1FFFFFFFFFF6C", | ||||
| "6CFFFFFFFFF6C8CCCCC7C4C3BFBFBEBFBABBB6C8FFFFCCBBC4FFFFD091F9F991F9F990F9906C6D016CAAFFFFFFFFFF70", | ||||
| "70FFFFFFF6D5A5CCC8C7C3C3BFBEBBBABBBAB6F6F6C4F9F9F9BBD1FFBBF990F9F991F99091906C016CA2FFFFFFFFFF70", | ||||
| "70FFFFFFFFAEC4C7C7C3BFBFBEBFBABBB6B6BBD1BBF9F9F9F9F9B6CCC8F9B4F990F990909090706C6CA2F6FFFFFFFF70", | ||||
| "70FFFFFFFFCCC3C8C3C3BFBEBBBABBBAB6B7BBB6F9F9F9B4F9F9F9B4BBB690F9B490B49090916C016CA1FFFFFFFFFF6C", | ||||
| "6CFFFFFFFFD19DC3BFBFBFBBBABBB6B7B6F9F9F9F9B4F9F9F9B4F9F9F9B4F9F9F9F990B4906C6C016CC8FFFFFFFFFF70", | ||||
| "70FFFFFFFFF69DBEBFBEBABABBB6B6B6F9F9F9B4F990F9B4F9F9F9F9F9F9F991F990F99090706C016CAAFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFA2B6BBBAB7B6B6B6B4F9B4F991909090F9F9F990B4F9B4F9F9F9F9B49090906D6C0199FFFFFFFFFFFF70", | ||||
| "70FFFFFFFFF6F694F9B6B6B4F9F9F9F990F9909090C8A2F999CC95F9F9F9B4F9909090916C6C0190A6FFFFFFFFFFFF6C", | ||||
| "6CFFFFFFFFFFFFCC91F990F9B4F991F991906C909DFFCCF9BFFFCCF9F9F990F9F991906C70016CA2FFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFC895909090909090906C909EFFFFA2F995FFFFA6B790F99190906C6C6C6CC4F6F6FFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFAEBF9590906C906C99C8FFF6FFBFB69008FFFFF69DB7906C6C6C9499D5F6F6FFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFD0A6A2C3A6CCFFFFFFFF08BBF990A2F6FFFFFFF6CCC8C8CCAFFFF6FFFFFFFFFFFFFFFFFF6C", | ||||
| "6CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6BFF99095F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D1A1BFF9906CA6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2C3BBF9F96C95F6F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6A1C3B6F9B4906C99FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", | ||||
| "6CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAAC3C3BAB4F9F990906C9DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD19DBBBBB6F9F9F990F990909099AAFFFFFFFFFFFFFFFFFFF6FFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A2A1BF9D9EBFA2BFA2BFA29DA2BFA2CCFFFFFFFFF6FFFFFFFFFFFFFFFFFFFF70", | ||||
| "70FFFFFFFFFFFFFFFFFFFFFFFFFFFFF6FFFFFFFFFFFFFFFFFFFFFFFFF6FFF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", | ||||
| "6CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70", | ||||
| "704C706C7001706C7001706C70706C7070707070707070706C7070707070704C707001707001706C704C6C7070017070"}; | ||||
|  | @ -1,3 +1,9 @@ | |||
| free-poker-tools (0.12-1) unstable; urgency=low | ||||
| 
 | ||||
|   * New release | ||||
| 
 | ||||
|  -- Mika Bostrom <bostik+fpdb@bostik.iki.fi>  Mon, 26 Oct 2009 17:49:07 +0200 | ||||
| 
 | ||||
| free-poker-tools (0.11.3+git20091023) unstable; urgency=low | ||||
| 
 | ||||
|   * Snapshot release | ||||
|  |  | |||
|  | @ -3,3 +3,4 @@ | |||
| # When installed into .../fpdb/ the script gets mode 644 | ||||
| # Note: "dh_fixperms -Xfpdb.py" did not work, hence this hack | ||||
| chmod 755 /usr/bin/fpdb | ||||
| chmod 755 /usr/share/pyshared/fpdb/HUD_main.py | ||||
|  |  | |||
|  | @ -132,8 +132,8 @@ class Site: | |||
| 
 | ||||
|         if self.use_frames == "": self.use_frames = False | ||||
|         if self.font       == "": self.font = "Sans"  | ||||
|         if self.hudbgcolor == "": self.hudbgcolor = "000000" | ||||
|         if self.hudfgcolor == "": self.hudfgcolor = "FFFFFF" | ||||
|         if self.hudbgcolor == "": self.hudbgcolor = "#000000" | ||||
|         if self.hudfgcolor == "": self.hudfgcolor = "#FFFFFF" | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         temp = "Site = " + self.site_name + "\n" | ||||
|  |  | |||
|  | @ -1145,6 +1145,7 @@ class Database: | |||
|         c.execute("INSERT INTO Sites (name,currency) VALUES ('Betfair', 'USD')") | ||||
|         c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')") | ||||
|         c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')") | ||||
|         c.execute("INSERT INTO Sites (name,currency) VALUES ('Partouche', 'EUR')") | ||||
|         if self.backend == self.SQLITE: | ||||
|             c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") | ||||
|         elif self.backend == self.PGSQL: | ||||
|  | @ -1264,63 +1265,6 @@ class Database: | |||
|             print "Error during fdb.lock_for_insert:", str(sys.exc_value) | ||||
|     #end def lock_for_insert | ||||
| 
 | ||||
|     def getGameTypeId(self, siteid, game): | ||||
|         c = self.get_cursor() | ||||
|         #FIXME: Fixed for NL at the moment | ||||
|         c.execute(self.sql.query['getGametypeNL'], (siteid, game['type'], game['category'], game['limitType'],  | ||||
|                         int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100))) | ||||
|         tmp = c.fetchone() | ||||
|         if (tmp == None): | ||||
|             hilo = "h" | ||||
|             if game['category'] in ['studhilo', 'omahahilo']: | ||||
|                 hilo = "s" | ||||
|             elif game['category'] in ['razz','27_3draw','badugi']: | ||||
|                 hilo = "l" | ||||
|             tmp  = self.insertGameTypes( (siteid, game['type'], game['base'], game['category'], game['limitType'], hilo, | ||||
|                                     int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100), 0, 0) ) | ||||
|         return tmp[0] | ||||
| 
 | ||||
|     def getSqlPlayerIDs(self, pnames, siteid): | ||||
|         result = {} | ||||
|         if(self.pcache == None): | ||||
|             self.pcache = LambdaDict(lambda  key:self.insertPlayer(key, siteid)) | ||||
|   | ||||
|         for player in pnames: | ||||
|             result[player] = self.pcache[player] | ||||
|             # NOTE: Using the LambdaDict does the same thing as: | ||||
|             #if player in self.pcache: | ||||
|             #    #print "DEBUG: cachehit" | ||||
|             #    pass | ||||
|             #else: | ||||
|             #    self.pcache[player] = self.insertPlayer(player, siteid) | ||||
|             #result[player] = self.pcache[player] | ||||
| 
 | ||||
|         return result | ||||
| 
 | ||||
|     def insertPlayer(self, name, site_id): | ||||
|         result = None | ||||
|         c = self.get_cursor() | ||||
|         q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s" | ||||
|         q = q.replace('%s', self.sql.query['placeholder']) | ||||
| 
 | ||||
|         #print "DEBUG: name: %s site: %s" %(name, site_id) | ||||
| 
 | ||||
|         c.execute (q, (site_id, name)) | ||||
| 
 | ||||
|         tmp = c.fetchone() | ||||
|         if (tmp == None): #new player | ||||
|             c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)".replace('%s',self.sql.query['placeholder']) | ||||
|                       ,(name, site_id)) | ||||
|             #Get last id might be faster here. | ||||
|             #c.execute ("SELECT id FROM Players WHERE name=%s", (name,)) | ||||
|             tmp = [self.get_last_insert_id(c)] | ||||
|         return tmp[0] | ||||
| 
 | ||||
|     def insertGameTypes(self, row): | ||||
|         c = self.get_cursor() | ||||
|         c.execute( self.sql.query['insertGameTypes'], row ) | ||||
|         return [self.get_last_insert_id(c)] | ||||
| 
 | ||||
|     def store_the_hand(self, h): | ||||
|         """Take a HandToWrite object and store it in the db""" | ||||
| 
 | ||||
|  | @ -1668,6 +1612,64 @@ class Database: | |||
| #            street4CheckCallRaiseChance, | ||||
| #            street4CheckCallRaiseDone) | ||||
| 
 | ||||
|     def getGameTypeId(self, siteid, game): | ||||
|         c = self.get_cursor() | ||||
|         #FIXME: Fixed for NL at the moment | ||||
|         c.execute(self.sql.query['getGametypeNL'], (siteid, game['type'], game['category'], game['limitType'],  | ||||
|                         int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100))) | ||||
|         tmp = c.fetchone() | ||||
|         if (tmp == None): | ||||
|             hilo = "h" | ||||
|             if game['category'] in ['studhilo', 'omahahilo']: | ||||
|                 hilo = "s" | ||||
|             elif game['category'] in ['razz','27_3draw','badugi']: | ||||
|                 hilo = "l" | ||||
|             tmp  = self.insertGameTypes( (siteid, game['type'], game['base'], game['category'], game['limitType'], hilo, | ||||
|                                     int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100), 0, 0) ) | ||||
|         return tmp[0] | ||||
| 
 | ||||
|     def getSqlPlayerIDs(self, pnames, siteid): | ||||
|         result = {} | ||||
|         if(self.pcache == None): | ||||
|             self.pcache = LambdaDict(lambda  key:self.insertPlayer(key, siteid)) | ||||
|   | ||||
|         for player in pnames: | ||||
|             result[player] = self.pcache[player] | ||||
|             # NOTE: Using the LambdaDict does the same thing as: | ||||
|             #if player in self.pcache: | ||||
|             #    #print "DEBUG: cachehit" | ||||
|             #    pass | ||||
|             #else: | ||||
|             #    self.pcache[player] = self.insertPlayer(player, siteid) | ||||
|             #result[player] = self.pcache[player] | ||||
| 
 | ||||
|         return result | ||||
| 
 | ||||
|     def insertPlayer(self, name, site_id): | ||||
|         result = None | ||||
|         c = self.get_cursor() | ||||
|         q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s" | ||||
|         q = q.replace('%s', self.sql.query['placeholder']) | ||||
| 
 | ||||
|         #print "DEBUG: name: %s site: %s" %(name, site_id) | ||||
| 
 | ||||
|         c.execute (q, (site_id, name)) | ||||
| 
 | ||||
|         tmp = c.fetchone() | ||||
|         if (tmp == None): #new player | ||||
|             c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)".replace('%s',self.sql.query['placeholder']) | ||||
|                       ,(name, site_id)) | ||||
|             #Get last id might be faster here. | ||||
|             #c.execute ("SELECT id FROM Players WHERE name=%s", (name,)) | ||||
|             tmp = [self.get_last_insert_id(c)] | ||||
|         return tmp[0] | ||||
| 
 | ||||
|     def insertGameTypes(self, row): | ||||
|         c = self.get_cursor() | ||||
|         c.execute( self.sql.query['insertGameTypes'], row ) | ||||
|         return [self.get_last_insert_id(c)] | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| ################################# | ||||
| # Finish of NEWIMPORT CODE | ||||
|  |  | |||
							
								
								
									
										562
									
								
								pyfpdb/DatabaseManager.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										562
									
								
								pyfpdb/DatabaseManager.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,562 @@ | |||
| 
 | ||||
| import os | ||||
| import pygtk | ||||
| pygtk.require('2.0') | ||||
| import gtk | ||||
| 
 | ||||
| #******************************************************************************************************* | ||||
| class DatabaseManager(object): | ||||
|     DatabaseTypes = {} | ||||
|      | ||||
|     @classmethod | ||||
|     def from_fpdb(klass, data, defaultDatabaseType=None): | ||||
|         #TODO: parse whatever data is | ||||
|         #TODO: sort out unsupported databases passed by user and log | ||||
|         databases = ( | ||||
|                 DatabaseTypeSqLite(name='myDb'), | ||||
|                 DatabaseTypeSqLite(name='myDb2'), | ||||
|                  | ||||
|                 ) | ||||
|         return klass(databases=databases, defaultDatabaseType=defaultDatabaseType) | ||||
|      | ||||
|      | ||||
|     def __init__(self, databases=None, defaultDatabaseType=None): | ||||
|         self._defaultDatabaseType = defaultDatabaseType | ||||
|         self._databases = [] if databases is None else list(databases) | ||||
|     def __iter__(self): | ||||
|         return iter(self._databases) | ||||
|     def set_default_database_type(self, databaseType): | ||||
|         self._defaultDatabaseType = defaultDatabaseType | ||||
|     def get_default_database_type(self): | ||||
|         return self._defaultDatabaseType | ||||
|     def database_from_id(self, idDatabase): | ||||
|         for database in self._databases: | ||||
|             if idDatabase == id(database): | ||||
|                 return database | ||||
|     def database_id(self, database): | ||||
|         return id(database) | ||||
|     def add_database(self, database): | ||||
|         if database in self._databases: | ||||
|             raise ValueError('database already registered') | ||||
|         self._databases.append(database) | ||||
|     def remove_database(self, database): | ||||
|         self._databases.remove(database) | ||||
|     def init_database(self, database): | ||||
|         pass | ||||
| 
 | ||||
| class DatabaseTypeMeta(type): | ||||
|     def __new__(klass, name, bases, kws): | ||||
|         newKlass = type.__new__(klass, name, bases, kws) | ||||
|         if newKlass.Type is not None: | ||||
|             if newKlass.Type in DatabaseManager.DatabaseTypes: | ||||
|                 raise ValueError('data base type already registered for: %s' % newKlass.Type) | ||||
|             DatabaseManager.DatabaseTypes[newKlass.Type] = newKlass | ||||
|         return newKlass | ||||
| 
 | ||||
| class DatabaseTypeBase(object): | ||||
|     __metaclass__ = DatabaseTypeMeta | ||||
|     Type = None | ||||
|     Params = () | ||||
| 
 | ||||
| class DatabaseTypePostgres(DatabaseTypeBase): | ||||
|     Type = 'postgres' | ||||
|     @classmethod | ||||
|     def display_name(klass): | ||||
|         return 'Postgres' | ||||
|     def __init__(self, name='', host='localhost', port=5432, user='postgres', password='', database='fpdb'): | ||||
|         self.name = name | ||||
|         self.host = host | ||||
|         self.port = port | ||||
|         self.user = user | ||||
|         self.password = password | ||||
|         self.database = database | ||||
| 
 | ||||
| class DatabaseTypeMysql(DatabaseTypeBase): | ||||
|     Type = 'mysql' | ||||
|     @classmethod | ||||
|     def display_name(klass): | ||||
|         return 'MySql' | ||||
|     def __init__(self, name='', host='localhost', port=3306, user='root', password='', database='fpdb'): | ||||
|         self.name = name | ||||
|         self.host = host | ||||
|         self.port = port | ||||
|         self.user = user | ||||
|         self.password = password | ||||
|         self.database = database | ||||
| 
 | ||||
| class DatabaseTypeSqLite(DatabaseTypeBase): | ||||
|     Type = 'sqlite' | ||||
|     @classmethod | ||||
|     def display_name(klass): | ||||
|         return 'SqLite' | ||||
|     def __init__(self, name='', host='', file='', database='fpdb'): | ||||
|         self.name = name | ||||
|         self.file = file | ||||
|         self.database = database | ||||
| 
 | ||||
| #TODO: how do we want to handle unsupported database types? | ||||
| # ..uncomment to remove unsupported database types | ||||
| #try: import psycopg2 | ||||
| #except ImportError: del DatabaseManager.DatabaseTypes['postgres'] | ||||
| #try: import MySQLdb | ||||
| #except ImportError: del DatabaseManager.DatabaseTypes['mysql'] | ||||
| #try: import sqlite3 | ||||
| #except ImportError: del DatabaseManager.DatabaseTypes['sqlite'] | ||||
| 
 | ||||
| #*************************************************************************************************************************** | ||||
| #TODO: derrive from gtk.VBox? | ||||
| class WidgetDatabaseProperties(gtk.VBox): | ||||
|          | ||||
|     ModeNew = 0 | ||||
|     ModeEdit = 1 | ||||
|     ModeAdd = 2 | ||||
|          | ||||
|     class SqLiteFileChooserButton(gtk.HBox): | ||||
|         #NOTE: for some weird reason it is impossible to let the user choose a non exiting filename with gtk.FileChooserButton, so impl our own on the fly | ||||
|         def __init__(self, widgetDatabaseProperties, parentWidget): | ||||
|             gtk.HBox.__init__(self) | ||||
|             self.set_homogeneous(False) | ||||
|              | ||||
|             self.parentWidget = parentWidget | ||||
|             self.widgetDatabaseProperties = widgetDatabaseProperties | ||||
|             self.entry = gtk.Entry() | ||||
|             self.button = gtk.Button('...') | ||||
|             self.button.connect('clicked', self.on_button_clicked) | ||||
|              | ||||
|             # layout widgets | ||||
|             self.pack_start(self.entry, True, True) | ||||
|             self.pack_start(self.button, False, False) | ||||
|              | ||||
|         def get_filename(self): | ||||
|             return self.entry.get_text() | ||||
|              | ||||
|         def set_filename(self, name): | ||||
|             self.entry.set_text(name) | ||||
|              | ||||
|         def on_button_clicked(self, button): | ||||
|             if self.widgetDatabaseProperties.mode == WidgetDatabaseProperties.ModeAdd: | ||||
|                 action = gtk.FILE_CHOOSER_ACTION_OPEN | ||||
|             elif self.widgetDatabaseProperties.mode == WidgetDatabaseProperties.ModeNew: | ||||
|                 action = gtk.FILE_CHOOSER_ACTION_SAVE | ||||
|             else: | ||||
|                 raise ValueError('unsupported dialog mode') | ||||
|             dlg = gtk.FileChooserDialog( | ||||
|                     title='Choose an exiting database file or type in name of a new one',  | ||||
|                     parent=self.parentWidget,  | ||||
|                     action=action,  | ||||
|                     buttons=( | ||||
|                             gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, | ||||
|                             gtk.STOCK_OK, gtk.RESPONSE_OK, | ||||
|                             ),  | ||||
|                     backend=None | ||||
|                     ) | ||||
|             dlg.set_default_response(gtk.RESPONSE_OK) | ||||
|             dlg.set_do_overwrite_confirmation(True) | ||||
|             if dlg.run() == gtk.RESPONSE_OK: | ||||
|                 fileName = dlg.get_filename() | ||||
|                 self.set_filename(fileName) | ||||
|             dlg.destroy() | ||||
|              | ||||
|      | ||||
|      | ||||
|     class FieldWidget(object): | ||||
|         def __init__(self, text='', attrDatabase='', widget=None, attrGet=None, attrSet=None, defaultValue=None, canEdit=False, tooltip=''): | ||||
|             """ | ||||
|             @param canEdit: True if the user can edit the attr in edit mode, False otherwise | ||||
|             """ | ||||
|             self._label = gtk.Label(text) | ||||
|             self._attrDatabase = attrDatabase | ||||
|             self._widget = widget | ||||
|             self._defaultValue = defaultValue | ||||
|             self._attrGetter=None,  | ||||
|             self._attrGet = attrGet  | ||||
|             self._attrSet = attrSet  | ||||
|             self._canEdit = canEdit | ||||
|              | ||||
|             self._label.set_tooltip_text(tooltip) | ||||
|             self._widget.set_tooltip_text(tooltip) | ||||
|                      | ||||
|         def widget(self):  | ||||
|             return self._widget | ||||
|         def label(self): | ||||
|             return self._label | ||||
|         def is_sensitive(self, database): | ||||
|             return hasattr(database, self._attrDatabase) | ||||
|         def can_edit(self): | ||||
|             return self._canEdit | ||||
|         def set_sensitive(self, flag): | ||||
|             self._label.set_sensitive(flag) | ||||
|             self._widget.set_sensitive(flag) | ||||
|         def value_from_database(self, database): | ||||
|             getattr(self._widget, self._attrSet)( getattr(database, self._attrDatabase) ) | ||||
|         def value_to_database(self, database): | ||||
|             setattr(database, self._attrDatabase, getattr(self._widget, self._attrGet)() ) | ||||
|         def reset_value(self): | ||||
|             getattr(self._widget, self._attrSet)(self._defaultValue) | ||||
|          | ||||
|     def __init__(self, databaseManager, database, mode=ModeEdit, parentWidget=None): | ||||
|             gtk.VBox.__init__(self) | ||||
|                          | ||||
|             self.databaseManager = databaseManager | ||||
|             self.database = database | ||||
|             self.mode = mode | ||||
|             self.parentWidget = parentWidget | ||||
|             self.fieldWidgets = ( | ||||
|                         self.FieldWidget( | ||||
|                                 text='Name:', | ||||
|                                 attrDatabase='name',  | ||||
|                                 widget=gtk.Entry(), | ||||
|                                 defaultValue='', | ||||
|                                 attrGet='get_text',  | ||||
|                                 attrSet='set_text',  | ||||
|                                 canEdit=True, | ||||
|                                 tooltip='Any name you like to name the database ' | ||||
|                         ), | ||||
|                         self.FieldWidget( | ||||
|                             text='Db:',  | ||||
|                             attrDatabase='database',  | ||||
|                             widget=gtk.Entry(),  | ||||
|                             defaultValue='', | ||||
|                             attrGet='get_text',  | ||||
|                             attrSet='set_text',  | ||||
|                             canEdit=False, | ||||
|                             tooltip='Name of the database to create' | ||||
|                         ), | ||||
|                         self.FieldWidget( | ||||
|                             text='File:',  | ||||
|                             attrDatabase='file',  | ||||
|                             widget=self.SqLiteFileChooserButton(self, self.parentWidget),  | ||||
|                             defaultValue='', | ||||
|                             attrGet='get_filename',  | ||||
|                             attrSet='set_filename',  | ||||
|                             canEdit=False,  | ||||
|                             tooltip='Fully qualified path of the file to hold the database ' | ||||
|                         ), | ||||
|                         self.FieldWidget( | ||||
|                             text='Host:',  | ||||
|                             attrDatabase='host',  | ||||
|                             widget=gtk.Entry(),  | ||||
|                             defaultValue='', | ||||
|                             attrGet='get_text',  | ||||
|                             attrSet='set_text',  | ||||
|                             canEdit=False,  | ||||
|                             tooltip='Host the database is located at' | ||||
|                         ), | ||||
|                         self.FieldWidget( | ||||
|                             text='Port:',  | ||||
|                             attrDatabase='port',  | ||||
|                             widget=gtk.SpinButton(adjustment=gtk.Adjustment(value=0, lower=0, upper=999999, step_incr=1, page_incr=10) ),  | ||||
|                             defaultValue=0, | ||||
|                             attrGet='get_value',  | ||||
|                             attrSet='set_value',  | ||||
|                             canEdit=False,  | ||||
|                             tooltip='Port to use to connect to the host' | ||||
|                         ), | ||||
|                         self.FieldWidget( | ||||
|                             text='User:',  | ||||
|                             attrDatabase='user',  | ||||
|                             widget=gtk.Entry(),  | ||||
|                             defaultValue='', | ||||
|                             attrGet='get_text',  | ||||
|                             attrSet='set_text',  | ||||
|                             canEdit=False,  | ||||
|                             tooltip='User name used to login to the host' | ||||
|                         ), | ||||
|                         self.FieldWidget( | ||||
|                             text='Pwd:',  | ||||
|                             attrDatabase='password',  | ||||
|                             widget=gtk.Entry(),  | ||||
|                             defaultValue='', | ||||
|                             attrGet='get_text',  | ||||
|                             attrSet='set_text',  | ||||
|                             canEdit=False,  | ||||
|                             tooltip='Password used to login to the host' | ||||
|                         ), | ||||
|                     ) | ||||
|              | ||||
|             # setup database type combo | ||||
|             self.comboType = gtk.ComboBox() | ||||
|             listStore= gtk.ListStore(str, str) | ||||
|             self.comboType.set_model(listStore) | ||||
|             cell = gtk.CellRendererText() | ||||
|             self.comboType.pack_start(cell, True) | ||||
|             self.comboType.add_attribute(cell, 'text', 0) | ||||
|             self.comboType.connect('changed', self.on_combo_type_changed) | ||||
|                      | ||||
|             # fill database type combo with available database klasses. we store (databaseDisplayName, databaseType) in our model for later lookup | ||||
|             iCurrentDatabase = 0 | ||||
|             databaseTypes = [(klass.display_name(), klass.Type) for klass in databaseManager.DatabaseTypes.values()] | ||||
|             databaseTypes.sort() | ||||
|             for i, (databaseDisplayName, databaseType) in enumerate(databaseTypes): | ||||
|                 listStore.append( (databaseDisplayName, databaseType) ) | ||||
|                 if databaseType == self.database.Type: | ||||
|                     iCurrentDatabase = i | ||||
|             if self.mode == self.ModeEdit or len(databaseTypes) < 2: | ||||
|                 self.comboType.set_button_sensitivity(gtk.SENSITIVITY_OFF) | ||||
|                  | ||||
|             # init and layout field widgets | ||||
|             self.pack_start(self.comboType, False, False, 2) | ||||
|             table = gtk.Table(rows=len(self.fieldWidgets) +1, columns=2, homogeneous=False) | ||||
|             self.pack_start(table, False, False, 2) | ||||
|             for i,fieldWidget in enumerate(self.fieldWidgets): | ||||
|                 table.attach(fieldWidget.label(), 0, 1, i, i+1, xoptions=gtk.FILL) | ||||
|                 table.attach(fieldWidget.widget(), 1, 2, i, i+1) | ||||
|                  | ||||
|             # init widget | ||||
|             self.comboType.set_active(iCurrentDatabase) | ||||
|             self._adjust_widgets(self.database) | ||||
|      | ||||
|     def _adjust_widgets(self, database): | ||||
|         for fieldWidget in self.fieldWidgets: | ||||
|             isSensitive = fieldWidget.is_sensitive(database) | ||||
|             if isSensitive: | ||||
|                 fieldWidget.value_from_database(database) | ||||
|             else: | ||||
|                 fieldWidget.reset_value() | ||||
|             if self.mode == self.ModeEdit: | ||||
|                 isSensitive = isSensitive and fieldWidget.can_edit() | ||||
|             fieldWidget.set_sensitive(isSensitive) | ||||
|      | ||||
|      | ||||
|     def on_combo_type_changed(self, combo): | ||||
|         i = self.comboType.get_active() | ||||
|         if i < 0: | ||||
|             return | ||||
|              | ||||
|         # check if we need to init a new database | ||||
|         currentDatabaseType = self.comboType.get_model()[i][1] | ||||
|         if currentDatabaseType == self.database.Type: | ||||
|             return | ||||
|              | ||||
|         # create new empty database | ||||
|         #NOTE: we dont register it in DatabaseManager | ||||
|         self.database = self.databaseManager.DatabaseTypes[currentDatabaseType]() | ||||
|         self._adjust_widgets(self.database) | ||||
|              | ||||
|      | ||||
|     def get_database(self): | ||||
|         for fieldWidget in self.fieldWidgets: | ||||
|             if fieldWidget.is_sensitive(self.database): | ||||
|                 fieldWidget.value_to_database(self.database) | ||||
|         return self.database | ||||
| 
 | ||||
| 
 | ||||
| class DialogDatabaseProperties(gtk.Dialog): | ||||
|     def __init__(self, databaseManager, database, parent=None,  mode=WidgetDatabaseProperties.ModeEdit, title=''): | ||||
|         gtk.Dialog.__init__(self, | ||||
|                 title=title,  | ||||
|                 parent=parent, | ||||
|                 flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, | ||||
|                 buttons=( | ||||
|                         gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, | ||||
|                         gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, | ||||
|                         ) | ||||
|                 ) | ||||
|         self.connect('response', self.on_dialog_response) | ||||
|          | ||||
|         # setup widget | ||||
|         self.widgetDatabaseProperties = WidgetDatabaseProperties(databaseManager,database, mode=mode, parentWidget=self) | ||||
|         self.vbox.pack_start(self.widgetDatabaseProperties, True, True) | ||||
|         self.show_all() | ||||
| 
 | ||||
|     def get_widget_database_properties(self): | ||||
|         return self.widgetDatabaseProperties | ||||
|      | ||||
|     def on_dialog_response(self, dlg, responseId): | ||||
|         if responseId == gtk.RESPONSE_REJECT: | ||||
|             pass | ||||
|         elif responseId == gtk.RESPONSE_ACCEPT: | ||||
|             pass | ||||
|              | ||||
| 
 | ||||
| #TODO: derrive from gtk.VBox?     | ||||
| # ..is there a way to derrive from gtk.Widget or similar? this would make parentWidget kw obsolete | ||||
| class WidgetDatabaseManager(gtk.VBox): | ||||
|     def __init__(self, databaseManager, parentWidget=None): | ||||
|         gtk.VBox.__init__(self) | ||||
|          | ||||
|         self.databaseManager = databaseManager | ||||
|         self.parentWidget = parentWidget | ||||
|              | ||||
|         #TODO: dono how to make word wrap work as expected | ||||
|         self.labelInfo = gtk.Label('database management') | ||||
|         self.labelInfo.set_line_wrap(True) | ||||
|         self.labelInfo.set_selectable(True) | ||||
|         self.labelInfo.set_single_line_mode(False) | ||||
|         self.labelInfo.set_alignment(0, 0) | ||||
|          | ||||
|         # database management buttons | ||||
|          | ||||
|         #TODO: bit messy the distinction New/Add/Edit. we'd have to pass three flags to DialogDatabaseProperties | ||||
|         # to handle this. maybe drop Edit (is just a Remove + Add), to keep things simple | ||||
|         self.buttonDatabaseNew = gtk.Button("New..") | ||||
|         self.buttonDatabaseNew.set_tooltip_text('creates a new database') | ||||
|         self.buttonDatabaseNew.connect('clicked', self.on_button_database_new_clicked) | ||||
|         self.buttonDatabaseAdd = gtk.Button("Add..") | ||||
|         self.buttonDatabaseAdd.set_tooltip_text('adds an existing database') | ||||
|         self.buttonDatabaseAdd.connect('clicked', self.on_button_database_add_clicked) | ||||
|         self.buttonDatabaseEdit = gtk.Button("Edit..") | ||||
|         self.buttonDatabaseEdit.set_tooltip_text('edit database settings') | ||||
|         self.buttonDatabaseEdit.connect('clicked', self.on_button_database_edit_clicked) | ||||
|         self.buttonDatabaseEdit.set_sensitive(False) | ||||
|         self.buttonDatabaseRemove = gtk.Button("Remove") | ||||
|         self.buttonDatabaseRemove.set_tooltip_text('removes the database from the list') | ||||
|         self.buttonDatabaseRemove.set_sensitive(False) | ||||
|          | ||||
|         #TODO: i dont think we should do any real database management here. maybe drop it | ||||
|         self.buttonDatabaseDelete = gtk.Button("Delete") | ||||
|         self.buttonDatabaseDelete.set_tooltip_text('removes the database from the list and deletes it') | ||||
|         self.buttonDatabaseDelete.set_sensitive(False) | ||||
|              | ||||
|         # init database tree         | ||||
|         self.treeDatabases = gtk.TreeView() | ||||
|         self.treeDatabaseColumns = (        #NOTE: column names starting with '_' will be hidden | ||||
|                 'Name',  | ||||
|                 'Status',  | ||||
|                 'Type',  | ||||
|                 '_id', | ||||
|                 ) | ||||
|          | ||||
|         store = gtk.ListStore(str, str, str, int) | ||||
|         self.treeDatabases.set_model(store) | ||||
|         columns = ('Name', 'Status', 'Type', '_id') | ||||
|         for i, column in enumerate(columns): | ||||
|             col = gtk.TreeViewColumn(column, gtk.CellRendererText(), text=i) | ||||
|             self.treeDatabases.append_column(col) | ||||
|             if column.startswith('_'): | ||||
|                 col.set_visible(False) | ||||
|          | ||||
|         self.treeDatabaseColumns = dict([(name, i) for (i, name) in enumerate(self.treeDatabaseColumns)]) | ||||
|         self.treeDatabases.get_selection().connect('changed', self.on_tree_databases_selection_changed) | ||||
|                  | ||||
|         # layout widgets | ||||
|         vbox = gtk.VBox(self) | ||||
|         vbox.pack_start(self.labelInfo, False, False, 2) | ||||
|         vbox.pack_start(gtk.HSeparator(), False, False, 2) | ||||
|         hbox = gtk.HBox() | ||||
|         self.add(hbox) | ||||
|         hbox.set_homogeneous(False) | ||||
|         vbox = gtk.VBox() | ||||
|         hbox.pack_start(vbox, False, False, 2) | ||||
|         vbox.pack_start(self.buttonDatabaseNew, False, False, 2) | ||||
|         vbox.pack_start(self.buttonDatabaseAdd, False, False, 2) | ||||
|         vbox.pack_start(self.buttonDatabaseEdit, False, False, 2) | ||||
|         vbox.pack_start(self.buttonDatabaseRemove, False, False, 2) | ||||
|         vbox.pack_start(self.buttonDatabaseDelete, False, False, 2) | ||||
|         box = gtk.VBox() | ||||
|         vbox.pack_start(box, True, True, 0) | ||||
|          | ||||
|         hbox.pack_start(gtk.VSeparator(), False, False, 2) | ||||
|         hbox.pack_end(self.treeDatabases, True, True, 2) | ||||
|          | ||||
|         self.show_all() | ||||
|          | ||||
|         # init widget | ||||
|         for database in self.databaseManager: | ||||
|             self.treeDatabases.get_model().append( (database.name, 'foo', database.Type, self.databaseManager.database_id(database)) ) | ||||
|          | ||||
|     #TODO: for some reason i have to click OK/Cancel twice to close the dialog         | ||||
|     def on_button_database_new_clicked(self, button): | ||||
|         databaseType = self.databaseManager.get_default_database_type() | ||||
|         if databaseType is None: | ||||
|             raise ValueError('no defult database type set') | ||||
|         dlg = DialogDatabaseProperties( | ||||
|                 self.databaseManager,  | ||||
|                 databaseType(),  | ||||
|                 parent=self.parentWidget,  | ||||
|                 mode=WidgetDatabaseProperties.ModeNew, | ||||
|                 title='[New database] - database properties' | ||||
|                 ) | ||||
|         if dlg.run() == gtk.RESPONSE_REJECT: | ||||
|             pass | ||||
|         if dlg.run() == gtk.RESPONSE_ACCEPT: | ||||
|             database = dlg.get_widget_database_properties().get_database() | ||||
|             #TODO: sanity checks + init databse if necessary | ||||
|             self.databaseManager.add_database(database) | ||||
|             self.treeDatabases.get_model().append( (database.name, 'foo', database.Type, self.databaseManager.database_id(database)) ) | ||||
|         dlg.destroy() | ||||
| 
 | ||||
|     def on_button_database_add_clicked(self, button): | ||||
|         databaseType = self.databaseManager.get_default_database_type() | ||||
|         if databaseType is None: | ||||
|             raise ValueError('no defult database type set') | ||||
|         dlg = DialogDatabaseProperties( | ||||
|                 self.databaseManager,  | ||||
|                 databaseType(),  | ||||
|                 parent=self.parentWidget,  | ||||
|                 mode=WidgetDatabaseProperties.ModeAdd, | ||||
|                 title='[Add database] - database properties' | ||||
|                 ) | ||||
|         if dlg.run() == gtk.RESPONSE_REJECT: | ||||
|             pass | ||||
|         if dlg.run() == gtk.RESPONSE_ACCEPT: | ||||
|             database = dlg.get_widget_database_properties().get_database() | ||||
|             #TODO: sanity checks | ||||
|             self.databaseManager.add_database(database) | ||||
|             self.treeDatabases.get_model().append( (database.name, 'foo', database.Type, self.databaseManager.database_id(database)) ) | ||||
|         dlg.destroy() | ||||
|          | ||||
|     def on_button_database_edit_clicked(self, button): | ||||
|         selection = self.treeDatabases.get_selection() | ||||
|         if selection is None: | ||||
|                 return | ||||
|                  | ||||
|         model, iter = selection.get_selected() | ||||
|         idDatabase = model.get_value(iter, self.treeDatabaseColumns['_id']) | ||||
|         database = self.databaseManager.database_from_id(idDatabase) | ||||
|         dlg = DialogDatabaseProperties( | ||||
|                 self.databaseManager,  | ||||
|                 database=database,  | ||||
|                 parent=self.parentWidget,  | ||||
|                 mode=WidgetDatabaseProperties.ModeEdit,  | ||||
|                 title='[Edit database] - database properties' | ||||
|                 ) | ||||
|         if dlg.run() == gtk.RESPONSE_REJECT: | ||||
|             pass | ||||
|         if dlg.run() == gtk.RESPONSE_ACCEPT: | ||||
|             database = dlg.get_database() | ||||
|             selection = self.treeDatabases.get_selection() | ||||
|             if selection is not None: | ||||
|                 model, iter = selection.get_selected() | ||||
|                 model.set_value(iter, 0, database.name) | ||||
|         dlg.destroy() | ||||
| 
 | ||||
|     def on_tree_databases_selection_changed(self, treeSelection): | ||||
|         hasSelection = bool(treeSelection.count_selected_rows()) | ||||
|          | ||||
|             # enable/disable selection dependend widgets | ||||
|         self.buttonDatabaseEdit.set_sensitive(hasSelection) | ||||
|         self.buttonDatabaseRemove.set_sensitive(hasSelection) | ||||
|         self.buttonDatabaseDelete.set_sensitive(hasSelection) | ||||
|          | ||||
| 
 | ||||
| class DialogDatabaseManager(gtk.Dialog): | ||||
|     def __init__(self, databaseManager, parent=None): | ||||
|         gtk.Dialog.__init__(self, | ||||
|         title="My dialog",  | ||||
|                 parent=parent, | ||||
|                 flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, | ||||
|                 buttons=( | ||||
|                         gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, | ||||
|                         gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, | ||||
|                         )) | ||||
|         #self.set_size_request(260, 250) | ||||
|         self.widgetDatabaseManager = WidgetDatabaseManager(databaseManager, parentWidget=self) | ||||
|         self.vbox.pack_start(self.widgetDatabaseManager, True, True) | ||||
|         self.show_all() | ||||
|          | ||||
| #************************************************************************************************** | ||||
| if __name__ == '__main__': | ||||
|     databaseManager = DatabaseManager.from_fpdb('', defaultDatabaseType=DatabaseTypeSqLite) | ||||
|      | ||||
|     #d = DialogDatabaseProperties( | ||||
|     #        DatabaseManager(defaultDatabaseType=DatabaseTypeSqLite), | ||||
|             #database=DatabaseTypePostgres(), | ||||
|     #        database=None, | ||||
|     #        ) | ||||
|     d = DialogDatabaseManager(databaseManager) | ||||
|     d.connect("destroy", gtk.main_quit) | ||||
|     d.run() | ||||
|     #gtk.main() | ||||
| 
 | ||||
| 
 | ||||
|  | @ -56,7 +56,10 @@ class DerivedStats(): | |||
| 
 | ||||
|         # This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and | ||||
|         # those values remain default in stud. | ||||
|         boardcards = hand.board['FLOP'] + hand.board['TURN'] + hand.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] | ||||
|         boardcards = [] | ||||
|         for street in hand.communityStreets: | ||||
|             boardcards += hand.board[street] | ||||
|         boardcards += [u'0x', u'0x', u'0x', u'0x', u'0x'] | ||||
|         cards = [Card.encodeCard(c) for c in boardcards[0:5]] | ||||
|         self.hands['boardcard1'] = cards[0] | ||||
|         self.hands['boardcard2'] = cards[1] | ||||
|  | @ -809,24 +812,11 @@ class DerivedStats(): | |||
|         self.hands['playersAtStreet4']  = 0 | ||||
|         self.hands['playersAtShowdown'] = 0 | ||||
| 
 | ||||
|         for street in hand.actionStreets: | ||||
|         for (i, street) in enumerate(hand.actionStreets[2:]): | ||||
|             actors = {} | ||||
|             for act in hand.actions[street]: | ||||
|                 actors[act[0]] = 1 | ||||
|             #print "len(actors.keys(%s)): %s" % ( street, len(actors.keys())) | ||||
|             if hand.gametype['base'] in ("hold"): | ||||
|                 if street in "FLOP": self.hands['playersAtStreet1'] = len(actors.keys()) | ||||
|                 elif street in "TURN": self.hands['playersAtStreet2'] = len(actors.keys()) | ||||
|                 elif street in "RIVER": self.hands['playersAtStreet3'] = len(actors.keys()) | ||||
|             elif hand.gametype['base'] in ("stud"): | ||||
|                 if street in "FOURTH": self.hands['playersAtStreet1'] = len(actors.keys()) | ||||
|                 elif street in "FIFTH": self.hands['playersAtStreet2'] = len(actors.keys()) | ||||
|                 elif street in "SIXTH": self.hands['playersAtStreet3'] = len(actors.keys()) | ||||
|                 elif street in "SEVENTH": self.hands['playersAtStreet4'] = len(actors.keys()) | ||||
|             elif hand.gametype['base'] in ("draw"): | ||||
|                 if street in "DRAWONE": self.hands['playersAtStreet1'] = len(actors.keys()) | ||||
|                 elif street in "DRAWTWO": self.hands['playersAtStreet2'] = len(actors.keys()) | ||||
|                 elif street in "DRAWTHREE": self.hands['playersAtStreet3'] = len(actors.keys()) | ||||
|             self.hands['playersAtStreet%s' % str(i+1)] = len(actors.keys()) | ||||
| 
 | ||||
|         #Need playersAtShowdown | ||||
| 
 | ||||
|  |  | |||
|  | @ -304,5 +304,5 @@ if __name__ == "__main__": | |||
|     LOG_FILENAME = './logging.out' | ||||
|     logging.basicConfig(filename=LOG_FILENAME,level=options.verbosity) | ||||
| 
 | ||||
|     e = Everleaf(in_path = options.ipath, out_path = options.opath, follow = options.follow, autostart=True, debugging=True) | ||||
|     e = Everleaf(in_path = options.ipath, out_path = options.opath, follow = options.follow, autostart=True) | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ import pygtk | |||
| pygtk.require('2.0') | ||||
| import gtk | ||||
| import os | ||||
| import sys | ||||
| import traceback | ||||
| from time import * | ||||
| #import pokereval | ||||
|  | @ -32,11 +33,12 @@ try: | |||
|     from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar | ||||
|     from numpy import arange, cumsum | ||||
|     from pylab import * | ||||
| except ImportError: | ||||
| except ImportError, inst: | ||||
|     print """Failed to load libs for graphing, graphing will not function. Please in | ||||
|                  stall numpy and matplotlib if you want to use graphs.""" | ||||
|     print """This is of no consequence for other parts of the program, e.g. import  | ||||
|          and HUD are NOT affected by this problem.""" | ||||
|     print "ImportError: %s" % inst.args | ||||
| 
 | ||||
| import fpdb_import | ||||
| import Database | ||||
|  |  | |||
|  | @ -37,11 +37,10 @@ try: | |||
| #    from matplotlib.dates import  DateFormatter, WeekdayLocator, HourLocator, \ | ||||
| #     DayLocator, MONDAY, timezone | ||||
| 
 | ||||
| except: | ||||
|     err = traceback.extract_tb(sys.exc_info()[2])[-1] | ||||
|     print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) | ||||
| except ImportError, inst: | ||||
|     print """Failed to load numpy in Session Viewer""" | ||||
|     print """This is of no consequence as the module currently doesn't do anything.""" | ||||
|     print """This is of no consequence as the page is broken and only of interest to developers.""" | ||||
|     print "ImportError: %s" % inst.args | ||||
| 
 | ||||
| import Card | ||||
| import fpdb_import | ||||
|  | @ -249,6 +248,8 @@ class GuiSessionViewer (threading.Thread): | |||
|         nametest = nametest.replace("L", "") | ||||
|         nametest = nametest.replace(",)",")") | ||||
|         q = q.replace("<player_test>", nametest) | ||||
|         q = q.replace("<ampersand_s>", "%s") | ||||
| 
 | ||||
|         self.db.cursor.execute(q) | ||||
|         THRESHOLD = 1800 | ||||
|         hands = self.db.cursor.fetchall() | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ | |||
| 
 | ||||
|     <import callFpdbHud = "True" interval = "10"  fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import> | ||||
| 
 | ||||
| 
 | ||||
| <!-- These values need some explaining | ||||
| 
 | ||||
|      aggregate_ring_game_stats : | ||||
|  | @ -567,6 +566,7 @@ Left-Drag to Move" | |||
|         <hhc site="Absolute" converter="AbsoluteToFpdb"/> | ||||
|         <hhc site="PartyPoker" converter="PartyPokerToFpdb"/> | ||||
|         <hhc site="Betfair" converter="BetfairToFpdb"/> | ||||
|         <hhc site="Partouche" converter="PartoucheToFpdb"/> | ||||
|     </hhcs> | ||||
| 
 | ||||
|     <supported_databases> | ||||
|  |  | |||
|  | @ -128,6 +128,9 @@ class HUD_main(object): | |||
|              | ||||
|             gtk.gdk.threads_enter() | ||||
|             try: # TODO: seriously need to decrease the scope of this block.. what are we expecting to error? | ||||
|                  # TODO: The purpose of this try/finally block is to make darn sure that threads_leave() | ||||
|                  # TODO: gets called. If there is an exception and threads_leave() doesn't get called we  | ||||
|                  # TODO: lock up.  REB | ||||
|                 newlabel = gtk.Label("%s - %s" % (table.site, table_name)) | ||||
|                 self.vb.add(newlabel) | ||||
|                 newlabel.show() | ||||
|  | @ -186,99 +189,95 @@ class HUD_main(object): | |||
| #    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. | ||||
|         try: | ||||
|             self.db_connection = Database.Database(self.config) | ||||
|             tourny_finder = re.compile('(\d+) (\d+)') | ||||
|         self.db_connection = Database.Database(self.config) | ||||
|         tourny_finder = re.compile('(\d+) (\d+)') | ||||
|          | ||||
| #       get hero's screen names and player ids | ||||
|             self.hero, self.hero_ids = {}, {} | ||||
|             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]) | ||||
|         self.hero, self.hero_ids = {}, {} | ||||
|         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]) | ||||
|      | ||||
|             while 1: # wait for a new hand number on stdin | ||||
|                 new_hand_id = sys.stdin.readline() | ||||
|                 new_hand_id = string.rstrip(new_hand_id) | ||||
|                 if new_hand_id == "":           # blank line means quit | ||||
|                     self.destroy() | ||||
|                     break # this thread is not always killed immediately with gtk.main_quit() | ||||
|         while 1: # wait for a new hand number on stdin | ||||
|             new_hand_id = sys.stdin.readline() | ||||
|             new_hand_id = string.rstrip(new_hand_id) | ||||
|             if new_hand_id == "":           # blank line means quit | ||||
|                 self.destroy() | ||||
|                 break # this thread is not always killed immediately with gtk.main_quit() | ||||
| #        get basic info about the new hand from the db | ||||
| #        if there is a db error, complain, skip hand, and proceed | ||||
|                 try: | ||||
|                     (table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id) | ||||
|             try: | ||||
|                 (table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(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'] | ||||
|                 except Exception, err: | ||||
|                     err = traceback.extract_tb(sys.exc_info()[2])[-1] | ||||
|                     print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) | ||||
|                     if new_hand_id: # new_hand_id is none if we had an error prior to the store | ||||
|                         sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(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'] | ||||
|             except Exception, err: | ||||
|                 err = traceback.extract_tb(sys.exc_info()[2])[-1] | ||||
|                 print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) | ||||
|                 if new_hand_id: # new_hand_id is none if we had an error prior to the store | ||||
|                     sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) | ||||
|                 continue | ||||
| 
 | ||||
|             if type == "tour":   # hand is from a tournament | ||||
|                 mat_obj = tourny_finder.search(table_name) | ||||
|                 if mat_obj: | ||||
|                     (tour_number, tab_number) = mat_obj.group(1, 2) | ||||
|                     temp_key = tour_number | ||||
|                 else:   # tourney, but can't get number and table | ||||
|                     print "could not find tournament: skipping " | ||||
|                     #sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id))) | ||||
|                     continue | ||||
|                      | ||||
|                 if type == "tour":   # hand is from a tournament | ||||
|                     mat_obj = tourny_finder.search(table_name) | ||||
|                     if mat_obj: | ||||
|                         (tour_number, tab_number) = mat_obj.group(1, 2) | ||||
|                         temp_key = tour_number | ||||
|                     else:   # tourney, but can't get number and table | ||||
|                         print "could not find tournament: skipping " | ||||
|                         #sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id))) | ||||
|                         continue | ||||
|                          | ||||
|                 else: | ||||
|                     temp_key = table_name | ||||
|             else: | ||||
|                 temp_key = table_name | ||||
| 
 | ||||
| #        Update an existing HUD | ||||
|                 if temp_key in self.hud_dict: | ||||
|                     try: | ||||
|                         # get stats using hud's specific params | ||||
|                         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']) | ||||
|                         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]) | ||||
|                     except: | ||||
|                         err = traceback.extract_tb(sys.exc_info()[2])[-1] | ||||
|                         print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) | ||||
|                         if new_hand_id: # new_hand_id is none if we had an error prior to the store | ||||
|                             sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) | ||||
|                         continue | ||||
|                     self.hud_dict[temp_key].stat_dict = stat_dict | ||||
|                     self.hud_dict[temp_key].cards = cards | ||||
|                     [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) | ||||
|             if temp_key in self.hud_dict: | ||||
|                 try: | ||||
|                     # get stats using hud's specific params | ||||
|                     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']) | ||||
|                     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]) | ||||
|                 except: | ||||
|                     err = traceback.extract_tb(sys.exc_info()[2])[-1] | ||||
|                     print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) | ||||
|                     if new_hand_id: # new_hand_id is none if we had an error prior to the store | ||||
|                         sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) | ||||
|                     continue | ||||
|                 self.hud_dict[temp_key].stat_dict = stat_dict | ||||
|                 self.hud_dict[temp_key].cards = cards | ||||
|                 [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) | ||||
|      | ||||
| #        Or create a new HUD | ||||
|             else: | ||||
|                 try: | ||||
|                     # get stats using default params | ||||
|                     self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] ) | ||||
|                     stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params, self.hero_ids[site_id]) | ||||
|                 except: | ||||
|                     err = traceback.extract_tb(sys.exc_info()[2])[-1] | ||||
|                     print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) | ||||
|                     if new_hand_id: # new_hand_id is none if we had an error prior to the store | ||||
|                         sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) | ||||
|                     continue | ||||
|                 if type == "tour": | ||||
|                     tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number) | ||||
|                 else: | ||||
|                     try: | ||||
|                         # get stats using default params | ||||
|                         self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] ) | ||||
|                         stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params, self.hero_ids[site_id]) | ||||
|                     except: | ||||
|                         err = traceback.extract_tb(sys.exc_info()[2])[-1] | ||||
|                         print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) | ||||
|                         if new_hand_id: # new_hand_id is none if we had an error prior to the store | ||||
|                             sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) | ||||
|                         continue | ||||
|                     if type == "tour": | ||||
|                         tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number) | ||||
|                     else: | ||||
|                         tablewindow = Tables.discover_table_by_name(self.config, table_name) | ||||
|                     if tablewindow == None: | ||||
|                     tablewindow = Tables.discover_table_by_name(self.config, table_name) | ||||
|                 if tablewindow == None: | ||||
| #        If no client window is found on the screen, complain and continue | ||||
|                         if type == "tour": | ||||
|                             table_name = "%s %s" % (tour_number, tab_number) | ||||
|                         sys.stderr.write("table name "+table_name+" not found, skipping.\n") | ||||
|                     else: | ||||
|                         self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards) | ||||
|                 self.db_connection.connection.rollback() | ||||
|         except: | ||||
|             err = traceback.extract_tb(sys.exc_info()[2])[-1] | ||||
|             print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) | ||||
|                     if type == "tour": | ||||
|                         table_name = "%s %s" % (tour_number, tab_number) | ||||
|                     sys.stderr.write("table name "+table_name+" not found, skipping.\n") | ||||
|                 else: | ||||
|                     self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards) | ||||
|             self.db_connection.connection.rollback() | ||||
| 
 | ||||
| if __name__== "__main__": | ||||
| 
 | ||||
|  |  | |||
|  | @ -28,11 +28,12 @@ from HandHistoryConverter import * | |||
| 
 | ||||
| class PartyPokerParseError(FpdbParseError): | ||||
|     "Usage: raise PartyPokerParseError(<msg>[, hh=<hh>][, hid=<hid>])" | ||||
| 
 | ||||
|     def __init__(self, msg='', hh=None, hid=None): | ||||
|         if hh is not None: | ||||
|             msg += "\n\nHand history attached below:\n" + self.wrapHh(hh) | ||||
|         return super(PartyPokerParseError, self).__init__(hid=hid) | ||||
|         #return super(PartyPokerParseError, self).__init__(msg, hid=hid) | ||||
|         return super(PartyPokerParseError, self).__init__(msg, hid=hid) | ||||
| 
 | ||||
|     def wrapHh(self, hh): | ||||
|         return ("%(DELIMETER)s\n%(HH)s\n%(DELIMETER)s") % \ | ||||
|                 {'DELIMETER': '#'*50, 'HH': hh} | ||||
|  | @ -93,7 +94,7 @@ class PartyPoker(HandHistoryConverter): | |||
|             """, | ||||
|           re.MULTILINE|re.VERBOSE) | ||||
| 
 | ||||
|     re_TotalPlayers = re.compile("^Total\s+number\s+of\s+players\s*:\s*(?P<MAXSEATS>\d+)", re.MULTILINE) | ||||
| #    re_TotalPlayers = re.compile("^Total\s+number\s+of\s+players\s*:\s*(?P<MAXSEATS>\d+)", re.MULTILINE) | ||||
|     re_SplitHands   = re.compile('\x00+') | ||||
|     re_TailSplitHands   = re.compile('(\x00+)') | ||||
|     lineSplitter    = '\n' | ||||
|  | @ -229,7 +230,6 @@ class PartyPoker(HandHistoryConverter): | |||
|                 "Unknown game type '%s'" % mg['GAME'], | ||||
|                 hh = handText) | ||||
| 
 | ||||
| 
 | ||||
|         if 'TOURNO' in mg: | ||||
|             info['type'] = 'tour' | ||||
|         else: | ||||
|  | @ -237,15 +237,12 @@ class PartyPoker(HandHistoryConverter): | |||
| 
 | ||||
|         if info['type'] == 'ring': | ||||
|             info['sb'], info['bb'] = ringBlinds(mg['RINGLIMIT']) | ||||
|             # FIXME: there are only $ and play money availible for cash | ||||
|             # to be honest, party doesn't save play money hh | ||||
|             info['currency'] = currencies[mg['CURRENCY']] | ||||
|         else: | ||||
|             info['sb'] = clearMoneyString(mg['SB']) | ||||
|             info['bb'] = clearMoneyString(mg['BB']) | ||||
|             info['currency'] = 'T$' | ||||
| 
 | ||||
|         # NB: SB, BB must be interpreted as blinds or bets depending on limit type. | ||||
|         return info | ||||
| 
 | ||||
| 
 | ||||
|  | @ -269,8 +266,8 @@ class PartyPoker(HandHistoryConverter): | |||
|             hh=hand.handText, hid = info['HID']) | ||||
| 
 | ||||
| 
 | ||||
|         m = self.re_TotalPlayers.search(hand.handText) | ||||
|         if m: info.update(m.groupdict()) | ||||
| #        m = self.re_TotalPlayers.search(hand.handText) | ||||
| #        if m: info.update(m.groupdict()) | ||||
| 
 | ||||
| 
 | ||||
|         # FIXME: it's dirty hack | ||||
|  | @ -318,7 +315,7 @@ class PartyPoker(HandHistoryConverter): | |||
|                 hand.tourNo = info[key] | ||||
|             if key == 'BUYIN': | ||||
|                 # FIXME: it's dirty hack T_T | ||||
|                 # code below assumes that rake is equal to zero | ||||
|                 # code below assumes that tournament rake is equal to zero | ||||
|                 cur = info[key][0] if info[key][0] not in '0123456789' else '' | ||||
|                 hand.buyin = info[key] + '+%s0' % cur | ||||
|             if key == 'LEVEL': | ||||
|  | @ -474,11 +471,9 @@ class PartyPoker(HandHistoryConverter): | |||
|             if m.group('CARDS') is not None: | ||||
|                 cards = renderCards(m.group('CARDS')) | ||||
| 
 | ||||
|                 (shown, mucked) = (False, False) | ||||
|                 if m.group('SHOWED') == "show": shown = True | ||||
|                 else: mucked = True | ||||
|                 mucked = m.group('SHOWED') != "show" | ||||
| 
 | ||||
|                 hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked) | ||||
|                 hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=True, mucked=mucked) | ||||
| 
 | ||||
| def ringBlinds(ringLimit): | ||||
|     "Returns blinds for current limit in cash games" | ||||
|  |  | |||
|  | @ -1895,9 +1895,9 @@ class Sql: | |||
|                 self.query['playerDetailedStats'] = """ | ||||
|                          select  <hgameTypeId>                                                          AS hgametypeid | ||||
|                                 ,gt.base | ||||
|                                 ,gt.category | ||||
|                                 ,gt.category                                                            AS category | ||||
|                                 ,upper(gt.limitType)                                                    AS limittype | ||||
|                                 ,s.name | ||||
|                                 ,s.name                                                                 AS name | ||||
|                                 ,min(gt.bigBlind)                                                       AS minbigblind | ||||
|                                 ,max(gt.bigBlind)                                                       AS maxbigblind | ||||
|                                 /*,<hcgametypeId>                                                       AS gtid*/ | ||||
|  | @ -1939,7 +1939,8 @@ class Sql: | |||
|                                 ,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0))                  AS bb100xr | ||||
|                                 ,avg((hp.totalProfit+hp.rake)/100.0)                                    AS profhndxr | ||||
|                                 ,avg(h.seats+0.0)                                                       AS avgseats | ||||
|                                 ,variance(hp.totalProfit/100.0)                                         AS variance | ||||
|                                 /*,variance(hp.totalProfit/100.0)                                         AS variance*/ | ||||
|                                 ,0.0                                                                    AS variance | ||||
|                           from HandsPlayers hp | ||||
|                                inner join Hands h       on  (h.id = hp.handId) | ||||
|                                inner join Gametypes gt  on  (gt.Id = h.gameTypeId) | ||||
|  | @ -2501,7 +2502,17 @@ class Sql: | |||
|                      AND  h.handStart <datestest> | ||||
|                     ORDER by time""" | ||||
|             elif db_server == 'sqlite': | ||||
|                 self.query['sessionStats'] = """ """ | ||||
|                 self.query['sessionStats'] = """ | ||||
|                     SELECT STRFTIME('<ampersand_s>', h.handStart) as time, hp.handId, hp.startCash, hp.winnings, hp.totalProfit | ||||
|                     FROM HandsPlayers hp | ||||
|                      INNER JOIN Hands h       on  (h.id = hp.handId) | ||||
|                      INNER JOIN Gametypes gt  on  (gt.Id = h.gameTypeId) | ||||
|                      INNER JOIN Sites s       on  (s.Id = gt.siteId) | ||||
|                      INNER JOIN Players p     on  (p.Id = hp.playerId) | ||||
|                     WHERE hp.playerId in <player_test> | ||||
|                      AND  h.handStart <datestest> | ||||
|                     ORDER by time""" | ||||
| 
 | ||||
| 
 | ||||
|             #################################### | ||||
|             # Queries to rebuild/modify hudcache | ||||
|  |  | |||
|  | @ -238,7 +238,8 @@ def discover_nt_by_name(c, tablename): | |||
|         try: | ||||
|             # maybe it's better to make global titles[hwnd] decoding? | ||||
|             # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html | ||||
|             if not tablename.lower() in titles[hwnd].decode(LOCALE_ENCODING).lower(): continue | ||||
|             if not tablename.lower() in titles[hwnd].decode(LOCALE_ENCODING).lower(): | ||||
|                 continue | ||||
|         except: | ||||
|             continue | ||||
|         if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window | ||||
|  | @ -246,8 +247,8 @@ def discover_nt_by_name(c, tablename): | |||
|         if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows | ||||
|         if ' - Table ' in titles[hwnd]: continue # Absolute table Chat window.. sigh. TODO: Can we tell what site we're trying to discover for somehow in here, so i can limit this check just to AP searches? | ||||
|         temp = decode_windows(c, titles[hwnd], hwnd) | ||||
|         #print "attach to window", temp | ||||
|         return decode_windows(c, titles[hwnd], hwnd) | ||||
|         print "attach to window", temp | ||||
|         return temp | ||||
|     return None | ||||
| 
 | ||||
| def discover_nt_tournament(c, tour_number, tab_number): | ||||
|  | @ -257,9 +258,12 @@ def discover_nt_tournament(c, tour_number, tab_number): | |||
|     titles ={} | ||||
|     win32gui.EnumWindows(win_enum_handler, titles) | ||||
|     for hwnd in titles: | ||||
|         if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows | ||||
|         if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window | ||||
|         if 'HUD:' in titles[hwnd]: continue # FPDB HUD window | ||||
|         # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows | ||||
|         if 'Chat:' in titles[hwnd]: continue | ||||
|         # Everleaf Network HH viewer window | ||||
|         if 'History for table:' in titles[hwnd]: continue | ||||
|         # FPDB HUD window | ||||
|         if 'HUD:' in titles[hwnd]: continue | ||||
| 
 | ||||
|         if re.search(search_string, titles[hwnd]): | ||||
|             return decode_windows(c, titles[hwnd], hwnd) | ||||
|  | @ -268,21 +272,33 @@ def discover_nt_tournament(c, tour_number, tab_number): | |||
| def get_nt_exe(hwnd): | ||||
|     """Finds the name of the executable that the given window handle belongs to.""" | ||||
|      | ||||
|     # Request privileges to enable "debug process", so we can later use PROCESS_VM_READ, retardedly required to GetModuleFileNameEx() | ||||
|     # Request privileges to enable "debug process", so we can later use | ||||
|     # PROCESS_VM_READ, retardedly required to GetModuleFileNameEx() | ||||
|     priv_flags = win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY | ||||
|     hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(), priv_flags) | ||||
|     hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(), | ||||
|                                              priv_flags) | ||||
|     # enable "debug process" | ||||
|     privilege_id = win32security.LookupPrivilegeValue (None, win32security.SE_DEBUG_NAME) | ||||
|     old_privs = win32security.AdjustTokenPrivileges (hToken, 0, [(privilege_id, win32security.SE_PRIVILEGE_ENABLED)]) | ||||
|     privilege_id = win32security.LookupPrivilegeValue(None, | ||||
|                                                       win32security.SE_DEBUG_NAME) | ||||
|     old_privs = win32security.AdjustTokenPrivileges(hToken, 0, | ||||
|                                                     [(privilege_id, | ||||
|                                                       win32security.SE_PRIVILEGE_ENABLED)]) | ||||
|      | ||||
|     # Open the process, and query it's filename | ||||
|     processid = win32process.GetWindowThreadProcessId(hwnd) | ||||
|     pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, False, processid[1]) | ||||
|     exename = win32process.GetModuleFileNameEx(pshandle, 0) | ||||
|      | ||||
|     # clean up | ||||
|     win32api.CloseHandle(pshandle) | ||||
|     win32api.CloseHandle(hToken) | ||||
|     pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | | ||||
|                                     win32con.PROCESS_VM_READ, False, | ||||
|                                     processid[1]) | ||||
|     try: | ||||
|         exename = win32process.GetModuleFileNameEx(pshandle, 0) | ||||
|     except pywintypes.error: | ||||
|         # insert code to call GetProcessImageName if we can find it.. | ||||
|         # returning None from here will hopefully break all following code | ||||
|         exename = None  | ||||
|     finally: | ||||
|         # clean up | ||||
|         win32api.CloseHandle(pshandle) | ||||
|         win32api.CloseHandle(hToken) | ||||
|          | ||||
|     return exename | ||||
| 
 | ||||
|  | @ -305,6 +321,8 @@ def decode_windows(c, title, hwnd): | |||
|     info['width']  = int( width ) - 2*b_width | ||||
|     info['height'] = int( height ) - b_width - tb_height | ||||
|     info['exe']    = get_nt_exe(hwnd) | ||||
|     print "get_nt_exe returned ", info['exe'] | ||||
|     # TODO: 'width' here is all sorts of screwed up. | ||||
| 
 | ||||
|     title_bits = re.split(' - ', info['title']) | ||||
|     info['name'] = title_bits[0] | ||||
|  |  | |||
|  | @ -626,7 +626,12 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") | |||
|         self.load_profile() | ||||
|          | ||||
|         self.statusIcon = gtk.StatusIcon() | ||||
|         self.statusIcon.set_from_stock(gtk.STOCK_HOME) | ||||
|         if os.path.exists('../gfx/fpdb-cards.png'): | ||||
|             self.statusIcon.set_from_file('../gfx/fpdb-cards.png') | ||||
|         elif os.path.exists('/usr/share/pixmaps/fpdb-cards.png'): | ||||
|             self.statusIcon.set_from_file('/usr/share/pixmaps/fpdb-cards.png') | ||||
|         else: | ||||
|             self.statusIcon.set_from_stock(gtk.STOCK_HOME) | ||||
|         self.statusIcon.set_tooltip("Free Poker Database") | ||||
|         self.statusIcon.connect('activate', self.statusicon_activate) | ||||
|         self.statusMenu = gtk.Menu() | ||||
|  | @ -673,8 +678,14 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") | |||
|         pass | ||||
|      | ||||
|     def statusicon_activate(self, widget, data = None): | ||||
|         self.window.show() | ||||
|         self.window.present() | ||||
|         # Let's allow the tray icon to toggle window visibility, the way | ||||
|         # most other apps work | ||||
|         shown = self.window.get_property('visible') | ||||
|         if shown: | ||||
|             self.window.hide() | ||||
|         else: | ||||
|             self.window.show() | ||||
|             self.window.present() | ||||
|          | ||||
|     def warning_box(self, str, diatitle="FPDB WARNING"): | ||||
|             diaWarning = gtk.Dialog(title=diatitle, parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) | ||||
|  |  | |||
|  | @ -77,10 +77,11 @@ class fpdb_db: | |||
|             import MySQLdb | ||||
|             if use_pool: | ||||
|                 MySQLdb = pool.manage(MySQLdb, pool_size=5) | ||||
|             try: | ||||
|                 self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) | ||||
|             except: | ||||
|                 raise FpdbMySQLFailedError("MySQL connection failed") | ||||
| #            try: | ||||
|             self.db = MySQLdb.connect(host=host, user=user, passwd=password, db=database, use_unicode=True) | ||||
|             #TODO: Add port option | ||||
| #            except: | ||||
| #                raise FpdbMySQLFailedError("MySQL connection failed") | ||||
|         elif backend==fpdb_db.PGSQL: | ||||
|             import psycopg2 | ||||
|             import psycopg2.extensions | ||||
|  |  | |||
							
								
								
									
										6
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -5,7 +5,7 @@ from distutils.core import setup | |||
| 
 | ||||
| setup(name = 'fpdb', | ||||
|     description = 'Free Poker Database', | ||||
|     version = '0.11.3', | ||||
|     version = '0.12', | ||||
|     author = 'FPDB team', | ||||
|     author_email = 'fpdb-main@lists.sourceforge.net', | ||||
|     packages = ['fpdb'], | ||||
|  | @ -15,7 +15,9 @@ setup(name = 'fpdb', | |||
|             ['docs/readme.txt', 'docs/release-notes.txt', | ||||
|             'docs/tabledesign.html', 'THANKS.txt']), | ||||
|         ('/usr/share/pixmaps', | ||||
|             ['gfx/fpdb-icon.png']), | ||||
|             ['gfx/fpdb-icon.png', 'gfx/fpdb-icon2.png', | ||||
|              'gfx/fpdb-cards.png' | ||||
|              ]), | ||||
|         ('/usr/share/applications', | ||||
|             ['files/fpdb.desktop']), | ||||
|         ('/usr/share/python-fpdb', | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user