module TableController ( Controller , test , new , view , push ) where import qualified Data.ByteString.Lazy.Char8 as L import qualified Graphics.UI.Gtk.ModelView as MV import qualified LoadSaveController as LSC import qualified TableView as View import Graphics.UI.Gtk import Data.Maybe import Data.List import SimpleRegex import Control.Monad import Control.Applicative import WindowedApp import Component type Controller = Ref C type StringList = MV.ListStore [L.ByteString] view :: C -> Widget view = View.mainWidget . gui new :: IO Controller new = do lsc <- LSC.new (Just "jira") lsv <- (lsc .> LSC.view) l <- MV.listStoreNew [] v <- View.new l lsv lsc .< (LSC.onSave (Just (Just <$> toJira l))) onClicked (View.searchPB v) (searchTableBackward (View.searchE v) l (View.treeView v)) onClicked (View.searchNB v) (searchTableForward (View.searchE v) l (View.treeView v)) View.add_col (View.treeView v) l (L.unpack . (!! 0)) "Line" 0 this <- newRef (C v l 1 Nothing) onToggled (View.groupB v) (this .<< updateGrouping) onValueSpinned (View.groupE v) (this .<< updateGrouping) return this push this rows = this .<< \s -> case groupCol s of Nothing -> pushRaw (zipWith (:) (map (L.pack . show) [1..]) rows) s Just (c, _) -> pushRaw (zipWith (:) (map (L.pack . show) [1..]) rows) (s {groupCol = Just (c, rows)}) -- internal functions groupRows [] _ = [] groupRows (row:rows) col = row : sameGroup ++ groupRows rest col where cell = row !! col (sameGroup, rest) = partition ((== cell) . (!! col)) rows updateGrouping state@(C g listM mc gCol) = do col <- spinButtonGetValueAsInt (View.groupE g) grouping <- toggleButtonGetActive (View.groupB g) if grouping then do rows <- MV.listStoreToList listM case gCol of Nothing -> pushRaw rows (state { groupCol = Just (col, rows)}) Just (ccol, crows) -> pushRaw crows (state { groupCol = Just (col, crows)}) else case gCol of Nothing -> return (state { groupCol = Nothing }) Just (ccols, crows) -> pushRaw crows (state { groupCol = Nothing}) searchTableBackward entry liststore treeview = do selI <- getSelectedRow treeview rows' <- MV.listStoreToList liststore let rows = reverse $ zip [0..] (take selI rows') searchRowRange rows entry treeview searchTableForward entry liststore treeview = do selI <- getSelectedRow treeview rows' <- MV.listStoreToList liststore let rows = zip [(selI + 1) ..] (drop (selI + 1) rows') searchRowRange rows entry treeview searchRowRange rows entry treeview = do searchTerm <- entryGetText entry let sI = filter (any (isInfixOf searchTerm) . (map L.unpack) . snd) rows case sI of ((nexti, _):_) -> do MV.treeViewSetCursor treeview [nexti] Nothing _ -> beep getSelectedRow treeV = do tsel <- MV.treeViewGetSelection treeV sel <- MV.treeSelectionGetSelectedRows tsel return $ case sel of ((fst_sel:_):_) -> fst_sel _ -> 0 {- toCsv :: StringList -> IO L.ByteString toCsv liststore = do cont <- MV.listStoreToList liststore return (L.unlines (lineToCsv <$> cont)) where lineToCsv :: [L.ByteString] -> L.ByteString lineToCsv ls = let els = doQuotes <$> ls in L.concat (intersperse (L.pack ";") els) doQuotes :: L.ByteString -> L.ByteString doQuotes cont = let escaped = L.foldl' (\s c -> s `L.append` (if c == '"' then L.pack ['\\', c] else L.pack [c])) L.empty cont in (L.pack "\"") `L.append` escaped `L.append` (L.pack "\"") -} toJira :: StringList -> IO L.ByteString toJira liststore = do cont <- MV.listStoreToList liststore return (L.unlines (lineToCsv <$> cont)) where lineToCsv :: [L.ByteString] -> L.ByteString lineToCsv ls = let els = escape <$> ls in (L.pack "| ") `L.append` L.concat (intersperse (L.pack " | ") els) `L.append` (L.pack " |") escape :: L.ByteString -> L.ByteString escape cont = L.foldl' (\s c -> s `L.append` (if c == '|' then L.pack ['\\', c] else L.pack [c])) L.empty cont pushRaw :: [[L.ByteString]] -> C -> IO C pushRaw rows c@(C g listM mc groupCol) = let addRows n [] = return n addRows n (r:rs) = do let r' = length r when (r' > n) $ forM_ [n .. r' - 1] (\i -> View.add_col (View.treeView g) listM (at i) ("$" ++ show i) i) (MV.listStoreAppend listM) r addRows (max n r') rs at :: Int -> [L.ByteString] -> String at i xs | (length xs) <= i = "" | otherwise = L.unpack $ xs !! i in do (MV.listStoreClear listM) rowcount <- spinButtonGetValueAsInt (View.maxLines g) let groupedRows = maybe selRows (groupRows selRows . fst) groupCol selRows = (take rowcount rows) cs <- addRows mc groupedRows spinButtonSetRange (View.groupE g) 0 (fromIntegral (cs - 1)) return (c { cols = cs }) data C = C { gui :: View.ViewState , listModel :: StringList , cols :: Int , groupCol :: Maybe (Int, [[L.ByteString]]) } -- tests test = windowedApp "TableController test" $ do t <- new :: IO Controller t `push` [[(L.pack . show) (c `rem` 3)| c <- [r .. r + 10]] | r <- [0 .. 9]] t .> view