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
This commit is contained in:
		
							
								
								
									
										342
									
								
								utils/wxPython/tests/wxSlash.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										342
									
								
								utils/wxPython/tests/wxSlash.py
									
									
									
									
									
										Normal file
									
								
							@@ -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()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user