/tortoisehg/hgtk/thgshelve.py

https://bitbucket.org/tortoisehg/hgtk/ · Python · 276 lines · 203 code · 42 blank · 31 comment · 37 complexity · 4938db695fa1ac4c5031c9b653486c3a MD5 · raw file

  1. # thgshelve.py - commit dialog for TortoiseHg
  2. #
  3. # Copyright 2007 Brad Schick, brad at gmail . com
  4. # Copyright 2007 TK Soh <teekaysoh@gmail.com>
  5. # Copyright 2007 Steve Borho <steve@borho.org>
  6. #
  7. # This software may be used and distributed according to the terms of the
  8. # GNU General Public License version 2, incorporated herein by reference.
  9. import os
  10. import gtk
  11. from mercurial import util, patch, ui
  12. from tortoisehg.util.i18n import _
  13. from tortoisehg.util import hglib, hgshelve
  14. from tortoisehg.hgtk.status import GStatus, FM_STATUS, FM_CHECKED, FM_PATH
  15. from tortoisehg.hgtk import gdialog, gtklib
  16. class GShelve(GStatus):
  17. """GTK+ based dialog for displaying repository status and shelving changes.
  18. Also provides related operations like add, delete, remove, revert, refresh,
  19. ignore, diff, and edit.
  20. """
  21. ### Overrides of base class methods ###
  22. def init(self):
  23. GStatus.init(self)
  24. self.mode = 'shelve'
  25. self.ui = ErrBufUI(self.ui)
  26. def parse_opts(self):
  27. GStatus.parse_opts(self)
  28. if not self.test_opt('rev'):
  29. self.opts['rev'] = ''
  30. def get_title(self):
  31. return self.get_reponame() + ' - shelve'
  32. def get_icon(self):
  33. return 'shelve.ico'
  34. def auto_check(self):
  35. if not self.test_opt('check'):
  36. return
  37. for row in self.filemodel:
  38. if row[FM_STATUS] in 'MAR' and row[FM_PATH] not in self.excludes:
  39. row[FM_CHECKED] = True
  40. self.update_check_count()
  41. self.opts['check'] = False
  42. def save_settings(self):
  43. settings = GStatus.save_settings(self)
  44. #settings['gshelve'] = self.vpaned.get_position()
  45. return settings
  46. def load_settings(self, settings):
  47. GStatus.load_settings(self, settings)
  48. #if settings:
  49. # self._setting_vpos = settings['gshelve']
  50. #else:
  51. # self._setting_vpos = -1
  52. def get_tbbuttons(self):
  53. tbbuttons = GStatus.get_tbbuttons(self)
  54. tbbuttons.insert(0, gtk.SeparatorToolItem())
  55. self.shelve_btn = self.make_toolbutton(gtk.STOCK_FILE, _('Shelve'),
  56. self.shelve_clicked, tip=_('set aside selected changes'))
  57. self.unshelve_btn = self.make_toolbutton(gtk.STOCK_EDIT, _('Unshelve'),
  58. self.unshelve_clicked, tip=_('restore shelved changes'))
  59. self.abandon_btn = self.make_toolbutton(gtk.STOCK_CANCEL, _('Abandon'),
  60. self.abandon_clicked, tip=_('abandon shelved changes'))
  61. tbbuttons.insert(0, self.abandon_btn)
  62. tbbuttons.insert(0, self.unshelve_btn)
  63. tbbuttons.insert(0, self.shelve_btn)
  64. return tbbuttons
  65. def get_body(self):
  66. status_body = GStatus.get_body(self)
  67. #vbox = gtk.VBox() # For named shelf collection
  68. #self.vpaned = gtk.VPaned()
  69. #self.vpaned.add1(vbox)
  70. #self.vpaned.add2(status_body)
  71. #self.vpaned.set_position(self._setting_vpos)
  72. self.activate_shelve_buttons(True)
  73. self.patch_text = gtk.TextView()
  74. self.patch_text.set_wrap_mode(gtk.WRAP_NONE)
  75. self.patch_text.set_editable(False)
  76. self.patch_text.modify_font(self.difffont)
  77. scroller = gtk.ScrolledWindow()
  78. scroller.set_policy(gtk.POLICY_AUTOMATIC,
  79. gtk.POLICY_AUTOMATIC)
  80. scroller.add(self.patch_text)
  81. self.diff_notebook.append_page(scroller, gtk.Label(_('Shelf Contents')))
  82. self.diff_notebook.show_all()
  83. return status_body
  84. def get_custom_menus(self):
  85. def shelve(menuitem, files):
  86. self.shelve_selected(files)
  87. self.activate_shelve_buttons(True)
  88. if self.is_merge():
  89. return ()
  90. else:
  91. return ((_('_Shelve'), shelve, 'MAR', 'shelve.ico'),)
  92. def should_live(self, widget=None, event=None):
  93. return False
  94. def refresh_complete(self):
  95. self.activate_shelve_buttons(True)
  96. if self.has_shelve_file():
  97. fp = open(self.repo.join('shelve'))
  98. buf = self.diff_highlight_buffer(fp.readlines())
  99. self.patch_text.set_buffer(buf)
  100. else:
  101. self.patch_text.set_buffer(gtk.TextBuffer())
  102. ### End of overridable methods ###
  103. def has_shelve_file(self):
  104. return os.path.exists(self.repo.join('shelve'))
  105. def activate_shelve_buttons(self, status):
  106. if status:
  107. self.shelve_btn.set_sensitive(len(self.filemodel) > 0)
  108. self.unshelve_btn.set_sensitive(self.has_shelve_file())
  109. self.abandon_btn.set_sensitive(self.has_shelve_file())
  110. else:
  111. self.shelve_btn.set_sensitive(False)
  112. self.unshelve_btn.set_sensitive(False)
  113. self.abandon_btn.set_sensitive(False)
  114. def shelve_selected(self, files=[]):
  115. if len(self.filemodel) < 1:
  116. gdialog.Prompt(_('Shelve'),
  117. _('No changes to shelve'), self).run()
  118. return
  119. wfiles = files or self.relevant_checked_files('MAR')
  120. if not wfiles:
  121. gdialog.Prompt(_('Shelve'),
  122. _('Please select diff chunks to shelve'), self).run()
  123. return
  124. doforce = False
  125. doappend = False
  126. if self.has_shelve_file():
  127. dialog = gtklib.MessageDialog(flags=gtk.DIALOG_MODAL)
  128. dialog.set_title(_('Shelve'))
  129. dialog.set_markup(_('<b>Shelve file exists!</b>'))
  130. dialog.add_buttons(_('Overwrite'), 1,
  131. _('Append'), 2,
  132. _('Cancel'), -1)
  133. dialog.set_transient_for(self)
  134. rval = dialog.run()
  135. dialog.destroy()
  136. if rval == 1:
  137. doforce = True
  138. elif rval == 2:
  139. doappend = True
  140. else:
  141. return
  142. def filter_patch(ui, chunks):
  143. accepted = []
  144. for chunk in chunks:
  145. file = util.localpath(chunk.filename())
  146. if file not in wfiles:
  147. # file was not selected for inclusion
  148. continue
  149. if file not in self.chunks:
  150. # file was never filtered, accept all chunks
  151. accepted.append(chunk)
  152. continue
  153. schunks = self.chunks[file]
  154. for i, c in enumerate(schunks):
  155. if chunk != c:
  156. continue
  157. if i == 0 or c.active:
  158. # take header and active chunks
  159. accepted.append(chunk)
  160. break
  161. return accepted
  162. # hgshelve only works 'interactively'
  163. self.ui.setconfig('ui', 'interactive', 'on')
  164. opts = {'addremove': None, 'include': [], 'force': doforce,
  165. 'append': doappend, 'exclude': []}
  166. hgshelve.filterpatch = filter_patch
  167. # shelve them!
  168. hgshelve.shelve(self.ui, self.repo, **opts)
  169. self.ui.setconfig('ui', 'interactive', 'off')
  170. self.chunks.clear_filechunks() # do not keep chunks
  171. self.reload_status()
  172. def unshelve(self):
  173. opts = {'addremove': None, 'include': [], 'force': None,
  174. 'append': None, 'exclude': [], 'inspect': None}
  175. try:
  176. self.ui.errorq = []
  177. self.ui.quiet = True
  178. hgshelve.unshelve(self.ui, self.repo, **opts)
  179. self.ui.quiet = False
  180. self.reload_status()
  181. except (util.Abort, IOError, patch.PatchError), e:
  182. gdialog.Prompt(_('Unshelve Abort'),
  183. ''.join(self.ui.errorq), self).run()
  184. except Exception, e:
  185. gdialog.Prompt(_('Unshelve Error'),
  186. _('Error: %s') % e, self).run()
  187. def abandon(self):
  188. try:
  189. response = gdialog.Confirm(_('Confirm Delete'), [], self,
  190. _('Delete the shelf contents?')).run()
  191. if response == gtk.RESPONSE_YES:
  192. self.ui.quiet = True
  193. hgshelve.abandon(self.ui, self.repo)
  194. self.ui.quiet = False
  195. self.reload_status()
  196. except Exception, e:
  197. gdialog.Prompt(_('Abandon Error'),
  198. _('Error: %s') % e, self).run()
  199. def shelve_clicked(self, toolbutton, data=None):
  200. if not self.isuptodate():
  201. return
  202. self.shelve_selected()
  203. self.activate_shelve_buttons(True)
  204. def unshelve_clicked(self, toolbutton, data=None):
  205. if not self.isuptodate():
  206. return
  207. self.unshelve()
  208. self.activate_shelve_buttons(True)
  209. def abandon_clicked(self, toolbutton, data=None):
  210. if not self.isuptodate():
  211. return
  212. self.abandon()
  213. self.activate_shelve_buttons(True)
  214. class ErrBufUI(ui.ui):
  215. """ui subclass to save hg and thg errors"""
  216. def __init__(self, src=None, errorq=[]):
  217. ui.ui.__init__(self, src)
  218. if src and hasattr(src, 'errorq'):
  219. self.errorq = src.errorq
  220. else:
  221. self.errorq = errorq
  222. def warn(self, *msg, **opts):
  223. self.errorq.extend(msg)
  224. ui.ui.warn(self, *msg, **opts)
  225. def run(_ui, *pats, **opts):
  226. cmdoptions = {
  227. 'user':opts.get('user', ''), 'date':opts.get('date', ''),
  228. 'modified':True, 'added':True, 'removed':True, 'deleted':True,
  229. 'unknown':True, 'ignored':False,
  230. 'exclude':[], 'include':[],
  231. 'check': True, 'git':False, 'addremove':False,
  232. }
  233. return GShelve(_ui, None, None, pats, cmdoptions)