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