package ui import ( "cwtch.im/cwtch/model" "cwtch.im/ui/go/the" "encoding/hex" "git.openprivacy.ca/openprivacy/log" "github.com/therecipe/qt/core" "reflect" "strings" ) type MessageModel struct { core.QAbstractTableModel ackIdx int handle string _ func(string) `signal:"setHandle,auto"` _ map[int]*core.QByteArray `property:"roles"` _ func() `constructor:"init"` _ func(int) `signal:"addMessage,auto"` _ func(int) `signal:"editMessage,auto"` _ func() `signal:"requestEIR,auto"` _ func(string) string `slot:"getNick,auto"` _ func(string) string `slot:"getImage,auto"` } type MessageWrapper struct { model.Message core.QObject Timestamp int64 PeerID string Acknowledged bool RawMessage string Error string Day string Signature string _ bool `property:"ackd"` } func (this *MessageModel) Handle() string{ return this.handle } func (this *MessageModel) setHandle(handle string) { this.handle = handle } func (this *MessageModel) init() { mdt := reflect.TypeOf([]MessageWrapper{}).Elem() roles := make(map[int]*core.QByteArray) for i := 0; i < mdt.NumField(); i++ { if mdt.Field(i).Name == "Acknowledged" { this.ackIdx = int(core.Qt__UserRole) + 1 + i } roles[int(core.Qt__UserRole) + 1 + i] = core.NewQByteArray2(mdt.Field(i).Name, -1) } roles[int(core.Qt__DisplayRole)] = core.NewQByteArray2("display", -1) this.SetRoles(roles) this.ConnectData(this.data) this.ConnectRowCount(this.rowCount) this.ConnectColumnCount(this.columnCount) this.ConnectHeaderData(this.headerData) this.ConnectRoleNames(this.roleNames) } func (this *MessageModel) roleNames() map[int]*core.QByteArray { return this.Roles() } func (this *MessageModel) isGroup() bool { return len(this.Handle()) == 32 } func (this *MessageModel) getNick(handle string) string { return GetNick(handle) } func (this *MessageModel) getImage(handle string) string { return GetProfilePic(handle) } func (this *MessageModel) num() int { if this.Handle() == "" || the.Peer == nil { log.Debugf("MessageModel.num: early returning 0") return 0 } if this.isGroup() { group := the.Peer.GetGroup(this.Handle()) if group != nil { return len(group.Timeline.Messages) + len(group.UnacknowledgedMessages) } } else { contact := the.Peer.GetContact(this.Handle()) if contact != nil { return len(contact.Timeline.Messages) } } log.Warnf("MessageModel.num: group/contact was nil, returning 0") return 0 } func (this *MessageModel) getMessage(idx int) *MessageWrapper { var modelmsg model.Message var ackd bool if this.isGroup() { group := the.Peer.GetGroup(this.Handle()) if idx >= len(group.Timeline.Messages) { modelmsg = group.UnacknowledgedMessages[idx - len(group.Timeline.Messages)] } else { modelmsg = group.Timeline.Messages[idx] ackd = true } } else { contact := the.Peer.GetContact(this.Handle()) if this.Handle() == "" || the.Peer == nil || contact == nil { modelmsg = model.Message{Message:"oops test hi uhhhhh :/"} } else if idx >= len(contact.Timeline.Messages) { log.Errorf("this shouldnt happen") } else { modelmsg = contact.Timeline.Messages[idx] ackd = modelmsg.Acknowledged } } return &MessageWrapper { Message: modelmsg, Timestamp: modelmsg.Timestamp.Unix(), RawMessage: modelmsg.Message, PeerID: modelmsg.PeerID, Error: modelmsg.Error, Acknowledged: ackd, Day: modelmsg.Timestamp.Format("January 2, 2006"), Signature: hex.EncodeToString(modelmsg.Signature), } } func (this *MessageModel) data(index *core.QModelIndex, role int) *core.QVariant { if !index.IsValid() { return core.NewQVariant() } if index.Row() >= this.num() { return core.NewQVariant() } if role == int(core.Qt__DisplayRole) { role = index.Column() + int(core.Qt__UserRole) + 1 } // modelData-element [role]-field value (aka the data ~_~) mderfv := reflect.ValueOf(*this.getMessage(index.Row())).Field(role - int(core.Qt__UserRole) - 1) typeStr := reflect.TypeOf([]MessageWrapper{}).Elem().Field(role - int(core.Qt__UserRole) - 1).Type.String() if typeStr == "string" { return core.NewQVariant1(mderfv.String()) } else if strings.HasPrefix(typeStr, "int") { return core.NewQVariant1(mderfv.Int()) } else if strings.HasPrefix(typeStr, "float") { return core.NewQVariant1(mderfv.Float()) } else if typeStr == "bool" { return core.NewQVariant1(mderfv.Bool()) } return core.NewQVariant1("unknown type " + typeStr) } func (this *MessageModel) headerData(section int, orientation core.Qt__Orientation, role int) *core.QVariant { if role != int(core.Qt__DisplayRole) || orientation == core.Qt__Vertical { return this.HeaderDataDefault(section, orientation, role) } mdt := reflect.TypeOf([]MessageWrapper{}).Elem() return core.NewQVariant12(mdt.Field(section).Name) } func (this *MessageModel) rowCount(parent *core.QModelIndex) int { return this.num() } func (this *MessageModel) columnCount(parent *core.QModelIndex) int { return reflect.TypeOf(MessageWrapper{}).NumField() } // perform this.BeginInsertRows() on the gui thread // important: // 1. idx MUST be set to this.num()'s value *before* calling addMessage() // 2. insert the message yourself // 3. this.RequestEIR() *must* be called afterward func (this *MessageModel) addMessage(idx int) { this.BeginInsertRows(core.NewQModelIndex(), idx, idx) } // perform this.EndInsertRows() on the gui thread after an AddMessage() func (this *MessageModel) requestEIR() { this.EndInsertRows() } // notify the gui that the message acknowledgement at index idx has been modified func (this *MessageModel) editMessage(idx int) { if idx < 0 || idx >= this.num() { log.Errorf("cant edit message %v. probably fine", idx) return } log.Debugf("editMessage(%v, %v)", idx, this.ackIdx) indexObject := this.Index(idx, 0, core.NewQModelIndex()) // replace third param with []int{} to update all attributes instead this.DataChanged(indexObject, indexObject, []int{this.ackIdx}) }