lhae-0.0.3: src/Controller/Grid.hs
module Controller.Grid (new,changePageEventHandler
,deleteCurrent,changePageTo
,writeCellInput,writeCellExpr
,addRows,addColumns,addNRows,addNColumns
,deleteRows,deleteColumns
,insertRow,insertColumn
,updateRowLabel,updateColumnLabel
,updateRowLabels,updateColumnLabels,batched)
where
import Control.Monad.Trans (liftIO)
import Control.Monad (forM_,when)
import Control.Applicative ((<$>))
import Data.Char (chr,ord)
import Graphics.UI.WX (Prop ((:=)),on)
import qualified Graphics.UI.WX as WX
import qualified Graphics.UI.WXCore as WXC
import Controller (Controller,onView,onModel,onGridModel,onGridView
,ctrlData,withCtrlData)
import {-# SOURCE #-} qualified Controller.Menu.Table.Copy as Copy
import {-# SOURCE #-} qualified Controller.Menu.Table.Delete as Delete
import {-# SOURCE #-} qualified Controller.Menu.Table.Transpose as Transpose
import {-# SOURCE #-} qualified Controller.Menu.Table.Rename as Rename
import Controller.Cell (updateInView,showContent,showSelectedContent)
import qualified Model as M
import qualified Model.Cell as Cell
import qualified Model.Grid as GridM
import Model.CellContent (CellExpr)
import qualified View.Component.Grid as GridV
import View (frame,onGrid)
import View.Modes (formulaMode)
import qualified View.GridPage as GridPage
import View.FormulaInput (logString)
import qualified View.Dialog.Simple as Dialog
import Util (justWhen,whenM)
import I18n (__)
import qualified ModelToView
import CellCoordinate (CellCoord,coordRange)
data LabelType = Row | Column
data LabelClickInfo = LabelClickInfo
{ labelType :: LabelType
, labelIndex :: Int
, labelPoint :: WX.Point
}
data CellClickInfo = CellClickInfo { cellCoord :: CellCoord
, cellPoint :: WX.Point
}
new :: Controller ()
new =
let addModel id =
do modelToView <- onView $ return . ModelToView.new
onModel $ M.addGrid id modelToView
addView grid =
do onView $ GridPage.add grid
ctrl <- ctrlData
onView $ \view ->
onGrid view $ \grid ->
do WXC.gridOnGridEvent grid $ \event ->
withCtrlData (eventHandler event) ctrl
WXC.windowOnKeyDown grid
$ GridPage.keyEventHandler view
in do
(gridViewId,gridView) <- onView GridPage.new
addModel gridViewId
addView gridView
lastRow,lastColumn :: Int -> Controller Bool
lastRow row = do
rows <- onGridView GridV.numDataRows
return $ row == rows
lastColumn col = do
cols <- onGridView GridV.numDataColumns
return $ col == cols
extendWhenClicked :: CellCoord -> Controller ()
extendWhenClicked (row,column) = do
whenM (lastRow row) $ addNRows 1
whenM (lastColumn column) $ addNColumns 1
eventHandler :: WXC.EventGrid -> Controller ()
eventHandler event =
case event of
WXC.GridLabelMouse row col (WXC.MouseLeftDown {}) ->
do extendWhenClicked (row,col)
liftIO WXC.propagateEvent
WXC.GridLabelMouse row col (WXC.MouseRightDown pt _) ->
if col == -1
then whenM (not <$> lastRow row)
$ labelClickDialog $ LabelClickInfo Row row pt
else whenM (not <$> lastColumn col)
$ labelClickDialog $ LabelClickInfo Column col pt
WXC.GridCellMouse row col (WXC.MouseRightDown pt _) ->
do lRow <- lastRow row
lCol <- lastColumn col
when (not lRow && not lCol) $ cellClickDialog
$ CellClickInfo (row,col) pt
WXC.GridCellMouse row col (WXC.MouseLeftDown {}) ->
do extendWhenClicked (row,col)
liftIO WXC.propagateEvent
WXC.GridEditorShown row col veto ->
do extendWhenClicked (row,col)
cell <- onGridModel $ GridM.getCell (row,col)
onView (formulaMode (row,col) $ Cell.input cell)
liftIO veto
WXC.GridCellSelect row col _ ->
do showContent (row,col)
liftIO WXC.propagateEvent
_ -> liftIO WXC.propagateEvent
labelClickDialog :: LabelClickInfo -> Controller ()
labelClickDialog info = do
cData <- ctrlData
let (copyLabel,deleteLabel,insertLabel,transposeLabel,renameLabel) =
case labelType info of Row -> ( __ "Copy row"
, __ "Delete row"
, __ "Insert row"
, __ "Transpose row"
, __ "Rename row")
Column -> ( __ "Copy column"
, __ "Delete column"
, __ "Insert column"
, __ "Transpose column"
, __ "Rename column")
onCopy =
case labelType info of
Row -> Copy.rowEventHandlerWith [labelIndex info]
Column -> Copy.columnEventHandlerWith [labelIndex info]
onDelete =
case labelType info of
Row -> Delete.rowEventHandlerWith [labelIndex info]
Column -> Delete.columnEventHandlerWith [labelIndex info]
onInsert = do
result <- onView $ Dialog.input insertLabel ""
justWhen result $ \label ->
case labelType info of
Row -> insertRow label $ labelIndex info
Column -> insertColumn label $ labelIndex info
onTranspose =
case labelType info of
Row -> Transpose.rowEventHandlerWith [labelIndex info]
Column -> Transpose.columnEventHandlerWith [labelIndex info]
onRename =
case labelType info of
Row -> Rename.rowEventHandlerWith $ labelIndex info
Column -> Rename.columnEventHandlerWith $ labelIndex info
makeMenu = do
menu <- WX.menuPane []
let makeItem label ctrl =
WX.menuItem menu [ WX.text := label
, on WX.command := withCtrlData ctrl cData]
makeItem copyLabel onCopy
makeItem deleteLabel onDelete
makeItem insertLabel onInsert
makeItem transposeLabel onTranspose
makeItem renameLabel onRename
return menu
menu <- liftIO makeMenu
onView $ WX.menuPopup menu (labelPoint info) . frame
cellClickDialog :: CellClickInfo -> Controller ()
cellClickDialog info = do
cData <- ctrlData
let onCopy = Copy.formulaAtEventHandler $ cellCoord info
makeMenu = do
menu <- WX.menuPane []
WX.menuItem menu [ WX.text := __ "Copy formula"
, on WX.command := withCtrlData onCopy cData]
return menu
menu <- liftIO makeMenu
onView $ WX.menuPopup menu (cellPoint info) . frame
changePageEventHandler :: Controller ()
changePageEventHandler = do
Just n <- onView $ GridPage.currentSelectionNum
Just id <- onView $ GridPage.currentSelectionId
onView $ GridPage.setCurrent n
onModel $ M.setCurrent id
showSelectedContent
deleteCurrent :: Controller ()
deleteCurrent = do
onModel M.deleteCurrent
onView GridPage.deleteCurrent
next <- onView GridPage.currentSelectionId
case next of
Just n -> do onModel $ M.setCurrent n
showSelectedContent
Nothing -> onView $ logString ""
changePageTo :: Int -> Controller ()
changePageTo = onView . GridPage.fireSelectionEvent
extendWhenAddingCells :: [(CellCoord,a)] -> Controller ()
extendWhenAddingCells cells =
let (maxRow,maxCol) = maximum $ map fst cells
in do
newRows <- do rows <- onGridView GridV.numDataRows
return $ maxRow - rows + 1
newCols <- do cols <- onGridView GridV.numDataColumns
return $ maxCol - cols + 1
when (newRows > 0) $ addNRows newRows
when (newCols > 0) $ addNColumns newCols
writeCellInput :: [(CellCoord,String)] -> Controller ()
writeCellInput [] = return ()
writeCellInput cells = do
extendWhenAddingCells cells
forM_ cells $ \(coord,input) -> do
onGridModel (GridM.setCellInput coord input) >>= updateInView
writeCellExpr :: [(CellCoord,CellExpr)] -> Controller ()
writeCellExpr [] = return ()
writeCellExpr cells = do
extendWhenAddingCells cells
forM_ cells $ \(coord,expr) -> do
onGridModel (GridM.setCellExpr coord expr) >>= updateInView
updateAllCellsInView :: Controller ()
updateAllCellsInView = do
rows <- onGridView GridV.numDataRows
cols <- onGridView GridV.numDataColumns
updateInView $ coordRange ((0,0),(rows-1,cols-1))
{- Reihenfolge wichtig:
1. zu Model hinzufügen
2. zu View hinzufügen
-}
addRows,addColumns :: [String] -> Controller ()
addRows [] = return ()
addRows captions = do
onGridModel $ GridM.addRows captions
onGridView $ GridV.addRows captions
updateAllCellsInView
addColumns [] = return ()
addColumns captions = do
onGridModel $ GridM.addColumns captions
onGridView $ GridV.addColumns captions
updateAllCellsInView
addNRows,addNColumns :: Int -> Controller ()
addNRows n = do
rows <- onGridView GridV.numDataRows
addRows $ map show [rows+1..rows+n]
addNColumns n = do
cols <- onGridView GridV.numDataColumns
addColumns $ map columnName [cols..cols+n-1]
where columnName i =
let number = (i `div` 26) + 1
in
replicate number $ chr $ (i `mod` 26) + ord 'A'
deleteRows,deleteColumns :: [Int] -> Controller ()
deleteRows rows = do
onGridModel $ GridM.deleteRows rows
onGridView $ GridV.deleteRows $ reverse rows
updateAllCellsInView
deleteColumns cols = do
onGridModel $ GridM.deleteColumns cols
onGridView $ GridV.deleteColumns $ reverse cols
updateAllCellsInView
insertRow,insertColumn :: String -> Int -> Controller ()
insertRow label i = do
onGridView $ GridV.insertRowBefore label i
onGridModel $ GridM.insertRowBefore label i
updateAllCellsInView
insertColumn label i = do
onGridView $ GridV.insertColumnBefore label i
onGridModel $ GridM.insertColumnBefore label i
updateAllCellsInView
updateRowLabel,updateColumnLabel :: Int -> String -> Controller ()
updateRowLabel n to = do
changed <- onGridModel $ GridM.updateRowLabel n to
onGridView $ GridV.setRowLabel n to
updateInView changed
showSelectedContent
updateColumnLabel n to = do
changed <- onGridModel $ GridM.updateColumnLabel n to
onGridView $ GridV.setColumnLabel n to
updateInView changed
showSelectedContent
updateRowLabels,updateColumnLabels :: [String] -> Controller ()
updateRowLabels labels = do
n <- onGridView GridV.numDataRows
forM_ (zip [0..n-1] labels) $ uncurry updateRowLabel
updateColumnLabels labels = do
n <- onGridView GridV.numDataColumns
forM_ (zip [0..n-1] labels) $ uncurry updateColumnLabel
batched :: Controller a -> Controller a
batched doThis = do
onGridView WXC.gridBeginBatch
result <- doThis
onGridView WXC.gridEndBatch
return result