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
9 from ..interaction
import Interaction
10 from ..qtutils
import get
11 from .. import gitcmds
13 from .. import qtutils
15 from . import completion
16 from . import standard
19 def create_new_branch(context
, revision
=''):
20 """Launches a dialog for creating a new branch"""
21 view
= CreateBranchDialog(context
, parent
=qtutils
.active_window())
23 view
.set_revision(revision
)
28 class CreateOpts(object):
29 def __init__(self
, context
):
30 self
.context
= context
35 self
.revision
= 'HEAD'
39 class CreateThread(QtCore
.QThread
):
40 command
= Signal(object, object, object)
41 result
= Signal(object)
43 def __init__(self
, opts
, parent
):
44 QtCore
.QThread
.__init
__(self
, parent
)
48 branch
= self
.opts
.branch
49 revision
= self
.opts
.revision
50 reset
= self
.opts
.reset
51 checkout
= self
.opts
.checkout
52 track
= self
.opts
.track
53 context
= self
.opts
.context
59 if track
and '/' in revision
:
60 remote
= revision
.split('/', 1)[0]
61 status
, out
, err
= git
.fetch(remote
)
62 self
.command
.emit(status
, out
, err
)
63 results
.append(('fetch', status
, out
, err
))
66 status
, out
, err
= model
.create_branch(
67 branch
, revision
, force
=reset
, track
=track
69 self
.command
.emit(status
, out
, err
)
71 results
.append(('branch', status
, out
, err
))
72 if status
== 0 and checkout
:
73 status
, out
, err
= git
.checkout(branch
)
74 self
.command
.emit(status
, out
, err
)
75 results
.append(('checkout', status
, out
, err
))
78 self
.result
.emit(results
)
81 class CreateBranchDialog(standard
.Dialog
):
82 """A dialog for creating branches."""
84 def __init__(self
, context
, parent
=None):
85 standard
.Dialog
.__init
__(self
, parent
=parent
)
86 self
.setWindowTitle(N_('Create Branch'))
87 if parent
is not None:
88 self
.setWindowModality(Qt
.WindowModal
)
90 self
.context
= context
91 self
.model
= context
.model
92 self
.opts
= CreateOpts(context
)
93 self
.thread
= CreateThread(self
.opts
, self
)
97 self
.branch_name_label
= QtWidgets
.QLabel()
98 self
.branch_name_label
.setText(N_('Branch Name'))
100 self
.branch_name
= completion
.GitCreateBranchLineEdit(context
)
101 self
.branch_validator
= completion
.BranchValidator(
102 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
)
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'), checked
=True)
125 self
.reset_radio
= qtutils
.radio(text
=N_('Reset'))
127 text
= N_('Fetch Tracking Branch')
128 self
.fetch_checkbox
= qtutils
.checkbox(text
=text
, checked
=True)
130 text
= N_('Checkout After Creation')
131 self
.checkout_checkbox
= qtutils
.checkbox(text
=text
, checked
=True)
133 icon
= icons
.branch()
134 self
.create_button
= qtutils
.create_button(
135 text
=N_('Create Branch'), icon
=icon
, default
=True
137 self
.close_button
= qtutils
.close_button()
139 self
.options_checkbox_layout
= qtutils
.hbox(
143 self
.checkout_checkbox
,
147 self
.branch_name_layout
= qtutils
.hbox(
148 defs
.margin
, defs
.spacing
, self
.branch_name_label
, self
.branch_name
151 self
.rev_radio_group
= qtutils
.buttongroup(
152 self
.local_radio
, self
.remote_radio
, self
.tag_radio
155 self
.rev_radio_layout
= qtutils
.hbox(
164 self
.rev_start_textinput_layout
= qtutils
.hbox(
165 defs
.no_margin
, defs
.spacing
, self
.rev_label
, defs
.spacing
, self
.revision
168 self
.rev_start_layout
= qtutils
.vbox(
171 self
.rev_radio_layout
,
173 self
.rev_start_textinput_layout
,
176 self
.options_radio_group
= qtutils
.buttongroup(
177 self
.no_update_radio
, self
.ffwd_only_radio
, self
.reset_radio
180 self
.options_radio_layout
= qtutils
.hbox(
183 self
.update_existing_label
,
184 self
.no_update_radio
,
185 self
.ffwd_only_radio
,
190 self
.buttons_layout
= qtutils
.hbox(
198 self
.main_layout
= qtutils
.vbox(
201 self
.branch_name_layout
,
202 self
.rev_start_layout
,
204 self
.options_radio_layout
,
205 self
.options_checkbox_layout
,
208 self
.setLayout(self
.main_layout
)
210 qtutils
.add_close_action(self
)
211 qtutils
.connect_button(self
.close_button
, self
.close
)
212 qtutils
.connect_button(self
.create_button
, self
.create_branch
)
213 qtutils
.connect_toggle(self
.local_radio
, self
.display_model
)
214 qtutils
.connect_toggle(self
.remote_radio
, self
.display_model
)
215 qtutils
.connect_toggle(self
.tag_radio
, self
.display_model
)
217 branches
= self
.branch_list
218 # pylint: disable=no-member
219 branches
.itemSelectionChanged
.connect(self
.branch_item_changed
)
222 thread
.command
.connect(Interaction
.log_status
, type=Qt
.QueuedConnection
)
223 thread
.result
.connect(self
.thread_result
, type=Qt
.QueuedConnection
)
225 self
.init_size(settings
=context
.settings
, parent
=parent
)
228 def set_revision(self
, revision
):
229 self
.revision
.setText(revision
)
232 self
.opts
.revision
= get(self
.revision
)
233 self
.opts
.branch
= get(self
.branch_name
)
234 self
.opts
.checkout
= get(self
.checkout_checkbox
)
235 self
.opts
.reset
= get(self
.reset_radio
)
236 self
.opts
.fetch
= get(self
.fetch_checkbox
)
237 self
.opts
.track
= get(self
.remote_radio
)
239 def create_branch(self
):
240 """Creates a branch; called by the "Create Branch" button"""
241 context
= self
.context
243 revision
= self
.opts
.revision
244 branch
= self
.opts
.branch
245 no_update
= get(self
.no_update_radio
)
246 ffwd_only
= get(self
.ffwd_only_radio
)
247 existing_branches
= gitcmds
.branch_list(context
)
250 if not branch
or not revision
:
251 Interaction
.critical(
253 N_('Please provide both a branch ' 'name and revision expression.'),
256 if branch
in existing_branches
:
258 msg
= N_('Branch "%s" already exists.') % branch
259 Interaction
.critical(N_('Branch Exists'), msg
)
261 # Whether we should prompt the user for lost commits
262 commits
= gitcmds
.rev_list_range(context
, revision
, branch
)
263 check_branch
= bool(commits
)
267 'Resetting "%(branch)s" to "%(revision)s" ' 'will lose commits.'
268 ) % dict(branch
=branch
, revision
=revision
)
270 Interaction
.critical(N_('Branch Exists'), msg
)
273 for idx
, commit
in enumerate(commits
):
274 subject
= commit
[1][0 : min(len(commit
[1]), 16)]
275 if len(subject
) < len(commit
[1]):
277 lines
.append('\t' + commit
[0][:8] + '\t' + subject
)
279 skip
= len(commits
) - 5
280 lines
.append('\t(%s)' % (N_('%d skipped') % skip
))
282 line
= N_('Recovering lost commits may not be easy.')
285 info_text
= N_('Reset "%(branch)s" to "%(revision)s"?') % dict(
286 branch
=branch
, revision
=revision
289 if not Interaction
.confirm(
299 title
= N_('Create Branch')
300 label
= N_('Updating')
301 self
.progress
= standard
.progress(title
, label
, self
)
305 def thread_result(self
, results
):
309 for (cmd
, status
, _
, _
) in results
:
311 Interaction
.critical(
312 N_('Error Creating Branch'),
314 N_('"%(command)s" returned exit status "%(status)d"')
315 % dict(command
='git ' + cmd
, status
=status
)
322 # pylint: disable=unused-argument
323 def branch_item_changed(self
, *rest
):
324 """This callback is called when the branch selection changes"""
325 # When the branch selection changes then we should update
326 # the "Revision Expression" accordingly.
327 qlist
= self
.branch_list
328 remote_branch
= qtutils
.selected_item(qlist
, self
.branch_sources())
329 if not remote_branch
:
331 # Update the model with the selection
332 self
.revision
.setText(remote_branch
)
334 # Set the branch field if we're branching from a remote branch.
335 if not get(self
.remote_radio
):
337 branch
= gitcmds
.strip_remote(self
.model
.remotes
, remote_branch
)
340 # Signal that we've clicked on a remote branch
341 self
.branch_name
.set_value(branch
)
343 def display_model(self
):
344 """Sets the branch list to the available branches"""
345 branches
= self
.branch_sources()
346 qtutils
.set_items(self
.branch_list
, branches
)
348 def branch_sources(self
):
349 """Get the list of items for populating the branch root list."""
350 if get(self
.local_radio
):
351 value
= self
.model
.local_branches
352 elif get(self
.remote_radio
):
353 value
= self
.model
.remote_branches
354 elif get(self
.tag_radio
):
355 value
= self
.model
.tags
361 self
.branch_name
.dispose()
362 self
.revision
.dispose()