/tortoisehg/hgtk/shellconf.py

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