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 | free-poker-tools (0.11.3+git20091023) unstable; urgency=low | ||||||
| 
 | 
 | ||||||
|   * Snapshot release |   * Snapshot release | ||||||
|  |  | ||||||
|  | @ -3,3 +3,4 @@ | ||||||
| # When installed into .../fpdb/ the script gets mode 644 | # When installed into .../fpdb/ the script gets mode 644 | ||||||
| # Note: "dh_fixperms -Xfpdb.py" did not work, hence this hack | # Note: "dh_fixperms -Xfpdb.py" did not work, hence this hack | ||||||
| chmod 755 /usr/bin/fpdb | 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.use_frames == "": self.use_frames = False | ||||||
|         if self.font       == "": self.font = "Sans"  |         if self.font       == "": self.font = "Sans"  | ||||||
|         if self.hudbgcolor == "": self.hudbgcolor = "000000" |         if self.hudbgcolor == "": self.hudbgcolor = "#000000" | ||||||
|         if self.hudfgcolor == "": self.hudfgcolor = "FFFFFF" |         if self.hudfgcolor == "": self.hudfgcolor = "#FFFFFF" | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         temp = "Site = " + self.site_name + "\n" |         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 ('Betfair', 'USD')") | ||||||
|         c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', '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 ('PartyPoker', 'USD')") | ||||||
|  |         c.execute("INSERT INTO Sites (name,currency) VALUES ('Partouche', 'EUR')") | ||||||
|         if self.backend == self.SQLITE: |         if self.backend == self.SQLITE: | ||||||
|             c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") |             c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") | ||||||
|         elif self.backend == self.PGSQL: |         elif self.backend == self.PGSQL: | ||||||
|  | @ -1264,63 +1265,6 @@ class Database: | ||||||
|             print "Error during fdb.lock_for_insert:", str(sys.exc_value) |             print "Error during fdb.lock_for_insert:", str(sys.exc_value) | ||||||
|     #end def lock_for_insert |     #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): |     def store_the_hand(self, h): | ||||||
|         """Take a HandToWrite object and store it in the db""" |         """Take a HandToWrite object and store it in the db""" | ||||||
| 
 | 
 | ||||||
|  | @ -1668,6 +1612,64 @@ class Database: | ||||||
| #            street4CheckCallRaiseChance, | #            street4CheckCallRaiseChance, | ||||||
| #            street4CheckCallRaiseDone) | #            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 | # 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 |         # This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and | ||||||
|         # those values remain default in stud. |         # 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]] |         cards = [Card.encodeCard(c) for c in boardcards[0:5]] | ||||||
|         self.hands['boardcard1'] = cards[0] |         self.hands['boardcard1'] = cards[0] | ||||||
|         self.hands['boardcard2'] = cards[1] |         self.hands['boardcard2'] = cards[1] | ||||||
|  | @ -809,24 +812,11 @@ class DerivedStats(): | ||||||
|         self.hands['playersAtStreet4']  = 0 |         self.hands['playersAtStreet4']  = 0 | ||||||
|         self.hands['playersAtShowdown'] = 0 |         self.hands['playersAtShowdown'] = 0 | ||||||
| 
 | 
 | ||||||
|         for street in hand.actionStreets: |         for (i, street) in enumerate(hand.actionStreets[2:]): | ||||||
|             actors = {} |             actors = {} | ||||||
|             for act in hand.actions[street]: |             for act in hand.actions[street]: | ||||||
|                 actors[act[0]] = 1 |                 actors[act[0]] = 1 | ||||||
|             #print "len(actors.keys(%s)): %s" % ( street, len(actors.keys())) |             self.hands['playersAtStreet%s' % str(i+1)] = 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()) |  | ||||||
| 
 | 
 | ||||||
|         #Need playersAtShowdown |         #Need playersAtShowdown | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -304,5 +304,5 @@ if __name__ == "__main__": | ||||||
|     LOG_FILENAME = './logging.out' |     LOG_FILENAME = './logging.out' | ||||||
|     logging.basicConfig(filename=LOG_FILENAME,level=options.verbosity) |     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') | pygtk.require('2.0') | ||||||
| import gtk | import gtk | ||||||
| import os | import os | ||||||
|  | import sys | ||||||
| import traceback | import traceback | ||||||
| from time import * | from time import * | ||||||
| #import pokereval | #import pokereval | ||||||
|  | @ -32,11 +33,12 @@ try: | ||||||
|     from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar |     from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar | ||||||
|     from numpy import arange, cumsum |     from numpy import arange, cumsum | ||||||
|     from pylab import * |     from pylab import * | ||||||
| except ImportError: | except ImportError, inst: | ||||||
|     print """Failed to load libs for graphing, graphing will not function. Please in |     print """Failed to load libs for graphing, graphing will not function. Please in | ||||||
|                  stall numpy and matplotlib if you want to use graphs.""" |                  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  |     print """This is of no consequence for other parts of the program, e.g. import  | ||||||
|          and HUD are NOT affected by this problem.""" |          and HUD are NOT affected by this problem.""" | ||||||
|  |     print "ImportError: %s" % inst.args | ||||||
| 
 | 
 | ||||||
| import fpdb_import | import fpdb_import | ||||||
| import Database | import Database | ||||||
|  |  | ||||||
|  | @ -37,11 +37,10 @@ try: | ||||||
| #    from matplotlib.dates import  DateFormatter, WeekdayLocator, HourLocator, \ | #    from matplotlib.dates import  DateFormatter, WeekdayLocator, HourLocator, \ | ||||||
| #     DayLocator, MONDAY, timezone | #     DayLocator, MONDAY, timezone | ||||||
| 
 | 
 | ||||||
| except: | except ImportError, inst: | ||||||
|     err = traceback.extract_tb(sys.exc_info()[2])[-1] |  | ||||||
|     print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) |  | ||||||
|     print """Failed to load numpy in Session Viewer""" |     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 Card | ||||||
| import fpdb_import | import fpdb_import | ||||||
|  | @ -249,6 +248,8 @@ class GuiSessionViewer (threading.Thread): | ||||||
|         nametest = nametest.replace("L", "") |         nametest = nametest.replace("L", "") | ||||||
|         nametest = nametest.replace(",)",")") |         nametest = nametest.replace(",)",")") | ||||||
|         q = q.replace("<player_test>", nametest) |         q = q.replace("<player_test>", nametest) | ||||||
|  |         q = q.replace("<ampersand_s>", "%s") | ||||||
|  | 
 | ||||||
|         self.db.cursor.execute(q) |         self.db.cursor.execute(q) | ||||||
|         THRESHOLD = 1800 |         THRESHOLD = 1800 | ||||||
|         hands = self.db.cursor.fetchall() |         hands = self.db.cursor.fetchall() | ||||||
|  |  | ||||||
|  | @ -4,7 +4,6 @@ | ||||||
| 
 | 
 | ||||||
|     <import callFpdbHud = "True" interval = "10"  fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import> |     <import callFpdbHud = "True" interval = "10"  fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import> | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| <!-- These values need some explaining | <!-- These values need some explaining | ||||||
| 
 | 
 | ||||||
|      aggregate_ring_game_stats : |      aggregate_ring_game_stats : | ||||||
|  | @ -567,6 +566,7 @@ Left-Drag to Move" | ||||||
|         <hhc site="Absolute" converter="AbsoluteToFpdb"/> |         <hhc site="Absolute" converter="AbsoluteToFpdb"/> | ||||||
|         <hhc site="PartyPoker" converter="PartyPokerToFpdb"/> |         <hhc site="PartyPoker" converter="PartyPokerToFpdb"/> | ||||||
|         <hhc site="Betfair" converter="BetfairToFpdb"/> |         <hhc site="Betfair" converter="BetfairToFpdb"/> | ||||||
|  |         <hhc site="Partouche" converter="PartoucheToFpdb"/> | ||||||
|     </hhcs> |     </hhcs> | ||||||
| 
 | 
 | ||||||
|     <supported_databases> |     <supported_databases> | ||||||
|  |  | ||||||
|  | @ -128,6 +128,9 @@ class HUD_main(object): | ||||||
|              |              | ||||||
|             gtk.gdk.threads_enter() |             gtk.gdk.threads_enter() | ||||||
|             try: # TODO: seriously need to decrease the scope of this block.. what are we expecting to error? |             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)) |                 newlabel = gtk.Label("%s - %s" % (table.site, table_name)) | ||||||
|                 self.vb.add(newlabel) |                 self.vb.add(newlabel) | ||||||
|                 newlabel.show() |                 newlabel.show() | ||||||
|  | @ -186,7 +189,6 @@ class HUD_main(object): | ||||||
| #    be passed to HUDs for use in the gui thread. HUD objects 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 | #    need their own access to the database, but should open their own | ||||||
| #    if it is required. | #    if it is required. | ||||||
|         try: |  | ||||||
|         self.db_connection = Database.Database(self.config) |         self.db_connection = Database.Database(self.config) | ||||||
|         tourny_finder = re.compile('(\d+) (\d+)') |         tourny_finder = re.compile('(\d+) (\d+)') | ||||||
|          |          | ||||||
|  | @ -276,9 +278,6 @@ class HUD_main(object): | ||||||
|                 else: |                 else: | ||||||
|                     self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards) |                     self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards) | ||||||
|             self.db_connection.connection.rollback() |             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 __name__== "__main__": | if __name__== "__main__": | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -28,11 +28,12 @@ from HandHistoryConverter import * | ||||||
| 
 | 
 | ||||||
| class PartyPokerParseError(FpdbParseError): | class PartyPokerParseError(FpdbParseError): | ||||||
|     "Usage: raise PartyPokerParseError(<msg>[, hh=<hh>][, hid=<hid>])" |     "Usage: raise PartyPokerParseError(<msg>[, hh=<hh>][, hid=<hid>])" | ||||||
|  | 
 | ||||||
|     def __init__(self, msg='', hh=None, hid=None): |     def __init__(self, msg='', hh=None, hid=None): | ||||||
|         if hh is not None: |         if hh is not None: | ||||||
|             msg += "\n\nHand history attached below:\n" + self.wrapHh(hh) |             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): |     def wrapHh(self, hh): | ||||||
|         return ("%(DELIMETER)s\n%(HH)s\n%(DELIMETER)s") % \ |         return ("%(DELIMETER)s\n%(HH)s\n%(DELIMETER)s") % \ | ||||||
|                 {'DELIMETER': '#'*50, 'HH': hh} |                 {'DELIMETER': '#'*50, 'HH': hh} | ||||||
|  | @ -93,7 +94,7 @@ class PartyPoker(HandHistoryConverter): | ||||||
|             """, |             """, | ||||||
|           re.MULTILINE|re.VERBOSE) |           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_SplitHands   = re.compile('\x00+') | ||||||
|     re_TailSplitHands   = re.compile('(\x00+)') |     re_TailSplitHands   = re.compile('(\x00+)') | ||||||
|     lineSplitter    = '\n' |     lineSplitter    = '\n' | ||||||
|  | @ -229,7 +230,6 @@ class PartyPoker(HandHistoryConverter): | ||||||
|                 "Unknown game type '%s'" % mg['GAME'], |                 "Unknown game type '%s'" % mg['GAME'], | ||||||
|                 hh = handText) |                 hh = handText) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         if 'TOURNO' in mg: |         if 'TOURNO' in mg: | ||||||
|             info['type'] = 'tour' |             info['type'] = 'tour' | ||||||
|         else: |         else: | ||||||
|  | @ -237,15 +237,12 @@ class PartyPoker(HandHistoryConverter): | ||||||
| 
 | 
 | ||||||
|         if info['type'] == 'ring': |         if info['type'] == 'ring': | ||||||
|             info['sb'], info['bb'] = ringBlinds(mg['RINGLIMIT']) |             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']] |             info['currency'] = currencies[mg['CURRENCY']] | ||||||
|         else: |         else: | ||||||
|             info['sb'] = clearMoneyString(mg['SB']) |             info['sb'] = clearMoneyString(mg['SB']) | ||||||
|             info['bb'] = clearMoneyString(mg['BB']) |             info['bb'] = clearMoneyString(mg['BB']) | ||||||
|             info['currency'] = 'T$' |             info['currency'] = 'T$' | ||||||
| 
 | 
 | ||||||
|         # NB: SB, BB must be interpreted as blinds or bets depending on limit type. |  | ||||||
|         return info |         return info | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -269,8 +266,8 @@ class PartyPoker(HandHistoryConverter): | ||||||
|             hh=hand.handText, hid = info['HID']) |             hh=hand.handText, hid = info['HID']) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         m = self.re_TotalPlayers.search(hand.handText) | #        m = self.re_TotalPlayers.search(hand.handText) | ||||||
|         if m: info.update(m.groupdict()) | #        if m: info.update(m.groupdict()) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         # FIXME: it's dirty hack |         # FIXME: it's dirty hack | ||||||
|  | @ -318,7 +315,7 @@ class PartyPoker(HandHistoryConverter): | ||||||
|                 hand.tourNo = info[key] |                 hand.tourNo = info[key] | ||||||
|             if key == 'BUYIN': |             if key == 'BUYIN': | ||||||
|                 # FIXME: it's dirty hack T_T |                 # 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 '' |                 cur = info[key][0] if info[key][0] not in '0123456789' else '' | ||||||
|                 hand.buyin = info[key] + '+%s0' % cur |                 hand.buyin = info[key] + '+%s0' % cur | ||||||
|             if key == 'LEVEL': |             if key == 'LEVEL': | ||||||
|  | @ -474,11 +471,9 @@ class PartyPoker(HandHistoryConverter): | ||||||
|             if m.group('CARDS') is not None: |             if m.group('CARDS') is not None: | ||||||
|                 cards = renderCards(m.group('CARDS')) |                 cards = renderCards(m.group('CARDS')) | ||||||
| 
 | 
 | ||||||
|                 (shown, mucked) = (False, False) |                 mucked = m.group('SHOWED') != "show" | ||||||
|                 if m.group('SHOWED') == "show": shown = True |  | ||||||
|                 else: mucked = True |  | ||||||
| 
 | 
 | ||||||
|                 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): | def ringBlinds(ringLimit): | ||||||
|     "Returns blinds for current limit in cash games" |     "Returns blinds for current limit in cash games" | ||||||
|  |  | ||||||
|  | @ -1895,9 +1895,9 @@ class Sql: | ||||||
|                 self.query['playerDetailedStats'] = """ |                 self.query['playerDetailedStats'] = """ | ||||||
|                          select  <hgameTypeId>                                                          AS hgametypeid |                          select  <hgameTypeId>                                                          AS hgametypeid | ||||||
|                                 ,gt.base |                                 ,gt.base | ||||||
|                                 ,gt.category |                                 ,gt.category                                                            AS category | ||||||
|                                 ,upper(gt.limitType)                                                    AS limittype |                                 ,upper(gt.limitType)                                                    AS limittype | ||||||
|                                 ,s.name |                                 ,s.name                                                                 AS name | ||||||
|                                 ,min(gt.bigBlind)                                                       AS minbigblind |                                 ,min(gt.bigBlind)                                                       AS minbigblind | ||||||
|                                 ,max(gt.bigBlind)                                                       AS maxbigblind |                                 ,max(gt.bigBlind)                                                       AS maxbigblind | ||||||
|                                 /*,<hcgametypeId>                                                       AS gtid*/ |                                 /*,<hcgametypeId>                                                       AS gtid*/ | ||||||
|  | @ -1939,7 +1939,8 @@ class Sql: | ||||||
|                                 ,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0))                  AS bb100xr |                                 ,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0))                  AS bb100xr | ||||||
|                                 ,avg((hp.totalProfit+hp.rake)/100.0)                                    AS profhndxr |                                 ,avg((hp.totalProfit+hp.rake)/100.0)                                    AS profhndxr | ||||||
|                                 ,avg(h.seats+0.0)                                                       AS avgseats |                                 ,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 |                           from HandsPlayers hp | ||||||
|                                inner join Hands h       on  (h.id = hp.handId) |                                inner join Hands h       on  (h.id = hp.handId) | ||||||
|                                inner join Gametypes gt  on  (gt.Id = h.gameTypeId) |                                inner join Gametypes gt  on  (gt.Id = h.gameTypeId) | ||||||
|  | @ -2501,7 +2502,17 @@ class Sql: | ||||||
|                      AND  h.handStart <datestest> |                      AND  h.handStart <datestest> | ||||||
|                     ORDER by time""" |                     ORDER by time""" | ||||||
|             elif db_server == 'sqlite': |             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 |             # Queries to rebuild/modify hudcache | ||||||
|  |  | ||||||
|  | @ -238,7 +238,8 @@ def discover_nt_by_name(c, tablename): | ||||||
|         try: |         try: | ||||||
|             # maybe it's better to make global titles[hwnd] decoding? |             # 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 |             # 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: |         except: | ||||||
|             continue |             continue | ||||||
|         if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window |         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 '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? |         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) |         temp = decode_windows(c, titles[hwnd], hwnd) | ||||||
|         #print "attach to window", temp |         print "attach to window", temp | ||||||
|         return decode_windows(c, titles[hwnd], hwnd) |         return temp | ||||||
|     return None |     return None | ||||||
| 
 | 
 | ||||||
| def discover_nt_tournament(c, tour_number, tab_number): | def discover_nt_tournament(c, tour_number, tab_number): | ||||||
|  | @ -257,9 +258,12 @@ def discover_nt_tournament(c, tour_number, tab_number): | ||||||
|     titles ={} |     titles ={} | ||||||
|     win32gui.EnumWindows(win_enum_handler, titles) |     win32gui.EnumWindows(win_enum_handler, titles) | ||||||
|     for hwnd in titles: |     for hwnd in titles: | ||||||
|         if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows |         # 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 'Chat:' in titles[hwnd]: continue | ||||||
|         if 'HUD:' in titles[hwnd]: continue # FPDB HUD window |         # 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]): |         if re.search(search_string, titles[hwnd]): | ||||||
|             return decode_windows(c, titles[hwnd], hwnd) |             return decode_windows(c, titles[hwnd], hwnd) | ||||||
|  | @ -268,18 +272,30 @@ def discover_nt_tournament(c, tour_number, tab_number): | ||||||
| def get_nt_exe(hwnd): | def get_nt_exe(hwnd): | ||||||
|     """Finds the name of the executable that the given window handle belongs to.""" |     """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 |     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" |     # enable "debug process" | ||||||
|     privilege_id = win32security.LookupPrivilegeValue (None, win32security.SE_DEBUG_NAME) |     privilege_id = win32security.LookupPrivilegeValue(None, | ||||||
|     old_privs = win32security.AdjustTokenPrivileges (hToken, 0, [(privilege_id, win32security.SE_PRIVILEGE_ENABLED)]) |                                                       win32security.SE_DEBUG_NAME) | ||||||
|  |     old_privs = win32security.AdjustTokenPrivileges(hToken, 0, | ||||||
|  |                                                     [(privilege_id, | ||||||
|  |                                                       win32security.SE_PRIVILEGE_ENABLED)]) | ||||||
|      |      | ||||||
|     # Open the process, and query it's filename |     # Open the process, and query it's filename | ||||||
|     processid = win32process.GetWindowThreadProcessId(hwnd) |     processid = win32process.GetWindowThreadProcessId(hwnd) | ||||||
|     pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, False, processid[1]) |     pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | | ||||||
|  |                                     win32con.PROCESS_VM_READ, False, | ||||||
|  |                                     processid[1]) | ||||||
|  |     try: | ||||||
|         exename = win32process.GetModuleFileNameEx(pshandle, 0) |         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 |         # clean up | ||||||
|         win32api.CloseHandle(pshandle) |         win32api.CloseHandle(pshandle) | ||||||
|         win32api.CloseHandle(hToken) |         win32api.CloseHandle(hToken) | ||||||
|  | @ -305,6 +321,8 @@ def decode_windows(c, title, hwnd): | ||||||
|     info['width']  = int( width ) - 2*b_width |     info['width']  = int( width ) - 2*b_width | ||||||
|     info['height'] = int( height ) - b_width - tb_height |     info['height'] = int( height ) - b_width - tb_height | ||||||
|     info['exe']    = get_nt_exe(hwnd) |     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']) |     title_bits = re.split(' - ', info['title']) | ||||||
|     info['name'] = title_bits[0] |     info['name'] = title_bits[0] | ||||||
|  |  | ||||||
|  | @ -626,6 +626,11 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") | ||||||
|         self.load_profile() |         self.load_profile() | ||||||
|          |          | ||||||
|         self.statusIcon = gtk.StatusIcon() |         self.statusIcon = gtk.StatusIcon() | ||||||
|  |         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_from_stock(gtk.STOCK_HOME) | ||||||
|         self.statusIcon.set_tooltip("Free Poker Database") |         self.statusIcon.set_tooltip("Free Poker Database") | ||||||
|         self.statusIcon.connect('activate', self.statusicon_activate) |         self.statusIcon.connect('activate', self.statusicon_activate) | ||||||
|  | @ -673,6 +678,12 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") | ||||||
|         pass |         pass | ||||||
|      |      | ||||||
|     def statusicon_activate(self, widget, data = None): |     def statusicon_activate(self, widget, data = None): | ||||||
|  |         # 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.show() | ||||||
|             self.window.present() |             self.window.present() | ||||||
|          |          | ||||||
|  |  | ||||||
|  | @ -77,10 +77,11 @@ class fpdb_db: | ||||||
|             import MySQLdb |             import MySQLdb | ||||||
|             if use_pool: |             if use_pool: | ||||||
|                 MySQLdb = pool.manage(MySQLdb, pool_size=5) |                 MySQLdb = pool.manage(MySQLdb, pool_size=5) | ||||||
|             try: | #            try: | ||||||
|                 self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) |             self.db = MySQLdb.connect(host=host, user=user, passwd=password, db=database, use_unicode=True) | ||||||
|             except: |             #TODO: Add port option | ||||||
|                 raise FpdbMySQLFailedError("MySQL connection failed") | #            except: | ||||||
|  | #                raise FpdbMySQLFailedError("MySQL connection failed") | ||||||
|         elif backend==fpdb_db.PGSQL: |         elif backend==fpdb_db.PGSQL: | ||||||
|             import psycopg2 |             import psycopg2 | ||||||
|             import psycopg2.extensions |             import psycopg2.extensions | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -5,7 +5,7 @@ from distutils.core import setup | ||||||
| 
 | 
 | ||||||
| setup(name = 'fpdb', | setup(name = 'fpdb', | ||||||
|     description = 'Free Poker Database', |     description = 'Free Poker Database', | ||||||
|     version = '0.11.3', |     version = '0.12', | ||||||
|     author = 'FPDB team', |     author = 'FPDB team', | ||||||
|     author_email = 'fpdb-main@lists.sourceforge.net', |     author_email = 'fpdb-main@lists.sourceforge.net', | ||||||
|     packages = ['fpdb'], |     packages = ['fpdb'], | ||||||
|  | @ -15,7 +15,9 @@ setup(name = 'fpdb', | ||||||
|             ['docs/readme.txt', 'docs/release-notes.txt', |             ['docs/readme.txt', 'docs/release-notes.txt', | ||||||
|             'docs/tabledesign.html', 'THANKS.txt']), |             'docs/tabledesign.html', 'THANKS.txt']), | ||||||
|         ('/usr/share/pixmaps', |         ('/usr/share/pixmaps', | ||||||
|             ['gfx/fpdb-icon.png']), |             ['gfx/fpdb-icon.png', 'gfx/fpdb-icon2.png', | ||||||
|  |              'gfx/fpdb-cards.png' | ||||||
|  |              ]), | ||||||
|         ('/usr/share/applications', |         ('/usr/share/applications', | ||||||
|             ['files/fpdb.desktop']), |             ['files/fpdb.desktop']), | ||||||
|         ('/usr/share/python-fpdb', |         ('/usr/share/python-fpdb', | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user