From: Harco de Hilster Date: Sun, 31 Jan 1999 19:55:22 +0000 (+0000) Subject: The obligatory Slashdot headlines retriever. Every self-respecting modern X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/18b79501898d435188f5fbd9f1878852fbe8dc97 The obligatory Slashdot headlines retriever. Every self-respecting modern widget library has to have one... I think it also makes a nice demonstration of wxPython's capabilities. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1536 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/utils/wxPython/tests/wxSlash.py b/utils/wxPython/tests/wxSlash.py new file mode 100644 index 0000000000..855389aa38 --- /dev/null +++ b/utils/wxPython/tests/wxSlash.py @@ -0,0 +1,342 @@ +#!/usr/bin/python +from wxPython.wx import * +from httplib import HTTP +from htmllib import HTMLParser +import os +import re +import formatter + +__doc__ = """This is wxSlash 1.0 + + It's the obligatory Slashdot.org headlines reader that any modern +widget set/library must have in order to be taken seriously :-) + + Usage is quite simple; wxSlash attempts to download the 'ultramode.txt' +file from http://slashdot.org, which contains the headlines in a computer +friendly format. It then displays said headlines in a wxWindows list control. + + You can read articles using either Python's html library or an external +browser. Uncheck the 'browser->internal' menu item to use the latter option. +Use the settings dialog box to set how external browser is started. + + This code is available under the wxWindows license, see elsewhere. If you +modify this code, be aware of the fact that slashdot.org's maintainer, +CmdrTaco, explicitly asks 'ultramode.txt' downloaders not to do this +automatically more than twice per hour. If this feature is abused, CmdrTaco +may remove the ultramode file completely and that will make a *lot* of people +unhappy. + + I want to thank Alex Shnitman whose slashes.pl (Perl/GTK) script gave me +the idea for this applet. + + Have fun with it, + + Harm van der Heijden (H.v.d.Heijden@phys.tue.nl) +""" + +class HTMLTextView(wxFrame): + def __init__(self, parent, id, title='HTMLTextView', url=None): + wxFrame.__init__(self, parent, id, title, wxPyDefaultPosition, + wxSize(600,400)) + + self.mainmenu = wxMenuBar() + + menu = wxMenu() + menu.Append(201, '&Open URL...', 'Open URL') + EVT_MENU(self, 201, self.OnFileOpen) + menu.Append(209, 'E&xit', 'Exit viewer') + EVT_MENU(self, 209, self.OnFileExit) + + self.mainmenu.Append(menu, '&File') + self.SetMenuBar(self.mainmenu) + self.CreateStatusBar(1) + + self.text = wxTextCtrl(self, -1, "", wxPyDefaultPosition, + wxPyDefaultSize, wxTE_MULTILINE | wxTE_READONLY) + + if (url): + self.OpenURL(url) + + def logprint(self, x): + self.SetStatusText(x) + + def OpenURL(self, url): + self.url = url + m = re.match('file:(\S+)\s*', url) + if m: + f = open(m.groups()[0],'r') + else: + m = re.match('http://([^/]+)(/\S*)\s*', url) + if m: + host = m.groups()[0] + path = m.groups()[1] + else: + m = re.match('http://(\S+)\s*', url) + if not m: + # Invalid URL + self.logprint("Invalid or unsupported URL: %s" % (url)) + return + host = m.groups()[0] + path = '' + f = RetrieveAsFile(host,path,self.logprint) + if not f: + self.logprint("Could not open %s" % (url)) + return + self.logprint("Receiving data...") + data = f.read() + tmp = open('/tmp/html.txt','w') + fmt = formatter.AbstractFormatter(formatter.DumbWriter(tmp)) + p = HTMLParser(fmt) + self.logprint("Parsing data...") + p.feed(data) + p.close() + tmp.close() + tmp = open('/tmp/html.txt', 'r') + self.text.SetValue(tmp.read()) + self.SetTitle(url) + self.logprint(url) + + def OnFileOpen(self, event): + dlg = wxTextEntryDialog(self, "Enter URL to open:", "") + if dlg.ShowModal() == wxID_OK: + url = dlg.GetValue() + else: + url = None + if url: + self.OpenURL(url) + + def OnFileExit(self, event): + self.Close() + + def OnCloseWindow(self, event): + self.Destroy() + + +def ParseSlashdot(f): + art_sep = re.compile('%%\r?\n') + line_sep = re.compile('\r?\n') + data = f.read() + list = art_sep.split(data) + art_list = [] + for i in range(1,len(list)-1): + art_list.append(line_sep.split(list[i])) + return art_list + +def myprint(x): + print x + +def RetrieveAsFile(host, path='', logprint = myprint): + try: + h = HTTP(host) + except: + logprint("Failed to create HTTP connection to %s... is the network available?" % (host)) + return None + h.putrequest('GET',path) + h.putheader('Accept','text/html') + h.putheader('Accept','text/plain') + h.endheaders() + errcode, errmsg, headers = h.getreply() + if errcode != 200: + logprint("HTTP error code %d: %s" % (errcode, errmsg)) + return None + f = h.getfile() +# f = open('/home/harm/ultramode.txt','r') + return f + +# This one isn't defined in the default wxPython modules... +def EVT_LIST_ITEM_SELECTED(win, id, func): + win.Connect(id, -1, wxEVT_COMMAND_LIST_ITEM_SELECTED, func) + +class AppStatusBar(wxStatusBar): + def __init__(self, parent): + wxStatusBar.__init__(self,parent, -1) + self.SetFieldsCount(2) + self.SetStatusWidths([100,-1]) + self.but = wxButton(self, 1001, "Refresh") + EVT_BUTTON(self, 1001, parent.OnViewRefresh) + self.OnSize(None) + + def logprint(self,x): + self.SetStatusText(x,1) + + def OnSize(self, event): + rect = self.GetFieldRect(0) + self.but.SetPosition(wxPoint(rect.x+2, rect.y+2)) + # The width/height we get is false. Why? Now I use a stupid trick: + rect2 = self.GetFieldRect(1) + rect.width = rect2.x - 8; + rect.height = 25; + self.but.SetSize(wxSize(rect.width-4, rect.height-4)) + +# This is a simple timer class to start a function after a short delay; +# For example, if you're about to perform function f which may take a long +# time, write "Please wait" in the statusbar, then create a QuickTimer(f) +# object to automatically call f after a short delay. That way, wxWindows +# will get a chance to update the statusbar before the long function is +# called. +# FIXME: can this be done better using an OnIdle kind of thing? +class QuickTimer(wxTimer): + def __init__(self, func, wait=100): + wxTimer.__init__(self) + self.callback = func + self.Start(wait); # wait .1 second (.001 second doesn't work. why?) + def Notify(self): + self.Stop(); + apply(self.callback, ()); + +class AppFrame(wxFrame): + def __init__(self, parent, id, title): + wxFrame.__init__(self, parent, id, title, wxPyDefaultPosition, + wxSize(650, 250)) + + # if the window manager closes the window: + EVT_CLOSE(self, self.OnCloseWindow); + + # Now Create the menu bar and items + self.mainmenu = wxMenuBar() + + menu = wxMenu() + menu.Append(209, 'E&xit', 'Enough of this already!') + EVT_MENU(self, 209, self.OnFileExit) + self.mainmenu.Append(menu, '&File') + menu = wxMenu() + menu.Append(210, '&Refresh', 'Refresh headlines') + EVT_MENU(self, 210, self.OnViewRefresh) + menu.Append(211, '&Slashdot Index', 'View Slashdot index') + EVT_MENU(self, 211, self.OnViewIndex) + menu.Append(212, 'Selected &Article', 'View selected article') + EVT_MENU(self, 212, self.OnViewArticle) + self.mainmenu.Append(menu, '&View') + menu = wxMenu() + menu.Append(220, '&Internal', 'Use internal text browser',TRUE) + menu.Check(220, true) + self.UseInternal = 1; + EVT_MENU(self, 220, self.OnBrowserInternal) + menu.Append(222, '&Settings...', 'External browser Settings') + EVT_MENU(self, 222, self.OnBrowserSettings) + self.mainmenu.Append(menu, '&Browser') + menu = wxMenu() + menu.Append(230, '&About', 'Some documentation'); + EVT_MENU(self, 230, self.OnAbout) + self.mainmenu.Append(menu, '&Help') + + self.SetMenuBar(self.mainmenu) + + self.BrowserSettings = "netscape -remote 'OpenURL(%s, new_window)'" + + # A status bar to tell people what's happening + self.sb = AppStatusBar(self) + self.SetStatusBar(self.sb) + + self.list = wxListCtrl(self, 1100) + self.list.SetSingleStyle(wxLC_REPORT) + self.list.InsertColumn(0, 'Subject') + self.list.InsertColumn(1, 'Date') + self.list.InsertColumn(2, 'Posted by') + self.list.InsertColumn(3, 'Comments') + self.list.SetColumnWidth(0, 300) + self.list.SetColumnWidth(1, 150) + self.list.SetColumnWidth(2, 100) + self.list.SetColumnWidth(3, 100) + + EVT_LIST_ITEM_SELECTED(self, 1100, self.OnItemSelected) + + self.logprint("Connecting to slashdot... Please wait.") + # Need a longer time here. Don't really know why + self.timer = QuickTimer(self.DoRefresh, 1000) + + def logprint(self, x): + self.sb.logprint(x) + + def OnFileExit(self, event): + self.Destroy() + + def DoRefresh(self): + f = RetrieveAsFile('slashdot.org','/ultramode.txt',self.sb.logprint) + art_list = ParseSlashdot(f) + self.list.DeleteAllItems() + self.url = [] + self.current = -1 + i = 0; + for article in art_list: + self.list.InsertStringItem(i, article[0]) + self.list.SetItemString(i, 1, article[2]) + self.list.SetItemString(i, 2, article[3]) + self.list.SetItemString(i, 3, article[6]) + self.url.append(article[1]) + i = i + 1 + self.logprint("File retrieved OK.") + + def OnViewRefresh(self, event): + self.timer = QuickTimer(self.DoRefresh) + self.logprint("Connecting to slashdot... Please wait."); + + def DoViewIndex(self): + if self.UseInternal: + self.view = HTMLTextView(self, -1, 'slashdot.org', + 'http://slashdot.org') + self.view.Show(true) + else: + self.logprint(self.BrowserSettings % ('http://slashdot.org')) + os.system(self.BrowserSettings % ('http://slashdot.org')) + self.logprint("OK") + + def OnViewIndex(self, event): + self.logprint("Starting browser... Please wait.") + self.timer = QuickTimer(self.DoViewIndex) + + def DoViewArticle(self): + if self.current<0: return + url = self.url[self.current] + if self.UseInternal: + self.view = HTMLTextView(self, -1, url, url) + self.view.Show(true) + else: + self.logprint(self.BrowserSettings % (url)) + os.system(self.BrowserSettings % (url)) + self.logprint("OK") + + def OnViewArticle(self, event): + self.logprint("Starting browser... Please wait.") + self.timer = QuickTimer(self.DoViewArticle) + + def OnBrowserInternal(self, event): + if self.mainmenu.Checked(220): + self.UseInternal = 1 + else: + self.UseInternal = 0 + + def OnBrowserSettings(self, event): + dlg = wxTextEntryDialog(self, "Enter command to view URL.\nUse %s as a placeholder for the URL.", "", self.BrowserSettings); + if dlg.ShowModal() == wxID_OK: + self.BrowserSettings = dlg.GetValue() + + def OnAbout(self, event): + dlg = wxMessageDialog(self, __doc__, "wxSlash", wxOK | wxICON_INFORMATION) + dlg.ShowModal() + + def OnItemSelected(self, event): + self.current = event.m_itemIndex + self.logprint("URL: %s" % (self.url[self.current])) + + def OnCloseWindow(self, event): + self.Destroy() + +class MyApp(wxApp): + def OnInit(self): + frame = AppFrame(NULL, -1, "Slashdot Breaking News") + frame.Show(true) + self.SetTopWindow(frame) + return true + +# +# main thingy +# +if __name__ == '__main__': + app = MyApp(0) + app.MainLoop() + + + + +