createbranch: apply flake8 suggestions
[git-cola.git] / cola / widgets / createbranch.py
blob66a9a65c0cfb357d02534131491cc50cf2836b1d
1 from __future__ import division, absolute_import, unicode_literals
3 from PyQt4 import QtGui
4 from PyQt4 import QtCore
5 from PyQt4.QtCore import Qt
6 from PyQt4.QtCore import SIGNAL
8 from cola import gitcmds
9 from cola import icons
10 from cola import qtutils
11 from cola.i18n import N_
12 from cola.interaction import Interaction
13 from cola.models import main
14 from cola.widgets import defs
15 from cola.widgets import completion
16 from cola.widgets.standard import Dialog
19 COMMAND_SIGNAL = 'command(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)'
22 def create_new_branch(revision='', settings=None):
23 """Launches a dialog for creating a new branch"""
24 model = main.MainModel()
25 model.update_status()
26 view = CreateBranchDialog(model, settings=settings,
27 parent=qtutils.active_window())
28 if revision:
29 view.set_revision(revision)
30 view.show()
31 return view
34 class CreateOpts(object):
35 def __init__(self, model):
36 self.model = model
37 self.reset = False
38 self.track = False
39 self.fetch = True
40 self.checkout = True
41 self.revision = 'HEAD'
42 self.branch = ''
45 class CreateThread(QtCore.QThread):
46 def __init__(self, opts, parent):
47 QtCore.QThread.__init__(self, parent)
48 self.opts = opts
50 def run(self):
51 branch = self.opts.branch
52 revision = self.opts.revision
53 reset = self.opts.reset
54 checkout = self.opts.checkout
55 track = self.opts.track
56 model = self.opts.model
57 results = []
58 status = 0
60 if track and '/' in revision:
61 remote = revision.split('/', 1)[0]
62 status, out, err = model.git.fetch(remote)
63 self.emit(SIGNAL(COMMAND_SIGNAL), status, out, err)
64 results.append(('fetch', status, out, err))
66 if status == 0:
67 status, out, err = model.create_branch(branch, revision,
68 force=reset,
69 track=track)
70 self.emit(SIGNAL(COMMAND_SIGNAL), status, out, err)
72 results.append(('branch', status, out, err))
73 if status == 0 and checkout:
74 status, out, err = model.git.checkout(branch)
75 self.emit(SIGNAL(COMMAND_SIGNAL), status, out, err)
76 results.append(('checkout', status, out, err))
78 main.model().update_status()
79 self.emit(SIGNAL('done(PyQt_PyObject)'), results)
82 class CreateBranchDialog(Dialog):
83 """A dialog for creating branches."""
85 def __init__(self, model, settings=None, parent=None):
86 Dialog.__init__(self, parent=parent)
87 self.setAttribute(Qt.WA_MacMetalStyle)
88 self.setWindowTitle(N_('Create Branch'))
89 if parent is not None:
90 self.setWindowModality(Qt.WindowModal)
92 self.model = model
93 self.opts = CreateOpts(model)
94 self.thread = CreateThread(self.opts, self)
96 self.progress = QtGui.QProgressDialog(self)
97 self.progress.setRange(0, 0)
98 self.progress.setCancelButton(None)
99 self.progress.setWindowTitle(N_('Create Branch'))
100 self.progress.setWindowModality(Qt.WindowModal)
102 self.branch_name_label = QtGui.QLabel()
103 self.branch_name_label.setText(N_('Branch Name'))
105 self.branch_name = QtGui.QLineEdit()
107 self.rev_label = QtGui.QLabel()
108 self.rev_label.setText(N_('Starting Revision'))
110 self.revision = completion.GitRefLineEdit()
111 current = gitcmds.current_branch()
112 if current:
113 self.revision.setText(current)
115 self.local_radio = qtutils.radio(text=N_('Local branch'), checked=True)
116 self.remote_radio = qtutils.radio(text=N_('Tracking branch'))
117 self.tag_radio = qtutils.radio(text=N_('Tag'))
119 self.branch_list = QtGui.QListWidget()
121 self.update_existing_label = QtGui.QLabel()
122 self.update_existing_label.setText(N_('Update Existing Branch:'))
124 self.no_update_radio = qtutils.radio(text=N_('No'))
125 self.ffwd_only_radio = qtutils.radio(text=N_('Fast Forward Only'),
126 checked=True)
127 self.reset_radio = qtutils.radio(text=N_('Reset'))
129 text = N_('Fetch Tracking Branch')
130 self.fetch_checkbox = qtutils.checkbox(text=text, checked=True)
132 text = N_('Checkout After Creation')
133 self.checkout_checkbox = qtutils.checkbox(text=text, checked=True)
135 icon = icons.branch()
136 self.create_button = qtutils.create_button(text=N_('Create Branch'),
137 icon=icon, default=True)
138 self.close_button = qtutils.close_button()
140 self.options_checkbox_layout = qtutils.hbox(defs.margin, defs.spacing,
141 self.fetch_checkbox,
142 self.checkout_checkbox,
143 qtutils.STRETCH)
145 self.branch_name_layout = qtutils.hbox(defs.margin, defs.spacing,
146 self.branch_name_label,
147 self.branch_name)
149 self.rev_radio_group = qtutils.buttongroup(self.local_radio,
150 self.remote_radio,
151 self.tag_radio)
153 self.rev_radio_layout = qtutils.hbox(defs.margin, defs.spacing,
154 self.local_radio,
155 self.remote_radio,
156 self.tag_radio,
157 qtutils.STRETCH)
159 self.rev_start_textinput_layout = qtutils.hbox(defs.no_margin,
160 defs.spacing,
161 self.rev_label,
162 defs.spacing,
163 self.revision)
165 self.rev_start_layout = qtutils.vbox(defs.no_margin, defs.spacing,
166 self.rev_radio_layout,
167 self.branch_list,
168 self.rev_start_textinput_layout)
170 self.options_radio_group = qtutils.buttongroup(self.no_update_radio,
171 self.ffwd_only_radio,
172 self.reset_radio)
174 self.options_radio_layout = qtutils.hbox(defs.no_margin, defs.spacing,
175 self.update_existing_label,
176 self.no_update_radio,
177 self.ffwd_only_radio,
178 self.reset_radio,
179 qtutils.STRETCH)
181 self.buttons_layout = qtutils.hbox(defs.margin, defs.spacing,
182 qtutils.STRETCH,
183 self.create_button,
184 self.close_button)
186 self.main_layout = qtutils.vbox(defs.margin, defs.spacing,
187 self.branch_name_layout,
188 self.rev_start_layout,
189 defs.button_spacing,
190 self.options_radio_layout,
191 self.options_checkbox_layout,
192 self.buttons_layout)
193 self.setLayout(self.main_layout)
195 qtutils.add_close_action(self)
196 qtutils.connect_button(self.close_button, self.close)
197 qtutils.connect_button(self.create_button, self.create_branch)
198 qtutils.connect_button(self.local_radio, self.display_model)
199 qtutils.connect_button(self.remote_radio, self.display_model)
200 qtutils.connect_button(self.tag_radio, self.display_model)
202 self.connect(self.branch_list, SIGNAL('itemSelectionChanged()'),
203 self.branch_item_changed)
205 self.connect(self.thread, SIGNAL(COMMAND_SIGNAL),
206 self.thread_command, Qt.QueuedConnection)
208 self.connect(self.thread, SIGNAL('done(PyQt_PyObject)'),
209 self.thread_done, Qt.QueuedConnection)
211 if not self.restore_state(settings=settings):
212 self.resize(555, 333)
214 self.display_model()
216 def set_revision(self, revision):
217 self.revision.setText(revision)
219 def getopts(self):
220 self.opts.revision = self.revision.value()
221 self.opts.branch = self.branch_name.text()
222 self.opts.checkout = self.checkout_checkbox.isChecked()
223 self.opts.reset = self.reset_radio.isChecked()
224 self.opts.fetch = self.fetch_checkbox.isChecked()
225 self.opts.track = self.remote_radio.isChecked()
227 def create_branch(self):
228 """Creates a branch; called by the "Create Branch" button"""
229 self.getopts()
230 revision = self.opts.revision
231 branch = self.opts.branch
232 no_update = self.no_update_radio.isChecked()
233 ffwd_only = self.ffwd_only_radio.isChecked()
234 existing_branches = gitcmds.branch_list()
235 check_branch = False
237 if not branch or not revision:
238 qtutils.critical(N_('Missing Data'),
239 N_('Please provide both a branch '
240 'name and revision expression.'))
241 return
242 if branch in existing_branches:
243 if no_update:
244 msg = N_('Branch "%s" already exists.') % branch
245 qtutils.critical(N_('Branch Exists'), msg)
246 return
247 # Whether we should prompt the user for lost commits
248 commits = gitcmds.rev_list_range(revision, branch)
249 check_branch = bool(commits)
251 if check_branch:
252 msg = (N_('Resetting "%(branch)s" to "%(revision)s" '
253 'will lose commits.') %
254 dict(branch=branch, revision=revision))
255 if ffwd_only:
256 qtutils.critical(N_('Branch Exists'), msg)
257 return
258 lines = [msg]
259 for idx, commit in enumerate(commits):
260 subject = commit[1][0:min(len(commit[1]), 16)]
261 if len(subject) < len(commit[1]):
262 subject += '...'
263 lines.append('\t' + commit[0][:8] + '\t' + subject)
264 if idx >= 5:
265 skip = len(commits) - 5
266 lines.append('\t(%s)' % (N_('%d skipped') % skip))
267 break
268 line = N_('Recovering lost commits may not be easy.')
269 lines.append(line)
271 info_text = (N_('Reset "%(branch)s" to "%(revision)s"?') %
272 dict(branch=branch, revision=revision))
274 if not qtutils.confirm(N_('Reset Branch?'),
275 '\n'.join(lines),
276 info_text,
277 N_('Reset Branch'),
278 default=False,
279 icon=icons.undo()):
280 return
281 self.setEnabled(False)
282 self.progress.setEnabled(True)
283 QtGui.QApplication.setOverrideCursor(Qt.WaitCursor)
285 # Show a nice progress bar
286 self.progress.setLabelText(N_('Updating...'))
287 self.progress.show()
288 self.thread.start()
290 def thread_command(self, status, out, err):
291 Interaction.log_status(status, out, err)
293 def thread_done(self, results):
294 self.setEnabled(True)
295 self.progress.close()
296 QtGui.QApplication.restoreOverrideCursor()
298 for (cmd, status, out, err) in results:
299 if status != 0:
300 Interaction.critical(
301 N_('Error Creating Branch'),
302 (N_('"%(command)s" returned exit status "%(status)d"') %
303 dict(command='git '+cmd, status=status)))
304 return
306 self.accept()
308 def branch_item_changed(self, *rest):
309 """This callback is called when the branch selection changes"""
310 # When the branch selection changes then we should update
311 # the "Revision Expression" accordingly.
312 qlist = self.branch_list
313 remote_branch = qtutils.selected_item(qlist, self.branch_sources())
314 if not remote_branch:
315 return
316 # Update the model with the selection
317 self.revision.setText(remote_branch)
319 # Set the branch field if we're branching from a remote branch.
320 if not self.remote_radio.isChecked():
321 return
322 branch = gitcmds.strip_remote(self.model.remotes, remote_branch)
323 if branch == 'HEAD':
324 return
325 # Signal that we've clicked on a remote branch
326 self.branch_name.setText(branch)
328 def display_model(self):
329 """Sets the branch list to the available branches
331 branches = self.branch_sources()
332 qtutils.set_items(self.branch_list, branches)
334 def branch_sources(self):
335 """Get the list of items for populating the branch root list.
337 if self.local_radio.isChecked():
338 return self.model.local_branches
339 elif self.remote_radio.isChecked():
340 return self.model.remote_branches
341 elif self.tag_radio.isChecked():
342 return self.model.tags