]> git.saurik.com Git - wxWidgets.git/blob - utils/wxPython/tests/wxSlash.py
internal browser creates temp file in current dir, safer if /tmp doesn't
[wxWidgets.git] / utils / wxPython / tests / wxSlash.py
1 #!/usr/bin/python
2 from wxPython.wx import *
3 from httplib import HTTP
4 from htmllib import HTMLParser
5 import os
6 import re
7 import formatter
8
9 __doc__ = """This is wxSlash 1.0
10
11 It's the obligatory Slashdot.org headlines reader that any modern
12 widget set/library must have in order to be taken seriously :-)
13
14 Usage is quite simple; wxSlash attempts to download the 'ultramode.txt'
15 file from http://slashdot.org, which contains the headlines in a computer
16 friendly format. It then displays said headlines in a wxWindows list control.
17
18 You can read articles using either Python's html library or an external
19 browser. Uncheck the 'browser->internal' menu item to use the latter option.
20 Use the settings dialog box to set how external browser is started.
21
22 This code is available under the wxWindows license, see elsewhere. If you
23 modify this code, be aware of the fact that slashdot.org's maintainer,
24 CmdrTaco, explicitly asks 'ultramode.txt' downloaders not to do this
25 automatically more than twice per hour. If this feature is abused, CmdrTaco
26 may remove the ultramode file completely and that will make a *lot* of people
27 unhappy.
28
29 I want to thank Alex Shnitman whose slashes.pl (Perl/GTK) script gave me
30 the idea for this applet.
31
32 Have fun with it,
33
34 Harm van der Heijden (H.v.d.Heijden@phys.tue.nl)
35 """
36
37 class HTMLTextView(wxFrame):
38 def __init__(self, parent, id, title='HTMLTextView', url=None):
39 wxFrame.__init__(self, parent, id, title, wxPyDefaultPosition,
40 wxSize(600,400))
41
42 self.mainmenu = wxMenuBar()
43
44 menu = wxMenu()
45 menu.Append(201, '&Open URL...', 'Open URL')
46 EVT_MENU(self, 201, self.OnFileOpen)
47 menu.Append(209, 'E&xit', 'Exit viewer')
48 EVT_MENU(self, 209, self.OnFileExit)
49
50 self.mainmenu.Append(menu, '&File')
51 self.SetMenuBar(self.mainmenu)
52 self.CreateStatusBar(1)
53
54 self.text = wxTextCtrl(self, -1, "", wxPyDefaultPosition,
55 wxPyDefaultSize, wxTE_MULTILINE | wxTE_READONLY)
56
57 if (url):
58 self.OpenURL(url)
59
60 def logprint(self, x):
61 self.SetStatusText(x)
62
63 def OpenURL(self, url):
64 self.url = url
65 m = re.match('file:(\S+)\s*', url)
66 if m:
67 f = open(m.groups()[0],'r')
68 else:
69 m = re.match('http://([^/]+)(/\S*)\s*', url)
70 if m:
71 host = m.groups()[0]
72 path = m.groups()[1]
73 else:
74 m = re.match('http://(\S+)\s*', url)
75 if not m:
76 # Invalid URL
77 self.logprint("Invalid or unsupported URL: %s" % (url))
78 return
79 host = m.groups()[0]
80 path = ''
81 f = RetrieveAsFile(host,path,self.logprint)
82 if not f:
83 self.logprint("Could not open %s" % (url))
84 return
85 self.logprint("Receiving data...")
86 data = f.read()
87 tmp = open('tmphtml.txt','w')
88 fmt = formatter.AbstractFormatter(formatter.DumbWriter(tmp))
89 p = HTMLParser(fmt)
90 self.logprint("Parsing data...")
91 p.feed(data)
92 p.close()
93 tmp.close()
94 tmp = open('tmphtml.txt', 'r')
95 self.text.SetValue(tmp.read())
96 self.SetTitle(url)
97 self.logprint(url)
98
99 def OnFileOpen(self, event):
100 dlg = wxTextEntryDialog(self, "Enter URL to open:", "")
101 if dlg.ShowModal() == wxID_OK:
102 url = dlg.GetValue()
103 else:
104 url = None
105 if url:
106 self.OpenURL(url)
107
108 def OnFileExit(self, event):
109 self.Close()
110
111 def OnCloseWindow(self, event):
112 self.Destroy()
113
114
115 def ParseSlashdot(f):
116 art_sep = re.compile('%%\r?\n')
117 line_sep = re.compile('\r?\n')
118 data = f.read()
119 list = art_sep.split(data)
120 art_list = []
121 for i in range(1,len(list)-1):
122 art_list.append(line_sep.split(list[i]))
123 return art_list
124
125 def myprint(x):
126 print x
127
128 def RetrieveAsFile(host, path='', logprint = myprint):
129 try:
130 h = HTTP(host)
131 except:
132 logprint("Failed to create HTTP connection to %s... is the network available?" % (host))
133 return None
134 h.putrequest('GET',path)
135 h.putheader('Accept','text/html')
136 h.putheader('Accept','text/plain')
137 h.endheaders()
138 errcode, errmsg, headers = h.getreply()
139 if errcode != 200:
140 logprint("HTTP error code %d: %s" % (errcode, errmsg))
141 return None
142 f = h.getfile()
143 # f = open('/home/harm/ultramode.txt','r')
144 return f
145
146 # This one isn't defined in the default wxPython modules...
147 def EVT_LIST_ITEM_SELECTED(win, id, func):
148 win.Connect(id, -1, wxEVT_COMMAND_LIST_ITEM_SELECTED, func)
149
150 class AppStatusBar(wxStatusBar):
151 def __init__(self, parent):
152 wxStatusBar.__init__(self,parent, -1)
153 self.SetFieldsCount(2)
154 self.SetStatusWidths([100,-1])
155 self.but = wxButton(self, 1001, "Refresh")
156 EVT_BUTTON(self, 1001, parent.OnViewRefresh)
157 self.OnSize(None)
158
159 def logprint(self,x):
160 self.SetStatusText(x,1)
161
162 def OnSize(self, event):
163 rect = self.GetFieldRect(0)
164 self.but.SetPosition(wxPoint(rect.x+2, rect.y+2))
165 # The width/height we get is false. Why? Now I use a stupid trick:
166 rect2 = self.GetFieldRect(1)
167 rect.width = rect2.x - 8;
168 rect.height = 25;
169 self.but.SetSize(wxSize(rect.width-4, rect.height-4))
170
171 # This is a simple timer class to start a function after a short delay;
172 # For example, if you're about to perform function f which may take a long
173 # time, write "Please wait" in the statusbar, then create a QuickTimer(f)
174 # object to automatically call f after a short delay. That way, wxWindows
175 # will get a chance to update the statusbar before the long function is
176 # called.
177 # FIXME: can this be done better using an OnIdle kind of thing?
178 class QuickTimer(wxTimer):
179 def __init__(self, func, wait=100):
180 wxTimer.__init__(self)
181 self.callback = func
182 self.Start(wait); # wait .1 second (.001 second doesn't work. why?)
183 def Notify(self):
184 self.Stop();
185 apply(self.callback, ());
186
187 class AppFrame(wxFrame):
188 def __init__(self, parent, id, title):
189 wxFrame.__init__(self, parent, id, title, wxPyDefaultPosition,
190 wxSize(650, 250))
191
192 # if the window manager closes the window:
193 EVT_CLOSE(self, self.OnCloseWindow);
194
195 # Now Create the menu bar and items
196 self.mainmenu = wxMenuBar()
197
198 menu = wxMenu()
199 menu.Append(209, 'E&xit', 'Enough of this already!')
200 EVT_MENU(self, 209, self.OnFileExit)
201 self.mainmenu.Append(menu, '&File')
202 menu = wxMenu()
203 menu.Append(210, '&Refresh', 'Refresh headlines')
204 EVT_MENU(self, 210, self.OnViewRefresh)
205 menu.Append(211, '&Slashdot Index', 'View Slashdot index')
206 EVT_MENU(self, 211, self.OnViewIndex)
207 menu.Append(212, 'Selected &Article', 'View selected article')
208 EVT_MENU(self, 212, self.OnViewArticle)
209 self.mainmenu.Append(menu, '&View')
210 menu = wxMenu()
211 menu.Append(220, '&Internal', 'Use internal text browser',TRUE)
212 menu.Check(220, true)
213 self.UseInternal = 1;
214 EVT_MENU(self, 220, self.OnBrowserInternal)
215 menu.Append(222, '&Settings...', 'External browser Settings')
216 EVT_MENU(self, 222, self.OnBrowserSettings)
217 self.mainmenu.Append(menu, '&Browser')
218 menu = wxMenu()
219 menu.Append(230, '&About', 'Some documentation');
220 EVT_MENU(self, 230, self.OnAbout)
221 self.mainmenu.Append(menu, '&Help')
222
223 self.SetMenuBar(self.mainmenu)
224
225 self.BrowserSettings = "netscape -remote 'OpenURL(%s, new_window)'"
226
227 # A status bar to tell people what's happening
228 self.sb = AppStatusBar(self)
229 self.SetStatusBar(self.sb)
230
231 self.list = wxListCtrl(self, 1100)
232 self.list.SetSingleStyle(wxLC_REPORT)
233 self.list.InsertColumn(0, 'Subject')
234 self.list.InsertColumn(1, 'Date')
235 self.list.InsertColumn(2, 'Posted by')
236 self.list.InsertColumn(3, 'Comments')
237 self.list.SetColumnWidth(0, 300)
238 self.list.SetColumnWidth(1, 150)
239 self.list.SetColumnWidth(2, 100)
240 self.list.SetColumnWidth(3, 100)
241
242 EVT_LIST_ITEM_SELECTED(self, 1100, self.OnItemSelected)
243
244 self.logprint("Connecting to slashdot... Please wait.")
245 # Need a longer time here. Don't really know why
246 self.timer = QuickTimer(self.DoRefresh, 1000)
247
248 def logprint(self, x):
249 self.sb.logprint(x)
250
251 def OnFileExit(self, event):
252 self.Destroy()
253
254 def DoRefresh(self):
255 f = RetrieveAsFile('slashdot.org','/ultramode.txt',self.sb.logprint)
256 art_list = ParseSlashdot(f)
257 self.list.DeleteAllItems()
258 self.url = []
259 self.current = -1
260 i = 0;
261 for article in art_list:
262 self.list.InsertStringItem(i, article[0])
263 self.list.SetItemString(i, 1, article[2])
264 self.list.SetItemString(i, 2, article[3])
265 self.list.SetItemString(i, 3, article[6])
266 self.url.append(article[1])
267 i = i + 1
268 self.logprint("File retrieved OK.")
269
270 def OnViewRefresh(self, event):
271 self.timer = QuickTimer(self.DoRefresh)
272 self.logprint("Connecting to slashdot... Please wait.");
273
274 def DoViewIndex(self):
275 if self.UseInternal:
276 self.view = HTMLTextView(self, -1, 'slashdot.org',
277 'http://slashdot.org')
278 self.view.Show(true)
279 else:
280 self.logprint(self.BrowserSettings % ('http://slashdot.org'))
281 os.system(self.BrowserSettings % ('http://slashdot.org'))
282 self.logprint("OK")
283
284 def OnViewIndex(self, event):
285 self.logprint("Starting browser... Please wait.")
286 self.timer = QuickTimer(self.DoViewIndex)
287
288 def DoViewArticle(self):
289 if self.current<0: return
290 url = self.url[self.current]
291 if self.UseInternal:
292 self.view = HTMLTextView(self, -1, url, url)
293 self.view.Show(true)
294 else:
295 self.logprint(self.BrowserSettings % (url))
296 os.system(self.BrowserSettings % (url))
297 self.logprint("OK")
298
299 def OnViewArticle(self, event):
300 self.logprint("Starting browser... Please wait.")
301 self.timer = QuickTimer(self.DoViewArticle)
302
303 def OnBrowserInternal(self, event):
304 if self.mainmenu.Checked(220):
305 self.UseInternal = 1
306 else:
307 self.UseInternal = 0
308
309 def OnBrowserSettings(self, event):
310 dlg = wxTextEntryDialog(self, "Enter command to view URL.\nUse %s as a placeholder for the URL.", "", self.BrowserSettings);
311 if dlg.ShowModal() == wxID_OK:
312 self.BrowserSettings = dlg.GetValue()
313
314 def OnAbout(self, event):
315 dlg = wxMessageDialog(self, __doc__, "wxSlash", wxOK | wxICON_INFORMATION)
316 dlg.ShowModal()
317
318 def OnItemSelected(self, event):
319 self.current = event.m_itemIndex
320 self.logprint("URL: %s" % (self.url[self.current]))
321
322 def OnCloseWindow(self, event):
323 self.Destroy()
324
325 class MyApp(wxApp):
326 def OnInit(self):
327 frame = AppFrame(NULL, -1, "Slashdot Breaking News")
328 frame.Show(true)
329 self.SetTopWindow(frame)
330 return true
331
332 #
333 # main thingy
334 #
335 if __name__ == '__main__':
336 app = MyApp(0)
337 app.MainLoop()
338
339
340
341
342