9 class ThreadPopup(gobject.GObject):
16 (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (object, object,))
21 def __init__(self, bbs_type):
22 gobject.GObject.__init__(self)
23 self._thread_view_list = []
24 self._bbs_type = bbs_type
25 self._timer_started = False
27 def push_thread_view(self, threadview):
28 threadview.connect("cursor-over-link-event", self.on_cursor_over_link)
29 self._thread_view_list.append(threadview)
31 def pop_thread_view(self):
32 view = self._thread_view_list.pop()
33 top = view.get_toplevel()
36 def _collapse(self, threadview):
37 length = len(self._thread_view_list)
38 for idx in range(length):
39 idx = length - idx - 1
40 view = self._thread_view_list[idx]
41 if view == threadview:
43 self.pop_thread_view()
45 def _is_thread_view_top(self, threadview):
46 listnum = len(self._thread_view_list)
49 last = self._thread_view_list[listnum-1]
50 return threadview == last
52 def on_cursor_over_link(self, widget, event, uri):
54 if not uri.startswith("http://"):
55 # maybe a relative uri.
56 uri = urlparse.urljoin(self._bbs_type.get_uri_base(), uri)
58 strict_uri = self._bbs_type.get_thread_uri()
59 idx = self._thread_view_list.index(widget)
60 if idx != len(self._thread_view_list)-1 and orig_uri == self._thread_view_list[idx+1].get_toplevel().uri:
62 if uri != strict_uri and uri.startswith(strict_uri):
63 resnum = uri[len(strict_uri):]
64 match = re.match("\d+", resnum)
66 resnum = int(match.group())
67 if self._check_to_need_hint(widget, resnum):
68 self._show_hint(widget, resnum, orig_uri)
70 def _get_owner(self, gdk_win):
71 top = gdk_win.get_toplevel()
72 for threadview in self._thread_view_list:
73 if threadview.window.get_toplevel() == top:
78 ret = gtk.gdk.window_at_pointer()
80 # print "unknown window"
81 self._collapse(self._thread_view_list[0])
82 self._timer_started = False
86 threadview = self._get_owner(gdk_win)
87 if threadview is None:
88 # print "unknown gdk window"
89 self._collapse(self._thread_view_list[0])
90 self._timer_started = False
93 length = len(self._thread_view_list)
95 # print "no popup window"
96 self._collapse(threadview)
97 self._timer_started = False
100 if self._is_thread_view_top(threadview):
103 uri, layout, element = threadview.ptrpos_to_uri(x, y)
104 view = self._thread_view_list[self._thread_view_list.index(threadview)+1]
105 if layout is None or uri is None or uri != view.get_toplevel().uri:
106 self._collapse(threadview)
110 def _show_hint(self, threadview, num, uri):
111 top = threadview.get_toplevel()
112 relative_x, relative_y = top.get_pointer()
113 gdk_win_x, gdk_win_y = top.window.get_origin()
114 abs_x = gdk_win_x + relative_x
115 abs_y = gdk_win_y + relative_y
117 popupwin = gtk.Window(gtk.WINDOW_POPUP)
119 view = thread_view.ThreadView()
120 view.connect("uri-clicked-event", self.on_threadview_uri_clicked)
121 self.push_thread_view(view)
124 view.drawingarea.size_allocate(gtk.gdk.Rectangle(0, 0, 300, 200))
126 for layout in self._thread_view_list[0].res_layout_list:
128 if isinstance(layout.element_list[0], thread_view.ElementEmpty):
130 if layout.resnum == num:
131 clone = layout.clone()
132 view.add_layout(clone)
136 popupwin.set_property("border_width", 1)
138 view.drawingarea.size_allocate(
139 gtk.gdk.Rectangle(0, 0, 300, int(min(200, view.adjustment.upper))))
141 popupwin.set_default_size(view.drawingarea.allocation.width,
142 view.drawingarea.allocation.height+2)
145 view.vscrollbar.hide()
147 # show the popup at an appropriate position.
148 width, height = popupwin.get_size()
149 if abs_x + width > gtk.gdk.screen_width():
150 abs_x = abs_x - width
151 if abs_y + height > gtk.gdk.screen_height():
152 abs_y = abs_y - height
153 popupwin.move(abs_x, abs_y)
157 if not self._timer_started:
158 self._timer_started = True
159 gobject.timeout_add(ThreadPopup._INTERVAL, self.on_timeout)
161 def _check_to_need_hint(self, threadview, num):
162 if self._is_thread_view_top(threadview):
165 def on_threadview_uri_clicked(self, widget, uri):
166 self.emit("uri-clicked-event", widget, uri)