From patchwork Mon Jul 30 11:56:41 2012
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: [v3,Log] Port to Gtk3 SL #3761
Date: Mon, 30 Jul 2012 16:56:41 -0000
From: Manuel Kaufmann <humitos@gmail.com>
X-Patchwork-Id: 1604
Message-Id: <1343649401-24353-1-git-send-email-humitos@gmail.com>
To: gonzalo@laptop.org
Cc: Manuel Kaufmann <humitos@gmail.com>, sugar-devel@lists.sugarlabs.org
Convert all the gtk2 and sugar-toolkit code to launch this Activity
using Gtk3. All these steps are documented here:
* http://wiki.sugarlabs.org/go/Features/GTK3/Porting/Log
Signed-off-by: Manuel Kaufmann <humitos@gmail.com>
---
logviewer.py | 168 ++++++++++++++++++++++++++++++++---------------------------
setup.py | 2 +-
2 files changed, 91 insertions(+), 79 deletions(-)
diff --git a/logviewer.py b/logviewer.py
index 71ab5c1..e87ef77 100644
a
|
b
|
from gettext import gettext as _ |
22 | 22 | |
23 | 23 | import re |
24 | 24 | |
25 | | import gtk |
26 | | import pango |
27 | | import gobject |
28 | | import gio |
29 | | |
30 | | from sugar.activity import activity |
31 | | from sugar.activity.widgets import ActivityToolbarButton |
32 | | from sugar import env |
33 | | from sugar.graphics import iconentry |
34 | | from sugar.graphics.toolbutton import ToolButton |
35 | | from sugar.graphics.toggletoolbutton import ToggleToolButton |
36 | | from sugar.graphics.palette import Palette |
37 | | from sugar.graphics.alert import NotifyAlert |
| 25 | from gi.repository import Gtk |
| 26 | from gi.repository import Gdk |
| 27 | from gi.repository import Pango |
| 28 | from gi.repository import GObject |
| 29 | from gi.repository import Gio |
| 30 | |
| 31 | from sugar3.activity import activity |
| 32 | from sugar3.activity.widgets import ActivityToolbarButton |
| 33 | from sugar3 import env |
| 34 | from sugar3.graphics import iconentry |
| 35 | from sugar3.graphics.toolbutton import ToolButton |
| 36 | from sugar3.graphics.toggletoolbutton import ToggleToolButton |
| 37 | from sugar3.graphics.palette import Palette |
| 38 | from sugar3.graphics.alert import NotifyAlert |
38 | 39 | from logcollect import LogCollect |
39 | | from sugar.graphics.toolbarbox import ToolbarBox |
40 | | from sugar.activity.widgets import CopyButton, StopButton |
41 | | from sugar.datastore import datastore |
| 40 | from sugar3.graphics.toolbarbox import ToolbarBox |
| 41 | from sugar3.activity.widgets import CopyButton, StopButton |
| 42 | from sugar3.datastore import datastore |
42 | 43 | |
43 | 44 | |
44 | 45 | _AUTOSEARCH_TIMEOUT = 1000 |
… |
… |
def _notify_response_cb(notify, response, activity): |
49 | 50 | activity.remove_alert(notify) |
50 | 51 | |
51 | 52 | |
52 | | class MultiLogView(gtk.HPaned): |
| 53 | class MultiLogView(Gtk.HPaned): |
53 | 54 | |
54 | 55 | def __init__(self, paths, extra_files): |
55 | | gtk.HPaned.__init__(self) |
| 56 | GObject.GObject.__init__(self) |
56 | 57 | |
57 | 58 | self.paths = paths |
58 | 59 | self.extra_files = extra_files |
… |
… |
class MultiLogView(gtk.HPaned): |
73 | 74 | self._find_logs() |
74 | 75 | |
75 | 76 | def _build_treeview(self): |
76 | | self._treeview = gtk.TreeView() |
| 77 | self._treeview = Gtk.TreeView() |
77 | 78 | |
78 | 79 | self._treeview.set_rules_hint(True) |
79 | 80 | self._treeview.connect('cursor-changed', self._cursor_changed_cb) |
80 | 81 | |
81 | | self._treemodel = gtk.TreeStore(gobject.TYPE_STRING) |
| 82 | self._treemodel = Gtk.TreeStore(GObject.TYPE_STRING) |
82 | 83 | |
83 | | sorted = gtk.TreeModelSort(self._treemodel) |
84 | | sorted.set_sort_column_id(0, gtk.SORT_ASCENDING) |
| 84 | # README: https://bugzilla.gnome.org/show_bug.cgi?id=680009 |
| 85 | sorted = self._treemodel.sort_new_with_model() |
| 86 | sorted.set_sort_column_id(0, Gtk.SortType.ASCENDING) |
85 | 87 | sorted.set_sort_func(0, self._sort_logfile) |
86 | 88 | self._treeview.set_model(sorted) |
87 | 89 | |
88 | | renderer = gtk.CellRendererText() |
89 | | col = gtk.TreeViewColumn(_('Log Files'), renderer, text=0) |
| 90 | renderer = Gtk.CellRendererText() |
| 91 | col = Gtk.TreeViewColumn(_('Log Files'), renderer, text=0) |
90 | 92 | self._treeview.append_column(col) |
91 | 93 | |
92 | 94 | self.path_iter = {} |
… |
… |
class MultiLogView(gtk.HPaned): |
96 | 98 | if len(self.extra_files): |
97 | 99 | self.extra_iter = self._treemodel.append(None, [_('Other')]) |
98 | 100 | |
99 | | scroll = gtk.ScrolledWindow() |
100 | | scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) |
| 101 | scroll = Gtk.ScrolledWindow() |
| 102 | scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) |
101 | 103 | scroll.add(self._treeview) |
102 | | scroll.set_size_request(gtk.gdk.screen_width() * 30 / 100, -1) |
| 104 | scroll.set_size_request(Gdk.Screen.width() * 30 / 100, -1) |
103 | 105 | |
104 | 106 | self.add1(scroll) |
105 | 107 | |
106 | 108 | def _build_textview(self): |
107 | | self._textview = gtk.TextView() |
108 | | self._textview.set_wrap_mode(gtk.WRAP_NONE) |
| 109 | self._textview = Gtk.TextView() |
| 110 | self._textview.set_wrap_mode(Gtk.WrapMode.NONE) |
109 | 111 | |
110 | | pangoFont = pango.FontDescription('Mono') |
| 112 | pangoFont = Pango.FontDescription('Mono') |
111 | 113 | self._textview.modify_font(pangoFont) |
112 | 114 | |
113 | | bgcolor = gtk.gdk.color_parse('#FFFFFF') |
114 | | self._textview.modify_base(gtk.STATE_NORMAL, bgcolor) |
| 115 | bgcolor = Gdk.color_parse('#FFFFFF') |
| 116 | self._textview.modify_base(Gtk.StateType.NORMAL, bgcolor) |
115 | 117 | |
116 | 118 | self._textview.set_editable(False) |
117 | 119 | |
118 | | self._tagtable = gtk.TextTagTable() |
119 | | hilite_tag = gtk.TextTag('search-hilite') |
120 | | hilite_tag.props.background = '#FFFFB0' |
121 | | self._tagtable.add(hilite_tag) |
122 | | select_tag = gtk.TextTag('search-select') |
123 | | select_tag.props.background = '#B0B0FF' |
124 | | self._tagtable.add(select_tag) |
125 | | |
126 | | scroll = gtk.ScrolledWindow() |
127 | | scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) |
| 120 | scroll = Gtk.ScrolledWindow() |
| 121 | scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) |
128 | 122 | scroll.add(self._textview) |
129 | 123 | |
130 | 124 | self.add2(scroll) |
131 | 125 | |
132 | | def _sort_logfile(self, treemodel, itera, iterb): |
| 126 | def _sort_logfile(self, treemodel, itera, iterb, user_data=None): |
133 | 127 | a = treemodel.get_value(itera, 0) |
134 | 128 | b = treemodel.get_value(iterb, 0) |
135 | 129 | if a == None or b == None: |
… |
… |
class MultiLogView(gtk.HPaned): |
162 | 156 | def _configure_watcher(self): |
163 | 157 | # Setting where GIO will be watching |
164 | 158 | for p in self.paths: |
165 | | monitor = gio.File(p).monitor_directory() |
| 159 | monitor = Gio.File.new_for_path(p)\ |
| 160 | .monitor_directory(Gio.FileMonitorFlags.NONE, None) |
166 | 161 | monitor.connect('changed', self._log_file_changed_cb) |
167 | 162 | self._gio_monitors.append(monitor) |
168 | 163 | |
169 | 164 | for f in self.extra_files: |
170 | | monitor = gio.File(f).monitor_file() |
| 165 | monitor = Gio.File.new_for_path(f)\ |
| 166 | .monitor_file(Gio.FileMonitorFlags.NONE, None) |
171 | 167 | monitor.connect('changed', self._log_file_changed_cb) |
172 | 168 | self._gio_monitors.append(monitor) |
173 | 169 | |
174 | 170 | def _log_file_changed_cb(self, monitor, log_file, other_file, event): |
175 | 171 | logfile = log_file.get_basename() |
176 | 172 | |
177 | | if event == gio.FILE_MONITOR_EVENT_CHANGED: |
| 173 | if event == Gio.FileMonitorEvent.CHANGED: |
178 | 174 | if logfile in self.logs: |
179 | 175 | self.logs[logfile].update() |
180 | | elif event == gio.FILE_MONITOR_EVENT_DELETED: |
| 176 | elif event == Gio.FileMonitorEvent.DELETED: |
181 | 177 | if logfile in self.logs: |
182 | 178 | self._remove_log_file(logfile) |
183 | | elif event == gio.FILE_MONITOR_EVENT_CREATED: |
| 179 | elif event == Gio.FileMonitorEvent.CREATED: |
184 | 180 | self._add_log_file(log_file.get_path()) |
185 | 181 | |
186 | 182 | def _cursor_changed_cb(self, treeview): |
187 | | treestore, text_iter = self._treeview.get_selection().get_selected() |
188 | | self._show_log(treestore.get_value(text_iter, 0)) |
| 183 | selection = self._treeview.get_selection() |
| 184 | if selection is not None: |
| 185 | treestore, text_iter = selection.get_selected() |
| 186 | self._show_log(treestore.get_value(text_iter, 0)) |
189 | 187 | |
190 | 188 | def _show_log(self, logfile): |
191 | 189 | if logfile in self.logs: |
192 | 190 | log = self.logs[logfile] |
193 | 191 | self._textview.set_buffer(log) |
194 | | self._textview.scroll_to_mark(log.get_insert(), 0) |
| 192 | self._textview.scroll_to_mark( |
| 193 | log.get_insert(), 0, use_align=False, xalign=0.5, yalign=0.5) |
195 | 194 | self.active_log = log |
196 | 195 | |
197 | 196 | def _find_logs(self): |
… |
… |
class MultiLogView(gtk.HPaned): |
233 | 232 | parent = self.path_iter[directory] |
234 | 233 | tree_iter = self._treemodel.append(parent, [logfile]) |
235 | 234 | |
236 | | model = LogBuffer(self._tagtable, path, tree_iter) |
| 235 | model = LogBuffer(path, tree_iter) |
237 | 236 | self.logs[logfile] = model |
238 | 237 | |
239 | 238 | log = self.logs[logfile] |
… |
… |
class MultiLogView(gtk.HPaned): |
243 | 242 | if self.active_log == None: |
244 | 243 | self.active_log = log |
245 | 244 | self._show_log(logfile) |
246 | | log_iter = \ |
247 | | self._treeview.get_model().convert_child_iter_to_iter(None, |
248 | | log.iter) |
| 245 | success, log_iter = \ |
| 246 | self._treeview.get_model().convert_child_iter_to_iter(log.iter) |
249 | 247 | self._treeview.get_selection().select_iter(log_iter) |
250 | 248 | |
251 | 249 | if written > 0 and self.active_log == log: |
252 | | self._textview.scroll_to_mark(log.get_insert(), 0) |
| 250 | self._textview.scroll_to_mark( |
| 251 | log.get_insert(), 0, use_align=False, xalign=0.5, yalign=0.5) |
253 | 252 | |
254 | 253 | def _remove_log_file(self, logfile): |
255 | 254 | log = self.logs[logfile] |
… |
… |
class MultiLogView(gtk.HPaned): |
268 | 267 | _buffer.remove_tag_by_name('search-select', start, end) |
269 | 268 | |
270 | 269 | text_iter = _buffer.get_start_iter() |
| 270 | |
271 | 271 | while True: |
272 | | next_found = text_iter.forward_search(text, 0) |
| 272 | next_found = text_iter.forward_search(text, 0, None) |
273 | 273 | if next_found is None: |
274 | 274 | break |
275 | 275 | start, end = next_found |
… |
… |
class MultiLogView(gtk.HPaned): |
291 | 291 | text_iter = _buffer.get_iter_at_mark(_buffer.get_insert()) |
292 | 292 | |
293 | 293 | if direction == 'backward': |
294 | | return text_iter.backward_search(self.search_text, 0) |
| 294 | return text_iter.backward_search(self.search_text, 0, None) |
295 | 295 | else: |
296 | | return text_iter.forward_search(self.search_text, 0) |
| 296 | return text_iter.forward_search(self.search_text, 0, None) |
297 | 297 | |
298 | 298 | def search_next(self, direction): |
299 | 299 | next_found = self.get_next_result(direction) |
… |
… |
class MultiLogView(gtk.HPaned): |
308 | 308 | |
309 | 309 | _buffer.place_cursor(start) |
310 | 310 | |
311 | | self._textview.scroll_to_iter(start, 0.1) |
312 | | self._textview.scroll_to_iter(end, 0.1) |
| 311 | self._textview.scroll_to_iter(start, 0.1, use_align=False, |
| 312 | xalign=0.5, yalign=0.5) |
| 313 | self._textview.scroll_to_iter(end, 0.1, use_align=False, |
| 314 | xalign=0.5, yalign=0.5) |
313 | 315 | |
314 | 316 | |
315 | | class LogBuffer(gtk.TextBuffer): |
| 317 | class LogBuffer(Gtk.TextBuffer): |
316 | 318 | |
317 | | def __init__(self, tagtable, logfile, iterator): |
318 | | gtk.TextBuffer.__init__(self, tagtable) |
| 319 | def __init__(self, logfile, iterator): |
| 320 | GObject.GObject.__init__(self) |
| 321 | |
| 322 | _tagtable = self.get_tag_table() |
| 323 | hilite_tag = Gtk.TextTag.new('search-hilite') |
| 324 | hilite_tag.props.background = '#FFFFB0' |
| 325 | _tagtable.add(hilite_tag) |
| 326 | select_tag = Gtk.TextTag.new('search-select') |
| 327 | select_tag.props.background = '#B0B0FF' |
| 328 | _tagtable.add(select_tag) |
319 | 329 | |
320 | 330 | self.logfile = logfile |
321 | 331 | self._pos = 0 |
… |
… |
class LogActivity(activity.Activity): |
367 | 377 | |
368 | 378 | self._build_toolbox() |
369 | 379 | |
| 380 | # Get Sugar's clipboard |
| 381 | self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) |
370 | 382 | self.show() |
371 | 383 | |
372 | 384 | def _build_toolbox(self): |
… |
… |
class LogActivity(activity.Activity): |
389 | 401 | toolbar_box.toolbar.insert(wrap_btn, -1) |
390 | 402 | |
391 | 403 | self.search_entry = iconentry.IconEntry() |
392 | | self.search_entry.set_size_request(gtk.gdk.screen_width() / 3, -1) |
| 404 | self.search_entry.set_size_request(Gdk.Screen.width() / 3, -1) |
393 | 405 | self.search_entry.set_icon_from_name( |
394 | 406 | iconentry.ICON_ENTRY_PRIMARY, 'system-search') |
395 | 407 | self.search_entry.add_clear_button() |
396 | 408 | self.search_entry.connect('activate', self._search_entry_activate_cb) |
397 | 409 | self.search_entry.connect('changed', self._search_entry_changed_cb) |
398 | | search_item = gtk.ToolItem() |
| 410 | search_item = Gtk.ToolItem() |
399 | 411 | search_item.add(self.search_entry) |
400 | 412 | toolbar_box.toolbar.insert(search_item, -1) |
401 | 413 | |
… |
… |
class LogActivity(activity.Activity): |
423 | 435 | delete_btn.connect('clicked', self._delete_log_cb) |
424 | 436 | toolbar_box.toolbar.insert(delete_btn, -1) |
425 | 437 | |
426 | | separator = gtk.SeparatorToolItem() |
| 438 | separator = Gtk.SeparatorToolItem() |
427 | 439 | separator.set_expand(True) |
428 | 440 | separator.set_draw(False) |
429 | 441 | toolbar_box.toolbar.insert(separator, -1) |
… |
… |
class LogActivity(activity.Activity): |
435 | 447 | |
436 | 448 | def __copy_clicked_cb(self, button): |
437 | 449 | if self.viewer.active_log: |
438 | | self.viewer.active_log.copy_clipboard(gtk.clipboard_get()) |
| 450 | self.viewer.active_log.copy_clipboard(self.clipboard) |
439 | 451 | |
440 | 452 | def _wrap_cb(self, button): |
441 | 453 | if button.get_active(): |
442 | | self.viewer._textview.set_wrap_mode(gtk.WRAP_WORD_CHAR) |
| 454 | self.viewer._textview.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) |
443 | 455 | else: |
444 | | self.viewer._textview.set_wrap_mode(gtk.WRAP_NONE) |
| 456 | self.viewer._textview.set_wrap_mode(Gtk.WrapMode.NONE) |
445 | 457 | |
446 | 458 | def _search_entry_activate_cb(self, entry): |
447 | 459 | if self._autosearch_timer: |
448 | | gobject.source_remove(self._autosearch_timer) |
| 460 | GObject.source_remove(self._autosearch_timer) |
449 | 461 | self.viewer.set_search_text(entry.props.text) |
450 | 462 | self._update_search_buttons() |
451 | 463 | |
452 | 464 | def _search_entry_changed_cb(self, entry): |
453 | 465 | if self._autosearch_timer: |
454 | | gobject.source_remove(self._autosearch_timer) |
455 | | self._autosearch_timer = gobject.timeout_add(_AUTOSEARCH_TIMEOUT, |
| 466 | GObject.source_remove(self._autosearch_timer) |
| 467 | self._autosearch_timer = GObject.timeout_add(_AUTOSEARCH_TIMEOUT, |
456 | 468 | self.__autosearch_timer_cb) |
457 | 469 | |
458 | 470 | def __autosearch_timer_cb(self): |
… |
… |
class CollectorPalette(Palette): |
503 | 515 | |
504 | 516 | self._collector = LogCollect() |
505 | 517 | |
506 | | label = gtk.Label( |
| 518 | label = Gtk.Label(label= |
507 | 519 | _('This captures information about the system\n'\ |
508 | 520 | 'and running processes to a journal entry.\n'\ |
509 | 521 | 'Use this to improve a problem report.')) |
510 | 522 | |
511 | | send_button = gtk.Button(_('Capture information')) |
| 523 | send_button = Gtk.Button(_('Capture information')) |
512 | 524 | send_button.connect('clicked', self._on_send_button_clicked_cb) |
513 | 525 | |
514 | | vbox = gtk.VBox(False, 5) |
515 | | vbox.pack_start(label) |
516 | | vbox.pack_start(send_button) |
| 526 | vbox = Gtk.VBox(False, 5) |
| 527 | vbox.pack_start(label, True, True, 0) |
| 528 | vbox.pack_start(send_button, True, True, 0) |
517 | 529 | vbox.show_all() |
518 | 530 | |
519 | 531 | self.set_content(vbox) |
diff --git a/setup.py b/setup.py
index 876cd3f..95390a3 100755
a
|
b
|
|
16 | 16 | # along with this program; if not, write to the Free Software |
17 | 17 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
18 | 18 | |
19 | | from sugar.activity import bundlebuilder |
| 19 | from sugar3.activity import bundlebuilder |
20 | 20 | |
21 | 21 | bundlebuilder.start() |
22 | 22 | |