{-| This module contains various need \"utility\" functions. The functions are general functions and vary. -} module Util where import qualified Control.Exception as E import qualified System.IO as H import Graphics.UI.Gtk import List ( (\\), isPrefixOf, isSuffixOf, sort ) import Control.Monad( filterM, forM, forM_ ) import System.FilePath( () , splitFileName, takeExtension ) import System.Directory import System.Posix.Files import System.Time import Buttons import Types {-| Takes a path to a directory, gets its contents, then filters \"bad\" paths from the contents. It then splits the contents into files & directories and returns both lists as a tuple. -} viewDirectory :: FilePath -- ^ The path to the desired directory. -> IO ([FilePath],[FilePath]) -- ^ A pair of lists containing 'FilePath's, files and directories respectively. viewDirectory location = do shownContents <- getDirectoryContents location >>= (\conts -> filterLinks ( filter ( not . isPrefixOf "." ) ( filter ( not . isSuffixOf "~" ) conts ) ) ) files <- filterM doesFileExist ( map ( location ) shownContents ) directories <- filterM doesDirectoryExist ( map ( location ) shownContents ) return ( sort ( map ( flip (\\) ( location ++ "/" ) ) directories ) , sort ( map ( flip (\\) ( location ++ "/" ) ) files ) ) {-| Takes a list of 'FilePath's and removes both symbolic links and the paths that aren't accessible by the current user. -} filterLinks :: [FilePath] -- ^ The list of 'FilePath's to be filtered. -> IO [FilePath] -- ^ The cleaned list of paths. filterLinks [] = return [] filterLinks (x:xs) = ( fileExist x `E.catch` (\e -> return ( False ) ) ) >>= ( \e -> case e of True -> ( getSymbolicLinkStatus x >>= ( \s -> case isSymbolicLink s of --If so, remove x and filter remaining. True -> filterLinks xs --Otherwise keep, and filter remaining. False -> filterLinks xs >>= (\l -> return ( x:l ) ) ) >>= ( \p -> filterM (\paths -> fileAccess paths True False False ) p ) ) False -> filterLinks xs ) {-| Creates an \"icon\" based upon the extension of a supplied path. If the path doesn't contain an extension it is the default \"File\" icon. If it contains an extension, it attempts to create on using the images in the Icons folder, but if there's no relevant icon it goes with the default icon. -} createIcon :: FilePath -- ^ The path to generate an \"icon\" from. -> IO Pixbuf -- ^ The 'Pixbuf' containing the image. createIcon file = case ( takeExtension file ) of "" -> doesDirectoryExist file >>= ( \e -> pixbufNewFromFile =<< iconpath ( if e then "Folder" else "File" ) ) name -> ( pixbufNewFromFile =<< iconpath ( tail name ) ) `E.catch` (\_ -> pixbufNewFromFile =<< iconpath ( "File" ) ) {-| Takes a 'FilePath' and creates a string representation of that files\/directories size. -} getFileSize :: FilePath -- ^ The path to a file\/directory. -> IO String -- ^ The string representation of the size. 0 if supplied path is a directory. getFileSize name = ( ( H.openFile name H.ReadMode ) >>= ( \h -> do a <- H.hFileSize h H.hClose h return ( show a ) ) ) `E.catch` (\_ -> return ( show 0 ) ) {-| Takes a 'FilePath' and creates a string representation of the current users permissions for that file\/directory. -} permissionString :: FilePath -- ^ The file\/directory of which permissions are to be obtained. -> IO String -- ^ The string representation of the permissions. \'\-\' where the user doesn't have a permission. permissionString name = getPermissions name >>= ( \p -> return ( ( if ( readable p ) then "r" else "-" ) ++ ( if ( writable p ) then "w" else "-" ) ++ ( if ( executable p ) then "x" else "-" ) ++ ( if ( searchable p ) then "s" else "-" ) ) ) {-| Refreshs an individual \"pane\" from the view. It clears the 'ListStore' and then populates the store with the elements supplied. Each row is populated with the icon, the name, the size, the last access details and the user permissions for the entry. The ListStore's are automatically updated on screen. -} refreshPane :: [FilePath] -- ^ The elements to be added to the 'ListStore' once it's emptied. -> ListStore StoreRow -- ^ The 'ListStore' to be updated. -> IO ( ) refreshPane elements tStore = do listStoreClear tStore c <- getCurrentDirectory forM_ elements $ \row -> do i <- createIcon row s <- getFileSize (c++"/"++row) t <- getModificationTime (c++"/"++row) p <- permissionString (c++"/"++row) listStoreAppend tStore ( StoreRow row i s ( show t ) p ) return ( )