Esempio n. 1
0
    def create_branch(self):
        """Creates a branch; called by the "Create Branch" button"""
        self.getopts()
        revision = self.opts.revision
        branch = self.opts.branch
        no_update = self.no_update_radio.isChecked()
        ffwd_only = self.ffwd_only_radio.isChecked()
        existing_branches = gitcmds.branch_list()
        check_branch = False

        if not branch or not revision:
            qtutils.critical(N_('Missing Data'),
                             N_('Please provide both a branch '
                                'name and revision expression.'))
            return
        if branch in existing_branches:
            if no_update:
                msg = N_('Branch "%s" already exists.') % branch
                qtutils.critical(N_('Branch Exists'), msg)
                return
            # Whether we should prompt the user for lost commits
            commits = gitcmds.rev_list_range(revision, branch)
            check_branch = bool(commits)

        if check_branch:
            msg = (N_('Resetting "%(branch)s" to "%(revision)s" '
                      'will lose commits.') %
                   dict(branch=branch, revision=revision))
            if ffwd_only:
                qtutils.critical(N_('Branch Exists'), msg)
                return
            lines = [msg]
            for idx, commit in enumerate(commits):
                subject = commit[1][0:min(len(commit[1]),16)]
                if len(subject) < len(commit[1]):
                    subject += '...'
                lines.append('\t' + commit[0][:8]
                        +'\t' + subject)
                if idx >= 5:
                    skip = len(commits) - 5
                    lines.append('\t(%s)' % (N_('%d skipped') % skip))
                    break
            line = N_('Recovering lost commits may not be easy.')
            lines.append(line)
            if not qtutils.confirm(N_('Reset Branch?'),
                                   '\n'.join(lines),
                                   (N_('Reset "%(branch)s" to "%(revision)s"?') %
                                    dict(branch=branch, revision=revision)),
                                   N_('Reset Branch'),
                                   default=False,
                                   icon=qtutils.theme_icon('edit-undo.svg')):
                return
        self.setEnabled(False)
        self.progress.setEnabled(True)
        QtGui.QApplication.setOverrideCursor(Qt.WaitCursor)

        # Show a nice progress bar
        self.progress.setLabelText(N_('Updating...'))
        self.progress.show()
        self.thread.start()
Esempio n. 2
0
    def __init__(self, parent, titlebar):
        DiffTextEdit.__init__(self, parent)
        self.model = model = main.model()

        # "Diff Options" tool menu
        self.diff_ignore_space_at_eol_action = add_action(self,
                N_('Ignore changes in whitespace at EOL'),
                self._update_diff_opts)
        self.diff_ignore_space_at_eol_action.setCheckable(True)

        self.diff_ignore_space_change_action = add_action(self,
                N_('Ignore changes in amount of whitespace'),
                self._update_diff_opts)
        self.diff_ignore_space_change_action.setCheckable(True)

        self.diff_ignore_all_space_action = add_action(self,
                N_('Ignore all whitespace'),
                self._update_diff_opts)
        self.diff_ignore_all_space_action.setCheckable(True)

        self.diff_function_context_action = add_action(self,
                N_('Show whole surrounding functions of changes'),
                self._update_diff_opts)
        self.diff_function_context_action.setCheckable(True)

        self.diffopts_button = create_action_button(
                tooltip=N_('Diff Options'), icon=options_icon())
        self.diffopts_menu = create_menu(N_('Diff Options'),
                                         self.diffopts_button)

        self.diffopts_menu.addAction(self.diff_ignore_space_at_eol_action)
        self.diffopts_menu.addAction(self.diff_ignore_space_change_action)
        self.diffopts_menu.addAction(self.diff_ignore_all_space_action)
        self.diffopts_menu.addAction(self.diff_function_context_action)
        self.diffopts_button.setMenu(self.diffopts_menu)
        qtutils.hide_button_menu_indicator(self.diffopts_button)

        titlebar.add_corner_widget(self.diffopts_button)

        self.action_apply_selection = qtutils.add_action(self, '',
                self.apply_selection, Qt.Key_S)

        self.action_revert_selection = qtutils.add_action(self, '',
                self.revert_selection)
        self.action_revert_selection.setIcon(qtutils.theme_icon('edit-undo.svg'))

        self.launch_editor = qtutils.add_action(self,
                cmds.LaunchEditor.name(), run(cmds.LaunchEditor),
                cmds.LaunchEditor.SHORTCUT,
                'Return', 'Enter')
        self.launch_editor.setIcon(qtutils.options_icon())

        self.launch_difftool = qtutils.add_action(self,
                cmds.LaunchDifftool.name(), run(cmds.LaunchDifftool),
                cmds.LaunchDifftool.SHORTCUT)
        self.launch_difftool.setIcon(qtutils.git_icon())

        model.add_observer(model.message_diff_text_changed, self._emit_text)

        self.connect(self, SIGNAL('set_text(PyQt_PyObject)'), self.setPlainText)
Esempio n. 3
0
    def _create_unstaged_context_menu(self, menu, s):
        modified_submodule = (s.modified and
                              s.modified[0] in self.m.submodules)
        if modified_submodule:
            return self._create_modified_submodule_context_menu(menu, s)

        if self.m.stageable():
            action = menu.addAction(qtutils.add_icon(),
                                    N_('Stage Selected'),
                                    cmds.run(cmds.Stage, self.unstaged()))
            action.setShortcut(hotkeys.STAGE_SELECTION)

        # Do all of the selected items exist?
        all_exist = all(not i in self.m.unstaged_deleted and core.exists(i)
                        for i in self.staged())

        if all_exist and self.unstaged():
            menu.addAction(self.launch_editor_action)

        if all_exist and s.modified and self.m.stageable():
            menu.addAction(self.launch_difftool_action)

        if s.modified and self.m.stageable():
            if self.m.undoable():
                menu.addSeparator()
                menu.addAction(self.revert_unstaged_edits_action)

        if all_exist and self.unstaged() and not utils.is_win32():
            menu.addSeparator()
            action = menu.addAction(qtutils.file_icon(),
                    cmds.OpenDefaultApp.name(),
                    cmds.run(cmds.OpenDefaultApp, self.unstaged()))
            action.setShortcut(hotkeys.PRIMARY_ACTION)

            action = menu.addAction(qtutils.open_file_icon(),
                    cmds.OpenParentDir.name(),
                    self._open_parent_dir)
            action.setShortcut(hotkeys.SECONDARY_ACTION)

        if all_exist and s.untracked:
            menu.addSeparator()
            if self.move_to_trash_action is not None:
                menu.addAction(self.move_to_trash_action)
            menu.addAction(self.delete_untracked_files_action)
            menu.addSeparator()
            menu.addAction(qtutils.theme_icon('edit-clear.svg'),
                           N_('Add to .gitignore'),
                           cmds.run(cmds.Ignore,
                                map(lambda x: '/' + x, self.untracked())))
        menu.addSeparator()
        menu.addAction(self.copy_path_action)
        menu.addAction(self.copy_relpath_action)
        if not selection.selection_model().is_empty():
            menu.addAction(self.view_history_action)
        return menu
Esempio n. 4
0
def abort_merge():
    """Prompts before aborting a merge in progress
    """
    title = N_('Abort Merge...')
    txt = N_('Aborting the current merge will cause '
             '*ALL* uncommitted changes to be lost.\n'
             'Recovering uncommitted changes is not possible.')
    info_txt = N_('Aborting the current merge?')
    ok_txt = N_('Abort Merge')
    if qtutils.confirm(title, txt, info_txt, ok_txt,
                       default=False, icon=qtutils.theme_icon('edit-undo.svg')):
        gitcmds.abort_merge()
Esempio n. 5
0
    def _create_unstaged_context_menu(self, menu, s):
        modified_submodule = s.modified and s.modified[0] in self.m.submodules
        if modified_submodule:
            return self._create_modified_submodule_context_menu(menu, s)

        if self.m.stageable():
            action = menu.addAction(qtutils.add_icon(), N_("Stage Selected"), cmds.run(cmds.Stage, self.unstaged()))
            action.setShortcut(cmds.Stage.SHORTCUT)

        # Do all of the selected items exist?
        all_exist = all(not i in self.m.unstaged_deleted and core.exists(i) for i in self.staged())

        if all_exist and self.unstaged():
            menu.addAction(self.launch_editor_action)

        if all_exist and s.modified and self.m.stageable():
            menu.addAction(self.launch_difftool_action)

        if s.modified and self.m.stageable():
            if self.m.undoable():
                menu.addSeparator()
                menu.addAction(self.revert_unstaged_edits_action)

        if all_exist and self.unstaged() and not utils.is_win32():
            menu.addSeparator()
            action = menu.addAction(
                qtutils.file_icon(), cmds.OpenDefaultApp.name(), cmds.run(cmds.OpenDefaultApp, self.unstaged())
            )
            action.setShortcut(cmds.OpenDefaultApp.SHORTCUT)

            action = menu.addAction(qtutils.open_file_icon(), cmds.OpenParentDir.name(), self._open_parent_dir)
            action.setShortcut(cmds.OpenParentDir.SHORTCUT)

        if all_exist and s.untracked:
            menu.addSeparator()
            if self.move_to_trash_action is not None:
                menu.addAction(self.move_to_trash_action)
            menu.addAction(self.delete_untracked_files_action)
            menu.addSeparator()
            menu.addAction(
                qtutils.theme_icon("edit-clear.svg"),
                N_("Add to .gitignore"),
                cmds.run(cmds.Ignore, map(lambda x: "/" + x, self.untracked())),
            )
        menu.addSeparator()
        menu.addAction(self.copy_path_action)
        menu.addAction(self.copy_relpath_action)
        return menu
Esempio n. 6
0
def abort_merge():
    """Prompts before aborting a merge in progress
    """
    title = N_('Abort Merge...')
    txt = N_('Aborting the current merge will cause '
             '*ALL* uncommitted changes to be lost.\n'
             'Recovering uncommitted changes is not possible.')
    info_txt = N_('Aborting the current merge?')
    ok_txt = N_('Abort Merge')
    if qtutils.confirm(title,
                       txt,
                       info_txt,
                       ok_txt,
                       default=False,
                       icon=qtutils.theme_icon('edit-undo.svg')):
        gitcmds.abort_merge()
Esempio n. 7
0
    def revert_selection(self):
        """Destructively revert selected lines or hunk from a worktree file."""

        if self.has_selection():
            title = N_('Revert Selected Lines?')
            ok_text = N_('Revert Selected Lines')
        else:
            title = N_('Revert Diff Hunk?')
            ok_text = N_('Revert Diff Hunk')

        if not qtutils.confirm(title,
                               N_('This operation drops uncommitted changes.\n'
                                  'These changes cannot be recovered.'),
                               N_('Revert the uncommitted changes?'),
                               ok_text,
                               default=True,
                               icon=qtutils.theme_icon('edit-undo.svg')):
            return
        self.process_diff_selection(reverse=True, apply_to_worktree=True)
Esempio n. 8
0
    def revert_selection(self):
        """Destructively revert selected lines or hunk from a worktree file."""

        if self.has_selection():
            title = N_('Revert Selected Lines?')
            ok_text = N_('Revert Selected Lines')
        else:
            title = N_('Revert Diff Hunk?')
            ok_text = N_('Revert Diff Hunk')

        if not qtutils.confirm(title,
                               N_('This operation drops uncommitted changes.\n'
                                  'These changes cannot be recovered.'),
                               N_('Revert the uncommitted changes?'),
                               ok_text,
                               default=True,
                               icon=qtutils.theme_icon('edit-undo.svg')):
            return
        self.process_diff_selection(reverse=True, apply_to_worktree=True)
Esempio n. 9
0
    def __init__(self, parent):
        QtGui.QTreeWidget.__init__(self, parent)

        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.headerItem().setHidden(True)
        self.setAllColumnsShowFocus(True)
        self.setSortingEnabled(False)
        self.setUniformRowHeights(True)
        self.setAnimated(True)
        self.setRootIsDecorated(False)

        self.add_item('Staged', 'plus.png', hide=True)
        self.add_item('Unmerged', 'unmerged.png', hide=True)
        self.add_item('Modified', 'modified.png', hide=True)
        self.add_item('Untracked', 'untracked.png', hide=True)

        # Used to restore the selection
        self.old_scroll = None
        self.old_selection = None
        self.old_contents = None

        self.expanded_items = set()

        self.process_selection = qtutils.add_action(self,
                'Process Selection', self._process_selection,
                defs.stage_shortcut)

        self.launch_difftool = qtutils.add_action(self,
                'Launch Diff Tool', self._launch_difftool,
                defs.difftool_shortcut)
        self.launch_difftool.setIcon(qtutils.icon('git.svg'))

        self.launch_editor = qtutils.add_action(self,
                'Launch Editor', self._launch_editor,
                defs.editor_shortcut)
        self.launch_editor.setIcon(qtutils.options_icon())

        if not utils.is_win32():
            self.open_using_default_app = qtutils.add_action(self,
                    self.txt_default_app,
                    self._open_using_default_app,
                    defs.default_app_shortcut)
            self.open_using_default_app.setIcon(qtutils.file_icon())

            self.open_parent_dir = qtutils.add_action(self,
                    self.txt_parent_dir,
                    self._open_parent_dir,
                    defs.parent_dir_shortcut)
            self.open_parent_dir.setIcon(qtutils.open_file_icon())

        self.up = qtutils.add_action(self,
                'Move Up', self.move_up, Qt.Key_K)
        self.down = qtutils.add_action(self,
                'Move Down', self.move_down, Qt.Key_J)

        self.copy_path_action = qtutils.add_action(self,
                                                   'Copy Path to Clipboard',
                                                   self.copy_path,
                                                   QtGui.QKeySequence.Copy)
        self.copy_path_action.setIcon(qtutils.theme_icon('edit-copy.svg'))

        self.connect(self, SIGNAL('about_to_update'), self._about_to_update)
        self.connect(self, SIGNAL('updated'), self._updated)

        self.m = cola.model()
        self.m.add_observer(self.m.message_about_to_update,
                            self.about_to_update)
        self.m.add_observer(self.m.message_updated, self.updated)

        self.connect(self, SIGNAL('itemSelectionChanged()'),
                     self.show_selection)

        self.connect(self,
                     SIGNAL('itemDoubleClicked(QTreeWidgetItem*,int)'),
                     self.double_clicked)

        self.connect(self,
                     SIGNAL('itemCollapsed(QTreeWidgetItem*)'),
                     lambda x: self.update_column_widths())

        self.connect(self,
                     SIGNAL('itemExpanded(QTreeWidgetItem*)'),
                     lambda x: self.update_column_widths())
Esempio n. 10
0
    def __init__(self, model, ctx, parent=None, settings=None):
        standard.MainWindow.__init__(self, parent)

        self.setAttribute(Qt.WA_MacMetalStyle)
        self.setMinimumSize(420, 420)

        # change when widgets are added/removed
        self.widget_version = 2
        self.model = model
        self.ctx = ctx
        self.settings = settings

        self.commits = {}
        self.commit_list = []

        self.thread = ReaderThread(ctx, self)
        self.revtext = completion.GitLogLineEdit()
        self.maxresults = standard.SpinBox()

        self.zoom_out = qtutils.create_action_button(
                tooltip=N_('Zoom Out'),
                icon=qtutils.theme_icon('zoom-out.png'))

        self.zoom_in = qtutils.create_action_button(
                tooltip=N_('Zoom In'),
                icon=qtutils.theme_icon('zoom-in.png'))

        self.zoom_to_fit = qtutils.create_action_button(
                tooltip=N_('Zoom to Fit'),
                icon=qtutils.theme_icon('zoom-fit-best.png'))

        self.notifier = notifier = observable.Observable()
        self.notifier.refs_updated = refs_updated = 'refs_updated'
        self.notifier.add_observer(refs_updated, self.display)
        self.notifier.add_observer(filelist.HISTORIES_SELECTED,
                                   self.histories_selected)

        self.treewidget = CommitTreeWidget(notifier, self)
        self.diffwidget = diff.DiffWidget(notifier, self)
        self.filewidget = filelist.FileWidget(notifier, self)
        self.graphview = GraphView(notifier, self)

        self.controls_layout = qtutils.hbox(defs.no_margin, defs.spacing,
                                            self.revtext, self.maxresults)

        self.controls_widget = QtGui.QWidget()
        self.controls_widget.setLayout(self.controls_layout)

        self.log_dock = qtutils.create_dock(N_('Log'), self, stretch=False)
        self.log_dock.setWidget(self.treewidget)
        log_dock_titlebar = self.log_dock.titleBarWidget()
        log_dock_titlebar.add_corner_widget(self.controls_widget)

        self.file_dock = qtutils.create_dock(N_('Files'), self)
        self.file_dock.setWidget(self.filewidget)

        self.diff_dock = qtutils.create_dock(N_('Diff'), self)
        self.diff_dock.setWidget(self.diffwidget)

        self.graph_controls_layout = qtutils.hbox(
                defs.no_margin, defs.button_spacing,
                self.zoom_out, self.zoom_in, self.zoom_to_fit)

        self.graph_controls_widget = QtGui.QWidget()
        self.graph_controls_widget.setLayout(self.graph_controls_layout)

        self.graphview_dock = qtutils.create_dock(N_('Graph'), self)
        self.graphview_dock.setWidget(self.graphview)
        graph_titlebar = self.graphview_dock.titleBarWidget()
        graph_titlebar.add_corner_widget(self.graph_controls_widget)

        self.lock_layout_action = qtutils.add_action_bool(self,
                N_('Lock Layout'), self.set_lock_layout, False)

        self.refresh_action = qtutils.add_action(self,
                N_('Refresh'), self.refresh, 'Ctrl+R')

        # Create the application menu
        self.menubar = QtGui.QMenuBar(self)

        # View Menu
        self.view_menu = qtutils.create_menu(N_('View'), self.menubar)
        self.view_menu.addAction(self.refresh_action)

        self.view_menu.addAction(self.log_dock.toggleViewAction())
        self.view_menu.addAction(self.graphview_dock.toggleViewAction())
        self.view_menu.addAction(self.diff_dock.toggleViewAction())
        self.view_menu.addAction(self.file_dock.toggleViewAction())
        self.view_menu.addSeparator()
        self.view_menu.addAction(self.lock_layout_action)

        self.menubar.addAction(self.view_menu.menuAction())
        self.setMenuBar(self.menubar)

        left = Qt.LeftDockWidgetArea
        right = Qt.RightDockWidgetArea
        self.addDockWidget(left, self.log_dock)
        self.addDockWidget(left, self.diff_dock)
        self.addDockWidget(right, self.graphview_dock)
        self.addDockWidget(right, self.file_dock)

        # Update fields affected by model
        self.revtext.setText(ctx.ref)
        self.maxresults.setValue(ctx.count)
        self.update_window_title()

        # Also re-loads dag.* from the saved state
        if not self.restore_state(settings=settings):
            self.resize_to_desktop()

        qtutils.connect_button(self.zoom_out, self.graphview.zoom_out)
        qtutils.connect_button(self.zoom_in, self.graphview.zoom_in)
        qtutils.connect_button(self.zoom_to_fit,
                               self.graphview.zoom_to_fit)

        self.thread.connect(self.thread, self.thread.commits_ready,
                            self.add_commits)

        self.thread.connect(self.thread, self.thread.done, self.thread_done)

        self.connect(self.treewidget,
                     SIGNAL('diff_commits(PyQt_PyObject,PyQt_PyObject)'),
                     self.diff_commits)

        self.connect(self.graphview,
                     SIGNAL('diff_commits(PyQt_PyObject,PyQt_PyObject)'),
                     self.diff_commits)

        self.connect(self.maxresults, SIGNAL('editingFinished()'),
                     self.display)

        self.connect(self.revtext, SIGNAL('textChanged(QString)'),
                     self.text_changed)

        self.connect(self.revtext, SIGNAL('activated()'), self.display)
        self.connect(self.revtext, SIGNAL('return()'), self.display)
        self.connect(self.revtext, SIGNAL('down()'), self.focus_tree)

        # The model is updated in another thread so use
        # signals/slots to bring control back to the main GUI thread
        self.model.add_observer(self.model.message_updated,
                                self.emit_model_updated)

        self.connect(self, SIGNAL('model_updated()'), self.model_updated,
                     Qt.QueuedConnection)

        qtutils.add_action(self, 'Focus Input', self.focus_input, 'Ctrl+L')
        qtutils.add_close_action(self)
Esempio n. 11
0
    def __init__(self, model, dag, parent=None, args=None):
        super(DAGView, self).__init__(parent)

        self.setAttribute(Qt.WA_MacMetalStyle)
        self.setMinimumSize(1, 1)

        # change when widgets are added/removed
        self.widget_version = 1
        self.model = model
        self.dag = dag

        self.commits = {}
        self.commit_list = []

        self.old_count = None
        self.old_ref = None

        self.revtext = completion.GitLogLineEdit(parent=self)

        self.maxresults = QtGui.QSpinBox()
        self.maxresults.setMinimum(1)
        self.maxresults.setMaximum(99999)
        self.maxresults.setPrefix("git log -")
        self.maxresults.setSuffix("")

        self.displaybutton = QtGui.QPushButton()
        self.displaybutton.setText("Display")

        self.zoom_in = QtGui.QPushButton()
        self.zoom_in.setIcon(qtutils.theme_icon("zoom-in.png"))
        self.zoom_in.setFlat(True)

        self.zoom_out = QtGui.QPushButton()
        self.zoom_out.setIcon(qtutils.theme_icon("zoom-out.png"))
        self.zoom_out.setFlat(True)

        self.top_layout = QtGui.QHBoxLayout()
        self.top_layout.setMargin(defs.margin)
        self.top_layout.setSpacing(defs.button_spacing)

        self.top_layout.addWidget(self.maxresults)
        self.top_layout.addWidget(self.revtext)
        self.top_layout.addWidget(self.displaybutton)
        self.top_layout.addStretch()
        self.top_layout.addWidget(self.zoom_out)
        self.top_layout.addWidget(self.zoom_in)

        self.notifier = notifier = observable.Observable()
        self.notifier.refs_updated = refs_updated = "refs_updated"
        self.notifier.add_observer(refs_updated, self.display)

        self.graphview = GraphView(notifier, self)
        self.treewidget = CommitTreeWidget(notifier, self)
        self.diffwidget = DiffWidget(notifier, self)

        for signal in (archive,):
            qtutils.relay_signal(self, self.graphview, SIGNAL(signal))
            qtutils.relay_signal(self, self.treewidget, SIGNAL(signal))

        self.splitter = QtGui.QSplitter()
        self.splitter.setOrientation(Qt.Horizontal)
        self.splitter.setChildrenCollapsible(True)
        self.splitter.setHandleWidth(defs.handle_width)

        self.left_splitter = QtGui.QSplitter()
        self.left_splitter.setOrientation(Qt.Vertical)
        self.left_splitter.setChildrenCollapsible(True)
        self.left_splitter.setHandleWidth(defs.handle_width)
        self.left_splitter.setStretchFactor(0, 1)
        self.left_splitter.setStretchFactor(1, 1)
        self.left_splitter.insertWidget(0, self.treewidget)
        self.left_splitter.insertWidget(1, self.diffwidget)

        self.splitter.insertWidget(0, self.left_splitter)
        self.splitter.insertWidget(1, self.graphview)

        self.splitter.setStretchFactor(0, 1)
        self.splitter.setStretchFactor(1, 1)

        self.main_layout = QtGui.QVBoxLayout()
        self.main_layout.setMargin(0)
        self.main_layout.setSpacing(0)
        self.main_layout.addLayout(self.top_layout)
        self.main_layout.addWidget(self.splitter)
        self.setLayout(self.main_layout)

        # Also re-loads dag.* from the saved state
        if not qtutils.apply_state(self):
            self.resize_to_desktop()

        # Update fields affected by model
        self.revtext.setText(dag.ref)
        self.maxresults.setValue(dag.count)
        self.update_window_title()

        self.thread = ReaderThread(dag, self)

        self.thread.connect(self.thread, self.thread.commits_ready, self.add_commits)

        self.thread.connect(self.thread, self.thread.done, self.thread_done)

        self.connect(self.splitter, SIGNAL("splitterMoved(int,int)"), self.splitter_moved)

        self.connect(self.zoom_in, SIGNAL("pressed()"), self.graphview.zoom_in)

        self.connect(self.zoom_out, SIGNAL("pressed()"), self.graphview.zoom_out)

        self.connect(self.treewidget, SIGNAL("diff_commits"), self.diff_commits)

        self.connect(self.graphview, SIGNAL("diff_commits"), self.diff_commits)

        self.connect(self.maxresults, SIGNAL("editingFinished()"), self.display)

        self.connect(self.displaybutton, SIGNAL("pressed()"), self.display)

        self.connect(self.revtext, SIGNAL("ref_changed"), self.display)

        self.connect(self.revtext, SIGNAL("textChanged(QString)"), self.text_changed)

        # The model is updated in another thread so use
        # signals/slots to bring control back to the main GUI thread
        self.model.add_observer(self.model.message_updated, self.emit_model_updated)

        self.connect(self, SIGNAL("model_updated"), self.model_updated)

        qtutils.add_close_action(self)
Esempio n. 12
0
    def __init__(self, parent=None):
        QtGui.QTreeWidget.__init__(self, parent)

        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.headerItem().setHidden(True)
        self.setAllColumnsShowFocus(True)
        self.setSortingEnabled(False)
        self.setUniformRowHeights(True)
        self.setAnimated(True)
        self.setRootIsDecorated(False)
        self.setIndentation(0)
        self.setDragEnabled(True)

        self.add_item(N_("Staged"), hide=True)
        self.add_item(N_("Unmerged"), hide=True)
        self.add_item(N_("Modified"), hide=True)
        self.add_item(N_("Untracked"), hide=True)

        # Used to restore the selection
        self.old_scroll = None
        self.old_selection = None
        self.old_contents = None
        self.old_current_item = None
        self.expanded_items = set()

        self.process_selection_action = qtutils.add_action(
            self, cmds.StageOrUnstage.name(), cmds.run(cmds.StageOrUnstage), cmds.StageOrUnstage.SHORTCUT
        )

        self.revert_unstaged_edits_action = qtutils.add_action(
            self, cmds.RevertUnstagedEdits.name(), cmds.run(cmds.RevertUnstagedEdits), cmds.RevertUnstagedEdits.SHORTCUT
        )
        self.revert_unstaged_edits_action.setIcon(qtutils.theme_icon("edit-undo.svg"))

        self.launch_difftool_action = qtutils.add_action(
            self, cmds.LaunchDifftool.name(), cmds.run(cmds.LaunchDifftool), cmds.LaunchDifftool.SHORTCUT
        )
        self.launch_difftool_action.setIcon(qtutils.git_icon())

        self.launch_editor_action = qtutils.add_action(
            self, cmds.LaunchEditor.name(), cmds.run(cmds.LaunchEditor), cmds.LaunchEditor.SHORTCUT, "Return", "Enter"
        )
        self.launch_editor_action.setIcon(qtutils.options_icon())

        if not utils.is_win32():
            self.open_using_default_app = qtutils.add_action(
                self, cmds.OpenDefaultApp.name(), self._open_using_default_app, cmds.OpenDefaultApp.SHORTCUT
            )
            self.open_using_default_app.setIcon(qtutils.file_icon())

            self.open_parent_dir_action = qtutils.add_action(
                self, cmds.OpenParentDir.name(), self._open_parent_dir, cmds.OpenParentDir.SHORTCUT
            )
            self.open_parent_dir_action.setIcon(qtutils.open_file_icon())

        self.up_action = qtutils.add_action(self, N_("Move Up"), self.move_up, Qt.Key_K)

        self.down_action = qtutils.add_action(self, N_("Move Down"), self.move_down, Qt.Key_J)

        self.copy_path_action = qtutils.add_action(
            self, N_("Copy Path to Clipboard"), self.copy_path, QtGui.QKeySequence.Copy
        )
        self.copy_path_action.setIcon(qtutils.theme_icon("edit-copy.svg"))

        self.copy_relpath_action = qtutils.add_action(
            self, N_("Copy Relative Path to Clipboard"), self.copy_relpath, QtGui.QKeySequence.Cut
        )
        self.copy_relpath_action.setIcon(qtutils.theme_icon("edit-copy.svg"))

        # MoveToTrash and Delete use the same shortcut.
        # We will only bind one of them, depending on whether or not the
        # MoveToTrash command is avaialble.  When available, the hotkey
        # is bound to MoveToTrash, otherwise it is bound to Delete.
        if cmds.MoveToTrash.AVAILABLE:
            self.move_to_trash_action = qtutils.add_action(
                self, N_("Move file(s) to trash"), self._trash_untracked_files, cmds.MoveToTrash.SHORTCUT
            )
            self.move_to_trash_action.setIcon(qtutils.discard_icon())
            delete_shortcut = []
        else:
            self.move_to_trash_action = None
            delete_shortcut = [cmds.Delete.SHORTCUT]

        self.delete_untracked_files_action = qtutils.add_action(
            self, N_("Delete File(s)..."), self._delete_untracked_files, *delete_shortcut
        )
        self.delete_untracked_files_action.setIcon(qtutils.discard_icon())

        self.connect(self, SIGNAL("about_to_update()"), self._about_to_update, Qt.QueuedConnection)
        self.connect(self, SIGNAL("updated()"), self._updated, Qt.QueuedConnection)

        self.m = main.model()
        self.m.add_observer(self.m.message_about_to_update, self.about_to_update)
        self.m.add_observer(self.m.message_updated, self.updated)

        self.connect(self, SIGNAL("itemSelectionChanged()"), self.show_selection)

        self.connect(self, SIGNAL("itemDoubleClicked(QTreeWidgetItem*,int)"), self.double_clicked)

        self.connect(self, SIGNAL("itemCollapsed(QTreeWidgetItem*)"), lambda x: self.update_column_widths())

        self.connect(self, SIGNAL("itemExpanded(QTreeWidgetItem*)"), lambda x: self.update_column_widths())
Esempio n. 13
0
    def contextMenuEvent(self, event):
        """Create the context menu for the diff display."""
        menu = QtGui.QMenu(self)
        s = selection.selection()
        filename = selection.filename()

        if s.modified and self.model.stageable():
            if s.modified[0] in main.model().submodules:
                action = menu.addAction(qtutils.add_icon(), cmds.Stage.name(), cmds.run(cmds.Stage, s.modified))
                action.setShortcut(cmds.Stage.SHORTCUT)
                menu.addAction(
                    qtutils.git_icon(), N_("Launch git-cola"), cmds.run(cmds.OpenRepo, core.abspath(s.modified[0]))
                )
            elif s.modified[0] not in main.model().unstaged_deleted:
                if self.has_selection():
                    apply_text = N_("Stage Selected Lines")
                    revert_text = N_("Revert Selected Lines...")
                else:
                    apply_text = N_("Stage Diff Hunk")
                    revert_text = N_("Revert Diff Hunk...")

                self.action_apply_selection.setText(apply_text)
                self.action_apply_selection.setIcon(qtutils.add_icon())

                self.action_revert_selection.setText(revert_text)

                menu.addAction(self.action_apply_selection)
                menu.addAction(self.action_revert_selection)

        if s.staged and self.model.unstageable():
            if s.staged[0] in main.model().submodules:
                action = menu.addAction(qtutils.remove_icon(), cmds.Unstage.name(), cmds.do(cmds.Unstage, s.staged))
                action.setShortcut(cmds.Unstage.SHORTCUT)
                menu.addAction(
                    qtutils.git_icon(), N_("Launch git-cola"), cmds.do(cmds.OpenRepo, core.abspath(s.staged[0]))
                )
            elif s.staged[0] not in main.model().staged_deleted:
                if self.has_selection():
                    apply_text = N_("Unstage Selected Lines")
                else:
                    apply_text = N_("Unstage Diff Hunk")

                self.action_apply_selection.setText(apply_text)
                self.action_apply_selection.setIcon(qtutils.remove_icon())

                menu.addAction(self.action_apply_selection)

        if self.model.stageable() or self.model.unstageable():
            # Do not show the "edit" action when the file does not exist.
            # Untracked files exist by definition.
            if filename and core.exists(filename):
                menu.addSeparator()
                menu.addAction(self.launch_editor)

            # Removed files can still be diffed.
            menu.addAction(self.launch_difftool)

        menu.addSeparator()
        action = menu.addAction(qtutils.theme_icon("edit-copy.svg"), N_("Copy"), self.copy)
        action.setShortcut(QtGui.QKeySequence.Copy)

        action = menu.addAction(qtutils.theme_icon("edit-select-all.svg"), N_("Select All"), self.selectAll)
        action.setShortcut(QtGui.QKeySequence.SelectAll)
        menu.exec_(self.mapToGlobal(event.pos()))
Esempio n. 14
0
    def __init__(self, parent=None):
        QtGui.QTreeWidget.__init__(self, parent)

        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.headerItem().setHidden(True)
        self.setAllColumnsShowFocus(True)
        self.setSortingEnabled(False)
        self.setUniformRowHeights(True)
        self.setAnimated(True)
        self.setRootIsDecorated(False)
        self.setIndentation(0)
        self.setDragEnabled(True)

        self.add_item(N_('Staged'), hide=True)
        self.add_item(N_('Unmerged'), hide=True)
        self.add_item(N_('Modified'), hide=True)
        self.add_item(N_('Untracked'), hide=True)

        # Used to restore the selection
        self.old_scroll = None
        self.old_selection = None
        self.old_contents = None
        self.old_current_item = None
        self.expanded_items = set()

        self.process_selection_action = qtutils.add_action(self,
                cmds.StageOrUnstage.name(),
                cmds.run(cmds.StageOrUnstage),
                cmds.StageOrUnstage.SHORTCUT)

        self.revert_unstaged_edits_action = qtutils.add_action(self,
                cmds.RevertUnstagedEdits.name(),
                cmds.run(cmds.RevertUnstagedEdits),
                cmds.RevertUnstagedEdits.SHORTCUT)
        self.revert_unstaged_edits_action.setIcon(qtutils.icon('undo.svg'))

        self.revert_uncommitted_edits_action = qtutils.add_action(self,
                cmds.RevertUncommittedEdits.name(),
                cmds.run(cmds.RevertUncommittedEdits),
                cmds.RevertUncommittedEdits.SHORTCUT)
        self.revert_uncommitted_edits_action.setIcon(qtutils.icon('undo.svg'))

        self.launch_difftool_action = qtutils.add_action(self,
                cmds.LaunchDifftool.name(),
                cmds.run(cmds.LaunchDifftool),
                cmds.LaunchDifftool.SHORTCUT)
        self.launch_difftool_action.setIcon(qtutils.git_icon())

        self.launch_editor_action = qtutils.add_action(self,
                cmds.LaunchEditor.name(),
                cmds.run(cmds.LaunchEditor),
                cmds.LaunchEditor.SHORTCUT,
                'Return', 'Enter')
        self.launch_editor_action.setIcon(qtutils.options_icon())

        if not utils.is_win32():
            self.open_using_default_app = qtutils.add_action(self,
                    cmds.OpenDefaultApp.name(),
                    self._open_using_default_app,
                    cmds.OpenDefaultApp.SHORTCUT)
            self.open_using_default_app.setIcon(qtutils.file_icon())

            self.open_parent_dir_action = qtutils.add_action(self,
                    cmds.OpenParentDir.name(),
                    self._open_parent_dir,
                    cmds.OpenParentDir.SHORTCUT)
            self.open_parent_dir_action.setIcon(qtutils.open_file_icon())

        self.up_action = qtutils.add_action(self,
                N_('Move Up'), self.move_up, Qt.Key_K)

        self.down_action = qtutils.add_action(self,
                N_('Move Down'), self.move_down, Qt.Key_J)

        self.copy_path_action = qtutils.add_action(self,
                N_('Copy Path to Clipboard'),
                self.copy_path, QtGui.QKeySequence.Copy)
        self.copy_path_action.setIcon(qtutils.theme_icon('edit-copy.svg'))

        self.copy_relpath_action = qtutils.add_action(self,
                N_('Copy Relative Path to Clipboard'),
                self.copy_relpath, QtGui.QKeySequence.Cut)
        self.copy_relpath_action.setIcon(qtutils.theme_icon('edit-copy.svg'))

        if cmds.MoveToTrash.AVAILABLE:
            self.move_to_trash_action = qtutils.add_action(self,
                    N_('Move file(s) to trash'),
                    self._trash_untracked_files, cmds.MoveToTrash.SHORTCUT)
            self.move_to_trash_action.setIcon(qtutils.discard_icon())
            delete_shortcut = cmds.Delete.SHORTCUT
        else:
            self.move_to_trash_action = None
            delete_shortcut = cmds.Delete.ALT_SHORTCUT

        self.delete_untracked_files_action = qtutils.add_action(self,
                N_('Delete File(s)...'),
                self._delete_untracked_files, delete_shortcut)
        self.delete_untracked_files_action.setIcon(qtutils.discard_icon())

        self.connect(self, SIGNAL('about_to_update'), self._about_to_update)
        self.connect(self, SIGNAL('updated'), self._updated)

        self.m = main.model()
        self.m.add_observer(self.m.message_about_to_update,
                            self.about_to_update)
        self.m.add_observer(self.m.message_updated, self.updated)

        self.connect(self, SIGNAL('itemSelectionChanged()'),
                     self.show_selection)

        self.connect(self, SIGNAL('itemDoubleClicked(QTreeWidgetItem*,int)'),
                     self.double_clicked)

        self.connect(self, SIGNAL('itemCollapsed(QTreeWidgetItem*)'),
                     lambda x: self.update_column_widths())

        self.connect(self, SIGNAL('itemExpanded(QTreeWidgetItem*)'),
                     lambda x: self.update_column_widths())
Esempio n. 15
0
    def __init__(self, parent):
        QtGui.QTreeWidget.__init__(self, parent)

        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.headerItem().setHidden(True)
        self.setAllColumnsShowFocus(True)
        self.setSortingEnabled(False)
        self.setUniformRowHeights(True)
        self.setAnimated(True)
        self.setRootIsDecorated(False)
        self.setIndentation(0)

        self.add_item(N_('Staged'), hide=True)
        self.add_item(N_('Unmerged'), hide=True)
        self.add_item(N_('Modified'), hide=True)
        self.add_item(N_('Untracked'), hide=True)

        # Used to restore the selection
        self.old_scroll = None
        self.old_selection = None
        self.old_contents = None

        self.expanded_items = set()

        self.process_selection = qtutils.add_action(self,
                N_('Stage / Unstage'), self._process_selection,
                cmds.Stage.SHORTCUT)

        self.launch_difftool = qtutils.add_action(self,
                cmds.LaunchDifftool.name(),
                cmds.run(cmds.LaunchDifftool),
                cmds.LaunchDifftool.SHORTCUT)
        self.launch_difftool.setIcon(qtutils.icon('git.svg'))

        self.launch_editor = qtutils.add_action(self,
                cmds.LaunchEditor.name(),
                cmds.run(cmds.LaunchEditor),
                cmds.LaunchEditor.SHORTCUT,
                'Return', 'Enter')
        self.launch_editor.setIcon(qtutils.options_icon())

        if not utils.is_win32():
            self.open_using_default_app = qtutils.add_action(self,
                    cmds.OpenDefaultApp.name(),
                    self._open_using_default_app,
                    cmds.OpenDefaultApp.SHORTCUT)
            self.open_using_default_app.setIcon(qtutils.file_icon())

            self.open_parent_dir = qtutils.add_action(self,
                    cmds.OpenParentDir.name(),
                    self._open_parent_dir,
                    cmds.OpenParentDir.SHORTCUT)
            self.open_parent_dir.setIcon(qtutils.open_file_icon())

        self.up = qtutils.add_action(self,
                N_('Move Up'), self.move_up, Qt.Key_K)
        self.down = qtutils.add_action(self,
                N_('Move Down'), self.move_down, Qt.Key_J)

        self.copy_path_action = qtutils.add_action(self,
                N_('Copy Path to Clipboard'),
                self.copy_path, QtGui.QKeySequence.Copy)
        self.copy_path_action.setIcon(qtutils.theme_icon('edit-copy.svg'))

        self.connect(self, SIGNAL('about_to_update'), self._about_to_update)
        self.connect(self, SIGNAL('updated'), self._updated)

        self.m = cola.model()
        self.m.add_observer(self.m.message_about_to_update,
                            self.about_to_update)
        self.m.add_observer(self.m.message_updated, self.updated)

        self.connect(self, SIGNAL('itemSelectionChanged()'),
                     self.show_selection)

        self.connect(self,
                     SIGNAL('itemDoubleClicked(QTreeWidgetItem*,int)'),
                     self.double_clicked)

        self.connect(self,
                     SIGNAL('itemCollapsed(QTreeWidgetItem*)'),
                     lambda x: self.update_column_widths())

        self.connect(self,
                     SIGNAL('itemExpanded(QTreeWidgetItem*)'),
                     lambda x: self.update_column_widths())
Esempio n. 16
0
    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())
Esempio n. 17
0
    def contextMenuEvent(self, event):
        """Create the context menu for the diff display."""
        menu = QtGui.QMenu(self)
        s = selection.selection()
        filename = selection.filename()

        if self.model.stageable() or self.model.unstageable():
            if self.model.stageable():
                self.stage_or_unstage.setText(N_('Stage'))
            else:
                self.stage_or_unstage.setText(N_('Unstage'))
            menu.addAction(self.stage_or_unstage)

        if s.modified and self.model.stageable():
            if s.modified[0] in main.model().submodules:
                action = menu.addAction(qtutils.add_icon(), cmds.Stage.name(),
                                        cmds.run(cmds.Stage, s.modified))
                action.setShortcut(hotkeys.STAGE_SELECTION)
                menu.addAction(
                    qtutils.git_icon(), N_('Launch git-cola'),
                    cmds.run(cmds.OpenRepo, core.abspath(s.modified[0])))
            elif s.modified[0] not in main.model().unstaged_deleted:
                if self.has_selection():
                    apply_text = N_('Stage Selected Lines')
                    revert_text = N_('Revert Selected Lines...')
                else:
                    apply_text = N_('Stage Diff Hunk')
                    revert_text = N_('Revert Diff Hunk...')

                self.action_apply_selection.setText(apply_text)
                self.action_apply_selection.setIcon(qtutils.add_icon())

                self.action_revert_selection.setText(revert_text)

                menu.addAction(self.action_apply_selection)
                menu.addAction(self.action_revert_selection)

        if s.staged and self.model.unstageable():
            if s.staged[0] in main.model().submodules:
                action = menu.addAction(qtutils.remove_icon(),
                                        cmds.Unstage.name(),
                                        cmds.do(cmds.Unstage, s.staged))
                action.setShortcut(hotkeys.STAGE_SELECTION)
                menu.addAction(
                    qtutils.git_icon(), N_('Launch git-cola'),
                    cmds.do(cmds.OpenRepo, core.abspath(s.staged[0])))
            elif s.staged[0] not in main.model().staged_deleted:
                if self.has_selection():
                    apply_text = N_('Unstage Selected Lines')
                else:
                    apply_text = N_('Unstage Diff Hunk')

                self.action_apply_selection.setText(apply_text)
                self.action_apply_selection.setIcon(qtutils.remove_icon())
                menu.addAction(self.action_apply_selection)

        if self.model.stageable() or self.model.unstageable():
            # Do not show the "edit" action when the file does not exist.
            # Untracked files exist by definition.
            if filename and core.exists(filename):
                menu.addSeparator()
                menu.addAction(self.launch_editor)

            # Removed files can still be diffed.
            menu.addAction(self.launch_difftool)

        # Add the Previous/Next File actions, which improves discoverability
        # of their associated shortcuts
        menu.addSeparator()
        menu.addAction(self.move_up)
        menu.addAction(self.move_down)

        menu.addSeparator()
        action = menu.addAction(qtutils.theme_icon('edit-copy.svg'),
                                N_('Copy'), self.copy)
        action.setShortcut(QtGui.QKeySequence.Copy)

        action = menu.addAction(qtutils.theme_icon('edit-select-all.svg'),
                                N_('Select All'), self.selectAll)
        action.setShortcut(QtGui.QKeySequence.SelectAll)
        menu.exec_(self.mapToGlobal(event.pos()))
Esempio n. 18
0
    def __init__(self, parent, titlebar):
        DiffTextEdit.__init__(self, parent)
        self.model = model = main.model()

        # "Diff Options" tool menu
        self.diff_ignore_space_at_eol_action = add_action(
            self, N_('Ignore changes in whitespace at EOL'),
            self._update_diff_opts)
        self.diff_ignore_space_at_eol_action.setCheckable(True)

        self.diff_ignore_space_change_action = add_action(
            self, N_('Ignore changes in amount of whitespace'),
            self._update_diff_opts)
        self.diff_ignore_space_change_action.setCheckable(True)

        self.diff_ignore_all_space_action = add_action(
            self, N_('Ignore all whitespace'), self._update_diff_opts)
        self.diff_ignore_all_space_action.setCheckable(True)

        self.diff_function_context_action = add_action(
            self, N_('Show whole surrounding functions of changes'),
            self._update_diff_opts)
        self.diff_function_context_action.setCheckable(True)

        self.diffopts_button = create_action_button(tooltip=N_('Diff Options'),
                                                    icon=options_icon())
        self.diffopts_menu = create_menu(N_('Diff Options'),
                                         self.diffopts_button)

        self.diffopts_menu.addAction(self.diff_ignore_space_at_eol_action)
        self.diffopts_menu.addAction(self.diff_ignore_space_change_action)
        self.diffopts_menu.addAction(self.diff_ignore_all_space_action)
        self.diffopts_menu.addAction(self.diff_function_context_action)
        self.diffopts_button.setMenu(self.diffopts_menu)
        qtutils.hide_button_menu_indicator(self.diffopts_button)

        titlebar.add_corner_widget(self.diffopts_button)

        self.action_apply_selection = qtutils.add_action(
            self, '', self.apply_selection, hotkeys.STAGE_DIFF)

        self.action_revert_selection = qtutils.add_action(
            self, '', self.revert_selection, hotkeys.REVERT)
        icon = qtutils.theme_icon('edit-undo.svg')
        self.action_revert_selection.setIcon(icon)

        self.launch_editor = actions.launch_editor(self, 'Return', 'Enter')
        self.launch_difftool = actions.launch_difftool(self)
        self.stage_or_unstage = actions.stage_or_unstage(self)

        # Emit up/down signals so that they can be routed by the main widget
        self.move_down = actions.move_down(self)
        self.move_up = actions.move_up(self)

        model.add_observer(model.message_diff_text_changed, self._emit_text)

        self.selection_model = selection_model = selection.selection_model()
        selection_model.add_observer(selection_model.message_selection_changed,
                                     self._update)
        self.connect(self, SIGNAL('update()'), self._update_callback,
                     Qt.QueuedConnection)

        self.connect(self, SIGNAL('set_text(PyQt_PyObject)'),
                     self.setPlainText)
Esempio n. 19
0
    def __init__(self, model, dag, parent=None, args=None):
        standard.Dialog.__init__(self, parent=parent)
        if utils.is_darwin():
            self.setAttribute(QtCore.Qt.WA_MacMetalStyle)
        # change when widgets are added/removed
        self.widget_version = 1

        self.model = model
        self.dag = dag
        self.setObjectName('dag')
        self.setMinimumSize(1, 1)

        self.revlabel = QtGui.QLabel()
        self.revlabel.setText('git log -')

        self.revtext = GitLogLineEdit(parent=self)

        self.maxresults = QtGui.QSpinBox()
        self.maxresults.setMinimum(-1)
        self.maxresults.setMaximum(2**31 - 1)

        self.displaybutton = QtGui.QPushButton()
        self.displaybutton.setText('Display')

        self.zoom_in = QtGui.QPushButton()
        self.zoom_in.setIcon(qtutils.theme_icon('zoom-in.png'))
        self.zoom_in.setFlat(True)

        self.zoom_out = QtGui.QPushButton()
        self.zoom_out.setIcon(qtutils.theme_icon('zoom-out.png'))
        self.zoom_out.setFlat(True)

        self._buttons_layt = QtGui.QHBoxLayout()
        self._buttons_layt.setMargin(2)
        self._buttons_layt.setSpacing(4)

        self._buttons_layt.addWidget(self.revlabel)
        self._buttons_layt.addWidget(self.maxresults)
        self._buttons_layt.addWidget(self.revtext)
        self._buttons_layt.addWidget(self.displaybutton)
        self._buttons_layt.addStretch()
        self._buttons_layt.addWidget(self.zoom_out)
        self._buttons_layt.addWidget(self.zoom_in)

        self._commits = {}
        self._notifier = notifier = observable.Observable()
        self._notifier.refs_updated = refs_updated = 'refs_updated'
        self._notifier.add_message_observer(refs_updated, self._display)

        self._graphview = GraphView(notifier)
        self._treewidget = CommitTreeWidget(notifier)
        self._diffwidget = DiffWidget(notifier)

        for signal in (archive,):
            qtutils.relay_signal(self, self._graphview, SIGNAL(signal))
            qtutils.relay_signal(self, self._treewidget, SIGNAL(signal))

        self._mainsplitter = QtGui.QSplitter()
        self._mainsplitter.setOrientation(QtCore.Qt.Horizontal)
        self._mainsplitter.setChildrenCollapsible(True)

        self._leftsplitter = QtGui.QSplitter()
        self._leftsplitter.setOrientation(QtCore.Qt.Vertical)
        self._leftsplitter.setChildrenCollapsible(True)
        self._leftsplitter.setStretchFactor(0, 1)
        self._leftsplitter.setStretchFactor(1, 1)
        self._leftsplitter.insertWidget(0, self._treewidget)
        self._leftsplitter.insertWidget(1, self._diffwidget)

        self._mainsplitter.insertWidget(0, self._leftsplitter)
        self._mainsplitter.insertWidget(1, self._graphview)

        self._mainsplitter.setStretchFactor(0, 1)
        self._mainsplitter.setStretchFactor(1, 1)

        self._layt = layt = QtGui.QVBoxLayout()
        layt.setMargin(0)
        layt.setSpacing(0)
        layt.addLayout(self._buttons_layt)
        layt.addWidget(self._mainsplitter)
        self.setLayout(layt)

        # Also re-loads dag.* from the saved state
        if not qtutils.apply_state(self):
            self.resize_to_desktop()

        # Update fields affected by model
        self.revtext.setText(dag.ref)
        self.maxresults.setValue(dag.count)
        self.update_window_title()

        self.thread = ReaderThread(self, dag)

        self.thread.connect(self.thread, self.thread.commits_ready,
                            self.add_commits)

        self.thread.connect(self.thread, self.thread.done,
                            self.thread_done)

        self.connect(self._mainsplitter, SIGNAL('splitterMoved(int,int)'),
                     self._splitter_moved)

        self.connect(self.zoom_in, SIGNAL('pressed()'),
                     self._graphview.zoom_in)

        self.connect(self.zoom_out, SIGNAL('pressed()'),
                     self._graphview.zoom_out)

        self.connect(self.maxresults, SIGNAL('valueChanged(int)'),
                     lambda(x): self.dag.set_count(x))

        self.connect(self.displaybutton, SIGNAL('pressed()'),
                     self._display)

        self.connect(self.revtext, SIGNAL('ref_changed'),
                     self._display)

        self.connect(self.revtext, SIGNAL('textChanged(QString)'),
                     self._text_changed)

        # The model is updated in another thread so use
        # signals/slots to bring control back to the main GUI thread
        self.model.add_message_observer(self.model.message_updated,
                                        self._model_updated)

        self.connect(self, SIGNAL('model_updated'),
                     self.model_updated)

        qtutils.add_close_action(self)
Esempio n. 20
0
    def __init__(self, parent=None):
        QtGui.QTreeWidget.__init__(self, parent)

        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.headerItem().setHidden(True)
        self.setAllColumnsShowFocus(True)
        self.setSortingEnabled(False)
        self.setUniformRowHeights(True)
        self.setAnimated(True)
        self.setRootIsDecorated(False)
        self.setIndentation(0)
        self.setDragEnabled(True)

        self.add_item(N_('Staged'), hide=True)
        self.add_item(N_('Unmerged'), hide=True)
        self.add_item(N_('Modified'), hide=True)
        self.add_item(N_('Untracked'), hide=True)

        # Used to restore the selection
        self.old_scroll = None
        self.old_selection = None
        self.old_contents = None
        self.old_current_item = None
        self.expanded_items = set()

        self.process_selection_action = qtutils.add_action(self,
                cmds.StageOrUnstage.name(),
                cmds.run(cmds.StageOrUnstage), hotkeys.STAGE_SELECTION)

        self.revert_unstaged_edits_action = qtutils.add_action(self,
                cmds.RevertUnstagedEdits.name(),
                cmds.run(cmds.RevertUnstagedEdits), hotkeys.REVERT)
        icon = qtutils.theme_icon('edit-undo.svg')
        self.revert_unstaged_edits_action.setIcon(icon)

        self.launch_difftool_action = qtutils.add_action(self,
                cmds.LaunchDifftool.name(),
                cmds.run(cmds.LaunchDifftool), hotkeys.DIFF)
        self.launch_difftool_action.setIcon(qtutils.git_icon())

        self.launch_editor_action = qtutils.add_action(self,
                cmds.LaunchEditor.name(),
                cmds.run(cmds.LaunchEditor), hotkeys.EDIT, *hotkeys.ACCEPT)
        self.launch_editor_action.setIcon(qtutils.options_icon())

        if not utils.is_win32():
            self.open_using_default_app = qtutils.add_action(self,
                    cmds.OpenDefaultApp.name(),
                    self._open_using_default_app, hotkeys.PRIMARY_ACTION)
            self.open_using_default_app.setIcon(qtutils.file_icon())

            self.open_parent_dir_action = qtutils.add_action(self,
                    cmds.OpenParentDir.name(),
                    self._open_parent_dir, hotkeys.SECONDARY_ACTION)
            self.open_parent_dir_action.setIcon(qtutils.open_file_icon())

        self.up_action = qtutils.add_action(self,
                N_('Move Up'), self.move_up,
                hotkeys.MOVE_UP, hotkeys.MOVE_UP_SECONDARY)

        self.down_action = qtutils.add_action(self,
                N_('Move Down'), self.move_down,
                hotkeys.MOVE_DOWN, hotkeys.MOVE_DOWN_SECONDARY)

        self.copy_path_action = qtutils.add_action(self,
                N_('Copy Path to Clipboard'), self.copy_path, hotkeys.COPY)
        self.copy_path_action.setIcon(qtutils.theme_icon('edit-copy.svg'))

        self.copy_relpath_action = qtutils.add_action(self,
                N_('Copy Relative Path to Clipboard'),
                self.copy_relpath, hotkeys.CUT)
        self.copy_relpath_action.setIcon(qtutils.theme_icon('edit-copy.svg'))

        self.view_history_action = qtutils.add_action(self,
                N_('View History...'),
                self.view_history, hotkeys.HISTORY)

        # MoveToTrash and Delete use the same shortcut.
        # We will only bind one of them, depending on whether or not the
        # MoveToTrash command is avaialble.  When available, the hotkey
        # is bound to MoveToTrash, otherwise it is bound to Delete.
        if cmds.MoveToTrash.AVAILABLE:
            self.move_to_trash_action = qtutils.add_action(self,
                    N_('Move file(s) to trash'),
                    self._trash_untracked_files, hotkeys.TRASH)
            self.move_to_trash_action.setIcon(qtutils.discard_icon())
            delete_shortcut = hotkeys.DELETE_FILE
        else:
            self.move_to_trash_action = None
            delete_shortcut = hotkeys.DELETE_FILE_SECONDARY

        self.delete_untracked_files_action = qtutils.add_action(self,
                N_('Delete File(s)...'),
                self._delete_untracked_files, delete_shortcut)
        self.delete_untracked_files_action.setIcon(qtutils.discard_icon())

        self.connect(self, SIGNAL('about_to_update()'),
                     self._about_to_update, Qt.QueuedConnection)
        self.connect(self, SIGNAL('updated()'),
                     self._updated, Qt.QueuedConnection)

        self.m = main.model()
        self.m.add_observer(self.m.message_about_to_update,
                            self.about_to_update)
        self.m.add_observer(self.m.message_updated, self.updated)

        self.connect(self, SIGNAL('itemSelectionChanged()'),
                     self.show_selection)

        self.connect(self, SIGNAL('itemDoubleClicked(QTreeWidgetItem*,int)'),
                     self.double_clicked)

        self.connect(self, SIGNAL('itemCollapsed(QTreeWidgetItem*)'),
                     lambda x: self.update_column_widths())

        self.connect(self, SIGNAL('itemExpanded(QTreeWidgetItem*)'),
                     lambda x: self.update_column_widths())
Esempio n. 21
0
    def __init__(self, model, dag, parent=None):
        MainWindow.__init__(self, parent)

        self.setAttribute(Qt.WA_MacMetalStyle)
        self.setMinimumSize(420, 420)

        # change when widgets are added/removed
        self.widget_version = 1
        self.model = model
        self.dag = dag

        self.commits = {}
        self.commit_list = []

        self.old_count = None
        self.old_ref = None
        self.thread = ReaderThread(dag, self)

        self.revtext = completion.GitLogLineEdit()

        self.maxresults = QtGui.QSpinBox()
        self.maxresults.setMinimum(1)
        self.maxresults.setMaximum(99999)
        self.maxresults.setPrefix('')
        self.maxresults.setSuffix('')

        self.zoom_out = qtutils.create_action_button(
                tooltip=N_('Zoom Out'),
                icon=qtutils.theme_icon('zoom-out.png'))

        self.zoom_in = qtutils.create_action_button(
                tooltip=N_('Zoom In'),
                icon=qtutils.theme_icon('zoom-in.png'))

        self.zoom_to_fit = qtutils.create_action_button(
                tooltip=N_('Zoom to Fit'),
                icon=qtutils.theme_icon('zoom-fit-best.png'))

        self.notifier = notifier = observable.Observable()
        self.notifier.refs_updated = refs_updated = 'refs_updated'
        self.notifier.add_observer(refs_updated, self.display)

        self.treewidget = CommitTreeWidget(notifier, self)
        self.diffwidget = DiffWidget(notifier, self)
        self.filewidget = FileWidget(notifier, self)
        self.graphview = GraphView(notifier, self)

        self.controls_layout = QtGui.QHBoxLayout()
        self.controls_layout.setMargin(defs.no_margin)
        self.controls_layout.setSpacing(defs.spacing)
        self.controls_layout.addWidget(self.revtext)
        self.controls_layout.addWidget(self.maxresults)

        self.controls_widget = QtGui.QWidget()
        self.controls_widget.setLayout(self.controls_layout)

        self.log_dock = qtutils.create_dock(N_('Log'), self, stretch=False)
        self.log_dock.setWidget(self.treewidget)
        log_dock_titlebar = self.log_dock.titleBarWidget()
        log_dock_titlebar.add_corner_widget(self.controls_widget)

        self.file_dock = qtutils.create_dock(N_('Files'), self)
        self.file_dock.setWidget(self.filewidget)

        self.diff_dock = qtutils.create_dock(N_('Diff'), self)
        self.diff_dock.setWidget(self.diffwidget)

        self.graph_controls_layout = QtGui.QHBoxLayout()
        self.graph_controls_layout.setMargin(defs.no_margin)
        self.graph_controls_layout.setSpacing(defs.button_spacing)
        self.graph_controls_layout.addWidget(self.zoom_out)
        self.graph_controls_layout.addWidget(self.zoom_in)
        self.graph_controls_layout.addWidget(self.zoom_to_fit)

        self.graph_controls_widget = QtGui.QWidget()
        self.graph_controls_widget.setLayout(self.graph_controls_layout)

        self.graphview_dock = qtutils.create_dock(N_('Graph'), self)
        self.graphview_dock.setWidget(self.graphview)
        graph_titlebar = self.graphview_dock.titleBarWidget()
        graph_titlebar.add_corner_widget(self.graph_controls_widget)

        self.lock_layout_action = qtutils.add_action_bool(self,
                N_('Lock Layout'), self.set_lock_layout, False)

        # Create the application menu
        self.menubar = QtGui.QMenuBar(self)

        # View Menu
        self.view_menu = qtutils.create_menu(N_('View'), self.menubar)
        self.view_menu.addAction(self.log_dock.toggleViewAction())
        self.view_menu.addAction(self.graphview_dock.toggleViewAction())
        self.view_menu.addAction(self.diff_dock.toggleViewAction())
        self.view_menu.addAction(self.file_dock.toggleViewAction())
        self.view_menu.addSeparator()
        self.view_menu.addAction(self.lock_layout_action)

        self.menubar.addAction(self.view_menu.menuAction())
        self.setMenuBar(self.menubar)

        left = Qt.LeftDockWidgetArea
        right = Qt.RightDockWidgetArea
        bottom = Qt.BottomDockWidgetArea
        self.addDockWidget(left, self.log_dock)
        self.addDockWidget(right, self.graphview_dock)
        self.addDockWidget(right, self.file_dock)
        self.addDockWidget(bottom, self.diff_dock)

        # Update fields affected by model
        self.revtext.setText(dag.ref)
        self.maxresults.setValue(dag.count)
        self.update_window_title()

        # Also re-loads dag.* from the saved state
        if not self.restore_state():
            self.resize_to_desktop()

        qtutils.connect_button(self.zoom_out, self.graphview.zoom_out)
        qtutils.connect_button(self.zoom_in, self.graphview.zoom_in)
        qtutils.connect_button(self.zoom_to_fit,
                               self.graphview.zoom_to_fit)

        self.thread.connect(self.thread, self.thread.commits_ready,
                            self.add_commits)

        self.thread.connect(self.thread, self.thread.done,
                            self.thread_done)

        self.connect(self.treewidget, SIGNAL('diff_commits'),
                     self.diff_commits)

        self.connect(self.graphview, SIGNAL('diff_commits'),
                     self.diff_commits)

        self.connect(self.maxresults, SIGNAL('editingFinished()'),
                     self.display)

        self.connect(self.revtext, SIGNAL('changed()'),
                     self.display)

        self.connect(self.revtext, SIGNAL('textChanged(QString)'),
                     self.text_changed)

        self.connect(self.revtext, SIGNAL('returnPressed()'),
                     self.display)

        # The model is updated in another thread so use
        # signals/slots to bring control back to the main GUI thread
        self.model.add_observer(self.model.message_updated,
                                self.emit_model_updated)

        self.connect(self, SIGNAL('model_updated'),
                     self.model_updated)

        qtutils.add_action(self, 'Focus search field',
                           lambda: self.revtext.setFocus(), 'Ctrl+l')

        qtutils.add_close_action(self)
Esempio n. 22
0
    def __init__(self, parent, titlebar):
        DiffTextEdit.__init__(self, parent)
        self.model = model = main.model()

        # "Diff Options" tool menu
        self.diff_ignore_space_at_eol_action = add_action(self,
                N_('Ignore changes in whitespace at EOL'),
                self._update_diff_opts)
        self.diff_ignore_space_at_eol_action.setCheckable(True)

        self.diff_ignore_space_change_action = add_action(self,
                N_('Ignore changes in amount of whitespace'),
                self._update_diff_opts)
        self.diff_ignore_space_change_action.setCheckable(True)

        self.diff_ignore_all_space_action = add_action(self,
                N_('Ignore all whitespace'),
                self._update_diff_opts)
        self.diff_ignore_all_space_action.setCheckable(True)

        self.diff_function_context_action = add_action(self,
                N_('Show whole surrounding functions of changes'),
                self._update_diff_opts)
        self.diff_function_context_action.setCheckable(True)

        self.diffopts_button = create_action_button(
                tooltip=N_('Diff Options'), icon=options_icon())
        self.diffopts_menu = create_menu(N_('Diff Options'),
                                         self.diffopts_button)

        self.diffopts_menu.addAction(self.diff_ignore_space_at_eol_action)
        self.diffopts_menu.addAction(self.diff_ignore_space_change_action)
        self.diffopts_menu.addAction(self.diff_ignore_all_space_action)
        self.diffopts_menu.addAction(self.diff_function_context_action)
        self.diffopts_button.setMenu(self.diffopts_menu)
        qtutils.hide_button_menu_indicator(self.diffopts_button)

        titlebar.add_corner_widget(self.diffopts_button)

        self.action_apply_selection = qtutils.add_action(self, '',
                self.apply_selection, hotkeys.STAGE_DIFF)

        self.action_revert_selection = qtutils.add_action(self, '',
                self.revert_selection, hotkeys.REVERT)
        icon = qtutils.theme_icon('edit-undo.svg')
        self.action_revert_selection.setIcon(icon)

        self.launch_editor = actions.launch_editor(self, 'Return', 'Enter')
        self.launch_difftool = actions.launch_difftool(self)
        self.stage_or_unstage = actions.stage_or_unstage(self)

        # Emit up/down signals so that they can be routed by the main widget
        self.move_down = actions.move_down(self)
        self.move_up = actions.move_up(self)

        model.add_observer(model.message_diff_text_changed, self._emit_text)

        self.selection_model = selection_model = selection.selection_model()
        selection_model.add_observer(selection_model.message_selection_changed,
                                     self._update)
        self.connect(self, SIGNAL('update()'),
                     self._update_callback, Qt.QueuedConnection)

        self.connect(self, SIGNAL('set_text(PyQt_PyObject)'), self.setPlainText)
Esempio n. 23
0
    def __init__(self, model, dag, parent=None, settings=None):
        MainWindow.__init__(self, parent)

        self.setAttribute(Qt.WA_MacMetalStyle)
        self.setMinimumSize(420, 420)

        # change when widgets are added/removed
        self.widget_version = 2
        self.model = model
        self.dag = dag
        self.settings = settings

        self.commits = {}
        self.commit_list = []

        self.thread = ReaderThread(dag, self)
        self.revtext = completion.GitLogLineEdit()
        self.maxresults = standard.SpinBox()

        self.zoom_out = qtutils.create_action_button(
            tooltip=N_('Zoom Out'), icon=qtutils.theme_icon('zoom-out.png'))

        self.zoom_in = qtutils.create_action_button(
            tooltip=N_('Zoom In'), icon=qtutils.theme_icon('zoom-in.png'))

        self.zoom_to_fit = qtutils.create_action_button(
            tooltip=N_('Zoom to Fit'),
            icon=qtutils.theme_icon('zoom-fit-best.png'))

        self.notifier = notifier = observable.Observable()
        self.notifier.refs_updated = refs_updated = 'refs_updated'
        self.notifier.add_observer(refs_updated, self.display)

        self.treewidget = CommitTreeWidget(notifier, self)
        self.diffwidget = DiffWidget(notifier, self)
        self.filewidget = FileWidget(notifier, self)
        self.graphview = GraphView(notifier, self)

        self.controls_layout = qtutils.hbox(defs.no_margin, defs.spacing,
                                            self.revtext, self.maxresults)

        self.controls_widget = QtGui.QWidget()
        self.controls_widget.setLayout(self.controls_layout)

        self.log_dock = qtutils.create_dock(N_('Log'), self, stretch=False)
        self.log_dock.setWidget(self.treewidget)
        log_dock_titlebar = self.log_dock.titleBarWidget()
        log_dock_titlebar.add_corner_widget(self.controls_widget)

        self.file_dock = qtutils.create_dock(N_('Files'), self)
        self.file_dock.setWidget(self.filewidget)

        self.diff_dock = qtutils.create_dock(N_('Diff'), self)
        self.diff_dock.setWidget(self.diffwidget)

        self.graph_controls_layout = qtutils.hbox(defs.no_margin,
                                                  defs.button_spacing,
                                                  self.zoom_out, self.zoom_in,
                                                  self.zoom_to_fit)

        self.graph_controls_widget = QtGui.QWidget()
        self.graph_controls_widget.setLayout(self.graph_controls_layout)

        self.graphview_dock = qtutils.create_dock(N_('Graph'), self)
        self.graphview_dock.setWidget(self.graphview)
        graph_titlebar = self.graphview_dock.titleBarWidget()
        graph_titlebar.add_corner_widget(self.graph_controls_widget)

        self.lock_layout_action = qtutils.add_action_bool(
            self, N_('Lock Layout'), self.set_lock_layout, False)

        self.refresh_action = qtutils.add_action(self, N_('Refresh'),
                                                 self.refresh, 'Ctrl+R')

        # Create the application menu
        self.menubar = QtGui.QMenuBar(self)

        # View Menu
        self.view_menu = qtutils.create_menu(N_('View'), self.menubar)
        self.view_menu.addAction(self.refresh_action)

        self.view_menu.addAction(self.log_dock.toggleViewAction())
        self.view_menu.addAction(self.graphview_dock.toggleViewAction())
        self.view_menu.addAction(self.diff_dock.toggleViewAction())
        self.view_menu.addAction(self.file_dock.toggleViewAction())
        self.view_menu.addSeparator()
        self.view_menu.addAction(self.lock_layout_action)

        self.menubar.addAction(self.view_menu.menuAction())
        self.setMenuBar(self.menubar)

        left = Qt.LeftDockWidgetArea
        right = Qt.RightDockWidgetArea
        self.addDockWidget(left, self.log_dock)
        self.addDockWidget(left, self.diff_dock)
        self.addDockWidget(right, self.graphview_dock)
        self.addDockWidget(right, self.file_dock)

        # Update fields affected by model
        self.revtext.setText(dag.ref)
        self.maxresults.setValue(dag.count)
        self.update_window_title()

        # Also re-loads dag.* from the saved state
        if not self.restore_state(settings=settings):
            self.resize_to_desktop()

        qtutils.connect_button(self.zoom_out, self.graphview.zoom_out)
        qtutils.connect_button(self.zoom_in, self.graphview.zoom_in)
        qtutils.connect_button(self.zoom_to_fit, self.graphview.zoom_to_fit)

        self.thread.connect(self.thread, self.thread.commits_ready,
                            self.add_commits)

        self.thread.connect(self.thread, self.thread.done, self.thread_done)

        self.connect(self.treewidget, SIGNAL('diff_commits'),
                     self.diff_commits)

        self.connect(self.graphview, SIGNAL('diff_commits'), self.diff_commits)

        self.connect(self.maxresults, SIGNAL('editingFinished()'),
                     self.display)

        self.connect(self.revtext, SIGNAL('changed()'), self.display)

        self.connect(self.revtext, SIGNAL('textChanged(QString)'),
                     self.text_changed)

        self.connect(self.revtext, SIGNAL('returnPressed()'), self.display)

        # The model is updated in another thread so use
        # signals/slots to bring control back to the main GUI thread
        self.model.add_observer(self.model.message_updated,
                                self.emit_model_updated)

        self.connect(self, SIGNAL('model_updated'), self.model_updated)

        qtutils.add_action(self, 'Focus search field',
                           lambda: self.revtext.setFocus(), 'Ctrl+L')

        qtutils.add_close_action(self)
Esempio n. 24
0
    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())
Esempio n. 25
0
    def __init__(self, parent):
        QtGui.QTreeWidget.__init__(self, parent)

        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.headerItem().setHidden(True)
        self.setAllColumnsShowFocus(True)
        self.setSortingEnabled(False)
        self.setUniformRowHeights(True)
        self.setAnimated(True)
        self.setRootIsDecorated(False)
        self.setIndentation(0)

        self.add_item(N_('Staged'), hide=True)
        self.add_item(N_('Unmerged'), hide=True)
        self.add_item(N_('Modified'), hide=True)
        self.add_item(N_('Untracked'), hide=True)

        # Used to restore the selection
        self.old_scroll = None
        self.old_selection = None
        self.old_contents = None
        self.old_current_item = None
        self.expanded_items = set()

        self.process_selection = qtutils.add_action(self,
                                                    N_('Stage / Unstage'),
                                                    self._process_selection,
                                                    cmds.Stage.SHORTCUT)

        self.revert_unstaged_edits_action = qtutils.add_action(
            self, N_('Revert Unstaged Edits...'),
            cmds.run(cmds.RevertUnstagedEdits),
            cmds.RevertUnstagedEdits.SHORTCUT)
        self.revert_unstaged_edits_action.setIcon(qtutils.icon('undo.svg'))

        self.launch_difftool = qtutils.add_action(
            self, cmds.LaunchDifftool.name(), cmds.run(cmds.LaunchDifftool),
            cmds.LaunchDifftool.SHORTCUT)
        self.launch_difftool.setIcon(qtutils.icon('git.svg'))

        self.launch_editor = qtutils.add_action(self, cmds.LaunchEditor.name(),
                                                cmds.run(cmds.LaunchEditor),
                                                cmds.LaunchEditor.SHORTCUT,
                                                'Return', 'Enter')
        self.launch_editor.setIcon(qtutils.options_icon())

        if not utils.is_win32():
            self.open_using_default_app = qtutils.add_action(
                self, cmds.OpenDefaultApp.name(), self._open_using_default_app,
                cmds.OpenDefaultApp.SHORTCUT)
            self.open_using_default_app.setIcon(qtutils.file_icon())

            self.open_parent_dir = qtutils.add_action(
                self, cmds.OpenParentDir.name(), self._open_parent_dir,
                cmds.OpenParentDir.SHORTCUT)
            self.open_parent_dir.setIcon(qtutils.open_file_icon())

        self.up = qtutils.add_action(self, N_('Move Up'), self.move_up,
                                     Qt.Key_K)

        self.down = qtutils.add_action(self, N_('Move Down'), self.move_down,
                                       Qt.Key_J)

        self.copy_path_action = qtutils.add_action(
            self, N_('Copy Path to Clipboard'), self.copy_path,
            QtGui.QKeySequence.Copy)
        self.copy_path_action.setIcon(qtutils.theme_icon('edit-copy.svg'))

        self.connect(self, SIGNAL('about_to_update'), self._about_to_update)
        self.connect(self, SIGNAL('updated'), self._updated)

        self.m = main.model()
        self.m.add_observer(self.m.message_about_to_update,
                            self.about_to_update)
        self.m.add_observer(self.m.message_updated, self.updated)

        self.connect(self, SIGNAL('itemSelectionChanged()'),
                     self.show_selection)

        self.connect(self, SIGNAL('itemDoubleClicked(QTreeWidgetItem*,int)'),
                     self.double_clicked)

        self.connect(self, SIGNAL('itemCollapsed(QTreeWidgetItem*)'),
                     lambda x: self.update_column_widths())

        self.connect(self, SIGNAL('itemExpanded(QTreeWidgetItem*)'),
                     lambda x: self.update_column_widths())
Esempio n. 26
0
    def contextMenuEvent(self, event):
        """Create the context menu for the diff display."""
        menu = QtGui.QMenu(self)
        s = selection.selection()
        filename = selection.filename()

        if self.model.stageable() or self.model.unstageable():
            if self.model.stageable():
                self.stage_or_unstage.setText(N_('Stage'))
            else:
                self.stage_or_unstage.setText(N_('Unstage'))
            menu.addAction(self.stage_or_unstage)

        if s.modified and self.model.stageable():
            if s.modified[0] in main.model().submodules:
                action = menu.addAction(qtutils.add_icon(),
                                        cmds.Stage.name(),
                                        cmds.run(cmds.Stage, s.modified))
                action.setShortcut(cmds.Stage.SHORTCUT)
                menu.addAction(qtutils.git_icon(),
                               N_('Launch git-cola'),
                               cmds.run(cmds.OpenRepo,
                                        core.abspath(s.modified[0])))
            elif s.modified[0] not in main.model().unstaged_deleted:
                if self.has_selection():
                    apply_text = N_('Stage Selected Lines')
                    revert_text = N_('Revert Selected Lines...')
                else:
                    apply_text = N_('Stage Diff Hunk')
                    revert_text = N_('Revert Diff Hunk...')

                self.action_apply_selection.setText(apply_text)
                self.action_apply_selection.setIcon(qtutils.add_icon())

                self.action_revert_selection.setText(revert_text)

                menu.addAction(self.action_apply_selection)
                menu.addAction(self.action_revert_selection)

        if s.staged and self.model.unstageable():
            if s.staged[0] in main.model().submodules:
                action = menu.addAction(qtutils.remove_icon(),
                                        cmds.Unstage.name(),
                                        cmds.do(cmds.Unstage, s.staged))
                action.setShortcut(cmds.Unstage.SHORTCUT)
                menu.addAction(qtutils.git_icon(),
                               N_('Launch git-cola'),
                               cmds.do(cmds.OpenRepo,
                                       core.abspath(s.staged[0])))
            elif s.staged[0] not in main.model().staged_deleted:
                if self.has_selection():
                    apply_text = N_('Unstage Selected Lines')
                else:
                    apply_text = N_('Unstage Diff Hunk')

                self.action_apply_selection.setText(apply_text)
                self.action_apply_selection.setIcon(qtutils.remove_icon())
                menu.addAction(self.action_apply_selection)

        if self.model.stageable() or self.model.unstageable():
            # Do not show the "edit" action when the file does not exist.
            # Untracked files exist by definition.
            if filename and core.exists(filename):
                menu.addSeparator()
                menu.addAction(self.launch_editor)

            # Removed files can still be diffed.
            menu.addAction(self.launch_difftool)

        # Add the Previous/Next File actions, which improves discoverability
        # of their associated shortcuts
        menu.addSeparator()
        menu.addAction(self.move_up)
        menu.addAction(self.move_down)

        menu.addSeparator()
        action = menu.addAction(qtutils.theme_icon('edit-copy.svg'),
                                N_('Copy'), self.copy)
        action.setShortcut(QtGui.QKeySequence.Copy)

        action = menu.addAction(qtutils.theme_icon('edit-select-all.svg'),
                                N_('Select All'), self.selectAll)
        action.setShortcut(QtGui.QKeySequence.SelectAll)
        menu.exec_(self.mapToGlobal(event.pos()))