psa: remove old event feed items
[feedingit] / src / opml.py
1 #!/usr/bin/env python2.5
2
3
4 # Copyright (c) 2007-2008 INdT.
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 #  This program is distributed in the hope that it will be useful,
11 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #  GNU Lesser General Public License for more details.
14 #
15 #  You should have received a copy of the GNU Lesser General Public License
16 #  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 #
18
19 # ============================================================================
20 # Name        : FeedingIt.py
21 # Author      : Yves Marcoz
22 # Version     : 0.2.2
23 # Description : Simple RSS Reader
24 # ============================================================================
25
26 from xml.dom.minidom import parse, parseString
27 import urllib2
28 import gtk
29 import hildon
30 import gobject
31 import time
32 from os.path import isfile, dirname
33 import gobject
34 import logging
35 logger = logging.getLogger(__name__)
36
37 class ExportOpmlData():
38     def __init__(self, parent, listing):
39         fs = hildon.FileSystemModel()
40         dialog = hildon.FileChooserDialog(parent, gtk.FILE_CHOOSER_ACTION_SAVE, fs)
41                                #(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
42                                 #gtk.STOCK_SAVE, gtk.RESPONSE_OK))
43                                #)
44         #dialog = gobject.new(hildon.FileChooserDialog, \
45         #            action=gtk.FILE_CHOOSER_ACTION_SAVE)
46         #dialog.set_default_response(gtk.RESPONSE_OK)
47         #dialog.set_property('autonaming',False)
48         #dialog.set_property('show-files',True)
49         dialog.set_current_folder('/home/user/MyDocs/')
50         dialog.set_current_name('feedingit-export')
51         dialog.set_extension('opml')
52         response = dialog.run()
53         dialog.hide()
54         if response == gtk.RESPONSE_OK:
55                 filename = dialog.get_filename()
56                 logger.debug("ExportOpmlData: %s" % filename)
57             #try:
58
59                 cont = True
60                 if isfile(filename):
61                     note = "File already exists. Aborted"
62                     confirm = hildon.Note ("confirmation", parent, "File already exists. Are you sure you want to overwrite it?", gtk.STOCK_DIALOG_WARNING )
63                     confirm.set_button_texts ("Yes", "Cancel")
64                     response = confirm.run()
65                     confirm.destroy()
66                     if response == gtk.RESPONSE_OK:
67                         cont = True
68                     else:
69                         note = "Operation cancelled."
70                         cont = False
71                 if cont:
72                     file = open(filename, "w")
73                     file.write(self.getOpmlText(listing))
74                     file.close()
75                     note = "Feeds exported to %s" %filename
76             #except:
77                 note = "Failed to export feeds"
78             
79             #dialog.destroy()
80             #dialog = hildon.Note ("information", parent, note , gtk.STOCK_DIALOG_INFO )
81             #dialog.run()
82             #dialog.destroy()
83         elif response == gtk.RESPONSE_CANCEL:
84             dialog.destroy()  
85
86     def getOpmlText(self, listing):
87         time_now = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime())
88         opml_text = """<?xml version="1.0" encoding="UTF-8"?>
89 <opml version="1.0">
90 <head>
91     <title>Feeding It Export</title>
92 </head>
93 <body>
94 """
95         for key in listing.getListOfFeeds():
96             title = listing.getFeedTitle(key)
97             url = listing.getFeedUrl(key)
98             if not title == "Archived Articles": 
99                 opml_text += """\n\t\t<outline  type="rss" text="%s" title="%s" xmlUrl="%s"/>""" % (self.sanitize(title), self.sanitize(title), self.sanitize(url))
100         opml_text += """\n</body>\n</opml>\n"""
101         return opml_text
102     
103     def sanitize(self, text):
104         from cgi import escape
105         return escape(text).encode('ascii', 'xmlcharrefreplace')
106         
107         
108
109 class GetOpmlData():
110     def __init__(self, parent):
111         self.parent = parent
112         dialog = hildon.Note ("confirmation", parent, "What type of OPML?", gtk.STOCK_DIALOG_WARNING )
113         dialog.set_button_texts ("File", "URL")
114         response = dialog.run()
115         dialog.destroy()
116     
117         if response == gtk.RESPONSE_OK:
118             # Choose a file
119             self.data = self.askForFile()
120         else:
121             # Download a URL
122             self.data = self.downloadFile()
123             
124     def getData(self):
125         if not self.data == None:
126                dialog = OpmlDialog(self.parent, self.data)
127                response = dialog.run()
128                if response == gtk.RESPONSE_ACCEPT:
129                    items = dialog.getItems()
130                else:
131                    items = []
132                dialog.destroy()
133                return items
134         return []
135
136     def downloadFile(self):
137         dlg = gtk.Dialog("Import OPML from web", self.parent, gtk.DIALOG_DESTROY_WITH_PARENT,
138                      ('Import', gtk.RESPONSE_OK,
139                       gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
140         hb = gtk.HBox(False, 5)
141         hb.pack_start(gtk.Label('URL:'), expand=False)
142         entry = hildon.Entry(0)
143         entry.set_text("http://")
144         entry.select_region(-1, -1)
145         hb.pack_start(entry, expand=True)
146         hb.show_all()
147         dlg.vbox.pack_start(hb, False)
148
149         resp = dlg.run()
150         url = entry.get_text()
151         dlg.destroy()
152         if resp == gtk.RESPONSE_CANCEL:
153             return None
154         try:
155             f = urllib2.urlopen(url)
156             data = f.read()
157             f.close()
158         except:
159             #Show error note
160             return None
161         return data
162
163     def askForFile(self):
164         #dialog = hildon.FileChooserDialog(self.parent,
165         #                       gtk.FILE_CHOOSER_ACTION_OPEN)
166         #dialog = gobject.new(hildon.FileChooserDialog, \
167         #            action=gtk.FILE_CHOOSER_ACTION_OPEN)
168         #dialog.set_default_response(gtk.RESPONSE_OK)
169         fs = hildon.FileSystemModel()
170         dialog = hildon.FileChooserDialog(self.parent, gtk.FILE_CHOOSER_ACTION_OPEN, fs)
171         
172         filter = gtk.FileFilter()
173         filter.set_name("All files")
174         filter.add_pattern("*")
175         dialog.add_filter(filter)
176
177         filter = gtk.FileFilter()
178         filter.set_name("OPML")
179         filter.add_pattern("*.xml")
180         filter.add_pattern("*.opml")
181         dialog.add_filter(filter)
182
183         response = dialog.run()
184         if response == gtk.RESPONSE_OK:
185             file = open(dialog.get_filename())
186             data = file.read()
187             file.close()
188             dialog.destroy()
189             return data
190         elif response == gtk.RESPONSE_CANCEL:
191             dialog.destroy()
192             return None
193
194
195 class OpmlDialog(gtk.Dialog):
196     def parse(self, opmlData):
197         self.feeds = []
198         dom1 = parseString(opmlData)
199         
200         outlines = dom1.getElementsByTagName('outline')
201         for outline in outlines:
202             title = outline.getAttribute('text')
203             url = outline.getAttribute('xmlUrl')
204             if url == "":
205                 url = outline.getAttribute('htmlUrl')
206             if not url == "":
207                 self.feeds.append( (title, url) )
208         
209     def getFeedLinks(self):
210         return self.feeds
211         
212     def __init__(self, parent, opmlData):
213         self.parse(opmlData)
214         gtk.Dialog.__init__(self, "Select OPML Feeds",  parent, gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
215         
216         self.pannableArea = hildon.PannableArea()
217         self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
218         self.treeview = gtk.TreeView(self.treestore)
219
220         self.displayFeeds()
221
222         self.set_default_size(-1, 600)
223         self.vbox.pack_start(self.pannableArea)
224         
225         button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
226         button.set_label("Select All")
227         button.connect("clicked", self.button_select_all_clicked)
228         self.action_area.pack_end(button)
229         
230         button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
231         button.set_label("Unselect All")
232         button.connect("clicked", self.button_select_none_clicked)
233         self.action_area.pack_end(button)
234         
235         self.show_all()
236         
237     def button_select_all_clicked(self, button):
238         self.treeview.get_selection().select_all()
239         
240     def button_select_none_clicked(self, button):
241         self.treeview.get_selection().unselect_all()
242         
243     def displayFeeds(self):
244         self.treeview.destroy()
245         self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
246         self.treeview = gtk.TreeView()
247         
248         self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
249         hildon.hildon_gtk_tree_view_set_ui_mode(self.treeview, gtk.HILDON_UI_MODE_EDIT)
250         self.refreshList()
251         self.treeview.append_column(gtk.TreeViewColumn('Feed Name', gtk.CellRendererText(), text = 0))
252
253         self.pannableArea.add(self.treeview)
254         self.pannableArea.show_all()
255         self.treeview.get_selection().select_all()
256
257     def refreshList(self, selected=None, offset=0):
258         rect = self.treeview.get_visible_rect()
259         y = rect.y+rect.height
260         self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
261         self.treeview.set_model(self.treestore)
262         for (title, url) in self.feeds:
263             item = self.treestore.append([title, url])
264             self.treeview.get_selection().select_iter(item)
265         #self.treeview.get_selection().select_all()
266         self.pannableArea.show_all()
267
268     def getItems(self):
269         list = []
270         treeselection = self.treeview.get_selection()
271         (model, pathlist) = treeselection.get_selected_rows()
272         for path in pathlist:
273             list.append( (model.get_value(model.get_iter(path),0), model.get_value(model.get_iter(path),1)) )
274         return list
275
276 def showOpmlData(widget, parent, button):
277     dialog = GetOpmlData(parent)
278     logger.debug("showOpmlData: %s" % dialog.getData())
279     #dialog.destroy()
280
281 if __name__ == "__main__":
282     window = hildon.Window()
283     window.set_title("Test App")
284
285     
286     button = gtk.Button("Click to confirm.")
287     window.add(button)
288     button.connect("clicked", showOpmlData, window, button)
289     window.connect("destroy", gtk.main_quit)
290     window.show_all()
291
292     gtk.main()
293     window.destroy()