FreeCAD

Форк
0
/
change_branch.py 
245 строк · 9.9 Кб
1
# SPDX-License-Identifier: LGPL-2.1-or-later
2
# ***************************************************************************
3
# *                                                                         *
4
# *   Copyright (c) 2022-2023 FreeCAD Project Association                   *
5
# *                                                                         *
6
# *   This file is part of FreeCAD.                                         *
7
# *                                                                         *
8
# *   FreeCAD is free software: you can redistribute it and/or modify it    *
9
# *   under the terms of the GNU Lesser General Public License as           *
10
# *   published by the Free Software Foundation, either version 2.1 of the  *
11
# *   License, or (at your option) any later version.                       *
12
# *                                                                         *
13
# *   FreeCAD is distributed in the hope that it will be useful, but        *
14
# *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
15
# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
16
# *   Lesser General Public License for more details.                       *
17
# *                                                                         *
18
# *   You should have received a copy of the GNU Lesser General Public      *
19
# *   License along with FreeCAD. If not, see                               *
20
# *   <https://www.gnu.org/licenses/>.                                      *
21
# *                                                                         *
22
# ***************************************************************************
23

24
import os
25

26
import FreeCAD
27
import FreeCADGui
28
from addonmanager_git import initialize_git
29

30
from PySide import QtWidgets, QtCore
31

32
translate = FreeCAD.Qt.translate
33

34

35
class ChangeBranchDialog(QtWidgets.QWidget):
36

37
    branch_changed = QtCore.Signal(str)
38

39
    def __init__(self, path: str, parent=None):
40
        super().__init__(parent)
41

42
        self.ui = FreeCADGui.PySideUic.loadUi(
43
            os.path.join(os.path.dirname(__file__), "change_branch.ui")
44
        )
45

46
        self.item_filter = ChangeBranchDialogFilter()
47
        self.ui.tableView.setModel(self.item_filter)
48

49
        self.item_model = ChangeBranchDialogModel(path, self)
50
        self.item_filter.setSourceModel(self.item_model)
51
        self.ui.tableView.sortByColumn(
52
            2, QtCore.Qt.DescendingOrder
53
        )  # Default to sorting by remote last-changed date
54

55
        # Figure out what row gets selected:
56
        git_manager = initialize_git()
57
        row = 0
58
        current_ref = git_manager.current_branch(path)
59
        selection_model = self.ui.tableView.selectionModel()
60
        for ref in self.item_model.branches:
61
            if ref["ref_name"] == current_ref:
62
                index = self.item_filter.mapFromSource(self.item_model.index(row, 0))
63
                selection_model.select(index, QtCore.QItemSelectionModel.ClearAndSelect)
64
                selection_model.select(index.siblingAtColumn(1), QtCore.QItemSelectionModel.Select)
65
                selection_model.select(index.siblingAtColumn(2), QtCore.QItemSelectionModel.Select)
66
                break
67
            row += 1
68

69
        # Make sure the column widths are OK:
70
        header = self.ui.tableView.horizontalHeader()
71
        header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
72

73
    def exec(self):
74
        if self.ui.exec() == QtWidgets.QDialog.Accepted:
75

76
            selection = self.ui.tableView.selectedIndexes()
77
            index = self.item_filter.mapToSource(selection[0])
78
            ref = self.item_model.data(index, ChangeBranchDialogModel.RefAccessRole)
79

80
            if ref["ref_name"] == self.item_model.current_branch:
81
                # This is the one we are already on... just return
82
                return
83

84
            result = QtWidgets.QMessageBox.critical(
85
                self,
86
                translate("AddonsInstaller", "DANGER: Developer feature"),
87
                translate(
88
                    "AddonsInstaller",
89
                    "DANGER: Switching branches is intended for developers and beta testers, "
90
                    "and may result in broken, non-backwards compatible documents, instability, "
91
                    "crashes, and/or the premature heat death of the universe. Are you sure you "
92
                    "want to continue?",
93
                ),
94
                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Cancel,
95
                QtWidgets.QMessageBox.Cancel,
96
            )
97
            if result == QtWidgets.QMessageBox.Cancel:
98
                return
99
            if self.item_model.dirty:
100
                result = QtWidgets.QMessageBox.critical(
101
                    self,
102
                    translate("AddonsInstaller", "There are local changes"),
103
                    translate(
104
                        "AddonsInstaller",
105
                        "WARNING: This repo has uncommitted local changes. Are you sure you want "
106
                        "to change branches (bringing the changes with you)?",
107
                    ),
108
                    QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Cancel,
109
                    QtWidgets.QMessageBox.Cancel,
110
                )
111
                if result == QtWidgets.QMessageBox.Cancel:
112
                    return
113

114
            gm = initialize_git()
115
            remote_name = ref["ref_name"]
116
            _, _, local_name = ref["ref_name"].rpartition("/")
117
            if ref["upstream"]:
118
                gm.checkout(self.item_model.path, remote_name)
119
            else:
120
                gm.checkout(self.item_model.path, remote_name, args=["-b", local_name])
121
            self.branch_changed.emit(local_name)
122

123

124
class ChangeBranchDialogModel(QtCore.QAbstractTableModel):
125

126
    branches = []
127
    DataSortRole = QtCore.Qt.UserRole
128
    RefAccessRole = QtCore.Qt.UserRole + 1
129

130
    def __init__(self, path: str, parent=None) -> None:
131
        super().__init__(parent)
132

133
        gm = initialize_git()
134
        self.path = path
135
        self.branches = gm.get_branches_with_info(path)
136
        self.current_branch = gm.current_branch(path)
137
        self.dirty = gm.dirty(path)
138
        self._remove_tracking_duplicates()
139

140
    def rowCount(self, parent: QtCore.QModelIndex = QtCore.QModelIndex()) -> int:
141
        if parent.isValid():
142
            return 0
143
        return len(self.branches)
144

145
    def columnCount(self, parent: QtCore.QModelIndex = QtCore.QModelIndex()) -> int:
146
        if parent.isValid():
147
            return 0
148
        return 3  # Local name, remote name, date
149

150
    def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.DisplayRole):
151
        if not index.isValid():
152
            return None
153
        row = index.row()
154
        column = index.column()
155
        if role == QtCore.Qt.ToolTipRole:
156
            tooltip = self.branches[row]["author"] + ": " + self.branches[row]["subject"]
157
            return tooltip
158
        elif role == QtCore.Qt.DisplayRole:
159
            dd = self.branches[row]
160
            if column == 2:
161
                if dd["date"] is not None:
162
                    q_date = QtCore.QDateTime.fromString(
163
                        dd["date"], QtCore.Qt.DateFormat.RFC2822Date
164
                    )
165
                    return QtCore.QLocale().toString(q_date, QtCore.QLocale.ShortFormat)
166
                return None
167
            elif column == 0:
168
                return dd["ref_name"]
169
            elif column == 1:
170
                return dd["upstream"]
171
            else:
172
                return None
173
        elif role == ChangeBranchDialogModel.DataSortRole:
174
            if column == 2:
175
                if self.branches[row]["date"] is not None:
176
                    q_date = QtCore.QDateTime.fromString(
177
                        self.branches[row]["date"], QtCore.Qt.DateFormat.RFC2822Date
178
                    )
179
                    return q_date
180
                return None
181
            elif column == 0:
182
                return self.branches[row]["ref_name"]
183
            elif column == 1:
184
                return self.branches[row]["upstream"]
185
            else:
186
                return None
187
        elif role == ChangeBranchDialogModel.RefAccessRole:
188
            return self.branches[row]
189

190
    def headerData(
191
        self,
192
        section: int,
193
        orientation: QtCore.Qt.Orientation,
194
        role: int = QtCore.Qt.DisplayRole,
195
    ):
196
        if orientation == QtCore.Qt.Vertical:
197
            return None
198
        if role != QtCore.Qt.DisplayRole:
199
            return None
200
        if section == 0:
201
            return translate(
202
                "AddonsInstaller",
203
                "Local",
204
                "Table header for local git ref name",
205
            )
206
        if section == 1:
207
            return translate(
208
                "AddonsInstaller",
209
                "Remote tracking",
210
                "Table header for git remote tracking branch name",
211
            )
212
        elif section == 2:
213
            return translate(
214
                "AddonsInstaller",
215
                "Last Updated",
216
                "Table header for git update date",
217
            )
218
        else:
219
            return None
220

221
    def _remove_tracking_duplicates(self):
222
        remote_tracking_branches = []
223
        branches_to_keep = []
224
        for branch in self.branches:
225
            if branch["upstream"]:
226
                remote_tracking_branches.append(branch["upstream"])
227
        for branch in self.branches:
228
            if (
229
                "HEAD" not in branch["ref_name"]
230
                and branch["ref_name"] not in remote_tracking_branches
231
            ):
232
                branches_to_keep.append(branch)
233
        self.branches = branches_to_keep
234

235

236
class ChangeBranchDialogFilter(QtCore.QSortFilterProxyModel):
237
    def lessThan(self, left: QtCore.QModelIndex, right: QtCore.QModelIndex):
238
        leftData = self.sourceModel().data(left, ChangeBranchDialogModel.DataSortRole)
239
        rightData = self.sourceModel().data(right, ChangeBranchDialogModel.DataSortRole)
240
        if leftData is None or rightData is None:
241
            if rightData is not None:
242
                return True
243
            else:
244
                return False
245
        return leftData < rightData
246

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.