X-Git-Url: http://git.sourceforge.jp/view?p=fukui-no-namari%2Ffukui-no-namari.git;a=blobdiff_plain;f=src%2FFukuiNoNamari%2Fthread_window.py;h=974a57ef9d32a35a00308e8ef97ff1b25239a02e;hp=7688e4ec4e7e879ecd0eb6f3c20deef8b78a6f7d;hb=refs%2Fheads%2Fmaster;hpb=448e2b8430c992cbb05e993f0ed4719051afa79b diff --git a/src/FukuiNoNamari/thread_window.py b/src/FukuiNoNamari/thread_window.py index 7688e4e..974a57e 100644 --- a/src/FukuiNoNamari/thread_window.py +++ b/src/FukuiNoNamari/thread_window.py @@ -33,22 +33,26 @@ import traceback import itertools import os import sys +from StringIO import StringIO import misc -from misc import FileWrap, ThreadInvoker +from misc import FileWrap import datfile import barehtmlparser import idxfile import session import board_window import uri_opener -from http_sub import HTTPRedirectHandler302, HTTPDebugHandler from BbsType import bbs_type_judge_uri from BbsType import bbs_type_exception import config import winwrapbase import bookmark_list import bookmark_window +import thread_view +import thread_popup +import submit_window +import network_manager GLADE_FILENAME = "thread_window.glade" @@ -73,215 +77,194 @@ def open_thread(uri, update=False): winwrap.load(update) # jump to the res if necessary. - strict_uri = winwrap.bbs_type.get_thread_uri() - if (winwrap.bbs_type.uri != strict_uri and - winwrap.bbs_type.uri.startswith(strict_uri)): - resnum = winwrap.bbs_type.uri[len(strict_uri):] + strict_uri = bbs_type.get_thread_uri() + if (bbs_type.uri != strict_uri and + bbs_type.uri.startswith(strict_uri)): + resnum = bbs_type.uri[len(strict_uri):] match = re.match("\d+", resnum) if match: resnum = int(match.group()) winwrap.jump_to_res(resnum) -class WinWrap(winwrapbase.WinWrapBase): - hovering_over_link = False - hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2) - regular_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM) - - - def relayout(self): - width = self.drawingarea.allocation.width - sum_height = 0 - for layout in self.pangolayout: - layout.set_width(width * pango.SCALE) - layout.posY = sum_height - x, y = layout.get_pixel_size() - sum_height += y - self.adjustment.upper = sum_height - - def draw_viewport(self): - view_y = self.adjustment.get_value() - self.drawingarea.window.draw_rectangle( - self.drawingarea.style.base_gc[0], - True, 0, 0, - self.drawingarea.allocation.width, - self.drawingarea.allocation.height) - - gc = self.drawingarea.window.new_gc() - for layout in self.pangolayout: - w, h = layout.get_pixel_size() - layout_top = layout.posY - layout_bottom = layout.posY + h - area_top = view_y - area_bottom = view_y + self.drawingarea.allocation.height - if layout_top <= area_bottom and layout_bottom >= area_top: - self.drawingarea.window.draw_layout( - gc, 0, layout.posY - int(view_y), layout) - - def on_drawingarea_expose_event(self, widget, event, data=None): - self.draw_viewport() - - def on_drawingarea_size_allocate(self, widget, allocation, data=None): - if allocation.width != self.drawingarea.prev_width: - self.relayout() - self.drawingarea.prev_width = allocation.width - self.adjustment.page_size = self.drawingarea.allocation.height - self.adjustment.page_increment = self.drawingarea.allocation.height - - def on_drawingarea_button_press_event(self, widget, event, data=None): - self.drawingarea.queue_draw() - - def on_vscrollbar_value_changed(self, widget, data=None): - self.drawingarea.queue_draw() - - def on_drawingarea_scroll_event(self, widget, event, data=None): - if event.direction == gtk.gdk.SCROLL_UP: - self.adjustment.value -= 66.476200804 - if self.adjustment.value < self.adjustment.lower: - self.adjustment.value = self.adjustment.lower - if event.direction == gtk.gdk.SCROLL_DOWN: - self.adjustment.value += 66.476200804 - max_value = self.adjustment.upper - self.adjustment.page_size - if self.adjustment.value > max_value: - self.adjustment.value = max_value - def __init__(self, uri): - self.pangolayout = [] +class HTMLParserToThreadView: + def __init__(self, threadview, resnum, left_margin): + self.threadview = threadview + self.resnum = resnum + self.left_margin = left_margin + self.initialize() - from BbsType import bbs_type_judge_uri - from BbsType import bbs_type_exception - self.bbs_type = bbs_type_judge_uri.get_type(uri) - if not self.bbs_type.is_thread(): - raise bbs_type_exception.BbsTypeError, \ - "the uri does not represent thread: " + uri - self.size = 0 - self.num = 0 - self.title = "" - self.lock_obj = False - self.jump_request_num = 0 - self.progress = False + def set_left_margin(self, left_margin): + self.left_margin = left_margin - glade_path = os.path.join(config.glade_dir, GLADE_FILENAME) - self.widget_tree = gtk.glade.XML(glade_path) - self.window = self.widget_tree.get_widget("thread_window") - self.toolbar = self.widget_tree.get_widget("toolbar") - self.toolbar.unset_style() - self.statusbar = self.widget_tree.get_widget("statusbar") - self.drawingarea = self.widget_tree.get_widget("drawingarea") - self.vscrollbar = self.widget_tree.get_widget("vscrollbar") - self.adjustment = self.vscrollbar.get_adjustment() - self.adjustment.step_increment = 20 + def initialize(self): + self.layout = None - self.drawingarea.prev_width = 0 + def on_new_line(self): + self.to_thread_view() + self.layout = self.threadview.create_res_layout( + self.left_margin, self.resnum) - self.initialize_buffer() + def from_html_parser(self, data, bold, href): + if self.layout == None: + self.layout = self.threadview.create_res_layout( + self.left_margin, self.resnum) - sigdic = {"on_refresh_activate": self.update, - "on_compose_activate": self.on_compose_clicked, - "on_toolbar_activate": self.on_toolbar_activate, - "on_statusbar_activate": self.on_statusbar_activate, - "on_refresh_activate": self.update, - "on_close_activate": self.on_close_activate, - "on_quit_activate": self.on_quit_activate, - "on_show_board_activate": self.on_show_board_activate, - "on_delete_activate": self.on_delete_activate, - "on_drawingarea_expose_event": self.on_drawingarea_expose_event, - "on_drawingarea_size_allocate": - self.on_drawingarea_size_allocate, - "on_thread_window_delete_event": - self.on_thread_window_delete_event, - "on_drawingarea_button_press_event": - self.on_drawingarea_button_press_event, - "on_drawingarea_scroll_event": - self.on_drawingarea_scroll_event, - "on_vscrollbar_value_changed": - self.on_vscrollbar_value_changed, - "on_add_bookmark_activate": self.on_add_bookmark_activate, - "on_manage_bookmarks_activate": \ - self.on_manage_bookmarks_activate, - "on_thread_window_destroy": self.on_thread_window_destroy} - self.widget_tree.signal_autoconnect(sigdic) + self.layout.add_text(data, bold, href) - self.restore() - self.window.show_all() + def to_thread_view(self): + if self.layout is not None: + self.threadview.add_layout(self.layout) + self.initialize() - self.created() - def initialize_buffer(self): - self.textbuffer = gtk.TextBuffer() +class LoadDat: - self.enditer = self.textbuffer.get_end_iter() - self.boldtag = self.textbuffer.create_tag(weight=pango.WEIGHT_BOLD) - self.leftmargintag = self.textbuffer.create_tag() - self.leftmargintag.set_property("left-margin", 20) + def __init__(self, bbs_type, threadwindow, threadview, statusbar): + self.bbs_type = bbs_type + self.threadwindow = threadwindow + self.threadview = threadview + self.statusbar = statusbar + self.lock_obj = False + self.jump_request_num = 0 + self.size = 0 + self.num = 0 + self.request_headers = None + self.response_headers = None - self.pangolayout = [] + self.statusbar_context_id = self.statusbar.get_context_id( + "Thread Window Status") + self.statusbar.push(self.statusbar_context_id, "OK.") - def destroy(self): - self.save() - self.window.destroy() + def initialize(self): + self.num = 0 + self.size = 0 + self.threadview.initialize_buffer() - def get_uri(self): - return self.bbs_type.get_thread_uri() + def jump_request(self, res_num): + if not self.threadview.jump_to_res(res_num): + self.jump_request_num = res_num - def on_compose_clicked(self, widget): - import submit_window - submit_window.open(self.bbs_type.get_thread_uri()) + def _do_jump_if_need(self): + if self.jump_request_num: + num = self.jump_request_num + self.jump_request_num = 0 + return self.threadview.jump_to_res(num) - def on_toolbar_activate(self, widget): - if self.toolbar.get_property("visible"): - self.toolbar.hide() - else: - self.toolbar.show() + def _do_jump(self): + if not self._do_jump_if_need(): + return self.threadview.jump_to_the_end() - def on_statusbar_activate(self, widget): - if self.statusbar.get_property("visible"): - self.statusbar.hide() + def _load(self): + dat_path = misc.get_thread_dat_path(self.bbs_type) + try: + fd = file(dat_path) + except IOError: + raise misc.StopChainException() else: - self.statusbar.show() + i = 0 + for line in fd: + self.append_rawres_to_buffer(line) + yield + fd.close() + self._do_jump() - def on_close_activate(self, widget): - self.destroy() + def _on_end(self): + self.request_headers = None + self.response_headers = None + self._un_lock() - def on_thread_window_delete_event(self, widget, event): - self.save() - return False - - def on_thread_window_destroy(self, widget): - self.destroyed() + def _lock(self): + if self.lock_obj: + print "Busy." + return False + self.lock_obj = True + return True - def on_quit_activate(self, widget): - session.main_quit() + def _un_lock(self): + self.lock_obj = False - def on_add_bookmark_activate(self, widget): - bookmark_list.bookmark_list.add_bookmark_with_edit( - name=self.title, uri=self.bbs_type.uri) + def load(self): + self.jump_request_num = 0 + if self._lock(): + misc.chain(lambda *args: None, self._on_end, self._load()) - def on_manage_bookmarks_activate(self, widget): - bookmark_window.open() + def _load_and_save(self, fd): + dat_path = misc.get_thread_dat_path(self.bbs_type) + try: + save_fd = FileWrap(dat_path) + save_fd.seek(self.size) + except IOError: + raise misc.StopChainException() + + for line in fd: + if not line.endswith("\n"): + # the last line is not terminated with '\n' + print "does not end with \\n. maybe incomplete" + self.response_headers["lastmodified"] = None + self.response_headers["etag"] = None + raise misc.StopChainException() + save_fd.write(line) + self.append_rawres_to_buffer(line) + yield + self.threadview.queue_draw() + self._do_jump_if_need() + + def on_received(self, res): + headers = res.headers + status = res.status + + if "Last-modified".capitalize() in headers: + self.statusbar.pop(self.statusbar_context_id) + self.statusbar.push(self.statusbar_context_id, + "%s [%s]" % (status, headers["last-modified".capitalize()])) + else: + self.statusbar.pop(self.statusbar_context_id) + self.statusbar.push(self.statusbar_context_id, "%s" % status) - def on_show_board_activate(self, widget): - board_window.open_board(self.bbs_type.get_uri_base()) + version, code, msg = status.split(None, 2) + code = int(code) + if code != 200 and code != 206: + self._on_end() + return + res.code = code - def on_delete_activate(self, widget): - try: - dat_path = misc.get_thread_dat_path(self.bbs_type) - os.remove(dat_path) - except OSError: - traceback.print_exc() - try: - idx_path = misc.get_thread_idx_path(self.bbs_type) - os.remove(idx_path) - except OSError: - traceback.print_exc() - try: - states_path = misc.get_thread_states_path(self.bbs_type) - os.remove(states_path) - except OSError: - traceback.print_exc() + if "Range".capitalize() in self.request_headers and code == 200: + self.initialize() + + self.response_headers = headers + fd = StringIO(res.message) + + def save_and_end(): + try: + self._saveidx() + finally: + self._on_end() + + misc.chain(lambda *args: None, save_and_end, self._load_and_save(fd)) + + def _saveidx(self): + lastmod = "" + etag = "" + if "last-modified".capitalize() in self.response_headers: + lastmod = self.response_headers["last-modified".capitalize()] + if "etag".capitalize() in self.response_headers: + etag = self.response_headers["etag".capitalize()] + + if self.num > 0: + # save idx + idx_dic = {"title": self.title, "lineCount": self.num, + "lastModified": lastmod, "etag": etag} + idxfile.save_idx(self.bbs_type, idx_dic) + + session.thread_idx_updated(self.bbs_type.get_thread_uri(), idx_dic) + + def _http_get_dat(self): - def http_get_dat(self, on_get_res): datfile_url = self.bbs_type.get_dat_uri() + headers = {} + idx_dic = idxfile.load_idx(self.bbs_type) lastmod = idx_dic["lastModified"] etag = idx_dic["etag"] @@ -296,151 +279,53 @@ class WinWrap(winwrapbase.WinWrapBase): req.add_header("If-None-Match", etag) req = self.bbs_type.set_extra_dat_request(req, self) - - opener = urllib2.build_opener(HTTPRedirectHandler302, HTTPDebugHandler) try: - res = opener.open(req) - except urllib2.HTTPError, e: - pass -# gobject.idle_add( -# lambda x: self.statusbar.push(0, x), "%d %s" % (e.code, e.msg)) + network_manager.request_get(req.get_full_url(), + req.headers, self.on_received) + except network_manager.BusyException: + self._on_end() + self.statusbar.pop(self.statusbar_context_id) + self.statusbar.push(self.statusbar_context_id, + "The network is busy. Try later.") + except: + self._on_end() + self.statusbar.pop(self.statusbar_context_id) + self.statusbar.push(self.statusbar_context_id, + str(sys.exc_info())) else: - headers = res.info() -# gobject.idle_add( -# lambda x: self.statusbar.push(0, x), "%d %s" % (res.code, res.msg)) - - maybe_incomplete = False - for line in res: - if not line.endswith("\n"): - maybe_incomplete = True - print "does not end with \\n. maybe incomplete" - break - on_get_res(line) - - res.close() - - if maybe_incomplete: - lastmod = None - etag = None - else: - if "Last-Modified" in headers: - lastmod = headers["Last-Modified"] - if "ETag" in headers: - etag = headers["Etag"] - - if self.num > 0: - # save idx - idx_dic = {"title": self.title, "lineCount": self.num, - "lastModified": lastmod, "etag": etag} - idxfile.save_idx(self.bbs_type, idx_dic) - - gobject.idle_add(session.thread_idx_updated, - self.bbs_type.get_thread_uri(), idx_dic) - - def update(self, widget=None): - - self.jump_request_num = 0 - - def load(): - if self.num == 0: - def create_mark(): - self.textbuffer.create_mark("1", self.enditer, True) - gobject.idle_add(create_mark) - - line_count = datfile.get_dat_line_count(self.bbs_type) - if line_count < self.num: - self.num = 0 - self.size = 0 + self.statusbar.pop(self.statusbar_context_id) + self.statusbar.push(self.statusbar_context_id, "GET...") + self.request_headers = req.headers - gobject.idle_add(self.initialize_buffer) + def update(self): - if line_count > self.num: - datfile.load_dat_partly( - self.bbs_type, self.append_rawres_to_buffer, self.num+1) - - def do_jump(): - if self.jump_request_num: - if self.jump_request_num <= num: - num = self.jump_request_num - self.jump_request_num = 0 - self.jump_to_res(num) - else: - self.jump_to_the_end() - - gobject.idle_add(do_jump) - - def get(): - dat_path = misc.get_thread_dat_path(self.bbs_type) - dat_file = FileWrap(dat_path) - - def save_line_and_append_to_buffer(line): - dat_file.seek(self.size) - dat_file.write(line) - self.append_rawres_to_buffer(line) - - self.http_get_dat(save_line_and_append_to_buffer) - dat_file.close() - - def do_jump(): - if self.jump_request_num: - num = self.jump_request_num - self.jump_request_num = 0 - self.jump_to_res(num) - - gobject.idle_add(do_jump) - - if self.lock(): - - def on_end(): - self.un_lock() - self.progress = False - - self.progress = True - t = ThreadInvoker(lambda : gobject.idle_add(on_end), load, get) - t.start() - - def load_dat(self): - - self.size = 0 - self.num = 0 self.jump_request_num = 0 - def load(): - datfile.load_dat(self.bbs_type, self.append_rawres_to_buffer) - - def jump(): - - def do_jump(): - if self.jump_request_num: - num = self.jump_request_num - self.jump_request_num = 0 - self.jump_to_res(num) - else: - self.jump_to_the_end() - - gobject.idle_add(do_jump) - - if self.lock(): - - def on_end(): - self.un_lock() - self.progress = False - - self.progress = True - t = ThreadInvoker(lambda : gobject.idle_add(on_end), load, jump) - t.start() + if not self._lock(): + return + + line_count = datfile.get_dat_line_count(self.bbs_type) + if line_count != self.num: + # load dat file once more + self.num = 0 + self.size = 0 + self.threadview.initialize_buffer() + def end_and_get(): + self._on_end() + self._http_get_dat() + misc.chain(lambda *args: None, end_and_get, self._load()) + else: + self._http_get_dat() def append_rawres_to_buffer(self, line): self.size += len(line) self.num += 1 - if not self.title and self.num == 1: + if self.num == 1: title = self.bbs_type.get_title_from_dat(line) if title: self.title = title - gobject.idle_add(self.window.set_title, title) - - self.res_queue = [] + self.threadwindow.set_title(title) line = line.decode(self.bbs_type.encoding, "replace") m = self.bbs_type.dat_reg.match(line) @@ -466,21 +351,18 @@ class WinWrap(winwrapbase.WinWrapBase): date += " ID:" + id self.reselems_to_buffer(num, name, mail, date, msg) else: - self.res_queue.append((str(self.num)+"\n", False, None, False)) - self.res_queue.append((line, False, None, True)) + self.reselems_to_buffer( + str(self.num), "Invalid Name", "Invalid Mail", + "Invalid Date", line) print "maybe syntax error.", self.num, line - def process_res_queue(res_queue, num): - self.process_queue(res_queue, num) - # for next res - #self.textbuffer.create_mark(str(num+1), self.enditer, True) - - gobject.idle_add( - process_res_queue, self.res_queue, self.num) - def reselems_to_buffer(self, num, name, mail, date, msg): + pipe = HTMLParserToThreadView(self.threadview, num, 0) p = barehtmlparser.BareHTMLParser( - lambda d,b,h: self.res_queue.append((d,b,h,False))) + pipe.from_html_parser, pipe.on_new_line) + + # First, create a pango layout for num,name,mail,date + # 'margin left' is 0 # number p.feed(str(num) + " ") @@ -492,83 +374,175 @@ class WinWrap(winwrapbase.WinWrapBase): # date p.feed(date) - p.feed("
") + p.flush() + + pipe.to_thread_view() + + # Second, create a pango layout for message + # 'margin left' is 20 # msg - p.reset_func(lambda d,b,h: self.res_queue.append((d,b,h,True))) + pipe.set_left_margin(20) p.feed(msg.lstrip(" ")) - p.feed("

") + p.feed("
") p.close() - def href_tag(self, href): - tag = self.textbuffer.create_tag(underline=pango.UNDERLINE_SINGLE) - tag.set_data("href", href) - return tag - - def process_queue(self, queue, num): - text = "" - for data, bold, href, margin in queue: - text += data - layout = self.drawingarea.create_pango_layout(text) - layout.set_wrap(pango.WRAP_CHAR) - layout.posY = 0 - layout.resnum = num - self.pangolayout.append(layout) - self.relayout() - self.drawingarea.queue_draw() -# taglist = [] -# if bold: -# taglist.append(self.boldtag) -# if href: -# taglist.append(self.href_tag(href)) -# if margin: -# taglist.append(self.leftmargintag) -# -# if taglist: -# self.textbuffer.insert_with_tags(self.enditer, data, *taglist) -# else: -# self.textbuffer.insert(self.enditer, data) + pipe.to_thread_view() + + +class WinWrap(winwrapbase.WinWrapBase): + + def __init__(self, uri): + self.bbs_type = bbs_type_judge_uri.get_type(uri) + if not self.bbs_type.is_thread(): + raise bbs_type_exception.BbsTypeError, \ + "the uri does not represent thread: " + uri + + glade_path = os.path.join(config.glade_dir, GLADE_FILENAME) + self.widget_tree = gtk.glade.XML(glade_path) + self._get_widgets() + self.widget_tree.signal_autoconnect(self) + + self.toolbar.unset_style() + + self.threadview = thread_view.ThreadView() + container = thread_view.ThreadViewContainer(self.threadview) + self.threadpopup = thread_popup.ThreadPopup(self.bbs_type) + self.threadpopup.push_thread_view(self.threadview) + self.vbox.pack_start(container) + self.vbox.reorder_child(container, 2) + self.window.set_focus(self.threadview) + + self.threadview.connect( + "populate-popup", self.on_thread_view_populate_popup) + self.threadview.connect( + "uri-clicked-event", self.on_thread_view_uri_clicked) + self.threadpopup.connect( + "uri-clicked-event", self.on_thread_popup_uri_clicked) + + self.initialize_buffer() + + self.dat_load = LoadDat(self.bbs_type, self.window, + self.threadview, self.statusbar) + + self.restore() + self.window.show_all() + + self.created() + + def _get_widgets(self): + self.window = self.widget_tree.get_widget("thread_window") + self.toolbar = self.widget_tree.get_widget("toolbar") + self.statusbar = self.widget_tree.get_widget("statusbar") + self.vbox = self.widget_tree.get_widget("vbox") + + def initialize_buffer(self): + self.threadview.initialize_buffer() + + def destroy(self): + self.save() + self.window.destroy() + + def get_uri(self): + return self.bbs_type.get_thread_uri() + + def show(self): + self.window.deiconify() + + def hide(self): + self.window.iconify() + + def _show_submit_window(self): + submit_window.open(self.bbs_type.get_thread_uri()) + + def _toggle_toolbar(self): + if self.toolbar.get_property("visible"): + self.toolbar.hide() + else: + self.toolbar.show() + + def _toggle_statusbar(self): + if self.statusbar.get_property("visible"): + self.statusbar.hide() + else: + self.statusbar.show() + + def _close_window(self): + self.destroy() + + def _quit_session(self): + session.main_quit() + + def _regist_as_bookmark(self): + title = self.window.get_title() + bookmark_list.bookmark_list.add_bookmark_with_edit( + name=title, uri=self.bbs_type.uri) + + def _manage_bookmarks(self): + bookmark_window.open() + + def _show_board(self): + board_window.open_board(self.bbs_type.get_uri_base()) + + def _delete_log(self): + try: + dat_path = misc.get_thread_dat_path(self.bbs_type) + os.remove(dat_path) + except OSError: + traceback.print_exc() + try: + idx_path = misc.get_thread_idx_path(self.bbs_type) + os.remove(idx_path) + except OSError: + traceback.print_exc() + try: + states_path = misc.get_thread_states_path(self.bbs_type) + os.remove(states_path) + except OSError: + traceback.print_exc() + + def _open_uri(self, uri): + if not uri.startswith("http://"): + # maybe a relative uri. + uri = urlparse.urljoin(self.bbs_type.get_uri_base(), uri) + + try: + uri_opener.open_uri(uri) + except bbs_type_exception.BbsTypeError: + # not supported, show with the web browser. + gnome.url_show(uri) + + def _copy_text_to_clipboard(self, text): + if text and len(text) > 0: + clip = gtk.Clipboard() + text = text.encode("utf8") + clip.set_text(text, len(text)) + + def _modify_uri(self, uri): + if not uri.startswith("http://"): + uri = "http://" + uri + return uri + + def update(self): + self.dat_load.update() + + def load_dat(self): + self.dat_load.load() def jump(self, value): - def j(): - if value > self.adjustment.upper - self.adjustment.page_size: - self.jump_to_the_end() - else: - self.adjustment.set_value(value) - gobject.idle_add(j) + gobject.idle_add(self.threadview.jump, value) def jump_to_layout(self, layout): - gobject.idle_add(lambda : self.jump(layout.posY)) + gobject.idle_add(self.threadview.jump_to_layout, layout) def jump_to_the_end(self): - def j(): - self.adjustment.set_value( - self.adjustment.upper - self.adjustment.page_size) - gobject.idle_add(j) -# mark = self.textbuffer.get_mark(str(num+1)) -# if mark: -# self.textview.scroll_to_mark(mark, 0) - - def lock(self): - if self.lock_obj: - print "locked, try later." - return False - else: - print "get lock" - self.lock_obj = True - return True - - def un_lock(self): - self.lock_obj = False - print "unlock" + gobject.idle_add(self.threadview.jump_to_the_end) def jump_to_res(self, resnum): - for layout in self.pangolayout: - if layout.resnum == resnum: - self.jump_to_layout(layout) - return - self.jump_request_num = resnum + if self.threadview.jump_to_res(resnum): + return + self.dat_load.jump_request(resnum) def load(self, update=False): dat_path = misc.get_thread_dat_path(self.bbs_type) @@ -665,3 +639,85 @@ class WinWrap(winwrapbase.WinWrapBase): priority=gobject.PRIORITY_HIGH) except: traceback.print_exc() + + + # signal handlers + + def on_thread_view_populate_popup(self, widget, menu): + menuitem = gtk.ImageMenuItem(gtk.STOCK_REFRESH) + menuitem.connect("activate", + self.on_popup_threadview_menu_refresh_activate) + menu.append(menuitem) + + def on_thread_view_uri_clicked(self, widget, uri): + self._open_uri(uri) + + def on_thread_popup_uri_clicked(self, widget, threadview, uri): + self._open_uri(uri) + + def on_thread_window_delete_event(self, widget, event): + self.save() + return False + + def on_thread_window_destroy(self, widget): + self.destroyed() + + + + + # menu commands + + # menu file + + def on_menu_file_show_board_activate(self, widget): + self._show_board() + + def on_menu_file_compose_activate(self, widget): + self._show_submit_window() + + def on_menu_file_delete_activate(self, widget): + self._delete_log() + + def on_menu_file_close_activate(self, widget): + self._close_window() + + def on_menu_file_quit_activate(self, widget): + self._quit_session() + + # menu view + + def on_menu_view_refresh_activate(self, widget): + self.update() + + def on_menu_view_toolbar_activate(self, widget): + self._toggle_toolbar() + + def on_menu_view_statusbar_activate(self, widget): + self._toggle_statusbar() + + # menu bookmarks + + def on_menu_bookmarks_bookmarkthispage_activate(self, widget): + self._regist_as_bookmark() + + def on_menu_bookmarks_showbookmarks_activate(self, widget): + self._manage_bookmarks() + + # toolbuttons + + def on_toolbutton_refresh_activate(self, widget): + self.update() + + def on_toolbutton_showboard_activate(self, widget): + self._show_board() + + def on_toolbutton_compose_activate(self, widget): + self._show_submit_window() + + def on_toolbutton_delete_activate(self, widget): + self._delete_log() + + # popup menus + + def on_popup_threadview_menu_refresh_activate(self, widget): + self.update()