bookmarks: add "Open in New Window" action and hotkeys
[git-cola.git] / cola / widgets / main.py
blob5ea90317a02d319df66234ee7e18fa57a67eed44
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_dock
30 from cola.qtutils import create_menu
31 from cola.widgets import action
32 from cola.widgets import cfgactions
33 from cola.widgets import editremotes
34 from cola.widgets import merge
35 from cola.widgets import remote
36 from cola.widgets.about import launch_about_dialog
37 from cola.widgets.about import show_shortcuts
38 from cola.widgets.archive import GitArchiveDialog
39 from cola.widgets.bookmarks import manage_bookmarks
40 from cola.widgets.bookmarks import BookmarksWidget
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.grep import grep
50 from cola.widgets.log import LogWidget
51 from cola.widgets.patch import apply_patches
52 from cola.widgets.prefs import preferences
53 from cola.widgets.recent import browse_recent_files
54 from cola.widgets.status import StatusWidget
55 from cola.widgets.search import search
56 from cola.widgets.standard import MainWindow
57 from cola.widgets.stash import stash
60 class MainView(MainWindow):
62 def __init__(self, model, parent=None):
63 MainWindow.__init__(self, parent)
64 self.setAttribute(Qt.WA_MacMetalStyle)
66 # Default size; this is thrown out when save/restore is used
67 self.resize(987, 610)
68 self.model = model
69 self.prefs_model = prefs_model = prefs.PreferencesModel()
71 # The widget version is used by import/export_state().
72 # Change this whenever dockwidgets are removed.
73 self.widget_version = 2
75 # Keeps track of merge messages we've seen
76 self.merge_message_hash = ''
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)
86 # "Actions" widget
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 # "Switch Repository" widget
99 self.bookmarksdockwidget = create_dock(N_('Bookmarks'), self)
100 self.bookmarkswidget = BookmarksWidget(parent=self.bookmarksdockwidget)
101 self.bookmarksdockwidget.setWidget(self.bookmarkswidget)
103 # "Commit Message Editor" widget
104 self.position_label = QtGui.QLabel()
105 font = qtutils.default_monospace_font()
106 font.setPointSize(int(font.pointSize() * 0.8))
107 self.position_label.setFont(font)
109 # make the position label fixed size to avoid layout issues
110 fm = self.position_label.fontMetrics()
111 width = fm.width('999:999')
112 height = self.position_label.sizeHint().height()
113 self.position_label.setFixedSize(width, height)
115 self.commitdockwidget = create_dock(N_('Commit'), self)
116 titlebar = self.commitdockwidget.titleBarWidget()
117 titlebar.add_corner_widget(self.position_label)
119 self.commitmsgeditor = CommitMessageEditor(model, self)
120 self.commitdockwidget.setWidget(self.commitmsgeditor)
122 # "Console" widget
123 self.logwidget = LogWidget()
124 self.logdockwidget = create_dock(N_('Console'), self)
125 self.logdockwidget.setWidget(self.logwidget)
126 self.logdockwidget.toggleViewAction().setChecked(False)
127 self.logdockwidget.hide()
129 # "Diff Viewer" widget
130 self.diffdockwidget = create_dock(N_('Diff'), self)
131 self.diffeditor = DiffEditor(self.diffdockwidget)
132 self.diffdockwidget.setWidget(self.diffeditor)
134 # All Actions
135 self.unstage_all_action = add_action(self,
136 N_('Unstage All'), cmds.run(cmds.UnstageAll))
137 self.unstage_all_action.setIcon(qtutils.icon('remove.svg'))
139 self.unstage_selected_action = add_action(self,
140 N_('Unstage From Commit'), cmds.run(cmds.UnstageSelected))
141 self.unstage_selected_action.setIcon(qtutils.icon('remove.svg'))
143 self.show_diffstat_action = add_action(self,
144 N_('Diffstat'), cmds.run(cmds.Diffstat), 'Alt+D')
146 self.stage_modified_action = add_action(self,
147 N_('Stage Changed Files To Commit'),
148 cmds.run(cmds.StageModified), 'Alt+A')
149 self.stage_modified_action.setIcon(qtutils.icon('add.svg'))
151 self.stage_untracked_action = add_action(self,
152 N_('Stage All Untracked'),
153 cmds.run(cmds.StageUntracked), 'Alt+U')
154 self.stage_untracked_action.setIcon(qtutils.icon('add.svg'))
156 self.apply_patches_action = add_action(self,
157 N_('Apply Patches...'), apply_patches)
159 self.export_patches_action = add_action(self,
160 N_('Export Patches...'), guicmds.export_patches, 'Alt+E')
162 self.new_repository_action = add_action(self,
163 N_('New Repository...'), guicmds.open_new_repo)
164 self.new_repository_action.setIcon(qtutils.new_icon())
166 self.preferences_action = add_action(self,
167 N_('Preferences'), self.preferences,
168 QtGui.QKeySequence.Preferences, 'Ctrl+O')
170 self.edit_remotes_action = add_action(self,
171 N_('Edit Remotes...'), lambda: editremotes.edit().exec_())
172 self.rescan_action = add_action(self,
173 cmds.Refresh.name(),
174 cmds.run(cmds.Refresh),
175 cmds.Refresh.SHORTCUT)
176 self.rescan_action.setIcon(qtutils.reload_icon())
178 self.browse_recently_modified_action = add_action(self,
179 N_('Recently Modified Files...'),
180 browse_recent_files, 'Shift+Ctrl+E')
182 self.cherry_pick_action = add_action(self,
183 N_('Cherry-Pick...'),
184 guicmds.cherry_pick, 'Ctrl+P')
186 self.load_commitmsg_action = add_action(self,
187 N_('Load Commit Message...'), guicmds.load_commitmsg)
189 self.save_tarball_action = add_action(self,
190 N_('Save As Tarball/Zip...'), self.save_archive)
192 self.quit_action = add_action(self,
193 N_('Quit'), self.close, 'Ctrl+Q')
194 self.manage_bookmarks_action = add_action(self,
195 N_('Bookmarks...'), self.manage_bookmarks)
196 self.grep_action = add_action(self,
197 N_('Grep'), grep, 'Ctrl+G')
198 self.merge_local_action = add_action(self,
199 N_('Merge...'), merge.local_merge)
201 self.merge_abort_action = add_action(self,
202 N_('Abort Merge...'), merge.abort_merge)
204 self.fetch_action = add_action(self,
205 N_('Fetch...'), remote.fetch)
206 self.push_action = add_action(self,
207 N_('Push...'), remote.push)
208 self.pull_action = add_action(self,
209 N_('Pull...'), remote.pull)
211 self.open_repo_action = add_action(self,
212 N_('Open...'), guicmds.open_repo)
213 self.open_repo_action.setIcon(qtutils.open_icon())
215 self.open_repo_new_action = add_action(self,
216 N_('Open in New Window...'), guicmds.open_repo_in_new_window)
217 self.open_repo_new_action.setIcon(qtutils.open_icon())
219 self.stash_action = add_action(self,
220 N_('Stash...'), stash, 'Alt+Shift+S')
222 self.clone_repo_action = add_action(self,
223 N_('Clone...'), guicmds.clone_repo)
224 self.clone_repo_action.setIcon(qtutils.git_icon())
226 self.help_docs_action = add_action(self,
227 N_('Documentation'), resources.show_html_docs,
228 QtGui.QKeySequence.HelpContents)
230 self.help_shortcuts_action = add_action(self,
231 N_('Keyboard Shortcuts'),
232 show_shortcuts,
233 QtCore.Qt.Key_Question)
235 self.visualize_current_action = add_action(self,
236 N_('Visualize Current Branch...'),
237 cmds.run(cmds.VisualizeCurrent))
238 self.visualize_all_action = add_action(self,
239 N_('Visualize All Branches...'),
240 cmds.run(cmds.VisualizeAll))
241 self.search_commits_action = add_action(self,
242 N_('Search...'), search)
243 self.browse_branch_action = add_action(self,
244 N_('Browse Current Branch...'), guicmds.browse_current)
245 self.browse_other_branch_action = add_action(self,
246 N_('Browse Other Branch...'), guicmds.browse_other)
247 self.load_commitmsg_template_action = add_action(self,
248 N_('Get Commit Message Template'),
249 cmds.run(cmds.LoadCommitMessageFromTemplate))
250 self.help_about_action = add_action(self,
251 N_('About'), launch_about_dialog)
253 self.diff_expression_action = add_action(self,
254 N_('Expression...'), guicmds.diff_expression)
255 self.branch_compare_action = add_action(self,
256 N_('Branches...'), compare_branches)
258 self.create_tag_action = add_action(self,
259 N_('Create Tag...'), create_tag)
261 self.create_branch_action = add_action(self,
262 N_('Create...'), create_new_branch, 'Ctrl+B')
264 self.delete_branch_action = add_action(self,
265 N_('Delete...'), guicmds.delete_branch)
267 self.delete_remote_branch_action = add_action(self,
268 N_('Delete Remote Branch...'), guicmds.delete_remote_branch)
270 self.checkout_branch_action = add_action(self,
271 N_('Checkout...'), guicmds.checkout_branch, 'Alt+B')
272 self.branch_review_action = add_action(self,
273 N_('Review...'), guicmds.review_branch)
275 self.browse_action = add_action(self,
276 N_('Browser...'), worktree_browser)
277 self.browse_action.setIcon(qtutils.git_icon())
279 self.dag_action = add_action(self,
280 N_('DAG...'), lambda: git_dag(self.model).show())
281 self.dag_action.setIcon(qtutils.git_icon())
283 self.rebase_start_action = add_action(self,
284 N_('Start Interactive Rebase...'), self.rebase_start)
286 self.rebase_edit_todo_action = add_action(self,
287 N_('Edit...'), self.rebase_edit_todo)
289 self.rebase_continue_action = add_action(self,
290 N_('Continue'), self.rebase_continue)
292 self.rebase_skip_action = add_action(self,
293 N_('Skip Current Patch'), self.rebase_skip)
295 self.rebase_abort_action = add_action(self,
296 N_('Abort'), self.rebase_abort)
298 # Relayed actions
299 status_tree = self.statusdockwidget.widget().tree
300 self.addAction(status_tree.revert_unstaged_edits_action)
301 if not self.browser_dockable:
302 # These shortcuts conflict with those from the
303 # 'Browser' widget so don't register them when
304 # the browser is a dockable tool.
305 self.addAction(status_tree.up)
306 self.addAction(status_tree.down)
307 self.addAction(status_tree.process_selection)
309 self.lock_layout_action = add_action_bool(self,
310 N_('Lock Layout'), self.set_lock_layout, False)
312 # Create the application menu
313 self.menubar = QtGui.QMenuBar(self)
315 # File Menu
316 self.file_menu = create_menu(N_('File'), self.menubar)
317 self.open_recent_menu = self.file_menu.addMenu(N_('Open Recent'))
318 self.open_recent_menu.setIcon(qtutils.open_icon())
319 self.file_menu.addAction(self.open_repo_action)
320 self.file_menu.addAction(self.open_repo_new_action)
321 self.file_menu.addAction(self.clone_repo_action)
322 self.file_menu.addAction(self.new_repository_action)
323 self.file_menu.addSeparator()
324 self.file_menu.addAction(self.rescan_action)
325 self.file_menu.addAction(self.edit_remotes_action)
326 self.file_menu.addAction(self.browse_recently_modified_action)
327 self.file_menu.addAction(self.manage_bookmarks_action)
328 self.file_menu.addSeparator()
329 self.file_menu.addAction(self.load_commitmsg_action)
330 self.file_menu.addAction(self.load_commitmsg_template_action)
331 self.file_menu.addSeparator()
332 self.file_menu.addAction(self.apply_patches_action)
333 self.file_menu.addAction(self.export_patches_action)
334 self.file_menu.addAction(self.save_tarball_action)
335 self.file_menu.addSeparator()
336 self.file_menu.addAction(self.preferences_action)
337 self.file_menu.addAction(self.quit_action)
338 self.menubar.addAction(self.file_menu.menuAction())
340 # Actions menu
341 self.actions_menu = create_menu(N_('Actions'), self.menubar)
342 self.actions_menu.addAction(self.fetch_action)
343 self.actions_menu.addAction(self.push_action)
344 self.actions_menu.addAction(self.pull_action)
345 self.actions_menu.addAction(self.stash_action)
346 self.actions_menu.addSeparator()
347 self.actions_menu.addAction(self.create_tag_action)
348 self.actions_menu.addAction(self.cherry_pick_action)
349 self.actions_menu.addAction(self.merge_local_action)
350 self.actions_menu.addAction(self.merge_abort_action)
351 self.actions_menu.addSeparator()
352 self.actions_menu.addAction(self.grep_action)
353 self.actions_menu.addAction(self.search_commits_action)
354 self.menubar.addAction(self.actions_menu.menuAction())
356 # Index Menu
357 self.commit_menu = create_menu(N_('Index'), self.menubar)
358 self.commit_menu.setTitle(N_('Index'))
359 self.commit_menu.addAction(self.stage_modified_action)
360 self.commit_menu.addAction(self.stage_untracked_action)
361 self.commit_menu.addSeparator()
362 self.commit_menu.addAction(self.unstage_all_action)
363 self.commit_menu.addAction(self.unstage_selected_action)
364 self.menubar.addAction(self.commit_menu.menuAction())
366 # Diff Menu
367 self.diff_menu = create_menu(N_('Diff'), self.menubar)
368 self.diff_menu.addAction(self.diff_expression_action)
369 self.diff_menu.addAction(self.branch_compare_action)
370 self.diff_menu.addSeparator()
371 self.diff_menu.addAction(self.show_diffstat_action)
372 self.menubar.addAction(self.diff_menu.menuAction())
374 # Branch Menu
375 self.branch_menu = create_menu(N_('Branch'), self.menubar)
376 self.branch_menu.addAction(self.branch_review_action)
377 self.branch_menu.addSeparator()
378 self.branch_menu.addAction(self.create_branch_action)
379 self.branch_menu.addAction(self.checkout_branch_action)
380 self.branch_menu.addAction(self.delete_branch_action)
381 self.branch_menu.addAction(self.delete_remote_branch_action)
382 self.branch_menu.addSeparator()
383 self.branch_menu.addAction(self.browse_branch_action)
384 self.branch_menu.addAction(self.browse_other_branch_action)
385 self.branch_menu.addSeparator()
386 self.branch_menu.addAction(self.visualize_current_action)
387 self.branch_menu.addAction(self.visualize_all_action)
388 self.menubar.addAction(self.branch_menu.menuAction())
390 # Rebase menu
391 self.rebase_menu = create_menu(N_('Rebase'), self.actions_menu)
392 self.rebase_menu.addAction(self.rebase_start_action)
393 self.rebase_menu.addAction(self.rebase_edit_todo_action)
394 self.rebase_menu.addSeparator()
395 self.rebase_menu.addAction(self.rebase_continue_action)
396 self.rebase_menu.addAction(self.rebase_skip_action)
397 self.rebase_menu.addSeparator()
398 self.rebase_menu.addAction(self.rebase_abort_action)
399 self.menubar.addAction(self.rebase_menu.menuAction())
401 # View Menu
402 self.view_menu = create_menu(N_('View'), self.menubar)
403 self.view_menu.addAction(self.browse_action)
404 self.view_menu.addAction(self.dag_action)
405 self.view_menu.addSeparator()
406 if self.browser_dockable:
407 self.view_menu.addAction(self.browserdockwidget.toggleViewAction())
409 self.setup_dockwidget_view_menu()
410 self.view_menu.addSeparator()
411 self.view_menu.addAction(self.lock_layout_action)
412 self.menubar.addAction(self.view_menu.menuAction())
414 # Help Menu
415 self.help_menu = create_menu(N_('Help'), self.menubar)
416 self.help_menu.addAction(self.help_docs_action)
417 self.help_menu.addAction(self.help_shortcuts_action)
418 self.help_menu.addAction(self.help_about_action)
419 self.menubar.addAction(self.help_menu.menuAction())
421 # Set main menu
422 self.setMenuBar(self.menubar)
424 # Arrange dock widgets
425 left = Qt.LeftDockWidgetArea
426 right = Qt.RightDockWidgetArea
427 bottom = Qt.BottomDockWidgetArea
429 self.addDockWidget(left, self.commitdockwidget)
430 if self.browser_dockable:
431 self.addDockWidget(left, self.browserdockwidget)
432 self.tabifyDockWidget(self.browserdockwidget, self.commitdockwidget)
433 self.addDockWidget(left, self.diffdockwidget)
434 self.addDockWidget(right, self.statusdockwidget)
435 self.addDockWidget(right, self.bookmarksdockwidget)
436 self.addDockWidget(bottom, self.actionsdockwidget)
437 self.addDockWidget(bottom, self.logdockwidget)
438 self.tabifyDockWidget(self.actionsdockwidget, self.logdockwidget)
441 # Listen for model notifications
442 model.add_observer(model.message_updated, self._update)
443 model.add_observer(model.message_mode_changed, lambda x: self._update())
445 prefs_model.add_observer(prefs_model.message_config_updated,
446 self._config_updated)
448 # Set a default value
449 self.show_cursor_position(1, 0)
451 self.connect(self.open_recent_menu, SIGNAL('aboutToShow()'),
452 self.build_recent_menu)
454 self.connect(self.commitmsgeditor, SIGNAL('cursorPosition(int,int)'),
455 self.show_cursor_position)
457 self.connect(self.diffeditor, SIGNAL('diff_options_updated()'),
458 self.statuswidget.refresh)
460 self.connect(self, SIGNAL('update'), self._update_callback)
461 self.connect(self, SIGNAL('install_config_actions'),
462 self._install_config_actions)
464 # Install .git-config-defined actions
465 self._config_task = None
466 self.install_config_actions()
468 # Restore saved settings
469 if not qtutils.apply_state(self):
470 self.set_initial_size()
472 self.statusdockwidget.widget().setFocus()
474 # Route command output here
475 Interaction.log_status = self.logwidget.log_status
476 Interaction.log = self.logwidget.log
477 Interaction.log(version.git_version_str() + '\n' +
478 N_('git cola version %s') % version.version())
480 def set_initial_size(self):
481 self.statuswidget.set_initial_size()
482 self.commitmsgeditor.set_initial_size()
484 # Qt overrides
485 def closeEvent(self, event):
486 """Save state in the settings manager."""
487 commit_msg = self.commitmsgeditor.commit_message(raw=True)
488 self.model.save_commitmsg(commit_msg)
489 MainWindow.closeEvent(self, event)
491 def build_recent_menu(self):
492 recent = settings.Settings().recent
493 cmd = cmds.OpenRepo
494 menu = self.open_recent_menu
495 menu.clear()
496 for r in recent:
497 name = os.path.basename(r)
498 directory = os.path.dirname(r)
499 text = '%s %s %s' % (name, unichr(0x2192), directory)
500 menu.addAction(text, cmds.run(cmd, r))
502 # Accessors
503 mode = property(lambda self: self.model.mode)
505 def _config_updated(self, source, config, value):
506 if config == prefs.FONTDIFF:
507 # The diff font
508 font = QtGui.QFont()
509 if not font.fromString(value):
510 return
511 self.logwidget.setFont(font)
512 self.diffeditor.setFont(font)
513 self.commitmsgeditor.setFont(font)
515 elif config == prefs.TABWIDTH:
516 # variable-tab-width setting
517 self.diffeditor.set_tabwidth(value)
518 self.commitmsgeditor.set_tabwidth(value)
520 elif config == prefs.LINEBREAK:
521 # enables automatic line breaks
522 self.commitmsgeditor.set_linebreak(value)
524 elif config == prefs.TEXTWIDTH:
525 # text width used for line wrapping
526 self.commitmsgeditor.set_textwidth(value)
528 def install_config_actions(self):
529 """Install .gitconfig-defined actions"""
530 self._config_task = self._start_config_actions_task()
532 def _start_config_actions_task(self):
533 """Do the expensive "get_config_actions()" call in the background"""
534 class ConfigActionsTask(QtCore.QRunnable):
535 def __init__(self, sender):
536 QtCore.QRunnable.__init__(self)
537 self._sender = sender
538 def run(self):
539 names = cfgactions.get_config_actions()
540 self._sender.emit(SIGNAL('install_config_actions'), names)
542 task = ConfigActionsTask(self)
543 QtCore.QThreadPool.globalInstance().start(task)
544 return task
546 def _install_config_actions(self, names):
547 """Install .gitconfig-defined actions"""
548 if not names:
549 return
550 menu = self.actions_menu
551 menu.addSeparator()
552 for name in names:
553 menu.addAction(name, cmds.run(cmds.RunConfigAction, name))
555 def _update(self):
556 self.emit(SIGNAL('update'))
558 def _update_callback(self):
559 """Update the title with the current branch and directory name."""
560 alerts = []
561 branch = self.model.currentbranch
562 curdir = core.getcwd()
563 is_merging = self.model.is_merging
564 is_rebasing = self.model.is_rebasing
566 msg = N_('Repository: %s') % curdir
567 msg += '\n'
568 msg += N_('Branch: %s') % branch
570 if is_rebasing:
571 msg += '\n\n'
572 msg += N_('This repository is currently being rebased.\n'
573 'Resolve conflicts, commit changes, and run:\n'
574 ' Rebase > Continue')
575 alerts.append(N_('Rebasing'))
577 elif is_merging:
578 msg += '\n\n'
579 msg += N_('This repository is in the middle of a merge.\n'
580 'Resolve conflicts and commit changes.')
581 alerts.append(N_('Merging'))
583 if self.mode == self.model.mode_amend:
584 alerts.append(N_('Amending'))
586 l = unichr(0xab)
587 r = unichr(0xbb)
588 title = ('%s: %s %s%s' % (
589 self.model.project,
590 branch,
591 alerts and ((r+' %s '+l+' ') % ', '.join(alerts)) or '',
592 self.model.git.worktree()))
594 self.setWindowTitle(title)
595 self.commitdockwidget.setToolTip(msg)
596 self.commitmsgeditor.set_mode(self.mode)
597 self.update_actions()
599 if not self.model.amending():
600 # Check if there's a message file in .git/
601 merge_msg_path = gitcmds.merge_message_path()
602 if merge_msg_path is None:
603 return
604 merge_msg_hash = utils.checksum(merge_msg_path)
605 if merge_msg_hash == self.merge_message_hash:
606 return
607 self.merge_message_hash = merge_msg_hash
608 cmds.do(cmds.LoadCommitMessageFromFile, merge_msg_path)
610 def update_actions(self):
611 is_rebasing = self.model.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))
623 return result
625 def setup_dockwidget_view_menu(self):
626 # Hotkeys for toggling the dock widgets
627 if utils.is_darwin():
628 optkey = 'Meta'
629 else:
630 optkey = 'Ctrl'
631 dockwidgets = (
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),
637 (optkey + '+5', self.bookmarksdockwidget),
639 for shortcut, dockwidget in dockwidgets:
640 # Associate the action with the shortcut
641 toggleview = dockwidget.toggleViewAction()
642 toggleview.setShortcut('Shift+' + shortcut)
643 self.view_menu.addAction(toggleview)
644 def showdock(show, dockwidget=dockwidget):
645 if show:
646 dockwidget.raise_()
647 dockwidget.widget().setFocus()
648 else:
649 self.setFocus()
650 self.addAction(toggleview)
651 connect_action_bool(toggleview, showdock)
653 # Create a new shortcut Shift+<shortcut> that gives focus
654 toggleview = QtGui.QAction(self)
655 toggleview.setShortcut(shortcut)
656 def focusdock(dockwidget=dockwidget, showdock=showdock):
657 if dockwidget.toggleViewAction().isChecked():
658 showdock(True)
659 else:
660 dockwidget.toggleViewAction().trigger()
661 self.addAction(toggleview)
662 connect_action(toggleview, focusdock)
664 def preferences(self):
665 return preferences(model=self.prefs_model, parent=self)
667 def save_archive(self):
668 ref = git.rev_parse('HEAD')[STDOUT]
669 shortref = ref[:7]
670 GitArchiveDialog.save(ref, shortref, self)
672 def show_cursor_position(self, rows, cols):
673 display = '&nbsp;%02d:%02d&nbsp;' % (rows, cols)
674 if cols > 78:
675 display = ('<span style="color: white; '
676 ' background-color: red;"'
677 '>%s</span>' % display)
678 elif cols > 72:
679 display = ('<span style="color: black; '
680 ' background-color: orange;"'
681 '>%s</span>' % display)
682 elif cols > 64:
683 display = ('<span style="color: black; '
684 ' background-color: yellow;"'
685 '>%s</span>' % display)
686 else:
687 display = ('<span style="color: grey;">%s</span>' % display)
689 self.position_label.setText(display)
691 def manage_bookmarks(self):
692 manage_bookmarks()
693 self.bookmarkswidget.refresh()
695 def rebase_start(self):
696 branch = guicmds.choose_ref(N_('Select New Upstream'),
697 N_('Interactive Rebase'))
698 if not branch:
699 return None
700 self.model.is_rebasing = True
701 self._update_callback()
702 cmds.do(cmds.Rebase, branch)
704 def rebase_edit_todo(self):
705 cmds.do(cmds.RebaseEditTodo)
707 def rebase_continue(self):
708 cmds.do(cmds.RebaseContinue)
710 def rebase_skip(self):
711 cmds.do(cmds.RebaseSkip)
713 def rebase_abort(self):
714 cmds.do(cmds.RebaseAbort)