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
44 GLADE_FILENAME = "board_window.glade"
46 def open_board(uri, update=False):
48 raise ValueError, "parameter must not be empty"
50 bbs_type = bbs_type_judge_uri.get_type(uri)
51 uri = bbs_type.get_uri_base() # use strict uri
53 winwrap = session.get_window(uri)
56 winwrap.window.present()
60 winwrap = WinWrap(bbs_type.uri) # pass the original uri
64 class WinWrap(winwrapbase.WinWrapBase, board_data.BoardData):
66 def __init__(self, uri):
68 self.bbs_type = bbs_type_judge_uri.get_type(uri)
69 board_data.BoardData.__init__(self, self.bbs_type)
71 glade_path = os.path.join(config.glade_dir, GLADE_FILENAME)
72 self.widget_tree = gtk.glade.XML(glade_path)
75 self.widget_tree.signal_autoconnect(self)
77 self.window.set_title(self.bbs_type.uri)
78 self.treeview.set_model(ThreadListModel())
79 self.toolbar.unset_style()
81 renderer = gtk.CellRendererText()
83 for column_class in board_column.tree_view_column_list:
84 column_class(renderer, self.treeview)
86 self.treeview.set_fixed_height_mode(True)
89 board_plugins.load(self.treeview, self.menu_edit)
96 def _get_widgets(self):
97 self.window = self.widget_tree.get_widget("window_board")
98 self.treeview = self.widget_tree.get_widget("treeview")
99 self.popupmenu = self.widget_tree.get_widget("popup_treeview_menu")
100 self.toolbar = self.widget_tree.get_widget("toolbar")
101 self.statusbar = self.widget_tree.get_widget("appbar")
102 self.progress = self.statusbar.get_progress()
103 self.filterbar = self.widget_tree.get_widget(
104 "bonobodockitem_filterbar")
105 self.entry_filterbar = self.widget_tree.get_widget("entry_filterbar")
106 self.menu_edit = self.widget_tree.get_widget("menu_edit").get_submenu()
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 thread = model.get_value(iter, ThreadListModel.column_names.index("id"))
128 title = model.get_value(
129 iter, ThreadListModel.column_names.index("title"))
130 print thread + ':"' + title + '"', "activated"
132 res = model.get_value(iter, ThreadListModel.column_names.index("res"))
133 lineCount = model.get_value(
134 iter, ThreadListModel.column_names.index("lineCount"))
136 update = res > lineCount
138 bbs_type_for_thread = self.bbs_type.clone_with_thread(thread)
139 uri_opener.open_uri(bbs_type_for_thread.get_thread_uri(), update)
141 def update_datastore(self, new_list):
142 print "reflesh datastore"
144 self.treeview.get_model().set_list(new_list)
146 # redraw visible area after set list to model
147 self.treeview.queue_draw()
151 def on_thread_idx_updated(self, thread_uri, idx_dic):
152 if not thread_uri or not idx_dic:
155 # nothing to do if thread_uri does not belong to this board.
156 bbs_type = bbs_type_judge_uri.get_type(thread_uri)
157 if not bbs_type.is_thread() \
158 or not bbs_type.is_same_board(self.bbs_type):
161 thread = bbs_type.thread
163 model = self.treeview.get_model()
165 idx_dic["id"] = thread
167 idx_dic["lastModified"] = misc.httpdate_to_secs(
168 idx_dic["lastModified"])
170 idx_dic["lastModified"] = 0
171 model.modify_row(idx_dic)
173 def load(self, update=False):
175 def modify_dict(item_dict):
176 # lastModified, httpdate to second
177 httpdate = item_dict["lastModified"]
179 secs = misc.httpdate_to_secs(httpdate)
181 item_dict["lastModified"] = 0
183 item_dict["lastModified"] = secs
186 def set_id(thread_id, item_dict):
187 item_dict["id"] = thread_id
190 def conv_dictdict_to_listdict(dictdict):
191 key_iter = dictdict.iterkeys()
192 value_iter = dictdict.itervalues()
193 iterable = itertools.imap(set_id, key_iter, value_iter)
194 iterable = itertools.imap(modify_dict, iterable)
195 return [item_dict for item_dict in iterable]
198 datalist = self.load_idxfiles()
199 self.merge_local_subjecttxt(datalist)
200 new_list = conv_dictdict_to_listdict(datalist)
201 gobject.idle_add(self.update_datastore, new_list)
204 print "start get subject.txt"
205 datalist = self.load_idxfiles()
206 self.merge_remote_subjecttxt(datalist)
207 new_list = conv_dictdict_to_listdict(datalist)
208 gobject.idle_add(self.update_datastore, new_list)
211 def reset_progress():
212 self.progress.set_fraction(0.0)
214 gobject.idle_add(reset_progress)
216 sbj_path = misc.get_board_subjecttxt_path(self.bbs_type)
217 sbj_exists = os.path.exists(sbj_path)
221 if update or not sbj_exists:
222 t = ThreadInvoker(on_end, get_remote)
225 t = ThreadInvoker(on_end, load_local)
230 states_path = misc.get_board_states_path(self.bbs_type)
231 dirname = os.path.dirname(states_path)
233 # save only if board dir exists.
234 if os.path.exists(dirname):
235 window_width, window_height = self.window.get_size()
236 toolbar_visible = self.toolbar.parent.get_property("visible")
237 statusbar_visible = self.statusbar.get_property("visible")
238 filterbar_visible = self.filterbar.get_property("visible")
240 columns = self.treeview.get_columns()
243 for column in columns:
249 width += str(column.get_width())
251 sort_column_name, sort_reverse = \
252 self.treeview.get_model().get_sort()
253 sort_reverse = str(sort_reverse)
255 f = file(states_path, "w")
257 f.write("columns=" + order + "\n")
258 f.write("widths=" + width + "\n")
259 f.write("sort_column=" + sort_column_name + "\n")
260 f.write("sort_reverse=" + sort_reverse + "\n")
261 f.write("window_width=" + str(window_width) + "\n")
262 f.write("window_height=" + str(window_height) + "\n")
263 f.write("toolbar_visible=" + str(toolbar_visible) + "\n")
264 f.write("statusbar_visible=" + str(statusbar_visible) + "\n")
265 f.write("filterbar_visible=" + str(filterbar_visible) + "\n")
269 traceback.print_exc()
273 ("columns", ()), ("widths", ()), ("sort_column", "num"),
274 ("sort_reverse", False), ("window_height", 600),
275 ("window_width", 600), ("toolbar_visible", True),
276 ("statusbar_visible", True), ("filterbar_visible", False)])
279 "columns", "widths", "sort_column", "sort_reverse",
280 "window_height", "window_width", "toolbar_visible",
281 "statusbar_visible", "filterbar_visible"]
283 interest_type_list = (
284 (list, str), (list, int), (str, None), (bool, None), (int, None),
285 (int, None), (bool, None), (bool, None), (bool, None))
287 def key_value_generator():
290 states_path = misc.get_board_states_path(self.bbs_type)
292 for line in file(states_path):
293 key_equal_value = line.rstrip()
295 index = key_equal_value.index("=")
299 key = key_equal_value[:index]
300 if key in interest_list:
301 value = key_equal_value[index+1:]
304 traceback.print_exc()
312 for key, value in generate_pair():
313 list_index = interest_list.index(key)
314 key_type, key_type_extra = interest_type_list[list_index]
317 elif key_type == int:
318 yield key, to_int(value)
319 elif key_type == bool:
320 value = value == "True"
322 elif key_type == list:
323 if key_type_extra == str:
324 yield key, value.split(",")
325 elif key_type_extra == int:
326 yield key, [i for i in itertools.imap(
327 to_int, value.split(","))]
329 print key, "not supported",
330 key_type, key_type_extra, value
332 print key, "not supported", key_type, value
335 key_base = config.gconf_app_key_base() + "/board_states"
336 gconf_client = gconf.client_get_default()
337 width = gconf_client.get_int(key_base + "/window_width")
338 height = gconf_client.get_int(key_base + "/window_height")
339 states_dict["toolbar_visible"] = gconf_client.get_bool(
340 key_base + "/toolbar")
341 states_dict["statusbar_visible"] = gconf_client.get_bool(
342 key_base + "/statusbar")
343 states_dict["filterbar_visible"] = gconf_client.get_bool(
344 key_base + "/filterbar")
347 states_dict["window_width"] = width
349 states_dict["window_height"] = height
355 traceback.print_exc()
357 for key, value in key_value_generator():
358 states_dict[key] = value
360 self.treeview.get_model().sort(
361 states_dict["sort_column"], True, states_dict["sort_reverse"])
363 # set column order before set column width
364 treeviewcolumn = dict(
365 [(cln.id, cln) for cln in self.treeview.get_columns()])
367 for column_name in states_dict["columns"]:
368 if column_name in treeviewcolumn:
369 column = treeviewcolumn[column_name]
370 self.treeview.move_column_after(column, base_column)
373 # set column width afeter set column order
374 for width, column in itertools.izip(
375 states_dict["widths"], self.treeview.get_columns()):
377 column.set_fixed_width(width)
379 self.window.set_default_size(
380 states_dict["window_width"], states_dict["window_height"])
382 if not states_dict["toolbar_visible"]:
383 gobject.idle_add(self.toolbar.parent.hide,
384 priority=gobject.PRIORITY_HIGH)
385 if not states_dict["statusbar_visible"]:
386 gobject.idle_add(self.statusbar.hide,
387 priority=gobject.PRIORITY_HIGH)
388 if not states_dict["filterbar_visible"]:
389 gobject.idle_add(self.filterbar.hide,
390 priority=gobject.PRIORITY_HIGH)
392 traceback.print_exc()
394 def on_menu_toolbar_activate(self, widget):
395 if self.toolbar.parent.get_property("visible"):
396 self.toolbar.parent.hide()
398 self.toolbar.parent.show()
400 def on_menu_statusbar_activate(self, widget):
401 if self.statusbar.get_property("visible"):
402 self.statusbar.hide()
404 self.statusbar.show()
409 # menu and toolbutton
411 def on_menu_add_bookmark_activate(self, widget):
412 bookmark_list.bookmark_list.add_bookmark_with_edit(
413 uri=self.bbs_type.uri)
415 def on_menu_close_activate(self, widget):
418 def on_menu_delete_activate(self, widget):
419 selection = self.treeview.get_selection()
420 model, iter = selection.get_selected()
423 thread = model.get_value(
424 iter, ThreadListModel.column_names.index("id"))
426 bbs_type_for_thread = self.bbs_type.clone_with_thread(thread)
428 dat_path = misc.get_thread_dat_path(bbs_type_for_thread)
432 traceback.print_exc()
433 idx_path = misc.get_thread_idx_path(bbs_type_for_thread)
437 traceback.print_exc()
438 states_path = misc.get_thread_states_path(bbs_type_for_thread)
440 os.remove(states_path)
442 traceback.print_exc()
444 def on_menu_filter_activate(self, widget):
445 self.filterbar.show()
446 self.entry_filterbar.grab_focus()
448 def on_menu_manage_bookmarks_activate(self, widget):
449 bookmark_window.open()
451 def on_menu_open_activate(self, widget):
454 def on_menu_quit_activate(self, widget):
457 def on_menu_refresh_activate(self, widget):
463 def on_window_board_delete_event(self, widget, event):
467 def on_window_board_destroy(self, widget):
468 self.popupmenu.destroy()
469 for column in self.treeview.get_columns():
476 def on_treeview_row_activated(self, widget, path, view_column):
479 def on_treeview_button_press_event(self, widget, event):
480 if event.button == 3:
484 pthinfo = widget.get_path_at_pos(x, y)
485 if pthinfo is not None:
486 path, col, cellx, celly = pthinfo
488 widget.set_cursor(path, col, 0)
489 self.popupmenu.popup(None, None, None, event.button, time)
495 def on_entry_filterbar_activate(self, widget):
496 text = widget.get_text()
498 def func(model, item):
500 item["title"].index(text)
506 model = self.treeview.get_model()
512 model.refilter(filter_func)
514 def on_toolbutton_filterbar_close_clicked(self, widget):
515 self.filterbar.hide()
517 def on_button_filterbar_clear_clicked(self, widget):
518 self.entry_filterbar.set_text("")
519 model = self.treeview.get_model()