PageRenderTime 89ms CodeModel.GetById 19ms app.highlight 65ms RepoModel.GetById 1ms app.codeStats 0ms

/tortoisehg/hgtk/shellconf.py

https://bitbucket.org/tortoisehg/hgtk/
Python | 423 lines | 363 code | 38 blank | 22 comment | 0 complexity | f737a54c8d2ce0916d7d00fc97606973 MD5 | raw file
  1# shellconf.py - User interface for the TortoiseHg shell extension settings
  2#
  3# Copyright 2009 Steve Borho <steve@borho.org>
  4#
  5# This software may be used and distributed according to the terms of the
  6# GNU General Public License version 2, incorporated herein by reference.
  7
  8import os
  9import gtk
 10import gobject
 11
 12from tortoisehg.util.i18n import _
 13from tortoisehg.util import menuthg
 14from tortoisehg.hgtk import gtklib
 15
 16class ShellConfigWindow(gtk.Window):
 17    'User interface for the TortoiseHg taskbar application'
 18    def __init__(self):
 19        'Initialize the Dialog'
 20        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
 21        gtklib.set_tortoise_icon(self, 'hg.ico')
 22        gtklib.set_tortoise_keys(self)
 23
 24        self.set_default_size(400, -1)
 25        self.set_title(_('TortoiseHg Shell Configuration'))
 26
 27        okay = gtk.Button(_('OK'))
 28        cancel = gtk.Button(_('Cancel'))
 29        self.apply = gtk.Button(_('Apply'))
 30
 31        vbox = gtk.VBox()
 32        vbox.set_border_width(5)
 33        self.add(vbox)
 34
 35        # Create a new notebook, place the position of the tabs
 36        self.notebook = notebook = gtk.Notebook()
 37        notebook.set_tab_pos(gtk.POS_TOP)
 38        vbox.pack_start(notebook, True, True)
 39        notebook.show()
 40
 41        # Context Menu page
 42        cmenuframe = self.add_page(notebook, _('Context Menu'))
 43        cmenuvbox = gtk.VBox()
 44        cmenuframe.add(cmenuvbox)
 45
 46        ## Top/Sub Menu items group
 47        cmframe = gtk.Frame(_('Menu Items'))
 48        cmframe.set_border_width(2)
 49        cmenuvbox.pack_start(cmframe, True, True, 2)
 50
 51        table = gtk.Table(2, 3)
 52        cmframe.add(table)
 53        def setcell(child, row, col, xopts=gtk.FILL|gtk.EXPAND, yopts=0):
 54            table.attach(child, col, col + 1, row, row + 1, xopts, yopts, 4, 2)
 55        def withframe(widget):
 56            scroll = gtk.ScrolledWindow()
 57            scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
 58            scroll.set_shadow_type(gtk.SHADOW_ETCHED_IN)
 59            scroll.add(widget)
 60            return scroll
 61
 62        # Sub menus pane
 63        label = gtk.Label(_('Sub menu items:'))
 64        label.set_alignment(0, 0.5)
 65        setcell(label, 0, 2)
 66
 67        # model: [0]hgcmd, [1]translated menu label
 68        self.submmodel = model = gtk.ListStore(gobject.TYPE_STRING,
 69                gobject.TYPE_STRING)
 70        self.submlist = list = gtk.TreeView(model)
 71        list.set_size_request(-1, 180)
 72        list.set_headers_visible(False)
 73        list.connect('row-activated', self.row_activated)
 74        column = gtk.TreeViewColumn()
 75        list.append_column(column)
 76        cell = gtk.CellRendererText()
 77        column.pack_start(cell, True)
 78        column.add_attribute(cell, 'text', 1)
 79        setcell(withframe(list), 1, 2, yopts=gtk.FILL|gtk.EXPAND)
 80
 81        # Top menus pane
 82        label = gtk.Label(_('Top menu items:'))
 83        label.set_alignment(0, 0.5)
 84        setcell(label, 0, 0)
 85
 86        # model: [0]hgcmd, [1]translated menu label
 87        self.topmmodel = model = gtk.ListStore(gobject.TYPE_STRING,
 88                gobject.TYPE_STRING)
 89        self.topmlist = list = gtk.TreeView(model)
 90        list.set_size_request(-1, 180)
 91        list.set_headers_visible(False)
 92        list.connect('row-activated', self.row_activated)
 93        column = gtk.TreeViewColumn()
 94        list.append_column(column)
 95        cell = gtk.CellRendererText()
 96        column.pack_start(cell, True)
 97        column.add_attribute(cell, 'text', 1)
 98        setcell(withframe(list), 1, 0, yopts=gtk.FILL|gtk.EXPAND)
 99
100        # move buttons
101        mbbox = gtk.VBox()
102        setcell(mbbox, 1, 1, xopts=0, yopts=0)
103
104        topbutton = gtk.Button(_('<- Top'))
105        topbutton.connect('clicked', self.top_clicked)
106        mbbox.add(topbutton)
107        subbutton = gtk.Button(_('Sub ->'))
108        subbutton.connect('clicked', self.sub_clicked)
109        mbbox.add(subbutton)
110
111        # menu behavior group
112        mbframe = gtk.Frame(_('Menu Behavior'))
113        mbframe.set_border_width(2)
114        cmenuvbox.pack_start(mbframe, True, True, 2)
115
116        mbbox = gtk.VBox()
117        mbframe.add(mbbox)
118        hbox = gtk.HBox()
119        mbbox.pack_start(hbox, False, False, 2)
120        self.hide_context_menu = gtk.CheckButton(_('Hide context menu outside repositories'))
121        hbox.pack_start(self.hide_context_menu, False, False, 2)
122
123        # Icons page
124        iconsframe = self.add_page(notebook, _('Icons'))
125        iconsvbox = gtk.VBox()
126        iconsframe.add(iconsvbox)
127
128        ## Overlays group
129        ovframe = gtk.Frame(_('Overlays'))
130        ovframe.set_border_width(2)
131        iconsvbox.pack_start(ovframe, False, False, 2)
132        ovcvbox = gtk.VBox()
133        ovframe.add(ovcvbox)
134        hbox = gtk.HBox()
135        ovcvbox.pack_start(hbox, False, False, 2)
136        self.ovenable = gtk.CheckButton(_('Enable overlays'))
137        hbox.pack_start(self.ovenable, False, False, 2)
138        self.lclonly = gtk.CheckButton(_('Local disks only'))
139        hbox.pack_start(self.lclonly, False, False, 2)
140
141        ## Overlay icon handlers group
142        frame = gtk.Frame(_('Enabled Overlay Handlers'))
143        frame.set_border_width(2)
144        iconsvbox.pack_start(frame, False, False, 2)
145        tvbox = gtk.VBox()
146        frame.add(tvbox)
147        
148        hbox = gtk.HBox()
149        tvbox.pack_start(hbox, False, False, 2)
150        hbox.pack_start(gtk.Label(
151            _('Warning: affects all Tortoises, logoff required after change')), 
152            False, False, 2)
153
154        hbox = gtk.HBox()
155        tvbox.pack_start(hbox, False, False, 2)
156
157        colvbox = gtk.VBox()
158        hbox.pack_start(colvbox, False, False, 2)
159        self.enableAddedHandler = gtk.CheckButton(_('Added'))
160        colvbox.pack_start(self.enableAddedHandler, False, False, 2)
161        self.enableUnversionedHandler = gtk.CheckButton(_('Unversioned'))
162        colvbox.pack_start(self.enableUnversionedHandler, False, False, 2)
163
164        colvbox = gtk.VBox()
165        hbox.pack_start(colvbox, False, False, 2)
166        self.enableLockedHandler = gtk.CheckButton(_('Locked*'))
167        colvbox.pack_start(self.enableLockedHandler, False, False, 2)
168        self.enableReadonlyHandler = gtk.CheckButton(_('Readonly*'))
169        colvbox.pack_start(self.enableReadonlyHandler, False, False, 2)
170
171        colvbox = gtk.VBox()
172        hbox.pack_start(colvbox, False, False, 2)
173        self.enableIgnoredHandler = gtk.CheckButton(_('Ignored*'))
174        colvbox.pack_start(self.enableIgnoredHandler, False, False, 2)
175        self.enableDeletedHandler = gtk.CheckButton(_('Deleted*'))
176        colvbox.pack_start(self.enableDeletedHandler, False, False, 2)
177
178        def connect_apply(checkbutton):
179            checkbutton.connect('toggled', lambda x: self.apply.set_sensitive(True))
180        connect_apply(self.hide_context_menu)
181        connect_apply(self.enableAddedHandler)
182        connect_apply(self.enableUnversionedHandler)
183        connect_apply(self.enableIgnoredHandler)
184        connect_apply(self.enableLockedHandler)
185        connect_apply(self.enableReadonlyHandler)
186        connect_apply(self.enableDeletedHandler)
187
188        hbox = gtk.HBox()
189        tvbox.pack_start(hbox, False, False, 2)
190        hbox.pack_start(gtk.Label(
191            _('*: not used by TortoiseHg')), 
192            False, False, 2)
193
194        ## Taskbar group
195        taskbarframe = gtk.Frame(_('Taskbar'))
196        taskbarframe.set_border_width(2)
197        iconsvbox.pack_start(taskbarframe, False, False, 2)
198        taskbarbox = gtk.VBox()
199        taskbarframe.add(taskbarbox)
200        hbox = gtk.HBox()
201        taskbarbox.pack_start(hbox, False, False, 2)
202        self.show_taskbaricon = gtk.CheckButton(_('Show Icon'))
203        hbox.pack_start(self.show_taskbaricon, False, False, 2)
204        self.hgighlight_taskbaricon = gtk.CheckButton(_('Highlight Icon'))
205        hbox.pack_start(self.hgighlight_taskbaricon, False, False, 2)
206
207        # Tooltips
208        tips = gtklib.Tooltips()
209
210        tooltip = _('Do not show menu items on unversioned folders' 
211                    ' (use shift + click to override)')
212        tips.set_tip(self.hide_context_menu, tooltip)
213        tooltip = _('Show overlay icons in Mercurial repositories')
214        tips.set_tip(self.ovenable, tooltip)
215        self.ovenable.connect('toggled', self.ovenable_toggled)
216        tooltip = _('Show overlays on local disks only')
217        tips.set_tip(self.lclonly, tooltip)
218        self.lclonly.connect('toggled', lambda x: self.apply.set_sensitive(True))
219
220        tooltip = _('Show the taskbar icon (restart needed)')
221        tips.set_tip(self.show_taskbaricon, tooltip)
222        self.show_taskbaricon.connect('toggled', lambda x: self.apply.set_sensitive(True))
223        tooltip = _('Highlight the taskbar icon during activity')
224        tips.set_tip(self.hgighlight_taskbaricon, tooltip)
225        self.hgighlight_taskbaricon.connect('toggled', lambda x: self.apply.set_sensitive(True))
226
227        self.load_shell_configs()
228
229        accelgroup = gtk.AccelGroup()
230        self.add_accel_group(accelgroup)
231
232        # Padding
233        vbox.pack_start(gtk.HBox(), False, False, 3)
234
235        # Bottom buttons
236        bbox = gtk.HBox()
237        vbox.pack_start(bbox, False, False)
238
239        lefthbbox = gtk.HButtonBox()
240        lefthbbox.set_layout(gtk.BUTTONBOX_START)
241        lefthbbox.set_spacing(6)
242        bbox.pack_start(lefthbbox, False, False)
243
244        bbox.pack_start(gtk.Label(''), True, True)
245
246        righthbbox = gtk.HButtonBox()
247        righthbbox.set_layout(gtk.BUTTONBOX_END)
248        righthbbox.set_spacing(6)
249        bbox.pack_start(righthbbox, False, False)
250
251        okay.connect('clicked', self.okay_clicked)
252        key, modifier = gtk.accelerator_parse('Return')
253        okay.add_accelerator('clicked', accelgroup, key, 0,
254                gtk.ACCEL_VISIBLE)
255        righthbbox.pack_start(okay, False, False)
256
257        cancel.connect('clicked', lambda x: self.destroy())
258        key, modifier = gtk.accelerator_parse('Escape')
259        cancel.add_accelerator('clicked', accelgroup, key, 0,
260                gtk.ACCEL_VISIBLE)
261        righthbbox.pack_start(cancel, False, False)
262
263        self.apply.connect('clicked', self.apply_clicked)
264        self.apply.set_sensitive(False)
265        righthbbox.pack_start(self.apply, False, False)
266
267    def add_page(self, notebook, tab):
268        frame = gtk.Frame()
269        frame.set_border_width(5)
270        frame.set_shadow_type(gtk.SHADOW_NONE)
271        frame.show()
272        label = gtk.Label(tab)
273        notebook.append_page(frame, label)
274        return frame
275
276    def load_shell_configs(self):
277        hide_context_menu = False
278        overlayenable = True
279        localdisks = False
280        promoteditems = 'commit'
281        show_taskbaricon = True
282        hgighlight_taskbaricon = True
283        enableUnversionedHandler = True
284        enableIgnoredHandler = True
285        enableLockedHandler = True
286        enableReadonlyHandler = True
287        enableDeletedHandler = True
288        enableAddedHandler = True
289        try:
290            from _winreg import HKEY_CURRENT_USER, OpenKey, QueryValueEx
291            hkey = OpenKey(HKEY_CURRENT_USER, r'Software\TortoiseHg')
292            t = ('1', 'True')
293            try: hide_context_menu = QueryValueEx(hkey, 'HideMenuOutsideRepo')[0] in t
294            except EnvironmentError: pass
295            try: overlayenable = QueryValueEx(hkey, 'EnableOverlays')[0] in t
296            except EnvironmentError: pass
297            try: localdisks = QueryValueEx(hkey, 'LocalDisksOnly')[0] in t
298            except EnvironmentError: pass
299            try: show_taskbaricon = QueryValueEx(hkey, 'ShowTaskbarIcon')[0] in t
300            except EnvironmentError: pass
301            try: hgighlight_taskbaricon = QueryValueEx(hkey, 'HighlightTaskbarIcon')[0] in t
302            except EnvironmentError: pass
303            try: promoteditems = QueryValueEx(hkey, 'PromotedItems')[0]
304            except EnvironmentError: pass
305
306            hkey = OpenKey(HKEY_CURRENT_USER, r'Software\TortoiseOverlays')
307            try: enableUnversionedHandler = QueryValueEx(hkey, 'ShowUnversionedOverlay')[0] != 0
308            except EnvironmentError: pass
309            try: enableIgnoredHandler = QueryValueEx(hkey, 'ShowIgnoredOverlay')[0] != 0
310            except EnvironmentError: pass
311            try: enableLockedHandler = QueryValueEx(hkey, 'ShowLockedOverlay')[0] != 0
312            except EnvironmentError: pass
313            try: enableReadonlyHandler = QueryValueEx(hkey, 'ShowReadonlyOverlay')[0] != 0
314            except EnvironmentError: pass
315            try: enableDeletedHandler = QueryValueEx(hkey, 'ShowDeletedOverlay')[0] != 0
316            except EnvironmentError: pass
317            try: enableAddedHandler = QueryValueEx(hkey, 'ShowAddedOverlay')[0] != 0
318            except EnvironmentError: pass
319        except (ImportError, WindowsError):
320            pass
321
322        self.hide_context_menu.set_active(hide_context_menu)
323        self.ovenable.set_active(overlayenable)
324        self.lclonly.set_active(localdisks)
325        self.lclonly.set_sensitive(overlayenable)
326        self.show_taskbaricon.set_active(show_taskbaricon)
327        self.hgighlight_taskbaricon.set_active(hgighlight_taskbaricon)
328        self.enableUnversionedHandler.set_active(enableUnversionedHandler)
329        self.enableIgnoredHandler.set_active(enableIgnoredHandler)
330        self.enableLockedHandler.set_active(enableLockedHandler)
331        self.enableReadonlyHandler.set_active(enableReadonlyHandler)
332        self.enableDeletedHandler.set_active(enableDeletedHandler)
333        self.enableAddedHandler.set_active(enableAddedHandler)
334
335        promoted = [pi.strip() for pi in promoteditems.split(',')]
336        self.submmodel.clear()
337        self.topmmodel.clear()
338        for cmd, info in menuthg.thgcmenu.items():
339            label = info['label']['str']
340            if cmd in promoted:
341                self.topmmodel.append((cmd, label))
342            else:
343                self.submmodel.append((cmd, label))
344        self.submmodel.set_sort_column_id(1, gtk.SORT_ASCENDING)
345        self.topmmodel.set_sort_column_id(1, gtk.SORT_ASCENDING)
346
347    def store_shell_configs(self):
348        hide_context_menu = self.hide_context_menu.get_active() and '1' or '0'
349        overlayenable = self.ovenable.get_active() and '1' or '0'
350        localdisks = self.lclonly.get_active() and '1' or '0'
351        show_taskbaricon = self.show_taskbaricon.get_active() and '1' or '0'
352        hgighlight_taskbaricon = self.hgighlight_taskbaricon.get_active() and '1' or '0'
353        enableUnversionedHandler = self.enableUnversionedHandler.get_active() and 1 or 0
354        enableIgnoredHandler = self.enableIgnoredHandler.get_active() and 1 or 0
355        enableLockedHandler = self.enableLockedHandler.get_active() and 1 or 0
356        enableReadonlyHandler = self.enableReadonlyHandler.get_active() and 1 or 0
357        enableDeletedHandler = self.enableDeletedHandler.get_active() and 1 or 0
358        enableAddedHandler = self.enableAddedHandler.get_active() and 1 or 0
359        promoted = []
360        for row in self.topmmodel:
361            promoted.append(row[0])
362        try:
363            from _winreg import HKEY_CURRENT_USER, CreateKey, SetValueEx, REG_SZ, REG_DWORD
364            hkey = CreateKey(HKEY_CURRENT_USER, r"Software\TortoiseHg")
365            SetValueEx(hkey, 'HideMenuOutsideRepo', 0, REG_SZ, hide_context_menu)
366            SetValueEx(hkey, 'EnableOverlays', 0, REG_SZ, overlayenable)
367            SetValueEx(hkey, 'LocalDisksOnly', 0, REG_SZ, localdisks)
368            SetValueEx(hkey, 'ShowTaskbarIcon', 0, REG_SZ, show_taskbaricon)
369            SetValueEx(hkey, 'HighlightTaskbarIcon', 0, REG_SZ, hgighlight_taskbaricon)
370            SetValueEx(hkey, 'PromotedItems', 0, REG_SZ, ','.join(promoted))
371            hkey = CreateKey(HKEY_CURRENT_USER, r'Software\TortoiseOverlays')
372            SetValueEx(hkey, 'ShowUnversionedOverlay', 0, REG_DWORD, enableUnversionedHandler)
373            SetValueEx(hkey, 'ShowIgnoredOverlay', 0, REG_DWORD, enableIgnoredHandler)
374            SetValueEx(hkey, 'ShowLockedOverlay', 0, REG_DWORD, enableLockedHandler)
375            SetValueEx(hkey, 'ShowReadonlyOverlay', 0, REG_DWORD, enableReadonlyHandler)
376            SetValueEx(hkey, 'ShowDeletedOverlay', 0, REG_DWORD, enableDeletedHandler)
377            SetValueEx(hkey, 'ShowAddedOverlay', 0, REG_DWORD, enableAddedHandler)
378        except ImportError:
379            pass
380
381    def move_to_other(self, list, paths=None):
382        if paths == None:
383            model, paths = list.get_selection().get_selected_rows()
384        else:
385            model = list.get_model()
386        if not paths:
387            return
388        if list == self.submlist:
389            otherlist = self.topmlist
390            othermodel = self.topmmodel
391        else:
392            otherlist = self.submlist
393            othermodel = self.submmodel
394        for path in paths:
395            cmd, label = model[path]
396            model.remove(model.get_iter(path))
397            othermodel.append((cmd, label))
398        othermodel.set_sort_column_id(1, gtk.SORT_ASCENDING)
399        self.apply.set_sensitive(True)
400
401    def row_activated(self, list, path, column):
402        self.move_to_other(list, (path,))
403
404    def sub_clicked(self, button):
405        self.move_to_other(self.topmlist)
406
407    def top_clicked(self, button):
408        self.move_to_other(self.submlist)
409
410    def okay_clicked(self, button):
411        self.store_shell_configs()
412        self.destroy()
413
414    def apply_clicked(self, button):
415        self.store_shell_configs()
416        button.set_sensitive(False)
417
418    def ovenable_toggled(self, check):
419        self.lclonly.set_sensitive(check.get_active())
420        self.apply.set_sensitive(True)
421
422def run(ui, *pats, **opts):
423    return ShellConfigWindow()