comparison finch/libgnt/pygnt/example/rss/gntrss-ui.py @ 18722:8b5082d54c1d

Make the rss-reader look and behave nicer.
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Sun, 29 Jul 2007 19:00:14 +0000
parents 64a7b13d3b8d
children 1aeda1e812a8
comparison
equal deleted inserted replaced
18721:7389b597a812 18722:8b5082d54c1d
21 USA 21 USA
22 """ 22 """
23 23
24 """ 24 """
25 This file deals with the UI part (gnt) of the application 25 This file deals with the UI part (gnt) of the application
26
27 TODO:
28 - Allow showing feeds of only selected 'category' and/or 'priority'. A different
29 window should be used to change such filtering.
30 - Display details of each item in its own window.
31 - Add search capability, and allow searching only in title/body. Also allow
32 filtering in the search results.
33 - Show the data and time for feed items (probably in a separate column .. perhaps not)
34 - Have a simple way to add a feed.
35 - Allow renaming a feed.
26 """ 36 """
27 37
28 import gntrss 38 import gntrss
29 import gnt 39 import gnt
30 import gobject 40 import gobject
37 47
38 gnt.gnt_init() 48 gnt.gnt_init()
39 49
40 class RssTree(gnt.Tree): 50 class RssTree(gnt.Tree):
41 __gsignals__ = { 51 __gsignals__ = {
42 'active_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_OBJECT,)), 52 'active_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_OBJECT,))
43 'key_pressed' : 'override'
44 } 53 }
45 54
46 def __init__(self): 55 def __init__(self):
47 self.active = None 56 self.active = None
48 gnt.Tree.__init__(self) 57 gnt.Tree.__init__(self)
58 gnt.set_flag(self, 8) # remove borders
59 self.connect('key_pressed', self.do_key_pressed)
49 60
50 def set_active(self, active): 61 def set_active(self, active):
51 if self.active == active: 62 if self.active == active:
52 return 63 return
53 if self.active: 64 if self.active:
55 old = self.active 66 old = self.active
56 self.active = active 67 self.active = active
57 self.set_row_flags(self.active, gnt.TEXT_FLAG_UNDERLINE) 68 self.set_row_flags(self.active, gnt.TEXT_FLAG_UNDERLINE)
58 self.emit('active_changed', old) 69 self.emit('active_changed', old)
59 70
60 def do_key_pressed(self, text): 71 def do_key_pressed(self, null, text):
61 if text == '\r': 72 if text == '\r':
62 now = self.get_selection_data() 73 now = self.get_selection_data()
63 self.set_active(now) 74 self.set_active(now)
64 return True 75 return True
65 return False 76 return False
121 132
122 #### 133 ####
123 # [[[ The list of feeds 134 # [[[ The list of feeds
124 ### 135 ###
125 136
137 # 'Add Feed' dialog
138 add_feed_win = None
139 def add_feed_win_closed(win):
140 global add_feed_win
141 add_feed_win = None
142
143 def add_new_feed():
144 global add_feed_win
145
146 if add_feed_win:
147 gnt.gnt_window_present(add_feed_win)
148 return
149 win = gnt.Window()
150 win.set_title("New Feed")
151
152 box = gnt.Box(False, False)
153 label = gnt.Label("Link")
154 box.add_widget(label)
155 entry = gnt.Entry("")
156 entry.set_size(40, 1)
157 box.add_widget(entry)
158
159 win.add_widget(box)
160 win.show()
161 add_feed_win = win
162 add_feed_win.connect("destroy", add_feed_win_closed)
163
126 # 164 #
127 # The active row in the feed-list has changed. Update the feed-item table. 165 # The active row in the feed-list has changed. Update the feed-item table.
128 def feed_active_changed(tree, old): 166 def feed_active_changed(tree, old):
129 items.remove_all() 167 items.remove_all()
130 if not tree.active: 168 if not tree.active:
131 return 169 return
170 update_items_title()
132 for item in tree.active.items: 171 for item in tree.active.items:
133 add_feed_item(item) 172 add_feed_item(item)
134 173
135 # 174 #
136 # Check for the action keys and decide how to deal with them. 175 # Check for the action keys and decide how to deal with them.
137 def feed_key_pressed(tree, text): 176 def feed_key_pressed(tree, text):
177 if tree.is_searching():
178 return
138 if text == 'r': 179 if text == 'r':
139 feed = tree.get_selection_data() 180 feed = tree.get_selection_data()
140 tree.perform_action_key('j') 181 tree.perform_action_key('j')
141 #tree.perform_action('move-down') 182 #tree.perform_action('move-down')
142 feed.refresh() 183 feed.refresh()
143 elif text == 'R': 184 elif text == 'R':
144 feeds = tree.get_rows() 185 feeds = tree.get_rows()
145 for feed in feeds: 186 for feed in feeds:
146 feed.refresh() 187 feed.refresh()
188 elif text == 'a':
189 add_new_feed()
147 else: 190 else:
148 return False 191 return False
149 return True 192 return True
150 193
151 feeds = RssTree() 194 feeds = RssTree()
152 feeds.set_property('columns', 2) 195 feeds.set_property('columns', 2)
153 feeds.set_col_width(0, 20) 196 feeds.set_col_width(0, 20)
154 feeds.set_col_width(1, 4) 197 feeds.set_col_width(1, 8)
155 feeds.set_column_resizable(0, False) 198 feeds.set_column_resizable(0, False)
156 feeds.set_column_resizable(1, False) 199 feeds.set_column_resizable(1, False)
157 feeds.set_column_is_right_aligned(1, True) 200 feeds.set_column_is_right_aligned(1, True)
158 feeds.set_show_separator(False) 201 feeds.set_show_separator(False)
202 feeds.set_column_title(0, "Feeds")
203 feeds.set_show_title(True)
159 204
160 feeds.connect('active_changed', feed_active_changed) 205 feeds.connect('active_changed', feed_active_changed)
161 feeds.connect('key_pressed', feed_key_pressed) 206 feeds.connect('key_pressed', feed_key_pressed)
207 gnt.unset_flag(feeds, 256) # Fix the width
162 208
163 #### 209 ####
164 # ]]] The list of feeds 210 # ]]] The list of feeds
165 ### 211 ###
166 212
175 details.clear() 221 details.clear()
176 if not tree.active: 222 if not tree.active:
177 return 223 return
178 item = tree.active 224 item = tree.active
179 details.append_text_with_flags(str(item.title) + "\n", gnt.TEXT_FLAG_BOLD) 225 details.append_text_with_flags(str(item.title) + "\n", gnt.TEXT_FLAG_BOLD)
180 details.append_text_with_flags(str(item.summary), gnt.TEXT_FLAG_NORMAL) 226 details.append_text_with_flags("Link: ", gnt.TEXT_FLAG_BOLD)
181 details.scroll(0) 227 details.append_text_with_flags(str(item.link) + "\n", gnt.TEXT_FLAG_UNDERLINE)
182 if item.unread: 228 details.append_text_with_flags("Date: ", gnt.TEXT_FLAG_BOLD)
183 item.set_property('unread', False) 229 details.append_text_with_flags(str(item.date) + "\n", gnt.TEXT_FLAG_NORMAL)
184 if old and old.unread: 230
185 old.set_property('unread', True) 231 details.append_text_with_flags("\n" + str(item.summary), gnt.TEXT_FLAG_NORMAL)
232 item.mark_unread(False)
233
234 if old and old.unread: # If the last selected item is marked 'unread', then make sure it's bold
235 items.set_row_flags(old, gnt.TEXT_FLAG_BOLD)
186 236
187 # 237 #
188 # Look for action keys in the feed-item list. 238 # Look for action keys in the feed-item list.
189 def item_key_pressed(tree, text): 239 def item_key_pressed(tree, text):
240 if tree.is_searching():
241 return
190 current = tree.get_selection_data() 242 current = tree.get_selection_data()
191 if text == 'M': # Mark all of the items 'read' 243 if text == 'M': # Mark all of the items 'read'
192 all = tree.get_rows() 244 all = tree.get_rows()
193 for item in all: 245 for item in all:
194 item.unread = False 246 item.mark_unread(False)
195 elif text == 'm': # Mark the current item 'read' 247 elif text == 'm': # Mark the current item 'read'
196 if current.unread: 248 current.mark_unread(False)
197 current.set_property('unread', False)
198 tree.perform_action_key('j') 249 tree.perform_action_key('j')
199 elif text == 'U': # Mark the current item 'unread' 250 elif text == 'U': # Mark the current item 'unread'
200 if not current.unread: 251 current.mark_unread(True)
201 current.set_property('unread', True)
202 elif text == 'd': 252 elif text == 'd':
203 current.remove() 253 current.remove()
204 tree.perform_action_key('j') 254 tree.perform_action_key('j')
205 else: 255 else:
206 return False 256 return False
207 return True 257 return True
208 258
209 items = RssTree() 259 items = RssTree()
210 items.set_property('columns', 1) 260 items.set_property('columns', 1)
211 items.set_col_width(0, 40) 261 items.set_col_width(0, 40)
262 items.set_column_title(0, "Items")
263 items.set_show_title(True)
212 items.connect('key_pressed', item_key_pressed) 264 items.connect('key_pressed', item_key_pressed)
213 items.connect('active_changed', item_active_changed) 265 items.connect('active_changed', item_active_changed)
214 266
267 size = gnt.screen_size()
268 items.set_size(size[0], size[1])
269
215 #### 270 ####
216 # ]]] The list of items in the feed 271 # ]]] The list of items in the feed
217 #### 272 ####
218 273
274 #
275 # Update the title of the items list depending on the selection in the feed list
276 def update_items_title():
277 feed = feeds.active
278 if feed:
279 items.set_column_title(0, str(feed.title) + ": " + str(feed.unread) + "(" + str(len(feed.items)) + ")")
280 else:
281 items.set_column_title(0, "Items")
282 items.draw()
283
219 # The container on the top 284 # The container on the top
285 line = gnt.Line(vertical = False)
286
287 # The textview to show the details of a feed
288 details = gnt.TextView()
289 details.set_take_focus(True)
290 details.set_flag(gnt.TEXT_VIEW_TOP_ALIGN)
291 details.attach_scroll_widget(details)
292
293 # Category tree
294 cat = gnt.Tree()
295 cat.set_property('columns', 1)
296 cat.set_column_title(0, 'Category')
297 cat.set_show_title(True)
298 gnt.set_flag(cat, 8) # remove borders
299
220 box = gnt.Box(homo = False, vert = False) 300 box = gnt.Box(homo = False, vert = False)
221 box.set_pad(0) 301 box.set_pad(0)
222 box.add_widget(feeds) 302
223 box.add_widget(items) 303 vbox = gnt.Box(homo = False, vert = True)
304 vbox.set_pad(0)
305 vbox.add_widget(feeds)
306 vbox.add_widget(gnt.Line(False))
307 vbox.add_widget(cat)
308 box.add_widget(vbox)
309
310 box.add_widget(gnt.Line(True))
311
312 vbox = gnt.Box(homo = False, vert = True)
313 vbox.set_pad(0)
314 vbox.add_widget(items)
315 vbox.add_widget(gnt.Line(False))
316 vbox.add_widget(details)
317 box.add_widget(vbox)
224 318
225 win.add_widget(box) 319 win.add_widget(box)
226
227 line = gnt.Line(vertical = False)
228 win.add_widget(line)
229
230 # The textview to show the details of a feed
231 details = gnt.TextView()
232
233 win.add_widget(details)
234
235 browser = gnt.Button("Open in Browser")
236 win.add_widget(browser)
237 details.attach_scroll_widget(browser)
238
239 win.show() 320 win.show()
240 321
241 def update_feed_title(feed, property): 322 def update_feed_title(feed, property):
242 if property.name == 'title': 323 if property.name == 'title':
243 feeds.change_text(feed, 0, feed.title) 324 feeds.change_text(feed, 0, feed.title)
244 elif property.name == 'unread': 325 elif property.name == 'unread':
245 feeds.change_text(feed, 1, str(feed.unread)) 326 feeds.change_text(feed, 1, str(feed.unread) + "(" + str(len(feed.items)) + ")")
327 if feeds.active == feed:
328 update_items_title()
246 329
247 # populate everything 330 # populate everything
248 for feed in gntrss.feeds: 331 for feed in gntrss.feeds:
249 feed.refresh() 332 feed.refresh()
250 add_feed(feed) 333 add_feed(feed)