def __init__(self, model, action, title, parent=None): """Customizes the dialog based on the remote action """ standard.Dialog.__init__(self, parent=parent) self.model = model self.action = action self.filtered_remote_branches = [] self.selected_remotes = [] self.setAttribute(Qt.WA_MacMetalStyle) self.setWindowTitle(title) if parent is not None: self.setWindowModality(Qt.WindowModal) self.task_runner = TaskRunner(self) self.progress = ProgressDialog(title, N_('Updating'), self) self.local_label = QtGui.QLabel() self.local_label.setText(N_('Local Branch')) self.local_branch = QtGui.QLineEdit() self.local_branches = QtGui.QListWidget() self.local_branches.addItems(self.model.local_branches) self.remote_label = QtGui.QLabel() self.remote_label.setText(N_('Remote')) self.remote_name = QtGui.QLineEdit() self.remotes = QtGui.QListWidget() if action == PUSH: self.remotes.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) self.remotes.addItems(self.model.remotes) self.remote_branch_label = QtGui.QLabel() self.remote_branch_label.setText(N_('Remote Branch')) self.remote_branch = QtGui.QLineEdit() self.remote_branches = QtGui.QListWidget() self.remote_branches.addItems(self.model.remote_branches) self.ffwd_only_checkbox = QtGui.QCheckBox() self.ffwd_only_checkbox.setText(N_('Fast Forward Only ')) self.ffwd_only_checkbox.setChecked(True) self.tags_checkbox = QtGui.QCheckBox() self.tags_checkbox.setText(N_('Include tags ')) self.rebase_checkbox = QtGui.QCheckBox() self.rebase_checkbox.setText(N_('Rebase ')) self.action_button = QtGui.QPushButton() self.action_button.setText(title) self.action_button.setIcon(qtutils.ok_icon()) self.close_button = QtGui.QPushButton() self.close_button.setText(N_('Close')) self.close_button.setIcon(qtutils.close_icon()) self.local_branch_layout = QtGui.QHBoxLayout() self.local_branch_layout.addWidget(self.local_label) self.local_branch_layout.addWidget(self.local_branch) self.remote_branch_layout = QtGui.QHBoxLayout() self.remote_branch_layout.addWidget(self.remote_label) self.remote_branch_layout.addWidget(self.remote_name) self.remote_branches_layout = QtGui.QHBoxLayout() self.remote_branches_layout.addWidget(self.remote_branch_label) self.remote_branches_layout.addWidget(self.remote_branch) self.options_layout = QtGui.QHBoxLayout() self.options_layout.setSpacing(defs.button_spacing) self.options_layout.addStretch() self.options_layout.addWidget(self.ffwd_only_checkbox) self.options_layout.addWidget(self.tags_checkbox) self.options_layout.addWidget(self.rebase_checkbox) self.options_layout.addWidget(self.action_button) self.options_layout.addWidget(self.close_button) self.main_layout = QtGui.QVBoxLayout() self.main_layout.setMargin(defs.margin) self.main_layout.setSpacing(defs.spacing) self.main_layout.addLayout(self.remote_branch_layout) self.main_layout.addWidget(self.remotes) if action == PUSH: self.main_layout.addLayout(self.local_branch_layout) self.main_layout.addWidget(self.local_branches) self.main_layout.addLayout(self.remote_branches_layout) self.main_layout.addWidget(self.remote_branches) else: # fetch and pull self.main_layout.addLayout(self.remote_branches_layout) self.main_layout.addWidget(self.remote_branches) self.main_layout.addLayout(self.local_branch_layout) self.main_layout.addWidget(self.local_branches) self.main_layout.addLayout(self.options_layout) self.setLayout(self.main_layout) default_remote = gitcmds.default_remote() or 'origin' remotes = self.model.remotes if default_remote in remotes: idx = remotes.index(default_remote) if self.select_remote(idx): self.remote_name.setText(default_remote) else: if self.select_first_remote(): self.remote_name.setText(remotes[0]) # Trim the remote list to just the default remote self.update_remotes() self.set_field_defaults() # Setup signals and slots self.connect(self.remotes, SIGNAL('itemSelectionChanged()'), self.update_remotes) self.connect(self.local_branches, SIGNAL('itemSelectionChanged()'), self.update_local_branches) self.connect(self.remote_branches, SIGNAL('itemSelectionChanged()'), self.update_remote_branches) connect_button(self.action_button, self.action_callback) connect_button(self.close_button, self.close) qtutils.add_action(self, N_('Close'), self.close, QtGui.QKeySequence.Close, 'Esc') if action == PULL: self.tags_checkbox.hide() self.ffwd_only_checkbox.hide() self.local_label.hide() self.local_branch.hide() self.local_branches.hide() self.remote_branch.setFocus() else: self.rebase_checkbox.hide() if not self.restore_state(): self.resize(666, 420) self.remote_name.setFocus()
def __init__(self, model, action, title, parent=None): """Customizes the dialog based on the remote action """ standard.Dialog.__init__(self, parent=parent) self.model = model self.action = action self.filtered_remote_branches = [] self.selected_remotes = [] self.setAttribute(Qt.WA_MacMetalStyle) self.setWindowTitle(title) if parent is not None: self.setWindowModality(Qt.WindowModal) self.task_runner = TaskRunner(self) self.progress = ProgressDialog(title, N_('Updating'), self) self.local_label = QtGui.QLabel() self.local_label.setText(N_('Local Branch')) self.local_branch = QtGui.QLineEdit() self.local_branches = QtGui.QListWidget() self.local_branches.addItems(self.model.local_branches) self.remote_label = QtGui.QLabel() self.remote_label.setText(N_('Remote')) self.remote_name = QtGui.QLineEdit() self.remotes = QtGui.QListWidget() if action == PUSH: self.remotes.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection) self.remotes.addItems(self.model.remotes) self.remote_branch_label = QtGui.QLabel() self.remote_branch_label.setText(N_('Remote Branch')) self.remote_branch = QtGui.QLineEdit() self.remote_branches = QtGui.QListWidget() self.remote_branches.addItems(self.model.remote_branches) self.ffwd_only_checkbox = QtGui.QCheckBox() self.ffwd_only_checkbox.setText(N_('Fast Forward Only ')) self.ffwd_only_checkbox.setChecked(True) self.tags_checkbox = QtGui.QCheckBox() self.tags_checkbox.setText(N_('Include tags ')) self.rebase_checkbox = QtGui.QCheckBox() self.rebase_checkbox.setText(N_('Rebase ')) self.action_button = QtGui.QPushButton() self.action_button.setText(title) self.action_button.setIcon(qtutils.ok_icon()) self.close_button = QtGui.QPushButton() self.close_button.setText(N_('Close')) self.close_button.setIcon(qtutils.close_icon()) self.local_branch_layout = qtutils.hbox(defs.small_margin, defs.spacing, self.local_label, self.local_branch) self.remote_branch_layout = qtutils.hbox(defs.small_margin, defs.spacing, self.remote_label, self.remote_name) self.remote_branches_layout = qtutils.hbox(defs.small_margin, defs.spacing, self.remote_branch_label, self.remote_branch) self.options_layout = qtutils.hbox( defs.no_margin, defs.button_spacing, qtutils.STRETCH, self.ffwd_only_checkbox, self.tags_checkbox, self.rebase_checkbox, self.action_button, self.close_button) if action == PUSH: widgets = ( self.remote_branch_layout, self.remotes, self.local_branch_layout, self.local_branches, self.remote_branches_layout, self.remote_branches, self.options_layout, ) else: # fetch and pull widgets = ( self.remote_branch_layout, self.remotes, self.remote_branches_layout, self.remote_branches, self.local_branch_layout, self.local_branches, self.options_layout, ) self.main_layout = qtutils.vbox(defs.no_margin, defs.spacing, *widgets) self.setLayout(self.main_layout) default_remote = gitcmds.default_remote() or 'origin' remotes = self.model.remotes if default_remote in remotes: idx = remotes.index(default_remote) if self.select_remote(idx): self.remote_name.setText(default_remote) else: if self.select_first_remote(): self.remote_name.setText(remotes[0]) # Trim the remote list to just the default remote self.update_remotes() self.set_field_defaults() # Setup signals and slots self.connect(self.remotes, SIGNAL('itemSelectionChanged()'), self.update_remotes) self.connect(self.local_branches, SIGNAL('itemSelectionChanged()'), self.update_local_branches) self.connect(self.remote_branches, SIGNAL('itemSelectionChanged()'), self.update_remote_branches) connect_button(self.action_button, self.action_callback) connect_button(self.close_button, self.close) qtutils.add_action(self, N_('Close'), self.close, QtGui.QKeySequence.Close, 'Esc') if action == PULL: self.tags_checkbox.hide() self.ffwd_only_checkbox.hide() self.local_label.hide() self.local_branch.hide() self.local_branches.hide() self.remote_branch.setFocus() else: self.rebase_checkbox.hide() if not self.restore_state(): self.resize(666, 420) self.remote_name.setFocus()
class RemoteActionDialog(standard.Dialog): def __init__(self, model, action, title, parent=None): """Customizes the dialog based on the remote action """ standard.Dialog.__init__(self, parent=parent) self.model = model self.action = action self.filtered_remote_branches = [] self.selected_remotes = [] self.setAttribute(Qt.WA_MacMetalStyle) self.setWindowTitle(title) if parent is not None: self.setWindowModality(Qt.WindowModal) self.task_runner = TaskRunner(self) self.progress = ProgressDialog(title, N_('Updating'), self) self.local_label = QtGui.QLabel() self.local_label.setText(N_('Local Branch')) self.local_branch = QtGui.QLineEdit() self.local_branches = QtGui.QListWidget() self.local_branches.addItems(self.model.local_branches) self.remote_label = QtGui.QLabel() self.remote_label.setText(N_('Remote')) self.remote_name = QtGui.QLineEdit() self.remotes = QtGui.QListWidget() if action == PUSH: self.remotes.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) self.remotes.addItems(self.model.remotes) self.remote_branch_label = QtGui.QLabel() self.remote_branch_label.setText(N_('Remote Branch')) self.remote_branch = QtGui.QLineEdit() self.remote_branches = QtGui.QListWidget() self.remote_branches.addItems(self.model.remote_branches) self.ffwd_only_checkbox = QtGui.QCheckBox() self.ffwd_only_checkbox.setText(N_('Fast Forward Only ')) self.ffwd_only_checkbox.setChecked(True) self.tags_checkbox = QtGui.QCheckBox() self.tags_checkbox.setText(N_('Include tags ')) self.rebase_checkbox = QtGui.QCheckBox() self.rebase_checkbox.setText(N_('Rebase ')) self.action_button = QtGui.QPushButton() self.action_button.setText(title) self.action_button.setIcon(qtutils.ok_icon()) self.close_button = QtGui.QPushButton() self.close_button.setText(N_('Close')) self.close_button.setIcon(qtutils.close_icon()) self.local_branch_layout = QtGui.QHBoxLayout() self.local_branch_layout.addWidget(self.local_label) self.local_branch_layout.addWidget(self.local_branch) self.remote_branch_layout = QtGui.QHBoxLayout() self.remote_branch_layout.addWidget(self.remote_label) self.remote_branch_layout.addWidget(self.remote_name) self.remote_branches_layout = QtGui.QHBoxLayout() self.remote_branches_layout.addWidget(self.remote_branch_label) self.remote_branches_layout.addWidget(self.remote_branch) self.options_layout = QtGui.QHBoxLayout() self.options_layout.setSpacing(defs.button_spacing) self.options_layout.addStretch() self.options_layout.addWidget(self.ffwd_only_checkbox) self.options_layout.addWidget(self.tags_checkbox) self.options_layout.addWidget(self.rebase_checkbox) self.options_layout.addWidget(self.action_button) self.options_layout.addWidget(self.close_button) self.main_layout = QtGui.QVBoxLayout() self.main_layout.setMargin(defs.margin) self.main_layout.setSpacing(defs.spacing) self.main_layout.addLayout(self.remote_branch_layout) self.main_layout.addWidget(self.remotes) if action == PUSH: self.main_layout.addLayout(self.local_branch_layout) self.main_layout.addWidget(self.local_branches) self.main_layout.addLayout(self.remote_branches_layout) self.main_layout.addWidget(self.remote_branches) else: # fetch and pull self.main_layout.addLayout(self.remote_branches_layout) self.main_layout.addWidget(self.remote_branches) self.main_layout.addLayout(self.local_branch_layout) self.main_layout.addWidget(self.local_branches) self.main_layout.addLayout(self.options_layout) self.setLayout(self.main_layout) default_remote = gitcmds.default_remote() or 'origin' remotes = self.model.remotes if default_remote in remotes: idx = remotes.index(default_remote) if self.select_remote(idx): self.remote_name.setText(default_remote) else: if self.select_first_remote(): self.remote_name.setText(remotes[0]) # Trim the remote list to just the default remote self.update_remotes() self.set_field_defaults() # Setup signals and slots self.connect(self.remotes, SIGNAL('itemSelectionChanged()'), self.update_remotes) self.connect(self.local_branches, SIGNAL('itemSelectionChanged()'), self.update_local_branches) self.connect(self.remote_branches, SIGNAL('itemSelectionChanged()'), self.update_remote_branches) connect_button(self.action_button, self.action_callback) connect_button(self.close_button, self.close) qtutils.add_action(self, N_('Close'), self.close, QtGui.QKeySequence.Close, 'Esc') if action == PULL: self.tags_checkbox.hide() self.ffwd_only_checkbox.hide() self.local_label.hide() self.local_branch.hide() self.local_branches.hide() self.remote_branch.setFocus() else: self.rebase_checkbox.hide() if not self.restore_state(): self.resize(666, 420) self.remote_name.setFocus() def set_rebase(self, value): self.rebase_checkbox.setChecked(value) def set_field_defaults(self): # Default to "git fetch origin master" action = self.action if action == FETCH or action == PULL: self.local_branch.setText('') self.remote_branch.setText('') return # Select the current branch by default for push if action == PUSH: branch = self.model.currentbranch try: idx = self.model.local_branches.index(branch) except ValueError: return if self.select_local_branch(idx): self.set_local_branch(branch) self.set_remote_branch('') def set_remote_name(self, remote_name): self.remote_name.setText(remote_name) if remote_name: self.remote_name.selectAll() def set_local_branch(self, branch): self.local_branch.setText(branch) if branch: self.local_branch.selectAll() def set_remote_branch(self, branch): self.remote_branch.setText(branch) if branch: self.remote_branch.selectAll() def set_remote_branches(self, branches): self.remote_branches.clear() self.remote_branches.addItems(branches) self.filtered_remote_branches = branches def select_first_remote(self): """Selects the first remote in the list view""" return self.select_remote(0) def select_remote(self, idx): """Selects a remote by index""" item = self.remotes.item(idx) if item: self.remotes.setItemSelected(item, True) self.remotes.setCurrentItem(item) self.set_remote_name(ustr(item.text())) return True else: return False def select_local_branch(self, idx): """Selects a local branch by index in the list view""" item = self.local_branches.item(idx) if not item: return False self.local_branches.setItemSelected(item, True) self.local_branches.setCurrentItem(item) self.local_branch.setText(item.text()) return True def display_remotes(self, widget): """Display the available remotes in a listwidget""" displayed = [] for remote_name in self.model.remotes: url = self.model.remote_url(remote_name, self.action) display = ('%s\t(%s)' % (remote_name, N_('URL: %s') % url)) displayed.append(display) qtutils.set_items(widget,displayed) def update_remotes(self, *rest): """Update the remote name when a remote from the list is selected""" widget = self.remotes remotes = self.model.remotes selection = qtutils.selected_item(widget, remotes) if not selection: self.selected_remotes = [] return self.set_remote_name(selection) self.selected_remotes = qtutils.selected_items(self.remotes, self.model.remotes) all_branches = gitcmds.branch_list(remote=True) branches = [] patterns = [] for remote in self.selected_remotes: pat = remote + '/*' patterns.append(pat) for branch in all_branches: for pat in patterns: if fnmatch.fnmatch(branch, pat): branches.append(branch) break if branches: self.set_remote_branches(branches) else: self.set_remote_branches(all_branches) self.set_remote_branch('') def update_local_branches(self,*rest): """Update the local/remote branch names when a branch is selected""" branches = self.model.local_branches widget = self.local_branches selection = qtutils.selected_item(widget, branches) if not selection: return self.set_local_branch(selection) self.set_remote_branch(selection) def update_remote_branches(self,*rest): """Update the remote branch name when a branch is selected""" widget = self.remote_branches branches = self.filtered_remote_branches selection = qtutils.selected_item(widget, branches) if not selection: return branch = utils.strip_one(selection) if branch == 'HEAD': return self.set_remote_branch(branch) def common_args(self): """Returns git arguments common to fetch/push/pulll""" remote_name = ustr(self.remote_name.text()) local_branch = ustr(self.local_branch.text()) remote_branch = ustr(self.remote_branch.text()) ffwd_only = self.ffwd_only_checkbox.isChecked() rebase = self.rebase_checkbox.isChecked() tags = self.tags_checkbox.isChecked() return (remote_name, { 'local_branch': local_branch, 'remote_branch': remote_branch, 'ffwd': ffwd_only, 'rebase': rebase, 'tags': tags, }) # Actions def push_to_all(self, dummy_remote, *args, **kwargs): selected_remotes = self.selected_remotes all_results = None for remote in selected_remotes: result = self.model.push(remote, *args, **kwargs) all_results = combine(result, all_results) return all_results def action_callback(self): action = self.action if action == FETCH: model_action = self.model.fetch elif action == PUSH: model_action = self.push_to_all else: # if action == PULL: model_action = self.model.pull remote_name = ustr(self.remote_name.text()) if not remote_name: errmsg = N_('No repository selected.') Interaction.log(errmsg) return remote, kwargs = self.common_args() self.selected_remotes = qtutils.selected_items(self.remotes, self.model.remotes) # Check if we're about to create a new branch and warn. remote_branch = ustr(self.remote_branch.text()) local_branch = ustr(self.local_branch.text()) if action == PUSH and not remote_branch: branch = local_branch candidate = '%s/%s' % (remote, branch) if candidate not in self.model.remote_branches: title = N_('Push') args = dict(branch=branch, remote=remote) msg = N_('Branch "%(branch)s" does not exist in "%(remote)s".\n' 'A new remote branch will be published.') % args info_txt= N_('Create a new remote branch?') ok_text = N_('Create Remote Branch') if not qtutils.confirm(title, msg, info_txt, ok_text, default=False, icon=qtutils.git_icon()): return if not self.ffwd_only_checkbox.isChecked(): if action == FETCH: title = N_('Force Fetch?') msg = N_('Non-fast-forward fetch overwrites local history!') info_txt = N_('Force fetching from %s?') % remote ok_text = N_('Force Fetch') elif action == PUSH: title = N_('Force Push?') msg = N_('Non-fast-forward push overwrites published ' 'history!\n(Did you pull first?)') info_txt = N_('Force push to %s?') % remote ok_text = N_('Force Push') else: # pull: shouldn't happen since the controls are hidden msg = "You probably don't want to do this.\n\tContinue?" return if not qtutils.confirm(title, msg, info_txt, ok_text, default=False, icon=qtutils.discard_icon()): return # Disable the GUI by default self.action_button.setEnabled(False) self.close_button.setEnabled(False) # Use a thread to update in the background task = ActionTask(self.task_runner, model_action, remote, kwargs) self.task_runner.start(task, progress=self.progress, finish=self.action_completed) def action_completed(self, task, status, out, err): # Grab the results of the action and finish up self.action_button.setEnabled(True) self.close_button.setEnabled(True) already_up_to_date = N_('Already up-to-date.') if not out: # git fetch --tags --verbose doesn't print anything... out = already_up_to_date command = 'git %s' % self.action.lower() message = (N_('"%(command)s" returned exit status %(status)d') % dict(command=command, status=status)) details = '' if out: details = out if err: details += '\n\n' + err log_message = message if details: log_message += '\n\n' + details Interaction.log(log_message) if status == 0: self.accept() return if self.action == PUSH: message += '\n\n' message += N_('Have you rebased/pulled lately?') Interaction.critical(self.windowTitle(), message=message, details=details)
class RemoteActionDialog(standard.Dialog): def __init__(self, model, action, title, parent=None): """Customizes the dialog based on the remote action """ standard.Dialog.__init__(self, parent=parent) self.model = model self.action = action self.filtered_remote_branches = [] self.selected_remotes = [] self.setAttribute(Qt.WA_MacMetalStyle) self.setWindowTitle(title) if parent is not None: self.setWindowModality(Qt.WindowModal) self.task_runner = TaskRunner(self) self.progress = ProgressDialog(title, N_('Updating'), self) self.local_label = QtGui.QLabel() self.local_label.setText(N_('Local Branch')) self.local_branch = QtGui.QLineEdit() self.local_branches = QtGui.QListWidget() self.local_branches.addItems(self.model.local_branches) self.remote_label = QtGui.QLabel() self.remote_label.setText(N_('Remote')) self.remote_name = QtGui.QLineEdit() self.remotes = QtGui.QListWidget() if action == PUSH: self.remotes.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection) self.remotes.addItems(self.model.remotes) self.remote_branch_label = QtGui.QLabel() self.remote_branch_label.setText(N_('Remote Branch')) self.remote_branch = QtGui.QLineEdit() self.remote_branches = QtGui.QListWidget() self.remote_branches.addItems(self.model.remote_branches) self.ffwd_only_checkbox = QtGui.QCheckBox() self.ffwd_only_checkbox.setText(N_('Fast Forward Only ')) self.ffwd_only_checkbox.setChecked(True) self.tags_checkbox = QtGui.QCheckBox() self.tags_checkbox.setText(N_('Include tags ')) self.rebase_checkbox = QtGui.QCheckBox() self.rebase_checkbox.setText(N_('Rebase ')) self.action_button = QtGui.QPushButton() self.action_button.setText(title) self.action_button.setIcon(qtutils.ok_icon()) self.close_button = QtGui.QPushButton() self.close_button.setText(N_('Close')) self.close_button.setIcon(qtutils.close_icon()) self.local_branch_layout = qtutils.hbox(defs.small_margin, defs.spacing, self.local_label, self.local_branch) self.remote_branch_layout = qtutils.hbox(defs.small_margin, defs.spacing, self.remote_label, self.remote_name) self.remote_branches_layout = qtutils.hbox(defs.small_margin, defs.spacing, self.remote_branch_label, self.remote_branch) self.options_layout = qtutils.hbox( defs.no_margin, defs.button_spacing, qtutils.STRETCH, self.ffwd_only_checkbox, self.tags_checkbox, self.rebase_checkbox, self.action_button, self.close_button) if action == PUSH: widgets = ( self.remote_branch_layout, self.remotes, self.local_branch_layout, self.local_branches, self.remote_branches_layout, self.remote_branches, self.options_layout, ) else: # fetch and pull widgets = ( self.remote_branch_layout, self.remotes, self.remote_branches_layout, self.remote_branches, self.local_branch_layout, self.local_branches, self.options_layout, ) self.main_layout = qtutils.vbox(defs.no_margin, defs.spacing, *widgets) self.setLayout(self.main_layout) default_remote = gitcmds.default_remote() or 'origin' remotes = self.model.remotes if default_remote in remotes: idx = remotes.index(default_remote) if self.select_remote(idx): self.remote_name.setText(default_remote) else: if self.select_first_remote(): self.remote_name.setText(remotes[0]) # Trim the remote list to just the default remote self.update_remotes() self.set_field_defaults() # Setup signals and slots self.connect(self.remotes, SIGNAL('itemSelectionChanged()'), self.update_remotes) self.connect(self.local_branches, SIGNAL('itemSelectionChanged()'), self.update_local_branches) self.connect(self.remote_branches, SIGNAL('itemSelectionChanged()'), self.update_remote_branches) connect_button(self.action_button, self.action_callback) connect_button(self.close_button, self.close) qtutils.add_action(self, N_('Close'), self.close, QtGui.QKeySequence.Close, 'Esc') if action == PULL: self.tags_checkbox.hide() self.ffwd_only_checkbox.hide() self.local_label.hide() self.local_branch.hide() self.local_branches.hide() self.remote_branch.setFocus() else: self.rebase_checkbox.hide() if not self.restore_state(): self.resize(666, 420) self.remote_name.setFocus() def set_rebase(self, value): self.rebase_checkbox.setChecked(value) def set_field_defaults(self): # Default to "git fetch origin master" action = self.action if action == FETCH or action == PULL: self.local_branch.setText('') self.remote_branch.setText('') return # Select the current branch by default for push if action == PUSH: branch = self.model.currentbranch try: idx = self.model.local_branches.index(branch) except ValueError: return if self.select_local_branch(idx): self.set_local_branch(branch) self.set_remote_branch('') def set_remote_name(self, remote_name): self.remote_name.setText(remote_name) if remote_name: self.remote_name.selectAll() def set_local_branch(self, branch): self.local_branch.setText(branch) if branch: self.local_branch.selectAll() def set_remote_branch(self, branch): self.remote_branch.setText(branch) if branch: self.remote_branch.selectAll() def set_remote_branches(self, branches): self.remote_branches.clear() self.remote_branches.addItems(branches) self.filtered_remote_branches = branches def select_first_remote(self): """Selects the first remote in the list view""" return self.select_remote(0) def select_remote(self, idx): """Selects a remote by index""" item = self.remotes.item(idx) if item: self.remotes.setItemSelected(item, True) self.remotes.setCurrentItem(item) self.set_remote_name(ustr(item.text())) return True else: return False def select_local_branch(self, idx): """Selects a local branch by index in the list view""" item = self.local_branches.item(idx) if not item: return False self.local_branches.setItemSelected(item, True) self.local_branches.setCurrentItem(item) self.local_branch.setText(item.text()) return True def display_remotes(self, widget): """Display the available remotes in a listwidget""" displayed = [] for remote_name in self.model.remotes: url = self.model.remote_url(remote_name, self.action) display = ('%s\t(%s)' % (remote_name, N_('URL: %s') % url)) displayed.append(display) qtutils.set_items(widget, displayed) def update_remotes(self, *rest): """Update the remote name when a remote from the list is selected""" widget = self.remotes remotes = self.model.remotes selection = qtutils.selected_item(widget, remotes) if not selection: self.selected_remotes = [] return self.set_remote_name(selection) self.selected_remotes = qtutils.selected_items(self.remotes, self.model.remotes) all_branches = gitcmds.branch_list(remote=True) branches = [] patterns = [] for remote in self.selected_remotes: pat = remote + '/*' patterns.append(pat) for branch in all_branches: for pat in patterns: if fnmatch.fnmatch(branch, pat): branches.append(branch) break if branches: self.set_remote_branches(branches) else: self.set_remote_branches(all_branches) self.set_remote_branch('') def update_local_branches(self, *rest): """Update the local/remote branch names when a branch is selected""" branches = self.model.local_branches widget = self.local_branches selection = qtutils.selected_item(widget, branches) if not selection: return self.set_local_branch(selection) self.set_remote_branch(selection) def update_remote_branches(self, *rest): """Update the remote branch name when a branch is selected""" widget = self.remote_branches branches = self.filtered_remote_branches selection = qtutils.selected_item(widget, branches) if not selection: return branch = utils.strip_one(selection) if branch == 'HEAD': return self.set_remote_branch(branch) def common_args(self): """Returns git arguments common to fetch/push/pulll""" remote_name = ustr(self.remote_name.text()) local_branch = ustr(self.local_branch.text()) remote_branch = ustr(self.remote_branch.text()) ffwd_only = self.ffwd_only_checkbox.isChecked() rebase = self.rebase_checkbox.isChecked() tags = self.tags_checkbox.isChecked() return (remote_name, { 'local_branch': local_branch, 'remote_branch': remote_branch, 'ffwd': ffwd_only, 'rebase': rebase, 'tags': tags, }) # Actions def push_to_all(self, dummy_remote, *args, **kwargs): selected_remotes = self.selected_remotes all_results = None for remote in selected_remotes: result = self.model.push(remote, *args, **kwargs) all_results = combine(result, all_results) return all_results def action_callback(self): action = self.action if action == FETCH: model_action = self.model.fetch elif action == PUSH: model_action = self.push_to_all else: # if action == PULL: model_action = self.model.pull remote_name = ustr(self.remote_name.text()) if not remote_name: errmsg = N_('No repository selected.') Interaction.log(errmsg) return remote, kwargs = self.common_args() self.selected_remotes = qtutils.selected_items(self.remotes, self.model.remotes) # Check if we're about to create a new branch and warn. remote_branch = ustr(self.remote_branch.text()) local_branch = ustr(self.local_branch.text()) if action == PUSH and not remote_branch: branch = local_branch candidate = '%s/%s' % (remote, branch) if candidate not in self.model.remote_branches: title = N_('Push') args = dict(branch=branch, remote=remote) msg = N_( 'Branch "%(branch)s" does not exist in "%(remote)s".\n' 'A new remote branch will be published.') % args info_txt = N_('Create a new remote branch?') ok_text = N_('Create Remote Branch') if not qtutils.confirm( title, msg, info_txt, ok_text, icon=qtutils.git_icon()): return if not self.ffwd_only_checkbox.isChecked(): if action == FETCH: title = N_('Force Fetch?') msg = N_('Non-fast-forward fetch overwrites local history!') info_txt = N_('Force fetching from %s?') % remote ok_text = N_('Force Fetch') elif action == PUSH: title = N_('Force Push?') msg = N_('Non-fast-forward push overwrites published ' 'history!\n(Did you pull first?)') info_txt = N_('Force push to %s?') % remote ok_text = N_('Force Push') else: # pull: shouldn't happen since the controls are hidden msg = "You probably don't want to do this.\n\tContinue?" return if not qtutils.confirm(title, msg, info_txt, ok_text, default=False, icon=qtutils.discard_icon()): return # Disable the GUI by default self.action_button.setEnabled(False) self.close_button.setEnabled(False) # Use a thread to update in the background task = ActionTask(self.task_runner, model_action, remote, kwargs) self.task_runner.start(task, progress=self.progress, finish=self.action_completed) def action_completed(self, task, status, out, err): # Grab the results of the action and finish up self.action_button.setEnabled(True) self.close_button.setEnabled(True) already_up_to_date = N_('Already up-to-date.') if not out: # git fetch --tags --verbose doesn't print anything... out = already_up_to_date command = 'git %s' % self.action.lower() message = (N_('"%(command)s" returned exit status %(status)d') % dict(command=command, status=status)) details = '' if out: details = out if err: details += '\n\n' + err log_message = message if details: log_message += '\n\n' + details Interaction.log(log_message) if status == 0: self.accept() return if self.action == PUSH: message += '\n\n' message += N_('Have you rebased/pulled lately?') Interaction.critical(self.windowTitle(), message=message, details=details)
def __init__(self, model, parent=None, settings=None): standard.MainWindow.__init__(self, parent) self.setAttribute(Qt.WA_MacMetalStyle) # Default size; this is thrown out when save/restore is used self.model = model self.settings = settings self.prefs_model = prefs_model = prefs.PreferencesModel() # The widget version is used by import/export_state(). # Change this whenever dockwidgets are removed. self.widget_version = 2 # Runs asynchronous tasks self.task_runner = TaskRunner(self) self.runtask = qtutils.RunTask() self.progress = standard.ProgressDialog('', '', self) cfg = gitcfg.current() self.browser_dockable = (cfg.get('cola.browserdockable') or cfg.get('cola.classicdockable')) if self.browser_dockable: self.browserdockwidget = create_dock(N_('Browser'), self) self.browserwidget = browse.worktree_browser_widget(self) self.browserdockwidget.setWidget(self.browserwidget) # "Actions" widget self.actionsdockwidget = create_dock(N_('Actions'), self) self.actionsdockwidgetcontents = action.ActionButtons(self) self.actionsdockwidget.setWidget(self.actionsdockwidgetcontents) self.actionsdockwidget.toggleViewAction().setChecked(False) self.actionsdockwidget.hide() # "Repository Status" widget self.statusdockwidget = create_dock(N_('Status'), self) titlebar = self.statusdockwidget.titleBarWidget() self.statuswidget = status.StatusWidget(titlebar, parent=self.statusdockwidget) self.statusdockwidget.setWidget(self.statuswidget) # "Switch Repository" widgets self.bookmarksdockwidget = create_dock(N_('Favorites'), self) self.bookmarkswidget = bookmarks.BookmarksWidget( bookmarks.BOOKMARKS, parent=self.bookmarksdockwidget) self.bookmarksdockwidget.setWidget(self.bookmarkswidget) self.recentdockwidget = create_dock(N_('Recent'), self) self.recentwidget = bookmarks.BookmarksWidget( bookmarks.RECENT_REPOS, parent=self.recentdockwidget) self.recentdockwidget.setWidget(self.recentwidget) self.recentdockwidget.hide() # "Commit Message Editor" widget self.position_label = QtGui.QLabel() font = qtutils.default_monospace_font() font.setPointSize(int(font.pointSize() * 0.8)) self.position_label.setFont(font) # make the position label fixed size to avoid layout issues fm = self.position_label.fontMetrics() width = fm.width('999:999') + defs.spacing height = self.position_label.sizeHint().height() + defs.spacing self.position_label.setFixedSize(width, height) self.commitdockwidget = create_dock(N_('Commit'), self) titlebar = self.commitdockwidget.titleBarWidget() titlebar.add_corner_widget(self.position_label) self.commitmsgeditor = commitmsg.CommitMessageEditor(model, self) self.commitdockwidget.setWidget(self.commitmsgeditor) # "Console" widget self.logwidget = log.LogWidget() self.logdockwidget = create_dock(N_('Console'), self) self.logdockwidget.setWidget(self.logwidget) self.logdockwidget.toggleViewAction().setChecked(False) self.logdockwidget.hide() # "Diff Viewer" widget self.diffdockwidget = create_dock(N_('Diff'), self) self.diffeditorwidget = diff.DiffEditorWidget(self.diffdockwidget) self.diffeditor = self.diffeditorwidget.editor self.diffdockwidget.setWidget(self.diffeditorwidget) # All Actions self.unstage_all_action = add_action(self, N_('Unstage All'), cmds.run(cmds.UnstageAll)) self.unstage_all_action.setIcon(icons.remove()) self.unstage_selected_action = add_action( self, N_('Unstage From Commit'), cmds.run(cmds.UnstageSelected)) self.unstage_selected_action.setIcon(icons.remove()) self.show_diffstat_action = add_action(self, N_('Diffstat'), cmds.run(cmds.Diffstat), hotkeys.DIFFSTAT) self.stage_modified_action = add_action( self, N_('Stage Changed Files To Commit'), cmds.run(cmds.StageModified), hotkeys.STAGE_MODIFIED) self.stage_modified_action.setIcon(icons.add()) self.stage_untracked_action = add_action(self, N_('Stage All Untracked'), cmds.run(cmds.StageUntracked), hotkeys.STAGE_UNTRACKED) self.stage_untracked_action.setIcon(icons.add()) self.apply_patches_action = add_action(self, N_('Apply Patches...'), patch.apply_patches) self.export_patches_action = add_action(self, N_('Export Patches...'), guicmds.export_patches, hotkeys.EXPORT) self.new_repository_action = add_action(self, N_('New Repository...'), guicmds.open_new_repo) self.new_repository_action.setIcon(icons.new()) self.preferences_action = add_action(self, N_('Preferences'), self.preferences, QtGui.QKeySequence.Preferences) self.edit_remotes_action = add_action( self, N_('Edit Remotes...'), lambda: editremotes.remote_editor().exec_()) self.rescan_action = add_action(self, cmds.Refresh.name(), cmds.run(cmds.Refresh), *hotkeys.REFRESH_HOTKEYS) self.rescan_action.setIcon(icons.sync()) self.find_files_action = add_action(self, N_('Find Files'), finder.finder, hotkeys.FINDER, hotkeys.FINDER_SECONDARY) self.find_files_action.setIcon(icons.zoom_in()) self.browse_recently_modified_action = add_action( self, N_('Recently Modified Files...'), recent.browse_recent_files, hotkeys.EDIT_SECONDARY) self.cherry_pick_action = add_action(self, N_('Cherry-Pick...'), guicmds.cherry_pick, hotkeys.CHERRY_PICK) self.load_commitmsg_action = add_action(self, N_('Load Commit Message...'), guicmds.load_commitmsg) self.save_tarball_action = add_action(self, N_('Save As Tarball/Zip...'), self.save_archive) self.quit_action = add_action(self, N_('Quit'), self.close, hotkeys.QUIT) self.grep_action = add_action(self, N_('Grep'), grep.grep, hotkeys.GREP) self.merge_local_action = add_action(self, N_('Merge...'), merge.local_merge, hotkeys.MERGE) self.merge_abort_action = add_action(self, N_('Abort Merge...'), merge.abort_merge) self.fetch_action = add_action(self, N_('Fetch...'), remote.fetch, hotkeys.FETCH) self.push_action = add_action(self, N_('Push...'), remote.push, hotkeys.PUSH) self.pull_action = add_action(self, N_('Pull...'), remote.pull, hotkeys.PULL) self.open_repo_action = add_action(self, N_('Open...'), guicmds.open_repo) self.open_repo_action.setIcon(icons.folder()) self.open_repo_new_action = add_action(self, N_('Open in New Window...'), guicmds.open_repo_in_new_window) self.open_repo_new_action.setIcon(icons.folder()) self.stash_action = add_action(self, N_('Stash...'), stash.stash, hotkeys.STASH) self.clone_repo_action = add_action(self, N_('Clone...'), self.clone_repo) self.clone_repo_action.setIcon(icons.repo()) self.help_docs_action = add_action(self, N_('Documentation'), resources.show_html_docs, QtGui.QKeySequence.HelpContents) self.help_shortcuts_action = add_action(self, N_('Keyboard Shortcuts'), about.show_shortcuts, hotkeys.QUESTION) self.visualize_current_action = add_action( self, N_('Visualize Current Branch...'), cmds.run(cmds.VisualizeCurrent)) self.visualize_all_action = add_action(self, N_('Visualize All Branches...'), cmds.run(cmds.VisualizeAll)) self.search_commits_action = add_action(self, N_('Search...'), search.search) self.browse_branch_action = add_action(self, N_('Browse Current Branch...'), guicmds.browse_current) self.browse_other_branch_action = add_action( self, N_('Browse Other Branch...'), guicmds.browse_other) self.load_commitmsg_template_action = add_action( self, N_('Get Commit Message Template'), cmds.run(cmds.LoadCommitMessageFromTemplate)) self.help_about_action = add_action(self, N_('About'), about.launch_about_dialog) self.diff_expression_action = add_action(self, N_('Expression...'), guicmds.diff_expression) self.branch_compare_action = add_action(self, N_('Branches...'), compare.compare_branches) self.create_tag_action = add_action(self, N_('Create Tag...'), createtag.create_tag) self.create_branch_action = add_action(self, N_('Create...'), createbranch.create_new_branch, hotkeys.BRANCH) self.delete_branch_action = add_action(self, N_('Delete...'), guicmds.delete_branch) self.delete_remote_branch_action = add_action( self, N_('Delete Remote Branch...'), guicmds.delete_remote_branch) self.rename_branch_action = add_action(self, N_('Rename Branch...'), guicmds.rename_branch) self.checkout_branch_action = add_action(self, N_('Checkout...'), guicmds.checkout_branch, hotkeys.CHECKOUT) self.branch_review_action = add_action(self, N_('Review...'), guicmds.review_branch) self.browse_action = add_action(self, N_('File Browser...'), browse.worktree_browser) self.browse_action.setIcon(icons.cola()) self.dag_action = add_action(self, N_('DAG...'), self.git_dag) self.dag_action.setIcon(icons.cola()) self.rebase_start_action = add_action( self, N_('Start Interactive Rebase...'), self.rebase_start) self.rebase_edit_todo_action = add_action(self, N_('Edit...'), self.rebase_edit_todo) self.rebase_continue_action = add_action(self, N_('Continue'), self.rebase_continue) self.rebase_skip_action = add_action(self, N_('Skip Current Patch'), self.rebase_skip) self.rebase_abort_action = add_action(self, N_('Abort'), self.rebase_abort) # For "Start Rebase" only, reverse the first argument to setEnabled() # so that we can operate on it as a group. # We can do this because can_rebase == not is_rebasing set_disabled = lambda x: self.rebase_start_action.setEnabled(not x) self.rebase_start_action_proxy = utils.Proxy(self.rebase_start_action, setEnabled=set_disabled) self.rebase_group = utils.Group(self.rebase_start_action_proxy, self.rebase_edit_todo_action, self.rebase_continue_action, self.rebase_skip_action, self.rebase_abort_action) self.lock_layout_action = add_action_bool(self, N_('Lock Layout'), self.set_lock_layout, False) # Create the application menu self.menubar = QtGui.QMenuBar(self) # File Menu self.file_menu = create_menu(N_('File'), self.menubar) self.file_menu.addAction(self.new_repository_action) self.open_recent_menu = self.file_menu.addMenu(N_('Open Recent')) self.open_recent_menu.setIcon(icons.folder()) self.file_menu.addAction(self.open_repo_action) self.file_menu.addAction(self.open_repo_new_action) self.file_menu.addAction(self.clone_repo_action) self.file_menu.addSeparator() self.file_menu.addAction(self.rescan_action) self.file_menu.addAction(self.find_files_action) self.file_menu.addAction(self.edit_remotes_action) self.file_menu.addAction(self.browse_recently_modified_action) self.file_menu.addSeparator() self.file_menu.addAction(self.load_commitmsg_action) self.file_menu.addAction(self.load_commitmsg_template_action) self.file_menu.addSeparator() self.file_menu.addAction(self.apply_patches_action) self.file_menu.addAction(self.export_patches_action) self.file_menu.addAction(self.save_tarball_action) self.file_menu.addSeparator() self.file_menu.addAction(self.preferences_action) self.file_menu.addAction(self.quit_action) self.menubar.addAction(self.file_menu.menuAction()) # Actions menu self.actions_menu = create_menu(N_('Actions'), self.menubar) self.actions_menu.addAction(self.fetch_action) self.actions_menu.addAction(self.push_action) self.actions_menu.addAction(self.pull_action) self.actions_menu.addAction(self.stash_action) self.actions_menu.addSeparator() self.actions_menu.addAction(self.create_tag_action) self.actions_menu.addAction(self.cherry_pick_action) self.actions_menu.addAction(self.merge_local_action) self.actions_menu.addAction(self.merge_abort_action) self.actions_menu.addSeparator() self.actions_menu.addAction(self.grep_action) self.actions_menu.addAction(self.search_commits_action) self.menubar.addAction(self.actions_menu.menuAction()) # Staging Area Menu self.commit_menu = create_menu(N_('Staging Area'), self.menubar) self.commit_menu.setTitle(N_('Staging Area')) self.commit_menu.addAction(self.stage_modified_action) self.commit_menu.addAction(self.stage_untracked_action) self.commit_menu.addSeparator() self.commit_menu.addAction(self.unstage_all_action) self.commit_menu.addAction(self.unstage_selected_action) self.menubar.addAction(self.commit_menu.menuAction()) # Diff Menu self.diff_menu = create_menu(N_('Diff'), self.menubar) self.diff_menu.addAction(self.diff_expression_action) self.diff_menu.addAction(self.branch_compare_action) self.diff_menu.addSeparator() self.diff_menu.addAction(self.show_diffstat_action) self.menubar.addAction(self.diff_menu.menuAction()) # Branch Menu self.branch_menu = create_menu(N_('Branch'), self.menubar) self.branch_menu.addAction(self.branch_review_action) self.branch_menu.addSeparator() self.branch_menu.addAction(self.create_branch_action) self.branch_menu.addAction(self.checkout_branch_action) self.branch_menu.addAction(self.delete_branch_action) self.branch_menu.addAction(self.delete_remote_branch_action) self.branch_menu.addAction(self.rename_branch_action) self.branch_menu.addSeparator() self.branch_menu.addAction(self.browse_branch_action) self.branch_menu.addAction(self.browse_other_branch_action) self.branch_menu.addSeparator() self.branch_menu.addAction(self.visualize_current_action) self.branch_menu.addAction(self.visualize_all_action) self.menubar.addAction(self.branch_menu.menuAction()) # Rebase menu self.rebase_menu = create_menu(N_('Rebase'), self.actions_menu) self.rebase_menu.addAction(self.rebase_start_action) self.rebase_menu.addAction(self.rebase_edit_todo_action) self.rebase_menu.addSeparator() self.rebase_menu.addAction(self.rebase_continue_action) self.rebase_menu.addAction(self.rebase_skip_action) self.rebase_menu.addSeparator() self.rebase_menu.addAction(self.rebase_abort_action) self.menubar.addAction(self.rebase_menu.menuAction()) # View Menu self.view_menu = create_menu(N_('View'), self.menubar) self.view_menu.addAction(self.browse_action) self.view_menu.addAction(self.dag_action) self.view_menu.addSeparator() if self.browser_dockable: self.view_menu.addAction(self.browserdockwidget.toggleViewAction()) self.setup_dockwidget_view_menu() self.view_menu.addSeparator() self.view_menu.addAction(self.lock_layout_action) self.menubar.addAction(self.view_menu.menuAction()) # Help Menu self.help_menu = create_menu(N_('Help'), self.menubar) self.help_menu.addAction(self.help_docs_action) self.help_menu.addAction(self.help_shortcuts_action) self.help_menu.addAction(self.help_about_action) self.menubar.addAction(self.help_menu.menuAction()) # Set main menu self.setMenuBar(self.menubar) # Arrange dock widgets left = Qt.LeftDockWidgetArea right = Qt.RightDockWidgetArea bottom = Qt.BottomDockWidgetArea self.addDockWidget(left, self.commitdockwidget) if self.browser_dockable: self.addDockWidget(left, self.browserdockwidget) self.tabifyDockWidget(self.browserdockwidget, self.commitdockwidget) self.addDockWidget(left, self.diffdockwidget) self.addDockWidget(right, self.statusdockwidget) self.addDockWidget(right, self.bookmarksdockwidget) self.addDockWidget(right, self.recentdockwidget) self.addDockWidget(bottom, self.actionsdockwidget) self.addDockWidget(bottom, self.logdockwidget) self.tabifyDockWidget(self.actionsdockwidget, self.logdockwidget) # Listen for model notifications model.add_observer(model.message_updated, self._update) model.add_observer(model.message_mode_changed, lambda x: self._update()) prefs_model.add_observer(prefs_model.message_config_updated, self._config_updated) # Set a default value self.show_cursor_position(1, 0) self.connect(self.open_recent_menu, SIGNAL('aboutToShow()'), self.build_recent_menu) self.connect(self.commitmsgeditor, SIGNAL('cursorPosition(int,int)'), self.show_cursor_position) self.connect(self.diffeditor, SIGNAL('diff_options_updated()'), self.statuswidget.refresh) self.connect(self.diffeditor, SIGNAL('move_down()'), self.statuswidget.move_down) self.connect(self.diffeditor, SIGNAL('move_up()'), self.statuswidget.move_up) self.connect(self.commitmsgeditor, SIGNAL('move_down()'), self.statuswidget.move_down) self.connect(self.commitmsgeditor, SIGNAL('move_up()'), self.statuswidget.move_up) self.connect(self, SIGNAL('update()'), self._update_callback, Qt.QueuedConnection) self.connect(self, SIGNAL('install_cfg_actions(PyQt_PyObject)'), self._install_config_actions, Qt.QueuedConnection) # Install .git-config-defined actions self.init_config_actions() # Restore saved settings if not self.restore_state(settings=settings): self.resize(987, 610) self.set_initial_size() self.statusdockwidget.widget().setFocus() # Route command output here Interaction.log_status = self.logwidget.log_status Interaction.log = self.logwidget.log Interaction.log(version.git_version_str() + '\n' + N_('git cola version %s') % version.version())
def __init__(self, parent=None): QtGui.QDialog.__init__(self, parent) self.setWindowTitle(N_('git-cola')) self.repodir = None self.task_runner = TaskRunner(self) self.progress = ProgressDialog('', '', self) self.new_button = qtutils.create_button(text=N_('New...'), icon=icons.new()) self.open_button = qtutils.create_button(text=N_('Open...'), icon=icons.repo()) self.clone_button = qtutils.create_button(text=N_('Clone...'), icon=icons.cola()) self.close_button = qtutils.close_button() settings = Settings() settings.load() self.bookmarks_label = QtGui.QLabel(N_('Select Repository...')) self.bookmarks_label.setAlignment(Qt.AlignCenter) self.bookmarks_model = QtGui.QStandardItemModel() item = QtGui.QStandardItem(N_('Select manually...')) item.setEditable(False) self.bookmarks_model.appendRow(item) added = set() all_repos = settings.bookmarks + settings.recent for repo in all_repos: if repo in added: continue added.add(repo) item = QtGui.QStandardItem(repo) item.setEditable(False) self.bookmarks_model.appendRow(item) selection_mode = QtGui.QAbstractItemView.SingleSelection self.bookmarks = QtGui.QListView() self.bookmarks.setSelectionMode(selection_mode) self.bookmarks.setAlternatingRowColors(True) self.bookmarks.setModel(self.bookmarks_model) if not all_repos: self.bookmarks_label.setMinimumHeight(1) self.bookmarks.setMinimumHeight(1) self.bookmarks_label.hide() self.bookmarks.hide() self.button_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.open_button, self.clone_button, self.new_button, qtutils.STRETCH, self.close_button) self.main_layout = qtutils.vbox(defs.margin, defs.spacing, self.bookmarks_label, self.bookmarks, self.button_layout) self.setLayout(self.main_layout) qtutils.connect_button(self.open_button, self.open_repo) qtutils.connect_button(self.clone_button, self.clone_repo) qtutils.connect_button(self.new_button, self.new_repo) qtutils.connect_button(self.close_button, self.reject) self.connect(self.bookmarks, SIGNAL('activated(QModelIndex)'), self.open_bookmark)
def __init__(self, model, parent=None, settings=None): standard.MainWindow.__init__(self, parent) self.setAttribute(Qt.WA_MacMetalStyle) # Default size; this is thrown out when save/restore is used self.model = model self.settings = settings self.prefs_model = prefs_model = prefs.PreferencesModel() # The widget version is used by import/export_state(). # Change this whenever dockwidgets are removed. self.widget_version = 2 # Keeps track of merge messages we've seen self.merge_message_hash = '' # Runs asynchronous tasks self.task_runner = TaskRunner(self) self.progress = standard.ProgressDialog('', '', self) cfg = gitcfg.current() self.browser_dockable = (cfg.get('cola.browserdockable') or cfg.get('cola.classicdockable')) if self.browser_dockable: self.browserdockwidget = create_dock(N_('Browser'), self) self.browserwidget = browse.worktree_browser_widget(self) self.browserdockwidget.setWidget(self.browserwidget) # "Actions" widget self.actionsdockwidget = create_dock(N_('Actions'), self) self.actionsdockwidgetcontents = action.ActionButtons(self) self.actionsdockwidget.setWidget(self.actionsdockwidgetcontents) self.actionsdockwidget.toggleViewAction().setChecked(False) self.actionsdockwidget.hide() # "Repository Status" widget self.statusdockwidget = create_dock(N_('Status'), self) titlebar = self.statusdockwidget.titleBarWidget() self.statuswidget = status.StatusWidget(titlebar, parent=self.statusdockwidget) self.statusdockwidget.setWidget(self.statuswidget) # "Switch Repository" widgets self.bookmarksdockwidget = create_dock(N_('Favorites'), self) self.bookmarkswidget = bookmarks.BookmarksWidget( bookmarks.BOOKMARKS, parent=self.bookmarksdockwidget) self.bookmarksdockwidget.setWidget(self.bookmarkswidget) self.recentdockwidget = create_dock(N_('Recent'), self) self.recentwidget = bookmarks.BookmarksWidget( bookmarks.RECENT_REPOS, parent=self.recentdockwidget) self.recentdockwidget.setWidget(self.recentwidget) self.recentdockwidget.hide() # "Commit Message Editor" widget self.position_label = QtGui.QLabel() font = qtutils.default_monospace_font() font.setPointSize(int(font.pointSize() * 0.8)) self.position_label.setFont(font) # make the position label fixed size to avoid layout issues fm = self.position_label.fontMetrics() width = fm.width('999:999') height = self.position_label.sizeHint().height() self.position_label.setFixedSize(width, height) self.commitdockwidget = create_dock(N_('Commit'), self) titlebar = self.commitdockwidget.titleBarWidget() titlebar.add_corner_widget(self.position_label) self.commitmsgeditor = commitmsg.CommitMessageEditor(model, self) self.commitdockwidget.setWidget(self.commitmsgeditor) # "Console" widget self.logwidget = log.LogWidget() self.logdockwidget = create_dock(N_('Console'), self) self.logdockwidget.setWidget(self.logwidget) self.logdockwidget.toggleViewAction().setChecked(False) self.logdockwidget.hide() # "Diff Viewer" widget self.diffdockwidget = create_dock(N_('Diff'), self) self.diffeditorwidget = diff.DiffEditorWidget(self.diffdockwidget) self.diffeditor = self.diffeditorwidget.editor self.diffdockwidget.setWidget(self.diffeditorwidget) # All Actions self.unstage_all_action = add_action(self, N_('Unstage All'), cmds.run(cmds.UnstageAll)) self.unstage_all_action.setIcon(qtutils.icon('remove.svg')) self.unstage_selected_action = add_action(self, N_('Unstage From Commit'), cmds.run(cmds.UnstageSelected)) self.unstage_selected_action.setIcon(qtutils.icon('remove.svg')) self.show_diffstat_action = add_action(self, N_('Diffstat'), cmds.run(cmds.Diffstat), 'Alt+D') self.stage_modified_action = add_action(self, N_('Stage Changed Files To Commit'), cmds.run(cmds.StageModified), 'Alt+A') self.stage_modified_action.setIcon(qtutils.icon('add.svg')) self.stage_untracked_action = add_action(self, N_('Stage All Untracked'), cmds.run(cmds.StageUntracked), 'Alt+U') self.stage_untracked_action.setIcon(qtutils.icon('add.svg')) self.apply_patches_action = add_action(self, N_('Apply Patches...'), patch.apply_patches) self.export_patches_action = add_action(self, N_('Export Patches...'), guicmds.export_patches, 'Alt+E') self.new_repository_action = add_action(self, N_('New Repository...'), guicmds.open_new_repo) self.new_repository_action.setIcon(qtutils.new_icon()) self.preferences_action = add_action(self, N_('Preferences'), self.preferences, QtGui.QKeySequence.Preferences) self.edit_remotes_action = add_action(self, N_('Edit Remotes...'), lambda: editremotes.remote_editor().exec_()) self.rescan_action = add_action(self, cmds.Refresh.name(), cmds.run(cmds.Refresh), *cmds.Refresh.SHORTCUTS) self.rescan_action.setIcon(qtutils.reload_icon()) self.find_files_action = add_action(self, N_('Find Files'), finder.finder, 'Ctrl+T', 'T') self.find_files_action.setIcon(qtutils.theme_icon('zoom-in.png')) self.browse_recently_modified_action = add_action(self, N_('Recently Modified Files...'), recent.browse_recent_files, 'Shift+Ctrl+E') self.cherry_pick_action = add_action(self, N_('Cherry-Pick...'), guicmds.cherry_pick, 'Shift+Ctrl+C') self.load_commitmsg_action = add_action(self, N_('Load Commit Message...'), guicmds.load_commitmsg) self.save_tarball_action = add_action(self, N_('Save As Tarball/Zip...'), self.save_archive) self.quit_action = add_action(self, N_('Quit'), self.close, 'Ctrl+Q') self.grep_action = add_action(self, N_('Grep'), grep.grep, 'Ctrl+G') self.merge_local_action = add_action(self, N_('Merge...'), merge.local_merge, 'Shift+Ctrl+M') self.merge_abort_action = add_action(self, N_('Abort Merge...'), merge.abort_merge) self.fetch_action = add_action(self, N_('Fetch...'), remote.fetch, 'Ctrl+F') self.push_action = add_action(self, N_('Push...'), remote.push, 'Ctrl+P') self.pull_action = add_action(self, N_('Pull...'), remote.pull, 'Shift+Ctrl+P') self.open_repo_action = add_action(self, N_('Open...'), guicmds.open_repo) self.open_repo_action.setIcon(qtutils.open_icon()) self.open_repo_new_action = add_action(self, N_('Open in New Window...'), guicmds.open_repo_in_new_window) self.open_repo_new_action.setIcon(qtutils.open_icon()) self.stash_action = add_action(self, N_('Stash...'), stash.stash, 'Alt+Shift+S') self.clone_repo_action = add_action(self, N_('Clone...'), self.clone_repo) self.clone_repo_action.setIcon(qtutils.git_icon()) self.help_docs_action = add_action(self, N_('Documentation'), resources.show_html_docs, QtGui.QKeySequence.HelpContents) self.help_shortcuts_action = add_action(self, N_('Keyboard Shortcuts'), about.show_shortcuts, Qt.Key_Question) self.visualize_current_action = add_action(self, N_('Visualize Current Branch...'), cmds.run(cmds.VisualizeCurrent)) self.visualize_all_action = add_action(self, N_('Visualize All Branches...'), cmds.run(cmds.VisualizeAll)) self.search_commits_action = add_action(self, N_('Search...'), search.search) self.browse_branch_action = add_action(self, N_('Browse Current Branch...'), guicmds.browse_current) self.browse_other_branch_action = add_action(self, N_('Browse Other Branch...'), guicmds.browse_other) self.load_commitmsg_template_action = add_action(self, N_('Get Commit Message Template'), cmds.run(cmds.LoadCommitMessageFromTemplate)) self.help_about_action = add_action(self, N_('About'), about.launch_about_dialog) self.diff_expression_action = add_action(self, N_('Expression...'), guicmds.diff_expression) self.branch_compare_action = add_action(self, N_('Branches...'), compare.compare_branches) self.create_tag_action = add_action(self, N_('Create Tag...'), createtag.create_tag) self.create_branch_action = add_action(self, N_('Create...'), createbranch.create_new_branch, 'Ctrl+B') self.delete_branch_action = add_action(self, N_('Delete...'), guicmds.delete_branch) self.delete_remote_branch_action = add_action(self, N_('Delete Remote Branch...'), guicmds.delete_remote_branch) self.rename_branch_action = add_action(self, N_('Rename Branch...'), guicmds.rename_branch) self.checkout_branch_action = add_action(self, N_('Checkout...'), guicmds.checkout_branch, 'Alt+B') self.branch_review_action = add_action(self, N_('Review...'), guicmds.review_branch) self.browse_action = add_action(self, N_('File Browser...'), browse.worktree_browser) self.browse_action.setIcon(qtutils.git_icon()) self.dag_action = add_action(self, N_('DAG...'), self.git_dag) self.dag_action.setIcon(qtutils.git_icon()) self.rebase_start_action = add_action(self, N_('Start Interactive Rebase...'), self.rebase_start) self.rebase_edit_todo_action = add_action(self, N_('Edit...'), self.rebase_edit_todo) self.rebase_continue_action = add_action(self, N_('Continue'), self.rebase_continue) self.rebase_skip_action = add_action(self, N_('Skip Current Patch'), self.rebase_skip) self.rebase_abort_action = add_action(self, N_('Abort'), self.rebase_abort) # Relayed actions status_tree = self.statusdockwidget.widget().tree self.addAction(status_tree.delete_untracked_files_action) if not self.browser_dockable: # These shortcuts conflict with those from the # 'Browser' widget so don't register them when # the browser is a dockable tool. self.addAction(status_tree.revert_unstaged_edits_action) self.addAction(status_tree.revert_uncommitted_edits_action) self.addAction(status_tree.up_action) self.addAction(status_tree.down_action) self.addAction(status_tree.process_selection_action) self.lock_layout_action = add_action_bool(self, N_('Lock Layout'), self.set_lock_layout, False) # Create the application menu self.menubar = QtGui.QMenuBar(self) # File Menu self.file_menu = create_menu(N_('File'), self.menubar) self.file_menu.addAction(self.new_repository_action) self.open_recent_menu = self.file_menu.addMenu(N_('Open Recent')) self.open_recent_menu.setIcon(qtutils.open_icon()) self.file_menu.addAction(self.open_repo_action) self.file_menu.addAction(self.open_repo_new_action) self.file_menu.addAction(self.clone_repo_action) self.file_menu.addSeparator() self.file_menu.addAction(self.rescan_action) self.file_menu.addAction(self.find_files_action) self.file_menu.addAction(self.edit_remotes_action) self.file_menu.addAction(self.browse_recently_modified_action) self.file_menu.addSeparator() self.file_menu.addAction(self.load_commitmsg_action) self.file_menu.addAction(self.load_commitmsg_template_action) self.file_menu.addSeparator() self.file_menu.addAction(self.apply_patches_action) self.file_menu.addAction(self.export_patches_action) self.file_menu.addAction(self.save_tarball_action) self.file_menu.addSeparator() self.file_menu.addAction(self.preferences_action) self.file_menu.addAction(self.quit_action) self.menubar.addAction(self.file_menu.menuAction()) # Actions menu self.actions_menu = create_menu(N_('Actions'), self.menubar) self.actions_menu.addAction(self.fetch_action) self.actions_menu.addAction(self.push_action) self.actions_menu.addAction(self.pull_action) self.actions_menu.addAction(self.stash_action) self.actions_menu.addSeparator() self.actions_menu.addAction(self.create_tag_action) self.actions_menu.addAction(self.cherry_pick_action) self.actions_menu.addAction(self.merge_local_action) self.actions_menu.addAction(self.merge_abort_action) self.actions_menu.addSeparator() self.actions_menu.addAction(self.grep_action) self.actions_menu.addAction(self.search_commits_action) self.menubar.addAction(self.actions_menu.menuAction()) # Staging Area Menu self.commit_menu = create_menu(N_('Staging Area'), self.menubar) self.commit_menu.setTitle(N_('Staging Area')) self.commit_menu.addAction(self.stage_modified_action) self.commit_menu.addAction(self.stage_untracked_action) self.commit_menu.addSeparator() self.commit_menu.addAction(self.unstage_all_action) self.commit_menu.addAction(self.unstage_selected_action) self.menubar.addAction(self.commit_menu.menuAction()) # Diff Menu self.diff_menu = create_menu(N_('Diff'), self.menubar) self.diff_menu.addAction(self.diff_expression_action) self.diff_menu.addAction(self.branch_compare_action) self.diff_menu.addSeparator() self.diff_menu.addAction(self.show_diffstat_action) self.menubar.addAction(self.diff_menu.menuAction()) # Branch Menu self.branch_menu = create_menu(N_('Branch'), self.menubar) self.branch_menu.addAction(self.branch_review_action) self.branch_menu.addSeparator() self.branch_menu.addAction(self.create_branch_action) self.branch_menu.addAction(self.checkout_branch_action) self.branch_menu.addAction(self.delete_branch_action) self.branch_menu.addAction(self.delete_remote_branch_action) self.branch_menu.addAction(self.rename_branch_action) self.branch_menu.addSeparator() self.branch_menu.addAction(self.browse_branch_action) self.branch_menu.addAction(self.browse_other_branch_action) self.branch_menu.addSeparator() self.branch_menu.addAction(self.visualize_current_action) self.branch_menu.addAction(self.visualize_all_action) self.menubar.addAction(self.branch_menu.menuAction()) # Rebase menu self.rebase_menu = create_menu(N_('Rebase'), self.actions_menu) self.rebase_menu.addAction(self.rebase_start_action) self.rebase_menu.addAction(self.rebase_edit_todo_action) self.rebase_menu.addSeparator() self.rebase_menu.addAction(self.rebase_continue_action) self.rebase_menu.addAction(self.rebase_skip_action) self.rebase_menu.addSeparator() self.rebase_menu.addAction(self.rebase_abort_action) self.menubar.addAction(self.rebase_menu.menuAction()) # View Menu self.view_menu = create_menu(N_('View'), self.menubar) self.view_menu.addAction(self.browse_action) self.view_menu.addAction(self.dag_action) self.view_menu.addSeparator() if self.browser_dockable: self.view_menu.addAction(self.browserdockwidget.toggleViewAction()) self.setup_dockwidget_view_menu() self.view_menu.addSeparator() self.view_menu.addAction(self.lock_layout_action) self.menubar.addAction(self.view_menu.menuAction()) # Help Menu self.help_menu = create_menu(N_('Help'), self.menubar) self.help_menu.addAction(self.help_docs_action) self.help_menu.addAction(self.help_shortcuts_action) self.help_menu.addAction(self.help_about_action) self.menubar.addAction(self.help_menu.menuAction()) # Set main menu self.setMenuBar(self.menubar) # Arrange dock widgets left = Qt.LeftDockWidgetArea right = Qt.RightDockWidgetArea bottom = Qt.BottomDockWidgetArea self.addDockWidget(left, self.commitdockwidget) if self.browser_dockable: self.addDockWidget(left, self.browserdockwidget) self.tabifyDockWidget(self.browserdockwidget, self.commitdockwidget) self.addDockWidget(left, self.diffdockwidget) self.addDockWidget(right, self.statusdockwidget) self.addDockWidget(right, self.bookmarksdockwidget) self.addDockWidget(right, self.recentdockwidget) self.addDockWidget(bottom, self.actionsdockwidget) self.addDockWidget(bottom, self.logdockwidget) self.tabifyDockWidget(self.actionsdockwidget, self.logdockwidget) # Listen for model notifications model.add_observer(model.message_updated, self._update) model.add_observer(model.message_mode_changed, lambda x: self._update()) prefs_model.add_observer(prefs_model.message_config_updated, self._config_updated) # Set a default value self.show_cursor_position(1, 0) self.connect(self.open_recent_menu, SIGNAL('aboutToShow()'), self.build_recent_menu) self.connect(self.commitmsgeditor, SIGNAL('cursorPosition(int,int)'), self.show_cursor_position) self.connect(self.diffeditor, SIGNAL('diff_options_updated()'), self.statuswidget.refresh) self.connect(self, SIGNAL('update'), self._update_callback) self.connect(self, SIGNAL('install_config_actions'), self._install_config_actions) # Install .git-config-defined actions self._config_task = None self.install_config_actions() # Restore saved settings if not self.restore_state(settings=settings): self.resize(987, 610) self.set_initial_size() self.statusdockwidget.widget().setFocus() # Route command output here Interaction.log_status = self.logwidget.log_status Interaction.log = self.logwidget.log Interaction.log(version.git_version_str() + '\n' + N_('git cola version %s') % version.version())
def __init__(self, model, action, title, parent=None, icon=None): """Customizes the dialog based on the remote action """ standard.Dialog.__init__(self, parent=parent) self.model = model self.action = action self.filtered_remote_branches = [] self.selected_remotes = [] self.setAttribute(Qt.WA_MacMetalStyle) self.setWindowTitle(title) if parent is not None: self.setWindowModality(Qt.WindowModal) self.task_runner = TaskRunner(self) self.progress = ProgressDialog(title, N_("Updating"), self) self.local_label = QtGui.QLabel() self.local_label.setText(N_("Local Branch")) self.local_branch = QtGui.QLineEdit() self.local_branches = QtGui.QListWidget() self.local_branches.addItems(self.model.local_branches) self.remote_label = QtGui.QLabel() self.remote_label.setText(N_("Remote")) self.remote_name = QtGui.QLineEdit() self.remotes = QtGui.QListWidget() if action == PUSH: self.remotes.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) self.remotes.addItems(self.model.remotes) self.remote_branch_label = QtGui.QLabel() self.remote_branch_label.setText(N_("Remote Branch")) self.remote_branch = QtGui.QLineEdit() self.remote_branches = QtGui.QListWidget() self.remote_branches.addItems(self.model.remote_branches) text = N_("Fast Forward Only ") self.ffwd_only_checkbox = qtutils.checkbox(text=text, checked=True) self.tags_checkbox = qtutils.checkbox(text=N_("Include tags ")) self.rebase_checkbox = qtutils.checkbox(text=N_("Rebase ")) if icon is None: icon = icons.ok() self.action_button = qtutils.create_button(text=title, icon=icon) self.close_button = qtutils.close_button() self.buttons = utils.Group(self.action_button, self.close_button) self.local_branch_layout = qtutils.hbox(defs.small_margin, defs.spacing, self.local_label, self.local_branch) self.remote_branch_layout = qtutils.hbox(defs.small_margin, defs.spacing, self.remote_label, self.remote_name) self.remote_branches_layout = qtutils.hbox( defs.small_margin, defs.spacing, self.remote_branch_label, self.remote_branch ) self.options_layout = qtutils.hbox( defs.no_margin, defs.button_spacing, qtutils.STRETCH, self.ffwd_only_checkbox, self.tags_checkbox, self.rebase_checkbox, self.action_button, self.close_button, ) if action == PUSH: widgets = ( self.remote_branch_layout, self.remotes, self.local_branch_layout, self.local_branches, self.remote_branches_layout, self.remote_branches, self.options_layout, ) else: # fetch and pull widgets = ( self.remote_branch_layout, self.remotes, self.remote_branches_layout, self.remote_branches, self.local_branch_layout, self.local_branches, self.options_layout, ) self.main_layout = qtutils.vbox(defs.no_margin, defs.spacing, *widgets) self.setLayout(self.main_layout) default_remote = gitcmds.default_remote() or "origin" remotes = self.model.remotes if default_remote in remotes: idx = remotes.index(default_remote) if self.select_remote(idx): self.remote_name.setText(default_remote) else: if self.select_first_remote(): self.remote_name.setText(remotes[0]) # Trim the remote list to just the default remote self.update_remotes() self.set_field_defaults() # Setup signals and slots self.connect(self.remotes, SIGNAL("itemSelectionChanged()"), self.update_remotes) self.connect(self.local_branches, SIGNAL("itemSelectionChanged()"), self.update_local_branches) self.connect(self.remote_branches, SIGNAL("itemSelectionChanged()"), self.update_remote_branches) connect_button(self.action_button, self.action_callback) connect_button(self.close_button, self.close) qtutils.add_action(self, N_("Close"), self.close, QtGui.QKeySequence.Close, "Esc") if action == PULL: self.tags_checkbox.hide() self.ffwd_only_checkbox.hide() self.local_label.hide() self.local_branch.hide() self.local_branches.hide() self.remote_branch.setFocus() else: self.rebase_checkbox.hide() if not self.restore_state(): self.resize(666, 420) self.remote_name.setFocus()