OSDN Git Service

025f33908a6a64182cee788a10678c85e35b2860
[fukui-no-namari/fukui-no-namari.git] / src / Hage1 / thread_window.py
1 # Copyright (C) 2006 by Aiwota Programmer
2 # aiwotaprog@tetteke.tk
3 #
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.
8 #
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.
13 #
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
17
18 import pygtk
19 pygtk.require('2.0')
20 import gtk
21 import gtk.glade
22 import os.path
23 import codecs
24 import re
25 import pango
26 import urllib2
27
28 import misc
29 import datfile
30 import barehtmlparser
31 import idxfile
32 import session
33 import board_window
34 from http_sub import HTTPRedirectHandler302
35
36 GLADE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
37                          "..", "data")
38 GLADE_FILENAME = "thread_window.glade"
39
40 def open_thread(uri):
41     if not uri:
42         raise ValueError, "parameter must not be empty"
43
44     winwrap = session.get_window(uri)
45     if winwrap:
46         # already opened
47         winwrap.window.present()
48         pass
49     else:
50         win_wrap = WinWrap(uri)
51         session.window_created(uri, win_wrap)
52
53
54 class WinWrap:
55
56     def __init__(self, uri):
57         from BbsType import bbs_type_judge_uri
58         from BbsType import bbs_type_exception
59         self.bbs_type = bbs_type_judge_uri.get_type(uri)
60         if not self.bbs_type.is_thread():
61             raise bbs_type_exception.BbsTypeError, \
62                   "the uri does not represent thread: " + uri
63         self.bbs = self.bbs_type.bbs_type
64         self.board = self.bbs_type.board
65         self.thread = self.bbs_type.thread
66         self.host = self.bbs_type.host
67         self.uri = self.bbs_type.uri
68         self.size = 0
69         self.num = 0
70         self.title = None
71
72         glade_path = os.path.join(GLADE_DIR, GLADE_FILENAME)
73         self.widget_tree = gtk.glade.XML(glade_path)
74         self.window = self.widget_tree.get_widget("thread_window")
75         self.textview = self.widget_tree.get_widget("textview")
76         self.textbuffer = self.textview.get_buffer()
77         self.enditer = self.textbuffer.get_end_iter()
78         self.boldtag = self.textbuffer.create_tag(weight=pango.WEIGHT_BOLD)
79         self.leftmargintag = self.textbuffer.create_tag()
80         self.leftmargintag.set_property("left-margin", 20)
81
82         sigdic = {"on_toolbutton_refresh_clicked": self.update,
83                   "on_refresh_activate": self.update,
84                   "on_close_activate": self.on_close_activate,
85                   "on_quit_activate": self.on_quit_activate,
86                   "on_show_board_activate": self.on_show_board_activate,
87                   "on_thread_window_destroy": self.on_thread_window_destroy}
88         self.widget_tree.signal_autoconnect(sigdic)
89
90         self.load_dat()
91
92     def on_close_activate(self, widget):
93         self.window.destroy()
94
95     def on_thread_window_destroy(self, widget):
96         -1
97
98     def on_quit_activate(self, widget):
99         session.main_quit()
100
101     def on_show_board_activate(self, widget):
102         board_window.open_board(self.bbs_type.get_uri_base())
103
104     def http_get_dat(self, on_get_res):
105         datfile_url = self.bbs_type.get_dat_uri()
106
107         idx_dic = idxfile.load_idx(self.bbs, self.board, self.thread)
108         lastmod = idx_dic["lastModified"]
109         etag = idx_dic["etag"]
110
111         req = urllib2.Request(datfile_url)
112         if self.size > 0:
113             req.add_header("Range", "bytes=" + str(self.size) + "-")
114         if lastmod:
115             req.add_header("If-Modified-Since", lastmod)
116         if etag:
117             req.add_header("If-None-Match", etag)
118         print req.headers
119
120         opener = urllib2.build_opener(HTTPRedirectHandler302)
121         res = opener.open(req)
122         headers = res.info()
123         print headers
124
125         line = res.readline()
126         maybe_incomplete = False
127         while line:
128             if not line.endswith("\n"):
129                 maybe_incomplete = True
130                 print "does not end with \\n. maybe incomplete"
131                 break
132             on_get_res(line)
133             line = res.readline()
134
135         res.close()
136
137         if maybe_incomplete:
138             lastmod = None
139             etag = None
140         else:
141             if "Last-Modified" in headers:
142                 lastmod = headers["Last-Modified"]
143             if "ETag" in headers:
144                 etag = headers["Etag"]
145
146         if self.num > 0:
147             if not self.title:
148                 self.title = datfile.get_title_from_dat(
149                     self.bbs, self.board, self.thread)
150                 if self.title:
151                     self.window.set_title(self.title)
152             # save idx
153             idx_dic = {"title": self.title, "lineCount": self.num,
154                    "lastModified": lastmod, "etag": etag}
155             idxfile.save_idx(self.bbs, self.board, self.thread, idx_dic)
156
157             session.thread_idx_updated(
158                 self.bbs_type.get_thread_uri(), idx_dic)
159
160     def update(self, widget=None):
161         line_count = datfile.get_dat_line_count(
162             self.bbs, self.board, self.thread)
163
164         if line_count > self.num:
165             datfile.load_dat_partly(
166                 self.bbs, self.board, self.thread,
167                 self.append_rawres_to_buffer, self.num+1)
168
169         dat_path = misc.get_thread_dat_path(self.bbs, self.board, self.thread)
170         dat_file = file(dat_path, "a+")
171
172         def save_line_and_append_to_buffer(line):
173             dat_file.seek(self.size)
174             dat_file.write(line)
175             self.append_rawres_to_buffer(line)
176
177         self.http_get_dat(save_line_and_append_to_buffer)
178         dat_file.close()
179
180     def load_dat(self):
181         self.size = 0
182         self.num = 0
183
184         self.title = datfile.get_title_from_dat(
185             self.bbs, self.board, self.thread)
186         if self.title:
187             self.window.set_title(self.title)
188
189         datfile.load_dat(self.bbs, self.board, self.thread,
190                          self.append_rawres_to_buffer)
191         self.textview.scroll_to_mark(self.textbuffer.get_insert(), 0)
192
193
194     def append_rawres_to_buffer(self, line):
195         self.size += len(line)
196         self.num += 1
197
198         h = lambda name,mail,date,msg: self.reselems_to_buffer(
199             self.num, name, mail, date, msg)
200
201         datfile.split_line_to_elems(line.decode("cp932", "replace"), h)
202         
203     def reselems_to_buffer(self, num, name, mail, date, msg):
204         # number
205         self.textbuffer.insert(self.enditer, str(num) + " ")
206
207         # name
208         p = barehtmlparser.BareHTMLParser(self.untiedata_to_buffer)
209         p.feed("<b>" + name + "</b>")
210         p.close()
211
212         # mail
213         self.textbuffer.insert(self.enditer, "[" + mail + "]")
214
215         # date
216         p.feed(date)
217         p.close()
218         self.textbuffer.insert(self.enditer, "\n")
219
220         # msg
221         p.reset_func(self.untiedata_to_buffer_with_leftmargin)
222         p.feed(msg)
223         p.close()
224
225         self.textbuffer.insert(self.enditer, "\n\n")
226
227     def untiedata_to_buffer(self, data, bold, href):
228         if bold:
229             self.textbuffer.insert_with_tags(self.enditer, data, self.boldtag)
230         else:
231             self.textbuffer.insert(self.enditer, data)
232
233     def untiedata_to_buffer_with_leftmargin(self, data, bold, href):
234         if bold:
235             self.textbuffer.insert_with_tags(self.enditer, data,
236                                              self.boldtag, self.leftmargintag)
237         else:
238             self.textbuffer.insert_with_tags(self.enditer, data,
239                                              self.leftmargintag)