;;; source model for table view

(provide :source-model)

(defvar *books*      (make-array 0 :fill-pointer t :adjustable t))
(defvar *book-model* nil)

(defmacro define-roles (start &rest roles)
  (let ((n start))
    `(progn
       ,@(mapcar (lambda (role) `(defconstant ,role ,(incf n))) roles))))

(define-roles #.|Qt.UserRole|
  +title-role+
  +author-role+)

(defstruct book
  title
  author)

(defvar *empty-model-index* (qnew "QModelIndex"))

(defun add-book (title author)
  (|beginInsertRows| *book-model* *empty-model-index*
                     (|rowCount| *book-model*) (|rowCount| *book-model*))
  (vector-push-extend (make-book :title title :author author)
                      *books*)
  (|endInsertRows| *book-model*))

(defun variant (value)
  (cond ((stringp value)
         (qvariant-from-value value "QString"))))

(defvar *empty-variant* (qnew "QVariant"))

(defconstant +filter-role+ |Qt.DisplayRole|) ; see QSortFilterProxyModel

(defun make-book-model ()
  (setf *book-model* (qnew "QAbstractListModel"))
  (qoverride *book-model* "rowCount(QModelIndex)"
             (lambda (index)
               (length *books*)))
  (qoverride *book-model* "data(QModelIndex,int)" ; QOVERRIDE return value is GC'd
             (lambda (index role)
               (let* ((row (|row| index))
                      (data (when (< -1 row (length *books*))
                              (let ((book (aref *books* row)))
                                (case role
                                  (#.+filter-role+ ; provide string for search
                                   (variant (x:join (list (book-title book) (book-author book)) " ")))
                                  (#.+title-role+
                                   (variant (book-title book)))
                                  (#.+author-role+
                                   (variant (book-author book))))))))
                 (or data
                     *empty-variant*))))
  (qoverride *book-model* "roleNames()"
             (lambda ()
               (list (cons +title-role+  "title")
                     (cons +author-role+ "author")))))
