home *** CD-ROM | disk | FTP | other *** search
/ Chip 2006 June / CHIP 2006-06.2.iso / program / freeware / Democracy-0.8.2.exe / xulrunner / python / frontend_implementation / UIBackendDelegate.py < prev    next >
Encoding:
Python Source  |  2006-04-10  |  8.4 KB  |  202 lines

  1. from frontend_implementation.HTMLDisplay import execChromeJS
  2. from random import randint
  3. from threading import Event
  4. from urllib import unquote
  5. from util import quoteJS
  6. import config
  7. import os
  8. import subprocess
  9. import time
  10. import resource
  11. import webbrowser
  12. import sys
  13. import _winreg
  14. import ctypes
  15.  
  16. ###############################################################################
  17. #### 'Delegate' objects for asynchronously asking the user questions       ####
  18. ###############################################################################
  19.  
  20. def dispatchResultByCookie(cookie, url):
  21.     UIBackendDelegate.returnValues[cookie] = unquote(url)
  22.     UIBackendDelegate.events[cookie].set()
  23.  
  24. #FIXME: is this sufficient?
  25. def generateCookie():
  26.     return str(randint(1000000000,9999999999))
  27.  
  28. class UIBackendDelegate:
  29.  
  30.     events = {}
  31.     returnValues ={}
  32.  
  33.     def initializeReturnEvent(self):
  34.         """Set up the data structures to listen for a return event
  35.         from XUL"""
  36.  
  37.         cookie = generateCookie()
  38.         UIBackendDelegate.events[cookie] = Event()
  39.         return cookie
  40.  
  41.     def getReturnValue(self, cookie):
  42.         """Block until the frontend gives us a return value, then
  43.         return it"""
  44.  
  45.         UIBackendDelegate.events[cookie].wait()
  46.         retval = UIBackendDelegate.returnValues[cookie]
  47.         del UIBackendDelegate.events[cookie]
  48.         del UIBackendDelegate.returnValues[cookie]
  49.         return retval
  50.  
  51.     # Private function to pop up a dialog asking a yes no question
  52.     # Returns true or false
  53.     def yesNoPrompt(self, title, text):
  54.         cookie = self.initializeReturnEvent()
  55.         title = quoteJS(title)
  56.         text = quoteJS(text)
  57.         execChromeJS(("showYesNoDialog('%s','%s','%s');" % (cookie,title, text)))
  58.         print "Yes/no dialog displayed"
  59.         ret = (str(self.getReturnValue(cookie)) != "0")
  60.         print "Dialog return is %s" % ret
  61.         return ret
  62.  
  63.     def getHTTPAuth(self, url, domain, prefillUser = None, prefillPassword = None):
  64.         """Ask the user for HTTP login information for a location, identified
  65.         to the user by its URL and the domain string provided by the
  66.         server requesting the authorization. Default values can be
  67.         provided for prefilling the form. If the user submits
  68.         information, it's returned as a (user, password)
  69.         tuple. Otherwise, if the user presses Cancel or similar, None
  70.         is returned."""
  71.         cookie = self.initializeReturnEvent()
  72.         message = "%s requires a username and password for \"%s\"." % (url, domain)
  73.         message = quoteJS(message)
  74.         execChromeJS("showPasswordDialog('%s','%s');" % (cookie, message))
  75.  
  76.         ret = self.getReturnValue(cookie)
  77.         if (len(ret) == 0):
  78.             return None
  79.  
  80.         # FIXME find a saner way of marshalling data
  81.         # Currently, the pair of strings is separated by "|", escaped by "\\"
  82.         ret = ret.split("|",1)
  83.         while ((len(ret[0])>0) and (ret[0][-1] == "\\") and 
  84.                (len(ret[0]) == 1 or ret[0][-2] != "\\")):
  85.             temp = ret.pop(0)
  86.             ret[0] = temp + '|' + ret[0]
  87.         while ((len(ret[1])>0) and (ret[1][-1] == "\\") and 
  88.                (len(ret[1]) == 1 or ret[1][-2] != "\\")):
  89.             temp = ret.pop(1)
  90.             ret[1] = temp + '|' + ret[1]
  91.         user = ret[0].replace("\\|","|").replace("\\\\","\\")
  92.         password = ret[1].replace("\\|","|").replace("\\\\","\\")
  93.         #print "Username is (%s)" % user
  94.         #print "Password is (%s)" % password
  95.         return (user, password)
  96.  
  97.     def isScrapeAllowed(self, url):
  98.         """Tell the user that URL wasn't a valid feed and ask if it should be
  99.         scraped for links instead. Returns True if the user gives
  100.         permission, or False if not."""
  101.         cookie = self.initializeReturnEvent()
  102.         url = quoteJS(url)
  103.         execChromeJS(("showIsScrapeAllowedDialog('%s','%s');" % (cookie,url)))
  104.         return (str(self.getReturnValue(cookie)) != "0")
  105.  
  106.     def updateAvailable(self, url):
  107.         """Tell the user that an update is available and ask them if they'd
  108.         like to download it now"""
  109.         title = "%s Version Alert" % (config.get(config.SHORT_APP_NAME), )
  110.         message = "A new version of %s is available. Would you like to download it now?" % (config.get(config.LONG_APP_NAME), )
  111.         download = self.yesNoPrompt(title, message)
  112.         if download:
  113.             self.openExternalURL(url)
  114.  
  115.     def dtvIsUpToDate(self):
  116.         execChromeJS("alert('%s is up to date.');" % \
  117.                      (quoteJS(config.get(config.LONG_APP_NAME)), ))
  118.  
  119.     def saveFailed(self, reason):
  120.         message = u"%s was unable to save its database. Recent changes may be lost %s" % \
  121.                      (config.get(config.SHORT_APP_NAME), reason)
  122.         execChromeJS("alert('%s');" % quoteJS(message))
  123.  
  124.     def validateFeedRemoval(self, feedTitle):
  125.         summary = u'Remove Channel'
  126.         message = u'Are you sure you want to remove the channel \'%s\'? This operation cannot be undone.' % feedTitle
  127.         buttons = (u'Remove', u'Cancel')
  128.         return self.yesNoPrompt(summary,message)
  129.  
  130.     def openExternalURL(self, url):
  131.         # It looks like the maximum URL length is about 2k. I can't
  132.         # seem to find the exact value
  133.         if len(url) > 2047:
  134.             url = url[:2047]
  135.         try:
  136.             webbrowser.open(url)
  137.         except webbrowser.Error:
  138.             util.failedExn("while opening %s in a new window" % url)
  139.  
  140.     def updateAvailableItemsCountFeedback(self, count):
  141.         # Inform the user in a way or another that newly available items are
  142.         # available
  143.         # FIXME: When we have a system tray icon, remove that
  144.         pass
  145.  
  146.     def interruptDownloadsAtShutdown(self, downloadsCount):
  147.         summary = u'Are you sure you want to quit?'
  148.         message = u'You have %d download%s still in progress.' % (downloadsCount, downloadsCount > 1 and 's' or '')
  149.         buttons = (u'Quit', u'Cancel')
  150.         return self.yesNoPrompt(summary, message)
  151.  
  152.     def notifyUnkownErrorOccurence(self, when, log = ''):
  153.         execChromeJS("showBugReportDialog('%s', '%s');" % \
  154.                      (quoteJS(when), quoteJS(log)))
  155.         return True
  156.  
  157.     def copyTextToClipboard(self, text):
  158.         execChromeJS("copyTextToClipboard('%s');" % quoteJS(text))
  159.  
  160.     # This is windows specific right now. We don't need it on other platforms
  161.     def setRunAtStartup(self, value):
  162.         if (value):
  163.             filename = os.path.join(resource.resourceRoot(),"..","Democracy.exe")
  164.             filename = os.path.normpath(filename)
  165.             print "Filename is %s" % filename
  166.             folder = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,"Software\Microsoft\Windows\CurrentVersion\Run",0, _winreg.KEY_SET_VALUE)
  167.             _winreg.SetValueEx(folder, "Democracy Player", 0,_winreg.REG_SZ, filename)
  168.         else:
  169.             folder = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,"Software\Microsoft\Windows\CurrentVersion\Run",0, _winreg.KEY_SET_VALUE)
  170.             _winreg.DeleteValue(folder, "Democracy Player")
  171.  
  172.     def launchDownloadDaemon(self, oldpid, port):
  173.         # Kill the old process, if it exists
  174.         if oldpid is not None:
  175.             # This isn't guaranteed to kill the process, but it's likely the
  176.             # best we can do
  177.             # See http://support.microsoft.com/kb/q178893/
  178.             # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/347462
  179.             PROCESS_TERMINATE = 1
  180.             handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, oldpid)
  181.             ctypes.windll.kernel32.TerminateProcess(handle, -1)
  182.             ctypes.windll.kernel32.CloseHandle(handle)
  183.         os.environ['DEMOCRACY_DOWNLOADER_PORT'] = str(port)
  184.  
  185.  
  186.         # Start the downloader.  We use the subprocess module to turn off the
  187.         # console.  One slightly awkward thing is that the current process
  188.         # might not have a valid stdin, so we create a pipe to it that we
  189.         # never actually use.
  190.         downloaderPath = os.path.join(resource.resourceRoot(), "..",
  191.                 "Democracy_Downloader.exe")
  192.         downloaderLog = open(config.get(config.DOWNLOADER_LOG_PATHNAME), 'wt')
  193.         startupinfo = subprocess.STARTUPINFO()
  194.         startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
  195.         try:
  196.             subprocess.Popen(downloaderPath, stdout=downloaderLog,
  197.                     stderr=downloaderLog, 
  198.                     stdin=subprocess.PIPE,
  199.                     startupinfo=startupinfo)
  200.         finally: 
  201.             downloaderLog.close()
  202.