OSDN Git Service

Add an update option to uri_opener.
[fukui-no-namari/fukui-no-namari.git] / src / Hage1 / thread_window.py
index 7f56e39..b251af7 100644 (file)
@@ -24,6 +24,8 @@ import codecs
 import re
 import pango
 import urllib2
+import urlparse
+import gnome
 
 import misc
 import datfile
@@ -31,27 +33,45 @@ import barehtmlparser
 import idxfile
 import session
 import board_window
+import uri_opener
 from http_sub import HTTPRedirectHandler302
+from BbsType import bbs_type_judge_uri
+from BbsType import bbs_type_exception
 
 GLADE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                          "..", "data")
 GLADE_FILENAME = "thread_window.glade"
 
-def open_thread(uri):
+def open_thread(uri, update=False):
     if not uri:
         raise ValueError, "parameter must not be empty"
 
+    bbs_type = bbs_type_judge_uri.get_type(uri)
+    if not bbs_type.is_thread():
+        raise bbs_type_exception.BbsTypeError, \
+              "the uri does not represent thread: " + uri
+    uri = bbs_type.get_thread_uri()  # use strict thread uri
+
     winwrap = session.get_window(uri)
     if winwrap:
         # already opened
         winwrap.window.present()
-        pass
+        if update:
+            winwrap.load(update)
     else:
-        win_wrap = WinWrap(uri)
-        session.window_created(uri, win_wrap)
+        winwrap = WinWrap(bbs_type.uri)  # pass original uri
+        session.window_created(uri, winwrap)
+        winwrap.load(update)
+
+    # jump to the res if necessary.
+    winwrap.jump_to_res(bbs_type.uri)
 
 
 class WinWrap:
+    hovering_over_link = False
+    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
@@ -80,6 +100,7 @@ class WinWrap:
         self.leftmargintag.set_property("left-margin", 20)
 
         sigdic = {"on_toolbutton_refresh_clicked": self.update,
+                  "on_toolbutton_compose_clicked": self.on_compose_clicked,
                   "on_refresh_activate": self.update,
                   "on_close_activate": self.on_close_activate,
                   "on_quit_activate": self.on_quit_activate,
@@ -87,7 +108,89 @@ class WinWrap:
                   "on_thread_window_destroy": self.on_thread_window_destroy}
         self.widget_tree.signal_autoconnect(sigdic)
 
-        self.load_dat()
+        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)
+
+    def on_compose_clicked(self, widget):
+        import submit_window
+        submit_window.open(self.bbs_type.get_thread_uri())
+
+    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()
+
+        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 on_link_clicked(self, widget, href):
+
+        if not href.startswith("http://"):
+            # maybe a relative uri.
+            href = urlparse.urljoin(self.bbs_type.get_uri_base(), href)
+
+        try:
+            uri_opener.open_uri(href)
+        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)
 
     def on_close_activate(self, widget):
         self.window.destroy()
@@ -209,9 +312,15 @@ class WinWrap:
         if self.title:
             self.window.set_title(self.title)
 
+        self.textbuffer.create_mark("1", self.enditer, True)
+
         datfile.load_dat(self.bbs, self.board, self.thread,
                          self.append_rawres_to_buffer)
-        self.textview.scroll_to_mark(self.textbuffer.get_insert(), 0)
+        if self.num > 0:
+            # jump to the last res.
+            mark = self.textbuffer.get_mark(str(self.num+1))
+            if mark:
+                self.textview.scroll_to_mark(mark, 0)
 
 
     def append_rawres_to_buffer(self, line):
@@ -222,41 +331,86 @@ class WinWrap:
             self.num, name, mail, date, msg)
 
         datfile.split_line_to_elems(line.decode("cp932", "replace"), h)
-        
+
+        # for next res
+        self.textbuffer.create_mark(str(self.num+1), self.enditer, True)
+
     def reselems_to_buffer(self, num, name, mail, date, msg):
+        p = barehtmlparser.BareHTMLParser(self.untiedata_to_buffer)
         # number
-        self.textbuffer.insert(self.enditer, str(num) + " ")
+        p.feed(str(num) + " ")
 
         # name
-        p = barehtmlparser.BareHTMLParser(self.untiedata_to_buffer)
         p.feed("<b>" + name + "</b>")
-        p.close()
 
         # mail
-        self.textbuffer.insert(self.enditer, "[" + mail + "]")
+        p.feed("[" + mail + "]")
 
         # date
         p.feed(date)
-        p.close()
-        self.textbuffer.insert(self.enditer, "\n")
+        p.feed("<br>")
 
         # msg
         p.reset_func(self.untiedata_to_buffer_with_leftmargin)
-        p.feed(msg)
+        p.feed(msg.lstrip(" "))
+
+        p.feed("<br><br>")
         p.close()
 
-        self.textbuffer.insert(self.enditer, "\n\n")
+    def href_tag(self, href):
+        tag = self.textbuffer.create_tag(underline=pango.UNDERLINE_SINGLE)
+        tag.set_data("href", href)
+        return tag
 
     def untiedata_to_buffer(self, data, bold, href):
         if bold:
-            self.textbuffer.insert_with_tags(self.enditer, data, self.boldtag)
+            if href:
+                self.textbuffer.insert_with_tags(
+                    self.enditer, data, self.boldtag, self.href_tag(href))
+            else:                
+                self.textbuffer.insert_with_tags(
+                    self.enditer, data, self.boldtag)
         else:
-            self.textbuffer.insert(self.enditer, data)
+            if href:
+                self.textbuffer.insert_with_tags(
+                    self.enditer, data, self.href_tag(href))
+            else:
+                self.textbuffer.insert(self.enditer, data)
 
     def untiedata_to_buffer_with_leftmargin(self, data, bold, href):
         if bold:
-            self.textbuffer.insert_with_tags(self.enditer, data,
-                                             self.boldtag, self.leftmargintag)
+            if href:
+                self.textbuffer.insert_with_tags(
+                    self.enditer, data, self.boldtag,
+                    self.leftmargintag,self.href_tag(href))
+            else:
+                self.textbuffer.insert_with_tags(
+                    self.enditer, data, self.boldtag, self.leftmargintag)
+        else:
+            if href:
+                self.textbuffer.insert_with_tags(
+                    self.enditer, data,
+                    self.leftmargintag, self.href_tag(href))
+            else:
+                self.textbuffer.insert_with_tags(
+                    self.enditer, data, self.leftmargintag)
+
+    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)
+
+    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_exists = os.path.exists(dat_path)
+        if update or not dat_exists:
+            self.update()
         else:
-            self.textbuffer.insert_with_tags(self.enditer, data,
-                                             self.leftmargintag)
+            self.load_dat()