PyWebKitGtk 1.1.7
[pywebkitgtk.git] / demos / browser.py
blobc6651a4c20bdf6d1d44e76deb858dfee809cbb6b
1 #!/usr/bin/env python
2 # Copyright (C) 2007, 2008, 2009 Jan Michael Alonzo <jmalonzo@gmai.com>
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
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 General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 # TODO:
20 # * fix tab relabelling
21 # * search page interface
22 # * custom button - w/o margins/padding to make tabs thin
25 from gettext import gettext as _
27 import gobject
28 import gtk
29 import pango
30 import webkit
31 from inspector import Inspector
33 ABOUT_PAGE = """
34 <html><head><title>PyWebKitGtk - About</title></head><body>
35 <h1>Welcome to <code>webbrowser.py</code></h1>
36 <p><a
37 href="http://code.google.com/p/pywebkitgtk/">http://code.google.com/p/pywebkitgtk/</a><br/>
38 </p>
39 </body></html>
40 """
42 class BrowserPage(webkit.WebView):
44 def __init__(self):
45 webkit.WebView.__init__(self)
46 settings = self.get_settings()
47 settings.set_property("enable-developer-extras", True)
49 # scale other content besides from text as well
50 self.set_full_content_zoom(True)
52 # make sure the items will be added in the end
53 # hence the reason for the connect_after
54 self.connect_after("populate-popup", self.populate_popup)
56 def populate_popup(self, view, menu):
57 # zoom buttons
58 zoom_in = gtk.ImageMenuItem(gtk.STOCK_ZOOM_IN)
59 zoom_in.connect('activate', zoom_in_cb, view)
60 menu.append(zoom_in)
62 zoom_out = gtk.ImageMenuItem(gtk.STOCK_ZOOM_OUT)
63 zoom_out.connect('activate', zoom_out_cb, view)
64 menu.append(zoom_out)
66 zoom_hundred = gtk.ImageMenuItem(gtk.STOCK_ZOOM_100)
67 zoom_hundred.connect('activate', zoom_hundred_cb, view)
68 menu.append(zoom_hundred)
70 printitem = gtk.ImageMenuItem(gtk.STOCK_PRINT)
71 menu.append(printitem)
72 printitem.connect('activate', print_cb, view)
74 page_properties = gtk.ImageMenuItem(gtk.STOCK_PROPERTIES)
75 menu.append(page_properties)
76 page_properties.connect('activate', page_properties_cb, view)
78 menu.append(gtk.SeparatorMenuItem())
80 aboutitem = gtk.ImageMenuItem(gtk.STOCK_ABOUT)
81 menu.append(aboutitem)
82 aboutitem.connect('activate', about_pywebkitgtk_cb, view)
84 menu.show_all()
85 return False
87 class TabLabel (gtk.HBox):
88 """A class for Tab labels"""
90 __gsignals__ = {
91 "close": (gobject.SIGNAL_RUN_FIRST,
92 gobject.TYPE_NONE,
93 (gobject.TYPE_OBJECT,))
96 def __init__ (self, title, child):
97 """initialize the tab label"""
98 gtk.HBox.__init__(self, False, 4)
99 self.title = title
100 self.child = child
101 self.label = gtk.Label(title)
102 self.label.props.max_width_chars = 30
103 self.label.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
104 self.label.set_alignment(0.0, 0.5)
106 icon = gtk.image_new_from_stock(gtk.STOCK_ORIENTATION_PORTRAIT, gtk.ICON_SIZE_BUTTON)
107 close_image = gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
108 close_button = gtk.Button()
109 close_button.set_relief(gtk.RELIEF_NONE)
110 close_button.connect("clicked", self._close_tab, child)
111 close_button.set_image(close_image)
112 self.pack_start(icon, False, False, 0)
113 self.pack_start(self.label, True, True, 0)
114 self.pack_start(close_button, False, False, 0)
116 self.set_data("label", self.label)
117 self.set_data("close-button", close_button)
118 self.connect("style-set", tab_label_style_set_cb)
120 def set_label (self, text):
121 """sets the text of this label"""
122 self.label.set_label(text)
124 def _close_tab (self, widget, child):
125 self.emit("close", child)
127 def tab_label_style_set_cb (tab_label, style):
128 context = tab_label.get_pango_context()
129 metrics = context.get_metrics(tab_label.style.font_desc, context.get_language())
130 char_width = metrics.get_approximate_digit_width()
131 (width, height) = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU)
132 tab_label.set_size_request(20 * pango.PIXELS(char_width) + 2 * width,
133 pango.PIXELS(metrics.get_ascent() +
134 metrics.get_descent()) + 8)
137 class ContentPane (gtk.Notebook):
139 __gsignals__ = {
140 "focus-view-title-changed": (gobject.SIGNAL_RUN_FIRST,
141 gobject.TYPE_NONE,
142 (gobject.TYPE_OBJECT, gobject.TYPE_STRING,)),
143 "new-window-requested": (gobject.SIGNAL_RUN_FIRST,
144 gobject.TYPE_NONE,
145 (gobject.TYPE_OBJECT,))
148 def __init__ (self):
149 """initialize the content pane"""
150 gtk.Notebook.__init__(self)
151 self.props.scrollable = True
152 self.props.homogeneous = True
153 self.connect("switch-page", self._switch_page)
155 self.show_all()
156 self._hovered_uri = None
158 def load (self, text):
159 """load the given uri in the current web view"""
160 child = self.get_nth_page(self.get_current_page())
161 view = child.get_child()
162 view.open(text)
164 def new_tab_with_webview (self, webview):
165 """creates a new tab with the given webview as its child"""
166 self._construct_tab_view(webview)
168 def new_tab (self, url=None):
169 """creates a new page in a new tab"""
170 # create the tab content
171 browser = BrowserPage()
172 self._construct_tab_view(browser, url)
174 def _construct_tab_view (self, web_view, url=None):
175 web_view.connect("hovering-over-link", self._hovering_over_link_cb)
176 web_view.connect("populate-popup", self._populate_page_popup_cb)
177 web_view.connect("load-finished", self._view_load_finished_cb)
178 web_view.connect("create-web-view", self._new_web_view_request_cb)
179 web_view.connect("title-changed", self._title_changed_cb)
180 inspector = Inspector(web_view.get_web_inspector())
182 scrolled_window = gtk.ScrolledWindow()
183 scrolled_window.props.hscrollbar_policy = gtk.POLICY_AUTOMATIC
184 scrolled_window.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
185 scrolled_window.add(web_view)
186 scrolled_window.show_all()
188 # create the tab
189 label = TabLabel(url, scrolled_window)
190 label.connect("close", self._close_tab)
191 label.show_all()
193 new_tab_number = self.append_page(scrolled_window, label)
194 self.set_tab_label_packing(scrolled_window, False, False, gtk.PACK_START)
195 self.set_tab_label(scrolled_window, label)
197 # hide the tab if there's only one
198 self.set_show_tabs(self.get_n_pages() > 1)
200 self.show_all()
201 self.set_current_page(new_tab_number)
203 # load the content
204 self._hovered_uri = None
205 if not url:
206 web_view.load_string(ABOUT_PAGE, "text/html", "iso-8859-15", "about")
207 else:
208 web_view.load_uri(url)
210 def _populate_page_popup_cb(self, view, menu):
211 # misc
212 if self._hovered_uri:
213 open_in_new_tab = gtk.MenuItem(_("Open Link in New Tab"))
214 open_in_new_tab.connect("activate", self._open_in_new_tab, view)
215 menu.insert(open_in_new_tab, 0)
216 menu.show_all()
218 def _open_in_new_tab (self, menuitem, view):
219 self.new_tab(self._hovered_uri)
221 def _close_tab (self, label, child):
222 page_num = self.page_num(child)
223 if page_num != -1:
224 view = child.get_child()
225 view.destroy()
226 self.remove_page(page_num)
227 self.set_show_tabs(self.get_n_pages() > 1)
229 def _switch_page (self, notebook, page, page_num):
230 child = self.get_nth_page(page_num)
231 view = child.get_child()
232 frame = view.get_main_frame()
233 self.emit("focus-view-title-changed", frame, frame.props.title)
235 def _hovering_over_link_cb (self, view, title, uri):
236 self._hovered_uri = uri
238 def _title_changed_cb (self, view, frame, title):
239 child = self.get_nth_page(self.get_current_page())
240 label = self.get_tab_label(child)
241 label.set_label(title)
242 self.emit("focus-view-title-changed", frame, title)
244 def _view_load_finished_cb(self, view, frame):
245 child = self.get_nth_page(self.get_current_page())
246 label = self.get_tab_label(child)
247 title = frame.get_title()
248 if not title:
249 title = frame.get_uri()
250 if title:
251 label.set_label(title)
253 def _new_web_view_request_cb (self, web_view, web_frame):
254 scrolled_window = gtk.ScrolledWindow()
255 scrolled_window.props.hscrollbar_policy = gtk.POLICY_AUTOMATIC
256 scrolled_window.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
257 view = BrowserPage()
258 scrolled_window.add(view)
259 scrolled_window.show_all()
261 vbox = gtk.VBox(spacing=1)
262 vbox.pack_start(scrolled_window, True, True)
264 window = gtk.Window()
265 window.add(vbox)
266 view.connect("web-view-ready", self._new_web_view_ready_cb)
267 return view
269 def _new_web_view_ready_cb (self, web_view):
270 self.emit("new-window-requested", web_view)
273 class WebToolbar(gtk.Toolbar):
275 __gsignals__ = {
276 "load-requested": (gobject.SIGNAL_RUN_FIRST,
277 gobject.TYPE_NONE,
278 (gobject.TYPE_STRING,)),
279 "new-tab-requested": (gobject.SIGNAL_RUN_FIRST,
280 gobject.TYPE_NONE, ()),
281 "view-source-mode-requested": (gobject.SIGNAL_RUN_FIRST,
282 gobject.TYPE_NONE,
283 (gobject.TYPE_BOOLEAN, ))
286 def __init__(self, location_enabled=True, toolbar_enabled=True):
287 gtk.Toolbar.__init__(self)
289 # location entry
290 if location_enabled:
291 self._entry = gtk.Entry()
292 self._entry.connect('activate', self._entry_activate_cb)
293 entry_item = gtk.ToolItem()
294 entry_item.set_expand(True)
295 entry_item.add(self._entry)
296 self._entry.show()
297 self.insert(entry_item, -1)
298 entry_item.show()
300 # add tab button
301 if toolbar_enabled:
302 addTabButton = gtk.ToolButton(gtk.STOCK_ADD)
303 addTabButton.connect("clicked", self._add_tab_cb)
304 self.insert(addTabButton, -1)
305 addTabButton.show()
307 viewSourceItem = gtk.ToggleToolButton(gtk.STOCK_PROPERTIES)
308 viewSourceItem.set_label("View Source Mode")
309 viewSourceItem.connect('toggled', self._view_source_mode_cb)
310 self.insert(viewSourceItem, -1)
311 viewSourceItem.show()
313 def location_set_text (self, text):
314 self._entry.set_text(text)
316 def _entry_activate_cb(self, entry):
317 self.emit("load-requested", entry.props.text)
319 def _add_tab_cb(self, button):
320 self.emit("new-tab-requested")
322 def _view_source_mode_cb(self, button):
323 self.emit("view-source-mode-requested", button.get_active())
325 class WebBrowser(gtk.Window):
327 def __init__(self):
328 gtk.Window.__init__(self)
330 toolbar = WebToolbar()
331 content_tabs = ContentPane()
332 content_tabs.connect("focus-view-title-changed", self._title_changed_cb, toolbar)
333 content_tabs.connect("new-window-requested", self._new_window_requested_cb)
334 toolbar.connect("load-requested", load_requested_cb, content_tabs)
335 toolbar.connect("new-tab-requested", new_tab_requested_cb, content_tabs)
336 toolbar.connect("view-source-mode-requested", view_source_mode_requested_cb, content_tabs)
338 vbox = gtk.VBox(spacing=1)
339 vbox.pack_start(toolbar, expand=False, fill=False)
340 vbox.pack_start(content_tabs)
342 self.add(vbox)
343 self.set_default_size(800, 600)
344 self.connect('destroy', destroy_cb, content_tabs)
346 self.show_all()
348 content_tabs.new_tab("http://www.google.com")
350 def _new_window_requested_cb (self, content_pane, view):
351 features = view.get_window_features()
352 window = view.get_toplevel()
354 scrolled_window = view.get_parent()
355 if features.get_property("scrollbar-visible"):
356 scrolled_window.props.hscrollbar_policy = gtk.POLICY_NEVER
357 scrolled_window.props.vscrollbar_policy = gtk.POLICY_NEVER
359 isLocationbarVisible = features.get_property("locationbar-visible")
360 isToolbarVisible = features.get_property("toolbar-visible")
361 if isLocationbarVisible or isToolbarVisible:
362 toolbar = WebToolbar(isLocationbarVisible, isToolbarVisible)
363 scrolled_window.get_parent().pack_start(toolbar, False, False, 0)
365 window.set_default_size(features.props.width, features.props.height)
366 window.move(features.props.x, features.props.y)
368 window.show_all()
369 return True
371 def _title_changed_cb (self, tabbed_pane, frame, title, toolbar):
372 if not title:
373 title = frame.get_uri()
374 self.set_title(_("PyWebKitGtk - %s") % title)
375 load_committed_cb(tabbed_pane, frame, toolbar)
377 # event handlers
378 def new_tab_requested_cb (toolbar, content_pane):
379 content_pane.new_tab("about:blank")
381 def load_requested_cb (widget, text, content_pane):
382 if not text:
383 return
384 content_pane.load(text)
386 def load_committed_cb (tabbed_pane, frame, toolbar):
387 uri = frame.get_uri()
388 if uri:
389 toolbar.location_set_text(uri)
391 def destroy_cb(window, content_pane):
392 """destroy window resources"""
393 num_pages = content_pane.get_n_pages()
394 while num_pages != -1:
395 child = content_pane.get_nth_page(num_pages)
396 if child:
397 view = child.get_child()
398 num_pages = num_pages - 1
399 window.destroy()
400 gtk.main_quit()
402 # context menu item callbacks
403 def about_pywebkitgtk_cb(menu_item, web_view):
404 web_view.open("http://live.gnome.org/PyWebKitGtk")
406 def zoom_in_cb(menu_item, web_view):
407 """Zoom into the page"""
408 web_view.zoom_in()
410 def zoom_out_cb(menu_item, web_view):
411 """Zoom out of the page"""
412 web_view.zoom_out()
414 def zoom_hundred_cb(menu_item, web_view):
415 """Zoom 100%"""
416 if not (web_view.get_zoom_level() == 1.0):
417 web_view.set_zoom_level(1.0)
419 def print_cb(menu_item, web_view):
420 mainframe = web_view.get_main_frame()
421 mainframe.print_full(gtk.PrintOperation(), gtk.PRINT_OPERATION_ACTION_PRINT_DIALOG);
423 def page_properties_cb(menu_item, web_view):
424 mainframe = web_view.get_main_frame()
425 datasource = mainframe.get_data_source()
426 main_resource = datasource.get_main_resource()
427 window = gtk.Window()
428 window.set_default_size(100, 60)
429 vbox = gtk.VBox()
430 hbox = gtk.HBox()
431 hbox.pack_start(gtk.Label("MIME Type :"), False, False)
432 hbox.pack_end(gtk.Label(main_resource.get_mime_type()), False, False)
433 vbox.pack_start(hbox, False, False)
434 hbox2 = gtk.HBox()
435 hbox2.pack_start(gtk.Label("URI : "), False, False)
436 hbox2.pack_end(gtk.Label(main_resource.get_uri()), False, False)
437 vbox.pack_start(hbox2, False, False)
438 hbox3 = gtk.HBox()
439 hbox3.pack_start(gtk.Label("Encoding : "), False, False)
440 hbox3.pack_end(gtk.Label(main_resource.get_encoding()), False, False)
441 vbox.pack_start(hbox3, False, False)
442 window.add(vbox)
443 window.show_all()
444 window.present()
447 def view_source_mode_requested_cb(widget, is_active, content_pane):
448 currentTab = content_pane.get_nth_page(content_pane.get_current_page())
449 childView = currentTab.get_child()
450 childView.set_view_source_mode(is_active)
451 childView.reload()
453 if __name__ == "__main__":
454 webbrowser = WebBrowser()
455 gtk.main()