File: archive.py

package info (click to toggle)
git-cola 4.16.0-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 6,844 kB
  • sloc: python: 37,972; sh: 298; makefile: 223; xml: 106; tcl: 62
file content (253 lines) | stat: -rw-r--r-- 8,366 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
"""Git Archive dialog"""
import os

from qtpy import QtCore
from qtpy import QtWidgets
from qtpy.QtCore import Qt
from qtpy.QtCore import Signal

from ..git import STDOUT
from ..i18n import N_
from ..interaction import Interaction
from .. import cmds
from .. import core
from .. import icons
from .. import qtutils
from .text import LineEdit
from .standard import Dialog
from . import defs


class ExpandableGroupBox(QtWidgets.QGroupBox):
    expanded = Signal(bool)

    def __init__(self, parent=None):
        QtWidgets.QGroupBox.__init__(self, parent)
        self.setFlat(True)
        self.is_expanded = True
        self.click_pos = None
        self.arrow_icon_size = defs.small_icon

    def set_expanded(self, expanded):
        if expanded == self.is_expanded:
            self.expanded.emit(expanded)
            return
        self.is_expanded = expanded
        for widget in self.findChildren(QtWidgets.QWidget):
            widget.setHidden(not expanded)
        self.expanded.emit(expanded)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            option = QtWidgets.QStyleOptionGroupBox()
            self.initStyleOption(option)
            icon_size = defs.small_icon
            button_area = QtCore.QRect(0, 0, icon_size, icon_size)
            offset = icon_size + defs.spacing
            adjusted = option.rect.adjusted(0, 0, -offset, 0)
            top_left = adjusted.topLeft()
            button_area.moveTopLeft(QtCore.QPoint(top_left))
            self.click_pos = event.pos()
        QtWidgets.QGroupBox.mousePressEvent(self, event)

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton and self.click_pos == event.pos():
            self.set_expanded(not self.is_expanded)
        QtWidgets.QGroupBox.mouseReleaseEvent(self, event)

    def paintEvent(self, _event):
        painter = QtWidgets.QStylePainter(self)
        option = QtWidgets.QStyleOptionGroupBox()
        self.initStyleOption(option)
        painter.save()
        painter.translate(self.arrow_icon_size + defs.spacing, 0)
        painter.drawText(option.rect, Qt.AlignLeft, self.title())
        painter.restore()

        style = QtWidgets.QStyle
        point = option.rect.adjusted(0, -4, 0, 0).topLeft()
        icon_size = self.arrow_icon_size
        option.rect = QtCore.QRect(point.x(), point.y(), icon_size, icon_size)
        if self.is_expanded:
            painter.drawPrimitive(style.PE_IndicatorArrowDown, option)
        else:
            painter.drawPrimitive(style.PE_IndicatorArrowRight, option)


def save_archive(context):
    oid = context.git.rev_parse('HEAD')[STDOUT]
    show_save_dialog(context, oid, parent=qtutils.active_window())


def show_save_dialog(context, oid, parent=None):
    shortoid = oid[:7]
    dlg = Archive(context, oid, shortoid, parent=parent)
    dlg.show()
    if dlg.exec_() != dlg.Accepted:
        return None
    return dlg


class Archive(Dialog):
    def __init__(self, context, ref, shortref=None, parent=None):
        Dialog.__init__(self, parent=parent)
        self.context = context
        if parent is not None:
            self.setWindowModality(Qt.WindowModal)

        # input
        self.ref = ref
        if shortref is None:
            shortref = ref

        # outputs
        self.fmt = None

        filename = f'{os.path.basename(core.getcwd())}-{shortref}'
        self.prefix = filename + '/'
        self.filename = filename

        # widgets
        self.setWindowTitle(N_('Save Archive'))

        self.filetext = LineEdit()
        self.filetext.set_value(self.filename)

        self.browse = qtutils.create_toolbutton(icon=icons.file_zip())

        stdout = context.git.archive('--list')[STDOUT]
        self.format_strings = stdout.rstrip().splitlines()
        self.format_combo = qtutils.combo(self.format_strings)

        self.close_button = qtutils.close_button()
        self.save_button = qtutils.create_button(
            text=N_('Save'), icon=icons.save(), default=True
        )
        self.prefix_label = QtWidgets.QLabel()
        self.prefix_label.setText(N_('Prefix'))
        self.prefix_text = LineEdit()
        self.prefix_text.set_value(self.prefix)

        self.prefix_group = ExpandableGroupBox()
        self.prefix_group.setTitle(N_('Advanced'))

        # layouts
        self.filelayt = qtutils.hbox(
            defs.no_margin, defs.spacing, self.browse, self.filetext, self.format_combo
        )

        self.prefixlayt = qtutils.hbox(
            defs.margin, defs.spacing, self.prefix_label, self.prefix_text
        )
        self.prefix_group.setLayout(self.prefixlayt)
        self.prefix_group.set_expanded(False)

        self.btnlayt = qtutils.hbox(
            defs.no_margin,
            defs.spacing,
            qtutils.STRETCH,
            self.close_button,
            self.save_button,
        )

        self.mainlayt = qtutils.vbox(
            defs.margin,
            defs.no_spacing,
            self.filelayt,
            self.prefix_group,
            qtutils.STRETCH,
            self.btnlayt,
        )
        self.setLayout(self.mainlayt)

        # initial setup; done before connecting to avoid
        # signal/slot side-effects
        if 'tar.gz' in self.format_strings:
            idx = self.format_strings.index('tar.gz')
        elif 'zip' in self.format_strings:
            idx = self.format_strings.index('zip')
        else:
            idx = 0
        self.format_combo.setCurrentIndex(idx)
        self.update_format(idx)

        # connections
        self.filetext.textChanged.connect(self.filetext_changed)
        self.prefix_text.textChanged.connect(self.prefix_text_changed)
        self.format_combo.currentIndexChanged.connect(self.update_format)
        self.prefix_group.expanded.connect(self.prefix_group_expanded)
        self.accepted.connect(self.archive_saved)

        qtutils.connect_button(self.browse, self.choose_filename)
        qtutils.connect_button(self.close_button, self.reject)
        qtutils.connect_button(self.save_button, self.save_archive)

        self.init_size(parent=parent)

    def archive_saved(self):
        context = self.context
        ref = self.ref
        fmt = self.fmt
        prefix = self.prefix
        filename = self.filename

        cmds.do(cmds.Archive, context, ref, fmt, prefix, filename)
        Interaction.information(
            N_('File Saved'), N_('File saved to "%s"') % self.filename
        )

    def save_archive(self):
        filename = self.filename
        if not filename:
            return
        if core.exists(filename):
            title = N_('Overwrite File?')
            msg = N_('The file "%s" exists and will be overwritten.') % filename
            info_txt = N_('Overwrite "%s"?') % filename
            ok_txt = N_('Overwrite')
            if not Interaction.confirm(
                title, msg, info_txt, ok_txt, default=False, icon=icons.save()
            ):
                return
        self.accept()

    def choose_filename(self):
        filename = qtutils.save_as(self.filename)
        if not filename:
            return
        self.filetext.setText(filename)
        self.update_format(self.format_combo.currentIndex())

    def filetext_changed(self, filename):
        self.filename = filename
        self.save_button.setEnabled(bool(self.filename))
        prefix = self.strip_exts(os.path.basename(self.filename)) + '/'
        self.prefix_text.setText(prefix)

    def prefix_text_changed(self, prefix):
        self.prefix = prefix

    def strip_exts(self, text):
        for format_string in self.format_strings:
            ext = '.' + format_string
            if text.endswith(ext):
                return text[: -len(ext)]
        return text

    def update_format(self, idx):
        self.fmt = self.format_strings[idx]
        text = self.strip_exts(self.filetext.text())
        self.filename = f'{text}.{self.fmt}'
        self.filetext.setText(self.filename)
        self.filetext.setFocus()
        if '/' in text:
            start = text.rindex('/') + 1
        else:
            start = 0
        self.filetext.setSelection(start, len(text) - start)

    def prefix_group_expanded(self, expanded):
        if expanded:
            self.prefix_text.setFocus()
        else:
            self.filetext.setFocus()