2 DocumentView is a generic interface to html document browsing.
4 __init__(self, userdir)
8 render_data(self, data, base_uri, mime_type)
12 location_changed(location)
24 class DocumentView(gobject
.GObject
):
26 "location_changed" : (
27 gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, [
28 gobject
.TYPE_STRING
]), # The new location
30 gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, []),
31 "loading_finished" : (
32 gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, []),
34 gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, [
35 gobject
.TYPE_STRING
]), # The status
37 gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_BOOLEAN
, [
38 gobject
.TYPE_STRING
]) # URI
40 def __init__(self
, emitOnIdle
=False):
41 gobject
.GObject
.__init
__(self
)
42 self
.emitOnIdle
= emitOnIdle
44 def emit(self
, *args
):
46 Override the gobject signal emission so that signals
47 can be emitted from the main loop on an idle handler
49 if self
.emitOnIdle
== True:
50 gobject
.idle_add(gobject
.GObject
.emit
,self
,*args
)
52 return gobject
.GObject
.emit(self
,*args
)
54 class WebKitDocumentView(DocumentView
):
55 """wraps the PyWebKitGtk HTML view in the DocumentView interface"""
56 def __init__(self
, userdir
):
57 DocumentView
.__init
__(self
)
59 import webkitgtk
# you'll need PyWebKitGtk
61 self
._view
= webkitgtk
.WebView()
65 for method
in dir(self
.__class
__):
66 if method
.startswith(sprefix
):
67 signal
= method
[len(sprefix
):]
68 self
._view
.connect(signal
, getattr(self
, method
))
70 self
._scrolled
_window
= gtk
.ScrolledWindow()
71 self
._scrolled
_window
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_AUTOMATIC
)
72 self
._scrolled
_window
.add(self
._view
)
74 self
._scrolled
_window
.show_all()
77 """returns the gtk widget of this view"""
78 return self
._scrolled
_window
80 def load_url(self
, url
):
83 self
.emit("location_changed",self
.location
)
86 self
._view
.stop_loading()
88 def render_data(self
, data
, base_uri
, mime_type
):
89 ct
= mime_type
.split("; ")
93 charset
= "utf-8" # default
95 self
.emit("location_changed",base_uri
)
96 self
._view
.load_string(data
, ct
[0], charset
, base_uri
)
98 def _signal_load_started(self
, object, frame
):
99 self
.emit("loading_started")
100 def _signal_load_progress_changed(self
, object, progress
):
102 def _signal_load_finished(self
, object, frame
):
103 self
.emit("loading_finished")
104 def _signal_title_changed(self
, object, title
, uri
):
106 self
.emit("location_changed",self
.location
)
107 def _signal_status_bar_text_changed(self
, object, text
):
111 class GtkHtmlDocumentView(DocumentView
):
112 """wraps the GTK HTML view in the DocumentView interface"""
113 def __init__(self
, userdir
):
114 DocumentView
.__init
__(self
)
116 import gtkhtml2
# you'll need Debian package python-gnome2-extras
118 self
._view
= gtkhtml2
.View()
119 self
._document
= gtkhtml2
.Document()
120 self
._widget
= gtk
.ScrolledWindow()
121 self
._widget
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_AUTOMATIC
)
122 self
._widget
.add(self
._view
)
125 self
._view
.connect("on_url", self
._signal
_on
_url
)
126 self
._document
.connect("link_clicked", self
._signal
_link
_clicked
)
127 self
._document
.connect("request-url", self
._signal
_request
_url
)
129 self
._view
.set_document(self
._document
)
132 """returns the gtk widget of this view"""
135 def load_url(self
, url
):
136 res
= self
._open
_url
(self
._complete
_url
(url
))
137 ct
= res
.info()['content-type']
138 self
.render_data(res
.read(), res
.geturl(), ct
)
140 def render_data(self
, data
, base_uri
, mime_type
):
141 self
.location
= base_uri
142 self
.emit("location_changed", self
.location
)
144 ct
= mime_type
.split("; ")
148 charset
= "utf-8" # default
150 self
._document
.clear()
152 self
._document
.open_stream(ct
[0])
154 self
._document
.write_stream(data
)
156 self
._document
.close_stream()
160 def _signal_on_url(self
, object, url
):
161 if url
== None: url
= ""
162 else: url
= self
._complete
_url
(url
)
163 self
.emit("status_changed", url
)
165 def _signal_link_clicked(self
, object, link
):
166 self
.emit("open_uri", self
._complete
_url
(link
))
168 def _signal_request_url(self
, object, url
, stream
):
169 stream
.write(self
._fetch
_url
(self
._complete
_url
(url
)))
171 def _open_url(self
, url
, headers
=[]):
173 opener
= urllib2
.build_opener()
174 opener
.addheaders
= [('User-agent', 'Wikitin')]+headers
175 return opener
.open(url
)
177 def _fetch_url(self
, url
, headers
=[]):
178 return self
._open
_url
(url
, headers
).read()
180 def _complete_url(self
, url
):
181 import string
, urlparse
, urllib
182 url
= urllib
.quote(url
, safe
=string
.punctuation
)
183 if urlparse
.urlparse(url
)[0] == '':
184 return urlparse
.urljoin(self
.location
, url
)
189 class MozEmbedDocumentView(DocumentView
):
190 """wraps the GTK embeddable Mozilla in the DocumentView interface"""
191 def __init__(self
, profiledir
):
192 DocumentView
.__init
__(self
)
194 import gtkmozembed
# you'll need Debian package python-gnome2-extras
196 print "Setting Mozilla profile dir to %s name %s" % (profiledir
, 'default')
197 gtkmozembed
.set_profile_path(profiledir
, 'default')
199 self
.moz
= gtkmozembed
.MozEmbed()
200 self
.url_load_request
= False # flag to break load_url recursion
205 for method
in dir(self
.__class
__):
206 if method
.startswith(sprefix
):
207 self
.moz
.connect(method
[len(sprefix
):], getattr(self
, method
))
210 """returns the gtk widget of this view"""
213 def load_url(self
, str):
214 self
.url_load_request
= True # don't handle open-uri signal
215 self
.moz
.load_url(str) # emits open-uri signal
216 self
.url_load_request
= False # handle open-uri again
221 self
.url_load_request
= True # don't handle open-uri signal
223 self
.url_load_request
= False # handle open-uri again
224 def go_forward(self
):
225 self
.url_load_request
= True # don't handle open-uri signal
226 self
.moz
.go_forward()
227 self
.url_load_request
= False # handle open-uri again
229 self
.moz
.reload(gtkmozembed
.FLAG_RELOADNORMAL
)
231 def render_data(self
, data
, base_uri
, mime_type
):
232 self
.url_load_request
= True # don't handle open-uri signal
234 ct
= mime_type
.split("; ")
238 charset
= "utf-8" # default
240 self
.location_changed(base_uri
)
242 # gtkmozembed hangs if it's fed more than 2^16 at a time
244 self
.moz
.open_stream(base_uri
, ct
[0])
246 block
, data
= data
[:2**16], data
[2**16:]
247 self
.moz
.append_data(block
, long(len(block
)))
248 if len(data
) == 0: break
249 self
.moz
.close_stream()
251 self
.url_load_request
= False # handle open-uri again
253 def _signal_link_message(self
, object):
254 self
.emit("status_changed", self
.moz
.get_link_message())
256 def _signal_open_uri(self
, object, uri
):
257 if self
.url_load_request
: return False # proceed as requested
258 # otherwise, this is from the page
261 if uri
.__class
__ == gobject
.GPointer
:
262 print "The gpointer bug, guessing...",
263 uri
= self
.moz
.get_link_message()
264 if uri
=="": print "<empty>",
267 return False # XXX can't handle, let MozEmbed do it
268 return self
.emit("open_uri", uri
)
270 print "No gpointer bug here !-)"
271 return self
.emit("open_uri", uri
)
273 def _signal_location(self
, object):
274 self
.location_changed(self
.moz
.get_location())
276 def location_changed(self
, location
):
277 print "moz: location: "+location
278 self
.location
= location
279 self
.emit("location_changed",self
.location
)
281 def _signal_progress(self
, object, cur
, maxim
):
283 print "Progress: %d" % cur
285 print 'Progress: %d%%' % (cur
/maxim
)
286 def _signal_net_state(self
, object, flags
, status
):
287 print 'net-state flags=%x status=%x' % (flags
,status
)
288 def _signal_new_window(self
, object, *args
):
289 print 'new-window', args
290 def _signal_net_start(self
, object):
291 self
.emit("loading_started")
292 def _signal_net_stop(self
, object):
293 self
.emit("loading_finished")
296 def get_subdir(dir, subdir
=''):
298 userdir
= os
.path
.join(dir, subdir
)
299 if not os
.access(userdir
, os
.F_OK
):
303 documentviews
= ['webkit', 'gtkmozembed', 'gtkhtml']
304 create_documentviews
= {
305 'webkit': lambda userdir
:WebKitDocumentView(userdir
),
306 'gtkmozembed': lambda userdir
:MozEmbedDocumentView(get_subdir(userdir
, 'mozilla')),
307 'gtkhtml': lambda userdir
:GtkHtmlDocumentView(userdir
),
310 def default_documentview(userdir
):
311 for documentview
in documentviews
:
313 return create_documentviews
[documentview
](userdir
)
317 print "No HTML view available!"