File: C:/Users/fred/anaconda3/Lib/site-packages/spyder/plugins/layout/widgets/dialog.py
# -*- coding: utf-8 -*-
#
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
# (see spyder/__init__.py for details)
"""Layout dialogs"""
# Standard library imports
import sys
# Third party imports
from qtpy.QtCore import QAbstractTableModel, QModelIndex, QSize, Qt
from qtpy.compat import from_qvariant, to_qvariant
from qtpy.QtWidgets import (QAbstractItemView, QComboBox, QDialog,
QDialogButtonBox, QGroupBox, QHBoxLayout,
QPushButton, QTableView, QVBoxLayout)
# Local imports
from spyder.config.base import _
from spyder.py3compat import to_text_string
class LayoutModel(QAbstractTableModel):
""" """
def __init__(self, parent, names, ui_names, order, active, read_only):
super(LayoutModel, self).__init__(parent)
# variables
self._parent = parent
self.names = names
self.ui_names = ui_names
self.order = order
self.active = active
self.read_only = read_only
self._rows = []
self.set_data(names, ui_names, order, active, read_only)
def set_data(self, names, ui_names, order, active, read_only):
""" """
self._rows = []
self.names = names
self.ui_names = ui_names
self.order = order
self.active = active
self.read_only = read_only
for name in order:
index = names.index(name)
if name in active:
row = [ui_names[index], name, True]
else:
row = [ui_names[index], name, False]
self._rows.append(row)
def flags(self, index):
"""Override Qt method"""
row = index.row()
ui_name, name, state = self.row(row)
if name in self.read_only:
return Qt.NoItemFlags
if not index.isValid():
return Qt.ItemIsEnabled
column = index.column()
if column in [0]:
return Qt.ItemFlags(int(Qt.ItemIsEnabled | Qt.ItemIsSelectable |
Qt.ItemIsUserCheckable |
Qt.ItemIsEditable))
else:
return Qt.ItemFlags(Qt.ItemIsEnabled)
def data(self, index, role=Qt.DisplayRole):
"""Override Qt method"""
if not index.isValid() or not 0 <= index.row() < len(self._rows):
return to_qvariant()
row = index.row()
column = index.column()
ui_name, name, state = self.row(row)
if role == Qt.DisplayRole or role == Qt.EditRole:
if column == 0:
return to_qvariant(ui_name)
elif role == Qt.UserRole:
if column == 0:
return to_qvariant(name)
elif role == Qt.CheckStateRole:
if column == 0:
if state:
return Qt.Checked
else:
return Qt.Unchecked
if column == 1:
return to_qvariant(state)
return to_qvariant()
def setData(self, index, value, role):
"""Override Qt method"""
row = index.row()
ui_name, name, state = self.row(row)
if role == Qt.CheckStateRole:
self.set_row(row, [ui_name, name, not state])
self._parent.setCurrentIndex(index)
self._parent.setFocus()
self.dataChanged.emit(index, index)
return True
elif role == Qt.EditRole:
self.set_row(
row, [from_qvariant(value, to_text_string), name, state])
self.dataChanged.emit(index, index)
return True
return True
def rowCount(self, index=QModelIndex()):
"""Override Qt method"""
return len(self._rows)
def columnCount(self, index=QModelIndex()):
"""Override Qt method"""
return 2
def row(self, rownum):
""" """
if self._rows == [] or rownum >= len(self._rows):
return [None, None, None]
else:
return self._rows[rownum]
def set_row(self, rownum, value):
""" """
self._rows[rownum] = value
class LayoutSaveDialog(QDialog):
""" """
def __init__(self, parent, order):
super(LayoutSaveDialog, self).__init__(parent)
# variables
self._parent = parent
# widgets
self.combo_box = QComboBox(self)
self.combo_box.addItems(order)
self.combo_box.setEditable(True)
self.combo_box.clearEditText()
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok |
QDialogButtonBox.Cancel,
Qt.Horizontal, self)
self.button_ok = self.button_box.button(QDialogButtonBox.Ok)
self.button_cancel = self.button_box.button(QDialogButtonBox.Cancel)
# widget setup
self.button_ok.setEnabled(False)
self.dialog_size = QSize(300, 100)
self.setWindowTitle('Save layout as')
self.setModal(True)
self.setMinimumSize(self.dialog_size)
self.setFixedSize(self.dialog_size)
# layouts
self.layout = QVBoxLayout()
self.layout.addWidget(self.combo_box)
self.layout.addWidget(self.button_box)
self.setLayout(self.layout)
# signals and slots
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.close)
self.combo_box.editTextChanged.connect(self.check_text)
def check_text(self, text):
"""Disable empty layout name possibility"""
if to_text_string(text) == u'':
self.button_ok.setEnabled(False)
else:
self.button_ok.setEnabled(True)
class LayoutSettingsDialog(QDialog):
"""Layout settings dialog"""
def __init__(self, parent, names, ui_names, order, active, read_only):
super(LayoutSettingsDialog, self).__init__(parent)
# variables
self._parent = parent
self._selection_model = None
self.names = names
self.ui_names = ui_names
self.order = order
self.active = active
self.read_only = read_only
# widgets
self.button_move_up = QPushButton(_('Move Up'))
self.button_move_down = QPushButton(_('Move Down'))
self.button_delete = QPushButton(_('Delete Layout'))
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok |
QDialogButtonBox.Cancel,
Qt.Horizontal, self)
self.group_box = QGroupBox(_("Layout Display and Order"))
self.table = QTableView(self)
self.ok_button = self.button_box.button(QDialogButtonBox.Ok)
self.cancel_button = self.button_box.button(QDialogButtonBox.Cancel)
self.cancel_button.setDefault(True)
self.cancel_button.setAutoDefault(True)
# widget setup
self.dialog_size = QSize(300, 200)
self.setMinimumSize(self.dialog_size)
self.setFixedSize(self.dialog_size)
self.setWindowTitle('Layout Settings')
self.table.setModel(
LayoutModel(self.table, names, ui_names, order, active, read_only))
self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table.setSelectionMode(QAbstractItemView.SingleSelection)
self.table.verticalHeader().hide()
self.table.horizontalHeader().hide()
self.table.setAlternatingRowColors(True)
self.table.setShowGrid(False)
self.table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.table.horizontalHeader().setStretchLastSection(True)
self.table.setColumnHidden(1, True)
# need to keep a reference for pyside not to segfault!
self._selection_model = self.table.selectionModel()
# layout
buttons_layout = QVBoxLayout()
buttons_layout.addWidget(self.button_move_up)
buttons_layout.addWidget(self.button_move_down)
buttons_layout.addStretch()
buttons_layout.addWidget(self.button_delete)
group_layout = QHBoxLayout()
group_layout.addWidget(self.table)
group_layout.addLayout(buttons_layout)
self.group_box.setLayout(group_layout)
layout = QVBoxLayout()
layout.addWidget(self.group_box)
layout.addWidget(self.button_box)
self.setLayout(layout)
# signals and slots
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.close)
self.button_delete.clicked.connect(self.delete_layout)
self.button_move_up.clicked.connect(lambda: self.move_layout(True))
self.button_move_down.clicked.connect(lambda: self.move_layout(False))
self.table.model().dataChanged.connect(
lambda: self.selection_changed(None, None))
self._selection_model.selectionChanged.connect(
lambda: self.selection_changed(None, None))
# focus table
if len(names) > len(read_only):
row = len(read_only)
index = self.table.model().index(row, 0)
self.table.setCurrentIndex(index)
self.table.setFocus()
else:
# initial button state in case only programmatic layouts
# are available
self.button_move_up.setDisabled(True)
self.button_move_down.setDisabled(True)
self.button_delete.setDisabled(True)
def delete_layout(self):
"""Delete layout from the config."""
names, ui_names, order, active, read_only = (
self.names, self.ui_names, self.order, self.active, self.read_only)
row = self.table.selectionModel().currentIndex().row()
ui_name, name, state = self.table.model().row(row)
if name not in read_only:
name = from_qvariant(
self.table.selectionModel().currentIndex().data(),
to_text_string)
if ui_name in ui_names:
index = ui_names.index(ui_name)
else:
# In case nothing has focus in the table
return
if index != -1:
order.remove(ui_name)
names.remove(ui_name)
ui_names.remove(ui_name)
if name in active:
active.remove(ui_name)
self.names, self.ui_names, self.order, self.active = (
names, ui_names, order, active)
self.table.model().set_data(
names, ui_names, order, active, read_only)
index = self.table.model().index(0, 0)
self.table.setCurrentIndex(index)
self.table.setFocus()
self.selection_changed(None, None)
if len(order) == 0 or len(names) == len(read_only):
self.button_move_up.setDisabled(True)
self.button_move_down.setDisabled(True)
self.button_delete.setDisabled(True)
def move_layout(self, up=True):
""" """
names, ui_names, order, active, read_only = (
self.names, self.ui_names, self.order, self.active, self.read_only)
row = self.table.selectionModel().currentIndex().row()
row_new = row
_ui_name, name, _state = self.table.model().row(row)
if name not in read_only:
if up:
row_new -= 1
else:
row_new += 1
if order[row_new] not in read_only:
order[row], order[row_new] = order[row_new], order[row]
self.order = order
self.table.model().set_data(
names, ui_names, order, active, read_only)
index = self.table.model().index(row_new, 0)
self.table.setCurrentIndex(index)
self.table.setFocus()
self.selection_changed(None, None)
def selection_changed(self, selection, deselection):
""" """
model = self.table.model()
index = self.table.currentIndex()
row = index.row()
order, names, ui_names, active, read_only = (
self.order, self.names, self.ui_names, self.active, self.read_only)
state = model.row(row)[2]
ui_name = model.row(row)[0]
# Check if name changed
if ui_name not in ui_names: # Did changed
# row == -1, means no items left to delete
if row != -1 and len(names) > len(read_only):
old_name = order[row]
order[row] = ui_name
names[names.index(old_name)] = ui_name
ui_names = names
if old_name in active:
active[active.index(old_name)] = ui_name
# Check if checkbox clicked
if state:
if ui_name not in active:
active.append(ui_name)
else:
if ui_name in active:
active.remove(ui_name)
self.active = active
self.order = order
self.names = names
self.ui_names = ui_names
self.button_move_up.setDisabled(False)
self.button_move_down.setDisabled(False)
if row == 0:
self.button_move_up.setDisabled(True)
if row == len(names) - 1:
self.button_move_down.setDisabled(True)
if len(names) == 0:
self.button_move_up.setDisabled(True)
self.button_move_down.setDisabled(True)
def test():
"""Run layout test widget test"""
from spyder.utils.qthelpers import qapplication
app = qapplication()
names = ['test', 'tester', '20', '30', '40']
ui_names = ['L1', 'L2', '20', '30', '40']
order = ['test', 'tester', '20', '30', '40']
read_only = ['test', 'tester']
active = ['test', 'tester']
widget_1 = LayoutSettingsDialog(
None, names, ui_names, order, active, read_only)
widget_2 = LayoutSaveDialog(None, order)
widget_1.show()
widget_2.show()
sys.exit(app.exec_())
if __name__ == '__main__':
test()