Browser.py :  » Network » Grail-Internet-Browser » grail-0.6 » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Network » Grail Internet Browser 
Grail Internet Browser » grail 0.6 » Browser.py
"""Browser class."""


import os
import string
import sys
import grailutil

from Tkinter import *
import tktools

from Viewer import Viewer


LOGO_IMAGES = "logo:"
FIRST_LOGO_IMAGE = LOGO_IMAGES + "T1.gif"


# Window title prefix
TITLE_PREFIX = "Grail: "


# If we have an icon file, replace tktools.make_toplevel so that it gets
# set up as the icon, otherwise don't do anything magic.
#
_mydir = os.path.dirname(grailutil.abspath(__file__))
_iconxbm_file = grailutil.which(
    'icon.xbm', (_mydir, os.path.join(_mydir, "data")))
if _iconxbm_file:
    _iconmask_file = os.path.join(os.path.dirname(_iconxbm_file),
                                  "iconmask.xbm")
    if not os.path.isfile(_iconmask_file):
        _iconmask_file = None
    def make_toplevel(*args, **kw):
        w = apply(tktools_make_toplevel, args, kw)
        # icon set up
        try: w.iconbitmap('@' + _iconxbm_file)
        except TclError: pass
        if _iconmask_file:
            try: w.iconmask('@' + _iconmask_file)
            except TclError: pass
        return w
    #
    tktools_make_toplevel = tktools.make_toplevel
    tktools.make_toplevel = make_toplevel


class Browser:
    """The Browser class provides the top-level GUI.

    It is a blatant rip-off of Mosaic's look and feel, with menus, a
    stop button, a URL display/entry area, and (last but not least) a
    viewer area.  But then, so are all other web browsers. :-)

    """
    def __init__(self, master, app=None,
                 width=None, height=None,
                 geometry=None):
        self.master = master
        if not app:
            app = grailutil.get_grailapp()
        prefs = app.prefs
        self.app = app

        if not width: width = prefs.GetInt('browser', 'default-width')
        if not height: height = prefs.GetInt('browser', 'default-height')

        self.create_widgets(width=width, height=height, geometry=geometry)
        self.root.iconname('Grail')
        app.add_browser(self)

    def create_widgets(self, width, height, geometry):
        # I'd like to be able to set the widget name here, but I'm not
        # sure what the correct thing to do is.  Setting it to `grail'
        # is definitely *not* the right thing to do since this causes
        # all sorts of problems.
        self.root = tktools.make_toplevel(self.master, class_='Grail')
        self._window_title("Grail: New Browser")
        if geometry:
            self.root.geometry(geometry)
        self.root.protocol("WM_DELETE_WINDOW", self.on_delete)
        self.topframe = Frame(self.root)
        self.topframe.pack(fill=X)
        self.create_logo()
        self.create_menubar()
        self.create_urlbar()
        self.create_statusbar()
        self.viewer = Viewer(self.root, browser=self,
                             width=width, height=height)
        self.context = self.viewer.context
        if self.app.prefs.GetBoolean('browser', 'show-logo'):
            self.logo_init()

    def create_logo(self):
        self.logo = Button(self.root, name="logo",
                           command=self.stop_command,
                           state=DISABLED)
        self.logo.pack(side=LEFT, fill=BOTH, padx=10, pady=10,
                       in_=self.topframe)
        self.root.bind("<Alt-period>", self.stop_command)
        self.logo_animate = 0

    def create_menubar(self):
        # Create menu bar, menus, and menu entries

        # Create menu bar
        self.mbar = Menu(self.root, name="menubar", tearoff=0)
        self.root.config(menu=self.mbar)

        # Create the menus
        self.create_menu("file")
        self.create_menu("go")
        self.histmenu = self.gomenu     # backward compatibility for Ping
        self.create_menu("search")
        self.create_menu("bookmarks")
        self.create_menu("preferences")

        # List of user menus (reset on page load)
        self.user_menus = []

        if self.get_helpspec():
            self.create_menu("help")

    def create_menu(self, name):
        menu = Menu(self.mbar, name=name)
        self.mbar.add_cascade(label=string.capitalize(name), menu=menu)
        setattr(self, name + "menu", menu)
        getattr(self, "create_menu_" + name)(menu)

    def _menucmd(self, menu, label, accelerator, command):
        if not accelerator:
            menu.add_command(label=label, command=command)
            return
        underline = None
        if len(accelerator) == 1:
            # do a lot to determine the underline position
            underline = string.find(label, accelerator)
            if underline == -1:
                accelerator = string.lower(accelerator)
                underline = string.find(label, accelerator)
                if underline == -1:
                    underline = None
                accelerator = string.upper(accelerator)
        menu.add_command(label=label, command=command, underline=underline,
                         accelerator="Alt-" + accelerator)
        self.root.bind("<Alt-%s>" % accelerator, command)
        if len(accelerator) == 1:
            self.root.bind("<Alt-%s>" % string.lower(accelerator), command)

    def create_menu_file(self, menu):
        self._menucmd(menu, "New Window", "N", self.new_command)
        self._menucmd(menu, "Clone Current Window", "K", self.clone_command)
        self._menucmd(menu, "View Source", "V", self.view_source_command)
        self._menucmd(menu, 'Open Location...', "L", self.open_uri_command)
        self._menucmd(menu, 'Open File...', "O", self.open_file_command)
        self._menucmd(menu, 'Open Selection', "E",
                      self.open_selection_command)
        menu.add_separator()
        self._menucmd(menu, "Save As...", "S", self.save_as_command)
        self._menucmd(menu, "Print...", "P", self.print_command)
        import DocumentInfo
        self._menucmd(menu, "Document Info...", "D",
                      DocumentInfo.DocumentInfoCommand(self))
        menu.add_separator()
        self._menucmd(menu, "I/O Status Panel...", "I", self.iostatus_command)
        menu.add_separator()
        self._menucmd(menu, "Close", "W", self.close_command),
        if not self.app.embedded:
            self._menucmd(menu, "Quit", "Q", self.quit_command)

    def create_menu_go(self, menu):
        self._menucmd(menu, "Back", "Left", self.back_command)
        self._menucmd(menu, "Forward", "Right", self.forward_command)
        self._menucmd(menu, "Reload", "R", self.reload_command)
        menu.add_separator()
        self._menucmd(menu, 'History...', "H", self.show_history_command)
        self._menucmd(menu, "Home", None, self.home_command)

    def create_menu_search(self, menu):
        menu.grail_browser = self       # Applet compatibility
        import SearchMenu
        SearchMenu.SearchMenu(menu, self.root, self)

    def create_menu_bookmarks(self, menu):
        menu.grail_browser = self # Applet compatibility
        import BookmarksGUI
        self.bookmarksmenu_menu = BookmarksGUI.BookmarksMenu(menu)

    def create_menu_preferences(self, menu):
        from PrefsPanels import PrefsPanelsMenu
        PrefsPanelsMenu(menu, self)

    def create_menu_help(self, menu):
        lines = self.get_helpspec()
        i = 0
        n = len(lines) - 1
        while i < n:
            label = lines[i]
            i = i+1
            if label == '-':
                menu.add_separator()
            else:
                url = lines[i]
                i = i+1
                self._menucmd(menu, label, None, HelpMenuCommand(self, url))

    __helpspec = None
    def get_helpspec(self):
        if self.__helpspec is not None:
            return self.__helpspec
        raw = self.app.prefs.Get('browser', 'help-menu')
        lines = filter(None, map(string.strip, string.split(raw, '\n')))
        lines = map(string.split, lines)
        self.__helpspec = tuple(map(string.join, lines))
        return self.__helpspec

    def create_urlbar(self):
        f = Frame(self.topframe)
        f.pack(fill=X)
        l = Label(self.root, name="uriLabel")
        l.pack(side=LEFT, in_=f)
        self.entry = Entry(self.root, name="uriEntry")
        self.entry.pack(side=LEFT, fill=X, expand=1, in_=f)
        self.entry.bind('<Return>', self.load_from_entry)

    def create_statusbar(self):
        msg_frame = Frame(self.root, name="statusbar")
        msg_frame.pack(fill=X, side=BOTTOM, in_=self.topframe)
        msg_frame.propagate(OFF)
        fontspec = self.app.prefs.Get('presentation', 'message-font')
        fontspec = string.strip(fontspec) or None
        self.msg = Label(self.root, font=fontspec, name="status")
        self.msg.pack(fill=X, in_=msg_frame)

    # --- External interfaces ---

    def get_async_image(self, src):
        # XXX This is here for the 0.2 ImageLoopItem applet only
        return self.context.get_async_image(src)

    def allowstop(self):
        self.logo_start()

    def clearstop(self):
        self.logo_stop()

    def clear_reset(self):
        num = len(self.user_menus)
        if num:
            last = self.mbar.index(END)
            if num > 1:
                self.mbar.delete(last-num+1, last)
            else:
                self.mbar.delete(last)
        for b in self.user_menus:
            b.destroy()
        self.user_menus[:] = []

    def set_url(self, url):
        self.set_entry(url)
        title, when = self.app.global_history.lookup_url(url)
        self.set_title(title or url)

    def set_title(self, title):
        self._window_title(TITLE_PREFIX + title)

    def message(self, string = ""):
        self.msg['text'] = string

    def messagevariable(self, variable=None):
        if variable:
            self.msg['textvariable'] = variable
        else:
            self.msg['textvariable'] = ""
            self.msg['text'] = ""
    message_clear = messagevariable

    def error_dialog(self, exception, msg):
        if self.app:
            self.app.error_dialog(exception, msg, root=self.root)
        else:
            print "ERROR:", msg

    def load(self, *args, **kw):
        """Interface for applets."""
        return apply(self.context.load, args, kw)

    def valid(self):
        return self.app and self in self.app.browsers

    # --- Internals ---

    def _window_title(self, title):
        self.root.title(title)
        self.root.iconname(title)

    def set_entry(self, url):
        self.entry.delete('0', END)
        self.entry.insert(END, url)

    def close(self):
        self.context.stop()
        self.viewer.close()
        self.root.destroy()
        self.bookmarksmenu_menu.close()
        self.bookmarksmenu_menu = None
        if self.app:
            self.app.del_browser(self)
            self.app.maybe_quit()

    # --- Callbacks ---

    # WM_DELETE_WINDOW on toplevel

    def on_delete(self):
        self.close()

    # <Return> in URL entry field

    def load_from_entry(self, event):
        url = string.strip(self.entry.get())
        if url:
            self.context.load(grailutil.complete_url(url))
        else:
            self.root.bell()

    # Stop command

    def stop_command(self, event=None):
        if self.context.busy():
            self.context.stop()
            self.message("Stopped.")

    # File menu commands

    def new_command(self, event=None):
        b = Browser(self.master, self.app)
        return b

    def clone_command(self, event=None):
        b = Browser(self.master, self.app)
        b.context.clone_history_from(self.context)
        return b

    def open_uri_command(self, event=None):
        import OpenURIDialog
        dialog = OpenURIDialog.OpenURIDialog(self.root)
        uri, new = dialog.go()
        if uri:
            if new:
                browser = Browser(self.master, self.app)
            else:
                browser = self
            browser.context.load(grailutil.complete_url(uri))

    def open_file_command(self, event=None):
        import FileDialog
        dialog = FileDialog.LoadFileDialog(self.master)
        filename = dialog.go(key="load")
        if filename:
            import urllib
            self.context.load('file:' + urllib.pathname2url(filename))

    def open_selection_command(self, event=None):
        try:
            selection = self.root.selection_get()
        except TclError:
            self.root.bell()
            return
        uri = string.joinfields(string.split(selection), '')
        self.context.load(grailutil.complete_url(uri))

    def view_source_command(self, event=None):
        self.context.view_source()

    def save_as_command(self, event=None):
        self.context.save_document()

    def print_command(self, event=None):
        self.context.print_document()

    def iostatus_command(self, event=None):
        self.app.open_io_status_panel()

    def close_command(self, event=None):
        # File/Close
        self.close()

    def quit_command(self, event=None):
        # File/Quit
        if self.app: self.app.quit()
        else: self.close()

    # History menu commands

    def home_command(self, event=None):
        home = self.app.prefs.Get('landmarks', 'home-page')
        if not home:
            home = self.app.prefs.Get('landmarks', 'default-home-page')
        self.context.load(home)

    def reload_command(self, event=None):
        self.context.reload_page()

    def forward_command(self, event=None):
        self.context.go_forward()

    def back_command(self, event=None):
        self.context.go_back()

    def show_history_command(self, event=None):
        self.context.show_history_dialog()

    # --- Animated logo ---

    def logo_init(self):
        """Initialize animated logo and display the first image.

        This doesn't start the animation sequence -- use logo_start()
        for that.

        """
        self.logo_index = 0             # Currently displayed image
        self.logo_last = -1             # Last image; -1 if unknown
        self.logo_id = None             # Tk id of timer callback
        self.logo_animate = 1           # True if animating
        self.logo_next()

    def logo_next(self):
        """Display the next image in the logo animation sequence.

        If the first image can't be found, disable animation.

        """
        self.logo_index = self.logo_index + 1
        if self.logo_last > 0 and self.logo_index > self.logo_last:
            self.logo_index = 1
        entytyname = "grail.logo.%d" % self.logo_index
        image = self.app.load_dingbat(entytyname)
        if not image:
            if self.logo_index == 1:
                self.logo_animate = 0
                return
            self.logo_index = 1
            entytyname = "grail.logo.%d" % self.logo_index
            image = self.app.load_dingbat(entytyname)
            if not image:
                self.logo_animate = 0
                return
        self.logo.config(image=image, state=NORMAL)

    def logo_start(self):
        """Start logo animation.

        If we can't/don't animate the logo, enable the stop button instead.

        """
        self.logo.config(state=NORMAL)
        if not self.logo_animate:
            return
        if not self.logo_id:
            self.logo_index = 0
            self.logo_next()
            self.logo_id = self.root.after(200, self.logo_update)

    def logo_stop(self):
        """Stop logo animation.

        If we can't/don't animate the logo, disable the stop button instead.

        """
        if not self.logo_animate:
            self.logo.config(state=DISABLED)
            return
        if self.logo_id:
            self.root.after_cancel(self.logo_id)
            self.logo_id = None
        self.logo_index = 0
        self.logo_next()

    def logo_update(self):
        """Keep logo animation going."""
        self.logo_id = None
        if self.logo_animate:
            self.logo_next()
            if self.logo_animate:
                self.logo_id = self.root.after(200, self.logo_update)

    # --- API for searching ---

    def search_for_pattern(self, pattern,
                           regex_flag, case_flag, backwards_flag):
        textwidget = self.viewer.text
        try:
            index = textwidget.index(SEL_FIRST)
            index = '%s + %s chars' % (str(index),
                                       backwards_flag and '0' or '1')
        except TclError:
            index = '1.0'
        length = IntVar(textwidget)
        hitlength = None
        hit = textwidget.search(pattern, index, count=length,
                                nocase=not case_flag,
                                regexp=regex_flag,
                                backwards=backwards_flag)
        if hit:
            try:
                textwidget.tag_remove(SEL, SEL_FIRST, SEL_LAST)
            except TclError:
                pass
            hitlength = length.get()
            textwidget.tag_add(SEL, hit, "%s + %s chars" % (hit, hitlength))
            textwidget.yview_pickplace(SEL_FIRST)
        return hit


class HelpMenuCommand:
    """Encapsulate a menu item into a callable object to load the resource.
    """
    def __init__(self, browser, url):
        self.__browser = browser
        self.__url = url

    def __call__(self, event=None):
        self.__browser.context.load(self.__url)


def test():
    """Test Browser class."""
    import sys
    url = None
    if sys.argv[1:]: url = sys.argv[1]
    root = Tk()
    b = Browser(root)
    if url: b.load(url)
    root.mainloop()


if __name__ == '__main__':
    test()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.