main: hide the menu indicator for the diff options
[git-cola.git] / cola / widgets / main.py
blob31b0ac48b764edbae0e730650c4109ec7bcc4ec1
1 """This view provides the main git-cola user interface.
2 """
3 import os
5 from PyQt4 import QtCore
6 from PyQt4 import QtGui
7 from PyQt4.QtCore import Qt
8 from PyQt4.QtCore import SIGNAL
10 from cola import cmds
11 from cola import core
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.git import git
21 from cola.git import STDOUT
22 from cola.i18n import N_
23 from cola.interaction import Interaction
24 from cola.models import prefs
25 from cola.qtutils import add_action
26 from cola.qtutils import add_action_bool
27 from cola.qtutils import connect_action
28 from cola.qtutils import connect_action_bool
29 from cola.qtutils import create_action_button
30 from cola.qtutils import create_dock
31 from cola.qtutils import create_menu
32 from cola.qtutils import options_icon
33 from cola.widgets import action
34 from cola.widgets import cfgactions
35 from cola.widgets import editremotes
36 from cola.widgets import merge
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.bookmarks import manage_bookmarks
42 from cola.widgets.bookmarks import BookmarksWidget
43 from cola.widgets.browse import worktree_browser
44 from cola.widgets.browse import worktree_browser_widget
45 from cola.widgets.commitmsg import CommitMessageEditor
46 from cola.widgets.compare import compare_branches
47 from cola.widgets.createtag import create_tag
48 from cola.widgets.createbranch import create_new_branch
49 from cola.widgets.dag import git_dag
50 from cola.widgets.diff import DiffEditor
51 from cola.widgets.grep import grep
52 from cola.widgets.log import LogWidget
53 from cola.widgets.patch import apply_patches
54 from cola.widgets.prefs import preferences
55 from cola.widgets.recent import browse_recent_files
56 from cola.widgets.status import StatusWidget
57 from cola.widgets.search import search
58 from cola.widgets.standard import MainWindow
59 from cola.widgets.stash import stash
62 class MainView(MainWindow):
64 def __init__(self, model, parent=None):
65 MainWindow.__init__(self, parent)
66 self.setAttribute(Qt.WA_MacMetalStyle)
68 # Default size; this is thrown out when save/restore is used
69 self.resize(987, 610)
70 self.model = model
71 self.prefs_model = prefs_model = prefs.PreferencesModel()
73 # The widget version is used by import/export_state().
74 # Change this whenever dockwidgets are removed.
75 self.widget_version = 2
77 # Keeps track of merge messages we've seen
78 self.merge_message_hash = ''
80 cfg = gitcfg.instance()
81 self.browser_dockable = (cfg.get('cola.browserdockable') or
82 cfg.get('cola.classicdockable'))
83 if self.browser_dockable:
84 self.browserdockwidget = create_dock(N_('Browser'), self)
85 self.browserwidget = worktree_browser_widget(self)
86 self.browserdockwidget.setWidget(self.browserwidget)
88 # "Actions" widget
89 self.actionsdockwidget = create_dock(N_('Actions'), self)
90 self.actionsdockwidgetcontents = action.ActionButtons(self)
91 self.actionsdockwidget.setWidget(self.actionsdockwidgetcontents)
92 self.actionsdockwidget.toggleViewAction().setChecked(False)
93 self.actionsdockwidget.hide()
95 # "Repository Status" widget
96 self.statuswidget = StatusWidget(self)
97 self.statusdockwidget = create_dock(N_('Status'), self)
98 self.statusdockwidget.setWidget(self.statuswidget)
100 # "Switch Repository" widget
101 self.bookmarksdockwidget = create_dock(N_('Bookmarks'), self)
102 self.bookmarkswidget = BookmarksWidget(parent=self.bookmarksdockwidget)
103 self.bookmarksdockwidget.setWidget(self.bookmarkswidget)
105 # "Commit Message Editor" widget
106 self.position_label = QtGui.QLabel()
107 font = qtutils.default_monospace_font()
108 font.setPointSize(int(font.pointSize() * 0.8))
109 self.position_label.setFont(font)
110 self.commitdockwidget = create_dock(N_('Commit'), self)
111 titlebar = self.commitdockwidget.titleBarWidget()
112 titlebar.add_corner_widget(self.position_label)
114 self.commitmsgeditor = CommitMessageEditor(model, self)
115 self.commitdockwidget.setWidget(self.commitmsgeditor)
117 # "Console" widget
118 self.logwidget = LogWidget()
119 self.logdockwidget = create_dock(N_('Console'), self)
120 self.logdockwidget.setWidget(self.logwidget)
121 self.logdockwidget.toggleViewAction().setChecked(False)
122 self.logdockwidget.hide()
124 # "Diff Viewer" widget
125 self.diffdockwidget = create_dock(N_('Diff'), self)
126 self.diffeditor = DiffEditor(self.diffdockwidget)
127 self.diffdockwidget.setWidget(self.diffeditor)
129 # "Diff Options" tool menu
130 self.diff_ignore_space_at_eol_action = add_action(self,
131 N_('Ignore changes in whitespace at EOL'),
132 self._update_diff_opts)
133 self.diff_ignore_space_at_eol_action.setCheckable(True)
135 self.diff_ignore_space_change_action = add_action(self,
136 N_('Ignore changes in amount of whitespace'),
137 self._update_diff_opts)
138 self.diff_ignore_space_change_action.setCheckable(True)
140 self.diff_ignore_all_space_action = add_action(self,
141 N_('Ignore all whitespace'),
142 self._update_diff_opts)
143 self.diff_ignore_all_space_action.setCheckable(True)
145 self.diff_function_context_action = add_action(self,
146 N_('Show whole surrounding functions of changes'),
147 self._update_diff_opts)
148 self.diff_function_context_action.setCheckable(True)
150 self.diffopts_button = create_action_button(
151 tooltip=N_('Diff Options'), icon=options_icon())
152 self.diffopts_button.setStyleSheet("""
153 QPushButton::menu-indicator {
154 image: none;
156 QPushButton {
157 border-style: none;
159 """)
160 self.diffopts_menu = create_menu(N_('Diff Options'),
161 self.diffopts_button)
163 self.diffopts_menu.addAction(self.diff_ignore_space_at_eol_action)
164 self.diffopts_menu.addAction(self.diff_ignore_space_change_action)
165 self.diffopts_menu.addAction(self.diff_ignore_all_space_action)
166 self.diffopts_menu.addAction(self.diff_function_context_action)
167 self.diffopts_button.setMenu(self.diffopts_menu)
169 titlebar = self.diffdockwidget.titleBarWidget()
170 titlebar.add_corner_widget(self.diffopts_button)
172 # All Actions
173 self.unstage_all_action = add_action(self,
174 N_('Unstage All'), cmds.run(cmds.UnstageAll))
175 self.unstage_all_action.setIcon(qtutils.icon('remove.svg'))
177 self.unstage_selected_action = add_action(self,
178 N_('Unstage From Commit'), cmds.run(cmds.UnstageSelected))
179 self.unstage_selected_action.setIcon(qtutils.icon('remove.svg'))
181 self.show_diffstat_action = add_action(self,
182 N_('Diffstat'), cmds.run(cmds.Diffstat), 'Alt+D')
184 self.stage_modified_action = add_action(self,
185 N_('Stage Changed Files To Commit'),
186 cmds.run(cmds.StageModified), 'Alt+A')
187 self.stage_modified_action.setIcon(qtutils.icon('add.svg'))
189 self.stage_untracked_action = add_action(self,
190 N_('Stage All Untracked'),
191 cmds.run(cmds.StageUntracked), 'Alt+U')
192 self.stage_untracked_action.setIcon(qtutils.icon('add.svg'))
194 self.apply_patches_action = add_action(self,
195 N_('Apply Patches...'), apply_patches)
197 self.export_patches_action = add_action(self,
198 N_('Export Patches...'), guicmds.export_patches, 'Alt+E')
200 self.new_repository_action = add_action(self,
201 N_('New Repository...'), guicmds.open_new_repo)
202 self.new_repository_action.setIcon(qtutils.new_icon())
204 self.preferences_action = add_action(self,
205 N_('Preferences'), self.preferences,
206 QtGui.QKeySequence.Preferences, 'Ctrl+O')
208 self.edit_remotes_action = add_action(self,
209 N_('Edit Remotes...'), lambda: editremotes.edit().exec_())
210 self.rescan_action = add_action(self,
211 cmds.Refresh.name(),
212 cmds.run(cmds.Refresh),
213 cmds.Refresh.SHORTCUT)
214 self.rescan_action.setIcon(qtutils.reload_icon())
216 self.browse_recently_modified_action = add_action(self,
217 N_('Recently Modified Files...'),
218 browse_recent_files, 'Shift+Ctrl+E')
220 self.cherry_pick_action = add_action(self,
221 N_('Cherry-Pick...'),
222 guicmds.cherry_pick, 'Ctrl+P')
224 self.load_commitmsg_action = add_action(self,
225 N_('Load Commit Message...'), guicmds.load_commitmsg)
227 self.save_tarball_action = add_action(self,
228 N_('Save As Tarball/Zip...'), self.save_archive)
230 self.quit_action = add_action(self,
231 N_('Quit'), self.close, 'Ctrl+Q')
232 self.manage_bookmarks_action = add_action(self,
233 N_('Bookmarks...'), self.manage_bookmarks)
234 self.grep_action = add_action(self,
235 N_('Grep'), grep, 'Ctrl+G')
236 self.merge_local_action = add_action(self,
237 N_('Merge...'), merge.local_merge)
239 self.merge_abort_action = add_action(self,
240 N_('Abort Merge...'), merge.abort_merge)
242 self.fetch_action = add_action(self,
243 N_('Fetch...'), remote.fetch)
244 self.push_action = add_action(self,
245 N_('Push...'), remote.push)
246 self.pull_action = add_action(self,
247 N_('Pull...'), remote.pull)
249 self.open_repo_action = add_action(self,
250 N_('Open...'), guicmds.open_repo)
251 self.open_repo_action.setIcon(qtutils.open_icon())
253 self.open_repo_new_action = add_action(self,
254 N_('Open in New Window...'), guicmds.open_repo_in_new_window)
255 self.open_repo_new_action.setIcon(qtutils.open_icon())
257 self.stash_action = add_action(self,
258 N_('Stash...'), stash, 'Alt+Shift+S')
260 self.clone_repo_action = add_action(self,
261 N_('Clone...'), guicmds.clone_repo)
262 self.clone_repo_action.setIcon(qtutils.git_icon())
264 self.help_docs_action = add_action(self,
265 N_('Documentation'), resources.show_html_docs,
266 QtGui.QKeySequence.HelpContents)
268 self.help_shortcuts_action = add_action(self,
269 N_('Keyboard Shortcuts'),
270 show_shortcuts,
271 QtCore.Qt.Key_Question)
273 self.visualize_current_action = add_action(self,
274 N_('Visualize Current Branch...'),
275 cmds.run(cmds.VisualizeCurrent))
276 self.visualize_all_action = add_action(self,
277 N_('Visualize All Branches...'),
278 cmds.run(cmds.VisualizeAll))
279 self.search_commits_action = add_action(self,
280 N_('Search...'), search)
281 self.browse_branch_action = add_action(self,
282 N_('Browse Current Branch...'), guicmds.browse_current)
283 self.browse_other_branch_action = add_action(self,
284 N_('Browse Other Branch...'), guicmds.browse_other)
285 self.load_commitmsg_template_action = add_action(self,
286 N_('Get Commit Message Template'),
287 cmds.run(cmds.LoadCommitMessageFromTemplate))
288 self.help_about_action = add_action(self,
289 N_('About'), launch_about_dialog)
291 self.diff_expression_action = add_action(self,
292 N_('Expression...'), guicmds.diff_expression)
293 self.branch_compare_action = add_action(self,
294 N_('Branches...'), compare_branches)
296 self.create_tag_action = add_action(self,
297 N_('Create Tag...'), create_tag)
299 self.create_branch_action = add_action(self,
300 N_('Create...'), create_new_branch, 'Ctrl+B')
302 self.delete_branch_action = add_action(self,
303 N_('Delete...'), guicmds.delete_branch)
305 self.delete_remote_branch_action = add_action(self,
306 N_('Delete Remote Branch...'), guicmds.delete_remote_branch)
308 self.checkout_branch_action = add_action(self,
309 N_('Checkout...'), guicmds.checkout_branch, 'Alt+B')
310 self.branch_review_action = add_action(self,
311 N_('Review...'), guicmds.review_branch)
313 self.browse_action = add_action(self,
314 N_('Browser...'), worktree_browser)
315 self.browse_action.setIcon(qtutils.git_icon())
317 self.dag_action = add_action(self,
318 N_('DAG...'), lambda: git_dag(self.model).show())
319 self.dag_action.setIcon(qtutils.git_icon())
321 self.rebase_start_action = add_action(self,
322 N_('Start Interactive Rebase...'), self.rebase_start)
324 self.rebase_edit_todo_action = add_action(self,
325 N_('Edit...'), self.rebase_edit_todo)
327 self.rebase_continue_action = add_action(self,
328 N_('Continue'), self.rebase_continue)
330 self.rebase_skip_action = add_action(self,
331 N_('Skip Current Patch'), self.rebase_skip)
333 self.rebase_abort_action = add_action(self,
334 N_('Abort'), self.rebase_abort)
336 # Relayed actions
337 status_tree = self.statusdockwidget.widget().tree
338 self.addAction(status_tree.revert_unstaged_edits_action)
339 if not self.browser_dockable:
340 # These shortcuts conflict with those from the
341 # 'Browser' widget so don't register them when
342 # the browser is a dockable tool.
343 self.addAction(status_tree.up)
344 self.addAction(status_tree.down)
345 self.addAction(status_tree.process_selection)
347 self.lock_layout_action = add_action_bool(self,
348 N_('Lock Layout'), self.set_lock_layout, False)
350 # Create the application menu
351 self.menubar = QtGui.QMenuBar(self)
353 # File Menu
354 self.file_menu = create_menu(N_('File'), self.menubar)
355 self.open_recent_menu = self.file_menu.addMenu(N_('Open Recent'))
356 self.open_recent_menu.setIcon(qtutils.open_icon())
357 self.file_menu.addAction(self.open_repo_action)
358 self.file_menu.addAction(self.open_repo_new_action)
359 self.file_menu.addAction(self.clone_repo_action)
360 self.file_menu.addAction(self.new_repository_action)
361 self.file_menu.addSeparator()
362 self.file_menu.addAction(self.rescan_action)
363 self.file_menu.addAction(self.edit_remotes_action)
364 self.file_menu.addAction(self.browse_recently_modified_action)
365 self.file_menu.addAction(self.manage_bookmarks_action)
366 self.file_menu.addSeparator()
367 self.file_menu.addAction(self.load_commitmsg_action)
368 self.file_menu.addAction(self.load_commitmsg_template_action)
369 self.file_menu.addSeparator()
370 self.file_menu.addAction(self.apply_patches_action)
371 self.file_menu.addAction(self.export_patches_action)
372 self.file_menu.addAction(self.save_tarball_action)
373 self.file_menu.addSeparator()
374 self.file_menu.addAction(self.preferences_action)
375 self.file_menu.addAction(self.quit_action)
376 self.menubar.addAction(self.file_menu.menuAction())
378 # Actions menu
379 self.actions_menu = create_menu(N_('Actions'), self.menubar)
380 self.actions_menu.addAction(self.fetch_action)
381 self.actions_menu.addAction(self.push_action)
382 self.actions_menu.addAction(self.pull_action)
383 self.actions_menu.addAction(self.stash_action)
384 self.actions_menu.addSeparator()
385 self.actions_menu.addAction(self.create_tag_action)
386 self.actions_menu.addAction(self.cherry_pick_action)
387 self.actions_menu.addAction(self.merge_local_action)
388 self.actions_menu.addAction(self.merge_abort_action)
389 self.actions_menu.addSeparator()
390 self.actions_menu.addAction(self.grep_action)
391 self.actions_menu.addAction(self.search_commits_action)
392 self.menubar.addAction(self.actions_menu.menuAction())
394 # Index Menu
395 self.commit_menu = create_menu(N_('Index'), self.menubar)
396 self.commit_menu.setTitle(N_('Index'))
397 self.commit_menu.addAction(self.stage_modified_action)
398 self.commit_menu.addAction(self.stage_untracked_action)
399 self.commit_menu.addSeparator()
400 self.commit_menu.addAction(self.unstage_all_action)
401 self.commit_menu.addAction(self.unstage_selected_action)
402 self.menubar.addAction(self.commit_menu.menuAction())
404 # Diff Menu
405 self.diff_menu = create_menu(N_('Diff'), self.menubar)
406 self.diff_menu.addAction(self.diff_expression_action)
407 self.diff_menu.addAction(self.branch_compare_action)
408 self.diff_menu.addSeparator()
409 self.diff_menu.addAction(self.show_diffstat_action)
410 self.menubar.addAction(self.diff_menu.menuAction())
412 # Branch Menu
413 self.branch_menu = create_menu(N_('Branch'), self.menubar)
414 self.branch_menu.addAction(self.branch_review_action)
415 self.branch_menu.addSeparator()
416 self.branch_menu.addAction(self.create_branch_action)
417 self.branch_menu.addAction(self.checkout_branch_action)
418 self.branch_menu.addAction(self.delete_branch_action)
419 self.branch_menu.addAction(self.delete_remote_branch_action)
420 self.branch_menu.addSeparator()
421 self.branch_menu.addAction(self.browse_branch_action)
422 self.branch_menu.addAction(self.browse_other_branch_action)
423 self.branch_menu.addSeparator()
424 self.branch_menu.addAction(self.visualize_current_action)
425 self.branch_menu.addAction(self.visualize_all_action)
426 self.menubar.addAction(self.branch_menu.menuAction())
428 # Rebase menu
429 self.rebase_menu = create_menu(N_('Rebase'), self.actions_menu)
430 self.rebase_menu.addAction(self.rebase_start_action)
431 self.rebase_menu.addAction(self.rebase_edit_todo_action)
432 self.rebase_menu.addSeparator()
433 self.rebase_menu.addAction(self.rebase_continue_action)
434 self.rebase_menu.addAction(self.rebase_skip_action)
435 self.rebase_menu.addSeparator()
436 self.rebase_menu.addAction(self.rebase_abort_action)
437 self.menubar.addAction(self.rebase_menu.menuAction())
439 # View Menu
440 self.view_menu = create_menu(N_('View'), self.menubar)
441 self.view_menu.addAction(self.browse_action)
442 self.view_menu.addAction(self.dag_action)
443 self.view_menu.addSeparator()
444 if self.browser_dockable:
445 self.view_menu.addAction(self.browserdockwidget.toggleViewAction())
447 self.setup_dockwidget_view_menu()
448 self.view_menu.addSeparator()
449 self.view_menu.addAction(self.lock_layout_action)
450 self.menubar.addAction(self.view_menu.menuAction())
452 # Help Menu
453 self.help_menu = create_menu(N_('Help'), self.menubar)
454 self.help_menu.addAction(self.help_docs_action)
455 self.help_menu.addAction(self.help_shortcuts_action)
456 self.help_menu.addAction(self.help_about_action)
457 self.menubar.addAction(self.help_menu.menuAction())
459 # Set main menu
460 self.setMenuBar(self.menubar)
462 # Arrange dock widgets
463 left = Qt.LeftDockWidgetArea
464 right = Qt.RightDockWidgetArea
465 bottom = Qt.BottomDockWidgetArea
467 self.addDockWidget(left, self.commitdockwidget)
468 if self.browser_dockable:
469 self.addDockWidget(left, self.browserdockwidget)
470 self.tabifyDockWidget(self.browserdockwidget, self.commitdockwidget)
471 self.addDockWidget(left, self.diffdockwidget)
472 self.addDockWidget(right, self.statusdockwidget)
473 self.addDockWidget(right, self.bookmarksdockwidget)
474 self.addDockWidget(bottom, self.actionsdockwidget)
475 self.addDockWidget(bottom, self.logdockwidget)
476 self.tabifyDockWidget(self.actionsdockwidget, self.logdockwidget)
479 # Listen for model notifications
480 model.add_observer(model.message_updated, self._update)
481 model.add_observer(model.message_mode_changed, lambda x: self._update())
483 prefs_model.add_observer(prefs_model.message_config_updated,
484 self._config_updated)
486 # Set a default value
487 self.show_cursor_position(1, 0)
489 self.connect(self.open_recent_menu, SIGNAL('aboutToShow()'),
490 self.build_recent_menu)
492 self.connect(self.commitmsgeditor, SIGNAL('cursorPosition(int,int)'),
493 self.show_cursor_position)
494 self.connect(self, SIGNAL('update'), self._update_callback)
495 self.connect(self, SIGNAL('install_config_actions'),
496 self._install_config_actions)
498 # Install .git-config-defined actions
499 self._config_task = None
500 self.install_config_actions()
502 # Restore saved settings
503 if not qtutils.apply_state(self):
504 self.set_initial_size()
506 self.statusdockwidget.widget().setFocus()
508 # Route command output here
509 Interaction.log_status = self.logwidget.log_status
510 Interaction.log = self.logwidget.log
511 Interaction.log(version.git_version_str() + '\n' +
512 N_('git cola version %s') % version.version())
514 def set_initial_size(self):
515 self.statuswidget.set_initial_size()
516 self.commitmsgeditor.set_initial_size()
518 # Qt overrides
519 def closeEvent(self, event):
520 """Save state in the settings manager."""
521 commit_msg = self.commitmsgeditor.commit_message(raw=True)
522 self.model.save_commitmsg(commit_msg)
523 MainWindow.closeEvent(self, event)
525 def build_recent_menu(self):
526 recent = settings.Settings().recent
527 cmd = cmds.OpenRepo
528 menu = self.open_recent_menu
529 menu.clear()
530 for r in recent:
531 name = os.path.basename(r)
532 directory = os.path.dirname(r)
533 text = '%s %s %s' % (name, unichr(0x2192), directory)
534 menu.addAction(text, cmds.run(cmd, r))
536 # Accessors
537 mode = property(lambda self: self.model.mode)
539 def _config_updated(self, source, config, value):
540 if config == prefs.FONTDIFF:
541 # The diff font
542 font = QtGui.QFont()
543 if not font.fromString(value):
544 return
545 self.logwidget.setFont(font)
546 self.diffeditor.setFont(font)
547 self.commitmsgeditor.setFont(font)
549 elif config == prefs.TABWIDTH:
550 # variable-tab-width setting
551 self.diffeditor.set_tabwidth(value)
552 self.commitmsgeditor.set_tabwidth(value)
554 elif config == prefs.LINEBREAK:
555 # enables automatic line breaks
556 self.commitmsgeditor.set_linebreak(value)
558 elif config == prefs.TEXTWIDTH:
559 # text width used for line wrapping
560 self.commitmsgeditor.set_textwidth(value)
562 def install_config_actions(self):
563 """Install .gitconfig-defined actions"""
564 self._config_task = self._start_config_actions_task()
566 def _start_config_actions_task(self):
567 """Do the expensive "get_config_actions()" call in the background"""
568 class ConfigActionsTask(QtCore.QRunnable):
569 def __init__(self, sender):
570 QtCore.QRunnable.__init__(self)
571 self._sender = sender
572 def run(self):
573 names = cfgactions.get_config_actions()
574 self._sender.emit(SIGNAL('install_config_actions'), names)
576 task = ConfigActionsTask(self)
577 QtCore.QThreadPool.globalInstance().start(task)
578 return task
580 def _install_config_actions(self, names):
581 """Install .gitconfig-defined actions"""
582 if not names:
583 return
584 menu = self.actions_menu
585 menu.addSeparator()
586 for name in names:
587 menu.addAction(name, cmds.run(cmds.RunConfigAction, name))
589 def _update(self):
590 self.emit(SIGNAL('update'))
592 def _update_callback(self):
593 """Update the title with the current branch and directory name."""
594 alerts = []
595 branch = self.model.currentbranch
596 curdir = core.getcwd()
597 is_merging = self.model.is_merging
598 is_rebasing = self.model.is_rebasing
600 msg = N_('Repository: %s') % curdir
601 msg += '\n'
602 msg += N_('Branch: %s') % branch
604 if is_rebasing:
605 msg += '\n\n'
606 msg += N_('This repository is currently being rebased.\n'
607 'Resolve conflicts, commit changes, and run:\n'
608 ' Rebase > Continue')
609 alerts.append(N_('Rebasing'))
611 elif is_merging:
612 msg += '\n\n'
613 msg += N_('This repository is in the middle of a merge.\n'
614 'Resolve conflicts and commit changes.')
615 alerts.append(N_('Merging'))
617 if self.mode == self.model.mode_amend:
618 alerts.append(N_('Amending'))
620 l = unichr(0xab)
621 r = unichr(0xbb)
622 title = ('%s: %s %s%s' % (
623 self.model.project,
624 branch,
625 alerts and ((r+' %s '+l+' ') % ', '.join(alerts)) or '',
626 self.model.git.worktree()))
628 self.setWindowTitle(title)
629 self.commitdockwidget.setToolTip(msg)
630 self.commitmsgeditor.set_mode(self.mode)
631 self.update_actions()
633 if not self.model.amending():
634 # Check if there's a message file in .git/
635 merge_msg_path = gitcmds.merge_message_path()
636 if merge_msg_path is None:
637 return
638 merge_msg_hash = utils.checksum(merge_msg_path)
639 if merge_msg_hash == self.merge_message_hash:
640 return
641 self.merge_message_hash = merge_msg_hash
642 cmds.do(cmds.LoadCommitMessageFromFile, merge_msg_path)
644 def update_actions(self):
645 is_rebasing = self.model.is_rebasing
646 can_rebase = not is_rebasing
647 self.rebase_start_action.setEnabled(can_rebase)
648 self.rebase_edit_todo_action.setEnabled(is_rebasing)
649 self.rebase_continue_action.setEnabled(is_rebasing)
650 self.rebase_skip_action.setEnabled(is_rebasing)
651 self.rebase_abort_action.setEnabled(is_rebasing)
653 def apply_state(self, state):
654 """Imports data for save/restore"""
655 result = MainWindow.apply_state(self, state)
656 self.lock_layout_action.setChecked(state.get('lock_layout', False))
657 return result
659 def setup_dockwidget_view_menu(self):
660 # Hotkeys for toggling the dock widgets
661 if utils.is_darwin():
662 optkey = 'Meta'
663 else:
664 optkey = 'Ctrl'
665 dockwidgets = (
666 (optkey + '+0', self.logdockwidget),
667 (optkey + '+1', self.commitdockwidget),
668 (optkey + '+2', self.statusdockwidget),
669 (optkey + '+3', self.diffdockwidget),
670 (optkey + '+4', self.actionsdockwidget),
671 (optkey + '+5', self.bookmarksdockwidget),
673 for shortcut, dockwidget in dockwidgets:
674 # Associate the action with the shortcut
675 toggleview = dockwidget.toggleViewAction()
676 toggleview.setShortcut('Shift+' + shortcut)
677 self.view_menu.addAction(toggleview)
678 def showdock(show, dockwidget=dockwidget):
679 if show:
680 dockwidget.raise_()
681 dockwidget.widget().setFocus()
682 else:
683 self.setFocus()
684 self.addAction(toggleview)
685 connect_action_bool(toggleview, showdock)
687 # Create a new shortcut Shift+<shortcut> that gives focus
688 toggleview = QtGui.QAction(self)
689 toggleview.setShortcut(shortcut)
690 def focusdock(dockwidget=dockwidget, showdock=showdock):
691 if dockwidget.toggleViewAction().isChecked():
692 showdock(True)
693 else:
694 dockwidget.toggleViewAction().trigger()
695 self.addAction(toggleview)
696 connect_action(toggleview, focusdock)
698 def _update_diff_opts(self):
699 space_at_eol = self.diff_ignore_space_at_eol_action.isChecked()
700 space_change = self.diff_ignore_space_change_action.isChecked()
701 all_space = self.diff_ignore_all_space_action.isChecked()
702 function_context = self.diff_function_context_action.isChecked()
704 gitcmds.update_diff_overrides(space_at_eol,
705 space_change,
706 all_space,
707 function_context)
708 self.statuswidget.refresh()
710 def preferences(self):
711 return preferences(model=self.prefs_model, parent=self)
713 def save_archive(self):
714 ref = git.rev_parse('HEAD')[STDOUT]
715 shortref = ref[:7]
716 GitArchiveDialog.save(ref, shortref, self)
718 def show_cursor_position(self, rows, cols):
719 display = '&nbsp;%02d:%02d&nbsp;' % (rows, cols)
720 if cols > 78:
721 display = ('<span style="color: white; '
722 ' background-color: red;"'
723 '>%s</span>' % display)
724 elif cols > 72:
725 display = ('<span style="color: black; '
726 ' background-color: orange;"'
727 '>%s</span>' % display)
728 elif cols > 64:
729 display = ('<span style="color: black; '
730 ' background-color: yellow;"'
731 '>%s</span>' % display)
732 else:
733 display = ('<span style="color: grey;">%s</span>' % display)
735 self.position_label.setText(display)
737 def manage_bookmarks(self):
738 manage_bookmarks()
739 self.bookmarkswidget.refresh()
741 def rebase_start(self):
742 branch = guicmds.choose_ref(N_('Select New Upstream'),
743 N_('Interactive Rebase'))
744 if not branch:
745 return None
746 self.model.is_rebasing = True
747 self._update_callback()
748 cmds.do(cmds.Rebase, branch)
750 def rebase_edit_todo(self):
751 cmds.do(cmds.RebaseEditTodo)
753 def rebase_continue(self):
754 cmds.do(cmds.RebaseContinue)
756 def rebase_skip(self):
757 cmds.do(cmds.RebaseSkip)
759 def rebase_abort(self):
760 cmds.do(cmds.RebaseAbort)