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)
182 return [item_dict for item_dict in iterable]
185 datalist = self.load_idxfiles()
186 self.merge_local_subjecttxt(datalist)
187 new_list = conv_dictdict_to_listdict(datalist)
188 gobject.idle_add(self.update_datastore, new_list)
190 def get_remote(datalist):
191 print "start get subject.txt"
192 self.merge_remote_subjecttxt(datalist)
193 new_list = conv_dictdict_to_listdict(datalist)
194 gobject.idle_add(self.update_datastore, new_list)
197 def reset_progress():
198 self.progress.set_fraction(0.0)
200 gobject.idle_add(reset_progress)
209 model = self.treeview.get_model()
211 iterable = model.original_list
213 # unmerge subject.txt
214 iterable = itertools.ifilter(
215 lambda dic: dic["lineCount"] > 0, iterable)
216 iterable = itertools.imap(lambda dic: dic.copy(), iterable)
217 iterable = itertools.imap(init_some, iterable)
219 new_dict = dict([(dic["id"], dic) for dic in iterable])
224 sbj_path = misc.get_board_subjecttxt_path(self.bbs_type)
225 sbj_exists = os.path.exists(sbj_path)
229 if update or not sbj_exists:
230 new_dict = deep_copy()
231 t = ThreadInvoker(on_end, lambda *x: get_remote(new_dict))
234 t = ThreadInvoker(on_end, load_local)
239 states_path = misc.get_board_states_path(self.bbs_type)
240 dirname = os.path.dirname(states_path)
242 # save only if board dir exists.
243 if os.path.exists(dirname):
244 window_width, window_height = self.window.get_size()
245 toolbar_visible = self.toolbar.parent.get_property("visible")
246 statusbar_visible = self.statusbar.get_property("visible")
247 filterbar_visible = self.filterbar.get_property("visible")
249 columns = self.treeview.get_columns()
252 for column in columns:
258 width += str(column.get_width())
260 sort_column_name, sort_reverse = \
261 self.treeview.get_model().get_sort()
262 sort_reverse = str(sort_reverse)
264 f = file(states_path, "w")
266 f.write("columns=" + order + "\n")
267 f.write("widths=" + width + "\n")
268 f.write("sort_column=" + sort_column_name + "\n")
269 f.write("sort_reverse=" + sort_reverse + "\n")
270 f.write("window_width=" + str(window_width) + "\n")
271 f.write("window_height=" + str(window_height) + "\n")
272 f.write("toolbar_visible=" + str(toolbar_visible) + "\n")
273 f.write("statusbar_visible=" + str(statusbar_visible) + "\n")
274 f.write("filterbar_visible=" + str(filterbar_visible) + "\n")
278 traceback.print_exc()
282 states_dict = board_states.states_file_to_dict(self.bbs_type)
284 self.treeview.get_model().sort(
285 states_dict["sort_column"], True, states_dict["sort_reverse"])
287 # set column order before set column width
288 treeviewcolumn = dict(
289 [(cln.id, cln) for cln in self.treeview.get_columns()])
291 for column_name in states_dict["columns"]:
292 if column_name in treeviewcolumn:
293 column = treeviewcolumn[column_name]
294 self.treeview.move_column_after(column, base_column)
297 # set column width afeter set column order
298 for width, column in itertools.izip(
299 states_dict["widths"], self.treeview.get_columns()):
301 column.set_fixed_width(width)
303 self.window.set_default_size(
304 states_dict["window_width"], states_dict["window_height"])
306 if not states_dict["toolbar_visible"]:
307 gobject.idle_add(self.toolbar.parent.hide,
308 priority=gobject.PRIORITY_HIGH)
309 if not states_dict["statusbar_visible"]:
310 gobject.idle_add(self.statusbar.hide,
311 priority=gobject.PRIORITY_HIGH)
312 if not states_dict["filterbar_visible"]:
313 gobject.idle_add(self.filterbar.hide,
314 priority=gobject.PRIORITY_HIGH)
316 traceback.print_exc()
318 def on_menu_toolbar_activate(self, widget):
319 if self.toolbar.parent.get_property("visible"):
320 self.toolbar.parent.hide()
322 self.toolbar.parent.show()
324 def on_menu_statusbar_activate(self, widget):
325 if self.statusbar.get_property("visible"):
326 self.statusbar.hide()
328 self.statusbar.show()
333 # menu and toolbutton
335 def on_menu_add_bookmark_activate(self, widget):
336 bookmark_list.bookmark_list.add_bookmark_with_edit(
337 uri=self.bbs_type.uri)
339 def on_menu_close_activate(self, widget):
342 def on_menu_delete_activate(self, widget):
343 selection = self.treeview.get_selection()
344 model, iter = selection.get_selected()
347 thread = model.get_dict(iter)["id"]
349 bbs_type_for_thread = self.bbs_type.clone_with_thread(thread)
351 dat_path = misc.get_thread_dat_path(bbs_type_for_thread)
355 traceback.print_exc()
356 idx_path = misc.get_thread_idx_path(bbs_type_for_thread)
360 traceback.print_exc()
361 states_path = misc.get_thread_states_path(bbs_type_for_thread)
363 os.remove(states_path)
365 traceback.print_exc()
367 def on_menu_filter_activate(self, widget):
368 self.filterbar.show()
369 self.entry_filterbar.grab_focus()
371 def on_menu_manage_bookmarks_activate(self, widget):
372 bookmark_window.open()
374 def on_menu_open_activate(self, widget):
377 def on_menu_quit_activate(self, widget):
380 def on_menu_refresh_activate(self, widget):
386 def on_window_board_delete_event(self, widget, event):
390 def on_window_board_destroy(self, widget):
391 self.popupmenu.destroy()
392 for column in self.treeview.get_columns():
399 def on_treeview_row_activated(self, widget, path, view_column):
402 def on_treeview_button_press_event(self, widget, event):
403 if event.button == 3:
407 pthinfo = widget.get_path_at_pos(x, y)
408 if pthinfo is not None:
409 path, col, cellx, celly = pthinfo
411 widget.set_cursor(path, col, 0)
412 self.popupmenu.popup(None, None, None, event.button, time)
418 def on_entry_filterbar_activate(self, widget):
419 text = widget.get_text()
421 def func(model, item):
423 item["title"].index(text)
429 model = self.treeview.get_model()
435 model.refilter(filter_func)
437 def on_toolbutton_filterbar_close_clicked(self, widget):
438 self.filterbar.hide()
440 def on_button_filterbar_clear_clicked(self, widget):
441 self.entry_filterbar.set_text("")
442 model = self.treeview.get_model()