stash: pylint updates
[git-cola.git] / cola / widgets / stash.py
blobd84435b4f0855b02567c55dce104afebeb2c7c79
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
7 from ..i18n import N_
8 from ..interaction import Interaction
9 from ..models import stash
10 from ..qtutils import get
11 from .. import cmds
12 from .. import icons
13 from .. import qtutils
14 from .. import utils
15 from . import defs
16 from . import diff
17 from . import standard
20 def view(context, show=True):
21 """Launches a stash dialog using the provided model + view
22 """
23 model = stash.StashModel(context)
24 stash_view = StashView(context, model, parent=qtutils.active_window())
25 if show:
26 stash_view.show()
27 stash_view.raise_()
28 return stash_view
31 class StashView(standard.Dialog):
33 def __init__(self, context, model, parent=None):
34 standard.Dialog.__init__(self, parent=parent)
35 self.context = context
36 self.model = model
37 self.stashes = []
38 self.revids = []
39 self.names = []
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(
49 text=N_('Apply'),
50 tooltip=N_('Apply the selected stash'),
51 icon=icons.ok())
53 self.button_save = qtutils.create_button(
54 text=N_('Save'),
55 tooltip=N_('Save modified state to new stash'),
56 icon=icons.save(), default=True)
58 self.button_drop = qtutils.create_button(
59 text=N_('Drop'),
60 tooltip=N_('Drop the selected stash'),
61 icon=icons.discard())
63 self.button_pop = qtutils.create_button(
64 text=N_('Pop'),
65 tooltip=N_('Apply and drop the selected stash (git stash pop)'),
66 icon=icons.discard())
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'))
77 # Arrange layouts
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,
84 self.button_close,
85 qtutils.STRETCH,
86 self.stash_index,
87 self.keep_index,
88 self.button_save,
89 self.button_apply,
90 self.button_pop,
91 self.button_drop)
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)
116 self.reject()
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):
121 if clicked:
122 self.keep_index.setChecked(False)
124 def keep_index_clicked(self, clicked):
125 if 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()
144 if not selection:
145 return
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
165 self.revids = revids
166 self.names = names
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)
180 def stash_pop(self):
181 self.stash_apply(pop=True)
183 def stash_apply(self, pop=False):
184 """Applies the currently selected stash
186 selection = self.selected_stash()
187 if not selection:
188 return
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'),
203 parent=self)
204 if not ok or not stash_name:
205 return
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)
212 return
213 context = self.context
214 keep_index = get(self.keep_index)
215 stash_index = get(self.stash_index)
216 if stash_index:
217 cmds.do(stash.StashIndex, context, stash_name)
218 else:
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()
227 if not selection:
228 return
229 if not Interaction.confirm(
230 N_('Drop Stash?'),
231 N_('Recovering a dropped stash is not possible.'),
232 N_('Drop the "%s" stash?') % name,
233 N_('Drop Stash'),
234 default=True, icon=icons.discard()):
235 return
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)
246 return state
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)
255 try:
256 self.splitter.setSizes(state['sizes'])
257 except (KeyError, ValueError, AttributeError):
258 pass
259 return result