LIB/GTK: refactor File base type

We have now ditched AnchoredFile and just use File with Path Abs
in the path field.

This is useful since we now:
* don't allow "." or ".." as filenames anymore
* normalise paths in our path parsers and reject paths with ".."

This also allows us to know that filepaths are always valid. In addition
the 'basename' function from hpath may throw an exception if run
on the root dir "/". This exception is basically uncatched currently,
which is fine, because it's not a selectable directory.
This commit is contained in:
2016-04-15 14:23:41 +02:00
parent 3d15a66350
commit bb6c1b3cda
8 changed files with 223 additions and 392 deletions

View File

@@ -46,6 +46,7 @@ import Data.Foldable
import Data.Maybe
(
catMaybes
, fromJust
)
import Graphics.UI.Gtk
import {-# SOURCE #-} HSFM.GUI.Gtk.Callbacks (setCallbacks)
@@ -62,6 +63,7 @@ import HSFM.GUI.Gtk.Data
import HSFM.GUI.Gtk.Icons
import HSFM.GUI.Gtk.Utils
import HSFM.Utils.IO
import Prelude hiding(readFile)
import System.INotify
(
addWatch
@@ -79,7 +81,9 @@ import System.IO.Error
-- |Constructs the initial MyView object with a few dummy models.
-- It also initializes the callbacks.
createMyView :: MyGUI -> IO FMView -> IO MyView
createMyView :: MyGUI
-> IO FMView
-> IO MyView
createMyView mygui iofmv = do
operationBuffer <- newTVarIO None
@@ -91,7 +95,7 @@ createMyView mygui iofmv = do
=<< readTVarIO rawModel
sortedModel <- newTVarIO =<< treeModelSortNewWithModel
=<< readTVarIO filteredModel
cwd <- newEmptyMVar
view' <- iofmv
view <- newTVarIO view'
@@ -194,6 +198,7 @@ createTreeView = do
-- |Re-reads the current directory or the given one and updates the View.
-- This is more or less a wrapper around `refreshView'`
--
-- If the third argument is Nothing, it tries to re-read the current directory.
-- If that fails, it reads "/" instead.
@@ -208,12 +213,12 @@ refreshView mygui myview mfp =
case mfp of
Just fp -> do
-- readFileWithFileInfo can just outright fail...
ecdir <- tryIOError (HSFM.FileSystem.FileType.readFileWithFileInfo fp)
ecdir <- tryIOError (readFile getFileInfo fp)
case ecdir of
Right cdir ->
-- ...or return an `AnchordFile` with a Failed constructor,
-- both of which need to be handled here
if (failed . file $ cdir)
if (failed cdir)
then refreshView mygui myview =<< getAlternativeDir
else refreshView' mygui myview cdir
Left _ -> refreshView mygui myview =<< getAlternativeDir
@@ -221,7 +226,7 @@ refreshView mygui myview mfp =
where
getAlternativeDir = do
ecd <- try (getCurrentDir myview) :: IO (Either SomeException
(AnchoredFile FileInfo))
Item)
case ecd of
Right dir -> return (Just $ fullPath dir)
Left _ -> return (P.parseAbs "/")
@@ -233,14 +238,17 @@ refreshView mygui myview mfp =
-- calls `refreshView` with the 3rd argument being Nothing.
refreshView' :: MyGUI
-> MyView
-> AnchoredFile FileInfo
-> Item
-> IO ()
refreshView' mygui myview dt@(ADirOrSym _) = do
refreshView' mygui myview dt@(DirOrSym _) = do
newRawModel <- fileListStore dt myview
writeTVarIO (rawModel myview) newRawModel
view' <- readTVarIO $ view myview
_ <- tryTakeMVar (cwd myview)
putMVar (cwd myview) dt
-- get selected items
tps <- getSelectedTreePaths mygui myview
trs <- catMaybes <$> mapM (treeRowReferenceNew newRawModel) tps
@@ -255,7 +263,7 @@ refreshView' mygui myview dt@(ADirOrSym _) = do
ntps <- mapM treeRowReferenceGetPath trs
mapM_ (treeSelectionSelectPath tvs) ntps
_ -> return ()
refreshView' mygui myview (_ :/ Failed{}) = refreshView mygui myview Nothing
refreshView' mygui myview Failed{} = refreshView mygui myview Nothing
refreshView' _ _ _ = return ()
@@ -288,7 +296,7 @@ constructView mygui myview = do
view' <- readTVarIO $ view myview
cdirp <- anchor <$> getFirstItem myview
cdirp <- path <$> getCurrentDir myview
-- update urlBar
entrySetText (urlBar mygui) (P.fromAbs cdirp)
@@ -300,7 +308,7 @@ constructView mygui myview = do
writeTVarIO (filteredModel myview) filteredModel'
treeModelFilterSetVisibleFunc filteredModel' $ \iter -> do
hidden <- showHidden <$> readTVarIO (settings mygui)
item <- (name . file) <$> treeModelGetRow rawModel' iter
item <- treeModelGetRow rawModel' iter >>= (P.basename . path)
if hidden
then return True
else return $ not . P.hiddenFile $ item
@@ -318,13 +326,13 @@ constructView mygui myview = do
-- set values
treeModelSetColumn rawModel' (makeColumnIdPixbuf 0)
(dirtreePix . file)
dirtreePix
treeModelSetColumn rawModel' (makeColumnIdString 1)
(P.fromRel . name . file)
(P.toFilePath . fromJust . P.basename . path)
treeModelSetColumn rawModel' (makeColumnIdString 2)
(packModTime . file)
packModTime
treeModelSetColumn rawModel' (makeColumnIdString 3)
(packPermissions . file)
packPermissions
-- update model of view
case view' of