Added config dialogs + auto-update
[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"/>""" % (title, title, url)
98         opml_text += """\n</body>\n</opml>\n"""
99         return opml_text
100         
101
102 class GetOpmlData():
103     def __init__(self, parent):
104         self.parent = parent
105         dialog = hildon.Note ("confirmation", parent, "What type of OPML?", gtk.STOCK_DIALOG_WARNING )
106         dialog.set_button_texts ("File", "URL")
107         response = dialog.run()
108         dialog.destroy()
109     
110         if response == gtk.RESPONSE_OK:
111             # Choose a file
112             self.data = self.askForFile()
113         else:
114             # Download a URL
115             self.data = self.downloadFile()
116             
117     def getData(self):
118         if not self.data == None:
119                dialog = OpmlDialog(self.parent, self.data)
120                response = dialog.run()
121                if response == gtk.RESPONSE_ACCEPT:
122                    items = dialog.getItems()
123                else:
124                    items = []
125                dialog.destroy()
126                return items
127         return []
128
129     def downloadFile(self):
130         dlg = gtk.Dialog("OPML Import", self.parent, gtk.DIALOG_DESTROY_WITH_PARENT,
131                      (gtk.STOCK_OK, gtk.RESPONSE_OK,
132                       gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
133         lbl = gtk.Label("Enter the URL of the OPML file:")
134         lbl.show()
135         dlg.vbox.pack_start(lbl)
136         entry = gtk.Entry()
137         entry.set_text("http://")
138         entry.select_region(0,-1)
139         entry.show()
140         dlg.vbox.pack_start(entry, False)
141
142         resp = dlg.run()
143         url = entry.get_text()
144         dlg.destroy()
145         if resp == gtk.RESPONSE_CANCEL:
146             return None
147         try:
148             f = urllib2.urlopen(url)
149             data = f.read()
150             f.close()
151         except:
152             #Show error note
153             return None
154         return data
155
156     def askForFile(self):
157         #dialog = hildon.FileChooserDialog(self.parent,
158         #                       gtk.FILE_CHOOSER_ACTION_OPEN)
159         #dialog = gobject.new(hildon.FileChooserDialog, \
160         #            action=gtk.FILE_CHOOSER_ACTION_OPEN)
161         #dialog.set_default_response(gtk.RESPONSE_OK)
162         fs = hildon.FileSystemModel()
163         dialog = hildon.FileChooserDialog(self.parent, gtk.FILE_CHOOSER_ACTION_OPEN, fs)
164         
165         filter = gtk.FileFilter()
166         filter.set_name("All files")
167         filter.add_pattern("*")
168         dialog.add_filter(filter)
169
170         filter = gtk.FileFilter()
171         filter.set_name("OPML")
172         filter.add_pattern("*.xml")
173         filter.add_pattern("*.opml")
174         dialog.add_filter(filter)
175
176         response = dialog.run()
177         if response == gtk.RESPONSE_OK:
178             file = open(dialog.get_filename())
179             data = file.read()
180             file.close()
181             dialog.destroy()
182             return data
183         elif response == gtk.RESPONSE_CANCEL:
184             dialog.destroy()
185             return None
186
187
188 class OpmlDialog(gtk.Dialog):
189     def parse(self, opmlData):
190         self.feeds = []
191         dom1 = parseString(opmlData)
192         
193         outlines = dom1.getElementsByTagName('outline')
194         for outline in outlines:
195             title = outline.getAttribute('text')
196             url = outline.getAttribute('xmlUrl')
197             if url == "":
198                 url = outline.getAttribute('htmlUrl')
199             if not url == "":
200                 self.feeds.append( (title, url) )
201         
202     def getFeedLinks(self):
203         return self.feeds
204         
205     def __init__(self, parent, opmlData):
206         self.parse(opmlData)
207         gtk.Dialog.__init__(self, "Select OPML Feeds",  parent, gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
208         
209         self.pannableArea = hildon.PannableArea()
210         self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
211         self.treeview = gtk.TreeView(self.treestore)
212
213         self.displayFeeds()
214
215         self.set_default_size(-1, 600)
216         self.vbox.pack_start(self.pannableArea)
217         
218         button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
219         button.set_label("Select All")
220         button.connect("clicked", self.button_select_all_clicked)
221         self.action_area.pack_end(button)
222         
223         button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
224         button.set_label("Unselect All")
225         button.connect("clicked", self.button_select_none_clicked)
226         self.action_area.pack_end(button)
227         
228         self.show_all()
229         
230     def button_select_all_clicked(self, button):
231         self.treeview.get_selection().select_all()
232         
233     def button_select_none_clicked(self, button):
234         self.treeview.get_selection().unselect_all()
235         
236     def displayFeeds(self):
237         self.treeview.destroy()
238         self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
239         self.treeview = gtk.TreeView()
240         
241         self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
242         hildon.hildon_gtk_tree_view_set_ui_mode(self.treeview, gtk.HILDON_UI_MODE_EDIT)
243         self.refreshList()
244         self.treeview.append_column(gtk.TreeViewColumn('Feed Name', gtk.CellRendererText(), text = 0))
245
246         self.pannableArea.add(self.treeview)
247         self.pannableArea.show_all()
248         self.treeview.get_selection().select_all()
249
250     def refreshList(self, selected=None, offset=0):
251         rect = self.treeview.get_visible_rect()
252         y = rect.y+rect.height
253         self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
254         self.treeview.set_model(self.treestore)
255         for (title, url) in self.feeds:
256             item = self.treestore.append([title, url])
257             self.treeview.get_selection().select_iter(item)
258         #self.treeview.get_selection().select_all()
259         self.pannableArea.show_all()
260
261     def getItems(self):
262         list = []
263         treeselection = self.treeview.get_selection()
264         (model, pathlist) = treeselection.get_selected_rows()
265         for path in pathlist:
266             list.append( (model.get_value(model.get_iter(path),0), model.get_value(model.get_iter(path),1)) )
267         return list
268
269 def showOpmlData(widget, parent, button):
270     dialog = GetOpmlData(parent)
271     print dialog.getData()
272     #dialog.destroy()
273
274 if __name__ == "__main__":
275     window = hildon.Window()
276     window.set_title("Test App")
277
278     
279     button = gtk.Button("Click to confirm.")
280     window.add(button)
281     button.connect("clicked", showOpmlData, window, button)
282     window.connect("destroy", gtk.main_quit)
283     window.show_all()
284
285     gtk.main()
286     window.destroy()