doc: Add git-cola-1.3.7 release notes
[git-cola.git] / cola / qtutils.py
blob96b5412df8a4e1aeda096e032b9e9510ca48eb15
1 # Copyright (c) 2008 David Aguilar
2 """This module provides miscellaneous Qt utility functions.
3 """
4 import os
6 from PyQt4 import QtCore
7 from PyQt4 import QtGui
9 import cola
10 from cola import core
11 from cola import utils
12 from cola import signals
13 from cola import resources
14 import cola.views.log
16 _logger = None
17 def logger():
18 global _logger
19 if not _logger:
20 _logger = cola.views.log.LogView()
21 cola.notifier().listen(signals.log_cmd, _logger.log)
22 return _logger
25 def log(status, output):
26 """Sends messages to the log window.
27 """
28 if not output:
29 return
30 cola.notifier().broadcast(signals.log_cmd, status, output)
32 def SLOT(signal, *args, **opts):
33 """
34 Returns a callback that broadcasts a message over the notifier.
36 If the caller of SLOT() provides args or opts then those are
37 used instead of the ones provided by the invoker of the callback.
39 """
40 def broadcast(*local_args, **local_opts):
41 if args or opts:
42 cola.notifier().broadcast(signal, *args, **opts)
43 else:
44 cola.notifier().broadcast(signal, *local_args, **local_opts)
45 return broadcast
48 def prompt(msg, title=None):
49 """Presents the user with an input widget and returns the input."""
50 if title is None:
51 title = msg
52 msg = tr(msg)
53 title = tr(title)
54 parent = QtGui.QApplication.instance().activeWindow()
55 result = QtGui.QInputDialog.getText(parent, msg, title)
56 return (unicode(result[0]), result[1])
58 def create_listwidget_item(text, filename):
59 """Creates a QListWidgetItem with text and the icon at filename."""
60 item = QtGui.QListWidgetItem()
61 item.setIcon(QtGui.QIcon(filename))
62 item.setText(text)
63 return item
65 _tree_icon_cache = {}
66 def create_treewidget_item(text, filename):
67 """Creates a QTreeWidgetItem with text and the icon at filename."""
68 if filename not in _tree_icon_cache:
69 _tree_icon_cache[filename] = QtGui.QIcon(filename)
70 icon = _tree_icon_cache[filename]
71 item = QtGui.QTreeWidgetItem()
72 item.setIcon(0, icon)
73 item.setText(0, text)
74 return item
76 def information(title, message=None):
77 """Launches a QMessageBox information with the
78 provided title and message."""
79 if message is None:
80 message = title
81 title = tr(title)
82 message = tr(message)
83 parent = QtGui.QApplication.instance().activeWindow()
84 QtGui.QMessageBox.information(parent, title, message)
85 # Register globally with the notifier
86 cola.notifier().listen(signals.information, information)
88 def selected_treeitem(tree_widget):
89 """Returns a(id_number, is_selected) for a QTreeWidget."""
90 id_number = None
91 selected = False
92 item = tree_widget.currentItem()
93 if item:
94 id_number = item.data(0, QtCore.Qt.UserRole).toInt()[0]
95 selected = True
96 return(id_number, selected)
98 def selected_row(list_widget):
99 """Returns a(row_number, is_selected) tuple for a QListWidget."""
100 row = list_widget.currentRow()
101 item = list_widget.item(row)
102 selected = item is not None and item.isSelected()
103 return(row, selected)
105 def selection_list(listwidget, items):
106 """Returns an array of model items that correspond to
107 the selected QListWidget indices."""
108 selected = []
109 itemcount = listwidget.count()
110 widgetitems = [ listwidget.item(idx) for idx in range(itemcount) ]
112 for item, widgetitem in zip(items, widgetitems):
113 if widgetitem.isSelected():
114 selected.append(item)
115 return selected
117 def tree_selection(treeitem, items):
118 """Returns model items that correspond to selected widget indices"""
119 itemcount = treeitem.childCount()
120 widgetitems = [ treeitem.child(idx) for idx in range(itemcount) ]
121 selected = []
122 for item, widgetitem in zip(items[:len(widgetitems)], widgetitems):
123 if widgetitem.isSelected():
124 selected.append(item)
126 return selected
128 def selected_item(list_widget, items):
129 """Returns the selected item in a QListWidget."""
130 row, selected = selected_row(list_widget)
131 if selected and row < len(items):
132 return items[row]
133 else:
134 return None
136 def open_dialog(parent, title, filename=None):
137 """Creates an Open File dialog and returns a filename."""
138 title_tr = tr(title)
139 return unicode(QtGui.QFileDialog
140 .getOpenFileName(parent, title_tr, filename))
142 def opendir_dialog(parent, title, path):
143 """Prompts for a directory path"""
145 flags = (QtGui.QFileDialog.ShowDirsOnly |
146 QtGui.QFileDialog.DontResolveSymlinks)
147 title_tr = tr(title)
148 qstr = (QtGui.QFileDialog
149 .getExistingDirectory(parent, title_tr, path, flags))
150 return unicode(qstr)
153 def save_dialog(parent, title, filename=''):
154 """Creates a Save File dialog and returns a filename."""
155 title_tr = parent.tr(title)
156 return unicode(QtGui.QFileDialog
157 .getSaveFileName(parent, title_tr, filename))
159 def icon(basename):
160 """Given a basename returns a QIcon from the corresponding cola icon."""
161 return QtGui.QIcon(resources.icon(basename))
163 def question(parent, title, message, default=True):
164 """Launches a QMessageBox question with the provided title and message.
165 Passing "default=False" will make "No" the default choice."""
166 yes = QtGui.QMessageBox.Yes
167 no = QtGui.QMessageBox.No
168 buttons = yes | no
169 if default:
170 default = yes
171 else:
172 default = no
173 title = tr(title)
174 message = tr(message)
175 result = QtGui.QMessageBox.question(parent, title, message,
176 buttons, default)
177 return result == QtGui.QMessageBox.Yes
179 def set_clipboard(text):
180 """Sets the copy/paste buffer to text."""
181 if not text:
182 return
183 clipboard = QtGui.QApplication.instance().clipboard()
184 clipboard.setText(text, QtGui.QClipboard.Clipboard)
185 clipboard.setText(text, QtGui.QClipboard.Selection)
187 def set_selected_item(widget, idx):
188 """Sets a the currently selected item to the item at index idx."""
189 if type(widget) is QtGui.QTreeWidget:
190 item = widget.topLevelItem(idx)
191 if item:
192 widget.setItemSelected(item, True)
193 widget.setCurrentItem(item)
195 def add_items(widget, items):
196 """Adds items to a widget."""
197 for item in items:
198 widget.addItem(item)
200 def set_items(widget, items):
201 """Clear the existing widget contents and set the new items."""
202 widget.clear()
203 add_items(widget, items)
205 def tr(txt):
206 """Translate a string into a local language."""
207 return unicode(QtGui.QApplication.instance().translate('', txt))
209 def icon_file(filename, staged=False, untracked=False):
210 """Returns a file path representing a corresponding file path."""
211 if staged:
212 if os.path.exists(core.encode(filename)):
213 ifile = resources.icon('staged.png')
214 else:
215 ifile = resources.icon('removed.png')
216 elif untracked:
217 ifile = resources.icon('untracked.png')
218 else:
219 ifile = utils.file_icon(filename)
220 return ifile
222 def icon_for_file(filename, staged=False, untracked=False):
223 """Returns a QIcon for a particular file path."""
224 ifile = icon_file(filename, staged=staged, untracked=untracked)
225 return icon(ifile)
227 def create_treeitem(filename, staged=False, untracked=False, check=True):
228 """Given a filename, return a QListWidgetItem suitable
229 for adding to a QListWidget. "staged" and "untracked"
230 controls whether to use the appropriate icons."""
231 if check:
232 ifile = icon_file(filename, staged=staged, untracked=untracked)
233 else:
234 ifile = resources.icon('staged.png')
235 return create_treewidget_item(filename, ifile)
238 def update_file_icons(widget, items, staged=True,
239 untracked=False, offset=0):
240 """Populate a QListWidget with custom icon items."""
241 for idx, model_item in enumerate(items):
242 item = widget.item(idx+offset)
243 if item:
244 item.setIcon(icon_for_file(model_item, staged, untracked))
246 def set_listwidget_strings(widget, items):
247 """Sets a list widget to the strings passed in items."""
248 widget.clear()
249 add_items(widget, [ QtGui.QListWidgetItem(i) for i in items ])
251 _icon_cache = {}
252 def cached_icon(key):
253 """Maintain a cache of standard icons and return cache entries."""
254 if key not in _icon_cache:
255 style = QtGui.QApplication.instance().style()
256 _icon_cache[key] = style.standardIcon(key)
257 return _icon_cache[key]
259 def dir_icon():
260 """Return a standard icon for a directory."""
261 return cached_icon(QtGui.QStyle.SP_DirIcon)
263 def file_icon():
264 """Return a standard icon for a file."""
265 return cached_icon(QtGui.QStyle.SP_FileIcon)
267 def diff_font():
268 """Return the diff font string."""
269 qfont = QtGui.QFont()
270 font = cola.model().cola_config('fontdiff')
271 if font and qfont.fromString(font):
272 return qfont
273 family = 'Monospace'
274 if cola.utils.is_darwin():
275 family = 'Monaco'
276 qfont.setFamily(family)
277 font = unicode(qfont.toString())
278 # TODO this might not be the best place for the default
279 cola.model().set_diff_font(font)
280 return qfont
282 def set_diff_font(widget):
283 """Updates the diff font based on the configured value."""
284 qfont = diff_font()
285 block = widget.signalsBlocked()
286 widget.blockSignals(True)
287 if isinstance(widget, QtGui.QFontComboBox):
288 widget.setCurrentFont(qfont)
289 else:
290 widget.setFont(qfont)
291 widget.blockSignals(block)