1 #!/usr/bin/env python2.5
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.
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.
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/>.
19 # ============================================================================
21 # Author : Yves Marcoz
23 # Description : Simple RSS Reader
24 # ============================================================================
26 from xml.dom.minidom import parse, parseString
32 from os.path import isfile, dirname
35 logger = logging.getLogger(__name__)
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))
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()
54 if response == gtk.RESPONSE_OK:
55 filename = dialog.get_filename()
56 logger.debug("ExportOpmlData: %s" % 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()
66 if response == gtk.RESPONSE_OK:
69 note = "Operation cancelled."
72 file = open(filename, "w")
73 file.write(self.getOpmlText(listing))
75 note = "Feeds exported to %s" %filename
77 note = "Failed to export feeds"
80 #dialog = hildon.Note ("information", parent, note , gtk.STOCK_DIALOG_INFO )
83 elif response == gtk.RESPONSE_CANCEL:
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"?>
91 <title>Feeding It Export</title>
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"""
103 def sanitize(self, text):
104 from cgi import escape
105 return escape(text).encode('ascii', 'xmlcharrefreplace')
110 def __init__(self, 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()
117 if response == gtk.RESPONSE_OK:
119 self.data = self.askForFile()
122 self.data = self.downloadFile()
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()
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)
147 dlg.vbox.pack_start(hb, False)
150 url = entry.get_text()
152 if resp == gtk.RESPONSE_CANCEL:
155 f = urllib2.urlopen(url)
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)
172 filter = gtk.FileFilter()
173 filter.set_name("All files")
174 filter.add_pattern("*")
175 dialog.add_filter(filter)
177 filter = gtk.FileFilter()
178 filter.set_name("OPML")
179 filter.add_pattern("*.xml")
180 filter.add_pattern("*.opml")
181 dialog.add_filter(filter)
183 response = dialog.run()
184 if response == gtk.RESPONSE_OK:
185 file = open(dialog.get_filename())
190 elif response == gtk.RESPONSE_CANCEL:
195 class OpmlDialog(gtk.Dialog):
196 def parse(self, opmlData):
198 dom1 = parseString(opmlData)
200 outlines = dom1.getElementsByTagName('outline')
201 for outline in outlines:
202 title = outline.getAttribute('text')
203 url = outline.getAttribute('xmlUrl')
205 url = outline.getAttribute('htmlUrl')
207 self.feeds.append( (title, url) )
209 def getFeedLinks(self):
212 def __init__(self, parent, opmlData):
214 gtk.Dialog.__init__(self, "Select OPML Feeds", parent, gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
216 self.pannableArea = hildon.PannableArea()
217 self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
218 self.treeview = gtk.TreeView(self.treestore)
222 self.set_default_size(-1, 600)
223 self.vbox.pack_start(self.pannableArea)
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)
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)
237 def button_select_all_clicked(self, button):
238 self.treeview.get_selection().select_all()
240 def button_select_none_clicked(self, button):
241 self.treeview.get_selection().unselect_all()
243 def displayFeeds(self):
244 self.treeview.destroy()
245 self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
246 self.treeview = gtk.TreeView()
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)
251 self.treeview.append_column(gtk.TreeViewColumn('Feed Name', gtk.CellRendererText(), text = 0))
253 self.pannableArea.add(self.treeview)
254 self.pannableArea.show_all()
255 self.treeview.get_selection().select_all()
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()
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)) )
276 def showOpmlData(widget, parent, button):
277 dialog = GetOpmlData(parent)
278 logger.debug("showOpmlData: %s" % dialog.getData())
281 if __name__ == "__main__":
282 window = hildon.Window()
283 window.set_title("Test App")
286 button = gtk.Button("Click to confirm.")
288 button.connect("clicked", showOpmlData, window, button)
289 window.connect("destroy", gtk.main_quit)