1from gi.repository import Gtk as gtk 2from gi.repository import Gdk as gdk 3from gi.repository.Gio import Settings as GSettings 4 5from .plugin import PluginView 6from .i18n import _, N_ 7from .accessible_treeview import * 8from . import ui_manager 9from .ui_manager import uimanager 10 11GSCHEMA = 'org.a11y.Accerciser' 12 13class AccerciserMainWindow(gtk.Window): 14 ''' 15 Main window class. 16 17 @ivar statusbar: Main window's status bar. 18 @type statusbar: gtk.Statusbar 19 @ivar treeview: Main accessible tree view. 20 @type treeview: L{AccessibleTreeView} 21 @ivar pluginview1: Top plugin area. 22 @type pluginview1: L{PluginView} 23 @ivar pluginview2: Bottom plugin area 24 @type pluginview2: L{PluginView} 25 @ivar main_actions: Main action group. 26 @type main_actions: gtk.ActionGroup 27 @ivar _vpaned: Vertical paned. 28 @type _vpaned: gtk.VPaned 29 @ivar _hpaned: Horizontal paned. 30 @type _hpaned: gtk.HPaned 31 ''' 32 __gtype_name__ = "AccerciserMainWindow" 33 34 def __init__(self, node): 35 ''' 36 Initialize the window. 37 38 @param node: Main application's node. 39 @type node: L{Node} 40 ''' 41 gtk.Window.__init__(self) 42 self.set_icon_name('accerciser') 43 self.set_title(_('Accerciser Accessibility Explorer')) 44 self.connect('key-press-event', self._onKeyPress) 45 node.connect('blink-done', self._onBlinkDone) 46 self.gsettings = GSettings.new(GSCHEMA) 47 width = self.gsettings.get_int('window-width') or 640 48 height = self.gsettings.get_int('window-height') or 640 49 self.set_default_size(width, height) 50 self.add_accel_group(ui_manager.uimanager.get_accel_group()) 51 # Populate window 52 self._populateUI(node) 53 54 selection = self.treeview.get_selection() 55 selection.connect('changed', self._onSelectionChanged) 56 57 def _populateUI(self, node): 58 ''' 59 Populate the top level window widget. 60 61 @param node: Main application's node. 62 @type node: L{Node} 63 ''' 64 main_vbox = gtk.VBox() 65 menu_bar = ui_manager.uimanager.get_widget(ui_manager.MAIN_MENU_PATH) 66 main_vbox.pack_start(menu_bar, False, True, 0) 67 self._vpaned = gtk.VPaned() 68 self._vpaned.set_position(350) 69 self._vpaned.set_name('vpaned') 70 main_vbox.pack_start(self._vpaned, True, True, 0) 71 self.statusbar = gtk.Statusbar() 72 main_vbox.pack_start(self.statusbar, False, True, 0) 73 self._hpaned = gtk.HPaned() 74 self._hpaned.set_position(250) 75 self._hpaned.set_name('hpaned') 76 self._vpaned.add1(self._hpaned) 77 self.pluginview1 = PluginView(N_('Top panel')) 78 self.pluginview2 = PluginView(N_('Bottom panel')) 79 self.pluginview2.connect('page_added', 80 self._onBottomPanelChange, 'added') 81 self.pluginview2.connect('page_removed', 82 self._onBottomPanelChange, 'removed') 83 self.pluginview2.connect_after('realize', self._onBottomPanelRealize) 84 self._vpaned.add2(self.pluginview2) 85 self._hpaned.add2(self.pluginview1) 86 sw = gtk.ScrolledWindow() 87 sw.set_policy(gtk.PolicyType.AUTOMATIC, gtk.PolicyType.AUTOMATIC) 88 sw.set_shadow_type(gtk.ShadowType.IN) 89 self.treeview = AccessibleTreeView(node) 90 ui_manager.uimanager.insert_action_group(self.treeview.action_group, 0) 91 for action in self.treeview.action_group.list_actions(): 92 merge_id = ui_manager.uimanager.new_merge_id() 93 action_name = action.get_name() 94 ui_manager.uimanager.add_ui(merge_id, ui_manager.TREE_ACTIONS_PATH, 95 action_name, action_name, 96 gtk.UIManagerItemType.MENUITEM, False) 97 98 merge_id = ui_manager.uimanager.new_merge_id() 99 action_name = self.treeview.refresh_current_action.get_name() 100 ui_manager.uimanager.add_ui(merge_id, ui_manager.POPUP_MENU_PATH, 101 action_name, action_name, 102 gtk.UIManagerItemType.MENUITEM, False) 103 104 sw.add(self.treeview) 105 self._hpaned.add1(sw) 106 107 for paned in (self._vpaned, self._hpaned): 108 if not self.gsettings.get_int(paned.get_name()): continue 109 paned_position = self.gsettings.get_int(paned.get_name()) 110 paned.set_position(paned_position) 111 setattr(paned, 'last_position', paned.get_position()) 112 113 self.add(main_vbox) 114 115 def _onBottomPanelChange(self, pluginview, page, page_num, action): 116 ''' 117 Callback for changes to the bottom L{PluginView}'s children. If there are no 118 tabs, shrink the paned. 119 120 @param pluginview: The L{PluginView} that emitted the signal. 121 @type pluginview: L{PluginView} 122 @param page: The child widget affected. 123 @type page: L{gtk.Widget} 124 @param page_num: the new page number for page. 125 @type page_num: integer 126 @param action: The type of event that accured, either "removed" or "added" 127 @type action: string 128 ''' 129 if pluginview.get_n_pages() == 1 and action == 'added': 130 last_pos = getattr(self._vpaned, 'last_position') 131 self._vpaned.set_position(last_pos or 350) 132 elif pluginview.get_n_pages() == 0: 133 setattr(self._vpaned, 'last_position', self._vpaned.get_position()) 134 self._vpaned.set_position(self._vpaned.get_allocated_height() - 30) 135 136 def _onBottomPanelRealize(self, pluginview): 137 if pluginview.get_n_pages() == 0: 138 self._vpaned.set_position(self._vpaned.get_allocated_height() - 30) 139 140 def _onKeyPress(self, widget, event): 141 ''' 142 Callback for a keypress event in the main window. 143 Used for navigating plugin tabs (<alt>+num). 144 145 @param widget: The widget that emitted the event. 146 @type widget: L{gtk.Widget} 147 @param event: The event that accured. 148 @type event: L{gtk.gdk.Event} 149 ''' 150 if event.state & gdk.ModifierType.MOD1_MASK and \ 151 event.keyval in range(gdk.keyval_from_name('0'), 152 gdk.keyval_from_name('9')): 153 tab_num = event.keyval - gdk.keyval_from_name('0') or 10 154 pages_count1 = self.pluginview1.getNVisiblePages() 155 pages_count2 = self.pluginview2.getNVisiblePages() 156 if pages_count1 + pages_count2 < tab_num: 157 return 158 elif pages_count1 >= tab_num: 159 self.pluginview1.focusTab(tab_num - 1) 160 else: 161 self.pluginview2.focusTab(tab_num - pages_count1 - 1) 162 163 def saveState(self): 164 ''' 165 Save the dimensions of the main window, and the position of the panes. 166 ''' 167 self.gsettings.set_int('window-width', self.get_allocated_width()) 168 self.gsettings.set_int('window-height', self.get_allocated_height()) 169 self.gsettings.set_int('hpaned', self._hpaned.get_position()) 170 if self.pluginview2.get_n_pages(): 171 position = self._vpaned.get_position() 172 else: 173 position = getattr(self._vpaned, 'last_position') 174 if position is not None: 175 self.gsettings.set_int('vpaned', position) 176 177 def _onBlinkDone(self, node): 178 ''' 179 Redraw main window after node stops blinking widget. Gets rid of artifacts. 180 181 @param node: 182 @type node: 183 ''' 184 self.queue_draw() 185 186 def _onSelectionChanged(self, selection): 187 ''' 188 Callback for selection "changed" of the main treeview selection. 189 Updates the status bar with the path to the selected accessible. 190 191 @param selection: The main tree view's selection object. 192 @type node: gtk.TreeSelection 193 ''' 194 model, iter = selection.get_selected() 195 context_id = self.statusbar.get_context_id('lineage') 196 if not iter: 197 return 198 tree_path = model.get_path(iter) 199 path_tuple = tuple(tree_path.get_indices()) 200 201 path = list(map(str, path_tuple)) 202 self.statusbar.pop(context_id) 203 if len(path) > 1: 204 self.statusbar.push(context_id, 'Path: '+' '.join(path[1:])) 205