therecipe / qt

Qt binding for Go (Golang) with support for Windows / macOS / Linux / FreeBSD / Android / iOS / Sailfish OS / Raspberry Pi / AsteroidOS / Ubuntu Touch / JavaScript / WebAssembly
GNU Lesser General Public License v3.0
10.5k stars 748 forks source link

Nested structs with library interface references in listview #1222

Open doitandbedone opened 3 years ago

doitandbedone commented 3 years ago

Hello, I'm having troubles with some nested structs within a listview. Here's the code to illustrate:

main.go: Main file where I propagate init calls.

func init() {
    model.Init()
}

func main() {
    core.QCoreApplication_SetAttribute(core.Qt__AA_EnableHighDpiScaling, true)

    app := widgets.NewQApplication(len(os.Args), os.Args)

    view := quick.NewQQuickView(nil)

    view.SetTitle("My title")
    view.SetResizeMode(quick.QQuickView__SizeRootObjectToView)
    view.SetSource(core.NewQUrl3("qrc:/qml/app.qml", 0))
    view.Show()

    app.Exec()
}

/qml/app.qml: Just holds the UI

import QtQuick 2.10             //ListView
import QtQuick.Controls 2.3     //Button
import QtQuick.Layouts 1.3      //ColumnLayout
import CustomQmlTypes 1.0       //CustomListModel
import QtQuick.Dialogs 1.0

Item {
    width: 500
    height: 500

    ColumnLayout {
        anchors.fill: parent

        RowLayout {

            Layout.fillWidth: true

            id: rowLayout
            anchors.fill: parent
            TextField {
                placeholderText: "This wants to grow horizontally"
                Layout.fillWidth: true
            }
            Button {
                text: "Select Folder..."
                onClicked: fileDialog.open()
            }
            FileDialog {
                id: fileDialog
                title: "Please choose a folder"
                selectFolder: true
                folder: shortcuts.home
                onAccepted: {
                    console.log("You chose: " + fileDialog.folder)
                    lvFiles.model.getFileList(fileDialog.folder)
                }
                onRejected: {
                    console.log("Canceled")
                    Qt.quit()
                }
            }
        }

        ListView {
            id: lvFiles

            Layout.fillWidth: true
            Layout.fillHeight: true

            model: CustomListModel{}
            delegate: Text {
                text: display
            }
        }
    }
}

model/model.go: Main model class where ModelData includes the struct FilePath. If I use a simpler type like string it works fine, but when using a struct the UI no longer shows up.

func Init() { CustomListModel_QmlRegisterType2("CustomQmlTypes", 1, 0, "CustomListModel") }

type ModelData struct {
    MD5  string
    File io.FilePath
}

type CustomListModel struct {
    core.QAbstractListModel

    _ func()                   `constructor:"init"`
    _ func(obj *core.QVariant) `signal:"getFileList,auto"`

    modelData []ModelData
}

func (m *CustomListModel) getFileList(item *core.QVariant) {
    var result []ModelData
    files, err := arkio.GetFileList(item.ToString())
    if err != nil {
        return
    }
    for _, filepath := range files {
        file, err := os.Open(filepath.Path)
        if err != nil {
            result = append(result, ModelData{"nil", filepath})
        }
        defer file.Close()

        hash := md5.New()

        if _, err := io.Copy(hash, file); err != nil {
            result = append(result, ModelData{"nil", filepath})
        }
        hashInBytes := hash.Sum(nil)[:16]
        hashedFile := ModelData{hex.EncodeToString(hashInBytes), filepath}
        result = append(result, hashedFile)
    }
    m.modelData = []ModelData{}
    for _, item := range result {
        m.BeginInsertRows(core.NewQModelIndex(), len(m.modelData), len(m.modelData))
        m.modelData = append(m.modelData, item)
        m.EndInsertRows()
    }
}

io/io.go: file where FilePath struct is defined. Even if the nested struct works, would os.FileInfo become an issue? How it it be signaled/represented?

type FilePath struct {
    Path string
    Info os.FileInfo
}

func GetFileList(path string) ([]FilePath, error) {
    var files []FilePath
    err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
        files = append(files, FilePath{path, info})
        return nil
    })
    if err != nil {
        return nil, err
    }
    for _, file := range files {
        fmt.Println(file.Path)
    }
    return files, nil
}

I saw a few nested examples but it seems to use New() and seems to be very hard to maintain the code, is it possible to follow what core.QAbstractListModel does and allow structs?

Thanks in advance!