QT added
parent
fee801a822
commit
0e5286c333
|
|
@ -0,0 +1,164 @@
|
||||||
|
import collections
|
||||||
|
from PySide6 import QtCore, QtWidgets
|
||||||
|
from QT.Main_Window import Attr_Dict
|
||||||
|
|
||||||
|
class Input_Dialog (QtWidgets.QDialog) :
|
||||||
|
|
||||||
|
def __init__ (self, title, ** spec) :
|
||||||
|
super ().__init__ (spec.pop ("parent", None))
|
||||||
|
self.setWindowTitle (title)
|
||||||
|
self.layout = L = QtWidgets.QFormLayout (self)
|
||||||
|
self.widgets = {}
|
||||||
|
self.min_width = spec.pop ("_MIN_WIDTH", 200)
|
||||||
|
self.field_spec = spec
|
||||||
|
self.dependencies = collections.defaultdict (list)
|
||||||
|
for name, fspec in spec.items () :
|
||||||
|
type = fspec.get ("type")
|
||||||
|
default = fspec.get ("default")
|
||||||
|
if type is None and default is not None :
|
||||||
|
type = default.__class__.__name__
|
||||||
|
getattr (self, "_add_%s" % type, self._add_str) \
|
||||||
|
(L, name, fspec, default, type)
|
||||||
|
for attr, format in fspec.get ("auto", {}).items () :
|
||||||
|
self.dependencies [attr].append ((name, format))
|
||||||
|
layout = QtWidgets.QHBoxLayout ()
|
||||||
|
ok = QtWidgets.QPushButton ("OK")
|
||||||
|
ok.clicked.connect (self.store_values)
|
||||||
|
cancel = QtWidgets.QPushButton ("Cancel")
|
||||||
|
cancel.clicked.connect (self.reject)
|
||||||
|
layout.addStretch (10)
|
||||||
|
layout.addWidget (ok)
|
||||||
|
layout.addWidget (cancel)
|
||||||
|
ok.setDefault (True)
|
||||||
|
L.addRow (layout)
|
||||||
|
self.setMinimumWidth (self.min_width)
|
||||||
|
self.result = Attr_Dict ()
|
||||||
|
# end def __init__
|
||||||
|
|
||||||
|
def get_values (self) :
|
||||||
|
data = Attr_Dict ()
|
||||||
|
errors = {}
|
||||||
|
for name, (getter, _) in self.widgets.items () :
|
||||||
|
data [name] = value = getter ()
|
||||||
|
fspec = self.field_spec [name]
|
||||||
|
if not value and fspec.get ("required", False) :
|
||||||
|
errors [name] = "Required"
|
||||||
|
return data, errors
|
||||||
|
# end def store_values
|
||||||
|
|
||||||
|
def store_values (self) :
|
||||||
|
self.result, errors = self.get_values ()
|
||||||
|
if not errors :
|
||||||
|
self.accept ()
|
||||||
|
# end def store_values
|
||||||
|
|
||||||
|
def _auto_update (self, changed) :
|
||||||
|
if changed in self.dependencies :
|
||||||
|
values, _ = self.get_values ()
|
||||||
|
for attr, format in self.dependencies [changed] :
|
||||||
|
if not values.get (attr) :
|
||||||
|
self.widgets [attr] [1] (format % values)
|
||||||
|
# end def _auto_update
|
||||||
|
|
||||||
|
def _add_str (self, L, name, fspec, default, type) :
|
||||||
|
widget = QtWidgets.QLineEdit ()
|
||||||
|
widget.setText (default or "")
|
||||||
|
self.widgets [name] = widget.text, widget.setText
|
||||||
|
L.addRow (fspec.get ("title", name.capitalize ()), widget)
|
||||||
|
widget.editingFinished.connect \
|
||||||
|
(lambda : self._auto_update (name))
|
||||||
|
# end def _add_str
|
||||||
|
|
||||||
|
def _add_int (self, L, name, fspec, default, type) :
|
||||||
|
widget = QtWidgets.QSpinBox ()
|
||||||
|
widget.setRange (-65536, 0x7FFFFFFF)
|
||||||
|
widget.setValue (default or 0)
|
||||||
|
self.widgets [name] = widget.value, widget.setValue
|
||||||
|
L.addRow (fspec.get ("title", name.capitalize ()), widget)
|
||||||
|
widget.editingFinished.connect \
|
||||||
|
(lambda : self._auto_update (name))
|
||||||
|
# end def _add_int
|
||||||
|
|
||||||
|
def _add_file_dialog (self, cb, L, name, fspec, default) :
|
||||||
|
layout = QtWidgets.QHBoxLayout ()
|
||||||
|
current = QtWidgets.QLineEdit ()
|
||||||
|
current.setText (default or "")
|
||||||
|
current.setEnabled (False)
|
||||||
|
change = QtWidgets.QPushButton ("...")
|
||||||
|
change.setFixedWidth (24)
|
||||||
|
change.clicked.connect (lambda : cb (fspec, current))
|
||||||
|
layout.addWidget (current)
|
||||||
|
layout.addWidget (change)
|
||||||
|
layout.setStretch (0, 10)
|
||||||
|
self.widgets [name] = current.text, current.setText
|
||||||
|
L.addRow (fspec.get ("title", name.capitalize ()), layout)
|
||||||
|
self.min_width = max (self.min_width, 600)
|
||||||
|
# end def _add_file_dialog
|
||||||
|
|
||||||
|
def _add_open_filename (self, L, name, fspec, default, type) :
|
||||||
|
self._add_file_dialog \
|
||||||
|
(self._choose_file_dialog, L, name, fspec, default)
|
||||||
|
# end def _add_open_filename
|
||||||
|
|
||||||
|
def _choose_file_dialog (self, fspec, current) :
|
||||||
|
filter = fspec.get ("filter", ())
|
||||||
|
filter = ";;".join ("%s (%s)" % (t, e) for (t, e) in filter)
|
||||||
|
file_name = QtWidgets.QFileDialog.getOpenFileName \
|
||||||
|
( filter = filter
|
||||||
|
) [0]
|
||||||
|
if file_name :
|
||||||
|
current.setText (file_name)
|
||||||
|
# end def _choose_file_dialog
|
||||||
|
|
||||||
|
def _add_save_filename (self, L, name, fspec, default, type) :
|
||||||
|
self._add_file_dialog \
|
||||||
|
(self._save_file_dialog, L, name, fspec, default)
|
||||||
|
# end def _add_open_filename
|
||||||
|
|
||||||
|
def _save_file_dialog (self, fspec, current) :
|
||||||
|
filter = fspec.get ("filter", ())
|
||||||
|
filter = ";;".join ("%s (%s)" % (t, e) for (t, e) in filter)
|
||||||
|
file_name = QtWidgets.QFileDialog.getSaveFileName \
|
||||||
|
( filter = filter
|
||||||
|
) [0]
|
||||||
|
if file_name :
|
||||||
|
current.setText (file_name)
|
||||||
|
# end def _save_file_dialog
|
||||||
|
|
||||||
|
def _add_drop_down (self, L, name, fspec, default, type) :
|
||||||
|
widget = QtWidgets.QComboBox ()
|
||||||
|
for idx, e in enumerate \
|
||||||
|
(sorted (fspec ["choices"], key = lambda e : e ["label"])) :
|
||||||
|
widget.addItem (e ["label"], e ["value"])
|
||||||
|
if "tooltip" in e :
|
||||||
|
widget.setItemData \
|
||||||
|
(idx, e ["tooltip"], QtCore.Qt.ToolTipRole)
|
||||||
|
self.widgets [name] = widget.currentText, widget.setCurrentText
|
||||||
|
L.addRow (fspec.get ("title", name.capitalize ()), widget)
|
||||||
|
widget.currentTextChanged.connect \
|
||||||
|
(lambda : self._auto_update (name))
|
||||||
|
# end def _add_drop_down
|
||||||
|
|
||||||
|
def run (self) :
|
||||||
|
if self.exec () == 1 :
|
||||||
|
return self.result
|
||||||
|
# end def run
|
||||||
|
|
||||||
|
# end class Input_Dialog
|
||||||
|
|
||||||
|
if __name__ == "__main__" :
|
||||||
|
app = QtWidgets.QApplication ([])
|
||||||
|
r = Input_Dialog \
|
||||||
|
( "Test"
|
||||||
|
, name = {"default": "", "title" : "Layer Name", "required": True}
|
||||||
|
, file_name = {"default": "", "title" : "Filename"
|
||||||
|
, "type" : "save_filename"
|
||||||
|
, "filter": ( ( "Layer Files", "*.layer")
|
||||||
|
, ( "Json Files", "*.json")
|
||||||
|
, ( "All Files", "*.*")
|
||||||
|
)
|
||||||
|
, "auto" : {"name" : "%(name)s/%(name)s.layer"}
|
||||||
|
}
|
||||||
|
).run ()
|
||||||
|
if r is not None :
|
||||||
|
print (r)
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
from PySide6 import QtWidgets, QtCore, QtGui
|
||||||
|
import os
|
||||||
|
|
||||||
|
class Attr_Dict (dict) :
|
||||||
|
|
||||||
|
def __getattr__ (self, key) :
|
||||||
|
return self [key]
|
||||||
|
# end def __getattr__
|
||||||
|
|
||||||
|
# end class Attr_Dict
|
||||||
|
|
||||||
|
class Main_Window (QtWidgets.QMainWindow) :
|
||||||
|
|
||||||
|
DEFAULT_SETTINGS_FILE = "settings.ini"
|
||||||
|
|
||||||
|
APP_NAME = "Main Window"
|
||||||
|
VERSION = "0"
|
||||||
|
APP_ORGANISATION = ("Org-Name", "Org-Domain")
|
||||||
|
|
||||||
|
def __init__ (self, app, settings) :
|
||||||
|
super ().__init__ ()
|
||||||
|
self.settings = settings
|
||||||
|
self.setWindowTitle ("%s %s" % (self.APP_NAME, self.VERSION))
|
||||||
|
self._setupActions (app)
|
||||||
|
self._setupGui ()
|
||||||
|
if not self.restore_settings (settings) :
|
||||||
|
self.show ()
|
||||||
|
# end def __init__
|
||||||
|
|
||||||
|
def _setupActions (self, app) :
|
||||||
|
self.actions = Attr_Dict ()
|
||||||
|
self._add_action ("exit", "Exit", self.close, icon = ":/icons/exit.png")
|
||||||
|
# end def _setupActions
|
||||||
|
|
||||||
|
def _add_action (self, name, label, callback, icon = None, ** options) :
|
||||||
|
A = QtGui.QAction (label, self, ** options)
|
||||||
|
if icon :
|
||||||
|
A.setIcon (QtGui.QIcon (icon))
|
||||||
|
self.actions [name] = A
|
||||||
|
A.triggered.connect (callback)
|
||||||
|
# end def _add_action
|
||||||
|
|
||||||
|
def _setupGui (self) :
|
||||||
|
pass
|
||||||
|
# end def _setupGui
|
||||||
|
|
||||||
|
def closeEvent (self, * args) :
|
||||||
|
self.save_settings ()
|
||||||
|
super ().closeEvent (* args)
|
||||||
|
# end def closeEvent
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _open_settings (cls, settings_file = None) :
|
||||||
|
if not settings_file :
|
||||||
|
settings_file = os.path.join (cls.APP_DIR, cls.DEFAULT_SETTINGS_FILE)
|
||||||
|
QtCore.QCoreApplication.setOrganizationName (cls.APP_ORGANISATION [0])
|
||||||
|
QtCore.QCoreApplication.setOrganizationDomain (cls.APP_ORGANISATION [1])
|
||||||
|
QtCore.QCoreApplication.setApplicationName (cls.APP_NAME)
|
||||||
|
return QtCore.QSettings (settings_file, QtCore.QSettings.IniFormat)
|
||||||
|
# end def _open_settings
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_settings (cls, cmd) :
|
||||||
|
settings = cls._open_settings (cmd.settings_file)
|
||||||
|
ps = cls._load_app_settings (settings)
|
||||||
|
settings.beginGroup ("TempSettings")
|
||||||
|
settings.setValue ("settingsFile", cmd.settings_file)
|
||||||
|
for n, v in ps.items () :
|
||||||
|
if getattr (cmd, n, None) != None :
|
||||||
|
v = getattr (cmd, n)
|
||||||
|
settings.setValue (n, v)
|
||||||
|
settings.endGroup ()
|
||||||
|
return settings
|
||||||
|
# end def load_settings
|
||||||
|
|
||||||
|
def restore_settings (self, settings) :
|
||||||
|
self.settings = settings
|
||||||
|
QtCore.QTimer.singleShot (1, self._restore_settings)
|
||||||
|
# end def restore_settings
|
||||||
|
|
||||||
|
def _restore_settings (self) :
|
||||||
|
settings = self.settings
|
||||||
|
settings.beginGroup ("MainWindow")
|
||||||
|
self.restoreGeometry (settings.value ("geometry" ))
|
||||||
|
self.restoreState (settings.value ("windowState"))
|
||||||
|
settings.endGroup ()
|
||||||
|
# end def _restore_settings
|
||||||
|
|
||||||
|
def save_settings (self) :
|
||||||
|
settings = self.settings
|
||||||
|
settings.beginGroup ("MainWindow")
|
||||||
|
settings.setValue ("geometry", self.saveGeometry ())
|
||||||
|
settings.setValue ("windowState", self.saveState ())
|
||||||
|
settings.endGroup ()
|
||||||
|
# end def save_settings
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run (cls, settings) :
|
||||||
|
QtWidgets.QApplication.setStyle ("macintosh")
|
||||||
|
app = QtWidgets.QApplication ([])
|
||||||
|
if cls.pre_main_window_action (settings) :
|
||||||
|
self = cls (app, settings)
|
||||||
|
if self.isVisible () :
|
||||||
|
app.exec_ ()
|
||||||
|
# end def run
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def pre_main_window_action (cls, settings) :
|
||||||
|
return True
|
||||||
|
# end def pre_main_window_action
|
||||||
|
|
||||||
|
# end class Main_Window
|
||||||
|
|
||||||
|
### __END__ Main_Window
|
||||||
|
|
@ -0,0 +1,448 @@
|
||||||
|
# Simplified tree model (based on a QtAbstractItemModel)
|
||||||
|
|
||||||
|
from PySide2 import QtCore, QtWidgets
|
||||||
|
from Accessor import Getter
|
||||||
|
import contextlib
|
||||||
|
|
||||||
|
Qt = QtCore.Qt
|
||||||
|
|
||||||
|
class Column :
|
||||||
|
"""Column definition"""
|
||||||
|
|
||||||
|
Flag_Map = dict \
|
||||||
|
( no_flag = (Qt.NoItemFlags, False)
|
||||||
|
, selectable = (Qt.ItemIsSelectable, True)
|
||||||
|
, enabled = (Qt.ItemIsEnabled, True)
|
||||||
|
, editable = (Qt.ItemIsEditable, False)
|
||||||
|
, drag = (Qt.ItemIsDragEnabled, False)
|
||||||
|
, drop = (Qt.ItemIsDropEnabled, False)
|
||||||
|
, checkable = (Qt.ItemIsUserCheckable, False)
|
||||||
|
, tristate = (Qt.ItemIsTristate, False)
|
||||||
|
)
|
||||||
|
|
||||||
|
Clone_Attributes = ("name", "attr", "getter", "_flags", "model")
|
||||||
|
|
||||||
|
def __init__ ( self, name, attr = None, getter = None, model = None
|
||||||
|
, ** flags
|
||||||
|
) :
|
||||||
|
self.name = name
|
||||||
|
self.attr = attr or name.lower ()
|
||||||
|
self.getter = getter or getattr (Getter, self.attr)
|
||||||
|
self.model = model
|
||||||
|
self._flags = flags
|
||||||
|
# end def __init__
|
||||||
|
|
||||||
|
def background (self, row) :
|
||||||
|
return None
|
||||||
|
# end def background
|
||||||
|
|
||||||
|
def __call__ (self, row) :
|
||||||
|
return self.getter (row)
|
||||||
|
# end def __call__
|
||||||
|
|
||||||
|
def clone (self, ** overrides) :
|
||||||
|
d = dict \
|
||||||
|
( (a, overrides.get (a, getattr (self, a)))
|
||||||
|
for a in self.Clone_Attributes
|
||||||
|
)
|
||||||
|
d.update (d.pop ("_flags", {}))
|
||||||
|
return self.__class__ (** d)
|
||||||
|
# end def clone
|
||||||
|
|
||||||
|
def checkstate (self, row) :
|
||||||
|
return None
|
||||||
|
# end def checkstate
|
||||||
|
|
||||||
|
def decoration (self, row) :
|
||||||
|
return None
|
||||||
|
# end def decoration
|
||||||
|
|
||||||
|
def flags (self, row) :
|
||||||
|
result = 0
|
||||||
|
for attr, (flag, default) in self.Flag_Map.items () :
|
||||||
|
v = self._flags.get (attr, default)
|
||||||
|
if callable (v) :
|
||||||
|
v = v (row)
|
||||||
|
if v :
|
||||||
|
result |= flag
|
||||||
|
return result
|
||||||
|
# end def flags
|
||||||
|
|
||||||
|
def font (self, row) :
|
||||||
|
return None
|
||||||
|
# end def font
|
||||||
|
|
||||||
|
def foreground (self, row) :
|
||||||
|
return None
|
||||||
|
# end def foreground
|
||||||
|
|
||||||
|
def text_aligment (self, row) :
|
||||||
|
return None
|
||||||
|
# end def text_aligment
|
||||||
|
|
||||||
|
# end class Column
|
||||||
|
|
||||||
|
class _Root_Item_ :
|
||||||
|
"""Simple models which can be used as hidden root element of no real root
|
||||||
|
element exists in the model
|
||||||
|
"""
|
||||||
|
parent = None
|
||||||
|
|
||||||
|
def __init__ (self, * children) :
|
||||||
|
self.children = []
|
||||||
|
for c in children :
|
||||||
|
self.append (c)
|
||||||
|
# end def __init__
|
||||||
|
|
||||||
|
def append (self, child) :
|
||||||
|
self.children.append (child)
|
||||||
|
child.parent = self
|
||||||
|
# end def append
|
||||||
|
|
||||||
|
def index (self, child) :
|
||||||
|
return self.children.index (child)
|
||||||
|
# end def index
|
||||||
|
|
||||||
|
def __delitem__ (self, key) :
|
||||||
|
del self.children [key]
|
||||||
|
# end def __delitem__
|
||||||
|
|
||||||
|
def __getitem__ (self, key) :
|
||||||
|
return self.children [key]
|
||||||
|
# end def __getitem__
|
||||||
|
|
||||||
|
def __len__ (self) :
|
||||||
|
return len (self.children)
|
||||||
|
# end def __len__
|
||||||
|
|
||||||
|
def __setitem__ (self, key, value) :
|
||||||
|
self.children [key] = value
|
||||||
|
if not isinstance (value, (list, tuple)) :
|
||||||
|
value = (value, )
|
||||||
|
for v in value :
|
||||||
|
v.parent = self
|
||||||
|
# end def __setitem__
|
||||||
|
|
||||||
|
def __str__ (self) :
|
||||||
|
return "<Root-Item>"
|
||||||
|
# end def __str__
|
||||||
|
|
||||||
|
# end class _Root_Item_
|
||||||
|
|
||||||
|
class Model_Adapter (QtCore.QAbstractItemModel) :
|
||||||
|
"""The underlying QT class handling the interface to the wrapper class
|
||||||
|
"""
|
||||||
|
|
||||||
|
### QT Interface
|
||||||
|
def columnCount (self, parent) :
|
||||||
|
return len (self.Columns)
|
||||||
|
# end def columnCount
|
||||||
|
|
||||||
|
def data (self, index, role) :
|
||||||
|
#print ("data", role)
|
||||||
|
if not index.isValid () :
|
||||||
|
return None
|
||||||
|
column = index.column ()
|
||||||
|
item = index.internalPointer ()
|
||||||
|
col_desc = self.Columns [column]
|
||||||
|
if role == Qt.DisplayRole or role == Qt.EditRole :
|
||||||
|
return col_desc (item)
|
||||||
|
elif role == Qt.CheckStateRole :
|
||||||
|
return col_desc.checkstate (item)
|
||||||
|
elif role == Qt.BackgroundRole :
|
||||||
|
return col_desc.background (item)
|
||||||
|
elif role == Qt.ForegroundRole :
|
||||||
|
return col_desc.foreground (item)
|
||||||
|
elif role == Qt.FontRole :
|
||||||
|
return col_desc.font (item)
|
||||||
|
elif role == Qt.DecorationRole :
|
||||||
|
return col_desc.decoration (item)
|
||||||
|
elif role == Qt.TextAlignmentRole :
|
||||||
|
return col_desc.text_aligment (item)
|
||||||
|
return None
|
||||||
|
# end def data
|
||||||
|
|
||||||
|
def flags (self, index) :
|
||||||
|
if index.isValid () :
|
||||||
|
data = index.internalPointer ()
|
||||||
|
col = index.column ()
|
||||||
|
return self.Columns [col].flags (data)
|
||||||
|
return super ().flags (index)
|
||||||
|
# end def flags
|
||||||
|
|
||||||
|
def index (self, row, column, parent_index, parent = None) :
|
||||||
|
#debug = "ID: %d <%-7s>" % \
|
||||||
|
# (row, self.item_path (parent_index, ", ") or "R")
|
||||||
|
if parent is None :
|
||||||
|
if not parent_index.isValid () :
|
||||||
|
parent = self.root_item
|
||||||
|
else :
|
||||||
|
parent = parent_index.internalPointer ()
|
||||||
|
try :
|
||||||
|
child = parent [row]
|
||||||
|
#print ("%s, P<%s>, C<%s>" %(1, parent, child))
|
||||||
|
return self.createIndex (row, column, child)
|
||||||
|
except IndexError as exc:
|
||||||
|
#print (debug, exc)
|
||||||
|
return self.invalid_index
|
||||||
|
# end def index
|
||||||
|
|
||||||
|
def index_for_item (self, item, column = 0) :
|
||||||
|
if item.parent :
|
||||||
|
row = item.parent.index (item)
|
||||||
|
return self.createIndex (row, column, item)
|
||||||
|
return self.invalid_index
|
||||||
|
# end def index_for_item
|
||||||
|
|
||||||
|
def item_from_index (self, index) :
|
||||||
|
if index.isValid () :
|
||||||
|
return index.internalPointer ()
|
||||||
|
# end def item_from_index
|
||||||
|
|
||||||
|
@property
|
||||||
|
def invalid_index (self) :
|
||||||
|
return QtCore.QModelIndex ()
|
||||||
|
# end def invalid_index
|
||||||
|
|
||||||
|
def parent (self, index) :
|
||||||
|
if not index.isValid () :
|
||||||
|
return self.invalid_index
|
||||||
|
item = index.internalPointer ()
|
||||||
|
parent = item.parent
|
||||||
|
if parent is self.root_item :
|
||||||
|
return self.invalid_index
|
||||||
|
if parent.parent :
|
||||||
|
row = parent.parent.index (parent)
|
||||||
|
else :
|
||||||
|
row = 0
|
||||||
|
return self.createIndex (row, 0, parent)
|
||||||
|
# end def parent
|
||||||
|
|
||||||
|
def rowCount (self, parent_index) :
|
||||||
|
if not parent_index.isValid () :
|
||||||
|
parent = self.root_item
|
||||||
|
else:
|
||||||
|
parent = parent_index.internalPointer ()
|
||||||
|
#path = self.item_path (parent_index, ", ") or "R"
|
||||||
|
#print ("RC: %-7s [%d]" % (path, len (parent)))
|
||||||
|
return len (parent)
|
||||||
|
# end def rowCount
|
||||||
|
|
||||||
|
def setData (self, index, value, role) :
|
||||||
|
if index.isValid () :
|
||||||
|
if self.set_data (index, value, role) :
|
||||||
|
self.dataChanged.emit (index, index)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
# end def setData
|
||||||
|
|
||||||
|
### QT Optional
|
||||||
|
def headerData (self, section, orientation, role) :
|
||||||
|
if ( (orientation == Qt.Horizontal)
|
||||||
|
and (role == Qt.DisplayRole)
|
||||||
|
) :
|
||||||
|
return self.Columns [section].name
|
||||||
|
return None
|
||||||
|
# end def headerData
|
||||||
|
|
||||||
|
def hasChildren (self, index) :
|
||||||
|
result = True
|
||||||
|
if index.isValid () :
|
||||||
|
result = bool (len (index.internalPointer ()))
|
||||||
|
#path = self.item_path (parent_index, ", ") or "R"
|
||||||
|
#print ("HC: %-7s [%s]" % (path, result))
|
||||||
|
return result
|
||||||
|
# end def hasChildren
|
||||||
|
|
||||||
|
### mime data handling
|
||||||
|
def supportedDropActions (self) :
|
||||||
|
default = super ().supportedDropActions ()
|
||||||
|
return getattr (self, "supported_drop_actions", default)
|
||||||
|
# end def supportedDropActions
|
||||||
|
|
||||||
|
def mimeTypes (self) :
|
||||||
|
model_fct = getattr (self, "mime_types", None)
|
||||||
|
result = super ().mimeTypes ()
|
||||||
|
if model_fct is not None :
|
||||||
|
result = model_fct (result)
|
||||||
|
return result
|
||||||
|
# end def mimeTypes
|
||||||
|
|
||||||
|
def mimeData (self, indexes) :
|
||||||
|
model_fct = getattr (self, "mime_data", None)
|
||||||
|
if model_fct :
|
||||||
|
items = [i.internalPointer () for i in indexes]
|
||||||
|
result = QtCore.QMimeData ()
|
||||||
|
model_fct (result, items, indexes)
|
||||||
|
return result
|
||||||
|
return super ().mimeData (indexes)
|
||||||
|
# end def mimeData
|
||||||
|
|
||||||
|
def dropMimeData (self, mime_data, action, row, column, parent) :
|
||||||
|
model_fct = getattr (self, "drop_mime_data", None)
|
||||||
|
if model_fct is None :
|
||||||
|
return super ().dropMimeData \
|
||||||
|
(mime_data, action, row, column, parent)
|
||||||
|
return model_fct \
|
||||||
|
(mime_data, action, row, column, parent)
|
||||||
|
# end def dropMimeData
|
||||||
|
|
||||||
|
### Python Interface
|
||||||
|
Columns = ()
|
||||||
|
Supported_Drop_Actions = ()
|
||||||
|
mimeTypes = ()
|
||||||
|
|
||||||
|
def __init__ (self, * items, ** kw) :
|
||||||
|
super ().__init__ ()
|
||||||
|
self.Columns = [c.clone (model = self) for c in self.Columns]
|
||||||
|
root_item = kw.pop ("root", None)
|
||||||
|
if root_item is None :
|
||||||
|
root_item = _Root_Item_ (* items)
|
||||||
|
self.root_item = root_item
|
||||||
|
# end def __init__
|
||||||
|
|
||||||
|
def append (self, item, parent = None) :
|
||||||
|
if parent is None :
|
||||||
|
parent = self.root_item
|
||||||
|
start = len (parent)
|
||||||
|
index = self.index_for_item (parent)
|
||||||
|
self.beginInsertRows (index, start, start)
|
||||||
|
parent.append (item)
|
||||||
|
self.endInsertRows ()
|
||||||
|
# end def append
|
||||||
|
|
||||||
|
def dump (self, root_index = None, indend = "") :
|
||||||
|
if root_index is None :
|
||||||
|
root_index = self.invalid_index
|
||||||
|
result = []
|
||||||
|
for i in range (self.rowCount (root_index)) :
|
||||||
|
index = self.index (i, 0, root_index)
|
||||||
|
item = self.item_from_index (index)
|
||||||
|
result.append ("%s%s" % (indend, item))
|
||||||
|
result.extend (self.dump (index, indend + "."))
|
||||||
|
if not indend :
|
||||||
|
print ("---- Dump by index functions")
|
||||||
|
print ("\n".join (result))
|
||||||
|
print ("---- Dump end")
|
||||||
|
return result
|
||||||
|
# end def dump
|
||||||
|
|
||||||
|
def _walk (self, path, root, root_index = None) :
|
||||||
|
for n in range (len (root)) :
|
||||||
|
c = root [n]
|
||||||
|
p = path + (n, )
|
||||||
|
if root_index is not None :
|
||||||
|
index = self.index (n, 0, root_index)
|
||||||
|
yield p, c, index
|
||||||
|
yield from self._walk (p, c, index)
|
||||||
|
else :
|
||||||
|
yield p, c
|
||||||
|
yield from self._walk (p, c)
|
||||||
|
# end def _walk
|
||||||
|
|
||||||
|
def walk (self, with_index = False) :
|
||||||
|
index = None
|
||||||
|
if with_index :
|
||||||
|
index = self.invalid_index
|
||||||
|
return self._walk ((), self.root_item, index)
|
||||||
|
# end def walk
|
||||||
|
|
||||||
|
def item_path (self, index, joiner = None) :
|
||||||
|
result = []
|
||||||
|
if index.isValid () :
|
||||||
|
result.extend (self.item_path (self.parent (index)))
|
||||||
|
result.append (index.row ())
|
||||||
|
if joiner :
|
||||||
|
result = joiner.join (result)
|
||||||
|
return result
|
||||||
|
# end def item_path
|
||||||
|
|
||||||
|
def qindex (self, item, col = 0) :
|
||||||
|
if item is self.root_item :
|
||||||
|
row = 0
|
||||||
|
else :
|
||||||
|
row = item.parent.index (item)
|
||||||
|
return self.createIndex (row, col, item.parent)
|
||||||
|
# end def qindex
|
||||||
|
|
||||||
|
def insert_row (self, item, parent_index = None, start = -1) :
|
||||||
|
count = 1
|
||||||
|
parent_index = parent_index or self.invalid_index
|
||||||
|
if start == -1 :
|
||||||
|
start = self.rowCount (parent_index)
|
||||||
|
if parent_index.isValid () :
|
||||||
|
parent = parent_index.internalPointer ()
|
||||||
|
else :
|
||||||
|
parent = self.root_item
|
||||||
|
self.beginInsertRows (parent_index, start, start + count - 1)
|
||||||
|
parent [start:start] = [item]
|
||||||
|
self.endInsertRows ()
|
||||||
|
return self.index (start, 0, parent_index)
|
||||||
|
# end def insert_row
|
||||||
|
|
||||||
|
def item_from_index (self, index) :
|
||||||
|
if index.isValid () :
|
||||||
|
return index.internalPointer ()
|
||||||
|
# end def item_from_index
|
||||||
|
|
||||||
|
def remove (self, index = None, item = None) :
|
||||||
|
if index is None :
|
||||||
|
parent = item.parent
|
||||||
|
row = parent.index (item)
|
||||||
|
parent_index = self.qindex (parent)
|
||||||
|
else :
|
||||||
|
row = index.row ()
|
||||||
|
parent_index = index.parent ()
|
||||||
|
if parent_index.isValid () :
|
||||||
|
parent = parent_index.internalPointer ()
|
||||||
|
else :
|
||||||
|
parent = self.root_item
|
||||||
|
item = parent [row]
|
||||||
|
self.beginRemoveRows (parent_index, row, row + 1)
|
||||||
|
del parent [row]
|
||||||
|
if hasattr (item, "delete") :
|
||||||
|
item.delete ()
|
||||||
|
self.endRemoveRows ()
|
||||||
|
# end def remove
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def replace_model (self) :
|
||||||
|
self.beginResetModel ()
|
||||||
|
yield
|
||||||
|
self.endResetModel ()
|
||||||
|
# end def replace_model
|
||||||
|
|
||||||
|
def set_data (self, index, value, role) :
|
||||||
|
return False
|
||||||
|
# end def set_data
|
||||||
|
|
||||||
|
# end class Model_Adapter
|
||||||
|
|
||||||
|
class Tree_View (QtWidgets.QTreeView) :
|
||||||
|
|
||||||
|
def expanded_nodes (self) :
|
||||||
|
expanded_path = []
|
||||||
|
model = self.model ()
|
||||||
|
if model :
|
||||||
|
for p, _, index in model.walk (True) :
|
||||||
|
if self.isExpanded (index) :
|
||||||
|
expanded_path.append (p)
|
||||||
|
return expanded_path
|
||||||
|
# end def expanded_nodes
|
||||||
|
|
||||||
|
def restore_expanded_nodes (self, expanded) :
|
||||||
|
model = self.model ()
|
||||||
|
if model :
|
||||||
|
indixes = {}
|
||||||
|
iv_index = model.invalid_index
|
||||||
|
for path in expanded :
|
||||||
|
parent_index = indixes.get (path [:-1], iv_index)
|
||||||
|
index = model.index (path [-1], 0, parent_index)
|
||||||
|
indixes [path] = index
|
||||||
|
item = model.item_from_index (index)
|
||||||
|
if item and len (item) :
|
||||||
|
self.setExpanded (index, True)
|
||||||
|
# end def restore_expanded_nodes
|
||||||
|
|
||||||
|
# end class Tree_View
|
||||||
|
### __END__ QT.Model_Adapter
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
from PySide2 import QtWidgets, QtGui
|
||||||
|
|
||||||
|
|
||||||
|
def Push_Button (text, clicked = None, icon = None) :
|
||||||
|
button = QtWidgets.QPushButton (text)
|
||||||
|
if clicked :
|
||||||
|
button.clicked.connect (clicked)
|
||||||
|
if icon :
|
||||||
|
button.setIcon (QtGui.QIcon (icon))
|
||||||
|
return button
|
||||||
|
# end def Push_Button
|
||||||
|
|
||||||
|
#class Push_Button (QtWidgets.QPushButton) :
|
||||||
|
#
|
||||||
|
# def __init__ ( self, text
|
||||||
|
# , callback = None
|
||||||
|
# , icon = None
|
||||||
|
# ) :
|
||||||
|
# super ().__init__ (text)
|
||||||
|
# if callback :
|
||||||
|
# self.clicked.connect (callback)
|
||||||
|
# if icon :
|
||||||
|
# self.setIcon (QtGui.QIcon (icon))
|
||||||
|
# # end def
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
[TempSettings]
|
||||||
|
settingsFile=@Invalid()
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
### package for commone QT classes
|
||||||
|
from PySide6 import QtWidgets, QtCore, QtGui, QtCore
|
||||||
|
QT = QtCore.Qt
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue