1 """This view provides the main git-cola user interface.
4 from PyQt4
import QtGui
5 from PyQt4
import QtCore
6 from PyQt4
.QtCore
import Qt
7 from PyQt4
.QtCore
import SIGNAL
9 from cola
import qtutils
10 from cola
.views
.syntax
import DiffSyntaxHighlighter
11 from cola
.views
.mainwindow
import MainWindow
13 class MainView(MainWindow
):
14 """The main cola interface."""
22 def __init__(self
, parent
=None):
23 MainWindow
.__init
__(self
, parent
)
24 self
.amend_is_checked
= self
.amend_radio
.isChecked
25 self
.action_undo
= self
.commitmsg
.undo
26 self
.action_redo
= self
.commitmsg
.redo
27 self
.action_paste
= self
.commitmsg
.paste
28 self
.action_select_all
= self
.commitmsg
.selectAll
30 # Qt does not support noun/verbs
31 self
.commit_button
.setText(qtutils
.tr('Commit@@verb'))
32 self
.commit_menu
.setTitle(qtutils
.tr('Commit@@verb'))
34 # Default to creating a new commit(i.e. not an amend commit)
35 self
.new_commit_radio
.setChecked(True)
37 # Diff/patch syntax highlighter
38 self
.syntax
= DiffSyntaxHighlighter(self
.display_text
.document())
40 # Display the current column
41 self
.connect(self
.commitmsg
,
42 SIGNAL('cursorPositionChanged()'),
43 self
.show_current_column
)
45 # Initialize the seen tree widget indexes
46 self
._seen
_indexes
= set()
48 # Initialize the GUI to show 'Column: 00'
49 self
.show_current_column()
51 # Internal field used by import/export_state().
52 # Change this whenever dockwidgets are removed.
53 self
._widget
_version
= 1
55 def set_staged(self
, items
, check
=True):
56 """Adds items to the 'Staged' subtree."""
57 self
._set
_subtree
(items
, self
.IDX_STAGED
, staged
=True, check
=check
)
59 def set_modified(self
, items
):
60 """Adds items to the 'Modified' subtree."""
61 self
._set
_subtree
(items
, self
.IDX_MODIFIED
)
63 def set_unmerged(self
, items
):
64 """Adds items to the 'Unmerged' subtree."""
65 self
._set
_subtree
(items
, self
.IDX_UNMERGED
)
67 def set_untracked(self
, items
):
68 """Adds items to the 'Untracked' subtree."""
69 self
._set
_subtree
(items
, self
.IDX_UNTRACKED
)
71 def _set_subtree(self
, items
, idx
,
72 staged
=False, untracked
=False, check
=True):
73 parent
= self
.status_tree
.topLevelItem(idx
)
76 treeitem
= qtutils
.create_treeitem(item
,
80 parent
.addChild(treeitem
)
81 if idx
not in self
._seen
_indexes
and items
:
82 self
._seen
_indexes
.add(idx
)
85 self
.status_tree
.setItemHidden(parent
, False)
87 self
.status_tree
.setItemHidden(parent
, True)
89 def set_display(self
, text
):
90 """Set the diff text display."""
92 self
.display_text
.setText(text
)
94 def expand_status(self
):
95 for idx
in xrange(0, self
.IDX_END
):
96 item
= self
.status_tree
.topLevelItem(idx
)
98 self
.status_tree
.expandItem(item
)
100 def index_for_item(self
, item
):
101 """Given an item, returns the index of the item.
102 The indexes for unstaged items are grouped such that
103 the index of unmerged[1] = len(modified) + 1, etc.
107 parent
= item
.parent()
110 tree
= self
.status_tree
111 pidx
= tree
.indexOfTopLevelItem(parent
)
112 if pidx
== self
.IDX_STAGED
:
113 return True, parent
.indexOfChild(item
)
114 elif pidx
== self
.IDX_MODIFIED
:
115 return False, parent
.indexOfChild(item
)
117 count
= tree
.topLevelItem(self
.IDX_MODIFIED
).childCount()
118 if pidx
== self
.IDX_UNMERGED
:
119 return False, count
+ parent
.indexOfChild(item
)
121 count
+= tree
.topLevelItem(self
.IDX_UNMERGED
).childCount()
122 if pidx
== self
.IDX_UNTRACKED
:
123 return False, count
+ parent
.indexOfChild(item
)
128 tree
= self
.status_tree
129 item
= tree
.currentItem()
132 parent
= item
.parent()
136 idx
= parent
.indexOfChild(item
)
137 pidx
= tree
.indexOfTopLevelItem(parent
)
139 if pidx
== self
.IDX_STAGED
or pidx
== self
.IDX_MODIFIED
:
140 return idx
, tree
.isItemSelected(item
)
142 elif pidx
== self
.IDX_UNMERGED
:
143 num_modified
= tree
.topLevelItem(self
.IDX_MODIFIED
).childCount()
144 return idx
+ num_modified
, tree
.isItemSelected(item
)
146 elif pidx
== self
.IDX_UNTRACKED
:
147 num_modified
= tree
.topLevelItem(self
.IDX_MODIFIED
).childCount()
148 num_unmerged
= tree
.topLevelItem(self
.IDX_UNMERGED
).childCount()
149 return idx
+ num_modified
+ num_unmerged
, tree
.isItemSelected(item
)
152 def staged_item(self
, itemidx
):
153 return self
._subtree
_item
(self
.IDX_STAGED
, itemidx
)
155 def modified_item(self
, itemidx
):
156 return self
._subtree
_item
(self
.IDX_MODIFIED
, itemidx
)
158 def unstaged_item(self
, itemidx
):
159 tree
= self
.status_tree
161 item
= tree
.topLevelItem(self
.IDX_MODIFIED
)
162 count
= item
.childCount()
164 return item
.child(itemidx
)
166 item
= tree
.topLevelItem(self
.IDX_UNMERGED
)
167 count
+= item
.childCount()
169 return item
.child(itemidx
)
171 item
= tree
.topLevelItem(self
.IDX_UNTRACKED
)
172 count
+= item
.childCount()
174 return item
.child(itemidx
)
178 def _subtree_item(self
, idx
, itemidx
):
179 parent
= self
.status_tree
.topLevelItem(idx
)
180 return parent
.child(itemidx
)
182 def unstaged(self
, items
):
183 tree
= self
.status_tree
184 num_modified
= tree
.topLevelItem(self
.IDX_MODIFIED
).childCount()
185 num_unmerged
= tree
.topLevelItem(self
.IDX_UNMERGED
).childCount()
186 modified
= self
.modified(items
)
187 unmerged
= self
.unmerged(items
[num_modified
:])
188 untracked
= self
.untracked(items
[num_modified
+num_unmerged
:])
189 return modified
+ unmerged
+ untracked
191 def staged(self
, items
):
192 return self
._subtree
_selection
(self
.IDX_STAGED
, items
)
194 def modified(self
, items
):
195 return self
._subtree
_selection
(self
.IDX_MODIFIED
, items
)
197 def unmerged(self
, items
):
198 return self
._subtree
_selection
(self
.IDX_UNMERGED
, items
)
200 def untracked(self
, items
):
201 return self
._subtree
_selection
(self
.IDX_UNTRACKED
, items
)
203 def _subtree_selection(self
, idx
, items
):
204 item
= self
.status_tree
.topLevelItem(idx
)
205 return qtutils
.tree_selection(item
, items
)
208 """Override base show to set icons and expand top-level items."""
209 result
= MainWindow
.show(self
)
210 staged
= self
.status_tree
.topLevelItem(self
.IDX_STAGED
)
211 staged
.setIcon(0, qtutils
.icon('plus.png'))
213 modified
= self
.status_tree
.topLevelItem(self
.IDX_MODIFIED
)
214 modified
.setIcon(0, qtutils
.icon('modified.png'))
216 unmerged
= self
.status_tree
.topLevelItem(self
.IDX_UNMERGED
)
217 unmerged
.setIcon(0, qtutils
.icon('unmerged.png'))
219 untracked
= self
.status_tree
.topLevelItem(self
.IDX_UNTRACKED
)
220 untracked
.setIcon(0, qtutils
.icon('untracked.png'))
223 qtutils
.set_diff_font(self
.display_text
)
225 self
.status_tree
.expandToDepth(0)
228 def enter_diff_mode(self
, text
):
230 Enter diff mode; changes the 'Staged' header to 'Changed'.
232 This also enables the 'Exit <Mode> Mode' button.
233 `text` is the message displayed on the button.
236 staged
= self
.status_tree
.topLevelItem(self
.IDX_STAGED
)
237 staged
.setText(0, self
.tr('Changed'))
238 self
.alt_button
.setText(self
.tr(text
))
239 self
.alt_button
.show()
241 def exit_diff_mode(self
):
243 Exit diff mode; changes the 'Changed' header to 'Staged'.
245 This also hides the 'Exit Diff Mode' button.
248 staged
= self
.status_tree
.topLevelItem(self
.IDX_STAGED
)
249 staged
.setText(0, self
.tr('Staged'))
250 self
.alt_button
.hide()
253 def action_cut(self
):
257 def action_copy(self
):
258 cursor
= self
.commitmsg
.textCursor()
259 selection
= cursor
.selection().toPlainText()
260 qtutils
.set_clipboard(selection
)
262 def action_delete(self
):
263 self
.commitmsg
.textCursor().removeSelectedText()
265 def reset_checkboxes(self
):
266 self
.new_commit_radio
.setChecked(True)
267 self
.amend_radio
.setChecked(False)
269 def reset_display(self
):
272 def copy_display(self
):
273 cursor
= self
.display_text
.textCursor()
274 selection
= cursor
.selection().toPlainText()
275 qtutils
.set_clipboard(selection
)
277 def diff_selection(self
):
278 cursor
= self
.display_text
.textCursor()
279 offset
= cursor
.position()
280 selection
= unicode(cursor
.selection().toPlainText())
281 return offset
, selection
283 def tree_selection(self
):
284 """Returns a list of (category, row) representing the tree selection."""
285 selected
= self
.status_tree
.selectedIndexes()
288 if idx
.parent().isValid():
289 parent_idx
= idx
.parent()
290 entry
= (parent_idx
.row(), idx
.row())
292 entry
= (-1, idx
.row())
296 def selected_line(self
):
297 cursor
= self
.display_text
.textCursor()
298 offset
= cursor
.position()
299 contents
= unicode(self
.display_text
.toPlainText())
301 and contents
[offset
-1]
302 and contents
[offset
-1] != '\n'):
304 data
= contents
[offset
:]
306 line
, rest
= data
.split('\n', 1)
311 def display(self
, text
):
312 self
.set_display(text
)
314 def show_current_column(self
):
315 cursor
= self
.commitmsg
.textCursor()
316 colnum
= cursor
.columnNumber()
317 self
.column_label
.setText('Column: %02d' % colnum
)
319 def import_state(self
, state
):
320 """Imports data for save/restore"""
321 MainWindow
.import_state(self
, state
)
322 # Restore the dockwidget, etc. window state
323 if 'windowstate' in state
:
324 windowstate
= state
['windowstate']
325 self
.restoreState(QtCore
.QByteArray
.fromBase64(str(windowstate
)),
326 self
._widget
_version
)
328 def export_state(self
):
329 """Exports data for save/restore"""
330 state
= MainWindow
.export_state(self
)
331 # Save the window state
332 windowstate
= self
.saveState(self
._widget
_version
)
333 state
['windowstate'] = unicode(windowstate
.toBase64().data())