OSDN Git Service

Add bookmark.
[fukui-no-namari/fukui-no-namari.git] / src / FukuiNoNamari / thread_window.py
index 4dbbc03..6a14b33 100644 (file)
@@ -30,19 +30,23 @@ import gobject
 import threading
 import gconf
 import traceback
+import os
 
 import misc
+from misc import FileWrap, ThreadInvoker
 import datfile
 import barehtmlparser
 import idxfile
 import session
 import board_window
 import uri_opener
-from http_sub import HTTPRedirectHandler302
+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
 
 GLADE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                          "..", "data")
@@ -72,42 +76,6 @@ def open_thread(uri, update=False):
     winwrap.jump_to_res(bbs_type.uri)
 
 
-class ThreadInvoker(threading.Thread):
-    def __init__(self, on_end, *methods):
-        super(ThreadInvoker, self).__init__()
-        self.on_end = on_end
-        self.methods = methods
-    def run(self):
-        try:
-            for m in self.methods:
-                m()
-        finally:
-            self.on_end()
-
-
-class FileWrap:
-    def __init__(self, path):
-        self._file = None
-        self._path = path
-    def __del__(self):
-        self.close()
-    def seek(self, size):
-        self.file().seek(size)
-    def write(self, data):
-        self.file().write(data)
-    def close(self):
-        if self._file:
-            self._file.close()
-            self._file = None
-    def file(self):
-        if not self._file:
-            basedir = os.path.dirname(self._path)
-            if not os.path.isdir(basedir):
-                os.makedirs(basedir)
-            self._file = file(self._path, "a+")
-        return self._file
-
-
 class WinWrap(winwrapbase.WinWrapBase):
     hovering_over_link = False
     hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
@@ -121,11 +89,6 @@ class WinWrap(winwrapbase.WinWrapBase):
         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 = ""
@@ -140,11 +103,9 @@ class WinWrap(winwrapbase.WinWrapBase):
         self.toolbar.unset_style()
         self.statusbar = self.widget_tree.get_widget("appbar")
         self.textview = self.widget_tree.get_widget("textview")
-        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)
+        self.textview.drag_dest_unset()
+
+        self.initialize_buffer()
 
         sigdic = {"on_refresh_activate": self.update,
                   "on_compose_activate": self.on_compose_clicked,
@@ -154,8 +115,12 @@ class WinWrap(winwrapbase.WinWrapBase):
                   "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_thread_window_delete_event":
                   self.on_thread_window_delete_event,
+                  "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)
 
@@ -169,6 +134,14 @@ class WinWrap(winwrapbase.WinWrapBase):
 
         self.created()
 
+    def initialize_buffer(self):
+        self.textbuffer = gtk.TextBuffer()
+        self.textview.set_buffer(self.textbuffer)
+        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 destroy(self):
         self.save()
         self.window.destroy()
@@ -279,13 +252,37 @@ class WinWrap(winwrapbase.WinWrapBase):
     def on_quit_activate(self, widget):
         session.main_quit()
 
+    def on_add_bookmark_activate(self, widget):
+        bookmark_list.bookmark_list.add_bookmark_with_edit(
+            name=self.title, uri=self.bbs_type.uri)
+
+    def on_manage_bookmarks_activate(self, widget):
+        bookmark_window.open()
+
     def on_show_board_activate(self, widget):
         board_window.open_board(self.bbs_type.get_uri_base())
 
+    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()
+
     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"]
 
@@ -296,48 +293,47 @@ class WinWrap(winwrapbase.WinWrapBase):
             req.add_header("If-Modified-Since", lastmod)
         if etag:
             req.add_header("If-None-Match", etag)
-        print req.headers
-
-        opener = urllib2.build_opener(HTTPRedirectHandler302)
-        res = opener.open(req)
-        headers = res.info()
-        print headers
-
-        line = res.readline()
-        maybe_incomplete = False
-        while line:
-            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()
-
-        if maybe_incomplete:
-            lastmod = None
-            etag = None
+
+        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))
         else:
-            if "Last-Modified" in headers:
-                lastmod = headers["Last-Modified"]
-            if "ETag" in headers:
-                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)
-
-            gobject.idle_add(session.thread_idx_updated,
-                             self.bbs_type.get_thread_uri(), idx_dic)
+            headers = res.info()
+            gobject.idle_add(
+                self.statusbar.set_status, "%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):
 
@@ -349,12 +345,16 @@ class WinWrap(winwrapbase.WinWrapBase):
                     self.textbuffer.create_mark("1", self.enditer, True)
                 gobject.idle_add(create_mark)
 
-            line_count = datfile.get_dat_line_count(
-                self.bbs, self.board, self.thread)
+            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)
+
             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):
                     if self.jump_request_num:
@@ -372,8 +372,7 @@ class WinWrap(winwrapbase.WinWrapBase):
                 gobject.idle_add(do_jump, self.num)
 
         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):
@@ -416,8 +415,7 @@ class WinWrap(winwrapbase.WinWrapBase):
                 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)
+            datfile.load_dat(self.bbs_type, self.append_rawres_to_buffer)
         def jump():
 
             def do_jump(num):
@@ -447,16 +445,40 @@ class WinWrap(winwrapbase.WinWrapBase):
         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)
+
+        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.res_queue.append((str(self.num)+"\n", False, None, False))
+            self.res_queue.append((line, False, None, True))
+            print "maybe syntax error.", self.num, line
 
         def process_res_queue(res_queue, num):
             self.process_queue(res_queue)
@@ -542,8 +564,7 @@ class WinWrap(winwrapbase.WinWrapBase):
                     self.jump_request_num = int(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()
@@ -552,12 +573,8 @@ class WinWrap(winwrapbase.WinWrapBase):
 
     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):
@@ -603,9 +620,7 @@ class WinWrap(winwrapbase.WinWrapBase):
             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="):
@@ -636,8 +651,10 @@ class WinWrap(winwrapbase.WinWrapBase):
             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.parent.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()