1 """Widgets for manipulating git stashes"""
2 from __future__
import division
, absolute_import
, unicode_literals
4 from qtpy
import QtCore
5 from qtpy
.QtCore
import Qt
8 from ..interaction
import Interaction
9 from ..models
import stash
10 from ..qtutils
import get
13 from .. import qtutils
17 from . import standard
20 def view(context
, show
=True):
21 """Launches a stash dialog using the provided model + view
23 model
= stash
.StashModel(context
)
24 stash_view
= StashView(context
, model
, parent
=qtutils
.active_window())
31 class StashView(standard
.Dialog
):
33 def __init__(self
, context
, model
, parent
=None):
34 standard
.Dialog
.__init
__(self
, parent
=parent
)
35 self
.context
= context
41 self
.setWindowTitle(N_('Stash'))
42 if parent
is not None:
43 self
.setWindowModality(Qt
.WindowModal
)
45 self
.stash_list
= standard
.ListWidget(parent
=self
)
46 self
.stash_text
= diff
.DiffTextEdit(context
, self
)
48 self
.button_apply
= qtutils
.create_button(
50 tooltip
=N_('Apply the selected stash'),
53 self
.button_save
= qtutils
.create_button(
55 tooltip
=N_('Save modified state to new stash'),
56 icon
=icons
.save(), default
=True)
58 self
.button_drop
= qtutils
.create_button(
60 tooltip
=N_('Drop the selected stash'),
63 self
.button_pop
= qtutils
.create_button(
65 tooltip
=N_('Apply and drop the selected stash (git stash pop)'),
68 self
.button_close
= qtutils
.close_button()
70 self
.keep_index
= qtutils
.checkbox(
71 text
=N_('Keep Index'), checked
=True,
72 tooltip
=N_('Stash unstaged changes only, keeping staged changes'))
74 self
.stash_index
= qtutils
.checkbox(
75 text
=N_('Stash Index'), tooltip
=N_('Stash staged changes only'))
78 self
.splitter
= qtutils
.splitter(Qt
.Horizontal
,
79 self
.stash_list
, self
.stash_text
)
80 self
.splitter
.setChildrenCollapsible(False)
82 self
.btn_layt
= qtutils
.hbox(
83 defs
.no_margin
, defs
.button_spacing
,
93 self
.main_layt
= qtutils
.vbox(defs
.margin
, defs
.spacing
,
94 self
.splitter
, self
.btn_layt
)
95 self
.setLayout(self
.main_layt
)
96 self
.splitter
.setSizes([self
.width()//3, self
.width()*2//3])
98 self
.stash_list
.itemSelectionChanged
.connect(self
.item_selected
)
100 qtutils
.connect_button(self
.button_save
, self
.stash_save
)
101 qtutils
.connect_button(self
.button_apply
, self
.stash_apply
)
102 qtutils
.connect_button(self
.button_pop
, self
.stash_pop
)
103 qtutils
.connect_button(self
.button_drop
, self
.stash_drop
)
104 qtutils
.connect_button(self
.button_close
, self
.close_and_rescan
)
106 qtutils
.connect_checkbox(self
.stash_index
, self
.stash_index_clicked
)
107 qtutils
.connect_checkbox(self
.keep_index
, self
.keep_index_clicked
)
109 self
.init_size(parent
=parent
)
111 self
.update_from_model()
112 self
.update_actions()
114 def close_and_rescan(self
):
115 cmds
.do(cmds
.Rescan
, self
.context
)
118 # "stash" and "keep" index are mutually disable, but we don't
119 # want a radio button because we'd have to add a 3rd "default" option.
120 def stash_index_clicked(self
, clicked
):
122 self
.keep_index
.setChecked(False)
124 def keep_index_clicked(self
, clicked
):
126 self
.stash_index
.setChecked(False)
128 def selected_stash(self
):
129 """Returns the stash name of the currently selected stash
131 list_widget
= self
.stash_list
132 stash_list
= self
.revids
133 return qtutils
.selected_item(list_widget
, stash_list
)
135 def selected_name(self
):
136 list_widget
= self
.stash_list
137 stash_list
= self
.names
138 return qtutils
.selected_item(list_widget
, stash_list
)
140 def item_selected(self
):
141 """Shows the current stash in the main view."""
142 self
.update_actions()
143 selection
= self
.selected_stash()
146 diff_text
= self
.model
.stash_diff(selection
)
147 self
.stash_text
.setPlainText(diff_text
)
149 def update_actions(self
):
150 is_staged
= self
.model
.is_staged()
151 is_changed
= self
.model
.is_changed()
152 is_selected
= bool(self
.selected_stash())
153 self
.stash_index
.setEnabled(is_staged
)
154 self
.keep_index
.setEnabled(is_changed
)
155 self
.button_save
.setEnabled(is_changed
)
156 self
.button_apply
.setEnabled(is_selected
)
157 self
.button_drop
.setEnabled(is_selected
)
158 self
.button_pop
.setEnabled(is_selected
)
160 def update_from_model(self
):
161 """Initiates git queries on the model and updates the view
163 stashes
, revids
, names
= self
.model
.stash_info()
164 self
.stashes
= stashes
168 self
.stash_list
.clear()
169 self
.stash_list
.addItems(self
.stashes
)
170 if self
.stash_list
.count() > 0:
171 item
= self
.stash_list
.item(0)
172 self
.stash_list
.setCurrentItem(item
)
174 # "Stash Index" depends on staged changes, so disable this option
175 # if there are no staged changes.
176 is_staged
= self
.model
.is_staged()
177 if get(self
.stash_index
) and not is_staged
:
178 self
.stash_index
.setChecked(False)
181 self
.stash_apply(pop
=True)
183 def stash_apply(self
, pop
=False):
184 """Applies the currently selected stash
186 selection
= self
.selected_stash()
189 context
= self
.context
190 index
= get(self
.keep_index
)
191 cmds
.do(stash
.ApplyStash
, context
, selection
, index
, pop
)
192 QtCore
.QTimer
.singleShot(1, self
.accept
)
194 def stash_save(self
):
195 """Saves the worktree in a stash
197 This prompts the user for a stash name and creates
198 a git stash named accordingly.
201 stash_name
, ok
= qtutils
.prompt(
202 N_('Enter a name for the stash'), title
=N_('Save Stash'),
204 if not ok
or not stash_name
:
206 # Sanitize the stash name
207 stash_name
= utils
.sanitize(stash_name
)
208 if stash_name
in self
.names
:
209 Interaction
.critical(
210 N_('Error: Stash exists'),
211 N_('A stash named "%s" already exists') % stash_name
)
213 context
= self
.context
214 keep_index
= get(self
.keep_index
)
215 stash_index
= get(self
.stash_index
)
217 cmds
.do(stash
.StashIndex
, context
, stash_name
)
219 cmds
.do(stash
.SaveStash
, context
, stash_name
, keep_index
)
220 QtCore
.QTimer
.singleShot(1, self
.accept
)
222 def stash_drop(self
):
223 """Drops the currently selected stash
225 selection
= self
.selected_stash()
226 name
= self
.selected_name()
229 if not Interaction
.confirm(
231 N_('Recovering a dropped stash is not possible.'),
232 N_('Drop the "%s" stash?') % name
,
234 default
=True, icon
=icons
.discard()):
236 cmds
.do(stash
.DropStash
, self
.context
, selection
)
237 self
.update_from_model()
238 self
.stash_text
.setPlainText('')
240 def export_state(self
):
241 """Export persistent settings"""
242 state
= super(StashView
, self
).export_state()
243 state
['keep_index'] = get(self
.keep_index
)
244 state
['stash_index'] = get(self
.stash_index
)
245 state
['sizes'] = get(self
.splitter
)
248 def apply_state(self
, state
):
249 """Apply persistent settings"""
250 result
= super(StashView
, self
).apply_state(state
)
251 keep_index
= bool(state
.get('keep_index', True))
252 stash_index
= bool(state
.get('stash_index', False))
253 self
.keep_index
.setChecked(keep_index
)
254 self
.stash_index
.setChecked(stash_index
)
256 self
.splitter
.setSizes(state
['sizes'])
257 except (KeyError, ValueError, AttributeError):