from __future__ import absolute_import, division, print_function
import os
from contextlib import contextmanager
from glue.external.qt import QtGui, QtCore
from glue.external.qt.QtCore import Qt
from glue.utils.qt import get_text
__all__ = ['update_combobox', 'GlueTabBar', 'load_ui', 'CUSTOM_QWIDGETS', 'process_dialog']
[docs]def update_combobox(combo, labeldata):
"""
Redefine the items in a QComboBox
Parameters
----------
widget : QComboBox
The widget to update
labeldata : sequence of N (label, data) tuples
The combobox will contain N items with the appropriate
labels, and data set as the userData
Returns
-------
combo : QComboBox
The updated input
Notes
-----
If the current userData in the combo box matches
any of labeldata, that selection will be retained.
Otherwise, the first item will be selected.
Signals are disabled while the combo box is updated
The QComboBox is modified inplace
"""
combo.blockSignals(True)
idx = combo.currentIndex()
if idx >= 0:
current = combo.itemData(idx)
else:
current = None
combo.clear()
index = 0
for i, (label, data) in enumerate(labeldata):
combo.addItem(label, userData=data)
if data is current:
index = i
combo.blockSignals(False)
combo.setCurrentIndex(index)
# We need to force emit this, otherwise if the index happens to be the
# same as before, even if the data is different, callbacks won't be
# called.
if idx == index or idx == -1:
combo.currentIndexChanged.emit(index)
[docs]class GlueTabBar(QtGui.QTabBar):
def __init__(self, *args, **kwargs):
super(GlueTabBar, self).__init__(*args, **kwargs)
[docs] def rename_tab(self, index=None):
""" Prompt user to rename a tab
:param index: integer. Index of tab to edit. Defaults to current index
"""
index = index or self.currentIndex()
label = get_text("New Tab Label")
if not label:
return
self.setTabText(index, label)
[docs] def mouseDoubleClickEvent(self, event):
if event.button() != Qt.LeftButton:
return
index = self.tabAt(event.pos())
if index >= 0:
self.rename_tab(index)
CUSTOM_QWIDGETS = []
[docs]def load_ui(path, parent=None, directory=None):
"""
Load a .ui file
Parameters
----------
path : str
Name of ui file to load
parent : QObject
Object to use as the parent of this widget
Returns
-------
w : QtGui.QWidget
The new widget
"""
if directory is not None:
full_path = os.path.join(directory, path)
else:
full_path = os.path.abspath(path)
if not os.path.exists(full_path) and 'site-packages.zip' in full_path:
# Workaround for Mac app
full_path = os.path.join(full_path.replace('site-packages.zip', 'glue'))
from glue.external.qt import load_ui
return load_ui(full_path, parent, custom_widgets=CUSTOM_QWIDGETS)
@contextmanager
[docs]def process_dialog(delay=0, accept=False, reject=False, function=None):
"""
Context manager to automatically capture the active dialog and carry out
certain actions.
Note that only one of ``accept``, ``reject``, or ``function`` should be
specified.
Parameters
----------
delay : int, optional
The delay in ms before acting on the dialog (since it may not yet exist
when the context manager is called).
accept : bool, optional
If `True`, accept the dialog after the specified delay.
reject : bool, optional
If `False`, reject the dialog after the specified delay
function : func, optional
For more complex user actions, specify a function that takes the dialog
as the first and only argument.
"""
def _accept(dialog):
dialog.accept()
def _reject(dialog):
dialog.reject()
n_args = sum((accept, reject, function is not None))
if n_args > 1:
raise ValueError("Only one of ``accept``, ``reject``, or "
"``function`` should be specified")
elif n_args == 0:
raise ValueError("One of ``accept``, ``reject``, or "
"``function`` should be specified")
if accept:
function = _accept
elif reject:
function = _reject
def wrapper():
from glue.external.qt import get_qapp
app = get_qapp()
dialog = app.focusWidget().window()
function(dialog)
timer = QtCore.QTimer()
timer.setInterval(delay)
timer.setSingleShot(True)
timer.timeout.connect(wrapper)
timer.start()
yield