createbranch: pylint updates
[git-cola.git] / cola / widgets / createbranch.py
bloba6e5fb3ce0ea810eb187b5c0cbd8248ea98eeedb
1 from __future__ import division, absolute_import, unicode_literals
3 from qtpy import QtWidgets
4 from qtpy import QtCore
5 from qtpy.QtCore import Qt
6 from qtpy.QtCore import Signal
8 from ..i18n import N_
9 from ..interaction import Interaction
10 from ..qtutils import get
11 from .. import gitcmds
12 from .. import icons
13 from .. import qtutils
14 from .standard import Dialog
15 from .standard import ProgressDialog
16 from . import defs
17 from . import completion
20 def create_new_branch(context, revision='', settings=None):
21 """Launches a dialog for creating a new branch"""
22 view = CreateBranchDialog(context, settings=settings,
23 parent=qtutils.active_window())
24 if revision:
25 view.set_revision(revision)
26 view.show()
27 return view
30 class CreateOpts(object):
31 def __init__(self, context):
32 self.context = context
33 self.reset = False
34 self.track = False
35 self.fetch = True
36 self.checkout = True
37 self.revision = 'HEAD'
38 self.branch = ''
41 class CreateThread(QtCore.QThread):
42 command = Signal(object, object, object)
43 result = Signal(object)
45 def __init__(self, opts, parent):
46 QtCore.QThread.__init__(self, parent)
47 self.opts = opts
49 def run(self):
50 branch = self.opts.branch
51 revision = self.opts.revision
52 reset = self.opts.reset
53 checkout = self.opts.checkout
54 track = self.opts.track
55 context = self.opts.context
56 git = context.git
57 model = context.model
58 results = []
59 status = 0
61 if track and '/' in revision:
62 remote = revision.split('/', 1)[0]
63 status, out, err = git.fetch(remote)
64 self.command.emit(status, out, err)
65 results.append(('fetch', status, out, err))
67 if status == 0:
68 status, out, err = model.create_branch(
69 branch, revision, force=reset, track=track)
70 self.command.emit(status, out, err)
72 results.append(('branch', status, out, err))
73 if status == 0 and checkout:
74 status, out, err = git.checkout(branch)
75 self.command.emit(status, out, err)
76 results.append(('checkout', status, out, err))
78 model.update_status()
79 self.result.emit(results)
82 class CreateBranchDialog(Dialog):
83 """A dialog for creating branches."""
85 def __init__(self, context, settings=None, parent=None):
86 Dialog.__init__(self, parent=parent)
87 self.setWindowTitle(N_('Create Branch'))
88 if parent is not None:
89 self.setWindowModality(Qt.WindowModal)
91 self.context = context
92 self.model = context.model
93 self.opts = CreateOpts(context)
94 self.thread = CreateThread(self.opts, self)
96 self.progress = None
98 self.branch_name_label = QtWidgets.QLabel()
99 self.branch_name_label.setText(N_('Branch Name'))
101 self.branch_name = completion.GitCreateBranchLineEdit(context)
102 self.branch_validator = completion.BranchValidator(
103 context.git, parent=self.branch_name)
104 self.branch_name.setValidator(self.branch_validator)
106 self.rev_label = QtWidgets.QLabel()
107 self.rev_label.setText(N_('Starting Revision'))
109 self.revision = completion.GitRefLineEdit(context)
110 current = gitcmds.current_branch(context)
111 if current:
112 self.revision.setText(current)
114 self.local_radio = qtutils.radio(text=N_('Local branch'), checked=True)
115 self.remote_radio = qtutils.radio(text=N_('Tracking branch'))
116 self.tag_radio = qtutils.radio(text=N_('Tag'))
118 self.branch_list = QtWidgets.QListWidget()
120 self.update_existing_label = QtWidgets.QLabel()
121 self.update_existing_label.setText(N_('Update Existing Branch:'))
123 self.no_update_radio = qtutils.radio(text=N_('No'))
124 self.ffwd_only_radio = qtutils.radio(text=N_('Fast Forward Only'),
125 checked=True)
126 self.reset_radio = qtutils.radio(text=N_('Reset'))
128 text = N_('Fetch Tracking Branch')
129 self.fetch_checkbox = qtutils.checkbox(text=text, checked=True)
131 text = N_('Checkout After Creation')
132 self.checkout_checkbox = qtutils.checkbox(text=text, checked=True)
134 icon = icons.branch()
135 self.create_button = qtutils.create_button(text=N_('Create Branch'),
136 icon=icon, default=True)
137 self.close_button = qtutils.close_button()
139 self.options_checkbox_layout = qtutils.hbox(defs.margin, defs.spacing,
140 self.fetch_checkbox,
141 self.checkout_checkbox,
142 qtutils.STRETCH)
144 self.branch_name_layout = qtutils.hbox(defs.margin, defs.spacing,
145 self.branch_name_label,
146 self.branch_name)
148 self.rev_radio_group = qtutils.buttongroup(self.local_radio,
149 self.remote_radio,
150 self.tag_radio)
152 self.rev_radio_layout = qtutils.hbox(defs.margin, defs.spacing,
153 self.local_radio,
154 self.remote_radio,
155 self.tag_radio,
156 qtutils.STRETCH)
158 self.rev_start_textinput_layout = qtutils.hbox(defs.no_margin,
159 defs.spacing,
160 self.rev_label,
161 defs.spacing,
162 self.revision)
164 self.rev_start_layout = qtutils.vbox(defs.no_margin, defs.spacing,
165 self.rev_radio_layout,
166 self.branch_list,
167 self.rev_start_textinput_layout)
169 self.options_radio_group = qtutils.buttongroup(self.no_update_radio,
170 self.ffwd_only_radio,
171 self.reset_radio)
173 self.options_radio_layout = qtutils.hbox(defs.no_margin, defs.spacing,
174 self.update_existing_label,
175 self.no_update_radio,
176 self.ffwd_only_radio,
177 self.reset_radio,
178 qtutils.STRETCH)
180 self.buttons_layout = qtutils.hbox(defs.margin, defs.spacing,
181 self.close_button,
182 qtutils.STRETCH,
183 self.create_button)
185 self.main_layout = qtutils.vbox(defs.margin, defs.spacing,
186 self.branch_name_layout,
187 self.rev_start_layout,
188 defs.button_spacing,
189 self.options_radio_layout,
190 self.options_checkbox_layout,
191 self.buttons_layout)
192 self.setLayout(self.main_layout)
194 qtutils.add_close_action(self)
195 qtutils.connect_button(self.close_button, self.close)
196 qtutils.connect_button(self.create_button, self.create_branch)
197 qtutils.connect_toggle(self.local_radio, self.display_model)
198 qtutils.connect_toggle(self.remote_radio, self.display_model)
199 qtutils.connect_toggle(self.tag_radio, self.display_model)
201 branches = self.branch_list
202 branches.itemSelectionChanged.connect(self.branch_item_changed)
204 thread = self.thread
205 thread.command.connect(self.thread_command, type=Qt.QueuedConnection)
206 thread.result.connect(self.thread_result, type=Qt.QueuedConnection)
208 self.init_size(settings=settings, parent=parent)
209 self.display_model()
211 def set_revision(self, revision):
212 self.revision.setText(revision)
214 def getopts(self):
215 self.opts.revision = get(self.revision)
216 self.opts.branch = get(self.branch_name)
217 self.opts.checkout = get(self.checkout_checkbox)
218 self.opts.reset = get(self.reset_radio)
219 self.opts.fetch = get(self.fetch_checkbox)
220 self.opts.track = get(self.remote_radio)
222 def create_branch(self):
223 """Creates a branch; called by the "Create Branch" button"""
224 context = self.context
225 self.getopts()
226 revision = self.opts.revision
227 branch = self.opts.branch
228 no_update = get(self.no_update_radio)
229 ffwd_only = get(self.ffwd_only_radio)
230 existing_branches = gitcmds.branch_list(context)
231 check_branch = False
233 if not branch or not revision:
234 Interaction.critical(
235 N_('Missing Data'),
236 N_('Please provide both a branch '
237 'name and revision expression.'))
238 return
239 if branch in existing_branches:
240 if no_update:
241 msg = N_('Branch "%s" already exists.') % branch
242 Interaction.critical(N_('Branch Exists'), msg)
243 return
244 # Whether we should prompt the user for lost commits
245 commits = gitcmds.rev_list_range(context, revision, branch)
246 check_branch = bool(commits)
248 if check_branch:
249 msg = (N_('Resetting "%(branch)s" to "%(revision)s" '
250 'will lose commits.') %
251 dict(branch=branch, revision=revision))
252 if ffwd_only:
253 Interaction.critical(N_('Branch Exists'), msg)
254 return
255 lines = [msg]
256 for idx, commit in enumerate(commits):
257 subject = commit[1][0:min(len(commit[1]), 16)]
258 if len(subject) < len(commit[1]):
259 subject += '...'
260 lines.append('\t' + commit[0][:8] + '\t' + subject)
261 if idx >= 5:
262 skip = len(commits) - 5
263 lines.append('\t(%s)' % (N_('%d skipped') % skip))
264 break
265 line = N_('Recovering lost commits may not be easy.')
266 lines.append(line)
268 info_text = (N_('Reset "%(branch)s" to "%(revision)s"?') %
269 dict(branch=branch, revision=revision))
271 if not Interaction.confirm(
272 N_('Reset Branch?'), '\n'.join(lines), info_text,
273 N_('Reset Branch'), default=False, icon=icons.undo()):
274 return
276 title = N_('Create Branch')
277 label = N_('Updating')
278 self.progress = ProgressDialog(title, label, self)
279 self.progress.show()
280 self.thread.start()
282 def thread_command(self, status, out, err):
283 Interaction.log_status(status, out, err)
285 def thread_result(self, results):
286 self.progress.hide()
287 del self.progress
289 for (cmd, status, _, _) in results:
290 if status != 0:
291 Interaction.critical(
292 N_('Error Creating Branch'),
293 (N_('"%(command)s" returned exit status "%(status)d"')
294 % dict(command='git '+cmd, status=status)))
295 return
297 self.accept()
299 # pylint: disable=unused-argument
300 def branch_item_changed(self, *rest):
301 """This callback is called when the branch selection changes"""
302 # When the branch selection changes then we should update
303 # the "Revision Expression" accordingly.
304 qlist = self.branch_list
305 remote_branch = qtutils.selected_item(qlist, self.branch_sources())
306 if not remote_branch:
307 return
308 # Update the model with the selection
309 self.revision.setText(remote_branch)
311 # Set the branch field if we're branching from a remote branch.
312 if not get(self.remote_radio):
313 return
314 branch = gitcmds.strip_remote(self.model.remotes, remote_branch)
315 if branch == 'HEAD':
316 return
317 # Signal that we've clicked on a remote branch
318 self.branch_name.set_value(branch)
320 def display_model(self):
321 """Sets the branch list to the available branches
323 branches = self.branch_sources()
324 qtutils.set_items(self.branch_list, branches)
326 def branch_sources(self):
327 """Get the list of items for populating the branch root list.
329 if get(self.local_radio):
330 value = self.model.local_branches
331 elif get(self.remote_radio):
332 value = self.model.remote_branches
333 elif get(self.tag_radio):
334 value = self.model.tags
335 else:
336 value = []
337 return value