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
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 _
31 from inspector
import Inspector
34 <html><head><title>PyWebKitGtk - About</title></head><body>
35 <h1>Welcome to <code>webbrowser.py</code></h1>
37 href="http://code.google.com/p/pywebkitgtk/">http://code.google.com/p/pywebkitgtk/</a><br/>
42 class BrowserPage(webkit
.WebView
):
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
):
58 zoom_in
= gtk
.ImageMenuItem(gtk
.STOCK_ZOOM_IN
)
59 zoom_in
.connect('activate', zoom_in_cb
, view
)
62 zoom_out
= gtk
.ImageMenuItem(gtk
.STOCK_ZOOM_OUT
)
63 zoom_out
.connect('activate', zoom_out_cb
, view
)
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
)
87 class TabLabel (gtk
.HBox
):
88 """A class for Tab labels"""
91 "close": (gobject
.SIGNAL_RUN_FIRST
,
93 (gobject
.TYPE_OBJECT
,))
96 def __init__ (self
, title
, child
):
97 """initialize the tab label"""
98 gtk
.HBox
.__init
__(self
, False, 4)
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
):
140 "focus-view-title-changed": (gobject
.SIGNAL_RUN_FIRST
,
142 (gobject
.TYPE_OBJECT
, gobject
.TYPE_STRING
,)),
143 "new-window-requested": (gobject
.SIGNAL_RUN_FIRST
,
145 (gobject
.TYPE_OBJECT
,))
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
)
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()
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()
189 label
= TabLabel(url
, scrolled_window
)
190 label
.connect("close", self
._close
_tab
)
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)
201 self
.set_current_page(new_tab_number
)
204 self
._hovered
_uri
= None
206 web_view
.load_string(ABOUT_PAGE
, "text/html", "iso-8859-15", "about")
208 web_view
.load_uri(url
)
210 def _populate_page_popup_cb(self
, view
, menu
):
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)
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
)
224 view
= child
.get_child()
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()
249 title
= frame
.get_uri()
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
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()
266 view
.connect("web-view-ready", self
._new
_web
_view
_ready
_cb
)
269 def _new_web_view_ready_cb (self
, web_view
):
270 self
.emit("new-window-requested", web_view
)
273 class WebToolbar(gtk
.Toolbar
):
276 "load-requested": (gobject
.SIGNAL_RUN_FIRST
,
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
,
283 (gobject
.TYPE_BOOLEAN
, ))
286 def __init__(self
, location_enabled
=True, toolbar_enabled
=True):
287 gtk
.Toolbar
.__init
__(self
)
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
)
297 self
.insert(entry_item
, -1)
302 addTabButton
= gtk
.ToolButton(gtk
.STOCK_ADD
)
303 addTabButton
.connect("clicked", self
._add
_tab
_cb
)
304 self
.insert(addTabButton
, -1)
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
):
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
)
343 self
.set_default_size(800, 600)
344 self
.connect('destroy', destroy_cb
, content_tabs
)
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
)
371 def _title_changed_cb (self
, tabbed_pane
, frame
, title
, toolbar
):
373 title
= frame
.get_uri()
374 self
.set_title(_("PyWebKitGtk - %s") % title
)
375 load_committed_cb(tabbed_pane
, frame
, toolbar
)
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
):
384 content_pane
.load(text
)
386 def load_committed_cb (tabbed_pane
, frame
, toolbar
):
387 uri
= frame
.get_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
)
397 view
= child
.get_child()
398 num_pages
= num_pages
- 1
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"""
410 def zoom_out_cb(menu_item
, web_view
):
411 """Zoom out of the page"""
414 def zoom_hundred_cb(menu_item
, web_view
):
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)
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)
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)
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)
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
)
453 if __name__
== "__main__":
454 webbrowser
= WebBrowser()