import threading
import gconf
import traceback
+import itertools
+import os
+import sys
import misc
from misc import FileWrap, ThreadInvoker
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
-GLADE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
- "..", "data")
GLADE_FILENAME = "thread_window.glade"
def open_thread(uri, update=False):
winwrap.load(update)
# jump to the res if necessary.
- winwrap.jump_to_res(bbs_type.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 HTMLParserToThreadView:
+ def __init__(self, threadview, resnum, left_margin):
+ self.threadview = threadview
+ self.resnum = resnum
+ self.left_margin = left_margin
+ self.initialize()
+
+ def set_left_margin(self, left_margin):
+ self.left_margin = left_margin
+
+ def initialize(self):
+ self.layout = None
+
+ def on_new_line(self):
+ self.to_thread_view()
+ self.layout = self.threadview.create_res_layout(
+ self.left_margin, self.resnum)
+
+ def from_html_parser(self, data, bold, href):
+ if self.layout == None:
+ self.layout = self.threadview.create_res_layout(
+ self.left_margin, self.resnum)
+
+ self.layout.add_text(data, bold, href)
+
+ def to_thread_view(self):
+ if self.layout is not None:
+ # gobject.idle_add(self.threadview.add_layout, self.layout)
+ gtk.gdk.threads_enter()
+ self.threadview.add_layout(self.layout)
+ gtk.gdk.threads_leave()
+ self.initialize()
class WinWrap(winwrapbase.WinWrapBase):
hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
regular_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM)
-
def __init__(self, uri):
from BbsType import bbs_type_judge_uri
from BbsType import bbs_type_exception
if not self.bbs_type.is_thread():
raise bbs_type_exception.BbsTypeError, \
"the uri does not represent thread: " + uri
- self.bbs = self.bbs_type.bbs_type
- self.board = self.bbs_type.board
- self.thread = self.bbs_type.thread
- self.host = self.bbs_type.host
- self.uri = self.bbs_type.uri
self.size = 0
self.num = 0
self.title = ""
self.jump_request_num = 0
self.progress = False
- glade_path = os.path.join(GLADE_DIR, GLADE_FILENAME)
+ 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._get_widgets()
+ self.widget_tree.signal_autoconnect(self)
+
self.toolbar.unset_style()
- self.statusbar = self.widget_tree.get_widget("appbar")
- self.textview = self.widget_tree.get_widget("textview")
- self.textview.drag_dest_unset()
- self.textbuffer = self.textview.get_buffer()
- 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)
-
- 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_thread_window_delete_event":
- self.on_thread_window_delete_event,
- "on_thread_window_destroy": self.on_thread_window_destroy}
- self.widget_tree.signal_autoconnect(sigdic)
-
- self.textview.connect("event-after", self.on_event_after)
- self.textview.connect("motion-notify-event",
- self.on_motion_notify_event)
- self.textview.connect("visibility-notify-event",
- self.on_visibility_notify_event)
+
+ self.threadview = thread_view.ThreadView()
+ self.threadpopup = thread_popup.ThreadPopup(self.bbs_type)
+ self.threadpopup.push_thread_view(self.threadview)
+ self.vbox.pack_start(self.threadview)
+ self.vbox.reorder_child(self.threadview, 2)
+ self.window.set_focus(self.threadview.drawingarea)
+
+ self._get_popupmenu_widgets()
+
+ 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.statusbar_context_id = self.statusbar.get_context_id(
+ "Thread Window Status")
+ self.statusbar.push(self.statusbar_context_id, "OK.")
+
+ self.initialize_buffer()
+
self.restore()
- self.window.show()
+ 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 _get_popupmenu_widgets(self):
+ self.threadview.popupmenu = self.widget_tree.get_widget(
+ "popup_threadview_menu")
+ self.threadview.menu_openuri = self.widget_tree.get_widget(
+ "popup_threadview_menu_openuri")
+ self.threadview.menu_copylinkaddress = self.widget_tree.get_widget(
+ "popup_threadview_menu_copylinkaddress")
+ self.threadview.menu_separator_link = self.widget_tree.get_widget(
+ "popup_threadview_menu_separator_link")
+ self.threadview.menu_copyselection = self.widget_tree.get_widget(
+ "popup_threadview_menu_copyselection")
+ self.threadview.menu_openasuri = self.widget_tree.get_widget(
+ "popup_threadview_menu_openasuri")
+ self.threadview.menu_separator_selection = self.widget_tree.get_widget(
+ "popup_threadview_menu_separator_selection")
+
+ 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 on_compose_clicked(self, widget):
- import submit_window
+ 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 on_toolbar_activate(self, widget):
- if self.toolbar.parent.get_property("visible"):
- self.toolbar.parent.hide()
+ def _toggle_toolbar(self):
+ if self.toolbar.get_property("visible"):
+ self.toolbar.hide()
else:
- self.toolbar.parent.show()
+ self.toolbar.show()
- def on_statusbar_activate(self, widget):
+ def _toggle_statusbar(self):
if self.statusbar.get_property("visible"):
self.statusbar.hide()
else:
self.statusbar.show()
- def on_event_after(self, widget, event):
- if event.type != gtk.gdk.BUTTON_RELEASE:
- return False
- if event.button != 1:
- return False
- buffer = widget.get_buffer()
+ def _close_window(self):
+ self.destroy()
- try:
- start, end = buffer.get_selection_bounds()
- except ValueError:
- pass
- else:
- if start.get_offset() != end.get_offset():
- return False
-
- x, y = widget.window_to_buffer_coords(
- gtk.TEXT_WINDOW_WIDGET, int (event.x), int(event.y))
- iter = widget.get_iter_at_location(x, y)
- if not iter.has_tag(self.leftmargintag) or x > 20:
- tags = iter.get_tags()
- for tag in tags:
- href = tag.get_data("href")
- if href:
- self.on_link_clicked(widget, href)
- return False
+ def _quit_session(self):
+ session.main_quit()
+
+ def _regist_as_bookmark(self):
+ bookmark_list.bookmark_list.add_bookmark_with_edit(
+ name=self.title, uri=self.bbs_type.uri)
- def on_link_clicked(self, widget, href):
+ 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()
- if not href.startswith("http://"):
+ def _open_uri(self, uri):
+ if not uri.startswith("http://"):
# maybe a relative uri.
- href = urlparse.urljoin(self.bbs_type.get_uri_base(), href)
+ uri = urlparse.urljoin(self.bbs_type.get_uri_base(), uri)
try:
- uri_opener.open_uri(href)
+ uri_opener.open_uri(uri)
except bbs_type_exception.BbsTypeError:
# not supported, show with the web browser.
- gnome.url_show(href)
-
- def on_motion_notify_event(self, widget, event):
- x, y = widget.window_to_buffer_coords(
- gtk.TEXT_WINDOW_WIDGET, int(event.x), int(event.y))
- self.set_cursor_if_appropriate(widget, x, y)
- widget.window.get_pointer()
- return False
-
- def on_visibility_notify_event(self, widget, event):
- wx, wy, mod = widget.window.get_pointer()
- bx, by = widget.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, wx, wy)
-
- self.set_cursor_if_appropriate(widget, bx, by)
- return False
-
- def set_cursor_if_appropriate(self, widget, x, y):
- hovering = False
-
- buffer = widget.get_buffer()
- iter = widget.get_iter_at_location(x, y)
- if not iter.has_tag(self.leftmargintag) or x > 20:
- tags = iter.get_tags()
- for tag in tags:
- href = tag.get_data("href")
- if href:
- hovering = True
-
- if hovering != self.hovering_over_link:
- self.hovering_over_link = hovering
-
- if self.hovering_over_link:
- widget.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
- self.hand_cursor)
- else:
- widget.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
- self.regular_cursor)
+ gnome.url_show(uri)
- def on_close_activate(self, widget):
- self.destroy()
-
- def on_thread_window_delete_event(self, widget, event):
- self.save()
- return False
-
- def on_thread_window_destroy(self, widget):
- self.destroyed()
-
- def on_quit_activate(self, widget):
- session.main_quit()
+ 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 on_show_board_activate(self, widget):
- board_window.open_board(self.bbs_type.get_uri_base())
+ def _modify_uri(self, uri):
+ if not uri.startswith("http://"):
+ uri = "http://" + uri
+ return uri
def http_get_dat(self, on_get_res):
datfile_url = self.bbs_type.get_dat_uri()
- idx_dic = idxfile.load_idx(self.bbs, self.board, self.thread)
+ idx_dic = idxfile.load_idx(self.bbs_type)
lastmod = idx_dic["lastModified"]
etag = idx_dic["etag"]
req = urllib2.Request(datfile_url)
+ req.add_header("User-agent", config.User_Agent)
if self.size > 0:
req.add_header("Range", "bytes=" + str(self.size) + "-")
if lastmod:
if etag:
req.add_header("If-None-Match", etag)
+ def push():
+ self.statusbar.pop(self.statusbar_context_id)
+ self.statusbar.push(self.statusbar_context_id, "GET...")
+ gobject.idle_add(push)
+
+ 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:
- gobject.idle_add(
- self.statusbar.set_status, "%d %s" % (e.code, e.msg))
+ def push(code, msg):
+ message = "%d %s" % (code, msg)
+ self.statusbar.pop(self.statusbar_context_id)
+ self.statusbar.push(self.statusbar_context_id, message)
+ gobject.idle_add(push, e.code, e.msg)
else:
headers = res.info()
- gobject.idle_add(
- self.statusbar.set_status, "%d %s" % (res.code, res.msg))
- line = res.readline()
+ if "Last-Modified" in headers:
+ la = headers["Last-Modified"]
+ def push(code, msg, lastm):
+ message = "%d %s [%s]" % (code, msg, lastm)
+ self.statusbar.pop(self.statusbar_context_id)
+ self.statusbar.push(self.statusbar_context_id, message)
+ gobject.idle_add(push, res.code, res.msg, la)
+ else:
+ def push(code, msg):
+ message = "%d %s" % (code, msg)
+ self.statusbar.pop(self.statusbar_context_id)
+ self.statusbar.push(self.statusbar_context_id, message)
+ gobject.idle_add(push, res.code, res.msg)
+
maybe_incomplete = False
- while line:
+ 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)
- line = res.readline()
res.close()
etag = headers["Etag"]
if self.num > 0:
- if not self.title:
- title = datfile.get_title_from_dat(
- self.bbs, self.board, self.thread)
- if title:
- self.title = title
- gobject.idle_add(self.window.set_title, title)
# save idx
idx_dic = {"title": self.title, "lineCount": self.num,
"lastModified": lastmod, "etag": etag}
- idxfile.save_idx(self.bbs, self.board, self.thread, idx_dic)
+ 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):
+ def update(self):
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
+
+ gobject.idle_add(self.initialize_buffer)
- line_count = datfile.get_dat_line_count(
- self.bbs, self.board, self.thread)
if line_count > self.num:
datfile.load_dat_partly(
- self.bbs, self.board, self.thread,
- self.append_rawres_to_buffer, self.num+1)
+ self.bbs_type, self.append_rawres_to_buffer, self.num+1)
- def do_jump(num):
+ def do_jump():
if self.jump_request_num:
if self.jump_request_num <= num:
- # jump if enable, otherwize jump later.
num = self.jump_request_num
self.jump_request_num = 0
- mark = self.textbuffer.get_mark(str(num))
- if mark:
- self.textview.scroll_to_mark(
- mark, 0, True, 0, 0)
+ self.jump_to_res(num)
else:
- self.jump_to_the_end(num)
+ self.jump_to_the_end()
- gobject.idle_add(do_jump, self.num)
+ gobject.idle_add(do_jump)
def get():
- dat_path = misc.get_thread_dat_path(
- self.bbs, self.board, self.thread)
+ dat_path = misc.get_thread_dat_path(self.bbs_type)
dat_file = FileWrap(dat_path)
def save_line_and_append_to_buffer(line):
self.append_rawres_to_buffer(line)
self.http_get_dat(save_line_and_append_to_buffer)
+ gtk.gdk.threads_enter()
+ self.threadview.redraw()
+ gtk.gdk.threads_leave()
dat_file.close()
def do_jump():
if self.jump_request_num:
num = self.jump_request_num
self.jump_request_num = 0
- mark = self.textbuffer.get_mark(str(num))
- if mark:
- self.textview.scroll_to_mark(mark, 0, True, 0, 0)
+ self.jump_to_res(num)
gobject.idle_add(do_jump)
self.jump_request_num = 0
def load():
+ datfile.load_dat(self.bbs_type, self.append_rawres_to_buffer)
- def create_mark():
- self.textbuffer.create_mark("1", self.enditer, True)
- gobject.idle_add(create_mark)
-
- datfile.load_dat(self.bbs, self.board, self.thread,
- self.append_rawres_to_buffer)
def jump():
- def do_jump(num):
+ def do_jump():
if self.jump_request_num:
num = self.jump_request_num
self.jump_request_num = 0
- mark = self.textbuffer.get_mark(str(num))
- if mark:
- self.textview.scroll_to_mark(mark, 0, True, 0, 0)
+ self.jump_to_res(num)
else:
- self.jump_to_the_end(num)
+ self.jump_to_the_end()
- gobject.idle_add(do_jump, self.num)
+ gobject.idle_add(do_jump)
if self.lock():
self.num += 1
if not self.title and self.num == 1:
- title = datfile.do_get_title_from_dat(line)
+ title = self.bbs_type.get_title_from_dat(line)
if title:
self.title = title
gobject.idle_add(self.window.set_title, title)
- h = lambda name,mail,date,msg: self.reselems_to_buffer(
- self.num, name, mail, date, msg)
-
- self.res_queue = []
- datfile.split_line_to_elems(line.decode("cp932", "replace"), h)
-
- def process_res_queue(res_queue, num):
- self.process_queue(res_queue)
- # for next res
- self.textbuffer.create_mark(str(num+1), self.enditer, True)
-
- gobject.idle_add(
- process_res_queue, self.res_queue, self.num)
+ line = line.decode(self.bbs_type.encoding, "replace")
+ m = self.bbs_type.dat_reg.match(line)
+ if m:
+ name = m.group("name")
+ mail = m.group("mail")
+ date = m.group("date")
+ msg = m.group("msg")
+ try:
+ num = int(m.group("num"))
+ except IndexError:
+ # use simple counter num
+ num = self.num
+ else:
+ # use num in dat
+ self.num = num
+ try:
+ id = m.group("id")
+ except IndexError:
+ pass
+ else:
+ if id:
+ date += " ID:" + id
+ self.reselems_to_buffer(num, name, mail, date, msg)
+ else:
+ self.reselems_to_buffer(
+ str(self.num), "Invalid Name", "Invalid Mail",
+ "Invalid Date", line)
+ print "maybe syntax error.", self.num, line
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) + " ")
# date
p.feed(date)
- p.feed("<br>")
+ 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("<br><br>")
+ p.feed("<br>")
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):
- for data, bold, href, margin in queue:
- 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()
+
+ def jump(self, value):
+ gobject.idle_add(self.threadview.jump, value)
- def jump_to_the_end(self, num):
- mark = self.textbuffer.get_mark(str(num+1))
- if mark:
- self.textview.scroll_to_mark(mark, 0)
+ def jump_to_layout(self, layout):
+ gobject.idle_add(self.threadview.jump_to_layout, layout)
+
+ def jump_to_the_end(self):
+ gobject.idle_add(self.threadview.jump_to_the_end)
def lock(self):
if self.lock_obj:
self.lock_obj = False
print "unlock"
- def jump_to_res(self, uri):
- strict_uri = self.bbs_type.get_thread_uri()
- if uri != strict_uri and uri.startswith(strict_uri):
- resnum = uri[len(strict_uri):]
- match = re.match("\d+", resnum)
- if match:
- resnum = match.group()
- mark = self.textbuffer.get_mark(resnum)
- if mark:
- self.textview.scroll_to_mark(mark, 0, True, 0, 0)
- elif self.progress:
- # try later.
- self.jump_request_num = int(resnum)
+ def jump_to_res(self, resnum):
+ if self.threadview.jump_to_res(resnum):
+ return
+ self.jump_request_num = resnum
def load(self, update=False):
- dat_path = misc.get_thread_dat_path(
- self.bbs_type.bbs_type, self.bbs_type.board, self.bbs_type.thread)
+ dat_path = misc.get_thread_dat_path(self.bbs_type)
dat_exists = os.path.exists(dat_path)
if update or not dat_exists:
self.update()
def save(self):
try:
- states_path = misc.get_thread_states_path(
- self.bbs_type.bbs_type, self.bbs_type.board,
- self.bbs_type.thread)
- dat_path = misc.get_thread_dat_path(
- self.bbs_type.bbs_type, self.bbs_type.board,
- self.bbs_type.thread)
+ states_path = misc.get_thread_states_path(self.bbs_type)
+ dat_path = misc.get_thread_dat_path(self.bbs_type)
# save only if dat file exists.
if os.path.exists(dat_path):
window_width, window_height = self.window.get_size()
- toolbar_visible = self.toolbar.parent.get_property("visible")
+ toolbar_visible = self.toolbar.get_property("visible")
statusbar_visible = self.statusbar.get_property("visible")
dirname = os.path.dirname(states_path)
except:
traceback.print_exc()
- states_path = misc.get_thread_states_path(
- self.bbs_type.bbs_type, self.bbs_type.board,
- self.bbs_type.thread)
+ states_path = misc.get_thread_states_path(self.bbs_type)
if os.path.exists(states_path):
for line in file(states_path):
if line.startswith("window_height="):
self.window.set_default_size(window_width, window_height)
if not toolbar_visible:
- gobject.idle_add(self.toolbar.parent.hide)
+ gobject.idle_add(self.toolbar.hide,
+ priority=gobject.PRIORITY_HIGH)
if not statusbar_visible:
- gobject.idle_add(self.statusbar.hide)
+ gobject.idle_add(self.statusbar.hide,
+ priority=gobject.PRIORITY_HIGH)
except:
traceback.print_exc()
+
+
+ # signal handlers
+
+ 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_openuri_activate(self, widget):
+ self._open_uri(widget.uri)
+
+ def on_popup_threadview_menu_copylinkaddress_activate(self, widget):
+ self._copy_text_to_clipboard(widget.uri)
+
+ def on_popup_threadview_menu_copyselection_activate(self, widget):
+ text = self.threadview.get_selected_text()
+ self._copy_text_to_clipboard(text)
+
+ def on_popup_threadview_menu_openasuri_activate(self, widget):
+ text = self.threadview.get_selected_text()
+ uri = self._modify_uri(text)
+ self._open_uri(uri)
+
+ def on_popup_threadview_menu_refresh_activate(self, widget):
+ self.update()