/tortoisehg/hgqt/shellconf.py

https://bitbucket.org/tortoisehg/hgtk/ · Python · 302 lines · 235 code · 50 blank · 17 comment · 19 complexity · 434d28fb3557f82f31c07d0054cbb494 MD5 · raw file

  1. # shellconf.py - User interface for the TortoiseHg shell extension settings
  2. #
  3. # Copyright 2009 Steve Borho <steve@borho.org>
  4. # Copyright 2010 Adrian Buehlmann <adrian@cadifra.com>
  5. #
  6. # This software may be used and distributed according to the terms of the
  7. # GNU General Public License version 2 or any later version.
  8. import sys
  9. from tortoisehg.hgqt.i18n import _
  10. from tortoisehg.util import menuthg, hglib
  11. from PyQt4.QtCore import *
  12. from PyQt4.QtGui import *
  13. from _winreg import (HKEY_CURRENT_USER, REG_SZ, REG_DWORD,
  14. OpenKey, CreateKey, QueryValueEx, SetValueEx)
  15. THGKEY = 'TortoiseHg'
  16. OVLKEY = 'TortoiseOverlays'
  17. PROMOTEDITEMS = 'PromotedItems'
  18. # reading functions
  19. def is_true(x): return x in ('1', 'True')
  20. def nonzero(x): return x != 0
  21. # writing functions
  22. def one_str(x):
  23. if x: return '1'
  24. return '0'
  25. def one_int(x):
  26. if x: return 1
  27. return 0
  28. def noop(x): return x
  29. vars = {
  30. # name:
  31. # default, regkey, regtype, evalfunc, wrfunc, checkbuttonattribute
  32. 'EnableOverlays':
  33. [True, THGKEY, REG_SZ, is_true, one_str, 'ovenable'],
  34. 'LocalDisksOnly':
  35. [False, THGKEY, REG_SZ, is_true, one_str, 'localonly'],
  36. 'ShowTaskbarIcon':
  37. [True, THGKEY, REG_SZ, is_true, one_str, 'show_taskbaricon'],
  38. 'HighlightTaskbarIcon':
  39. [True, THGKEY, REG_SZ, is_true, one_str, 'highlight_taskbaricon'],
  40. 'HideMenuOutsideRepo':
  41. [False, THGKEY, REG_SZ, is_true, one_str, 'hidecmenu'],
  42. PROMOTEDITEMS:
  43. ['commit', THGKEY, REG_SZ, noop, noop, None],
  44. 'ShowUnversionedOverlay':
  45. [True, OVLKEY, REG_DWORD, nonzero, one_int, 'enableUnversionedHandler'],
  46. 'ShowIgnoredOverlay':
  47. [True, OVLKEY, REG_DWORD, nonzero, one_int, 'enableIgnoredHandler'],
  48. 'ShowLockedOverlay':
  49. [True, OVLKEY, REG_DWORD, nonzero, one_int, 'enableLockedHandler'],
  50. 'ShowReadonlyOverlay':
  51. [True, OVLKEY, REG_DWORD, nonzero, one_int, 'enableReadonlyHandler'],
  52. 'ShowDeletedOverlay':
  53. [True, OVLKEY, REG_DWORD, nonzero, one_int, 'enableDeletedHandler'],
  54. 'ShowAddedOverlay':
  55. [True, OVLKEY, REG_DWORD, nonzero, one_int, 'enableAddedHandler']
  56. }
  57. class ShellConfigWindow(QDialog):
  58. def __init__(self, parent=None):
  59. super(ShellConfigWindow, self).__init__(parent)
  60. self.menu_cmds = {}
  61. self.dirty = False
  62. layout = QVBoxLayout()
  63. tw = QTabWidget()
  64. layout.addWidget(tw)
  65. # cmenu tab
  66. cmenuwidget = QWidget()
  67. grid = QGridLayout()
  68. cmenuwidget.setLayout(grid)
  69. tw.addTab(cmenuwidget, _("Contex Menu"))
  70. w = QLabel(_("Top menu items:"))
  71. grid.addWidget(w, 0, 0)
  72. self.topmenulist = w = QListWidget()
  73. grid.addWidget(w, 1, 0, 4, 1)
  74. w.itemClicked.connect(self.listItemClicked)
  75. w = QLabel(_("Sub menu items:"))
  76. grid.addWidget(w, 0, 2)
  77. self.submenulist = w = QListWidget()
  78. grid.addWidget(w, 1, 2, 4, 1)
  79. w.itemClicked.connect(self.listItemClicked)
  80. style = QApplication.style()
  81. icon = style.standardIcon(QStyle.SP_ArrowLeft)
  82. self.top_button = w = QPushButton(icon, '')
  83. grid.addWidget(w, 2, 1)
  84. w.clicked.connect(self.top_clicked)
  85. icon = style.standardIcon(QStyle.SP_ArrowRight)
  86. self.sub_button = w = QPushButton(icon, '')
  87. grid.addWidget(w, 3, 1)
  88. w.clicked.connect(self.sub_clicked)
  89. grid.setRowStretch(1, 10)
  90. grid.setRowStretch(4, 10)
  91. def checkbox(label):
  92. cb = QCheckBox(label)
  93. cb.stateChanged.connect(self.stateChanged)
  94. return cb
  95. hidebox = QGroupBox(_('Menu Behavior'))
  96. grid.addWidget(hidebox, 5, 0, 5, 3)
  97. self.hidecmenu = checkbox(_('Hide context menu outside repositories'))
  98. self.hidecmenu.setToolTip(_('Do not show menu items on unversioned '
  99. 'folders (use shift + click to override)'))
  100. hidebox.setLayout(QVBoxLayout())
  101. hidebox.layout().addWidget(self.hidecmenu)
  102. # Icons tab
  103. iconswidget = QWidget()
  104. iconslayout = QVBoxLayout()
  105. iconswidget.setLayout(iconslayout)
  106. tw.addTab(iconswidget, _("Icons"))
  107. # Overlays group
  108. gbox = QGroupBox(_("Overlays"))
  109. iconslayout.addWidget(gbox)
  110. hb = QHBoxLayout()
  111. gbox.setLayout(hb)
  112. self.ovenable = cb = checkbox(_("Enabled overlays"))
  113. hb.addWidget(cb)
  114. self.localonly = checkbox(_("Local disks only"))
  115. hb.addWidget(self.localonly)
  116. hb.addStretch()
  117. # Enabled Overlay Handlers group
  118. gbox = QGroupBox(_("Enabled Overlay Handlers"))
  119. iconslayout.addWidget(gbox)
  120. grid = QGridLayout()
  121. gbox.setLayout(grid)
  122. grid.setColumnStretch(3, 10)
  123. w = QLabel(_("Warning: affects all Tortoises, logoff required after change"))
  124. grid.addWidget(w, 0, 0, 1, 3)
  125. self.enableAddedHandler = w = checkbox(_("Added"))
  126. grid.addWidget(w, 1, 0)
  127. self.enableLockedHandler = w = checkbox(_("Locked*"))
  128. grid.addWidget(w, 1, 1)
  129. self.enableIgnoredHandler = w = checkbox(_("Ignored*"))
  130. grid.addWidget(w, 1, 2)
  131. self.enableUnversionedHandler = w = checkbox(_("Unversioned"))
  132. grid.addWidget(w, 2, 0)
  133. self.enableReadonlyHandler = w = checkbox(_("Readonly*"))
  134. grid.addWidget(w, 2, 1)
  135. self.enableDeletedHandler = w = checkbox(_("Deleted*"))
  136. grid.addWidget(w, 2, 2)
  137. w = QLabel(_("*: not used by TortoiseHg"))
  138. grid.addWidget(w, 3, 0, 1, 3)
  139. # Taskbar group
  140. gbox = QGroupBox(_("Taskbar"))
  141. iconslayout.addWidget(gbox)
  142. hb = QHBoxLayout()
  143. gbox.setLayout(hb)
  144. self.show_taskbaricon = cb = checkbox(_("Show Icon"))
  145. hb.addWidget(cb)
  146. self.highlight_taskbaricon = cb = checkbox(_("Highlight Icon"))
  147. hb.addWidget(cb)
  148. hb.addStretch()
  149. iconslayout.addStretch()
  150. # dialog buttons
  151. BB = QDialogButtonBox
  152. bb = QDialogButtonBox(BB.Ok|BB.Cancel|BB.Apply)
  153. self.apply_button = bb.button(BB.Apply)
  154. bb.accepted.connect(self.accept)
  155. bb.rejected.connect(self.reject)
  156. bb.button(BB.Apply).clicked.connect(self.apply)
  157. bb.button(BB.Ok).setDefault(True)
  158. layout.addWidget(bb)
  159. self.setLayout(layout)
  160. self.setWindowTitle(_("TortoiseHg Shell Configuration"))
  161. self.load_shell_configs()
  162. def load_shell_configs(self):
  163. for name, info in vars.iteritems():
  164. default, regkey, regtype, evalfunc, wrfunc, cbattr = info
  165. try:
  166. hkey = OpenKey(HKEY_CURRENT_USER, 'Software\\' + regkey)
  167. v = QueryValueEx(hkey, name)[0]
  168. vars[name][0] = evalfunc(v)
  169. except (WindowsError, EnvironmentError):
  170. pass
  171. if cbattr != None:
  172. checkbutton = getattr(self, cbattr)
  173. checkbutton.setChecked(vars[name][0])
  174. promoteditems = vars[PROMOTEDITEMS][0]
  175. self.set_menulists(promoteditems)
  176. self.dirty = False
  177. self.update_states()
  178. def set_menulists(self, promoteditems):
  179. for list in (self.topmenulist, self.submenulist):
  180. list.clear()
  181. list.setSortingEnabled(True)
  182. promoted = [pi.strip() for pi in promoteditems.split(',')]
  183. for cmd, info in menuthg.thgcmenu.items():
  184. label = info['label']
  185. item = QListWidgetItem(hglib.tounicode(label['str']))
  186. item._id = label['id']
  187. if cmd in promoted:
  188. self.topmenulist.addItem(item)
  189. else:
  190. self.submenulist.addItem(item)
  191. self.menu_cmds[item._id] = cmd
  192. def store_shell_configs(self):
  193. if not self.dirty:
  194. return
  195. promoted = []
  196. list = self.topmenulist
  197. for row in range(list.count()):
  198. cmd = self.menu_cmds[list.item(row)._id]
  199. promoted.append(cmd)
  200. hkey = CreateKey(HKEY_CURRENT_USER, "Software\\" + THGKEY)
  201. SetValueEx(hkey, PROMOTEDITEMS, 0, REG_SZ, ','.join(promoted))
  202. for name, info in vars.iteritems():
  203. default, regkey, regtype, evalfunc, wrfunc, cbattr = info
  204. if cbattr == None:
  205. continue
  206. checkbutton = getattr(self, cbattr)
  207. v = wrfunc(checkbutton.isChecked())
  208. hkey = CreateKey(HKEY_CURRENT_USER, 'Software\\' + regkey)
  209. SetValueEx(hkey, name, 0, regtype, v)
  210. self.dirty = False
  211. self.update_states()
  212. def accept(self):
  213. self.store_shell_configs()
  214. QDialog.accept(self)
  215. def reject(self):
  216. QDialog.reject(self)
  217. def apply(self):
  218. self.store_shell_configs()
  219. def top_clicked(self):
  220. self.move_selected(self.submenulist, self.topmenulist)
  221. def sub_clicked(self):
  222. self.move_selected(self.topmenulist, self.submenulist)
  223. def move_selected(self, fromlist, tolist):
  224. row = fromlist.currentRow()
  225. if row < 0:
  226. return
  227. item = fromlist.takeItem(row)
  228. tolist.addItem(item)
  229. tolist.setCurrentItem(item)
  230. fromlist.setCurrentItem(None)
  231. self.dirty = True
  232. self.update_states()
  233. def update_states(self):
  234. self.top_button.setEnabled(len(self.submenulist.selectedItems()) > 0)
  235. self.sub_button.setEnabled(len(self.topmenulist.selectedItems()) > 0)
  236. self.apply_button.setEnabled(self.dirty)
  237. def stateChanged(self, state):
  238. self.dirty = True
  239. self.update_states()
  240. def listItemClicked(self, item):
  241. itemlist = item.listWidget()
  242. for list in (self.topmenulist, self.submenulist):
  243. if list != itemlist:
  244. list.setCurrentItem(None)
  245. self.update_states()
  246. def run(ui, *pats, **opts):
  247. return ShellConfigWindow()
  248. if __name__ == "__main__":
  249. app = QApplication(sys.argv)
  250. form = ShellConfigWindow()
  251. form.show()
  252. app.exec_()