Esempio n. 1
0
class Application(BaseApplication.BaseApplication):
    """The application class represents a group of browser windows."""
    def __init__(self, prefs=None, display=None):
        self.root = Tk(className='Grail', screenName=display)
        self.root.withdraw()
        resources = os.path.join(script_dir, "data", "Grail.ad")
        if os.path.isfile(resources):
            self.root.option_readfile(resources, "startupFile")
        BaseApplication.BaseApplication.__init__(self, prefs)
        # The stylesheet must be initted before any Viewers, so it
        # registers its' prefs callbacks first, hence reloads before the
        # viewers reconfigure w.r.t. the new styles.
        self.stylesheet = Stylesheet.Stylesheet(self.prefs)
        self.load_images = 1  # Overridden by cmd line or pref.

        # socket management
        sockets = self.prefs.GetInt('sockets', 'number')
        self.sq = SocketQueue(sockets)
        self.prefs.AddGroupCallback('sockets',
                                    lambda self=self: \
                                    self.sq.change_max(
                                        self.prefs.GetInt('sockets',
                                                          'number')))

        # initialize on_exit_methods before global_history
        self.on_exit_methods = []
        self.global_history = GlobalHistory.GlobalHistory(self)
        self.login_cache = {}
        self.rexec_cache = {}
        self.url_cache = CacheManager(self)
        self.image_cache = ImageCache(self.url_cache)
        self.auth = AuthenticationManager(self)
        self.root.report_callback_exception = self.report_callback_exception
        if sys.stdin.isatty():
            # only useful if stdin might generate KeyboardInterrupt
            self.keep_alive()
        self.browsers = []
        self.iostatuspanel = None
        self.in_exception_dialog = None
        from ancillary import Greek
        for k, v in Greek.entitydefs.items():
            Application.dingbatimages[k] = (v, '_sym')
        self.root.bind_class("Text", "<Alt-Left>", self.dummy_event)
        self.root.bind_class("Text", "<Alt-Right>", self.dummy_event)

    def dummy_event(self, event):
        pass

    def register_on_exit(self, method):
        self.on_exit_methods.append(method)

    def unregister_on_exit(self, method):
        try:
            self.on_exit_methods.remove(method)
        except ValueError:
            pass

    def exit_notification(self):
        for m in self.on_exit_methods[:]:
            try:
                m()
            except:
                pass

    def add_browser(self, browser):
        self.browsers.append(browser)

    def del_browser(self, browser):
        try:
            self.browsers.remove(browser)
        except ValueError:
            pass

    def quit(self):
        self.root.quit()

    def open_io_status_panel(self):
        if not self.iostatuspanel:
            from ancillary import IOStatusPanel
            self.iostatuspanel = IOStatusPanel.IOStatusPanel(self)
        else:
            self.iostatuspanel.reopen()

    def maybe_quit(self):
        if not (self.embedded or self.browsers):
            self.quit()

    def go(self):
        try:
            try:
                if ilu_tk:
                    ilu_tk.RunMainLoop()
                else:
                    self.root.mainloop()
            except KeyboardInterrupt:
                pass
        finally:
            self.exit_notification()

    def keep_alive(self):
        # Exercise the Python interpreter regularly so keyboard
        # interrupts get through
        self.root.tk.createtimerhandler(KEEPALIVE_TIMER, self.keep_alive)

    def get_cached_image(self, url):
        return self.image_cache.get_image(url)

    def set_cached_image(self, url, image, owner=None):
        self.image_cache.set_image(url, image, owner)

    def open_url(self, url, method, params, reload=0, data=None):
        api = self.url_cache.open(url, method, params, reload, data=data)
        api._url_ = url
        return api

    def open_url_simple(self, url):
        api = self.open_url(url, 'GET', {})
        errcode, errmsg, meta = api.getmeta()
        if errcode != 200:
            raise IOError(('url open error', errcode, errmsg, meta))
        return URLReadWrapper(api, meta)

    def get_cache_keys(self):
        """For applets."""
        return self.url_cache.items.keys()

    def decode_pipeline(self, fp, content_encoding, error=1):
        if self.decode_prog.has_key(content_encoding):
            prog = self.decode_prog[content_encoding]
            if not prog: return fp
            tfn = tempfile.mktemp()
            ok = 0
            try:
                temp = open(tfn, 'w')
                BUFSIZE = 8192
                while 1:
                    buf = fp.read(BUFSIZE)
                    if not buf: break
                    temp.write(buf)
                temp.close()
                ok = 1
            finally:
                if not ok:
                    try:
                        os.unlink(tfn)
                    except os.error:
                        pass
            pipeline = '%s <%s; rm -f %s' % (prog, tfn, tfn)
            # XXX What if prog fails?
            return os.popen(pipeline, 'r')
        if error:
            self.error_dialog(
                IOError,
                "Can't decode content-encoding: %s" % content_encoding)
        return None

    decode_prog = {
        'gzip': 'gzip -d',
        'x-gzip': 'gzip -d',
        'compress': 'compress -d',
        'x-compress': 'compress -d',
    }

    def exception_dialog(self, message="", root=None):
        exc, val, tb = sys.exc_type, sys.exc_value, sys.exc_traceback
        self.exc_dialog(message, exc, val, tb, root)

    def report_callback_exception(self, exc, val, tb, root=None):
        self.exc_dialog("in a callback function", exc, val, tb, root)

    def exc_dialog(self, message, exc, val, tb, root=None):
        if self.in_exception_dialog:
            print()
            print("*** Recursive exception", message)
            import traceback
            traceback.print_exception(exc, val, tb)
            return
        self.in_exception_dialog = 1

        def f(s=self, m=message, e=exc, v=val, t=tb, root=root):
            s._exc_dialog(m, e, v, t, root)

        if TkVersion >= 4.1:
            self.root.after_idle(f)
        else:
            self.root.after(0, f)

    def _exc_dialog(self, message, exc, val, tb, root=None):
        # XXX This needn't be a modal dialog --
        # XXX should SafeDialog be changed to support callbacks?
        from utils import SafeDialog
        msg = "An exception occurred " + str(message) + " :\n"
        msg = msg + str(exc) + " : " + str(val)
        dlg = SafeDialog.Dialog(
            root or self.root,
            text=msg,
            title="Python Exception: " + str(exc),
            bitmap='error',
            default=0,
            strings=("OK", "Show traceback"),
        )
        self.in_exception_dialog = 0
        if dlg.num == 1:
            self.traceback_dialog(exc, val, tb)

    def traceback_dialog(self, exc, val, tb):
        # XXX This could actually just create a new Browser window...
        from utils import TbDialog
        TbDialog.TracebackDialog(self.root, exc, val, tb)

    def error_dialog(self, exc, msg, root=None):
        # Display an error dialog.
        # Return when the user clicks OK
        # XXX This needn't be a modal dialog
        from utils import SafeDialog
        if type(msg) in (List, Tuple):
            s = ''
            for item in msg:
                s = s + ':\n' + str(item)
            msg = s[2:]
        else:
            msg = str(msg)
        SafeDialog.Dialog(
            root or self.root,
            text=msg,
            title="Error: " + str(exc),
            bitmap='error',
            default=0,
            strings=('OK', ),
        )

    dingbatimages = {
        'ldots': ('...', None),  # math stuff
        'sp': (' ', None),
        'hairsp': ('\240', None),
        'thinsp': ('\240', None),
        'emdash': ('--', None),
        'endash': ('-', None),
        'mdash': ('--', None),
        'ndash': ('-', None),
        'ensp': (' ', None)
    }

    def clear_dingbat(self, entname):
        if self.dingbatimages.has_key(entname):
            del self.dingbatimages[entname]

    def set_dingbat(self, entname, entity):
        self.dingbatimages[entname] = entity

    def load_dingbat(self, entname):
        if self.dingbatimages.has_key(entname):
            return self.dingbatimages[entname]
        gifname = grailutil.which(entname + '.gif', self.iconpath)
        if gifname:
            img = PhotoImage(file=gifname, master=self.root)
            self.dingbatimages[entname] = img
            return img
        self.dingbatimages[entname] = None
        return None
Esempio n. 2
0
class Application(BaseApplication.BaseApplication):

    """The application class represents a group of browser windows."""

    def __init__(self, prefs=None, display=None):
        self.root = Tk(className='Grail', screenName=display)
        self.root.withdraw()
        resources = os.path.join(script_dir, "data", "Grail.ad")
        if os.path.isfile(resources):
            self.root.option_readfile(resources, "startupFile")
        BaseApplication.BaseApplication.__init__(self, prefs)
        # The stylesheet must be initted before any Viewers, so it
        # registers its' prefs callbacks first, hence reloads before the
        # viewers reconfigure w.r.t. the new styles.
        self.stylesheet = Stylesheet.Stylesheet(self.prefs)
        self.load_images = 1            # Overridden by cmd line or pref.

        # socket management
        sockets = self.prefs.GetInt('sockets', 'number')
        self.sq = SocketQueue(sockets)
        self.prefs.AddGroupCallback('sockets',
                                    lambda self=self: \
                                    self.sq.change_max(
                                        self.prefs.GetInt('sockets',
                                                          'number')))

        # initialize on_exit_methods before global_history
        self.on_exit_methods = []
        self.global_history = GlobalHistory.GlobalHistory(self)
        self.login_cache = {}
        self.rexec_cache = {}
        self.url_cache = CacheManager(self)
        self.image_cache = ImageCache(self.url_cache)
        self.auth = AuthenticationManager(self)
        self.root.report_callback_exception = self.report_callback_exception
        if sys.stdin.isatty():
            # only useful if stdin might generate KeyboardInterrupt
            self.keep_alive()
        self.browsers = []
        self.iostatuspanel = None
        self.in_exception_dialog = None
        import Greek
        for k, v in Greek.entitydefs.items():
            Application.dingbatimages[k] = (v, '_sym')
        self.root.bind_class("Text", "<Alt-Left>", self.dummy_event)
        self.root.bind_class("Text", "<Alt-Right>", self.dummy_event)

    def dummy_event(self, event):
        pass

    def register_on_exit(self, method):
        self.on_exit_methods.append(method)
    def unregister_on_exit(self, method):
        try: self.on_exit_methods.remove(method)
        except ValueError: pass
    def exit_notification(self):
        for m in self.on_exit_methods[:]:
            try: m()
            except: pass

    def add_browser(self, browser):
        self.browsers.append(browser)

    def del_browser(self, browser):
        try: self.browsers.remove(browser)
        except ValueError: pass

    def quit(self):
        self.root.quit()

    def open_io_status_panel(self):
        if not self.iostatuspanel:
            import IOStatusPanel
            self.iostatuspanel = IOStatusPanel.IOStatusPanel(self)
        else:
            self.iostatuspanel.reopen()

    def maybe_quit(self):
        if not (self.embedded or self.browsers):
            self.quit()

    def go(self):
        try:
            try:
                if ilu_tk:
                    ilu_tk.RunMainLoop()
                else:
                    self.root.mainloop()
            except KeyboardInterrupt:
                pass
        finally:
            self.exit_notification()

    def keep_alive(self):
        # Exercise the Python interpreter regularly so keyboard
        # interrupts get through
        self.root.tk.createtimerhandler(KEEPALIVE_TIMER, self.keep_alive)

    def get_cached_image(self, url):
        return self.image_cache.get_image(url)

    def set_cached_image(self, url, image, owner=None):
        self.image_cache.set_image(url, image, owner)

    def open_url(self, url, method, params, reload=0, data=None):
        api = self.url_cache.open(url, method, params, reload, data=data)
        api._url_ = url
        return api

    def open_url_simple(self, url):
        api = self.open_url(url, 'GET', {})
        errcode, errmsg, meta = api.getmeta()
        if errcode != 200:
            raise IOError, ('url open error', errcode, errmsg, meta)
        return URLReadWrapper(api, meta)

    def get_cache_keys(self):
        """For applets."""
        return self.url_cache.items.keys()

    def decode_pipeline(self, fp, content_encoding, error=1):
        if self.decode_prog.has_key(content_encoding):
            prog = self.decode_prog[content_encoding]
            if not prog: return fp
            tfn = tempfile.mktemp()
            ok = 0
            try:
                temp = open(tfn, 'w')
                BUFSIZE = 8192
                while 1:
                        buf = fp.read(BUFSIZE)
                        if not buf: break
                        temp.write(buf)
                temp.close()
                ok = 1
            finally:
                if not ok:
                    try:
                        os.unlink(tfn)
                    except os.error:
                        pass
            pipeline = '%s <%s; rm -f %s' % (prog, tfn, tfn)
            # XXX What if prog fails?
            return os.popen(pipeline, 'r')
        if error:
            self.error_dialog(IOError,
                "Can't decode content-encoding: %s" % content_encoding)
        return None

    decode_prog = {
        'gzip': 'gzip -d',
        'x-gzip': 'gzip -d',
        'compress': 'compress -d',
        'x-compress': 'compress -d',
        }

    def exception_dialog(self, message="", root=None):
        exc, val, tb = sys.exc_type, sys.exc_value, sys.exc_traceback
        self.exc_dialog(message, exc, val, tb, root)

    def report_callback_exception(self, exc, val, tb, root=None):
        self.exc_dialog("in a callback function", exc, val, tb, root)

    def exc_dialog(self, message, exc, val, tb, root=None):
        if self.in_exception_dialog:
            print
            print "*** Recursive exception", message
            import traceback
            traceback.print_exception(exc, val, tb)
            return
        self.in_exception_dialog = 1
        def f(s=self, m=message, e=exc, v=val, t=tb, root=root):
            s._exc_dialog(m, e, v, t, root)
        if TkVersion >= 4.1:
            self.root.after_idle(f)
        else:
            self.root.after(0, f)

    def _exc_dialog(self, message, exc, val, tb, root=None):
        # XXX This needn't be a modal dialog --
        # XXX should SafeDialog be changed to support callbacks?
        import SafeDialog
        msg = "An exception occurred " + str(message) + " :\n"
        msg = msg + str(exc) + " : " + str(val)
        dlg = SafeDialog.Dialog(root or self.root,
                                text=msg,
                                title="Python Exception: " + str(exc),
                                bitmap='error',
                                default=0,
                                strings=("OK", "Show traceback"),
                                )
        self.in_exception_dialog = 0
        if dlg.num == 1:
            self.traceback_dialog(exc, val, tb)

    def traceback_dialog(self, exc, val, tb):
        # XXX This could actually just create a new Browser window...
        import TbDialog
        TbDialog.TracebackDialog(self.root, exc, val, tb)

    def error_dialog(self, exc, msg, root=None):
        # Display an error dialog.
        # Return when the user clicks OK
        # XXX This needn't be a modal dialog
        import SafeDialog
        if type(msg) in (ListType, TupleType):
            s = ''
            for item in msg:
                s = s + ':\n' + str(item)
            msg = s[2:]
        else:
            msg = str(msg)
        SafeDialog.Dialog(root or self.root,
                      text=msg,
                      title="Error: " + str(exc),
                      bitmap='error',
                      default=0,
                      strings=('OK',),
                      )

    dingbatimages = {'ldots': ('...', None),    # math stuff
                     'sp': (' ', None),
                     'hairsp': ('\240', None),
                     'thinsp': ('\240', None),
                     'emdash': ('--', None),
                     'endash': ('-', None),
                     'mdash': ('--', None),
                     'ndash': ('-', None),
                     'ensp': (' ', None)
                     }

    def clear_dingbat(self, entname):
        if self.dingbatimages.has_key(entname):
            del self.dingbatimages[entname]

    def set_dingbat(self, entname, entity):
        self.dingbatimages[entname] = entity

    def load_dingbat(self, entname):
        if self.dingbatimages.has_key(entname):
            return self.dingbatimages[entname]
        gifname = grailutil.which(entname + '.gif', self.iconpath)
        if gifname:
            img = PhotoImage(file=gifname, master=self.root)
            self.dingbatimages[entname] = img
            return img
        self.dingbatimages[entname] = None
        return None