]> git.saurik.com Git - wxWidgets.git/blob - utils/wxPython/tests/wxSlash.py
wxPython version 2.0b5
[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.1
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 which 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
147 class AppStatusBar(wxStatusBar):
148 def __init__(self, parent):
149 wxStatusBar.__init__(self,parent, -1)
150 self.SetFieldsCount(2)
151 self.SetStatusWidths([-1, 100])
152 self.but = wxButton(self, 1001, "Refresh")
153 EVT_BUTTON(self, 1001, parent.OnViewRefresh)
154 self.OnSize(None)
155
156 def logprint(self,x):
157 self.SetStatusText(x,0)
158
159 def OnSize(self, event):
160 rect = self.GetFieldRect(1)
161 self.but.SetPosition(wxPoint(rect.x+2, rect.y+2))
162 self.but.SetSize(wxSize(rect.width-4, rect.height-4))
163
164 # This is a simple timer class to start a function after a short delay;
165 class QuickTimer(wxTimer):
166 def __init__(self, func, wait=100):
167 wxTimer.__init__(self)
168 self.callback = func
169 self.Start(wait); # wait .1 second (.001 second doesn't work. why?)
170 def Notify(self):
171 self.Stop();
172 apply(self.callback, ());
173
174 class AppFrame(wxFrame):
175 def __init__(self, parent, id, title):
176 wxFrame.__init__(self, parent, id, title, wxPyDefaultPosition,
177 wxSize(650, 250))
178
179 # if the window manager closes the window:
180 EVT_CLOSE(self, self.OnCloseWindow);
181
182 # Now Create the menu bar and items
183 self.mainmenu = wxMenuBar()
184
185 menu = wxMenu()
186 menu.Append(209, 'E&xit', 'Enough of this already!')
187 EVT_MENU(self, 209, self.OnFileExit)
188 self.mainmenu.Append(menu, '&File')
189 menu = wxMenu()
190 menu.Append(210, '&Refresh', 'Refresh headlines')
191 EVT_MENU(self, 210, self.OnViewRefresh)
192 menu.Append(211, '&Slashdot Index', 'View Slashdot index')
193 EVT_MENU(self, 211, self.OnViewIndex)
194 menu.Append(212, 'Selected &Article', 'View selected article')
195 EVT_MENU(self, 212, self.OnViewArticle)
196 self.mainmenu.Append(menu, '&View')
197 menu = wxMenu()
198 menu.Append(220, '&Internal', 'Use internal text browser',TRUE)
199 menu.Check(220, true)
200 self.UseInternal = 1;
201 EVT_MENU(self, 220, self.OnBrowserInternal)
202 menu.Append(222, '&Settings...', 'External browser Settings')
203 EVT_MENU(self, 222, self.OnBrowserSettings)
204 self.mainmenu.Append(menu, '&Browser')
205 menu = wxMenu()
206 menu.Append(230, '&About', 'Some documentation');
207 EVT_MENU(self, 230, self.OnAbout)
208 self.mainmenu.Append(menu, '&Help')
209
210 self.SetMenuBar(self.mainmenu)
211
212 if wxPlatform == '__WXGTK__':
213 # I like lynx. Also Netscape 4.5 doesn't react to my cmdline opts
214 self.BrowserSettings = "xterm -e lynx %s &"
215 elif wxPlatform == '__WXMSW__':
216 # netscape 4.x likes to hang out here...
217 self.BrowserSettings = '\progra~1\Netscape\Communicator\Program\netscape.exe %s'
218 else:
219 # a wild guess...
220 self.BrowserSettings = 'netscape %s'
221
222 # A status bar to tell people what's happening
223 self.sb = AppStatusBar(self)
224 self.SetStatusBar(self.sb)
225
226 self.list = wxListCtrl(self, 1100)
227 self.list.SetSingleStyle(wxLC_REPORT)
228 self.list.InsertColumn(0, 'Subject')
229 self.list.InsertColumn(1, 'Date')
230 self.list.InsertColumn(2, 'Posted by')
231 self.list.InsertColumn(3, 'Comments')
232 self.list.SetColumnWidth(0, 300)
233 self.list.SetColumnWidth(1, 150)
234 self.list.SetColumnWidth(2, 100)
235 self.list.SetColumnWidth(3, 100)
236
237 EVT_LIST_ITEM_SELECTED(self, 1100, self.OnItemSelected)
238
239 self.logprint("Connecting to slashdot... Please wait.")
240 # wxYield doesn't yet work here. That's why we use a timer
241 # to make sure that we see some GUI stuff before the slashdot
242 # file is transfered.
243 self.timer = QuickTimer(self.DoRefresh, 1000)
244
245 def logprint(self, x):
246 self.sb.logprint(x)
247
248 def OnFileExit(self, event):
249 self.Destroy()
250
251 def DoRefresh(self):
252 f = RetrieveAsFile('slashdot.org','/ultramode.txt',self.sb.logprint)
253 art_list = ParseSlashdot(f)
254 self.list.DeleteAllItems()
255 self.url = []
256 self.current = -1
257 i = 0;
258 for article in art_list:
259 self.list.InsertStringItem(i, article[0])
260 self.list.SetStringItem(i, 1, article[2])
261 self.list.SetStringItem(i, 2, article[3])
262 self.list.SetStringItem(i, 3, article[6])
263 self.url.append(article[1])
264 i = i + 1
265 self.logprint("File retrieved OK.")
266
267 def OnViewRefresh(self, event):
268 self.logprint("Connecting to slashdot... Please wait.");
269 wxYield()
270 self.DoRefresh()
271
272 def DoViewIndex(self):
273 if self.UseInternal:
274 self.view = HTMLTextView(self, -1, 'slashdot.org',
275 'http://slashdot.org')
276 self.view.Show(true)
277 else:
278 self.logprint(self.BrowserSettings % ('http://slashdot.org'))
279 os.system(self.BrowserSettings % ('http://slashdot.org'))
280 self.logprint("OK")
281
282 def OnViewIndex(self, event):
283 self.logprint("Starting browser... Please wait.")
284 wxYield()
285 self.DoViewIndex()
286
287 def DoViewArticle(self):
288 if self.current<0: return
289 url = self.url[self.current]
290 if self.UseInternal:
291 self.view = HTMLTextView(self, -1, url, url)
292 self.view.Show(true)
293 else:
294 self.logprint(self.BrowserSettings % (url))
295 os.system(self.BrowserSettings % (url))
296 self.logprint("OK")
297
298 def OnViewArticle(self, event):
299 self.logprint("Starting browser... Please wait.")
300 wxYield()
301 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