1 # Copyright (c) 2008 David Aguilar
2 """This module provides miscellaneous Qt utility functions.
6 from PyQt4
import QtGui
7 from PyQt4
import QtCore
8 from PyQt4
.QtCore
import SIGNAL
12 from cola
import utils
13 from cola
import signals
14 from cola
import resources
15 from cola
.decorators
import memoize
21 logview
= cola
.views
.log
.LogView()
22 cola
.notifier().connect(signals
.log_cmd
, logview
.log
)
26 def log(status
, output
):
27 """Sends messages to the log window.
31 cola
.notifier().broadcast(signals
.log_cmd
, status
, output
)
34 def SLOT(signal
, *args
, **opts
):
36 Returns a callback that broadcasts a message over the notifier.
38 If the caller of SLOT() provides args or opts then those are
39 used instead of the ones provided by the invoker of the callback.
42 def broadcast(*local_args
, **local_opts
):
44 cola
.notifier().broadcast(signal
, *args
, **opts
)
46 cola
.notifier().broadcast(signal
, *local_args
, **local_opts
)
50 def prompt(msg
, title
=None):
51 """Presents the user with an input widget and returns the input."""
56 parent
= QtGui
.QApplication
.instance().activeWindow()
57 result
= QtGui
.QInputDialog
.getText(parent
, msg
, title
)
58 return (unicode(result
[0]), result
[1])
61 def create_listwidget_item(text
, filename
):
62 """Creates a QListWidgetItem with text and the icon at filename."""
63 item
= QtGui
.QListWidgetItem()
64 item
.setIcon(QtGui
.QIcon(filename
))
69 def create_treewidget_item(text
, filename
):
70 """Creates a QTreeWidgetItem with text and the icon at filename."""
71 icon
= cached_icon_from_path(filename
)
72 item
= QtGui
.QTreeWidgetItem()
79 def cached_icon_from_path(filename
):
80 return QtGui
.QIcon(filename
)
83 def information(title
, message
=None):
84 """Launches a QMessageBox information with the
85 provided title and message."""
90 parent
= QtGui
.QApplication
.instance().activeWindow()
91 QtGui
.QMessageBox
.information(parent
, title
, message
)
93 # Register globally with the notifier
94 cola
.notifier().connect(signals
.information
, information
)
97 def selected_treeitem(tree_widget
):
98 """Returns a(id_number, is_selected) for a QTreeWidget."""
101 item
= tree_widget
.currentItem()
103 id_number
= item
.data(0, QtCore
.Qt
.UserRole
).toInt()[0]
105 return(id_number
, selected
)
107 def selected_row(list_widget
):
108 """Returns a(row_number, is_selected) tuple for a QListWidget."""
109 row
= list_widget
.currentRow()
110 item
= list_widget
.item(row
)
111 selected
= item
is not None and item
.isSelected()
112 return(row
, selected
)
114 def selection_list(listwidget
, items
):
115 """Returns an array of model items that correspond to
116 the selected QListWidget indices."""
118 itemcount
= listwidget
.count()
119 widgetitems
= [ listwidget
.item(idx
) for idx
in range(itemcount
) ]
121 for item
, widgetitem
in zip(items
, widgetitems
):
122 if widgetitem
.isSelected():
123 selected
.append(item
)
127 def tree_selection(treeitem
, items
):
128 """Returns model items that correspond to selected widget indices"""
129 itemcount
= treeitem
.childCount()
130 widgetitems
= [ treeitem
.child(idx
) for idx
in range(itemcount
) ]
132 for item
, widgetitem
in zip(items
[:len(widgetitems
)], widgetitems
):
133 if widgetitem
.isSelected():
134 selected
.append(item
)
139 def selected_item(list_widget
, items
):
140 """Returns the selected item in a QListWidget."""
141 row
, selected
= selected_row(list_widget
)
142 if selected
and row
< len(items
):
148 def open_dialog(parent
, title
, filename
=None):
149 """Creates an Open File dialog and returns a filename."""
151 return unicode(QtGui
.QFileDialog
152 .getOpenFileName(parent
, title_tr
, filename
))
155 def opendir_dialog(parent
, title
, path
):
156 """Prompts for a directory path"""
158 flags
= (QtGui
.QFileDialog
.ShowDirsOnly |
159 QtGui
.QFileDialog
.DontResolveSymlinks
)
161 qstr
= (QtGui
.QFileDialog
162 .getExistingDirectory(parent
, title_tr
, path
, flags
))
166 def save_dialog(parent
, title
, filename
=''):
167 """Creates a Save File dialog and returns a filename."""
168 title_tr
= parent
.tr(title
)
169 return unicode(QtGui
.QFileDialog
170 .getSaveFileName(parent
, title_tr
, filename
))
174 """Given a basename returns a QIcon from the corresponding cola icon."""
175 return QtGui
.QIcon(resources
.icon(basename
))
178 def question(parent
, title
, message
, default
=True):
179 """Launches a QMessageBox question with the provided title and message.
180 Passing "default=False" will make "No" the default choice."""
181 yes
= QtGui
.QMessageBox
.Yes
182 no
= QtGui
.QMessageBox
.No
189 message
= tr(message
)
190 result
= QtGui
.QMessageBox
.question(parent
, title
, message
,
192 return result
== QtGui
.QMessageBox
.Yes
195 def set_clipboard(text
):
196 """Sets the copy/paste buffer to text."""
199 clipboard
= QtGui
.QApplication
.instance().clipboard()
200 clipboard
.setText(text
, QtGui
.QClipboard
.Clipboard
)
201 clipboard
.setText(text
, QtGui
.QClipboard
.Selection
)
204 def set_selected_item(widget
, idx
):
205 """Sets a the currently selected item to the item at index idx."""
206 if type(widget
) is QtGui
.QTreeWidget
:
207 item
= widget
.topLevelItem(idx
)
209 widget
.setItemSelected(item
, True)
210 widget
.setCurrentItem(item
)
213 def add_items(widget
, items
):
214 """Adds items to a widget."""
219 def set_items(widget
, items
):
220 """Clear the existing widget contents and set the new items."""
222 add_items(widget
, items
)
227 """Translate a string into a local language."""
228 if type(txt
) is QtCore
.QString
:
229 # This has already been translated; leave as-is
231 return unicode(QtGui
.QApplication
.instance().translate('', txt
))
234 def icon_file(filename
, staged
=False, untracked
=False):
235 """Returns a file path representing a corresponding file path."""
237 if os
.path
.exists(core
.encode(filename
)):
238 ifile
= resources
.icon('staged.png')
240 ifile
= resources
.icon('removed.png')
242 ifile
= resources
.icon('untracked.png')
244 ifile
= utils
.file_icon(filename
)
248 def icon_for_file(filename
, staged
=False, untracked
=False):
249 """Returns a QIcon for a particular file path."""
250 ifile
= icon_file(filename
, staged
=staged
, untracked
=untracked
)
254 def create_treeitem(filename
, staged
=False, untracked
=False, check
=True):
255 """Given a filename, return a QListWidgetItem suitable
256 for adding to a QListWidget. "staged" and "untracked"
257 controls whether to use the appropriate icons."""
259 ifile
= icon_file(filename
, staged
=staged
, untracked
=untracked
)
261 ifile
= resources
.icon('staged.png')
262 return create_treewidget_item(filename
, ifile
)
265 def update_file_icons(widget
, items
, staged
=True,
266 untracked
=False, offset
=0):
267 """Populate a QListWidget with custom icon items."""
268 for idx
, model_item
in enumerate(items
):
269 item
= widget
.item(idx
+offset
)
271 item
.setIcon(icon_for_file(model_item
, staged
, untracked
))
273 def set_listwidget_strings(widget
, items
):
274 """Sets a list widget to the strings passed in items."""
276 add_items(widget
, [ QtGui
.QListWidgetItem(i
) for i
in items
])
279 def cached_icon(key
):
280 """Maintain a cache of standard icons and return cache entries."""
281 style
= QtGui
.QApplication
.instance().style()
282 return style
.standardIcon(key
)
286 """Return a standard icon for a directory."""
287 return cached_icon(QtGui
.QStyle
.SP_DirIcon
)
291 """Return a standard icon for a file."""
292 return cached_icon(QtGui
.QStyle
.SP_FileIcon
)
296 """Return the diff font string."""
297 qfont
= QtGui
.QFont()
298 font
= cola
.model().cola_config('fontdiff')
299 if font
and qfont
.fromString(font
):
302 if cola
.utils
.is_darwin():
304 qfont
.setFamily(family
)
305 font
= unicode(qfont
.toString())
306 # TODO this might not be the best place for the default
307 cola
.model().set_diff_font(font
)
311 def set_diff_font(widget
):
312 """Updates the diff font based on the configured value."""
314 block
= widget
.signalsBlocked()
315 widget
.blockSignals(True)
316 if isinstance(widget
, QtGui
.QFontComboBox
):
317 widget
.setCurrentFont(qfont
)
319 widget
.setFont(qfont
)
320 widget
.blockSignals(block
)
323 def add_close_action(widget
):
324 """Adds a Ctrl+w close action to a widget."""
325 action
= QtGui
.QAction(widget
.tr('Close...'), widget
)
326 action
.setShortcut('Ctrl+w')
327 widget
.addAction(action
)
328 widget
.connect(action
, SIGNAL('triggered()'), widget
.close
)
331 def center_on_screen(widget
):
332 """Move widget to the center of the default screen"""
333 desktop
= QtGui
.QApplication
.instance().desktop()
334 rect
= desktop
.screenGeometry(QtGui
.QCursor().pos())
337 widget
.move(cx
- widget
.width()/2, cy
- widget
.height()/2)