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
33 from threadlistmodel import ThreadListModel
34 from BbsType import bbs_type_judge_uri
38 from misc import ThreadInvoker
40 import bookmark_window
45 GLADE_FILENAME = "board_window.glade"
47 def open_board(uri, update=False):
49 raise ValueError, "parameter must not be empty"
51 bbs_type = bbs_type_judge_uri.get_type(uri)
52 uri = bbs_type.get_uri_base() # use strict uri
54 winwrap = session.get_window(uri)
57 winwrap.window.present()
61 winwrap = WinWrap(bbs_type.uri) # pass the original uri
65 class WinWrap(winwrapbase.WinWrapBase, board_data.BoardData):
67 def __init__(self, uri):
69 self.bbs_type = bbs_type_judge_uri.get_type(uri)
70 board_data.BoardData.__init__(self, self.bbs_type)
72 glade_path = os.path.join(config.glade_dir, GLADE_FILENAME)
73 self.widget_tree = gtk.glade.XML(glade_path)
76 self.widget_tree.signal_autoconnect(self)
78 self.window.set_title(self.bbs_type.uri)
79 self.treeview.set_model(ThreadListModel())
80 self.toolbar.unset_style()
82 renderer = gtk.CellRendererText()
84 for column_class in board_column.tree_view_column_list:
85 column_class(renderer, self.treeview)
87 self.treeview.set_fixed_height_mode(True)
90 board_plugins.load(self.widget_tree)
97 def _get_widgets(self):
98 self.window = self.widget_tree.get_widget("window_board")
99 self.treeview = self.widget_tree.get_widget("treeview")
100 self.popupmenu = self.widget_tree.get_widget("popup_treeview_menu")
101 self.toolbar = self.widget_tree.get_widget("toolbar")
102 self.statusbar = self.widget_tree.get_widget("appbar")
103 self.progress = self.statusbar.get_progress()
104 self.filterbar = self.widget_tree.get_widget(
105 "bonobodockitem_filterbar")
106 self.entry_filterbar = self.widget_tree.get_widget("entry_filterbar")
108 def set_status(self, text):
109 self.statusbar.set_status(text)
111 def set_fraction(self, fraction):
112 self.progress.set_fraction(fraction)
116 self.window.destroy()
119 return self.bbs_type.get_uri_base()
122 self.window.deiconify()
125 self.window.iconify()
127 def open_thread(self):
128 treeselection = self.treeview.get_selection()
129 model, iter = treeselection.get_selected()
133 dic = model.get_dict(iter)
136 print thread + ':"' + title + '"', "activated"
139 lineCount = dic["lineCount"]
141 update = res > lineCount
143 bbs_type_for_thread = self.bbs_type.clone_with_thread(thread)
144 uri_opener.open_uri(bbs_type_for_thread.get_thread_uri(), update)
146 def update_datastore(self, new_list):
147 print "reflesh datastore"
149 self.treeview.get_model().set_list(new_list)
151 # redraw visible area after set list to model
152 self.treeview.queue_draw()
156 def on_thread_idx_updated(self, thread_uri, idx_dic):
157 if not thread_uri or not idx_dic:
160 # nothing to do if thread_uri does not belong to this board.
161 bbs_type = bbs_type_judge_uri.get_type(thread_uri)
162 if not bbs_type.is_thread() \
163 or not bbs_type.is_same_board(self.bbs_type):
166 thread = bbs_type.thread
168 model = self.treeview.get_model()
170 idx_dic["id"] = thread
172 idx_dic["lastModified"] = misc.httpdate_to_secs(
173 idx_dic["lastModified"])
175 idx_dic["lastModified"] = 0
176 model.modify_row(idx_dic)
178 def load(self, update=False):
180 def set_id(thread_id, item_dict):
181 item_dict["id"] = thread_id
184 def conv_dictdict_to_listdict(dictdict):
185 key_iter = dictdict.iterkeys()
186 value_iter = dictdict.itervalues()
187 iterable = itertools.imap(set_id, key_iter, value_iter)
189 # remove not in subject.txt and not cache.
190 iterable = itertools.ifilter(
191 lambda dic: dic["num"] > 0 or dic["lineCount"] > 0, iterable)
193 return [item_dict for item_dict in iterable]
196 datalist = self.load_idxfiles()
197 self.merge_local_subjecttxt(datalist)
198 new_list = conv_dictdict_to_listdict(datalist)
199 gobject.idle_add(self.update_datastore, new_list)
201 def get_remote(datalist):
202 print "start get subject.txt"
203 self.merge_remote_subjecttxt(datalist)
204 new_list = conv_dictdict_to_listdict(datalist)
205 gobject.idle_add(self.update_datastore, new_list)
208 def reset_progress():
209 self.progress.set_fraction(0.0)
211 gobject.idle_add(reset_progress)
216 dic["oldRes"] = dic["res"]
221 model = self.treeview.get_model()
223 iterable = model.original_list
225 iterable = itertools.imap(lambda dic: dic.copy(), iterable)
226 iterable = itertools.imap(init_some, iterable)
228 new_dict = dict([(dic["id"], dic) for dic in iterable])
233 sbj_path = misc.get_board_subjecttxt_path(self.bbs_type)
234 sbj_exists = os.path.exists(sbj_path)
238 if update or not sbj_exists:
239 new_dict = deep_copy()
240 t = ThreadInvoker(on_end, lambda *x: get_remote(new_dict))
243 t = ThreadInvoker(on_end, load_local)
248 states_path = misc.get_board_states_path(self.bbs_type)
249 dirname = os.path.dirname(states_path)
251 # save only if board dir exists.
252 if os.path.exists(dirname):
253 window_width, window_height = self.window.get_size()
254 toolbar_visible = self.toolbar.parent.get_property("visible")
255 statusbar_visible = self.statusbar.get_property("visible")
256 filterbar_visible = self.filterbar.get_property("visible")
258 columns = self.treeview.get_columns()
261 for column in columns:
267 width += str(column.get_width())
269 sort_column_name, sort_reverse = \
270 self.treeview.get_model().get_sort()
271 sort_reverse = str(sort_reverse)
273 f = file(states_path, "w")
275 f.write("columns=" + order + "\n")
276 f.write("widths=" + width + "\n")
277 f.write("sort_column=" + sort_column_name + "\n")
278 f.write("sort_reverse=" + sort_reverse + "\n")
279 f.write("window_width=" + str(window_width) + "\n")
280 f.write("window_height=" + str(window_height) + "\n")
281 f.write("toolbar_visible=" + str(toolbar_visible) + "\n")
282 f.write("statusbar_visible=" + str(statusbar_visible) + "\n")
283 f.write("filterbar_visible=" + str(filterbar_visible) + "\n")
287 traceback.print_exc()
291 states_dict = board_states.states_file_to_dict(self.bbs_type)
294 self.treeview.get_model().sort(
295 states_dict["sort_column"], True,
296 states_dict["sort_reverse"])
300 # set column order before set column width
301 treeviewcolumn = dict(
302 [(cln.id, cln) for cln in self.treeview.get_columns()])
304 for column_name in states_dict["columns"]:
305 if column_name in treeviewcolumn:
306 column = treeviewcolumn[column_name]
307 self.treeview.move_column_after(column, base_column)
310 # set column width afeter set column order
311 for width, column in itertools.izip(
312 states_dict["widths"], self.treeview.get_columns()):
314 column.set_fixed_width(width)
316 self.window.set_default_size(
317 states_dict["window_width"], states_dict["window_height"])
319 if not states_dict["toolbar_visible"]:
320 gobject.idle_add(self.toolbar.parent.hide,
321 priority=gobject.PRIORITY_HIGH)
322 if not states_dict["statusbar_visible"]:
323 gobject.idle_add(self.statusbar.hide,
324 priority=gobject.PRIORITY_HIGH)
325 if not states_dict["filterbar_visible"]:
326 gobject.idle_add(self.filterbar.hide,
327 priority=gobject.PRIORITY_HIGH)
329 traceback.print_exc()
331 def on_menu_toolbar_activate(self, widget):
332 if self.toolbar.parent.get_property("visible"):
333 self.toolbar.parent.hide()
335 self.toolbar.parent.show()
337 def on_menu_statusbar_activate(self, widget):
338 if self.statusbar.get_property("visible"):
339 self.statusbar.hide()
341 self.statusbar.show()
346 # menu and toolbutton
348 def on_menu_add_bookmark_activate(self, widget):
349 bookmark_list.bookmark_list.add_bookmark_with_edit(
350 uri=self.bbs_type.uri)
352 def on_menu_close_activate(self, widget):
355 def on_menu_delete_activate(self, widget):
356 selection = self.treeview.get_selection()
357 model, iter = selection.get_selected()
360 thread = model.get_dict(iter)["id"]
362 bbs_type_for_thread = self.bbs_type.clone_with_thread(thread)
364 dat_path = misc.get_thread_dat_path(bbs_type_for_thread)
368 traceback.print_exc()
369 idx_path = misc.get_thread_idx_path(bbs_type_for_thread)
373 traceback.print_exc()
374 states_path = misc.get_thread_states_path(bbs_type_for_thread)
376 os.remove(states_path)
378 traceback.print_exc()
380 def on_menu_filter_activate(self, widget):
381 self.filterbar.show()
382 self.entry_filterbar.grab_focus()
384 def on_menu_manage_bookmarks_activate(self, widget):
385 bookmark_window.open()
387 def on_menu_open_activate(self, widget):
390 def on_menu_quit_activate(self, widget):
393 def on_menu_refresh_activate(self, widget):
399 def on_window_board_delete_event(self, widget, event):
403 def on_window_board_destroy(self, widget):
404 self.popupmenu.destroy()
405 for column in self.treeview.get_columns():
412 def on_treeview_row_activated(self, widget, path, view_column):
415 def on_treeview_button_press_event(self, widget, event):
416 if event.button == 3:
420 pthinfo = widget.get_path_at_pos(x, y)
421 if pthinfo is not None:
422 path, col, cellx, celly = pthinfo
424 widget.set_cursor(path, col, 0)
425 self.popupmenu.popup(None, None, None, event.button, time)
431 def on_entry_filterbar_activate(self, widget):
432 text = widget.get_text()
434 def func(model, item):
436 item["title"].index(text)
442 model = self.treeview.get_model()
448 model.refilter(filter_func)
450 def on_toolbutton_filterbar_close_clicked(self, widget):
451 self.filterbar.hide()
453 def on_button_filterbar_clear_clicked(self, widget):
454 self.entry_filterbar.set_text("")
455 model = self.treeview.get_model()