OSDN Git Service

Multithreads are abandoned. Alternatly, The asyncore substitutes.(#16776)
[fukui-no-namari/fukui-no-namari.git] / src / FukuiNoNamari / thread_popup.py
1
2 import gtk
3 import gobject
4 import re
5 import urlparse
6 import copy
7 import thread_view
8 from ThreadViewBase.element import ElementEmpty
9
10
11 class ThreadViewForPopup(thread_view.ThreadView):
12
13     # no popup
14     def _do_popup(self, x, y, button, time): pass
15
16
17 class ThreadPopup(gobject.GObject):
18     '''
19     classdocs
20     '''
21
22     __gsignals__ = {
23         "uri-clicked-event":
24         (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (object, object,))
25         }
26
27     _INTERVAL = 100
28     _BORDER_WIDTH = 1
29
30     def __init__(self, bbs_type):
31         gobject.GObject.__init__(self)        
32         self._thread_view_list = []
33         self._bbs_type = bbs_type
34         self._timer_started = False
35
36     def push_thread_view(self, threadview):
37         threadview.connect("cursor-over-link-event", self.on_cursor_over_link)
38         self._thread_view_list.append(threadview)
39
40     def pop_thread_view(self):
41         view = self._thread_view_list.pop()
42         top = view.get_toplevel()
43         top.destroy()
44
45     def _collapse(self, threadview):
46         length = len(self._thread_view_list)
47         for idx in range(length):
48             idx = length - idx - 1
49             view = self._thread_view_list[idx]
50             if view == threadview:
51                 break
52             self.pop_thread_view()
53
54     def _is_thread_view_top(self, threadview):
55         listnum = len(self._thread_view_list)
56         if listnum == 0:
57             return False
58         last = self._thread_view_list[listnum-1]
59         return threadview == last
60
61     def on_cursor_over_link(self, widget, event, uri):
62         orig_uri = uri
63         if not uri.startswith("http://"):
64             # maybe a relative uri.
65             uri = urlparse.urljoin(self._bbs_type.get_uri_base(), uri)
66
67         strict_uri = self._bbs_type.get_thread_uri()
68         idx = self._thread_view_list.index(widget)
69         if idx != len(self._thread_view_list)-1 and orig_uri == self._thread_view_list[idx+1].get_toplevel().uri:
70             return
71         if not self._check_to_need_hint(widget):
72             return
73         if uri != strict_uri and uri.startswith(strict_uri):
74             resnum = uri[len(strict_uri):]
75             match = re.match("(?P<left>\d+)-(?P<right>\d+)", resnum)
76             if match:
77                 left = int(match.group("left"))
78                 right = int(match.group("right"))
79                 if left <= right:
80                     resnum = range(left, right+1)
81                 else:
82                     resnum = range(left, right-1, -1)
83                 self._show_hint(widget, resnum, orig_uri)
84                 return
85             match = re.match("\d+", resnum)
86             if match:
87                 resnum = [int(match.group())]
88                 self._show_hint(widget, resnum, orig_uri)
89
90     def _get_owner(self, gdk_win):
91         top = gdk_win.get_toplevel()
92         for threadview in self._thread_view_list:
93             if threadview.window.get_toplevel() == top:
94                 return threadview
95         return None
96
97     def on_timeout(self):
98         ret = gtk.gdk.window_at_pointer()
99         if ret is None:
100             # print "unknown window"
101             self._collapse(self._thread_view_list[0])
102             self._timer_started = False
103             return False
104
105         gdk_win, x, y = ret
106         threadview = self._get_owner(gdk_win)
107         if threadview is None:
108             # print "unknown gdk window"
109             self._collapse(self._thread_view_list[0])
110             self._timer_started = False
111             return False
112
113         length = len(self._thread_view_list)
114         if length == 1:
115             # print "no popup window"
116             self._collapse(threadview)
117             self._timer_started = False
118             return False
119
120         if self._is_thread_view_top(threadview):
121             return True
122
123         uri, layout, element = threadview.ptrpos_to_uri(x, y)
124         view = self._thread_view_list[self._thread_view_list.index(threadview)+1]           
125         if layout is None or uri is None or uri != view.get_toplevel().uri:
126             self._collapse(threadview)
127
128         return True
129
130     def _show_hint(self, threadview, numlist, uri):
131         top = threadview.get_toplevel()
132         relative_x, relative_y = top.get_pointer()
133         gdk_win_x, gdk_win_y = top.window.get_origin()
134         abs_x = gdk_win_x + relative_x
135         abs_y = gdk_win_y + relative_y
136  
137         popupwin = gtk.Window(gtk.WINDOW_POPUP)
138
139         view = ThreadViewForPopup()
140         popupwin.add(thread_view.ThreadViewContainer(view))
141         view.connect("uri-clicked-event", self.on_threadview_uri_clicked)
142         self.push_thread_view(view)
143
144         # set width
145         view.size_allocate(gtk.gdk.Rectangle(0, 0, 300, 200))
146         view.adjustment.page_size = 200
147
148         for num in numlist:
149             for layout in self._thread_view_list[0].res_layout_list:
150                 # skip empty line
151                 if isinstance(layout.element_list[0], ElementEmpty):
152                     continue
153                 if layout.resnum == num:
154                     clone = layout.clone()
155                     view.add_layout(clone)
156         popupwin.view = view
157         popupwin.uri = uri
158         popupwin.set_property("border_width", ThreadPopup._BORDER_WIDTH)
159
160         view.size_allocate(
161             gtk.gdk.Rectangle(0, 0, 300, int(min(200, view.adjustment.upper))))
162
163         popupwin.set_default_size(view.allocation.width
164                                   +ThreadPopup._BORDER_WIDTH*2,
165                                   view.allocation.height
166                                   +ThreadPopup._BORDER_WIDTH*2)
167
168         # show the popup at an appropriate position.
169         width, height = popupwin.get_size()
170         if abs_x + width > gtk.gdk.screen_width():
171             abs_x = abs_x - width
172         if abs_y + height > gtk.gdk.screen_height():
173             abs_y = abs_y - height
174         popupwin.move(abs_x, abs_y)
175
176         popupwin.show_all()
177
178         if not self._timer_started:
179             self._timer_started = True
180             gobject.timeout_add(ThreadPopup._INTERVAL, self.on_timeout)
181
182     def _check_to_need_hint(self, threadview):
183         if self._is_thread_view_top(threadview):
184             return True
185
186     def on_threadview_uri_clicked(self, widget, uri):
187         self.emit("uri-clicked-event", widget, uri)