4 from doc_popup
import DocPopup
6 # Space between the line of text where the cursor is and the popup
13 class CompletionPopup(gtk
.Window
):
15 """Class implementing a completion popup for ShellView
17 This class encapsulates the user interface logic for completion
18 popups. The actual code to determine possible completions lives in
19 tokenized_statement.py.
24 'expose-event': 'override',
27 def __init__(self
, view
):
28 gtk
.Window
.__init
__(self
, gtk
.WINDOW_POPUP
)
30 self
.set_border_width(1)
32 sw
= gtk
.ScrolledWindow()
35 sw
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_AUTOMATIC
)
37 self
.__tree
_model
= gtk
.ListStore(str, str, object)
38 self
.__tree
= gtk
.TreeView(self
.__tree
_model
)
39 self
.__tree
.set_headers_visible(False)
41 self
.__tree
.get_selection().connect('changed', self
.__on
_selection
_changed
)
43 cell
= gtk
.CellRendererText()
44 column
= gtk
.TreeViewColumn(None, cell
, text
=0)
45 self
.__tree
.append_column(column
)
50 self
.set_default_size(WIDTH
, HEIGHT
)
52 # A small amount of background shows between the scrollbar and the list;
53 # which looks ugly if it is the only gray thing in the window, so change
54 # the window background to white
55 self
.modify_bg(gtk
.STATE_NORMAL
, gtk
.gdk
.Color(65535, 65535, 65535))
57 self
.__doc
_popup
= DocPopup()
59 self
._in
_change
= False
62 def do_expose_event(self
, event
):
63 gtk
.Window
.do_expose_event(self
, event
)
65 # Draw a black rectangle around the popup
66 cr
= event
.window
.cairo_create()
68 cr
.set_source_rgb(0., 0., 0.)
69 cr
.rectangle(0.5, 0.5, self
.allocation
.width
- 1, self
.allocation
.height
- 1)
74 def __update_completions(self
):
75 buf
= self
.__view
.get_buffer()
77 self
.__in
_change
= True
78 self
.__tree
_model
.clear()
79 for display
, completion
, obj
in buf
.find_completions():
80 self
.__tree
_model
.append([display
, completion
, obj
])
82 self
.__tree
.set_cursor(0)
83 self
.__in
_change
= False
84 self
.__update
_doc
_popup
()
86 def __update_position(self
):
87 buf
= self
.__view
.get_buffer()
89 insert
= buf
.get_iter_at_mark(buf
.get_insert())
91 cursor_rect
= self
.__view
.get_iter_location(insert
)
92 cursor_rect
.x
, cursor_rect
.y
= self
.__view
.buffer_to_window_coords(gtk
.TEXT_WINDOW_TEXT
, cursor_rect
.x
, cursor_rect
.y
)
94 window
= self
.__view
.get_window(gtk
.TEXT_WINDOW_LEFT
)
95 window_x
, window_y
= window
.get_origin()
96 cursor_rect
.x
+= window_x
97 cursor_rect
.y
+= window_y
100 y
= cursor_rect
.y
+ cursor_rect
.height
+ VERTICAL_GAP
102 # If the popup would go off the screen, pop it up above instead; should we
103 # reverse the direction of the items here, as for a menu? I think that would
104 # be more confusing than not doing so.
105 if y
+ HEIGHT
> window
.get_screen().get_height():
106 y
= cursor_rect
.y
- VERTICAL_GAP
- HEIGHT
109 old_x
, old_y
= self
.window
.get_position()
110 if y
== old_y
or x
>= old_x
:
114 def __update_doc_popup(self
):
116 self
.__doc
_popup
.popdown()
119 model
, iter = self
.__tree
.get_selection().get_selected()
121 self
.__doc
_popup
.popdown()
124 obj
= model
.get_value(iter, 2)
126 # Long term it would be nice to preview the value of the
127 # object, but it's distracting to show the class docs on int
128 # for every integer constant, etc, which is what the DocPopup
131 not (inspect
.ismodule(obj
) or
132 inspect
.isclass(obj
) or
133 inspect
.isroutine(obj
) or
134 inspect
.isgetsetdescriptor(obj
) or
135 inspect
.ismemberdescriptor(obj
) or
136 isinstance(obj
, property))):
137 self
.__doc
_popup
.popdown()
140 self
.__doc
_popup
.set_target(obj
)
141 self
.__doc
_popup
.popup()
143 def __insert_selected(self
):
144 model
, iter = self
.__tree
.get_selection().get_selected()
145 completion
= model
.get_value(iter, 1)
147 self
.__view
.get_buffer().insert_interactive_at_cursor(completion
, True)
149 def __on_selection_changed(self
, selection
):
150 if not self
.__in
_change
:
151 self
.__update
_doc
_popup
()
154 """Pop up the completion popup.
156 If there are no possibilities completion at the insert cursor
157 location, the popup is not popped up. If there is exactly one
158 possibility, then completion is done immediately to that one
166 self
.__update
_completions
()
167 if len(self
.__tree
_model
) < 2:
168 if len(self
.__tree
_model
) == 0:
170 self
.__insert
_selected
()
173 self
.__update
_position
()
178 self
.__doc
_popup
.position_next_to_window(self
)
179 self
.__update
_doc
_popup
()
181 # Send a synthetic focus in so that the TreeView thinks it is
183 focus_in
= gtk
.gdk
.Event(gtk
.gdk
.FOCUS_CHANGE
)
184 focus_in
.window
= self
.window
189 """Update the completion popup after the cursor is moved, or text is inserted.
191 If there are no completion possibilities at the cursor when this is called,
192 the popup is popped down.
199 self
.__update
_completions
()
200 if len(self
.__tree
_model
) == 0:
204 self
.__update
_position
()
207 """Hide the completion if it is currently showing"""
214 if self
.__doc
_popup
.showing
:
215 self
.__doc
_popup
.popdown()
219 def on_key_press_event(self
, event
):
220 """Do key press handling while the popup is active.
222 Returns True if the key press is handled, False otherwise.
226 if event
.keyval
== gtk
.keysyms
.Escape
:
229 elif event
.keyval
in (gtk
.keysyms
.KP_Enter
, gtk
.keysyms
.Return
):
230 self
.__insert
_selected
()
233 # These keys are forwarded to the popup to move the selected row
234 elif event
.keyval
in (gtk
.keysyms
.Up
, gtk
.keysyms
.KP_Up
,
235 gtk
.keysyms
.Down
, gtk
.keysyms
.KP_Down
,
236 gtk
.keysyms
.Page_Up
, gtk
.keysyms
.KP_Page_Up
,
237 gtk
.keysyms
.Page_Down
, gtk
.keysyms
.KP_Page_Down
):