INblobs-0.1.1: src/INChecksUI.hs
module INChecksUI
( checksList
, iNCheck
, singleCheckOverIN
, checkValidINOnSave
, multipleChecksOverIN_UI
, multipleChecksOverINs_UI
) where
import INChecks
import State
import qualified PersistentDocument as PD
import Common
import Constants
import Document
import SafetyNet
import DocumentFile
import CommonIO
import InfoKind
import CommonUI
import Text.XML.HaXml.XmlContent (XmlContent)
import Graphics.UI.WXCore hiding (Document)
import Graphics.UI.WX
import Data.Map (Map)
import qualified Data.Map as Map
import Data.List
import Control.Monad
------------------------------------------------------------------------------------------
showINErrorList :: (Show g, Show n, Show e) => [INError g n e] -> String
showINErrorList = unlines' . map show
showError :: (Show g, Show n, Show e) => Map ErrorLoc [INError g n e] -> String
showError = Map.foldWithKey aux ""
where -- aux :: ErrorLoc -> [INError g n e] -> String -> String
aux loc err str = '\t':show loc ++ '\n': indent 2 (showINErrorList err) ++ '\n':str
showError2 :: (Show g, Show n, Show e) => Map ErrorLoc (Map String (String, [INError g n e])) -> String
showError2 = Map.foldWithKey aux2 "" . Map.map (Map.foldWithKey aux "")
where -- aux :: String -> (String, [INError g n e]) -> String -> String
aux checkName (badMsg, err) str = checkName ++ " :\n"
++ indent 1 (showINErrorList err) ++ '\n':str
aux2 :: ErrorLoc -> String -> String -> String
aux2 loc err str = '\t':show loc ++ '\n': indent 2 err ++ '\n':str
-- | Run the check operation over current IN system.
singleCheckOverIN :: (Show g, Show n, Show e) => Check g n e -> State g n e -> IO ()
singleCheckOverIN (checkName, _, okMsg, badMsg, func) state =
do w <- getNetworkFrame state
pDoc <- getDocument state
doc <- PD.getDocument pDoc
wxcBeginBusyCursor
let l = func doc
wxcEndBusyCursor
if Map.null l
then infoDialog w (checkName ++ ": Passed") okMsg
else do logMessage $ badMsg ++ ": \n" ++ showError l
errorDialog w (checkName ++ ": Failed") (badMsg ++ ".\nSee report in the bottom area.")
-- | Run the \"valid IN\" check operation over current IN system on Save.
checkValidINOnSave :: (Show g, Show n, Show e) => State g n e -> IO a -> IO ()
checkValidINOnSave state action =
do w <- getNetworkFrame state
pDoc <- getDocument state
doc <- PD.getDocument pDoc
wxcBeginBusyCursor
let l = func doc
wxcEndBusyCursor
if Map.null l
then ignoreResult action
else do logMessage $ badMsg ++ ": \n" ++ showError l
go <- proceedDialog w (checkName ++ ": Failed") (badMsg ++ ".\nSee report in the bottom area.\n\nDo you really want to proceed?")
if go then ignoreResult action else return ()
where (checkName, _, okMsg, badMsg, func) = iNCheck
-- | Run multiple check operations over current IN system.
multipleChecksOverIN :: (Show g, Show n, Show e) => [Check g n e] -> State g n e -> IO ()
multipleChecksOverIN listChecks state =
do w <- getNetworkFrame state
pDoc <- getDocument state
doc <- PD.getDocument pDoc
wxcBeginBusyCursor
case runChecksOver doc listChecks of
(goodsStr, Nothing) ->
do
wxcEndBusyCursor
infoDialog w "All checks passed" goodsStr
(goodsStr, Just (badsStr,badsStrLong)) ->
do
wxcEndBusyCursor
logMessage $ goodsStr ++ badsStrLong
errorDialog w "Checks Failed"
$ goodsStr ++ badsStr
++ "See report in the bottom area."
-- | Runs multiple checks over a document.
runChecksOver :: (Show g, Show n, Show e) =>
Document g n e -> [Check g n e] -> (String -- good checks
, Maybe (String -- bad checks
,String -- long bag checks report
))
runChecksOver doc listChecks =
if null bads
then (goodsStr, Nothing)
else (goodsStr, Just (badsStr, badsStrLong))
where
(goods, bads) = partition passed $ map (calc doc) listChecks
goodsStr = unlines $ map showOK goods
badsStr = unlines $ map showBAD bads
badsStrLong = showError2 $ transf bads
calc doc (a,_,b,c,func) = (a,b,c, func doc)
passed (_,_,_, r) = Map.null r
showOK (name,okMsg,_,_) = name ++ ": Passed\n\t" ++ okMsg
showBAD (name,_,badMsg,_) = name ++ ": Failed\n\t" ++ badMsg
-- | Change from errors by Check inner sorted by 'ErrorLoc' to errors by 'ErrorLoc', inner sorted by Check.
transf :: [(String, String, String, Map ErrorLoc [INError g n e])] -> Map ErrorLoc (Map String (String, [INError g n e]))
transf = Map.unionsWith Map.union . map aux1
where aux1 :: (String, String, String, Map ErrorLoc [INError g n e]) -> Map ErrorLoc (Map String (String, [INError g n e]))
aux1 (name,_, badMsg, mapp) = Map.map (\v -> Map.singleton name (badMsg,v)) mapp
multipleChecksOverIN_UI :: (Show g, Show n, Show e) => Frame () -> State g n e -> IO ()
multipleChecksOverIN_UI theFrame state =
do
mChecks <- chooseChecksDialog theFrame
case mChecks of
Nothing -> return ()
Just [] -> infoDialog theFrame "Zero checks" "Zero checks chosen, so nothing to do"
Just ks -> multipleChecksOverIN ks state
chooseChecksDialog :: Frame () -> IO (Maybe [Check g n e])
chooseChecksDialog theFrame =
do
dialog <- dialog theFrame
[ text := "Choose Checks"
]
p <- panel dialog []
lChks <- mapM (\(name, desc,_,_,_) -> checkBox p [ text := name
, checked := False
, tooltip := desc
]
) checksList
ok <- button p [ text := "Check" ]
set dialog [ layout := container p $
margin 10 $
column 5 [ label "Apply the following checks:"
, margin 10 . column 5 $ map widget lChks
, hfloatCentre $ widget ok
]
]
showModal dialog $ \stop ->
do set ok [ on command :=
do
sels <- filterM isSelected $ zip lChks checksList
stop (Just $ map snd sels)
]
isSelected = checkBoxGetValue . fst
fst5 (a,_,_,_,_) = a
multipleChecksOverINs_UI :: (InfoKind n g, InfoKind e g, XmlContent g, Show g)
=> State g n e -> IO ()
multipleChecksOverINs_UI state =
do
newFrame <- frame [ text := "Multiple Checks Over Multiple INs"
, size := sz 900 600
]
p <- panel newFrame []
txt <- textCtrlRich p []
textCtrlSetEditable txt False
okB <- button p [ text := "Exit"
, on command := close newFrame
]
saveB <- button p [ text := "Save to file"
, on command := safetyNet newFrame $
do
mFile <- fileSaveDialog newFrame rememberCurrentDir False "File to save report to:" [("Any file", ["*","*.txt","*.log"])] directory filename
case mFile of
Nothing -> errorDialog newFrame "No File" "No file to write to.\n Report not saved."
Just file -> do str <- textCtrlGetValue txt
writeFile file str
]
set newFrame [ layout := container p $
margin 10 $
column 5 [ fill $ widget txt
, hfloatRight $ row 5 [widget saveB, widget okB]
]
]
files <- filesOpenDialog newFrame rememberCurrentDir allowReadOnly message extensions directory filename
mlChecks <- chooseChecksDialog newFrame
case (files, mlChecks) of
(fs, Just cs) | not (null fs) && not (null cs) -> -- useful case
do
textCtrlAppendText txt "Checking ...\n"
wxcBeginBusyCursor
mapM_ (reportPerFile state txt cs) fs
wxcEndBusyCursor
x -> textCtrlAppendText txt "No files and/or no checks chosen, so nothing to do"
where
rememberCurrentDir = True
allowReadOnly = True
message = "Open " ++ toolName ++ " files"
directory = "examples"
filename = ""
-- | For each INblobs file add some info to the report.
reportPerFile :: (InfoKind n g, InfoKind e g, XmlContent g, Show g) =>
State g n e -> TextCtrl () -> [Check g n e] -> FilePath -> IO ()
reportPerFile _ txt chks fname =
do
contents <- strictReadFile fname
let errorOrDocument = DocumentFile.fromString contents
textCtrlAppendText txt $ fname ++ "\n"
case errorOrDocument of
Left err -> addError2TextCtrl txt $ err ++ "\nChecks not performed.\n"
Right (doc, [], False) ->
case runChecksOver doc chks of
(goodsStr, Nothing) -> addGood2TextCtrl txt "All checks passed"
(goodsStr, Just (badsStr,badsStrLong)) ->
do
addGood2TextCtrl txt goodsStr
addTxtOfColor2TextCtrl (wxcolor orange) txt badsStrLong
Right (doc, warnings, True) ->
addError2TextCtrl txt $
"File read warning\n"
++ "The file you opened has the old " ++ toolName
++ " file format which will become obsolete in newer versions of "
++ toolName ++ ".\nChecks not performed.\n"
Right (doc, warnings, False) ->
addError2TextCtrl txt $
"Warnings while reading file:\n\n"
++ unlines ( map ("* " ++) (take 10 warnings)
++ if length warnings > 10 then ["..."] else []
)
++ "\n Most likely you are reading a file that is created by a newer version of "
++ toolName ++ ".\nChecks not performed.\n"
textCtrlAppendText txt $ '\n': replicate 20 '#' ++ "\n\n"