status: use Italics instead of Bold-with-background for headers
[git-cola.git] / cola / widgets / archive.py
blob0ff2dfa5edac7eb3992f2930240df77703e8ec79
1 from __future__ import division, absolute_import, unicode_literals
3 import os
5 from PyQt4 import QtCore
6 from PyQt4 import QtGui
7 from PyQt4.QtCore import Qt
8 from PyQt4.QtCore import SIGNAL
10 from cola import cmds
11 from cola import core
12 from cola import icons
13 from cola import qtutils
14 from cola.git import git
15 from cola.git import STDOUT
16 from cola.i18n import N_
17 from cola.widgets import defs
18 from cola.compat import ustr
21 class ExpandableGroupBox(QtGui.QGroupBox):
23 def __init__(self, parent=None):
24 QtGui.QGroupBox.__init__(self, parent)
25 self.setFlat(True)
26 self.expanded = True
27 self.click_pos = None
28 self.arrow_icon_size = defs.small_icon
30 def set_expanded(self, expanded):
31 if expanded == self.expanded:
32 self.emit(SIGNAL('expanded(bool)'), expanded)
33 return
34 self.expanded = expanded
35 for widget in self.findChildren(QtGui.QWidget):
36 widget.setHidden(not expanded)
37 self.emit(SIGNAL('expanded(bool)'), expanded)
39 def mousePressEvent(self, event):
40 if event.button() == Qt.LeftButton:
41 option = QtGui.QStyleOptionGroupBox()
42 self.initStyleOption(option)
43 icon_size = defs.small_icon
44 button_area = QtCore.QRect(0, 0, icon_size, icon_size)
45 offset = icon_size + defs.spacing
46 adjusted = option.rect.adjusted(0, 0, -offset, 0)
47 top_left = adjusted.topLeft()
48 button_area.moveTopLeft(QtCore.QPoint(top_left))
49 self.click_pos = event.pos()
50 QtGui.QGroupBox.mousePressEvent(self, event)
52 def mouseReleaseEvent(self, event):
53 if (event.button() == Qt.LeftButton and
54 self.click_pos == event.pos()):
55 self.set_expanded(not self.expanded)
56 QtGui.QGroupBox.mouseReleaseEvent(self, event)
58 def paintEvent(self, event):
59 painter = QtGui.QStylePainter(self)
60 option = QtGui.QStyleOptionGroupBox()
61 self.initStyleOption(option)
62 painter.save()
63 painter.translate(self.arrow_icon_size + defs.spacing, 0)
64 painter.drawText(option.rect, Qt.AlignLeft, self.title())
65 painter.restore()
67 style = QtGui.QStyle
68 point = option.rect.adjusted(0, -4, 0, 0).topLeft()
69 icon_size = self.arrow_icon_size
70 option.rect = QtCore.QRect(point.x(), point.y(), icon_size, icon_size)
71 if self.expanded:
72 painter.drawPrimitive(style.PE_IndicatorArrowDown, option)
73 else:
74 painter.drawPrimitive(style.PE_IndicatorArrowRight, option)
78 class GitArchiveDialog(QtGui.QDialog):
80 @staticmethod
81 def save_hashed_objects(ref, shortref, parent=None):
82 dlg = GitArchiveDialog(ref, shortref, parent)
83 if dlg.exec_() != dlg.Accepted:
84 return None
85 return dlg
87 def __init__(self, ref, shortref=None, parent=None):
88 QtGui.QDialog.__init__(self, parent)
89 if parent is not None:
90 self.setWindowModality(Qt.WindowModal)
92 # input
93 self.ref = ref
94 if shortref is None:
95 shortref = ref
97 # outputs
98 self.fmt = None
100 filename = '%s-%s' % (os.path.basename(core.getcwd()), shortref)
101 self.prefix = filename + '/'
102 self.filename = filename
104 # widgets
105 self.setWindowTitle(N_('Save Archive'))
107 self.filetext = QtGui.QLineEdit()
108 self.filetext.setText(self.filename)
110 self.browse = qtutils.create_toolbutton(icon=icons.file_zip())
112 self.format_strings = (
113 git.archive('--list')[STDOUT].rstrip().splitlines())
114 self.format_combo = QtGui.QComboBox()
115 self.format_combo.setEditable(False)
116 self.format_combo.addItems(self.format_strings)
118 self.close_button = qtutils.close_button()
119 self.save_button = qtutils.create_button(text=N_('Save'),
120 icon=icons.save(),
121 default=True)
122 self.prefix_label = QtGui.QLabel()
123 self.prefix_label.setText(N_('Prefix'))
124 self.prefix_text = QtGui.QLineEdit()
125 self.prefix_text.setText(self.prefix)
127 self.prefix_group = ExpandableGroupBox()
128 self.prefix_group.setTitle(N_('Advanced'))
130 # layouts
131 self.filelayt = qtutils.hbox(defs.no_margin, defs.spacing,
132 self.browse, self.filetext,
133 self.format_combo)
135 self.prefixlayt = qtutils.hbox(defs.margin, defs.spacing,
136 self.prefix_label, self.prefix_text)
137 self.prefix_group.setLayout(self.prefixlayt)
138 self.prefix_group.set_expanded(False)
140 self.btnlayt = qtutils.hbox(defs.no_margin, defs.spacing,
141 qtutils.STRETCH, self.close_button,
142 self.save_button)
144 self.mainlayt = qtutils.vbox(defs.margin, defs.no_spacing,
145 self.filelayt, self.prefix_group,
146 qtutils.STRETCH, self.btnlayt)
147 self.setLayout(self.mainlayt)
148 self.resize(defs.scale(520), defs.scale(10))
150 # initial setup; done before connecting to avoid
151 # signal/slot side-effects
152 if 'tar.gz' in self.format_strings:
153 idx = self.format_strings.index('tar.gz')
154 elif 'zip' in self.format_strings:
155 idx = self.format_strings.index('zip')
156 else:
157 idx = 0
158 self.format_combo.setCurrentIndex(idx)
159 self.update_filetext_for_format(idx)
161 # connections
162 self.connect(self.filetext, SIGNAL('textChanged(QString)'),
163 self.filetext_changed)
165 self.connect(self.prefix_text, SIGNAL('textChanged(QString)'),
166 self.prefix_text_changed)
168 self.connect(self.format_combo, SIGNAL('currentIndexChanged(int)'),
169 self.update_filetext_for_format)
171 self.connect(self.prefix_group, SIGNAL('expanded(bool)'),
172 self.prefix_group_expanded)
174 self.connect(self, SIGNAL('accepted()'), self.archive_saved)
176 qtutils.connect_button(self.browse, self.choose_filename)
177 qtutils.connect_button(self.close_button, self.reject)
178 qtutils.connect_button(self.save_button, self.save_archive)
180 def archive_saved(self):
181 cmds.do(cmds.Archive, self.ref, self.fmt, self.prefix, self.filename)
182 qtutils.information(N_('File Saved'),
183 N_('File saved to "%s"') % self.filename)
185 def save_archive(self):
186 filename = self.filename
187 if not filename:
188 return
189 if core.exists(filename):
190 title = N_('Overwrite File?')
191 msg = N_('The file "%s" exists and will be overwritten.') % filename
192 info_txt = N_('Overwrite "%s"?') % filename
193 ok_txt = N_('Overwrite')
194 if not qtutils.confirm(title, msg, info_txt, ok_txt,
195 default=False, icon=icons.save()):
196 return
197 self.accept()
199 def choose_filename(self):
200 filename = qtutils.save_as(self.filename)
201 if not filename:
202 return
203 self.filetext.setText(filename)
204 self.update_filetext_for_format(self.format_combo.currentIndex())
206 def filetext_changed(self, qstr):
207 self.filename = ustr(qstr)
208 self.save.setEnabled(bool(self.filename))
209 prefix = self.strip_exts(os.path.basename(self.filename)) + '/'
210 self.prefix_text.setText(prefix)
212 def prefix_text_changed(self, qstr):
213 self.prefix = ustr(qstr)
215 def strip_exts(self, text):
216 for format_string in self.format_strings:
217 ext = '.'+format_string
218 if text.endswith(ext):
219 return text[:-len(ext)]
220 return text
222 def update_filetext_for_format(self, idx):
223 self.fmt = self.format_strings[idx]
224 text = self.strip_exts(ustr(self.filetext.text()))
225 self.filename = '%s.%s' % (text, self.fmt)
226 self.filetext.setText(self.filename)
227 self.filetext.setFocus()
228 if '/' in text:
229 start = text.rindex('/') + 1
230 else:
231 start = 0
232 self.filetext.setSelection(start, len(text) - start)
234 def prefix_group_expanded(self, expanded):
235 if expanded:
236 self.prefix_text.setFocus()
237 else:
238 self.filetext.setFocus()