diff --git a/examples/customsortfiltermodel/main.go b/examples/customsortfiltermodel/main.go new file mode 100644 index 00000000..c7f51179 --- /dev/null +++ b/examples/customsortfiltermodel/main.go @@ -0,0 +1,109 @@ +package main + +import ( + "fmt" + qt "github.com/mappu/miqt/qt6" + "os" +) + +func GetTreeView(parent *qt.QWidget) *qt.QTreeView { + treeView := qt.NewQTreeView(parent) + treeView.SetAlternatingRowColors(true) + treeView.SetSortingEnabled(true) + treeView.SetColumnWidth(0, 300) + treeView.SetContentsMargins(0, 0, 0, 0) + treeView.Header().SetDefaultSectionSize(200) + treeView.Header().SetStretchLastSection(true) + treeView.SetSelectionMode(qt.QAbstractItemView__ExtendedSelection) + + return treeView +} + +func PopulateData(rootItem *TreeItem) { + cellData := make([]*TreeCell, 0) + cellData = append(cellData, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("Big File"))) + cellData = append(cellData, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("10.7 MiB"))) + item := NewTreeItem(cellData, rootItem, false) + err := item.SetData(1, qt.NewQVariant6(11225400), qt.UserRole) + if err != nil { + fmt.Printf("Error setting UserData: %v\n", err) + } + err = item.SetData(0, qt.NewQVariant11("Big File"), qt.UserRole) + if err != nil { + fmt.Printf("Error setting UserData: %v\n", err) + } + rootItem.AppendChild(&item) + + cellData2 := make([]*TreeCell, 0) + cellData2 = append(cellData2, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("Small File"))) + cellData2 = append(cellData2, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("110 Bytes"))) + item2 := NewTreeItem(cellData2, rootItem, false) + err = item2.SetData(1, qt.NewQVariant6(110), qt.UserRole) + if err != nil { + fmt.Printf("Error setting UserData: %v\n", err) + } + err = item.SetData(0, qt.NewQVariant11("Small File"), qt.UserRole) + if err != nil { + fmt.Printf("Error setting UserData: %v\n", err) + } + rootItem.AppendChild(&item2) + + cellData3 := make([]*TreeCell, 0) + cellData3 = append(cellData3, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("Medium File"))) + cellData3 = append(cellData3, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("109.5 KiB"))) + item3 := NewTreeItem(cellData3, rootItem, false) + err = item3.SetData(1, qt.NewQVariant6(112200), qt.UserRole) + if err != nil { + fmt.Printf("Error setting UserData: %v\n", err) + } + err = item.SetData(0, qt.NewQVariant11("Medium File"), qt.UserRole) + if err != nil { + fmt.Printf("Error setting UserData: %v\n", err) + } + rootItem.AppendChild(&item3) +} + +func GetDialog() *qt.QDialog { + dialog := qt.NewQDialog3(nil, qt.Dialog) + dialog.SetWindowFlags(qt.WindowStaysOnTopHint) + dialogLayout := qt.NewQVBoxLayout2() + dialogLayout.SetSpacing(0) + dialogLayout.SetContentsMargins(0, 0, 0, 0) + dialog.SetContentsMargins(10, 10, 10, 10) + dialog.SetLayout(dialogLayout.Layout()) + dialog.SetWindowTitle("Example Sort Model Usage") + + treeView := GetTreeView(dialog.QWidget) + + // Model + model, rootItem := GetModel(dialog.QObject) + PopulateData(rootItem) + + sortModel := qt.NewQSortFilterProxyModel2(treeView.QObject) + sortModel.SetSortRole(int(qt.UserRole)) + sortModel.OnLessThan(func(super func(source_left *qt.QModelIndex, source_right *qt.QModelIndex) bool, source_left *qt.QModelIndex, source_right *qt.QModelIndex) bool { + // In our case we know that the data from our TreeItem will come back as an int for our UserRole + leftData := sortModel.SourceModel().Data(source_left, sortModel.SortRole()) + rightData := sortModel.SourceModel().Data(source_right, sortModel.SortRole()) + + if source_left.Column() == 0 { + return leftData.ToString() < rightData.ToString() + } + return leftData.ToLongLong() < rightData.ToLongLong() + }) + + sortModel.SetSourceModel(model) + treeView.SetModel(sortModel.QAbstractItemModel) + + dialogLayout.AddWidget3(treeView.QWidget, 0, qt.AlignCenter) + return dialog +} + +func main() { + qt.NewQApplication(os.Args) + + dialog := GetDialog() + dialog.Show() + + qt.QApplication_Exec() +} diff --git a/examples/customsortfiltermodel/model.go b/examples/customsortfiltermodel/model.go new file mode 100644 index 00000000..8429569b --- /dev/null +++ b/examples/customsortfiltermodel/model.go @@ -0,0 +1,94 @@ +package main + +import ( + qt "github.com/mappu/miqt/qt6" + "slices" + "unsafe" +) + +func GetModel(parent *qt.QObject) (*qt.QAbstractItemModel, *TreeItem) { + model := qt.NewQAbstractItemModel2(parent) + + data := make([]*TreeCell, 0) + data = append(data, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("Name"))) + data = append(data, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("Size"))) + rootItem := NewTreeItem(data, nil, true) + + model.OnData(func(index *qt.QModelIndex, role int) *qt.QVariant { + if !index.IsValid() { + return qt.NewQVariant() + } + if !slices.Contains([]qt.ItemDataRole{qt.DisplayRole, qt.UserRole}, qt.ItemDataRole(role)) { + return qt.NewQVariant() + } + item := (*TreeItem)(index.InternalPointer()) + return item.Data(index.Column(), qt.ItemDataRole(role)) + }) + + model.OnHeaderData(func(super func(section int, orientation qt.Orientation, role int) *qt.QVariant, section int, orientation qt.Orientation, role int) *qt.QVariant { + if qt.ItemDataRole(role) != qt.DisplayRole { + return qt.NewQVariant() + } + if orientation == qt.Horizontal && role == int(qt.DisplayRole) { + return rootItem.Data(section, qt.DisplayRole) + } + return qt.NewQVariant() + }) + + model.OnIndex(func(row int, column int, parent *qt.QModelIndex) *qt.QModelIndex { + if !model.HasIndex3(row, column, parent) { + return qt.NewQModelIndex() + } + var parentItem *TreeItem + if !parent.IsValid() { + parentItem = &rootItem + } else { + parentItem = (*TreeItem)(parent.InternalPointer()) + } + child, err := parentItem.Child(row) + if err != nil { + return qt.NewQModelIndex() + } + newIndex := model.CreateIndex2(row, column, uintptr(unsafe.Pointer(child))) + return &newIndex + }) + + model.OnParent(func(child *qt.QModelIndex) *qt.QModelIndex { + if !child.IsValid() { + return qt.NewQModelIndex() + } + parentItem := (*TreeItem)(child.InternalPointer()).ParentItem() + if parentItem != &rootItem { + row, err := parentItem.Row() + if err != nil { + return qt.NewQModelIndex() + } + index := model.CreateIndex2(row, 0, uintptr(unsafe.Pointer(parentItem))) + return &index + } + return qt.NewQModelIndex() + }) + + model.OnRowCount(func(parent *qt.QModelIndex) int { + if parent.Column() > 0 { + return 0 + } + var item *TreeItem + if !parent.IsValid() { + item = &rootItem + } else { + item = (*TreeItem)(parent.InternalPointer()) + } + return item.ChildCount() + }) + + model.OnColumnCount(func(parent *qt.QModelIndex) int { + if parent.IsValid() { + item := (*TreeItem)(parent.InternalPointer()) + return item.ColumnCount() + } + return rootItem.ColumnCount() + }) + + return model, &rootItem +} diff --git a/examples/customsortfiltermodel/tree_cell.go b/examples/customsortfiltermodel/tree_cell.go new file mode 100644 index 00000000..3635c16e --- /dev/null +++ b/examples/customsortfiltermodel/tree_cell.go @@ -0,0 +1,33 @@ +package main + +import ( + "fmt" + qt "github.com/mappu/miqt/qt6" + "strconv" +) + +type TreeCell struct { + data map[qt.ItemDataRole]string +} + +func NewTreeCell(role qt.ItemDataRole, value qt.QVariant) *TreeCell { + data := make(map[qt.ItemDataRole]string) + data[role] = value.ToString() + return &TreeCell{data: data} +} + +func (cell *TreeCell) SetData(data qt.QVariant, role qt.ItemDataRole) { + cell.data[role] = data.ToString() +} + +func (cell *TreeCell) Data(role qt.ItemDataRole) *qt.QVariant { + if role == qt.UserRole { + number, err := strconv.ParseInt(cell.data[role], 10, 64) + if err != nil { + fmt.Printf("Error converting %s to int: %v\n", number, err) + return qt.NewQVariant11(cell.data[role]) + } + return qt.NewQVariant6(number) + } + return qt.NewQVariant11(cell.data[role]) +} diff --git a/examples/customsortfiltermodel/tree_item.go b/examples/customsortfiltermodel/tree_item.go new file mode 100644 index 00000000..d6ba0fa4 --- /dev/null +++ b/examples/customsortfiltermodel/tree_item.go @@ -0,0 +1,82 @@ +package main + +import ( + "fmt" + "slices" + + qt "github.com/mappu/miqt/qt6" +) + +type TreeItem struct { + data []*TreeCell + parent *TreeItem + children []*TreeItem + isRoot bool +} + +func NewTreeItem(data []*TreeCell, parent *TreeItem, isRoot bool) TreeItem { + return TreeItem{ + data: data, + parent: parent, + isRoot: isRoot, + } +} + +func (self *TreeItem) IsRoot() bool { + return self.isRoot +} + +func (self *TreeItem) AppendChild(child *TreeItem) { + self.children = append(self.children, child) +} + +func (self *TreeItem) Child(row int) (*TreeItem, error) { + if row >= 0 && row <= self.ChildCount() { + return self.children[row], nil + } + return nil, fmt.Errorf("TreeItem does not have child at row %d", row) +} + +func (self *TreeItem) ColumnCount() int { + return len(self.data) +} + +func (self *TreeItem) ChildCount() int { + return len(self.children) +} + +func (self *TreeItem) Data(column int, role qt.ItemDataRole) *qt.QVariant { + if column >= 0 && column < len(self.data) { + if !slices.Contains([]qt.ItemDataRole{qt.DisplayRole, qt.UserRole}, role) { + return qt.NewQVariant() + } + return self.data[column].Data(role) + } + return qt.NewQVariant() +} + +func (self *TreeItem) SetData(column int, value *qt.QVariant, role qt.ItemDataRole) error { + if column >= 0 && column < len(self.data) { + self.data[column].SetData(*value, role) + } else { + cell := NewTreeCell(role, *value) + self.data = append(self.data, cell) + } + return nil +} + +func (self *TreeItem) Row() (int, error) { + if self.parent == nil { + return 0, nil + } + for index, child := range self.parent.children { + if child == self { + return index, nil + } + } + return 0, fmt.Errorf("could not find child in its parent") +} + +func (self *TreeItem) ParentItem() *TreeItem { + return self.parent +}