Merge lp:~bratsche/gwibber/input-focus into lp:gwibber
- input-focus
- Merge into trunk
Proposed by
Cody Russell
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~bratsche/gwibber/input-focus |
Merge into: | lp:gwibber |
Diff against target: |
482 lines (+61/-56) 2 files modified
gwibber/client.py (+18/-16) gwibber/gwui.py (+43/-40) |
To merge this branch: | bzr merge lp:~bratsche/gwibber/input-focus |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ken VanDine | Approve | ||
Review via email: mp+21578@code.launchpad.net |
Commit message
Description of the change
Sets the focus children so that the text input widget has the focus.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'gwibber/client.py' |
2 | --- gwibber/client.py 2010-03-17 17:17:13 +0000 |
3 | +++ gwibber/client.py 2010-03-17 17:37:30 +0000 |
4 | @@ -26,7 +26,7 @@ |
5 | self.ui = gtk.Builder() |
6 | |
7 | self.model = gwui.Model() |
8 | - |
9 | + |
10 | self.service = self.model.daemon |
11 | self.service.connect_to_signal("LoadingStarted", self.on_loading_started) |
12 | self.service.connect_to_signal("LoadingComplete", self.on_loading_complete) |
13 | @@ -51,7 +51,7 @@ |
14 | self.service.Refresh() |
15 | |
16 | self.setup_ui() |
17 | - |
18 | + |
19 | # set state online/offline |
20 | if not self.connection.isConnected(): |
21 | log.logger.info("Setting to Offline") |
22 | @@ -74,7 +74,7 @@ |
23 | resources.get_ui_asset("gwibber.svg"), 24, 24)) |
24 | self.set_icon_name("gwibber") |
25 | self.connect("delete-event", self.on_window_close) |
26 | - |
27 | + |
28 | # Load the application menu |
29 | menu_ui = self.setup_menu() |
30 | self.add_accel_group(menu_ui.get_accel_group()) |
31 | @@ -92,7 +92,7 @@ |
32 | |
33 | menubar = menu_ui.get_widget("/menubar_main") |
34 | menubar.append(menu_spin) |
35 | - |
36 | + |
37 | view_class = getattr(gwui, |
38 | "MultiStreamUi" if len(self.model.settings["streams"]) > 1 |
39 | else "SingleStreamUi") |
40 | @@ -104,7 +104,7 @@ |
41 | self.stream_view.connect("stream-closed", self.on_stream_closed) |
42 | if isinstance(self.stream_view, gwui.MultiStreamUi): |
43 | self.stream_view.connect("pane-closed", self.on_pane_closed) |
44 | - |
45 | + |
46 | self.input = gwui.Input() |
47 | self.input.connect("submit", self.on_input_activate) |
48 | self.input.connect("changed", self.on_input_changed) |
49 | @@ -113,6 +113,8 @@ |
50 | self.input_splitter.pack1(self.stream_view, resize=True) |
51 | self.input_splitter.pack2(self.input, resize=False) |
52 | |
53 | + self.input_splitter.set_focus_child(self.input) |
54 | + |
55 | self.button_send = gtk.Button(_("Send")) |
56 | self.button_send.connect("clicked", self.on_button_send_clicked) |
57 | |
58 | @@ -125,7 +127,7 @@ |
59 | content.pack_start(self.input_splitter, True) |
60 | content.pack_start(self.message_target, False) |
61 | content.set_border_width(5) |
62 | - |
63 | + |
64 | layout = gtk.VBox() |
65 | layout.pack_start(menubar, False) |
66 | layout.pack_start(content, True) |
67 | @@ -147,16 +149,16 @@ |
68 | if self.stream_view: |
69 | state = self.stream_view.get_state() |
70 | self.stream_view.destroy() |
71 | - |
72 | + |
73 | self.stream_view = self.view_class(self.model) |
74 | self.stream_view.connect("action", self.on_action) |
75 | self.stream_view.connect("search", self.on_perform_search) |
76 | self.stream_view.connect("stream-changed", self.on_stream_changed) |
77 | self.stream_view.connect("stream-closed", self.on_stream_closed) |
78 | - |
79 | + |
80 | if isinstance(self.stream_view, gwui.MultiStreamUi): |
81 | self.stream_view.connect("pane-closed", self.on_pane_closed) |
82 | - |
83 | + |
84 | self.input_splitter.add1(self.stream_view) |
85 | self.stream_view.show_all() |
86 | if state: self.stream_view.set_state(state) |
87 | @@ -223,7 +225,7 @@ |
88 | ("help_report", None, _("Report A Problem..."), None, None, lambda *a: util.load_url(BUG_URL)), |
89 | ]) |
90 | |
91 | - |
92 | + |
93 | ui = gtk.UIManager() |
94 | ui.insert_action_group(self.actions, pos=0) |
95 | ui.add_ui_from_string(ui_string) |
96 | @@ -243,7 +245,7 @@ |
97 | if "reply" in features: |
98 | if message["sender"].get("nick", 0) and not "thread" in features: |
99 | self.input.set_text("@%s: " % message["sender"]["nick"]) |
100 | - |
101 | + |
102 | self.message_target.set_target(message) |
103 | self.input.textview.grab_focus() |
104 | buf = self.input.textview.get_buffer() |
105 | @@ -254,7 +256,7 @@ |
106 | |
107 | def get_message(self, id): |
108 | return dict(self.model.messages.get_record(id).items()) |
109 | - |
110 | + |
111 | def on_refresh(self, *args): |
112 | self.service.Refresh() |
113 | |
114 | @@ -262,7 +264,7 @@ |
115 | id = self.model.streams.put_record(CouchRecord(data, kind)) |
116 | self.model.refresh() |
117 | self.service.PerformOp('{"id": "%s"}' % id) |
118 | - |
119 | + |
120 | if "operation" in data: |
121 | stream = str(self.model.features[data["operation"]]["stream"]) |
122 | else: stream = "search" |
123 | @@ -348,7 +350,7 @@ |
124 | def on_message_action_menu(self, msg): |
125 | theme = gtk.icon_theme_get_default() |
126 | menu = gtk.Menu() |
127 | - |
128 | + |
129 | for a in actions.MENU_ITEMS: |
130 | if a.include(self, msg): |
131 | image = gtk.image_new_from_icon_name(a.icon, gtk.ICON_SIZE_MENU) |
132 | @@ -399,14 +401,14 @@ |
133 | self.service.Send(json.dumps(data)) |
134 | self.message_target.end() |
135 | else: self.service.SendMessage(text) |
136 | - |
137 | + |
138 | def on_new_stream(self, *args): |
139 | if isinstance(self.stream_view, gwui.MultiStreamUi): |
140 | self.stream_view.new_stream() |
141 | else: |
142 | self.set_view("MultiStreamUi") |
143 | self.stream_view.new_stream() |
144 | - |
145 | + |
146 | def on_loading_started(self, *args): |
147 | self.loading_spinner.set_from_animation( |
148 | gtk.gdk.PixbufAnimation(resources.get_ui_asset("progress.gif"))) |
149 | |
150 | === modified file 'gwibber/gwui.py' |
151 | --- gwibber/gwui.py 2010-03-17 17:17:13 +0000 |
152 | +++ gwibber/gwui.py 2010-03-17 17:37:30 +0000 |
153 | @@ -30,11 +30,11 @@ |
154 | gobject.GObject.__init__(self) |
155 | |
156 | self.daemon = util.getbus("Service") |
157 | - |
158 | + |
159 | self.account_monitor = util.getbus("Accounts") |
160 | self.account_monitor.connect_to_signal("AccountChanged", self.on_stream_changed) |
161 | self.account_monitor.connect_to_signal("AccountDeleted", self.on_stream_changed) |
162 | - |
163 | + |
164 | self.streams_monitor = util.getbus("Streams") |
165 | self.streams_monitor.connect_to_signal("StreamChanged", self.on_stream_changed) |
166 | self.streams_monitor.connect_to_signal("StreamClosed", self.on_stream_changed) |
167 | @@ -69,7 +69,7 @@ |
168 | def find_all(self, **params): |
169 | for stream in self.get_streams(): |
170 | if self.match(stream, params): yield stream |
171 | - |
172 | + |
173 | if "items" in stream: |
174 | for stream in stream["items"]: |
175 | if self.match(stream, params): yield stream |
176 | @@ -130,7 +130,7 @@ |
177 | } |
178 | |
179 | default_streams = self.services[account["protocol"]]["default_streams"] |
180 | - |
181 | + |
182 | if len(default_streams) > 1: |
183 | for feature in default_streams: |
184 | aname = self.features[feature]["stream"] |
185 | @@ -174,7 +174,7 @@ |
186 | "color": util.Color(account["color"]), |
187 | "protocol": account["protocol"], |
188 | }) |
189 | - |
190 | + |
191 | items.append(item) |
192 | |
193 | searches = { |
194 | @@ -192,13 +192,13 @@ |
195 | sId = search["_id"] |
196 | searches["items"].append({ |
197 | "name": search["name"], |
198 | - "account": None, |
199 | + "account": None, |
200 | "view": self.messages.execute_view("transient_time", "messages")[[sId, {}]:[sId, 0]], |
201 | "stream": "search", |
202 | "transient": sId, |
203 | "color": None, |
204 | }) |
205 | - |
206 | + |
207 | items.append(searches) |
208 | return items |
209 | |
210 | @@ -222,7 +222,7 @@ |
211 | |
212 | def on_click_link(self, view, frame, req): |
213 | uri = req.get_uri() |
214 | - |
215 | + |
216 | if uri.startswith("file:///"): return False |
217 | elif uri.startswith("gwibber:"): |
218 | url = urlparse.urlparse(uri) |
219 | @@ -230,7 +230,7 @@ |
220 | query = urlparse.parse_qs(url.query) |
221 | query = dict((x,y[0]) for x,y in query.items()) |
222 | self.emit("action", uri, cmd, query) |
223 | - else: util.load_url(uri) |
224 | + else: util.load_url(uri) |
225 | return True |
226 | |
227 | def render(self, theme, template, **kwargs): |
228 | @@ -245,7 +245,7 @@ |
229 | theme_path = resources.get_theme_path(theme) |
230 | template_path = resources.get_template_path(template, theme) |
231 | lookup_paths = list(resources.get_template_dirs()) + [theme_path] |
232 | - |
233 | + |
234 | template = open(template_path).read() |
235 | template = Template(template, lookup=TemplateLookup(directories=lookup_paths)) |
236 | content = template.render(theme=util.get_theme_colors(), resources=resources, _=_, **kwargs) |
237 | @@ -253,7 +253,7 @@ |
238 | # Avoid navigation redraw crashes |
239 | if isinstance(self, Navigation) and not self.get_property("visible"): |
240 | return content |
241 | - |
242 | + |
243 | self.load_html_string(content, "file://%s/" % os.path.dirname(template_path)) |
244 | return content |
245 | |
246 | @@ -273,7 +273,7 @@ |
247 | self.selected_stream = None |
248 | self.tree_enabled = False |
249 | self.small_icons = False |
250 | - |
251 | + |
252 | def render(self): |
253 | return WebUi.render(self, self.model.settings["theme"], "navigation.mako", |
254 | streams=self.model.get_streams(), |
255 | @@ -334,7 +334,7 @@ |
256 | self.splitter = gtk.HPaned() |
257 | self.splitter.add1(self.navigation_scroll) |
258 | self.splitter.add2(layout) |
259 | - |
260 | + |
261 | self.splitter.set_position(self.model.settings["sidebar_splitter"]) |
262 | self.handle_splitter_position_change(self.model.settings["sidebar_splitter"]) |
263 | self.splitter.connect("notify", self.on_splitter_drag) |
264 | @@ -368,8 +368,8 @@ |
265 | def on_splitter_drag(self, pane, ev): |
266 | if ev.name == 'position': |
267 | pos = pane.get_position() |
268 | - self.handle_splitter_position_change(pos) |
269 | - |
270 | + self.handle_splitter_position_change(pos) |
271 | + |
272 | def on_stream_closed(self, widget, id, kind): |
273 | self.emit("stream-closed", id, kind) |
274 | |
275 | @@ -378,7 +378,7 @@ |
276 | self.emit("stream-changed", stream) |
277 | self.update_search_visibility() |
278 | self.update() |
279 | - |
280 | + |
281 | def update_search_visibility(self): |
282 | stream = self.navigation.selected_stream |
283 | if stream is not None: |
284 | @@ -428,14 +428,14 @@ |
285 | self.scroll.add_with_viewport(self.container) |
286 | |
287 | self.pack_start(self.scroll, True) |
288 | - |
289 | + |
290 | def on_stream_closed(self, widget, id, kind): |
291 | self.emit("stream-closed", id, kind) |
292 | |
293 | def on_pane_closed(self, widget): |
294 | widget.destroy() |
295 | self.emit("pane-closed", len(self.container)) |
296 | - |
297 | + |
298 | def on_search(self, widget, query): |
299 | self.emit("search", query) |
300 | |
301 | @@ -483,7 +483,7 @@ |
302 | # Build the top navigation bar |
303 | close_icon = gtk.image_new_from_stock("gtk-close", gtk.ICON_SIZE_MENU) |
304 | down_arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_NONE) |
305 | - |
306 | + |
307 | btn_arrow = gtk.Button() |
308 | btn_arrow.set_relief(gtk.RELIEF_NONE) |
309 | btn_arrow.add(down_arrow) |
310 | @@ -514,7 +514,7 @@ |
311 | # Build the main message view |
312 | self.message_view = MessageStreamView(self.model) |
313 | self.message_view.connect("action", self.on_action) |
314 | - |
315 | + |
316 | self.message_scroll = gtk.ScrolledWindow() |
317 | self.message_scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) |
318 | self.message_scroll.set_shadow_type(gtk.SHADOW_IN) |
319 | @@ -530,7 +530,7 @@ |
320 | def on_dropdown(self, button): |
321 | w, h = self.arrow.window.get_geometry()[2:4] |
322 | x, y = self.arrow.window.get_origin() |
323 | - |
324 | + |
325 | window = gtk.Window() |
326 | window.move(x, y + h) |
327 | window.set_decorated(False) |
328 | @@ -566,7 +566,7 @@ |
329 | |
330 | is_search = stream["stream"] == "search" and stream["name"] == "Search" |
331 | self.search_box.set_visible(not is_search) |
332 | - |
333 | + |
334 | if stream["account"]: |
335 | fname = resources.get_ui_asset("icons/breakdance/16x16/%s.png" % stream["protocol"]) |
336 | self.icon_protocol.set_from_file(fname) |
337 | @@ -604,10 +604,10 @@ |
338 | self.model = model |
339 | self.model.connect("changed", self.on_account_changed) |
340 | self.accounts = [] |
341 | - |
342 | + |
343 | self.target = None |
344 | self.action = None |
345 | - |
346 | + |
347 | self.targetbar = WebUi() |
348 | self.targetbar.connect("action", self.on_action) |
349 | self.targetbar.set_size_request(0, 24) |
350 | @@ -661,11 +661,11 @@ |
351 | |
352 | def render(self, views): |
353 | accounts = CouchDatabase(COUCH_DB_ACCOUNTS).get_records(COUCH_TYPE_ACCOUNT, True) |
354 | - |
355 | + |
356 | accounts = dict((a.id, a.value) for a in accounts) |
357 | messages = [] |
358 | seen = {} |
359 | - |
360 | + |
361 | for view in views: |
362 | view.options["descending"] = True |
363 | view.options["limit"] = 100 |
364 | @@ -698,8 +698,8 @@ |
365 | else: |
366 | if message["txtid"]: |
367 | seen[message["txtid"]] = n |
368 | - |
369 | - WebUi.render(self, self.model.settings["theme"], "template.mako", |
370 | + |
371 | + WebUi.render(self, self.model.settings["theme"], "template.mako", |
372 | message_store=messages, |
373 | preferences=self.model.settings, |
374 | services=self.model.services, |
375 | @@ -712,14 +712,14 @@ |
376 | |
377 | def __init__(self): |
378 | gtk.HBox.__init__(self, spacing=2) |
379 | - |
380 | + |
381 | self.entry = gtk.Entry() |
382 | self.entry.connect("activate", self.on_search) |
383 | self.entry.connect("changed", self.on_changed) |
384 | |
385 | self.button = gtk.Button("Search") |
386 | self.button.connect("clicked", self.on_search) |
387 | - |
388 | + |
389 | self.pack_start(self.entry, True) |
390 | self.pack_start(self.button, False) |
391 | |
392 | @@ -731,7 +731,7 @@ |
393 | def on_search(self, *args): |
394 | self.emit("search", self.entry.get_text()) |
395 | self.clear() |
396 | - |
397 | + |
398 | def clear(self): |
399 | self.entry.set_text("") |
400 | |
401 | @@ -748,7 +748,7 @@ |
402 | |
403 | def focus(self): |
404 | self.entry.grab_focus() |
405 | - |
406 | + |
407 | class Input(gtk.Frame): |
408 | __gsignals__ = { |
409 | "submit": (gobject.SIGNAL_RUN_LAST | gobject.SIGNAL_ACTION, None, (str, int)), |
410 | @@ -767,6 +767,9 @@ |
411 | scroll.add(self.textview) |
412 | self.add(scroll) |
413 | |
414 | + self.set_focus_child(scroll) |
415 | + scroll.set_focus_child(self.textview) |
416 | + |
417 | def get_text(self): |
418 | return self.textview.get_text() |
419 | |
420 | @@ -780,7 +783,7 @@ |
421 | text = self.textview.get_text() |
422 | chars = self.textview.get_char_count() |
423 | self.emit("changed", text, chars) |
424 | - |
425 | + |
426 | def do_submit_event(self, tv): |
427 | text = tv.get_text() |
428 | chars = tv.get_char_count() |
429 | @@ -798,13 +801,13 @@ |
430 | |
431 | self.overlay_color = util.get_theme_colors()["text"].darker(3).hex |
432 | self.overlay_text = '<span weight="bold" size="xx-large" foreground="%s">%s</span>' |
433 | - |
434 | + |
435 | self.shortener = util.getbus("URLShorten") |
436 | |
437 | self.connection = util.getbus("Connection") |
438 | self.connection.connect_to_signal("ConnectionOnline", self.on_connection_online) |
439 | self.connection.connect_to_signal("ConnectionOffline", self.on_connection_offline) |
440 | - |
441 | + |
442 | self.get_buffer().connect("insert-text", self.on_add_text) |
443 | self.get_buffer().connect("changed", self.on_text_changed) |
444 | self.connect("expose-event", self.expose_view) |
445 | @@ -820,7 +823,7 @@ |
446 | self.set_right_margin(2) |
447 | self.set_pixels_above_lines(2) |
448 | self.set_pixels_below_lines(2) |
449 | - |
450 | + |
451 | self.base_color = util.get_style().base[gtk.STATE_NORMAL] |
452 | self.error_color = gtk.gdk.color_parse("indianred") |
453 | |
454 | @@ -849,7 +852,7 @@ |
455 | buf = self.get_buffer() |
456 | buf.stop_emission("insert-text") |
457 | service = self.model.settings["urlshorter"] or "is.gd" |
458 | - |
459 | + |
460 | def add_shortened(shortened_url): |
461 | "Internal add-shortened-url-to-buffer function: a closure" |
462 | iter_start = buf.get_iter_at_mark(mark_start) |
463 | @@ -860,7 +863,7 @@ |
464 | "Internal shortening-url-died function: a closure" |
465 | iter = buf.get_iter_at_mark(mark) |
466 | buf.insert(iter, text) # shortening failed |
467 | - |
468 | + |
469 | # set a mark at iter, so that the callback knows where to insert |
470 | mark_start = buf.create_mark(None, iter, True) |
471 | # insert a placeholder character |
472 | @@ -870,9 +873,9 @@ |
473 | iter_end = buf.get_iter_at_mark(buf.get_insert()) |
474 | mark_end = buf.create_mark(None, iter_end, True) |
475 | self.shortener.Shorten(text, service, |
476 | - reply_handler=add_shortened, |
477 | + reply_handler=add_shortened, |
478 | error_handler=error_shortened) |
479 | - |
480 | + |
481 | def set_overlay_text(self, text): |
482 | self.pango_overlay.set_markup(self.overlay_text % (self.overlay_color, text)) |
483 |
Awesome, thanks!