Kiln » TortoiseHg » TortoiseHg
Clone URL:  
Pushed to one repository · View In Graph Contained in 1.9, 1.9.1, and 1.9.2

backout: introduce Backout dialog

Changeset 052f61d956c4

Parent 7ffbc51b8c4f

by Yuki KODAMA

Changes to 4 files · Browse files at 052f61d956c4 Showing diff from parent 7ffbc51b8c4f Diff from another changeset...

Change 1 of 1 Show Entire File tortoisehg/​hgqt/​backout.py Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
@@ -0,0 +1,186 @@
+# backout.py - Backout dialog for TortoiseHg +# +# Copyright 2010 Yuki KODAMA <endflow.net@gmail.com> +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +from PyQt4.QtCore import Qt, pyqtSignal +from PyQt4.QtGui import QDialog, QDialogButtonBox, QVBoxLayout, QLabel +from PyQt4.QtGui import QCheckBox, QTextEdit, QTextEdit, QTextCursor + +from mercurial import hg, ui + +from tortoisehg.util import hglib, paths +from tortoisehg.hgqt.i18n import _ +from tortoisehg.hgqt import qtlib, csinfo, i18n, cmdui + +keep = i18n.keepgettext() + +class BackoutDialog(QDialog): + + repoInvalidated = pyqtSignal() + + def __init__(self, repo=None, rev='tip', parent=None, opts={}): + super(BackoutDialog, self).__init__(parent) + self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) + + self.ui = ui.ui() + if repo: + self.repo = repo + else: + root = paths.find_root() + if root: + self.repo = hg.repository(self.ui, path=root) + else: + raise 'not repository' + + # main layout box + box = QVBoxLayout() + box.setSpacing(8) + box.setContentsMargins(*(6,)*4) + + ## target revision + target_sep = qtlib.LabeledSeparator(_('Target changeset')) + box.addWidget(target_sep) + + style = csinfo.panelstyle(selectable=True) + self.target_info = csinfo.create(self.repo, rev, style, withupdate=True) + box.addWidget(self.target_info) + + ## backout message + msg_sep = qtlib.LabeledSeparator(_('Backout commit message')) + box.addWidget(msg_sep) + + revhex = self.target_info.get_data('revid') + self.msgset = keep._('Backed out changeset: ') + self.msgset['id'] += revhex + self.msgset['str'] += revhex + + self.msg_text = QTextEdit() + self.msg_text.setText(self.msgset['str']) + box.addWidget(self.msg_text, 1) + + ## options + opt_sep = qtlib.LabeledSeparator(_('Options')) + box.addWidget(opt_sep) + + obox = QVBoxLayout() + obox.setSpacing(3) + box.addLayout(obox) + + self.eng_chk = QCheckBox(_('Use English backout message')) + self.eng_chk.toggled.connect(self.eng_toggled) + engmsg = self.repo.ui.configbool('tortoisehg', 'engmsg', False) + self.eng_chk.setChecked(engmsg) + + obox.addWidget(self.eng_chk) + self.merge_chk = QCheckBox(_('Merge with old dirstate parent ' + 'after backout')) + obox.addWidget(self.merge_chk) + + ## command widget + self.cmd = cmdui.Widget() + self.cmd.commandStarted.connect(self.command_started) + self.cmd.commandFinished.connect(self.command_finished) + self.cmd.commandCanceling.connect(self.command_canceling) + box.addWidget(self.cmd, 2) + + ## bottom buttons + buttons = QDialogButtonBox() + self.cancel_btn = buttons.addButton(QDialogButtonBox.Cancel) + self.cancel_btn.clicked.connect(self.cancel_clicked) + self.close_btn = buttons.addButton(QDialogButtonBox.Close) + self.close_btn.clicked.connect(self.reject) + self.backout_btn = buttons.addButton(_('&Backout'), + QDialogButtonBox.ActionRole) + self.backout_btn.clicked.connect(self.backout) + self.detail_btn = buttons.addButton(_('Detail'), + QDialogButtonBox.ResetRole) + self.detail_btn.setAutoDefault(False) + self.detail_btn.setCheckable(True) + self.detail_btn.toggled.connect(self.detail_toggled) + box.addWidget(buttons) + + # dialog setting + self.setLayout(box) + self.setMinimumWidth(480) + self.setMaximumHeight(800) + self.resize(0, 340) + reponame = hglib.get_reponame(self.repo) + self.setWindowTitle(_("Backout '%s' - %s") \ + % (revhex, hglib.tounicode(reponame))) + + self.merge_chk.setChecked(bool(opts.get('merge'))) + + # prepare to show + self.cmd.setHidden(True) + self.cancel_btn.setHidden(True) + self.detail_btn.setHidden(True) + self.msg_text.setFocus() + cursor = self.msg_text.textCursor() + cursor.movePosition(QTextCursor.EndOfBlock) + self.msg_text.setTextCursor(cursor) + + ### Private Methods ### + + def eng_toggled(self, checked): + msg = self.msg_text.toPlainText() + origmsg = (checked and self.msgset['str'] or self.msgset['id']) + if msg != origmsg: + if not qtlib.QuestionMsgBox(_('Confirm Discard Message'), + _('Discard current backout message?'), parent=self): + self.eng_chk.blockSignals(True) + self.eng_chk.setChecked(not checked) + self.eng_chk.blockSignals(False) + return + newmsg = (checked and self.msgset['id'] or self.msgset['str']) + self.msg_text.setText(newmsg) + + def backout(self): + # prepare command line + msg = self.msg_text.toPlainText() + revhex = self.target_info.get_data('revid') + cmdline = ['backout', '--rev', revhex] + if self.merge_chk.isChecked(): + cmdline += ['--merge'] + cmdline += ['--message', hglib.fromunicode(msg)] + + # start backing out + self.cmd.run(cmdline) + + ### Signal Handlers ### + + def cancel_clicked(self): + self.cmd.cancel() + + def detail_toggled(self, checked): + self.cmd.show_output(checked) + + def command_started(self): + self.cmd.setShown(True) + self.close_btn.setHidden(True) + self.cancel_btn.setShown(True) + self.detail_btn.setShown(True) + + def command_finished(self, wrapper): + if wrapper.data is not 0 or self.cmd.is_show_output(): + self.detail_btn.setChecked(True) + self.close_btn.setShown(True) + self.close_btn.setAutoDefault(True) + self.close_btn.setFocus() + self.cancel_btn.setHidden(True) + else: + self.repoInvalidated.emit() + self.accept() + + def command_canceling(self): + self.cancel_btn.setDisabled(True) + +def run(ui, *pats, **opts): + kargs = {'opts': opts} + if opts.get('rev'): + kargs['rev'] = opts.get('rev') + elif len(pats) == 1: + kargs['rev'] = pats[0] + return BackoutDialog(**kargs)
 
110
111
112
113
 
114
115
 
116
 
 
117
118
119
 
145
146
147
 
 
 
148
149
150
 
 
151
152
153
 
110
111
112
 
113
114
 
115
116
117
118
119
120
121
 
147
148
149
150
151
152
153
154
 
155
156
157
158
159
@@ -110,10 +110,12 @@
  ('manifest', _('Show at rev...'), None,   _('Show the manifest at selected revision'), None,   self.showAtRev), - ('update', _('Update to rev...'), None, None, None, + ('update', _('Update...'), None, None, None,   self.updateToRev), - ('tag', _('Tag to rev...'), None, None, None, + ('tag', _('Tag...'), None, None, None,   self.tagToRev), + ('backout', _('Backout...'), None, None, None, + self.backoutToRev),   ]   return a   @@ -145,9 +147,13 @@
  def tagToRev(self):   self.emit(SIGNAL('tagToRevision'), self.current_rev)   + def backoutToRev(self): + self.emit(SIGNAL('backoutToRevision'), self.current_rev) +   def contextMenuEvent(self, event):   menu = QtGui.QMenu(self) - for act in ['update', 'manifest', 'tag', None, 'back', 'forward']: + for act in ['update', 'manifest', 'tag', 'backout', None, + 'back', 'forward']:   if act:   menu.addAction(self._actions[act])   else:
 
20
21
22
23
 
24
25
26
 
186
187
188
 
189
190
191
 
236
237
238
 
 
 
 
 
 
 
 
 
 
 
239
240
241
 
20
21
22
 
23
24
25
26
 
186
187
188
189
190
191
192
 
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
@@ -20,7 +20,7 @@
   from tortoisehg.hgqt.qtlib import geticon  from tortoisehg.hgqt.repomodel import HgRepoListModel -from tortoisehg.hgqt import cmdui, update, tag, manifestdialog +from tortoisehg.hgqt import cmdui, update, tag, manifestdialog, backout  from tortoisehg.hgqt.config import HgConfig    from repoview import HgRepoView @@ -186,6 +186,7 @@
  connect(view, SIGNAL('revisionActivated'), self.revision_activated)   connect(view, SIGNAL('updateToRevision'), self.updateToRevision)   connect(view, SIGNAL('tagToRevision'), self.tagToRevision) + connect(view, SIGNAL('backoutToRevision'), self.backoutToRevision)   #self.attachQuickBar(view.goto_toolbar)   gotoaction = view.goto_toolbar.toggleViewAction()   gotoaction.setIcon(geticon('goto')) @@ -236,6 +237,17 @@
  dlg.repoInvalidated.connect(invalidated)   dlg.show()   + def backoutToRevision(self, rev): + saved = self.setScanForRepoChanges(False) + dlg = backout.BackoutDialog(self.repo, str(rev), self) + def finished(ret): + self.setScanForRepoChanges(saved) + dlg.finished.connect(finished) + def invalidated(): + self.reload() # TODO: implement something less drastic than a full reload + dlg.repoInvalidated.connect(invalidated) + dlg.show() +   def revision_selected(self, rev):   if self.repomodel.graph:   ctx = self.repomodel.repo.changectx(rev)
 
337
338
339
 
 
 
 
 
340
341
342
 
378
379
380
381
 
382
383
384
 
660
661
662
 
 
 
 
 
 
663
664
665
 
337
338
339
340
341
342
343
344
345
346
347
 
383
384
385
 
386
387
388
389
 
665
666
667
668
669
670
671
672
673
674
675
676
@@ -337,6 +337,11 @@
  from tortoisehg.hgqt.quickop import run   qtrun(run, ui, *pats, **opts)   +def backout(ui, *pats, **opts): + """backout tool""" + from tortoisehg.hgqt.backout import run + qtrun(run, ui, *pats, **opts) +  def thgstatus(ui, *pats, **opts):   """update TortoiseHg status cache"""   from tortoisehg.util.thgstatus import run @@ -378,7 +383,7 @@
  qtrun(run, ui, *pats, **opts)    def tag(ui, *pats, **opts): - """clone tool""" + """tag tool"""   from tortoisehg.hgqt.tag import run   qtrun(run, ui, *pats, **opts)   @@ -660,6 +665,12 @@
  "archive": (archive,   [('r', 'rev', '', _('revision to archive'))],   _('thg archive')), + "^backout": (backout, + [('', 'merge', None, + _('merge with old dirstate parent after backout')), + ('', 'parent', '', _('parent to choose when backing out merge')), + ('r', 'rev', '', _('revision to backout'))], + _('thg backout [OPTION]... [[-r] REV]')),   "^clone":   (clone,   [('U', 'noupdate', None,