hinotify-0.1: tests/DirTree/DirTree.hs
{-
Duncan Coutts 2006
Doesn't compile with gtk2hs 0.9.10, you'll need the darcs version.
-}
import qualified Data.Map as Map
import System.Directory
import Data.IORef
import Control.Monad (liftM)
import Ix (inRange)
import System.INotify
import Graphics.UI.Gtk
import Graphics.UI.Gtk.TreeList.Types (TypedTreeModelClass)
import Graphics.UI.Gtk.TreeList.TreeModel (TreeModelFlags(TreeModelListOnly))
import Graphics.UI.Gtk.TreeList.CustomStore
import Graphics.UI.Gtk.TreeList.TreeIter
import Control.Concurrent
instance TypedTreeModelClass (CustomTreeModel a)
dirModelNew :: FilePath -> IO (CustomTreeModel () FilePath)
dirModelNew path = do
dirContents <- getDirectoryContents path
rows <- newIORef (Map.fromList (zip dirContents (repeat ())))
model <- customTreeModelNew () CustomTreeModelImplementation {
customTreeModelGetFlags = return [TreeModelListOnly],
customTreeModelGetIter = \[n] -> return (Just (TreeIter 0 (fromIntegral n) 0 0)),
customTreeModelGetPath = \(TreeIter _ n _ _) -> return [fromIntegral n],
customTreeModelGetRow = \(TreeIter _ n _ _) ->
readIORef rows >>= \rows ->
if inRange (0, Map.size rows - 1) (fromIntegral n)
then return (fst $ Map.elemAt (fromIntegral n) rows)
else fail "DirModel.getRow: iter does not refer to a valid entry",
customTreeModelIterNext = \(TreeIter _ n _ _) ->
readIORef rows >>= \rows ->
if n >= fromIntegral (Map.size rows) - 1
then return Nothing
else return (Just (TreeIter 0 (n+1) 0 0)),
customTreeModelIterChildren = \_ -> return Nothing,
customTreeModelIterHasChild = \_ -> return False,
customTreeModelIterNChildren = \index -> readIORef rows >>= \rows ->
case index of
Nothing -> return $! Map.size rows
_ -> return 0,
customTreeModelIterNthChild = \index n -> case index of
Nothing -> return (Just (TreeIter 0 (fromIntegral n) 0 0))
_ -> return Nothing,
customTreeModelIterParent = \_ -> return Nothing,
customTreeModelRefNode = \_ -> return (),
customTreeModelUnrefNode = \_ -> return ()
}
notify <- inotify_init
watch <- inotify_add_watch notify [Move, Create, Delete] path $ \event ->
let add file = do
index <- atomicModifyIORef rows (\map ->
let map' = Map.insert file () map
in (map', Map.findIndex file map'))
treeModelRowInserted model [index] (TreeIter 0 (fromIntegral index) 0 0)
remove file = do
index <- atomicModifyIORef rows (\map ->
let map' = Map.delete file map
in (map', Map.findIndex file map))
treeModelRowDeleted model [index]
in case event of
MovedIn _ _ file -> add file
MovedOut _ _ file -> remove file
Created _ file -> add file
Deleted _ file -> remove file
_ -> putStrLn $ "other event: " ++ show event
-- TODO: on destroy model (inotify_rm_watch watch)
return model
main = do
initGUI
win <- windowNew
win `onDestroy` mainQuit
model <- dirModelNew "/home/kolmodin/Desktop"
tv <- treeViewNewWithModel model
win `containerAdd` tv
tvc <- treeViewColumnNew
treeViewAppendColumn tv tvc
text <- cellRendererTextNew
cellLayoutPackStart tvc text True
cellLayoutSetAttributes tvc text model
(\file -> [cellText := file])
widgetShowAll win
timeoutAddFull (yield >> return True) priorityDefaultIdle 50
mainGUI