2 # Copyright (C) 2007-2008 Jan Alonzo <jmalonzo@unpluggable.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 <strong>Home:</strong><a
38 href="http://code.google.com/p/pywebkitgtk/">http://code.google.com/p/pywebkitgtk/</a><br/>
39 <strong>Wiki:</strong><a
40 href="http://live.gnome.org/PyWebKitGtk">http://live.gnome.org/PyWebKitGtk</a><br/>
45 class BrowserPage(webkit
.WebView
):
48 webkit
.WebView
.__init
__(self
)
49 settings
= self
.get_settings()
50 settings
.set_property("enable-developer-extras", True)
52 # scale other content besides from text as well
53 self
.set_full_content_zoom(True)
55 # make sure the items will be added in the end
56 # hence the reason for the connect_after
57 self
.connect_after("populate-popup", self
.populate_popup
)
59 def populate_popup(self
, view
, menu
):
61 zoom_in
= gtk
.ImageMenuItem(gtk
.STOCK_ZOOM_IN
)
62 zoom_in
.connect('activate', zoom_in_cb
, view
)
65 zoom_out
= gtk
.ImageMenuItem(gtk
.STOCK_ZOOM_OUT
)
66 zoom_out
.connect('activate', zoom_out_cb
, view
)
69 zoom_hundred
= gtk
.ImageMenuItem(gtk
.STOCK_ZOOM_100
)
70 zoom_hundred
.connect('activate', zoom_hundred_cb
, view
)
71 menu
.append(zoom_hundred
)
73 menu
.append(gtk
.SeparatorMenuItem())
75 aboutitem
= gtk
.ImageMenuItem(gtk
.STOCK_ABOUT
)
76 menu
.append(aboutitem
)
77 aboutitem
.connect('activate', about_pywebkitgtk_cb
, view
)
82 class TabLabel (gtk
.HBox
):
83 """A class for Tab labels"""
86 "close": (gobject
.SIGNAL_RUN_FIRST
,
88 (gobject
.TYPE_OBJECT
,))
91 def __init__ (self
, title
, child
):
92 """initialize the tab label"""
93 gtk
.HBox
.__init
__(self
, False, 4)
96 self
.label
= gtk
.Label(title
)
97 self
.label
.props
.max_width_chars
= 30
98 self
.label
.set_ellipsize(pango
.ELLIPSIZE_MIDDLE
)
99 self
.label
.set_alignment(0.0, 0.5)
101 icon
= gtk
.image_new_from_stock(gtk
.STOCK_ORIENTATION_PORTRAIT
, gtk
.ICON_SIZE_MENU
)
102 close_image
= gtk
.image_new_from_stock(gtk
.STOCK_CLOSE
, gtk
.ICON_SIZE_MENU
)
103 close_button
= gtk
.Button()
104 close_button
.set_relief(gtk
.RELIEF_NONE
)
105 close_button
.connect("clicked", self
._close
_tab
, child
)
106 close_button
.add(close_image
)
107 self
.pack_start(icon
, False, False, 0)
108 self
.pack_start(self
.label
, True, True, 0)
109 self
.pack_start(close_button
, False, False, 0)
111 self
.set_data("label", self
.label
)
112 self
.set_data("close-button", close_button
)
113 self
.connect("style-set", tab_label_style_set_cb
)
115 def set_label_text (self
, text
):
116 """sets the text of this label"""
117 self
.label
.set_label(text
)
119 def _close_tab (self
, widget
, child
):
120 self
.emit("close", child
)
122 def tab_label_style_set_cb (tab_label
, style
):
123 context
= tab_label
.get_pango_context()
124 metrics
= context
.get_metrics(tab_label
.style
.font_desc
, context
.get_language())
125 char_width
= metrics
.get_approximate_digit_width()
126 (width
, height
) = gtk
.icon_size_lookup_for_settings(tab_label
.get_settings(), gtk
.ICON_SIZE_MENU
)
127 tab_label
.set_size_request(20 * pango
.PIXELS(char_width
) + 2 * width
, -1)
128 button
= tab_label
.get_data("close-button")
129 button
.set_size_request(width
+ 4, height
+ 4)
132 class ContentPane (gtk
.Notebook
):
135 "focus-view-title-changed": (gobject
.SIGNAL_RUN_FIRST
,
137 (gobject
.TYPE_OBJECT
, gobject
.TYPE_STRING
,)),
138 "focus-view-load-committed": (gobject
.SIGNAL_RUN_FIRST
,
140 (gobject
.TYPE_OBJECT
, gobject
.TYPE_OBJECT
,))
144 """initialize the content pane"""
145 gtk
.Notebook
.__init
__(self
)
146 self
.props
.scrollable
= True
147 self
.props
.homogeneous
= True
148 self
.connect("switch-page", self
._switch
_page
)
151 self
._hovered
_uri
= None
153 def load (self
, text
):
154 """load the given uri in the current web view"""
155 child
= self
.get_nth_page(self
.get_current_page())
156 view
= child
.get_child()
159 def new_tab (self
, url
=None):
160 """creates a new page in a new tab"""
161 # create the tab content
162 browser
= BrowserPage()
163 browser
.connect("hovering-over-link", self
._hovering
_over
_link
_cb
)
164 browser
.connect("populate-popup", self
._populate
_page
_popup
_cb
)
165 browser
.connect("load-committed", self
._view
_load
_committed
_cb
)
166 browser
.connect("load-finished", self
._view
_load
_finished
_cb
)
167 inspector
= Inspector(browser
.get_web_inspector())
169 scrolled_window
= gtk
.ScrolledWindow()
170 scrolled_window
.props
.hscrollbar_policy
= gtk
.POLICY_AUTOMATIC
171 scrolled_window
.props
.vscrollbar_policy
= gtk
.POLICY_AUTOMATIC
172 scrolled_window
.add(browser
)
173 scrolled_window
.show_all()
176 self
._hovered
_uri
= None
178 browser
.load_string(ABOUT_PAGE
, "text/html", "iso-8859-15", "about")
184 label
= TabLabel(url
, scrolled_window
)
185 label
.connect("close", self
._close
_tab
)
188 new_tab_number
= self
.append_page(scrolled_window
, label
)
189 self
.set_tab_label_packing(scrolled_window
, False, False, gtk
.PACK_START
)
190 self
.set_tab_label(scrolled_window
, label
)
192 # hide the tab if there's only one
193 self
.set_show_tabs(self
.get_n_pages() > 1)
196 self
.set_current_page(new_tab_number
)
198 def _populate_page_popup_cb(self
, view
, menu
):
200 if self
._hovered
_uri
:
201 open_in_new_tab
= gtk
.MenuItem(_("Open Link in New Tab"))
202 open_in_new_tab
.connect("activate", self
._open
_in
_new
_tab
, view
)
203 menu
.insert(open_in_new_tab
, 0)
206 def _open_in_new_tab (self
, menuitem
, view
):
207 self
.new_tab(self
._hovered
_uri
)
209 def _close_tab (self
, label
, child
):
210 page_num
= self
.page_num(child
)
212 view
= child
.get_child()
214 self
.remove_page(page_num
)
215 self
.set_show_tabs(self
.get_n_pages() > 1)
217 def _switch_page (self
, notebook
, page
, page_num
):
218 child
= self
.get_nth_page(page_num
)
219 view
= child
.get_child()
220 frame
= view
.get_main_frame()
221 self
.emit("focus-view-load-committed", view
, frame
)
223 def _hovering_over_link_cb (self
, view
, title
, uri
):
224 self
._hovered
_uri
= uri
226 def _view_load_committed_cb (self
, view
, frame
):
227 self
.emit("focus-view-load-committed", view
, frame
)
229 def _view_load_finished_cb(self
, view
, frame
):
230 child
= self
.get_nth_page(self
.get_current_page())
231 label
= self
.get_tab_label(child
)
232 title
= frame
.get_title()
234 title
= frame
.get_uri()
235 label
.set_label_text(title
)
238 class WebToolbar(gtk
.Toolbar
):
241 "load-requested": (gobject
.SIGNAL_RUN_FIRST
,
243 (gobject
.TYPE_STRING
,)),
244 "new-tab-requested": (gobject
.SIGNAL_RUN_FIRST
,
245 gobject
.TYPE_NONE
, ())
249 gtk
.Toolbar
.__init
__(self
)
252 self
._entry
= gtk
.Entry()
253 self
._entry
.connect('activate', self
._entry
_activate
_cb
)
254 entry_item
= gtk
.ToolItem()
255 entry_item
.set_expand(True)
256 entry_item
.add(self
._entry
)
259 self
.insert(entry_item
, -1)
263 button
= gtk
.ToolButton(gtk
.STOCK_ADD
)
264 button
.connect("clicked", self
._add
_tab
_cb
)
265 self
.insert(button
, -1)
268 def location_set_text (self
, text
):
269 self
._entry
.set_text(text
)
271 def _entry_activate_cb(self
, entry
):
272 self
.emit("load-requested", entry
.props
.text
)
274 def _add_tab_cb (self
, button
):
275 self
.emit("new-tab-requested")
277 class WebBrowser(gtk
.Window
):
280 gtk
.Window
.__init
__(self
)
282 toolbar
= WebToolbar()
283 content_tabs
= ContentPane()
284 content_tabs
.connect("focus-view-load-committed", self
._load
_committed
_cb
, toolbar
)
285 toolbar
.connect("load-requested", load_requested_cb
, content_tabs
)
286 toolbar
.connect("new-tab-requested", new_tab_requested_cb
, content_tabs
)
288 vbox
= gtk
.VBox(spacing
=1)
289 vbox
.pack_start(toolbar
, expand
=False, fill
=False)
290 vbox
.pack_start(content_tabs
)
293 self
.set_default_size(800, 600)
294 self
.connect('destroy', destroy_cb
, content_tabs
)
296 content_tabs
.new_tab("http://www.google.com")
300 def _load_committed_cb (self
, tabbed_pane
, view
, frame
, toolbar
):
301 title
= frame
.get_title()
303 title
= frame
.get_uri()
304 self
.set_title(_("PyWebKitGtk - %s") % title
)
305 load_committed_cb(tabbed_pane
, view
, frame
, toolbar
)
308 def new_tab_requested_cb (toolbar
, content_pane
):
309 content_pane
.new_tab("about:blank")
311 def load_requested_cb (widget
, text
, content_pane
):
314 content_pane
.load(text
)
316 def load_committed_cb (tabbed_pane
, view
, frame
, toolbar
):
317 uri
= frame
.get_uri()
319 toolbar
.location_set_text(uri
)
321 def destroy_cb(window
, content_pane
):
322 """destroy window resources"""
323 num_pages
= content_pane
.get_n_pages()
324 while num_pages
!= -1:
325 child
= content_pane
.get_nth_page(num_pages
)
327 view
= child
.get_child()
329 num_pages
= num_pages
- 1
333 # context menu item callbacks
334 def about_pywebkitgtk_cb(menu_item
, web_view
):
335 web_view
.open("http://live.gnome.org/PyWebKitGtk")
337 def zoom_in_cb(menu_item
, web_view
):
338 """Zoom into the page"""
341 def zoom_out_cb(menu_item
, web_view
):
342 """Zoom out of the page"""
345 def zoom_hundred_cb(menu_item
, web_view
):
347 if not (web_view
.get_zoom_level() == 1.0):
348 web_view
.set_zoom_level(1.0)
350 if __name__
== "__main__":
351 webbrowser
= WebBrowser()