from schrodinger.Qt import QtCore
from schrodinger.Qt import QtGui
from schrodinger.Qt import QtWidgets
from schrodinger.Qt.QtCore import Qt
from schrodinger.structure import Structure
[docs]class BaseTable(QtWidgets.QTableWidget):
[docs]    def __init__(self, parent=None):
        QtWidgets.QTableWidget.__init__(self, parent)
        self.setup()
        self.reset() 
[docs]    def reset(self):
        self.removeAllRows() 
[docs]    def removeAllRows(self):
        while self.rowCount() > 0:
            self.removeRow(0) 
[docs]    def setup(self):
        self.show()
        self.setEnabled(True)
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.setColumnCount(len(self.header_titles))
        self.setHorizontalHeaderLabels(self.header_titles)
        header = self.horizontalHeader()
        header.setSectionResizeMode(QtWidgets.QHeaderView.Interactive)
        vheader = self.verticalHeader()
        vheader.setVisible(False)
        self.setSortingEnabled(True) 
[docs]    def keyPressEvent(self, event):
        if event.matches(QtGui.QKeySequence.Copy):
            mime_data = QtCore.QMimeData()
            text = self.getSelectedText()
            mime_data.setText(text)
            QtWidgets.QApplication.clipboard().setMimeData(mime_data) 
[docs]    def getSelectedText(self):
        items = self.selectedItems()
        if not items:
            return ''
        current_row = items[0].row()
        lines = []
        line = []
        for item in items:
            row = item.row()
            if row > current_row:
                current_row = row
                lines.append('\t'.join(line))
                line = []
            line.append(item.text())
        if line:
            lines.append('\t'.join(line))
        text = '\n'.join(lines)
        return text  
[docs]class LogTable(BaseTable):
    Super = BaseTable
    header_titles = ['Time', 'Tag', 'Caller', 'Text']
[docs]    def __init__(self, parent=None):
        self.log = []
        self.Super.__init__(self, parent) 
[docs]    def setup(self):
        self.Super.setup(self)
        self.setColumnWidth(0, 100)
        self.setColumnWidth(1, 80)
        self.setColumnWidth(2, 150)
        self.setColumnWidth(3, 500) 
[docs]    def addEntry(self, entry):
        row_idx = self.rowCount()
        self.setRowCount(row_idx + 1)
        self.setRowHeight(row_idx, 18)
        self.setItem(row_idx, 0, QtWidgets.QTableWidgetItem(entry.timestamp))
        self.setItem(row_idx, 1, QtWidgets.QTableWidgetItem(entry.tag))
        self.setItem(row_idx, 2, QtWidgets.QTableWidgetItem(entry.caller))
        self.setItem(row_idx, 3, QtWidgets.QTableWidgetItem(entry.text))
        self.resizeRowsToContents()  
[docs]class LogTagTable(BaseTable):
    Super = BaseTable
    header_titles = ['Enable', 'Tag']
[docs]    def __init__(self, parent=None):
        self.Super.__init__(self, parent)  
[docs]def find_signals(obj_name, obj):
    signals = []
    for name in dir(obj):
        attr = getattr(obj, name)
        if isinstance(attr, QtCore.pyqtBoundSignal):
            signals.append((obj_name, obj, name, attr))
    return signals 
EXCLUDE_DEEP_FIND_CLASSES = (Structure,)
[docs]def deep_find_signals(obj_name, obj, done_list=None, depth=0):
    signals = []
    if isinstance(obj, EXCLUDE_DEEP_FIND_CLASSES):
        print('Object %s excluded from scanning.' % obj_name)
        return signals
    if depth > 8:
        print('Depth %i in %s' % (depth, obj_name))
        if depth > 30:
            print('Max depth exceeded.')
            return signals
    if done_list is None:
        done_list = []
    try:
        for item in done_list:
            if obj is item:
                return signals
    except TypeError:
        return signals
    done_list.append(obj)
    if not hasattr(obj, '__dict__'):
        return signals
    signals.extend(find_signals(obj_name, obj))
    for sub_obj_name, sub_obj in obj.__dict__.items():
        if obj_name:
            full_name = obj_name + '.' + sub_obj_name
        else:
            full_name = sub_obj_name
        signals.extend(
            deep_find_signals(full_name, sub_obj, done_list, depth=depth + 1))
    return signals 
[docs]class SignalTable(BaseTable):
    Super = BaseTable
    header_titles = ['Enable', 'Object', 'Signal']
[docs]    def __init__(self, parent=None):
        self.connected_slots = {}
        self.all_slots = {}
        self.signals = []
        self.Super.__init__(self, parent)
        self.cellChanged.connect(self.onCellChanged) 
[docs]    def setup(self):
        self.Super.setup(self)
        self.setColumnWidth(0, 50)
        self.setColumnWidth(1, 150)
        self.setColumnWidth(2, 300) 
[docs]    def addEntry(self, obj_name, obj, signal_name, signal):
        row_idx = self.rowCount()
        self.setRowCount(row_idx + 1)
        self.setRowHeight(row_idx, 18)
        check_item = QtWidgets.QTableWidgetItem()
        check_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled |
                            Qt.ItemIsUserCheckable)
        check_item.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        check_item.setCheckState(Qt.Unchecked)
        check_item.signal = signal
        self.setItem(row_idx, 0, check_item)
        self.setItem(row_idx, 1, QtWidgets.QTableWidgetItem(obj_name))
        self.setItem(row_idx, 2, QtWidgets.QTableWidgetItem(signal_name)) 
[docs]    def onCellChanged(self, row, column):
        if column == 0:
            item = self.item(row, column)
            if item.checkState() == QtCore.Qt.Checked:
                self.connectSignal(item.signal)
            else:
                self.disconnectSignal(item.signal) 
[docs]    def deepFindSignals(self, obj_name, obj, done_list=None):
        return deep_find_signals(obj_name, obj, done_list) 
[docs]    def scan(self, obj, exclude_objs):
        self.disconnectSignals()
        self.reset()
        signals = self.deepFindSignals('', obj, exclude_objs)
        self.signals = signals
        for obj_name, obj, signal_name, signal in signals:
            self.addEntry(obj_name, obj, signal_name, signal) 
[docs]    def registerSignals(self, slot_factory):
        for obj_name, obj, signal_name, signal in self.signals:
            slot = slot_factory(obj_name, signal_name, signal)
            self.all_slots[signal] = slot 
[docs]    def deregisterSignals(self):
        self.disconnectSignals()
        for signal in list(self.all_slots):
            self.all_slots.pop(signal) 
[docs]    def connectSignals(self):
        for signal in list(self.connected_slots):
            self.connectSignal(signal) 
[docs]    def disconnectSignals(self):
        for signal in list(self.connected_slots):
            self.disconnectSignal(signal) 
[docs]    def connectSignal(self, signal):
        if signal in self.connected_slots:
            return
        slot = self.all_slots[signal]
        signal.connect(slot)
        self.connected_slots[signal] = slot 
[docs]    def disconnectSignal(self, signal):
        if signal not in self.connected_slots:
            return
        slot = self.connected_slots.pop(signal)
        signal.disconnect(slot) 
[docs]    def applyFilter(self, filter_string):
        for row_idx in range(self.rowCount()):
            obj_name = self.item(row_idx, 1).text().lower()
            signal_name = self.item(row_idx, 2).text().lower()
            filter_string = filter_string.lower()
            found = filter_string in obj_name or filter_string in signal_name
            self.setRowHidden(row_idx, not found)  
class _HistoryLineEdit(QtWidgets.QLineEdit):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.history = []
        self.history_index = 0
        self.temp_text = ''
    def keyPressEvent(self, e):
        if e.key() == QtCore.Qt.Key_Up:
            if self.history_index < len(self.history):
                if self.history_index == 0:
                    self.temp_text = self.text()
                self.history_index += 1
                text = self.history[-1 * self.history_index]
                self.setText(text)
        elif e.key() == QtCore.Qt.Key_Down:
            if self.history_index > 0:
                text = self.history[-1 * self.history_index]
                self.history_index -= 1
            else:
                text = self.temp_text
            self.setText(text)
        else:
            super().keyPressEvent(e)