0.4.3-5 Added GetStatus dbus call, and bugfixes
[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
35 class ExportOpmlData():
36     def __init__(self, parent, listing):
37         fs = hildon.FileSystemModel()
38         dialog = hildon.FileChooserDialog(parent, gtk.FILE_CHOOSER_ACTION_SAVE, fs)
39                                #(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
40                                 #gtk.STOCK_SAVE, gtk.RESPONSE_OK))
41                                #)
42         #dialog = gobject.new(hildon.FileChooserDialog, \
43         #            action=gtk.FILE_CHOOSER_ACTION_SAVE)
44         #dialog.set_default_response(gtk.RESPONSE_OK)
45         #dialog.set_property('autonaming',False)
46         #dialog.set_property('show-files',True)
47         dialog.set_current_folder('/home/user/MyDocs/')
48         dialog.set_current_name('feedingit-export')
49         dialog.set_extension('opml')
50         response = dialog.run()
51         dialog.hide()
52         if response == gtk.RESPONSE_OK:
53                 filename = dialog.get_filename()
54                 print filename
55             #try:
56
57                 cont = True
58                 if isfile(filename):
59                     note = "File already exists. Aborted"
60                     confirm = hildon.Note ("confirmation", parent, "File already exists. Are you sure you want to overwrite it?", gtk.STOCK_DIALOG_WARNING )
61                     confirm.set_button_texts ("Yes", "Cancel")
62                     response = confirm.run()
63                     confirm.destroy()
64                     if response == gtk.RESPONSE_OK:
65                         cont = True
66                     else:
67                         note = "Operation cancelled."
68                         cont = False
69                 if cont:
70                     file = open(filename, "w")
71                     file.write(self.getOpmlText(listing))
72                     file.close()
73                     note = "Feeds exported to %s" %filename
74             #except:
75                 note = "Failed to export feeds"
76             
77             #dialog.destroy()
78             #dialog = hildon.Note ("information", parent, note , gtk.STOCK_DIALOG_INFO )
79             #dialog.run()
80             #dialog.destroy()
81         elif response == gtk.RESPONSE_CANCEL:
82             dialog.destroy()  
83
84     def getOpmlText(self, listing):
85         time_now = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime())
86         opml_text = """<?xml version="1.0" encoding="UTF-8"?>
87 <opml version="1.0">
88 <head>
89     <title>Feeding It Export</title>
90 </head>
91 <body>
92 """
93         for key in listing.getListOfFeeds():
94             title = listing.getFeedTitle(key)
95             url = listing.getFeedUrl(key)
96             if not title == "Archived Articles": 
97                 opml_text += """\n\t\t<outline  type="rss" text="%s" title="%s" xmlUrl="%s"/>""" % (self.sanitize(title), self.sanitize(title), self.sanitize(url))
98         opml_text += """\n</body>\n</opml>\n"""
99         return opml_text
100     
101     def sanitize(self, text):
102         return text.encode('ascii', 'xmlcharrefreplace')
103         
104         
105
106 class GetOpmlData():
107     def __init__(self, parent):
108         self.parent = parent
109         dialog = hildon.Note ("confirmation", parent, "What type of OPML?", gtk.STOCK_DIALOG_WARNING )
110         dialog.set_button_texts ("File", "URL")
111         response = dialog.run()
112         dialog.destroy()
113     
114         if response == gtk.RESPONSE_OK:
115             # Choose a file
116             self.data = self.askForFile()
117         else:
118             # Download a URL
119             self.data = self.downloadFile()
120             
121     def getData(self):
122         if not self.data == None:
123                dialog = OpmlDialog(self.parent, self.data)
124                response = dialog.run()
125                if response == gtk.RESPONSE_ACCEPT:
126                    items = dialog.getItems()
127                else:
128                    items = []
129                dialog.destroy()
130                return items
131         return []
132
133     def downloadFile(self):
134         dlg = gtk.Dialog("OPML Import", self.parent, gtk.DIALOG_DESTROY_WITH_PARENT,
135                      (gtk.STOCK_OK, gtk.RESPONSE_OK,
136                       gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
137         lbl = gtk.Label("Enter the URL of the OPML file:")
138         lbl.show()
139         dlg.vbox.pack_start(lbl)
140         entry = gtk.Entry()
141         entry.set_text("http://")
142         entry.select_region(0,-1)
143         entry.show()
144         dlg.vbox.pack_start(entry, False)
145
146         resp = dlg.run()
147         url = entry.get_text()
148         dlg.destroy()
149         if resp == gtk.RESPONSE_CANCEL:
150             return None
151         try:
152             f = urllib2.urlopen(url)
153             data = f.read()
154             f.close()
155         except:
156             #Show error note
157             return None
158         return data
159
160     def askForFile(self):
161         #dialog = hildon.FileChooserDialog(self.parent,
162         #                       gtk.FILE_CHOOSER_ACTION_OPEN)
163         #dialog = gobject.new(hildon.FileChooserDialog, \
164         #            action=gtk.FILE_CHOOSER_ACTION_OPEN)
165         #dialog.set_default_response(gtk.RESPONSE_OK)
166         fs = hildon.FileSystemModel()
167         dialog = hildon.FileChooserDialog(self.parent, gtk.FILE_CHOOSER_ACTION_OPEN, fs)
168         
169         filter = gtk.FileFilter()
170         filter.set_name("All files")
171         filter.add_pattern("*")
172         dialog.add_filter(filter)
173
174         filter = gtk.FileFilter()
175         filter.set_name("OPML")
176         filter.add_pattern("*.xml")
177         filter.add_pattern("*.opml")
178         dialog.add_filter(filter)
179
180         response = dialog.run()
181         if response == gtk.RESPONSE_OK:
182             file = open(dialog.get_filename())
183             data = file.read()
184             file.close()
185             dialog.destroy()
186             return data
187         elif response == gtk.RESPONSE_CANCEL:
188             dialog.destroy()
189             return None
190
191
192 class OpmlDialog(gtk.Dialog):
193     def parse(self, opmlData):
194         self.feeds = []
195         dom1 = parseString(opmlData)
196         
197         outlines = dom1.getElementsByTagName('outline')
198         for outline in outlines:
199             title = outline.getAttribute('text')
200             url = outline.getAttribute('xmlUrl')
201             if url == "":
202                 url = outline.getAttribute('htmlUrl')
203             if not url == "":
204                 self.feeds.append( (title, url) )
205         
206     def getFeedLinks(self):
207         return self.feeds
208         
209     def __init__(self, parent, opmlData):
210         self.parse(opmlData)
211         gtk.Dialog.__init__(self, "Select OPML Feeds",  parent, gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
212         
213         self.pannableArea = hildon.PannableArea()
214         self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
215         self.treeview = gtk.TreeView(self.treestore)
216
217         self.displayFeeds()
218
219         self.set_default_size(-1, 600)
220         self.vbox.pack_start(self.pannableArea)
221         
222         button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
223         button.set_label("Select All")
224         button.connect("clicked", self.button_select_all_clicked)
225         self.action_area.pack_end(button)
226         
227         button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
228         button.set_label("Unselect All")
229         button.connect("clicked", self.button_select_none_clicked)
230         self.action_area.pack_end(button)
231         
232         self.show_all()
233         
234     def button_select_all_clicked(self, button):
235         self.treeview.get_selection().select_all()
236         
237     def button_select_none_clicked(self, button):
238         self.treeview.get_selection().unselect_all()
239         
240     def displayFeeds(self):
241         self.treeview.destroy()
242         self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
243         self.treeview = gtk.TreeView()
244         
245         self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
246         hildon.hildon_gtk_tree_view_set_ui_mode(self.treeview, gtk.HILDON_UI_MODE_EDIT)
247         self.refreshList()
248         self.treeview.append_column(gtk.TreeViewColumn('Feed Name', gtk.CellRendererText(), text = 0))
249
250         self.pannableArea.add(self.treeview)
251         self.pannableArea.show_all()
252         self.treeview.get_selection().select_all()
253
254     def refreshList(self, selected=None, offset=0):
255         rect = self.treeview.get_visible_rect()
256         y = rect.y+rect.height
257         self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
258         self.treeview.set_model(self.treestore)
259         for (title, url) in self.feeds:
260             item = self.treestore.append([title, url])
261             self.treeview.get_selection().select_iter(item)
262         #self.treeview.get_selection().select_all()
263         self.pannableArea.show_all()
264
265     def getItems(self):
266         list = []
267         treeselection = self.treeview.get_selection()
268         (model, pathlist) = treeselection.get_selected_rows()
269         for path in pathlist:
270             list.append( (model.get_value(model.get_iter(path),0), model.get_value(model.get_iter(path),1)) )
271         return list
272
273 def showOpmlData(widget, parent, button):
274     dialog = GetOpmlData(parent)
275     print dialog.getData()
276     #dialog.destroy()
277
278 if __name__ == "__main__":
279     window = hildon.Window()
280     window.set_title("Test App")
281
282     
283     button = gtk.Button("Click to confirm.")
284     window.add(button)
285     button.connect("clicked", showOpmlData, window, button)
286     window.connect("destroy", gtk.main_quit)
287     window.show_all()
288
289     gtk.main()
290     window.destroy()