OSDN Git Service

Add average column
[fukui-no-namari/fukui-no-namari.git] / src / Hage1 / board_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
23 import time
24
25 import board_data
26 import thread_window
27 import misc
28
29 GLADE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
30                          "..", "data")
31 GLADE_FILENAME = "board_window.glade"
32
33
34 class WinWrap:
35
36     def __init__(self, bbs, board):
37         self.bbs = bbs
38         self.board = board
39
40         glade_path = os.path.join(GLADE_DIR, GLADE_FILENAME)
41         self.mainwin = gtk.glade.XML(glade_path)
42
43         self.treeview = self.mainwin.get_widget("treeview")
44         self.treeview.set_rules_hint(True)
45
46         self.popupmenu = self.mainwin.get_widget("popup_menu")
47
48         renderer = gtk.CellRendererText()
49
50         self.treeviewcolumn = {}
51         for i in range(1, len(ThreadListModel.column_names)):
52             column_name = ThreadListModel.column_names[i]
53             self.treeviewcolumn[column_name] = gtk.TreeViewColumn(
54                 column_name, renderer, text=i)
55             self.treeviewcolumn[column_name].set_resizable(True)
56             self.treeviewcolumn[column_name].set_reorderable(True)
57             self.treeviewcolumn[column_name].set_clickable(True)
58             self.treeviewcolumn[column_name].connect(
59                 "clicked", self.on_column_clicked, column_name)
60             self.treeview.append_column(self.treeviewcolumn[column_name])
61
62         sigdic = {"on_board_window_destroy": self.on_board_window_destroy,
63                   "on_quit_activate": self.on_quit_activate,
64                   "on_load_local_activate": self.on_load_local_activate,
65                   "on_get_remote_activate": self.on_get_remote_activate,
66                   "on_treeview_row_activated":
67                   lambda w,p,v: self.on_open_thread(w),
68                   "on_treeview_button_press_event":
69                   self.on_treeview_button_press_event,
70                   "on_popup_menu_open_activate": self.on_open_thread}
71         self.mainwin.signal_autoconnect(sigdic)
72
73     def on_board_window_destroy(self, widget):
74         gtk.main_quit()
75
76     def on_quit_activate(self, widget):
77         gtk.main_quit()
78
79     def on_load_local_activate(self, widget):
80         t = board_data.LoadLocal(self.bbs, self.board, self.update_datastore)
81         t.start()
82
83     def on_get_remote_activate(self, widget):
84         t = board_data.GetRemote(self.bbs, self.board, self.update_datastore)
85         t.start()
86
87     def on_column_clicked(self, treeviewcolumn, column_name):
88         model = self.treeview.get_model()
89         if model:
90             model.sort(column_name)
91             self.reset_sort_indicator()
92
93     def reset_sort_indicator(self):
94         model = self.treeview.get_model()
95         if model:
96             sort_column_name, sort_reverse = model.get_sort()
97             for name,column in self.treeviewcolumn.iteritems():
98                 column.set_sort_indicator(False)
99             if sort_column_name != "num" or sort_reverse:
100                 self.treeviewcolumn[sort_column_name].set_sort_indicator(True)
101                 if sort_reverse:
102                     self.treeviewcolumn[sort_column_name].set_sort_order(
103                         gtk.SORT_DESCENDING)
104                 else:
105                     self.treeviewcolumn[sort_column_name].set_sort_order(
106                         gtk.SORT_ASCENDING)
107         
108     def on_open_thread(self, widget):
109         treeselection = self.treeview.get_selection()
110         model, iter = treeselection.get_selected()
111         if not iter:
112             return
113
114         thread = model.get_value(iter, ThreadListModel.column_names.index("id"))
115         title = model.get_value(
116             iter, ThreadListModel.column_names.index("title"))
117         print thread + ':"' + title + '"', "activated"
118
119         thread_window.WinWrap(self.bbs, self.board, thread)
120
121     def on_treeview_button_press_event(self, widget, event):
122         if event.button == 3:
123             x = int(event.x)
124             y = int(event.y)
125             time = event.time
126             pthinfo = widget.get_path_at_pos(x, y)
127             if pthinfo is not None:
128                 path, col, cellx, celly = pthinfo
129                 widget.grab_focus()
130                 widget.set_cursor(path, col, 0)
131                 self.popupmenu.popup(None, None, None, event.button, time)
132             return 1
133
134     def update_datastore(self, datalist, lastmod):
135         print "reflesh datastore"
136
137         try:
138             lastmod = misc.httpdate_to_secs(lastmod)
139         except:
140             lastmod = 0
141
142         time_start = time.time()
143         list_list = []
144         for id, dic in datalist.iteritems():
145             dic["id"] = id
146
147             # average
148             if lastmod == 0 or dic["num"] == 0:
149                 dic["average"] = 0
150             else:
151                 res = dic["res"]
152                 start = int(id)
153                 dic["average"] = int(res * 60 * 60 * 24 / (lastmod - start))
154
155             list_list.append(dic)
156
157         model = self.treeview.get_model()
158         if model:
159             sort_column_name, sort_reverse = model.get_sort()
160             model = ThreadListModel(list_list, sort_column_name, sort_reverse)
161         else:
162             model = ThreadListModel(list_list)
163         self.treeview.set_model(model)
164
165         self.reset_sort_indicator()
166
167         print "end"
168         time_end = time.time()
169         print time_end - time_start
170
171
172 class ThreadListModel(gtk.GenericTreeModel):
173     column_types = (str, int, str, int, int, str, int)
174     column_names = ["id", "num", "title", "res", "lineCount",
175                     "lastModified", "average"]
176
177     def __init__(self, list, sort_column_name="num", sort_reverse=False):
178         gtk.GenericTreeModel.__init__(self)
179         self.list = list
180         self.sort_column_name = sort_column_name
181         self.sort_reverse = sort_reverse
182         self.do_sort(self.sort_column_name, self.sort_reverse)
183
184     def build_order_dict(self):
185         # key: thread id, value: index in self.list
186         self.order_dict = dict(
187             [(item["id"], index) for index, item in enumerate(self.list)])
188  
189     def compare(self, v1, v2, reverse):
190         if not reverse:
191             if v1 == 0 and v2 == 0:
192                 return 0
193             elif v1 == 0:
194                 return 1
195             elif v2 == 0:
196                 return -1
197         return v1 - v2
198
199     def get_sort(self):
200         return self.sort_column_name, self.sort_reverse
201
202     def do_sort(self, column_name, reverse):
203         if self.column_types[self.column_names.index(column_name)] == str:
204             self.list.sort(None, lambda dic: dic[column_name], reverse)
205         else:
206             h = lambda x, y: self.compare(x, y, reverse)
207             self.list.sort(h, lambda dic: dic[column_name], reverse)
208         self.build_order_dict()
209
210     def sort(self, column_name):
211         old_order_dict = self.order_dict
212
213         if column_name == self.sort_column_name:
214             # sort reverse
215             self.sort_reverse = not self.sort_reverse
216         else:
217             self.sort_column_name = column_name
218             self.sort_reverse = False
219
220         self.do_sort(self.sort_column_name, self.sort_reverse)
221
222         neworder = [old_order_dict[item["id"]] for item in self.list]
223         self.rows_reordered(None, None, neworder)
224
225     def on_get_flags(self):
226         return gtk.TREE_MODEL_LIST_ONLY
227
228     def on_get_n_columns(self):
229         return len(self.column_types)
230
231     def on_get_column_type(self, n):
232         return self.column_types[n]
233
234     def on_get_iter(self, path):
235         return self.list[path[0]]
236
237     def on_get_path(self, rowref):
238         return self.order_dict[rowref["id"]]
239
240     def on_get_value(self, rowref, column):
241         return rowref[self.column_names[column]]
242
243     def on_iter_next(self, rowref):
244         try:
245             i = self.order_dict[rowref["id"]] + 1
246             return self.list[i]
247         except IndexError:
248             return None
249
250     def on_iter_children(self, rowref):
251         if rowref:
252             return None
253         return self.list[0]
254
255     def on_iter_has_child(self, rowref):
256         return False
257
258     def on_iter_n_children(self, rowref):
259         if rowref:
260             return 0
261         return len(self.list)
262
263     def on_iter_nth_child(self, rowref, n):
264         if rowref:
265             return None
266         try:
267             return self.list[n]
268         except IndexError:
269             return None
270
271     def on_iter_parent(self, child):
272         return None