LIB/GTK: enhance FileOperation type so we can have partial functions

This also add a copy mode dialog to the copy operations.
This commit is contained in:
Julian Ospald 2015-12-18 16:55:46 +01:00
parent a4849cf044
commit 58665d7b29
No known key found for this signature in database
GPG Key ID: 220CD1C5BDEED020
2 changed files with 68 additions and 41 deletions

View File

@ -141,9 +141,7 @@ data MyView = MkMyView {
-- |filtered proxy model -- |filtered proxy model
, filteredModel :: TVar (TypedTreeModelFilter DTInfoZipper) , filteredModel :: TVar (TypedTreeModelFilter DTInfoZipper)
, fsState :: TVar DTInfoZipper , fsState :: TVar DTInfoZipper
, operationBuffer :: TVar (Either , operationBuffer :: TVar FileOperation
(DTInfoZipper -> FileOperation)
FileOperation)
} }
@ -255,30 +253,23 @@ del row mygui myview = case row of
-- |Supposed to be used with `withRow`. Initializes a file copy operation. -- |Supposed to be used with `withRow`. Initializes a file copy operation.
copyInit :: DTInfoZipper -> MyGUI -> MyView -> IO () copyInit :: DTInfoZipper -> MyGUI -> MyView -> IO ()
copyInit row mygui myview = case row of copyInit row mygui myview = case row of
dz -> writeTVarIO (operationBuffer myview) (Left $ FCopy dz) dz -> writeTVarIO (operationBuffer myview) (FCopy . CP1 $ dz)
-- |Finalizes a file copy operation. -- |Finalizes a file copy operation.
copyFinal :: MyGUI -> MyView -> IO () copyFinal :: MyGUI -> MyView -> IO ()
copyFinal mygui myview = do copyFinal mygui myview = do
mOp <- readTVarIO (operationBuffer myview) op <- readTVarIO (operationBuffer myview)
op <- case mOp of case op of
Left pOp -> do FCopy (CP1 sourceDir) -> do
curDir <- readTVarIO (fsState myview) curDir <- readTVarIO (fsState myview)
case pOp curDir of let cmsg = "Really copy file \"" ++ getFullPath sourceDir
op@(FCopy _ _) -> return op ++ "\"" ++ " to \"" ++ getFullPath curDir ++ "\"?"
_ -> return None withConfirmationDialog cmsg $ do
Right op@(FCopy _ _) -> return op copyMode <- showCopyModeChooserDialog
_ -> return None withErrorDialog ((runFileOp . FCopy . CC sourceDir curDir $ copyMode)
doCopy op >> refreshTreeView mygui myview Nothing)
where _ -> return ()
doCopy op@(FCopy from to) = do
let cmsg = "Really copy file \"" ++ getFullPath from
++ "\"" ++ " to \"" ++ getFullPath to ++ "\"?"
withConfirmationDialog cmsg
$ withErrorDialog
(runFileOp op >> refreshTreeView mygui myview Nothing)
doCopy _ = return ()
-- |Go up one directory and visualize it in the treeView. -- |Go up one directory and visualize it in the treeView.
@ -406,6 +397,7 @@ constructTreeView mygui myview = do
dirtreePix (Failed {}) = errorPix mygui dirtreePix (Failed {}) = errorPix mygui
-- |Push a message to the status bar.
pushStatusBar :: MyGUI -> String -> IO (ContextId, MessageId) pushStatusBar :: MyGUI -> String -> IO (ContextId, MessageId)
pushStatusBar mygui str = do pushStatusBar mygui str = do
let sb = statusBar mygui let sb = statusBar mygui
@ -426,21 +418,44 @@ showErrorDialog str = do
widgetDestroy errorDialog widgetDestroy errorDialog
-- |Asks the user for confirmation and returns True/False.
showConfirmationDialog :: String -> IO Bool showConfirmationDialog :: String -> IO Bool
showConfirmationDialog str = do showConfirmationDialog str = do
errorDialog <- messageDialogNew Nothing confirmDialog <- messageDialogNew Nothing
[DialogDestroyWithParent] [DialogDestroyWithParent]
MessageQuestion MessageQuestion
ButtonsYesNo ButtonsYesNo
str str
rID <- dialogRun errorDialog rID <- dialogRun confirmDialog
widgetDestroy errorDialog widgetDestroy confirmDialog
case rID of case rID of
ResponseYes -> return True ResponseYes -> return True
ResponseNo -> return False ResponseNo -> return False
_ -> return False _ -> return False
-- |Asks the user which directory copy mode he wants via dialog popup
-- and returns `DirCopyMode`.
showCopyModeChooserDialog :: IO DirCopyMode
showCopyModeChooserDialog = do
chooserDialog <- messageDialogNew Nothing
[DialogDestroyWithParent]
MessageQuestion
ButtonsNone
"Choose the copy mode"
dialogAddButton chooserDialog "Strict" (ResponseUser 0)
dialogAddButton chooserDialog "Merge" (ResponseUser 1)
dialogAddButton chooserDialog "Replace" (ResponseUser 2)
rID <- dialogRun chooserDialog
widgetDestroy chooserDialog
case rID of
ResponseUser 0 -> return Strict
ResponseUser 1 -> return Merge
ResponseUser 2 -> return Replace
-- |Carry out an IO action with a confirmation dialog.
-- If the user presses "No", then do nothing.
withConfirmationDialog :: String -> IO () -> IO () withConfirmationDialog :: String -> IO () -> IO ()
withConfirmationDialog str io = do withConfirmationDialog str io = do
run <- showConfirmationDialog str run <- showConfirmationDialog str
@ -471,7 +486,7 @@ startMainWindow startdir = do
fsState <- readPath' startdir >>= newTVarIO fsState <- readPath' startdir >>= newTVarIO
operationBuffer <- newTVarIO (Right None) operationBuffer <- newTVarIO None
builder <- builderNew builder <- builderNew
builderAddFromFile builder "data/Gtk/builder.xml" builderAddFromFile builder "data/Gtk/builder.xml"

View File

@ -61,14 +61,23 @@ import qualified System.Directory as SD
-- |Data type describing an actual file operation that can be -- |Data type describing an actual file operation that can be
-- carried out via `doFile`. Useful to build up a list of operations -- carried out via `doFile`. Useful to build up a list of operations
-- or delay operations. -- or delay operations.
data FileOperation = FCopy DTInfoZipper DTInfoZipper data FileOperation = FCopy Copy
| FMove FilePath FilePath | FMove Move
| FDelete DTInfoZipper | FDelete DTInfoZipper
| FOpen DTInfoZipper | FOpen DTInfoZipper
| FExecute DTInfoZipper [String] | FExecute DTInfoZipper [String]
| None | None
data Copy = CP1 DTInfoZipper
| CP2 DTInfoZipper DTInfoZipper
| CC DTInfoZipper DTInfoZipper DirCopyMode
data Move = MP1 DTInfoZipper
| MC DTInfoZipper DTInfoZipper
-- |Directory copy modes. -- |Directory copy modes.
-- Strict means we fail if the target directory already exists. -- Strict means we fail if the target directory already exists.
-- Merge means we keep the old directories/files, but overwrite old files -- Merge means we keep the old directories/files, but overwrite old files
@ -80,13 +89,16 @@ data DirCopyMode = Strict
| Replace | Replace
runFileOp :: FileOperation -> IO () runFileOp :: FileOperation -> IO (Maybe FileOperation)
runFileOp (FCopy from@(File {}, _) to) = copyFileToDir from to runFileOp (FCopy (CC from@(File {}, _) to cm)) =
runFileOp (FCopy from@(Dir {}, _) to) = copyDir Merge from to copyFileToDir from to >> return Nothing
runFileOp (FDelete fp) = easyDelete fp runFileOp (FCopy (CC from@(Dir {}, _) to cm)) =
runFileOp (FOpen fp) = void $ openFile fp copyDir cm from to >> return Nothing
runFileOp (FExecute fp args) = void $ executeFile fp args runFileOp fo@(FCopy _) = return $ Just fo
runFileOp _ = return () runFileOp (FDelete fp) = easyDelete fp >> return Nothing
runFileOp (FOpen fp) = openFile fp >> return Nothing
runFileOp (FExecute fp args) = executeFile fp args >> return Nothing
runFileOp _ = return Nothing