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()
121 def open_thread(self):
122 treeselection = self.treeview.get_selection()
123 model, iter = treeselection.get_selected()
127 dic = model.get_dict(iter)
130 print thread + ':"' + title + '"', "activated"
133 lineCount = dic["lineCount"]
135 update = res > lineCount
137 bbs_type_for_thread = self.bbs_type.clone_with_thread(thread)
138 uri_opener.open_uri(bbs_type_for_thread.get_thread_uri(), update)
140 def update_datastore(self, new_list):
141 print "reflesh datastore"
143 self.treeview.get_model().set_list(new_list)
145 # redraw visible area after set list to model
146 self.treeview.queue_draw()
150 def on_thread_idx_updated(self, thread_uri, idx_dic):
151 if not thread_uri or not idx_dic:
154 # nothing to do if thread_uri does not belong to this board.
155 bbs_type = bbs_type_judge_uri.get_type(thread_uri)
156 if not bbs_type.is_thread() \
157 or not bbs_type.is_same_board(self.bbs_type):
160 thread = bbs_type.thread
162 model = self.treeview.get_model()
164 idx_dic["id"] = thread
166 idx_dic["lastModified"] = misc.httpdate_to_secs(
167 idx_dic["lastModified"])
169 idx_dic["lastModified"] = 0
170 model.modify_row(idx_dic)
172 def load(self, update=False):
174 def set_id(thread_id, item_dict):
175 item_dict["id"] = thread_id
178 def conv_dictdict_to_listdict(dictdict):
179 key_iter = dictdict.iterkeys()
180 value_iter = dictdict.itervalues()
181 iterable = itertools.imap(set_id, key_iter, value_iter)
183 # remove not in subject.txt and not cache.
184 iterable = itertools.ifilter(
185 lambda dic: dic["num"] > 0 or dic["lineCount"] > 0, iterable)
187 return [item_dict for item_dict in iterable]
190 datalist = self.load_idxfiles()
191 self.merge_local_subjecttxt(datalist)
192 new_list = conv_dictdict_to_listdict(datalist)
193 gobject.idle_add(self.update_datastore, new_list)
195 def get_remote(datalist):
196 print "start get subject.txt"
197 self.merge_remote_subjecttxt(datalist)
198 new_list = conv_dictdict_to_listdict(datalist)
199 gobject.idle_add(self.update_datastore, new_list)
202 def reset_progress():
203 self.progress.set_fraction(0.0)
205 gobject.idle_add(reset_progress)
210 dic["oldRes"] = dic["res"]
215 model = self.treeview.get_model()
217 iterable = model.original_list
219 iterable = itertools.imap(lambda dic: dic.copy(), iterable)
220 iterable = itertools.imap(init_some, iterable)
222 new_dict = dict([(dic["id"], dic) for dic in iterable])
227 sbj_path = misc.get_board_subjecttxt_path(self.bbs_type)
228 sbj_exists = os.path.exists(sbj_path)
232 if update or not sbj_exists:
233 new_dict = deep_copy()
234 t = ThreadInvoker(on_end, lambda *x: get_remote(new_dict))
237 t = ThreadInvoker(on_end, load_local)
242 states_path = misc.get_board_states_path(self.bbs_type)
243 dirname = os.path.dirname(states_path)
245 # save only if board dir exists.
246 if os.path.exists(dirname):
247 window_width, window_height = self.window.get_size()
248 toolbar_visible = self.toolbar.parent.get_property("visible")
249 statusbar_visible = self.statusbar.get_property("visible")
250 filterbar_visible = self.filterbar.get_property("visible")
252 columns = self.treeview.get_columns()
255 for column in columns:
261 width += str(column.get_width())
263 sort_column_name, sort_reverse = \
264 self.treeview.get_model().get_sort()
265 sort_reverse = str(sort_reverse)
267 f = file(states_path, "w")
269 f.write("columns=" + order + "\n")
270 f.write("widths=" + width + "\n")
271 f.write("sort_column=" + sort_column_name + "\n")
272 f.write("sort_reverse=" + sort_reverse + "\n")
273 f.write("window_width=" + str(window_width) + "\n")
274 f.write("window_height=" + str(window_height) + "\n")
275 f.write("toolbar_visible=" + str(toolbar_visible) + "\n")
276 f.write("statusbar_visible=" + str(statusbar_visible) + "\n")
277 f.write("filterbar_visible=" + str(filterbar_visible) + "\n")
281 traceback.print_exc()
285 states_dict = board_states.states_file_to_dict(self.bbs_type)
288 self.treeview.get_model().sort(
289 states_dict["sort_column"], True,
290 states_dict["sort_reverse"])
294 # set column order before set column width
295 treeviewcolumn = dict(
296 [(cln.id, cln) for cln in self.treeview.get_columns()])
298 for column_name in states_dict["columns"]:
299 if column_name in treeviewcolumn:
300 column = treeviewcolumn[column_name]
301 self.treeview.move_column_after(column, base_column)
304 # set column width afeter set column order
305 for width, column in itertools.izip(
306 states_dict["widths"], self.treeview.get_columns()):
308 column.set_fixed_width(width)
310 self.window.set_default_size(
311 states_dict["window_width"], states_dict["window_height"])
313 if not states_dict["toolbar_visible"]:
314 gobject.idle_add(self.toolbar.parent.hide,
315 priority=gobject.PRIORITY_HIGH)
316 if not states_dict["statusbar_visible"]:
317 gobject.idle_add(self.statusbar.hide,
318 priority=gobject.PRIORITY_HIGH)
319 if not states_dict["filterbar_visible"]:
320 gobject.idle_add(self.filterbar.hide,
321 priority=gobject.PRIORITY_HIGH)
323 traceback.print_exc()
325 def on_menu_toolbar_activate(self, widget):
326 if self.toolbar.parent.get_property("visible"):
327 self.toolbar.parent.hide()
329 self.toolbar.parent.show()
331 def on_menu_statusbar_activate(self, widget):
332 if self.statusbar.get_property("visible"):
333 self.statusbar.hide()
335 self.statusbar.show()
340 # menu and toolbutton
342 def on_menu_add_bookmark_activate(self, widget):
343 bookmark_list.bookmark_list.add_bookmark_with_edit(
344 uri=self.bbs_type.uri)
346 def on_menu_close_activate(self, widget):
349 def on_menu_delete_activate(self, widget):
350 selection = self.treeview.get_selection()
351 model, iter = selection.get_selected()
354 thread = model.get_dict(iter)["id"]
356 bbs_type_for_thread = self.bbs_type.clone_with_thread(thread)
358 dat_path = misc.get_thread_dat_path(bbs_type_for_thread)
362 traceback.print_exc()
363 idx_path = misc.get_thread_idx_path(bbs_type_for_thread)
367 traceback.print_exc()
368 states_path = misc.get_thread_states_path(bbs_type_for_thread)
370 os.remove(states_path)
372 traceback.print_exc()
374 def on_menu_filter_activate(self, widget):
375 self.filterbar.show()
376 self.entry_filterbar.grab_focus()
378 def on_menu_manage_bookmarks_activate(self, widget):
379 bookmark_window.open()
381 def on_menu_open_activate(self, widget):
384 def on_menu_quit_activate(self, widget):
387 def on_menu_refresh_activate(self, widget):
393 def on_window_board_delete_event(self, widget, event):
397 def on_window_board_destroy(self, widget):
398 self.popupmenu.destroy()
399 for column in self.treeview.get_columns():
406 def on_treeview_row_activated(self, widget, path, view_column):
409 def on_treeview_button_press_event(self, widget, event):
410 if event.button == 3:
414 pthinfo = widget.get_path_at_pos(x, y)
415 if pthinfo is not None:
416 path, col, cellx, celly = pthinfo
418 widget.set_cursor(path, col, 0)
419 self.popupmenu.popup(None, None, None, event.button, time)
425 def on_entry_filterbar_activate(self, widget):
426 text = widget.get_text()
428 def func(model, item):
430 item["title"].index(text)
436 model = self.treeview.get_model()
442 model.refilter(filter_func)
444 def on_toolbutton_filterbar_close_clicked(self, widget):
445 self.filterbar.hide()
447 def on_button_filterbar_clear_clicked(self, widget):
448 self.entry_filterbar.set_text("")
449 model = self.treeview.get_model()