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:
|
|||
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!