1 """This view provides the main git-cola user interface.
5 from PyQt4
import QtCore
6 from PyQt4
import QtGui
7 from PyQt4
.QtCore
import Qt
8 from PyQt4
.QtCore
import SIGNAL
12 from cola
import gitcmds
13 from cola
import guicmds
14 from cola
import gitcfg
15 from cola
import qtutils
16 from cola
import resources
17 from cola
import settings
18 from cola
import utils
19 from cola
import version
20 from cola
.bookmarks
import manage_bookmarks
21 from cola
.git
import git
22 from cola
.git
import STDOUT
23 from cola
.i18n
import N_
24 from cola
.interaction
import Interaction
25 from cola
.models
import prefs
26 from cola
.qtutils
import add_action
27 from cola
.qtutils
import add_action_bool
28 from cola
.qtutils
import connect_action
29 from cola
.qtutils
import connect_action_bool
30 from cola
.qtutils
import create_dock
31 from cola
.qtutils
import create_menu
32 from cola
.qtutils
import create_toolbutton
33 from cola
.qtutils
import options_icon
34 from cola
.widgets
import action
35 from cola
.widgets
import cfgactions
36 from cola
.widgets
import editremotes
37 from cola
.widgets
import remote
38 from cola
.widgets
.about
import launch_about_dialog
39 from cola
.widgets
.about
import show_shortcuts
40 from cola
.widgets
.archive
import GitArchiveDialog
41 from cola
.widgets
.browse
import worktree_browser
42 from cola
.widgets
.browse
import worktree_browser_widget
43 from cola
.widgets
.commitmsg
import CommitMessageEditor
44 from cola
.widgets
.compare
import compare_branches
45 from cola
.widgets
.createtag
import create_tag
46 from cola
.widgets
.createbranch
import create_new_branch
47 from cola
.widgets
.dag
import git_dag
48 from cola
.widgets
.diff
import DiffEditor
49 from cola
.widgets
.log
import LogWidget
50 from cola
.widgets
import merge
51 from cola
.widgets
.prefs
import preferences
52 from cola
.widgets
.recent
import browse_recent
53 from cola
.widgets
.status
import StatusWidget
54 from cola
.widgets
.search
import search
55 from cola
.widgets
.standard
import MainWindow
56 from cola
.widgets
.stash
import stash
59 class MainView(MainWindow
):
61 def __init__(self
, model
, parent
=None):
62 MainWindow
.__init
__(self
, parent
)
63 # Default size; this is thrown out when save/restore is used
66 self
.prefs_model
= prefs_model
= prefs
.PreferencesModel()
68 # The widget version is used by import/export_state().
69 # Change this whenever dockwidgets are removed.
70 self
.widget_version
= 2
72 # Keeps track of merge messages we've seen
73 self
.merge_message_hash
= ''
75 self
.setAcceptDrops(True)
76 self
.setAttribute(Qt
.WA_MacMetalStyle
)
78 cfg
= gitcfg
.instance()
79 self
.browser_dockable
= (cfg
.get('cola.browserdockable') or
80 cfg
.get('cola.classicdockable'))
81 if self
.browser_dockable
:
82 self
.browserdockwidget
= create_dock(N_('Browser'), self
)
83 self
.browserwidget
= worktree_browser_widget(self
)
84 self
.browserdockwidget
.setWidget(self
.browserwidget
)
87 self
.actionsdockwidget
= create_dock(N_('Actions'), self
)
88 self
.actionsdockwidgetcontents
= action
.ActionButtons(self
)
89 self
.actionsdockwidget
.setWidget(self
.actionsdockwidgetcontents
)
90 self
.actionsdockwidget
.toggleViewAction().setChecked(False)
91 self
.actionsdockwidget
.hide()
93 # "Repository Status" widget
94 self
.statuswidget
= StatusWidget(self
)
95 self
.statusdockwidget
= create_dock(N_('Status'), self
)
96 self
.statusdockwidget
.setWidget(self
.statuswidget
)
98 # "Commit Message Editor" widget
99 self
.position_label
= QtGui
.QLabel()
100 font
= qtutils
.default_monospace_font()
101 font
.setPointSize(int(font
.pointSize() * 0.8))
102 self
.position_label
.setFont(font
)
103 self
.commitdockwidget
= create_dock(N_('Commit'), self
)
104 titlebar
= self
.commitdockwidget
.titleBarWidget()
105 titlebar
.add_corner_widget(self
.position_label
)
107 self
.commitmsgeditor
= CommitMessageEditor(model
, self
)
108 self
.commitdockwidget
.setWidget(self
.commitmsgeditor
)
111 self
.logwidget
= LogWidget()
112 self
.logdockwidget
= create_dock(N_('Console'), self
)
113 self
.logdockwidget
.setWidget(self
.logwidget
)
114 self
.logdockwidget
.toggleViewAction().setChecked(False)
115 self
.logdockwidget
.hide()
117 # "Diff Viewer" widget
118 self
.diffdockwidget
= create_dock(N_('Diff'), self
)
119 self
.diffeditor
= DiffEditor(self
.diffdockwidget
)
120 self
.diffdockwidget
.setWidget(self
.diffeditor
)
122 # "Diff Options" tool menu
123 self
.diff_ignore_space_at_eol_action
= add_action(self
,
124 N_('Ignore changes in whitespace at EOL'),
125 self
._update
_diff
_opts
)
126 self
.diff_ignore_space_at_eol_action
.setCheckable(True)
128 self
.diff_ignore_space_change_action
= add_action(self
,
129 N_('Ignore changes in amount of whitespace'),
130 self
._update
_diff
_opts
)
131 self
.diff_ignore_space_change_action
.setCheckable(True)
133 self
.diff_ignore_all_space_action
= add_action(self
,
134 N_('Ignore all whitespace'),
135 self
._update
_diff
_opts
)
136 self
.diff_ignore_all_space_action
.setCheckable(True)
138 self
.diff_function_context_action
= add_action(self
,
139 N_('Show whole surrounding functions of changes'),
140 self
._update
_diff
_opts
)
141 self
.diff_function_context_action
.setCheckable(True)
143 self
.diffopts_button
= create_toolbutton(text
=N_('Options'),
145 tooltip
=N_('Diff Options'))
146 self
.diffopts_menu
= create_menu(N_('Diff Options'),
147 self
.diffopts_button
)
149 self
.diffopts_menu
.addAction(self
.diff_ignore_space_at_eol_action
)
150 self
.diffopts_menu
.addAction(self
.diff_ignore_space_change_action
)
151 self
.diffopts_menu
.addAction(self
.diff_ignore_all_space_action
)
152 self
.diffopts_menu
.addAction(self
.diff_function_context_action
)
153 self
.diffopts_button
.setMenu(self
.diffopts_menu
)
154 self
.diffopts_button
.setPopupMode(QtGui
.QToolButton
.InstantPopup
)
156 titlebar
= self
.diffdockwidget
.titleBarWidget()
157 titlebar
.add_corner_widget(self
.diffopts_button
)
160 self
.menu_unstage_all
= add_action(self
,
161 N_('Unstage All'), cmds
.run(cmds
.UnstageAll
))
162 self
.menu_unstage_all
.setIcon(qtutils
.icon('remove.svg'))
164 self
.menu_unstage_selected
= add_action(self
,
165 N_('Unstage From Commit'), cmds
.run(cmds
.UnstageSelected
))
166 self
.menu_unstage_selected
.setIcon(qtutils
.icon('remove.svg'))
168 self
.menu_show_diffstat
= add_action(self
,
169 N_('Diffstat'), cmds
.run(cmds
.Diffstat
), 'Alt+D')
171 self
.menu_stage_modified
= add_action(self
,
172 N_('Stage Changed Files To Commit'),
173 cmds
.run(cmds
.StageModified
), 'Alt+A')
174 self
.menu_stage_modified
.setIcon(qtutils
.icon('add.svg'))
176 self
.menu_stage_untracked
= add_action(self
,
177 N_('Stage All Untracked'),
178 cmds
.run(cmds
.StageUntracked
), 'Alt+U')
179 self
.menu_stage_untracked
.setIcon(qtutils
.icon('add.svg'))
181 self
.menu_export_patches
= add_action(self
,
182 N_('Export Patches...'), guicmds
.export_patches
, 'Alt+E')
184 self
.new_repository
= add_action(self
,
185 N_('New Repository...'), guicmds
.open_new_repo
)
186 self
.new_repository
.setIcon(qtutils
.new_icon())
188 self
.menu_preferences
= add_action(self
,
189 N_('Preferences'), self
.preferences
,
190 QtGui
.QKeySequence
.Preferences
, 'Ctrl+O')
192 self
.menu_edit_remotes
= add_action(self
,
193 N_('Edit Remotes...'), lambda: editremotes
.edit().exec_())
194 self
.menu_rescan
= add_action(self
,
196 cmds
.run(cmds
.Refresh
),
197 cmds
.Refresh
.SHORTCUT
)
198 self
.menu_rescan
.setIcon(qtutils
.reload_icon())
200 self
.menu_browse_recent
= add_action(self
,
201 N_('Recently Modified Files...'),
202 browse_recent
, 'Shift+Ctrl+E')
204 self
.menu_cherry_pick
= add_action(self
,
205 N_('Cherry-Pick...'),
206 guicmds
.cherry_pick
, 'Ctrl+P')
208 self
.menu_load_commitmsg
= add_action(self
,
209 N_('Load Commit Message...'), guicmds
.load_commitmsg
)
211 self
.menu_save_tarball
= add_action(self
,
212 N_('Save As Tarball/Zip...'), self
.save_archive
)
214 self
.menu_quit
= add_action(self
,
215 N_('Quit'), self
.close
, 'Ctrl+Q')
216 self
.menu_manage_bookmarks
= add_action(self
,
217 N_('Bookmarks...'), manage_bookmarks
)
218 self
.menu_grep
= add_action(self
,
219 N_('Grep'), guicmds
.grep
, 'Ctrl+G')
220 self
.menu_merge_local
= add_action(self
,
221 N_('Merge...'), merge
.local_merge
)
223 self
.menu_merge_abort
= add_action(self
,
224 N_('Abort Merge...'), merge
.abort_merge
)
226 self
.menu_fetch
= add_action(self
,
227 N_('Fetch...'), remote
.fetch
)
228 self
.menu_push
= add_action(self
,
229 N_('Push...'), remote
.push
)
230 self
.menu_pull
= add_action(self
,
231 N_('Pull...'), remote
.pull
)
233 self
.menu_open_repo
= add_action(self
,
234 N_('Open...'), guicmds
.open_repo
)
235 self
.menu_open_repo
.setIcon(qtutils
.open_icon())
237 self
.menu_stash
= add_action(self
,
238 N_('Stash...'), stash
, 'Alt+Shift+S')
240 self
.menu_clone_repo
= add_action(self
,
241 N_('Clone...'), guicmds
.clone_repo
)
242 self
.menu_clone_repo
.setIcon(qtutils
.git_icon())
244 self
.menu_help_docs
= add_action(self
,
245 N_('Documentation'), resources
.show_html_docs
,
246 QtGui
.QKeySequence
.HelpContents
)
248 self
.menu_help_shortcuts
= add_action(self
,
249 N_('Keyboard Shortcuts'),
251 QtCore
.Qt
.Key_Question
)
253 self
.menu_visualize_current
= add_action(self
,
254 N_('Visualize Current Branch...'),
255 cmds
.run(cmds
.VisualizeCurrent
))
256 self
.menu_visualize_all
= add_action(self
,
257 N_('Visualize All Branches...'),
258 cmds
.run(cmds
.VisualizeAll
))
259 self
.menu_search_commits
= add_action(self
,
260 N_('Search...'), search
)
261 self
.menu_browse_branch
= add_action(self
,
262 N_('Browse Current Branch...'), guicmds
.browse_current
)
263 self
.menu_browse_other_branch
= add_action(self
,
264 N_('Browse Other Branch...'), guicmds
.browse_other
)
265 self
.menu_load_commitmsg_template
= add_action(self
,
266 N_('Get Commit Message Template'),
267 cmds
.run(cmds
.LoadCommitMessageFromTemplate
))
268 self
.menu_help_about
= add_action(self
,
269 N_('About'), launch_about_dialog
)
271 self
.menu_diff_expression
= add_action(self
,
272 N_('Expression...'), guicmds
.diff_expression
)
273 self
.menu_branch_compare
= add_action(self
,
274 N_('Branches...'), compare_branches
)
276 self
.menu_create_tag
= add_action(self
,
277 N_('Create Tag...'), create_tag
)
279 self
.menu_create_branch
= add_action(self
,
280 N_('Create...'), create_new_branch
, 'Ctrl+B')
282 self
.menu_delete_branch
= add_action(self
,
283 N_('Delete...'), guicmds
.delete_branch
)
285 self
.menu_delete_remote_branch
= add_action(self
,
286 N_('Delete Remote Branch...'), guicmds
.delete_remote_branch
)
288 self
.menu_checkout_branch
= add_action(self
,
289 N_('Checkout...'), guicmds
.checkout_branch
, 'Alt+B')
290 self
.menu_branch_review
= add_action(self
,
291 N_('Review...'), guicmds
.review_branch
)
293 self
.menu_browse
= add_action(self
,
294 N_('Browser...'), worktree_browser
)
295 self
.menu_browse
.setIcon(qtutils
.git_icon())
297 self
.menu_dag
= add_action(self
,
298 N_('DAG...'), lambda: git_dag(self
.model
).show())
299 self
.menu_dag
.setIcon(qtutils
.git_icon())
301 self
.rebase_start_action
= add_action(self
,
302 N_('Start Interactive Rebase...'), self
.rebase_start
)
304 self
.rebase_edit_todo_action
= add_action(self
,
305 N_('Edit...'), self
.rebase_edit_todo
)
307 self
.rebase_continue_action
= add_action(self
,
308 N_('Continue'), self
.rebase_continue
)
310 self
.rebase_skip_action
= add_action(self
,
311 N_('Skip Current Patch'), self
.rebase_skip
)
313 self
.rebase_abort_action
= add_action(self
,
314 N_('Abort'), self
.rebase_abort
)
317 if not self
.browser_dockable
:
318 # These shortcuts conflict with those from the
319 # 'Browser' widget so don't register them when
320 # the browser is a dockable tool.
321 status_tree
= self
.statusdockwidget
.widget().tree
322 self
.addAction(status_tree
.up
)
323 self
.addAction(status_tree
.down
)
324 self
.addAction(status_tree
.process_selection
)
326 self
.lock_layout_action
= add_action_bool(self
,
327 N_('Lock Layout'), self
.set_lock_layout
, False)
329 # Create the application menu
330 self
.menubar
= QtGui
.QMenuBar(self
)
333 self
.file_menu
= create_menu(N_('File'), self
.menubar
)
334 self
.file_menu
.addAction(self
.new_repository
)
335 self
.file_menu
.addAction(self
.menu_open_repo
)
336 self
.menu_open_recent
= self
.file_menu
.addMenu(N_('Open Recent'))
337 self
.file_menu
.addSeparator()
338 self
.file_menu
.addAction(self
.menu_clone_repo
)
339 self
.file_menu
.addAction(self
.menu_manage_bookmarks
)
340 self
.file_menu
.addSeparator()
341 self
.file_menu
.addAction(self
.menu_edit_remotes
)
342 self
.file_menu
.addAction(self
.menu_rescan
)
343 self
.file_menu
.addSeparator()
344 self
.file_menu
.addAction(self
.menu_browse_recent
)
345 self
.file_menu
.addSeparator()
346 self
.file_menu
.addAction(self
.menu_load_commitmsg
)
347 self
.file_menu
.addAction(self
.menu_load_commitmsg_template
)
348 self
.file_menu
.addSeparator()
349 self
.file_menu
.addAction(self
.menu_save_tarball
)
350 self
.file_menu
.addAction(self
.menu_export_patches
)
351 self
.file_menu
.addSeparator()
352 self
.file_menu
.addAction(self
.menu_preferences
)
353 self
.file_menu
.addAction(self
.menu_quit
)
354 self
.menubar
.addAction(self
.file_menu
.menuAction())
357 self
.actions_menu
= create_menu(N_('Actions'), self
.menubar
)
358 self
.actions_menu
.addAction(self
.menu_fetch
)
359 self
.actions_menu
.addAction(self
.menu_push
)
360 self
.actions_menu
.addAction(self
.menu_pull
)
361 self
.actions_menu
.addAction(self
.menu_stash
)
362 self
.actions_menu
.addSeparator()
363 self
.actions_menu
.addAction(self
.menu_create_tag
)
364 self
.actions_menu
.addAction(self
.menu_cherry_pick
)
365 self
.actions_menu
.addAction(self
.menu_merge_local
)
366 self
.actions_menu
.addAction(self
.menu_merge_abort
)
367 self
.actions_menu
.addSeparator()
368 self
.actions_menu
.addAction(self
.menu_grep
)
369 self
.actions_menu
.addAction(self
.menu_search_commits
)
370 self
.menubar
.addAction(self
.actions_menu
.menuAction())
373 self
.commit_menu
= create_menu(N_('Index'), self
.menubar
)
374 self
.commit_menu
.setTitle(N_('Index'))
375 self
.commit_menu
.addAction(self
.menu_stage_modified
)
376 self
.commit_menu
.addAction(self
.menu_stage_untracked
)
377 self
.commit_menu
.addSeparator()
378 self
.commit_menu
.addAction(self
.menu_unstage_all
)
379 self
.commit_menu
.addAction(self
.menu_unstage_selected
)
380 self
.menubar
.addAction(self
.commit_menu
.menuAction())
383 self
.diff_menu
= create_menu(N_('Diff'), self
.menubar
)
384 self
.diff_menu
.addAction(self
.menu_diff_expression
)
385 self
.diff_menu
.addAction(self
.menu_branch_compare
)
386 self
.diff_menu
.addSeparator()
387 self
.diff_menu
.addAction(self
.menu_show_diffstat
)
388 self
.menubar
.addAction(self
.diff_menu
.menuAction())
391 self
.branch_menu
= create_menu(N_('Branch'), self
.menubar
)
392 self
.branch_menu
.addAction(self
.menu_branch_review
)
393 self
.branch_menu
.addSeparator()
394 self
.branch_menu
.addAction(self
.menu_create_branch
)
395 self
.branch_menu
.addAction(self
.menu_checkout_branch
)
396 self
.branch_menu
.addAction(self
.menu_delete_branch
)
397 self
.branch_menu
.addAction(self
.menu_delete_remote_branch
)
398 self
.branch_menu
.addSeparator()
399 self
.branch_menu
.addAction(self
.menu_browse_branch
)
400 self
.branch_menu
.addAction(self
.menu_browse_other_branch
)
401 self
.branch_menu
.addSeparator()
402 self
.branch_menu
.addAction(self
.menu_visualize_current
)
403 self
.branch_menu
.addAction(self
.menu_visualize_all
)
404 self
.menubar
.addAction(self
.branch_menu
.menuAction())
407 self
.rebase_menu
= create_menu(N_('Rebase'), self
.actions_menu
)
408 self
.rebase_menu
.addAction(self
.rebase_start_action
)
409 self
.rebase_menu
.addAction(self
.rebase_edit_todo_action
)
410 self
.rebase_menu
.addSeparator()
411 self
.rebase_menu
.addAction(self
.rebase_continue_action
)
412 self
.rebase_menu
.addAction(self
.rebase_skip_action
)
413 self
.rebase_menu
.addSeparator()
414 self
.rebase_menu
.addAction(self
.rebase_abort_action
)
415 self
.menubar
.addAction(self
.rebase_menu
.menuAction())
418 self
.view_menu
= create_menu(N_('View'), self
.menubar
)
419 self
.view_menu
.addAction(self
.menu_browse
)
420 self
.view_menu
.addAction(self
.menu_dag
)
421 self
.view_menu
.addSeparator()
422 if self
.browser_dockable
:
423 self
.view_menu
.addAction(self
.browserdockwidget
.toggleViewAction())
425 self
.setup_dockwidget_view_menu()
426 self
.view_menu
.addSeparator()
427 self
.view_menu
.addAction(self
.lock_layout_action
)
428 self
.menubar
.addAction(self
.view_menu
.menuAction())
431 self
.help_menu
= create_menu(N_('Help'), self
.menubar
)
432 self
.help_menu
.addAction(self
.menu_help_docs
)
433 self
.help_menu
.addAction(self
.menu_help_shortcuts
)
434 self
.help_menu
.addAction(self
.menu_help_about
)
435 self
.menubar
.addAction(self
.help_menu
.menuAction())
438 self
.setMenuBar(self
.menubar
)
440 # Arrange dock widgets
441 left
= Qt
.LeftDockWidgetArea
442 right
= Qt
.RightDockWidgetArea
443 bottom
= Qt
.BottomDockWidgetArea
445 self
.addDockWidget(left
, self
.commitdockwidget
)
446 if self
.browser_dockable
:
447 self
.addDockWidget(left
, self
.browserdockwidget
)
448 self
.tabifyDockWidget(self
.browserdockwidget
, self
.commitdockwidget
)
449 self
.addDockWidget(left
, self
.diffdockwidget
)
450 self
.addDockWidget(bottom
, self
.actionsdockwidget
)
451 self
.addDockWidget(bottom
, self
.logdockwidget
)
452 self
.tabifyDockWidget(self
.actionsdockwidget
, self
.logdockwidget
)
454 self
.addDockWidget(right
, self
.statusdockwidget
)
456 # Listen for model notifications
457 model
.add_observer(model
.message_updated
, self
._update
_view
)
459 prefs_model
.add_observer(prefs_model
.message_config_updated
,
460 self
._config
_updated
)
462 # Set a default value
463 self
.show_cursor_position(1, 0)
465 self
.connect(self
.menu_open_recent
, SIGNAL('aboutToShow()'),
466 self
.build_recent_menu
)
468 self
.connect(self
.commitmsgeditor
, SIGNAL('cursorPosition(int,int)'),
469 self
.show_cursor_position
)
470 self
.connect(self
, SIGNAL('update'), self
._update
_callback
)
471 self
.connect(self
, SIGNAL('install_config_actions'),
472 self
._install
_config
_actions
)
474 # Install .git-config-defined actions
475 self
._config
_task
= None
476 self
.install_config_actions()
478 # Restore saved settings
479 if not qtutils
.apply_state(self
):
480 self
.set_initial_size()
482 self
.statusdockwidget
.widget().setFocus()
484 # Route command output here
485 Interaction
.log_status
= self
.logwidget
.log_status
486 Interaction
.log
= self
.logwidget
.log
487 Interaction
.log(version
.git_version_str() + '\n' +
488 N_('git cola version %s') % version
.version())
490 def set_initial_size(self
):
491 self
.statuswidget
.set_initial_size()
492 self
.commitmsgeditor
.set_initial_size()
495 def closeEvent(self
, event
):
496 """Save state in the settings manager."""
497 commit_msg
= self
.commitmsgeditor
.commit_message(raw
=True)
498 self
.model
.save_commitmsg(commit_msg
)
499 MainWindow
.closeEvent(self
, event
)
501 def build_recent_menu(self
):
502 recent
= settings
.Settings().recent
503 menu
= self
.menu_open_recent
506 name
= os
.path
.basename(r
)
507 directory
= os
.path
.dirname(r
)
508 text
= '%s %s %s' % (name
, unichr(0x2192), directory
)
509 menu
.addAction(text
, cmds
.run(cmds
.OpenRepo
, r
))
512 mode
= property(lambda self
: self
.model
.mode
)
514 def _config_updated(self
, source
, config
, value
):
515 if config
== prefs
.FONTDIFF
:
518 if not font
.fromString(value
):
520 self
.logwidget
.setFont(font
)
521 self
.diffeditor
.setFont(font
)
522 self
.commitmsgeditor
.setFont(font
)
524 elif config
== prefs
.TABWIDTH
:
525 # variable-tab-width setting
526 self
.diffeditor
.set_tabwidth(value
)
527 self
.commitmsgeditor
.set_tabwidth(value
)
529 elif config
== prefs
.LINEBREAK
:
530 # enables automatic line breaks
531 self
.commitmsgeditor
.set_linebreak(value
)
533 elif config
== prefs
.TEXTWIDTH
:
534 # text width used for line wrapping
535 self
.commitmsgeditor
.set_textwidth(value
)
537 def install_config_actions(self
):
538 """Install .gitconfig-defined actions"""
539 self
._config
_task
= self
._start
_config
_actions
_task
()
541 def _start_config_actions_task(self
):
542 """Do the expensive "get_config_actions()" call in the background"""
543 class ConfigActionsTask(QtCore
.QRunnable
):
544 def __init__(self
, sender
):
545 QtCore
.QRunnable
.__init
__(self
)
546 self
._sender
= sender
548 names
= cfgactions
.get_config_actions()
549 self
._sender
.emit(SIGNAL('install_config_actions'), names
)
551 task
= ConfigActionsTask(self
)
552 QtCore
.QThreadPool
.globalInstance().start(task
)
555 def _install_config_actions(self
, names
):
556 """Install .gitconfig-defined actions"""
559 menu
= self
.actions_menu
562 menu
.addAction(name
, cmds
.run(cmds
.RunConfigAction
, name
))
564 def _update_view(self
):
565 self
.emit(SIGNAL('update'))
567 def _update_callback(self
):
568 """Update the title with the current branch and directory name."""
569 branch
= self
.model
.currentbranch
570 curdir
= core
.getcwd()
571 is_rebasing
= self
.model
.is_rebasing
573 msg
= N_('Repository: %s') % curdir
575 msg
+= N_('Branch: %s') % branch
578 msg
+= N_('This repository is currently being rebased.\n'
579 'Resolve conflicts, commit changes, and run:\n'
580 ' Rebase > Continue')
581 self
.commitdockwidget
.setToolTip(msg
)
585 alerts
.append(N_('Rebasing').upper())
586 if self
.mode
== self
.model
.mode_amend
:
587 alerts
.append(N_('Amending').upper())
591 title
= ('%s: %s %s%s' % (
594 alerts
and ((r
+' %s '+l
+' ') % ', '.join(alerts
)) or '',
595 self
.model
.git
.worktree()))
596 self
.setWindowTitle(title
)
597 self
.commitmsgeditor
.set_mode(self
.mode
)
598 self
.update_rebase_actions(is_rebasing
)
600 if not self
.model
.amending():
601 # Check if there's a message file in .git/
602 merge_msg_path
= gitcmds
.merge_message_path()
603 if merge_msg_path
is None:
605 merge_msg_hash
= utils
.checksum(merge_msg_path
)
606 if merge_msg_hash
== self
.merge_message_hash
:
608 self
.merge_message_hash
= merge_msg_hash
609 cmds
.do(cmds
.LoadCommitMessageFromFile
, merge_msg_path
)
611 def update_rebase_actions(self
, is_rebasing
):
612 can_rebase
= not is_rebasing
613 self
.rebase_start_action
.setEnabled(can_rebase
)
614 self
.rebase_edit_todo_action
.setEnabled(is_rebasing
)
615 self
.rebase_continue_action
.setEnabled(is_rebasing
)
616 self
.rebase_skip_action
.setEnabled(is_rebasing
)
617 self
.rebase_abort_action
.setEnabled(is_rebasing
)
619 def apply_state(self
, state
):
620 """Imports data for save/restore"""
621 result
= MainWindow
.apply_state(self
, state
)
622 self
.lock_layout_action
.setChecked(state
.get('lock_layout', False))
625 def setup_dockwidget_view_menu(self
):
626 # Hotkeys for toggling the dock widgets
627 if utils
.is_darwin():
632 (optkey
+ '+0', self
.logdockwidget
),
633 (optkey
+ '+1', self
.commitdockwidget
),
634 (optkey
+ '+2', self
.statusdockwidget
),
635 (optkey
+ '+3', self
.diffdockwidget
),
636 (optkey
+ '+4', self
.actionsdockwidget
),
638 for shortcut
, dockwidget
in dockwidgets
:
639 # Associate the action with the shortcut
640 toggleview
= dockwidget
.toggleViewAction()
641 toggleview
.setShortcut(shortcut
)
642 self
.view_menu
.addAction(toggleview
)
643 def showdock(show
, dockwidget
=dockwidget
):
646 dockwidget
.widget().setFocus()
649 self
.addAction(toggleview
)
650 connect_action_bool(toggleview
, showdock
)
652 # Create a new shortcut Shift+<shortcut> that gives focus
653 toggleview
= QtGui
.QAction(self
)
654 toggleview
.setShortcut('Shift+' + shortcut
)
655 def focusdock(dockwidget
=dockwidget
, showdock
=showdock
):
656 if dockwidget
.toggleViewAction().isChecked():
659 dockwidget
.toggleViewAction().trigger()
660 self
.addAction(toggleview
)
661 connect_action(toggleview
, focusdock
)
663 def _update_diff_opts(self
):
664 space_at_eol
= self
.diff_ignore_space_at_eol_action
.isChecked()
665 space_change
= self
.diff_ignore_space_change_action
.isChecked()
666 all_space
= self
.diff_ignore_all_space_action
.isChecked()
667 function_context
= self
.diff_function_context_action
.isChecked()
669 gitcmds
.update_diff_overrides(space_at_eol
,
673 self
.statuswidget
.refresh()
675 def preferences(self
):
676 return preferences(model
=self
.prefs_model
, parent
=self
)
678 def save_archive(self
):
679 ref
= git
.rev_parse('HEAD')[STDOUT
]
681 GitArchiveDialog
.save(ref
, shortref
, self
)
683 def dragEnterEvent(self
, event
):
685 MainWindow
.dragEnterEvent(self
, event
)
686 event
.acceptProposedAction()
688 def dropEvent(self
, event
):
689 """Apply dropped patches with git-am"""
691 urls
= event
.mimeData().urls()
694 paths
= map(lambda x
: unicode(x
.path()), urls
)
695 patches
= [p
for p
in paths
if p
.endswith('.patch')]
696 dirs
= [p
for p
in paths
if os
.path
.isdir(p
)]
699 patches
.extend(self
._gather
_patches
(d
))
700 cmds
.do(cmds
.ApplyPatches
, patches
)
702 def _gather_patches(self
, path
):
703 """Find patches in a subdirectory"""
705 for root
, subdirs
, files
in os
.walk(path
):
706 for name
in [f
for f
in files
if f
.endswith('.patch')]:
707 patches
.append(os
.path
.join(root
, name
))
710 def show_cursor_position(self
, rows
, cols
):
711 display
= ' %02d:%02d ' % (rows
, cols
)
713 display
= ('<span style="color: white; '
714 ' background-color: red;"'
715 '>%s</span>' % display
)
717 display
= ('<span style="color: black; '
718 ' background-color: orange;"'
719 '>%s</span>' % display
)
721 display
= ('<span style="color: black; '
722 ' background-color: yellow;"'
723 '>%s</span>' % display
)
725 display
= ('<span style="color: grey;">%s</span>' % display
)
727 self
.position_label
.setText(display
)
729 def rebase_start(self
):
730 branch
= guicmds
.choose_ref(N_('Select New Upstream'),
731 N_('Interactive Rebase'))
734 self
.model
.is_rebasing
= True
735 self
._update
_callback
()
736 cmds
.do(cmds
.Rebase
, branch
)
738 def rebase_edit_todo(self
):
739 cmds
.do(cmds
.RebaseEditTodo
)
741 def rebase_continue(self
):
742 cmds
.do(cmds
.RebaseContinue
)
744 def rebase_skip(self
):
745 cmds
.do(cmds
.RebaseSkip
)
747 def rebase_abort(self
):
748 cmds
.do(cmds
.RebaseAbort
)