2 from wxPython
.wx
import *
3 from httplib
import HTTP
4 from htmllib
import HTMLParser
9 __doc__
= """This is wxSlash 1.0
11 It's the obligatory Slashdot.org headlines reader that any modern
12 widget set/library must have in order to be taken seriously :-)
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.
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.
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
29 I want to thank Alex Shnitman whose slashes.pl (Perl/GTK) script gave me
30 the idea for this applet.
34 Harm van der Heijden (H.v.d.Heijden@phys.tue.nl)
37 class HTMLTextView(wxFrame
):
38 def __init__(self
, parent
, id, title
='HTMLTextView', url
=None):
39 wxFrame
.__init
__(self
, parent
, id, title
, wxPyDefaultPosition
,
42 self
.mainmenu
= wxMenuBar()
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
)
50 self
.mainmenu
.Append(menu
, '&File')
51 self
.SetMenuBar(self
.mainmenu
)
52 self
.CreateStatusBar(1)
54 self
.text
= wxTextCtrl(self
, -1, "", wxPyDefaultPosition
,
55 wxPyDefaultSize
, wxTE_MULTILINE | wxTE_READONLY
)
60 def logprint(self
, x
):
63 def OpenURL(self
, url
):
65 m
= re
.match('file:(\S+)\s*', url
)
67 f
= open(m
.groups()[0],'r')
69 m
= re
.match('http://([^/]+)(/\S*)\s*', url
)
74 m
= re
.match('http://(\S+)\s*', url
)
77 self
.logprint("Invalid or unsupported URL: %s" % (url
))
81 f
= RetrieveAsFile(host
,path
,self
.logprint
)
83 self
.logprint("Could not open %s" % (url
))
85 self
.logprint("Receiving data...")
87 tmp
= open('tmphtml.txt','w')
88 fmt
= formatter
.AbstractFormatter(formatter
.DumbWriter(tmp
))
90 self
.logprint("Parsing data...")
94 tmp
= open('tmphtml.txt', 'r')
95 self
.text
.SetValue(tmp
.read())
99 def OnFileOpen(self
, event
):
100 dlg
= wxTextEntryDialog(self
, "Enter URL to open:", "")
101 if dlg
.ShowModal() == wxID_OK
:
108 def OnFileExit(self
, event
):
111 def OnCloseWindow(self
, event
):
115 def ParseSlashdot(f
):
116 art_sep
= re
.compile('%%\r?\n')
117 line_sep
= re
.compile('\r?\n')
119 list = art_sep
.split(data
)
121 for i
in range(1,len(list)-1):
122 art_list
.append(line_sep
.split(list[i
]))
128 def RetrieveAsFile(host
, path
='', logprint
= myprint
):
132 logprint("Failed to create HTTP connection to %s... is the network available?" % (host
))
134 h
.putrequest('GET',path
)
135 h
.putheader('Accept','text/html')
136 h
.putheader('Accept','text/plain')
138 errcode
, errmsg
, headers
= h
.getreply()
140 logprint("HTTP error code %d: %s" % (errcode
, errmsg
))
143 # f = open('/home/harm/ultramode.txt','r')
147 class AppStatusBar(wxStatusBar
):
148 def __init__(self
, parent
):
149 wxStatusBar
.__init
__(self
,parent
, -1)
150 self
.SetFieldsCount(2)
151 self
.SetStatusWidths([100,-1])
152 self
.but
= wxButton(self
, 1001, "Refresh")
153 EVT_BUTTON(self
, 1001, parent
.OnViewRefresh
)
156 def logprint(self
,x
):
157 self
.SetStatusText(x
,1)
159 def OnSize(self
, event
):
160 rect
= self
.GetFieldRect(0)
161 self
.but
.SetPosition(wxPoint(rect
.x
+2, rect
.y
+2))
162 # The width/height we get is false. Why? Now I use a stupid trick:
163 rect2
= self
.GetFieldRect(1)
164 rect
.width
= rect2
.x
- 8;
166 self
.but
.SetSize(wxSize(rect
.width
-4, rect
.height
-4))
168 # This is a simple timer class to start a function after a short delay;
169 # For example, if you're about to perform function f which may take a long
170 # time, write "Please wait" in the statusbar, then create a QuickTimer(f)
171 # object to automatically call f after a short delay. That way, wxWindows
172 # will get a chance to update the statusbar before the long function is
174 # FIXME: can this be done better using an OnIdle kind of thing?
175 class QuickTimer(wxTimer
):
176 def __init__(self
, func
, wait
=100):
177 wxTimer
.__init
__(self
)
179 self
.Start(wait
); # wait .1 second (.001 second doesn't work. why?)
182 apply(self
.callback
, ());
184 class AppFrame(wxFrame
):
185 def __init__(self
, parent
, id, title
):
186 wxFrame
.__init
__(self
, parent
, id, title
, wxPyDefaultPosition
,
189 # if the window manager closes the window:
190 EVT_CLOSE(self
, self
.OnCloseWindow
);
192 # Now Create the menu bar and items
193 self
.mainmenu
= wxMenuBar()
196 menu
.Append(209, 'E&xit', 'Enough of this already!')
197 EVT_MENU(self
, 209, self
.OnFileExit
)
198 self
.mainmenu
.Append(menu
, '&File')
200 menu
.Append(210, '&Refresh', 'Refresh headlines')
201 EVT_MENU(self
, 210, self
.OnViewRefresh
)
202 menu
.Append(211, '&Slashdot Index', 'View Slashdot index')
203 EVT_MENU(self
, 211, self
.OnViewIndex
)
204 menu
.Append(212, 'Selected &Article', 'View selected article')
205 EVT_MENU(self
, 212, self
.OnViewArticle
)
206 self
.mainmenu
.Append(menu
, '&View')
208 menu
.Append(220, '&Internal', 'Use internal text browser',TRUE
)
209 menu
.Check(220, true
)
210 self
.UseInternal
= 1;
211 EVT_MENU(self
, 220, self
.OnBrowserInternal
)
212 menu
.Append(222, '&Settings...', 'External browser Settings')
213 EVT_MENU(self
, 222, self
.OnBrowserSettings
)
214 self
.mainmenu
.Append(menu
, '&Browser')
216 menu
.Append(230, '&About', 'Some documentation');
217 EVT_MENU(self
, 230, self
.OnAbout
)
218 self
.mainmenu
.Append(menu
, '&Help')
220 self
.SetMenuBar(self
.mainmenu
)
222 self
.BrowserSettings
= "netscape -remote 'OpenURL(%s, new_window)'"
224 # A status bar to tell people what's happening
225 self
.sb
= AppStatusBar(self
)
226 self
.SetStatusBar(self
.sb
)
228 self
.list = wxListCtrl(self
, 1100)
229 self
.list.SetSingleStyle(wxLC_REPORT
)
230 self
.list.InsertColumn(0, 'Subject')
231 self
.list.InsertColumn(1, 'Date')
232 self
.list.InsertColumn(2, 'Posted by')
233 self
.list.InsertColumn(3, 'Comments')
234 self
.list.SetColumnWidth(0, 300)
235 self
.list.SetColumnWidth(1, 150)
236 self
.list.SetColumnWidth(2, 100)
237 self
.list.SetColumnWidth(3, 100)
239 EVT_LIST_ITEM_SELECTED(self
, 1100, self
.OnItemSelected
)
241 self
.logprint("Connecting to slashdot... Please wait.")
242 # Need a longer time here. Don't really know why
243 self
.timer
= QuickTimer(self
.DoRefresh
, 1000)
245 def logprint(self
, x
):
248 def OnFileExit(self
, event
):
252 f
= RetrieveAsFile('slashdot.org','/ultramode.txt',self
.sb
.logprint
)
253 art_list
= ParseSlashdot(f
)
254 self
.list.DeleteAllItems()
258 for article
in art_list
:
259 self
.list.InsertStringItem(i
, article
[0])
260 self
.list.SetItemString(i
, 1, article
[2])
261 self
.list.SetItemString(i
, 2, article
[3])
262 self
.list.SetItemString(i
, 3, article
[6])
263 self
.url
.append(article
[1])
265 self
.logprint("File retrieved OK.")
267 def OnViewRefresh(self
, event
):
268 self
.timer
= QuickTimer(self
.DoRefresh
)
269 self
.logprint("Connecting to slashdot... Please wait.");
271 def DoViewIndex(self
):
273 self
.view
= HTMLTextView(self
, -1, 'slashdot.org',
274 'http://slashdot.org')
277 self
.logprint(self
.BrowserSettings
% ('http://slashdot.org'))
278 os
.system(self
.BrowserSettings
% ('http://slashdot.org'))
281 def OnViewIndex(self
, event
):
282 self
.logprint("Starting browser... Please wait.")
283 self
.timer
= QuickTimer(self
.DoViewIndex
)
285 def DoViewArticle(self
):
286 if self
.current
<0: return
287 url
= self
.url
[self
.current
]
289 self
.view
= HTMLTextView(self
, -1, url
, url
)
292 self
.logprint(self
.BrowserSettings
% (url
))
293 os
.system(self
.BrowserSettings
% (url
))
296 def OnViewArticle(self
, event
):
297 self
.logprint("Starting browser... Please wait.")
298 self
.timer
= QuickTimer(self
.DoViewArticle
)
300 def OnBrowserInternal(self
, event
):
301 if self
.mainmenu
.Checked(220):
306 def OnBrowserSettings(self
, event
):
307 dlg
= wxTextEntryDialog(self
, "Enter command to view URL.\nUse %s as a placeholder for the URL.", "", self
.BrowserSettings
);
308 if dlg
.ShowModal() == wxID_OK
:
309 self
.BrowserSettings
= dlg
.GetValue()
311 def OnAbout(self
, event
):
312 dlg
= wxMessageDialog(self
, __doc__
, "wxSlash", wxOK | wxICON_INFORMATION
)
315 def OnItemSelected(self
, event
):
316 self
.current
= event
.m_itemIndex
317 self
.logprint("URL: %s" % (self
.url
[self
.current
]))
319 def OnCloseWindow(self
, event
):
324 frame
= AppFrame(NULL
, -1, "Slashdot Breaking News")
326 self
.SetTopWindow(frame
)
332 if __name__
== '__main__':