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
21 _logger
= cola
.views
.log
.LogView()
22 cola
.notifier().connect(signals
.log_cmd
, _logger
.log
)
26 def log(status
, output
):
27 """Sends messages to the log window.
31 cola
.notifier().broadcast(signals
.log_cmd
, status
, output
)
33 def SLOT(signal
, *args
, **opts
):
35 Returns a callback that broadcasts a message over the notifier.
37 If the caller of SLOT() provides args or opts then those are
38 used instead of the ones provided by the invoker of the callback.
41 def broadcast(*local_args
, **local_opts
):
43 cola
.notifier().broadcast(signal
, *args
, **opts
)
45 cola
.notifier().broadcast(signal
, *local_args
, **local_opts
)
49 def prompt(msg
, title
=None):
50 """Presents the user with an input widget and returns the input."""
55 parent
= QtGui
.QApplication
.instance().activeWindow()
56 result
= QtGui
.QInputDialog
.getText(parent
, msg
, title
)
57 return (unicode(result
[0]), result
[1])
59 def create_listwidget_item(text
, filename
):
60 """Creates a QListWidgetItem with text and the icon at filename."""
61 item
= QtGui
.QListWidgetItem()
62 item
.setIcon(QtGui
.QIcon(filename
))
67 def create_treewidget_item(text
, filename
):
68 """Creates a QTreeWidgetItem with text and the icon at filename."""
69 if filename
not in _tree_icon_cache
:
70 _tree_icon_cache
[filename
] = QtGui
.QIcon(filename
)
71 icon
= _tree_icon_cache
[filename
]
72 item
= QtGui
.QTreeWidgetItem()
77 def information(title
, message
=None):
78 """Launches a QMessageBox information with the
79 provided title and message."""
84 parent
= QtGui
.QApplication
.instance().activeWindow()
85 QtGui
.QMessageBox
.information(parent
, title
, message
)
86 # Register globally with the notifier
87 cola
.notifier().connect(signals
.information
, information
)
89 def selected_treeitem(tree_widget
):
90 """Returns a(id_number, is_selected) for a QTreeWidget."""
93 item
= tree_widget
.currentItem()
95 id_number
= item
.data(0, QtCore
.Qt
.UserRole
).toInt()[0]
97 return(id_number
, selected
)
99 def selected_row(list_widget
):
100 """Returns a(row_number, is_selected) tuple for a QListWidget."""
101 row
= list_widget
.currentRow()
102 item
= list_widget
.item(row
)
103 selected
= item
is not None and item
.isSelected()
104 return(row
, selected
)
106 def selection_list(listwidget
, items
):
107 """Returns an array of model items that correspond to
108 the selected QListWidget indices."""
110 itemcount
= listwidget
.count()
111 widgetitems
= [ listwidget
.item(idx
) for idx
in range(itemcount
) ]
113 for item
, widgetitem
in zip(items
, widgetitems
):
114 if widgetitem
.isSelected():
115 selected
.append(item
)
118 def tree_selection(treeitem
, items
):
119 """Returns model items that correspond to selected widget indices"""
120 itemcount
= treeitem
.childCount()
121 widgetitems
= [ treeitem
.child(idx
) for idx
in range(itemcount
) ]
123 for item
, widgetitem
in zip(items
[:len(widgetitems
)], widgetitems
):
124 if widgetitem
.isSelected():
125 selected
.append(item
)
129 def selected_item(list_widget
, items
):
130 """Returns the selected item in a QListWidget."""
131 row
, selected
= selected_row(list_widget
)
132 if selected
and row
< len(items
):
137 def open_dialog(parent
, title
, filename
=None):
138 """Creates an Open File dialog and returns a filename."""
140 return unicode(QtGui
.QFileDialog
141 .getOpenFileName(parent
, title_tr
, filename
))
143 def opendir_dialog(parent
, title
, path
):
144 """Prompts for a directory path"""
146 flags
= (QtGui
.QFileDialog
.ShowDirsOnly |
147 QtGui
.QFileDialog
.DontResolveSymlinks
)
149 qstr
= (QtGui
.QFileDialog
150 .getExistingDirectory(parent
, title_tr
, path
, flags
))
154 def save_dialog(parent
, title
, filename
=''):
155 """Creates a Save File dialog and returns a filename."""
156 title_tr
= parent
.tr(title
)
157 return unicode(QtGui
.QFileDialog
158 .getSaveFileName(parent
, title_tr
, filename
))
161 """Given a basename returns a QIcon from the corresponding cola icon."""
162 return QtGui
.QIcon(resources
.icon(basename
))
164 def question(parent
, title
, message
, default
=True):
165 """Launches a QMessageBox question with the provided title and message.
166 Passing "default=False" will make "No" the default choice."""
167 yes
= QtGui
.QMessageBox
.Yes
168 no
= QtGui
.QMessageBox
.No
175 message
= tr(message
)
176 result
= QtGui
.QMessageBox
.question(parent
, title
, message
,
178 return result
== QtGui
.QMessageBox
.Yes
180 def set_clipboard(text
):
181 """Sets the copy/paste buffer to text."""
184 clipboard
= QtGui
.QApplication
.instance().clipboard()
185 clipboard
.setText(text
, QtGui
.QClipboard
.Clipboard
)
186 clipboard
.setText(text
, QtGui
.QClipboard
.Selection
)
188 def set_selected_item(widget
, idx
):
189 """Sets a the currently selected item to the item at index idx."""
190 if type(widget
) is QtGui
.QTreeWidget
:
191 item
= widget
.topLevelItem(idx
)
193 widget
.setItemSelected(item
, True)
194 widget
.setCurrentItem(item
)
196 def add_items(widget
, items
):
197 """Adds items to a widget."""
201 def set_items(widget
, items
):
202 """Clear the existing widget contents and set the new items."""
204 add_items(widget
, items
)
207 """Translate a string into a local language."""
208 if type(txt
) is QtCore
.QString
:
209 # This has already been translated; leave as-is
211 return unicode(QtGui
.QApplication
.instance().translate('', txt
))
213 def icon_file(filename
, staged
=False, untracked
=False):
214 """Returns a file path representing a corresponding file path."""
216 if os
.path
.exists(core
.encode(filename
)):
217 ifile
= resources
.icon('staged.png')
219 ifile
= resources
.icon('removed.png')
221 ifile
= resources
.icon('untracked.png')
223 ifile
= utils
.file_icon(filename
)
226 def icon_for_file(filename
, staged
=False, untracked
=False):
227 """Returns a QIcon for a particular file path."""
228 ifile
= icon_file(filename
, staged
=staged
, untracked
=untracked
)
231 def create_treeitem(filename
, staged
=False, untracked
=False, check
=True):
232 """Given a filename, return a QListWidgetItem suitable
233 for adding to a QListWidget. "staged" and "untracked"
234 controls whether to use the appropriate icons."""
236 ifile
= icon_file(filename
, staged
=staged
, untracked
=untracked
)
238 ifile
= resources
.icon('staged.png')
239 return create_treewidget_item(filename
, ifile
)
242 def update_file_icons(widget
, items
, staged
=True,
243 untracked
=False, offset
=0):
244 """Populate a QListWidget with custom icon items."""
245 for idx
, model_item
in enumerate(items
):
246 item
= widget
.item(idx
+offset
)
248 item
.setIcon(icon_for_file(model_item
, staged
, untracked
))
250 def set_listwidget_strings(widget
, items
):
251 """Sets a list widget to the strings passed in items."""
253 add_items(widget
, [ QtGui
.QListWidgetItem(i
) for i
in items
])
256 def cached_icon(key
):
257 """Maintain a cache of standard icons and return cache entries."""
258 if key
not in _icon_cache
:
259 style
= QtGui
.QApplication
.instance().style()
260 _icon_cache
[key
] = style
.standardIcon(key
)
261 return _icon_cache
[key
]
264 """Return a standard icon for a directory."""
265 return cached_icon(QtGui
.QStyle
.SP_DirIcon
)
268 """Return a standard icon for a file."""
269 return cached_icon(QtGui
.QStyle
.SP_FileIcon
)
272 """Return the diff font string."""
273 qfont
= QtGui
.QFont()
274 font
= cola
.model().cola_config('fontdiff')
275 if font
and qfont
.fromString(font
):
278 if cola
.utils
.is_darwin():
280 qfont
.setFamily(family
)
281 font
= unicode(qfont
.toString())
282 # TODO this might not be the best place for the default
283 cola
.model().set_diff_font(font
)
286 def set_diff_font(widget
):
287 """Updates the diff font based on the configured value."""
289 block
= widget
.signalsBlocked()
290 widget
.blockSignals(True)
291 if isinstance(widget
, QtGui
.QFontComboBox
):
292 widget
.setCurrentFont(qfont
)
294 widget
.setFont(qfont
)
295 widget
.blockSignals(block
)
298 def add_close_action(widget
):
299 """Adds a Ctrl+w close action to a widget."""
300 action
= QtGui
.QAction(widget
.tr('Close...'), widget
)
301 action
.setShortcut('Ctrl+w')
302 widget
.addAction(action
)
303 widget
.connect(action
, SIGNAL('triggered()'), widget
.close
)
306 def center_on_screen(widget
):
307 """Move widget to the center of the default screen"""
308 desktop
= QtGui
.QApplication
.instance().desktop()
309 rect
= desktop
.screenGeometry(QtGui
.QCursor().pos())
312 widget
.move(cx
- widget
.width()/2, cy
- widget
.height()/2)