module Graphics.UI.Gtk.ModelView.ListStore (
ListStore,
listStoreNew,
listStoreNewDND,
listStoreDefaultDragSourceIface,
listStoreDefaultDragDestIface,
listStoreIterToIndex,
listStoreGetValue,
listStoreSafeGetValue,
listStoreSetValue,
listStoreToList,
listStoreGetSize,
listStoreInsert,
listStorePrepend,
listStoreAppend,
listStoreRemove,
listStoreClear,
) where
import Control.Monad (liftM, when)
import Data.IORef
import Data.Ix (inRange)
#if __GLASGOW_HASKELL__>=606
import qualified Data.Sequence as Seq
import Data.Sequence (Seq)
import qualified Data.Foldable as F
#else
import qualified Graphics.UI.Gtk.ModelView.Sequence as Seq
import Graphics.UI.Gtk.ModelView.Sequence (Seq)
#endif
import Graphics.UI.Gtk.Types (GObjectClass(..))
import Graphics.UI.Gtk.ModelView.CustomStore
import Graphics.UI.Gtk.ModelView.TreeModel
import Graphics.UI.Gtk.ModelView.TreeDrag
import Control.Monad.Trans ( liftIO )
newtype ListStore a = ListStore (CustomStore (IORef (Seq a)) a)
instance TypedTreeModelClass ListStore
instance TreeModelClass (ListStore a)
instance GObjectClass (ListStore a) where
toGObject (ListStore tm) = toGObject tm
unsafeCastGObject = ListStore . unsafeCastGObject
listStoreNew :: [a] -> IO (ListStore a)
listStoreNew xs = listStoreNewDND xs (Just listStoreDefaultDragSourceIface)
(Just listStoreDefaultDragDestIface)
listStoreNewDND :: [a]
-> Maybe (DragSourceIface ListStore a)
-> Maybe (DragDestIface ListStore a)
-> IO (ListStore a)
listStoreNewDND xs mDSource mDDest = do
rows <- newIORef (Seq.fromList xs)
customStoreNew rows ListStore TreeModelIface {
treeModelIfaceGetFlags = return [TreeModelListOnly],
treeModelIfaceGetIter = \[n] -> readIORef rows >>= \rows ->
return (if Seq.null rows then Nothing else
Just (TreeIter 0 (fromIntegral n) 0 0)),
treeModelIfaceGetPath = \(TreeIter _ n _ _) -> return [fromIntegral n],
treeModelIfaceGetRow = \(TreeIter _ n _ _) ->
readIORef rows >>= \rows ->
if inRange (0, Seq.length rows 1) (fromIntegral n)
then return (rows `Seq.index` fromIntegral n)
else fail "ListStore.getRow: iter does not refer to a valid entry",
treeModelIfaceIterNext = \(TreeIter _ n _ _) ->
readIORef rows >>= \rows ->
if inRange (0, Seq.length rows 1) (fromIntegral (n+1))
then return (Just (TreeIter 0 (n+1) 0 0))
else return Nothing,
treeModelIfaceIterChildren = \_ -> return Nothing,
treeModelIfaceIterHasChild = \_ -> return False,
treeModelIfaceIterNChildren = \index -> readIORef rows >>= \rows ->
case index of
Nothing -> return $! Seq.length rows
_ -> return 0,
treeModelIfaceIterNthChild = \index n -> case index of
Nothing -> return (Just (TreeIter 0 (fromIntegral n) 0 0))
_ -> return Nothing,
treeModelIfaceIterParent = \_ -> return Nothing,
treeModelIfaceRefNode = \_ -> return (),
treeModelIfaceUnrefNode = \_ -> return ()
} mDSource mDDest
listStoreIterToIndex :: TreeIter -> Int
listStoreIterToIndex (TreeIter _ n _ _) = fromIntegral n
listStoreDefaultDragSourceIface :: DragSourceIface ListStore row
listStoreDefaultDragSourceIface = DragSourceIface {
treeDragSourceRowDraggable = \_ _-> return True,
treeDragSourceDragDataGet = treeSetRowDragData,
treeDragSourceDragDataDelete = \model (dest:_) -> do
liftIO $ listStoreRemove model dest
return True
}
listStoreDefaultDragDestIface :: DragDestIface ListStore row
listStoreDefaultDragDestIface = DragDestIface {
treeDragDestRowDropPossible = \model dest -> do
mModelPath <- treeGetRowDragData
case mModelPath of
Nothing -> return False
Just (model', source) -> return (toTreeModel model==toTreeModel model'),
treeDragDestDragDataReceived = \model (dest:_) -> do
mModelPath <- treeGetRowDragData
case mModelPath of
Nothing -> return False
Just (model', (source:_)) ->
if toTreeModel model/=toTreeModel model' then return False
else liftIO $ do
row <- listStoreGetValue model source
listStoreInsert model dest row
return True
}
listStoreGetValue :: ListStore a -> Int -> IO a
listStoreGetValue (ListStore model) index =
readIORef (customStoreGetPrivate model) >>= return . (`Seq.index` index)
listStoreSafeGetValue :: ListStore a -> Int -> IO (Maybe a)
listStoreSafeGetValue (ListStore model) index = do
seq <- readIORef (customStoreGetPrivate model)
return $ if index >=0 && index < Seq.length seq
then Just $ seq `Seq.index` index
else Nothing
listStoreSetValue :: ListStore a -> Int -> a -> IO ()
listStoreSetValue (ListStore model) index value = do
modifyIORef (customStoreGetPrivate model) (Seq.update index value)
stamp <- customStoreGetStamp model
treeModelRowChanged model [index] (TreeIter stamp (fromIntegral index) 0 0)
listStoreToList :: ListStore a -> IO [a]
listStoreToList (ListStore model) =
liftM
#if __GLASGOW_HASKELL__>=606
F.toList
#else
Seq.toList
#endif
$ readIORef (customStoreGetPrivate model)
listStoreGetSize :: ListStore a -> IO Int
listStoreGetSize (ListStore model) =
liftM Seq.length $ readIORef (customStoreGetPrivate model)
listStoreInsert :: ListStore a -> Int -> a -> IO ()
listStoreInsert (ListStore model) index value = do
seq <- readIORef (customStoreGetPrivate model)
when (index >= 0) $ do
let index' | index > Seq.length seq = Seq.length seq
| otherwise = index
writeIORef (customStoreGetPrivate model) (insert index' value seq)
stamp <- customStoreGetStamp model
treeModelRowInserted model [index'] (TreeIter stamp (fromIntegral index') 0 0)
where insert :: Int -> a -> Seq a -> Seq a
insert i x xs = front Seq.>< x Seq.<| back
where (front, back) = Seq.splitAt i xs
listStorePrepend :: ListStore a -> a -> IO ()
listStorePrepend (ListStore model) value = do
modifyIORef (customStoreGetPrivate model)
(\seq -> value Seq.<| seq)
stamp <- customStoreGetStamp model
treeModelRowInserted model [0] (TreeIter stamp 0 0 0)
listStoreAppend :: ListStore a -> a -> IO Int
listStoreAppend (ListStore model) value = do
index <- atomicModifyIORef (customStoreGetPrivate model)
(\seq -> (seq Seq.|> value, Seq.length seq))
stamp <- customStoreGetStamp model
treeModelRowInserted model [index] (TreeIter stamp (fromIntegral index) 0 0)
return index
listStoreRemove :: ListStore a -> Int -> IO ()
listStoreRemove (ListStore model) index = do
seq <- readIORef (customStoreGetPrivate model)
when (index >=0 && index < Seq.length seq) $ do
writeIORef (customStoreGetPrivate model) (delete index seq)
treeModelRowDeleted model [index]
where delete :: Int -> Seq a -> Seq a
delete i xs = front Seq.>< Seq.drop 1 back
where (front, back) = Seq.splitAt i xs
listStoreClear :: ListStore a -> IO ()
listStoreClear (ListStore model) =
let loop (1) Seq.EmptyR = return ()
loop n (seq Seq.:> _) = do
writeIORef (customStoreGetPrivate model) seq
treeModelRowDeleted model [n]
loop (n1) (Seq.viewr seq)
in do seq <- readIORef (customStoreGetPrivate model)
loop (Seq.length seq 1) (Seq.viewr seq)