1 # Copyright (C) 2006 by Aiwota Programmer
2 # aiwotaprog@tetteke.tk
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
32 from threadlistmodel import ThreadListModel
33 from BbsType import bbs_type_judge_uri
37 from misc import ThreadInvoker
39 import bookmark_window
43 GLADE_FILENAME = "board_window.glade"
45 def open_board(uri, update=False):
47 raise ValueError, "parameter must not be empty"
49 winwrap = session.get_window(uri)
52 winwrap.window.present()
56 winwrap = WinWrap(uri)
60 class WinWrap(winwrapbase.WinWrapBase, board_data.BoardData):
62 def __init__(self, uri):
64 self.bbs_type = bbs_type_judge_uri.get_type(uri)
65 board_data.BoardData.__init__(self, self.bbs_type)
67 glade_path = os.path.join(config.glade_dir, GLADE_FILENAME)
68 self.widget_tree = gtk.glade.XML(glade_path)
71 self.widget_tree.signal_autoconnect(self)
73 self.window.set_title(self.bbs_type.uri)
74 self.treeview.set_model(ThreadListModel())
75 self.toolbar.unset_style()
77 renderer = gtk.CellRendererText()
79 for column_class in board_column.tree_view_column_list:
80 column_class(renderer, self.treeview)
82 self.treeview.set_fixed_height_mode(True)
85 board_plugins.load(self.treeview, self.menu_edit)
92 def _get_widgets(self):
93 self.window = self.widget_tree.get_widget("window_board")
94 self.treeview = self.widget_tree.get_widget("treeview")
95 self.popupmenu = self.widget_tree.get_widget("popup_treeview_menu")
96 self.toolbar = self.widget_tree.get_widget("toolbar")
97 self.statusbar = self.widget_tree.get_widget("appbar")
98 self.filterbar = self.widget_tree.get_widget(
99 "bonobodockitem_filterbar")
100 self.entry_filterbar = self.widget_tree.get_widget("entry_filterbar")
101 self.menu_edit = self.widget_tree.get_widget("menu_edit").get_submenu()
103 def set_status(self, text):
104 self.statusbar.set_status(text)
108 self.window.destroy()
111 return self.bbs_type.get_uri_base()
113 def open_thread(self):
114 treeselection = self.treeview.get_selection()
115 model, iter = treeselection.get_selected()
119 thread = model.get_value(iter, ThreadListModel.column_names.index("id"))
120 title = model.get_value(
121 iter, ThreadListModel.column_names.index("title"))
122 print thread + ':"' + title + '"', "activated"
124 res = model.get_value(iter, ThreadListModel.column_names.index("res"))
125 lineCount = model.get_value(
126 iter, ThreadListModel.column_names.index("lineCount"))
128 update = res > lineCount
130 bbs_type_for_thread = self.bbs_type.clone_with_thread(thread)
131 uri_opener.open_uri(bbs_type_for_thread.get_thread_uri(), update)
133 def update_datastore(self, datalist):
134 print "reflesh datastore"
137 for id, dic in datalist.iteritems():
141 httpdate = dic["lastModified"]
143 secs = misc.httpdate_to_secs(httpdate)
144 dic["lastModified"] = secs
146 dic["lastModified"] = 0
148 list_list.append(dic)
150 model = self.treeview.get_model()
151 model.set_list(list_list)
153 # redraw visible area after set list to model
154 self.treeview.queue_draw()
158 def on_thread_idx_updated(self, thread_uri, idx_dic):
159 if not thread_uri or not idx_dic:
162 # nothing to do if thread_uri does not belong to this board.
163 bbs_type = bbs_type_judge_uri.get_type(thread_uri)
164 if not bbs_type.is_thread() \
165 or not bbs_type.is_same_board(self.bbs_type):
168 thread = bbs_type.thread
170 model = self.treeview.get_model()
172 idx_dic["id"] = thread
174 idx_dic["lastModified"] = misc.httpdate_to_secs(
175 idx_dic["lastModified"])
177 idx_dic["lastModified"] = 0
178 model.modify_row(idx_dic)
180 def load(self, update=False):
183 datalist = self.load_idxfiles()
184 self.merge_local_subjecttxt(datalist)
185 gobject.idle_add(self.update_datastore, datalist)
188 print "start get subject.txt"
189 datalist = self.load_idxfiles()
190 self.merge_remote_subjecttxt(datalist)
191 gobject.idle_add(self.update_datastore, datalist)
193 sbj_path = misc.get_board_subjecttxt_path(self.bbs_type)
194 sbj_exists = os.path.exists(sbj_path)
196 if update or not sbj_exists:
197 t = ThreadInvoker(lambda *args: -1, get_remote)
200 t = ThreadInvoker(lambda *args: -1, load_local)
205 states_path = misc.get_board_states_path(self.bbs_type)
206 dirname = os.path.dirname(states_path)
208 # save only if board dir exists.
209 if os.path.exists(dirname):
210 window_width, window_height = self.window.get_size()
211 toolbar_visible = self.toolbar.parent.get_property("visible")
212 statusbar_visible = self.statusbar.get_property("visible")
213 filterbar_visible = self.filterbar.get_property("visible")
215 columns = self.treeview.get_columns()
218 for column in columns:
224 width += str(column.get_width())
226 sort_column_name, sort_reverse = \
227 self.treeview.get_model().get_sort()
228 sort_reverse = str(sort_reverse)
230 f = file(states_path, "w")
232 f.write("columns=" + order + "\n")
233 f.write("widths=" + width + "\n")
234 f.write("sort_column=" + sort_column_name + "\n")
235 f.write("sort_reverse=" + sort_reverse + "\n")
236 f.write("window_width=" + str(window_width) + "\n")
237 f.write("window_height=" + str(window_height) + "\n")
238 f.write("toolbar_visible=" + str(toolbar_visible) + "\n")
239 f.write("statusbar_visible=" + str(statusbar_visible) + "\n")
240 f.write("filterbar_visible=" + str(filterbar_visible) + "\n")
244 traceback.print_exc()
250 toolbar_visible = True
251 statusbar_visible = True
252 filterbar_visible = False
255 key_base = config.gconf_app_key_base() + "/board_states"
256 gconf_client = gconf.client_get_default()
257 width = gconf_client.get_int(key_base + "/window_width")
258 height = gconf_client.get_int(key_base + "/window_height")
259 toolbar_visible = gconf_client.get_bool(key_base + "/toolbar")
260 statusbar_visible = gconf_client.get_bool(key_base + "/statusbar")
261 filterbar_visible = gconf_client.get_bool(key_base + "/filterbar")
266 window_height = height
268 traceback.print_exc()
270 states_path = misc.get_board_states_path(self.bbs_type)
271 if os.path.exists(states_path):
272 sort_column_name = "num"
274 clns = self.treeview.get_columns()
275 treeviewcolumn = dict([(cln.id, cln) for cln in clns])
276 for line in file(states_path):
277 if line.startswith("columns="):
278 line = line[len("columns="):].rstrip("\n")
280 for name in line.split(","):
281 if name in treeviewcolumn:
282 column = treeviewcolumn[name]
283 self.treeview.move_column_after(
286 elif line.startswith("widths="):
287 line = line[len("widths="):].rstrip("\n")
288 columns = self.treeview.get_columns()
289 for i, width in enumerate(line.split(",")):
296 columns[i].set_fixed_width(width)
297 elif line.startswith("sort_column="):
298 kolumn_name = line[len("sort_column="):].rstrip("\n")
299 if kolumn_name in treeviewcolumn:
300 sort_column_name = kolumn_name
301 elif line.startswith("sort_reverse="):
302 reverse = line[len("sort_reverse="):].rstrip("\n")
303 sort_reverse = reverse == "True"
304 elif line.startswith("window_height="):
305 height = window_height
308 line[len("window_height="):].rstrip("\n"))
312 window_height = height
313 elif line.startswith("window_width="):
317 line[len("window_width="):].rstrip("\n"))
322 elif line.startswith("toolbar_visible="):
323 tbar = line[len("toolbar_visible="):].rstrip("\n")
324 toolbar_visible = tbar == "True"
325 elif line.startswith("statusbar_visible="):
326 sbar = line[len("statusbar_visible="):].rstrip("\n")
327 statusbar_visible = sbar == "True"
328 elif line.startswith("filterbar_visible="):
329 fbar = line[len("filterbar_visible="):].rstrip("\n")
330 filterbar_visible = fbar == "True"
332 self.treeview.get_model().sort(
333 sort_column_name, True, sort_reverse)
335 self.window.set_default_size(window_width, window_height)
337 if not toolbar_visible:
338 gobject.idle_add(self.toolbar.parent.hide,
339 priority=gobject.PRIORITY_HIGH)
340 if not statusbar_visible:
341 gobject.idle_add(self.statusbar.hide,
342 priority=gobject.PRIORITY_HIGH)
343 if not filterbar_visible:
344 gobject.idle_add(self.filterbar.hide,
345 priority=gobject.PRIORITY_HIGH)
347 traceback.print_exc()
349 def on_menu_toolbar_activate(self, widget):
350 if self.toolbar.parent.get_property("visible"):
351 self.toolbar.parent.hide()
353 self.toolbar.parent.show()
355 def on_menu_statusbar_activate(self, widget):
356 if self.statusbar.get_property("visible"):
357 self.statusbar.hide()
359 self.statusbar.show()
364 # menu and toolbutton
366 def on_menu_add_bookmark_activate(self, widget):
367 bookmark_list.bookmark_list.add_bookmark_with_edit(
368 uri=self.bbs_type.uri)
370 def on_menu_close_activate(self, widget):
373 def on_menu_delete_activate(self, widget):
374 selection = self.treeview.get_selection()
375 model, iter = selection.get_selected()
378 thread = model.get_value(
379 iter, ThreadListModel.column_names.index("id"))
381 bbs_type_for_thread = self.bbs_type.clone_with_thread(thread)
383 dat_path = misc.get_thread_dat_path(bbs_type_for_thread)
387 traceback.print_exc()
388 idx_path = misc.get_thread_idx_path(bbs_type_for_thread)
392 traceback.print_exc()
393 states_path = misc.get_thread_states_path(bbs_type_for_thread)
395 os.remove(states_path)
397 traceback.print_exc()
399 def on_menu_filter_activate(self, widget):
400 self.filterbar.show()
401 self.entry_filterbar.grab_focus()
403 def on_menu_manage_bookmarks_activate(self, widget):
404 bookmark_window.open()
406 def on_menu_open_activate(self, widget):
409 def on_menu_quit_activate(self, widget):
412 def on_menu_refresh_activate(self, widget):
418 def on_window_board_delete_event(self, widget, event):
422 def on_window_board_destroy(self, widget):
428 def on_treeview_row_activated(self, widget, path, view_column):
431 def on_treeview_button_press_event(self, widget, event):
432 if event.button == 3:
436 pthinfo = widget.get_path_at_pos(x, y)
437 if pthinfo is not None:
438 path, col, cellx, celly = pthinfo
440 widget.set_cursor(path, col, 0)
441 self.popupmenu.popup(None, None, None, event.button, time)
447 def on_entry_filterbar_activate(self, widget):
448 text = widget.get_text()
450 def func(model, item):
452 item["title"].index(text)
458 model = self.treeview.get_model()
464 model.refilter(filter_func)
466 def on_toolbutton_filterbar_close_clicked(self, widget):
467 self.filterbar.hide()
469 def on_button_filterbar_clear_clicked(self, widget):
470 self.entry_filterbar.set_text("")
471 model = self.treeview.get_model()