Expanded my entry in contributors.txt.
[fpdb-dooglus.git] / pyfpdb / GuiAutoImport.py
blobc782e4d156cb0ad62167436279c4f88165107776
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
4 #Copyright 2008-2011 Steffen Schaumburg
5 #This program is free software: you can redistribute it and/or modify
6 #it under the terms of the GNU Affero General Public License as published by
7 #the Free Software Foundation, version 3 of the License.
9 #This program is distributed in the hope that it will be useful,
10 #but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 #GNU General Public License for more details.
14 #You should have received a copy of the GNU Affero General Public License
15 #along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #In the "official" distribution you can find the license in agpl-3.0.txt.
18 import L10n
19 _ = L10n.get_translation()
21 import threading
22 import subprocess
23 import traceback
25 import pygtk
26 pygtk.require('2.0')
27 import gtk
28 import gobject
29 import os
30 import sys
31 import time
33 import logging
34 # logging has been set up in fpdb.py or HUD_main.py, use their settings:
35 log = logging.getLogger("importer")
38 import fpdb_import
39 from optparse import OptionParser
40 import Configuration
41 import string
43 if os.name == "nt":
44 import win32console
47 class GuiAutoImport (threading.Thread):
48 def __init__(self, settings, config, sql = None, parent = None, cli = False):
49 self.importtimer = 0
50 self.settings = settings
51 self.config = config
52 self.sql = sql
53 self.parent = parent
55 imp = self.config.get_import_parameters()
57 self.input_settings = {}
58 self.pipe_to_hud = None
60 self.importer = fpdb_import.Importer(self, self.settings, self.config, self.sql)
61 self.importer.setCallHud(True)
62 self.importer.setQuiet(False)
63 self.importer.setFailOnError(False)
64 self.importer.setHandCount(0)
66 self.server = settings['db-host']
67 self.user = settings['db-user']
68 self.password = settings['db-password']
69 self.database = settings['db-databaseName']
71 if cli == False:
72 self.setupGui()
73 else:
74 # TODO: Separate the code that grabs the directories from config
75 # Separate the calls to the Importer API
76 # Create a timer interface that doesn't rely on GTK
77 pass
79 def setupGui(self):
80 self.mainVBox = gtk.VBox(False,1)
82 hbox = gtk.HBox(True, 0) # contains 2 equal vboxes
83 self.mainVBox.pack_start(hbox, False, False, 0)
85 vbox1 = gtk.VBox(True, 0)
86 hbox.pack_start(vbox1, True, True, 0)
87 vbox2 = gtk.VBox(True, 0)
88 hbox.pack_start(vbox2, True, True, 0)
90 self.intervalLabel = gtk.Label(_("Time between imports in seconds:"))
91 self.intervalLabel.set_alignment(xalign=1.0, yalign=0.5)
92 vbox1.pack_start(self.intervalLabel, False, True, 0)
94 hbox = gtk.HBox(False, 0)
95 vbox2.pack_start(hbox, False, True, 0)
96 self.intervalEntry = gtk.Entry()
97 self.intervalEntry.set_text(str(self.config.get_import_parameters().get("interval")))
98 hbox.pack_start(self.intervalEntry, False, False, 0)
99 lbl1 = gtk.Label()
100 hbox.pack_start(lbl1, expand=False, fill=True)
102 lbl = gtk.Label('')
103 vbox1.pack_start(lbl, expand=False, fill=True)
104 lbl = gtk.Label('')
105 vbox2.pack_start(lbl, expand=False, fill=True)
107 self.addSites(vbox1, vbox2)
108 self.textbuffer = gtk.TextBuffer()
109 self.textview = gtk.TextView(self.textbuffer)
111 hbox = gtk.HBox(False, 0)
112 self.mainVBox.pack_start(hbox, expand=True, padding=3)
114 hbox = gtk.HBox(False, 0)
115 self.mainVBox.pack_start(hbox, expand=False, padding=3)
117 lbl1 = gtk.Label()
118 hbox.pack_start(lbl1, expand=True, fill=False)
120 self.doAutoImportBool = False
121 self.startButton = gtk.ToggleButton(_("Start _Auto Import"))
122 self.startButton.connect("clicked", self.startClicked, "start clicked")
123 hbox.pack_start(self.startButton, expand=False, fill=False)
125 self.DetectButton = gtk.Button(_("Detect Directories"))
126 self.DetectButton.connect("clicked", self.detect_hh_dirs, "detect")
127 #hbox.pack_start(self.DetectButton, expand=False, fill=False)
130 lbl2 = gtk.Label()
131 hbox.pack_start(lbl2, expand=True, fill=False)
133 hbox = gtk.HBox(False, 0)
134 hbox.show()
136 self.mainVBox.pack_start(hbox, expand=True, padding=3)
138 scrolledwindow = gtk.ScrolledWindow()
139 scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
140 self.mainVBox.pack_end(scrolledwindow, expand=True)
141 scrolledwindow.add(self.textview)
143 self.mainVBox.show_all()
144 self.addText(_("Auto Import Ready."))
146 def addText(self, text):
147 end_iter = self.textbuffer.get_end_iter()
148 self.textbuffer.insert(end_iter, text)
149 self.textview.scroll_to_mark(self.textbuffer.get_insert(), 0)
152 #end of GuiAutoImport.__init__
153 def browseClicked(self, widget, data):
154 """runs when user clicks one of the browse buttons in the auto import tab"""
155 current_path=data[1].get_text()
157 dia_chooser = gtk.FileChooserDialog(title=_("Please choose the path that you want to Auto Import"),
158 action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
159 buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
160 #dia_chooser.set_current_folder(pathname)
161 dia_chooser.set_filename(current_path)
162 #dia_chooser.set_select_multiple(select_multiple) #not in tv, but want this in bulk import
163 dia_chooser.set_destroy_with_parent(True)
164 dia_chooser.set_transient_for(self.parent)
166 response = dia_chooser.run()
167 if response == gtk.RESPONSE_OK:
168 #print dia_chooser.get_filename(), 'selected'
169 data[1].set_text(dia_chooser.get_filename())
170 self.input_settings[data[0]][0] = dia_chooser.get_filename()
171 elif response == gtk.RESPONSE_CANCEL:
172 #print 'Closed, no files selected'
173 pass
174 dia_chooser.destroy()
175 #end def GuiAutoImport.browseClicked
177 def do_import(self):
178 """Callback for timer to do an import iteration."""
179 if self.doAutoImportBool:
180 self.startButton.set_label(_(u'_Auto Import Running'))
181 self.importer.runUpdated()
182 self.addText(".")
183 #sys.stdout.write(".")
184 #sys.stdout.flush()
185 gobject.timeout_add(1000, self.reset_startbutton)
186 return True
187 return False
189 def reset_startbutton(self):
190 if self.pipe_to_hud is not None:
191 self.startButton.set_label(_(u'Stop _Auto Import'))
192 else:
193 self.startButton.set_label(_(u'Start _Auto Import'))
195 return False
197 def detect_hh_dirs(self, widget, data):
198 """Attempt to find user hand history directories for enabled sites"""
199 the_sites = self.config.get_supported_sites()
200 for site in the_sites:
201 params = self.config.get_site_parameters(site)
202 if params['enabled'] == True:
203 print (_("DEBUG:") + " " + _("Detecting hand history directory for site: '%s'") % site)
204 if os.name == 'posix':
205 if self.posix_detect_hh_dirs(site):
206 #data[1].set_text(dia_chooser.get_filename())
207 self.input_settings[site][0]
208 pass
209 elif os.name == 'nt':
210 # Sorry
211 pass
213 def posix_detect_hh_dirs(self, site):
214 defaults = {
215 'PokerStars': '~/.wine/drive_c/Program Files/PokerStars/HandHistory',
217 if site == 'PokerStars':
218 directory = os.path.expanduser(defaults[site])
219 for file in [file for file in os.listdir(directory) if not file in [".",".."]]:
220 print file
221 return False
223 def startClicked(self, widget, data):
224 """runs when user clicks start on auto import tab"""
226 # Check to see if we have an open file handle to the HUD and open one if we do not.
227 # bufsize = 1 means unbuffered
228 # We need to close this file handle sometime.
230 # TODO: Allow for importing from multiple dirs - REB 29AUG2008
231 # As presently written this function does nothing if there is already a pipe open.
232 # That is not correct. It should open another dir for importing while piping the
233 # results to the same pipe. This means that self.path should be a a list of dirs
234 # to watch.
236 if data == "autostart" or (widget == self.startButton and self.startButton.get_active()):
237 self.startButton.set_active(True)
238 # - Does the lock acquisition need to be more sophisticated for multiple dirs?
239 # (see comment above about what to do if pipe already open)
240 # - Ideally we want to release the lock if the auto-import is killed by some
241 # kind of exception - is this possible?
242 if self.settings['global_lock'].acquire(wait=False, source="AutoImport"): # returns false immediately if lock not acquired
243 self.addText("\n" + _("Global lock taken ... Auto Import Started.")+"\n")
244 self.doAutoImportBool = True
245 self.startButton.set_label(_(u'Stop _Auto Import'))
246 while gtk.events_pending(): # change the label NOW don't wait for the pipe to open
247 gtk.main_iteration(False)
248 if self.pipe_to_hud is None:
249 if self.config.install_method == "exe": # if py2exe, run hud_main.exe
250 path = self.config.fpdb_program_path
251 command = "HUD_main.exe"
252 bs = 0
253 elif os.name == 'nt':
254 path = sys.path[0].replace('\\','\\\\')
255 if win32console.GetConsoleWindow() == 0:
256 command = 'pythonw "'+path+'\\HUD_main.pyw" ' + self.settings['cl_options']
257 else:
258 command = 'python "'+path+'\\HUD_main.pyw" ' + self.settings['cl_options']
259 bs = 0
260 else:
261 command = os.path.join(sys.path[0], 'HUD_main.pyw')
262 command = [command, ] + string.split(self.settings['cl_options'])
263 bs = 1
265 print _("opening pipe to HUD")
266 try:
267 if self.config.install_method == "exe" or (os.name == "nt" and win32console.GetConsoleWindow()) == 0:
268 self.pipe_to_hud = subprocess.Popen(command, bufsize=bs,
269 stdin=subprocess.PIPE,
270 stdout=subprocess.PIPE, # needed for pythonw / py2exe
271 stderr=subprocess.PIPE, # needed for pythonw / py2exe
272 universal_newlines=True
274 else:
275 self.pipe_to_hud = subprocess.Popen(command, bufsize=bs, stdin=subprocess.PIPE, universal_newlines=True)
276 except:
277 err = traceback.extract_tb(sys.exc_info()[2])[-1]
278 #self.addText( "\n*** GuiAutoImport Error opening pipe: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]))
279 self.addText("\n" + _("*** GuiAutoImport Error opening pipe:") + " " + traceback.format_exc() )
280 else:
281 for site in self.input_settings:
282 self.importer.addImportDirectory(self.input_settings[site][0], True, site, self.input_settings[site][1])
283 self.addText("\n * Add "+ site+ " import directory "+ str(self.input_settings[site][0]))
284 self.do_import()
285 interval = int(self.intervalEntry.get_text())
286 if self.importtimer != 0:
287 gobject.source_remove(self.importtimer)
288 self.importtimer = gobject.timeout_add(interval * 1000, self.do_import)
290 else:
291 self.addText(_("\nAuto Import aborted - global lock not available"))
292 else: # toggled off
293 gobject.source_remove(self.importtimer)
294 self.settings['global_lock'].release()
295 self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer
296 self.addText(_("\nStopping Auto Import - global lock released."))
297 if self.pipe_to_hud.poll() is not None:
298 self.addText(_("\n * Stop Auto Import: HUD already terminated"))
299 else:
300 self.pipe_to_hud.terminate()
301 #print >>self.pipe_to_hud.stdin, "\n"
302 # self.pipe_to_hud.communicate('\n') # waits for process to terminate
303 self.pipe_to_hud = None
304 self.startButton.set_label(_(u' Start _Auto Import '))
306 #end def GuiAutoImport.startClicked
308 def get_vbox(self):
309 """returns the vbox of this thread"""
310 return self.mainVBox
311 #end def get_vbox
313 #Create the site line given required info and setup callbacks
314 #enabling and disabling sites from this interface not possible
315 #expects a box to layout the line horizontally
316 def createSiteLine(self, hbox1, hbox2, site, iconpath, hhpath, filter_name, active = True):
317 label = gtk.Label(_("%s auto-import:") % site)
318 hbox1.pack_start(label, False, False, 3)
319 label.show()
321 dirPath=gtk.Entry()
322 dirPath.set_text(hhpath)
323 hbox1.pack_start(dirPath, True, True, 3)
324 dirPath.show()
326 browseButton=gtk.Button(_("Browse..."))
327 browseButton.connect("clicked", self.browseClicked, [site] + [dirPath])
328 hbox2.pack_start(browseButton, False, False, 3)
329 browseButton.show()
331 label = gtk.Label("%s filter:" % site)
332 hbox2.pack_start(label, False, False, 3)
333 label.show()
335 filter=gtk.Entry()
336 filter.set_text(filter_name)
337 hbox2.pack_start(filter, True, True, 3)
338 filter.show()
340 def addSites(self, vbox1, vbox2):
341 the_sites = self.config.get_supported_sites()
342 #log.debug("addSites: the_sites="+str(the_sites))
343 for site in the_sites:
344 pathHBox1 = gtk.HBox(False, 0)
345 vbox1.pack_start(pathHBox1, False, True, 0)
346 pathHBox2 = gtk.HBox(False, 0)
347 vbox2.pack_start(pathHBox2, False, True, 0)
349 params = self.config.get_site_parameters(site)
350 paths = self.config.get_default_paths(site)
351 self.createSiteLine(pathHBox1, pathHBox2, site, False, paths['hud-defaultPath'], params['converter'], params['enabled'])
352 self.input_settings[site] = [paths['hud-defaultPath']] + [params['converter']]
353 #log.debug("addSites: input_settings="+str(self.input_settings))
355 if __name__== "__main__":
356 def destroy(*args): # call back for terminating the main eventloop
357 gtk.main_quit()
359 # settings = {}
360 # settings['db-host'] = "192.168.1.100"
361 # settings['db-user'] = "mythtv"
362 # settings['db-password'] = "mythtv"
363 # settings['db-databaseName'] = "fpdb"
364 # settings['hud-defaultInterval'] = 10
365 # settings['hud-defaultPath'] = 'C:/Program Files/PokerStars/HandHistory/nutOmatic'
366 # settings['callFpdbHud'] = True
368 parser = OptionParser()
369 parser.add_option("-q", "--quiet", action="store_false", dest="gui", default=True, help="don't start gui")
370 (options, argv) = parser.parse_args()
372 config = Configuration.Config()
374 settings = {}
375 if os.name == 'nt': settings['os'] = 'windows'
376 else: settings['os'] = 'linuxmac'
378 settings.update(config.get_db_parameters())
379 settings.update(config.get_import_parameters())
380 settings.update(config.get_default_paths())
382 if(options.gui == True):
383 i = GuiAutoImport(settings, config, None, None)
384 main_window = gtk.Window()
385 main_window.connect('destroy', destroy)
386 main_window.add(i.mainVBox)
387 main_window.show()
388 gtk.main()
389 else:
390 i = GuiAutoImport(settings, config, cli = True)